From 859894de23f27e2429a16ed04db99fd0bcb1b076 Mon Sep 17 00:00:00 2001
From: Tobias Edler <tobias.edler@gmail.com>
Date: Tue, 3 Dec 2024 20:11:20 +0100
Subject: [PATCH 01/35] =?UTF-8?q?Tankanzeigen-Einstellungen=20hinzugef?=
 =?UTF-8?q?=C3=BCgt?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/obp60task/gen_set.pl | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/gen_set.pl b/lib/obp60task/gen_set.pl
index a83bda2..f986e7f 100755
--- a/lib/obp60task/gen_set.pl
+++ b/lib/obp60task/gen_set.pl
@@ -1,5 +1,5 @@
 #!/bin/perl -w
-#A tool to generate that part of config.json  that deals with pages and fields.
+#A tool to generate the part of config.json that deals with pages and fields.
 
 #List of all pages and the number of parameters they expect.
 %NoOfFieldsPerPage=qw( 
@@ -77,7 +77,7 @@ for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
         print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
         print "\t",'"capabilities": {',"\n";
         print "\t",'    "obp60":"true"',"\n";
-        print "\t",'},',"\n";
+        print "\t",'}, ls',"\n";
         print "\t",'"condition":[';
         foreach $page (@Pages) {
             if($NoOfFieldsPerPage{$page}>=$FieldNo){ 
@@ -87,4 +87,25 @@ for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
         print "\b],\n";
     print '},',"\n";
     } 
+    print "{\n";
+    print "\t","\"name\": \"page", $PageNo,"fluid\",\n";
+    print "\t",'"label": "Fluid type",',"\n";
+    print "\t",'"type": "list",',"\n";
+    print "\t",'"default": "0",',"\n";
+    print "\t",'"list": [',"\n";
+    print "\t",'{"l":"Fuel (0)","v":"0"},',"\n";
+    print "\t",'{"l":"Water (1)","v":"1"},',"\n";
+    print "\t",'{"l":"Gray Water (2)","v":"2"},',"\n";
+    print "\t",'{"l":"Live Well (3)","v":"3"},',"\n";
+    print "\t",'{"l":"Oil (4)","v":"4"},',"\n";
+    print "\t",'{"l":"Black Water (5)","v":"5"},',"\n";
+    print "\t",'{"l":"Fuel Gasoline (6)","v":"6"}',"\n";
+    print "\t",'],',"\n";
+    print "\t",'"description": "Fluid type in tank",',"\n";
+    print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
+    print "\t",'"capabilities": {',"\n";
+    print "\t",'"obp60":"true"',"\n";
+    print "\t",'},',"\n";
+    print "\t",'"condition":[{"page',$PageNo,'type":"Fluid"}]',"\n";
+    print '},',"\n";
 } 

From 0692d0687dc72cf8456bbf18cd8d423a53c90313 Mon Sep 17 00:00:00 2001
From: TobiasE-github <142840185+TobiasE-github@users.noreply.github.com>
Date: Tue, 3 Dec 2024 20:59:57 +0100
Subject: [PATCH 02/35] Aktualisieren von gen_set.pl, Typo entfernt

---
 lib/obp60task/gen_set.pl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/obp60task/gen_set.pl b/lib/obp60task/gen_set.pl
index f986e7f..0f7c588 100755
--- a/lib/obp60task/gen_set.pl
+++ b/lib/obp60task/gen_set.pl
@@ -77,7 +77,7 @@ for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
         print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
         print "\t",'"capabilities": {',"\n";
         print "\t",'    "obp60":"true"',"\n";
-        print "\t",'}, ls',"\n";
+        print "\t",'}, ',"\n";
         print "\t",'"condition":[';
         foreach $page (@Pages) {
             if($NoOfFieldsPerPage{$page}>=$FieldNo){ 

From 2659fb9fb741c93dfe7559a7463ec307f02b5c65 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Mon, 9 Dec 2024 14:01:23 +0100
Subject: [PATCH 03/35] Refactor color detection and usage

---
 lib/obp60task/OBP60QRWiFi.h          | 22 ++-----
 lib/obp60task/PageApparentWind.cpp   | 28 ++------
 lib/obp60task/PageBME280.cpp         | 28 ++------
 lib/obp60task/PageBattery.cpp        | 28 +-------
 lib/obp60task/PageBattery2.cpp       | 30 +--------
 lib/obp60task/PageClock.cpp          | 55 +++++-----------
 lib/obp60task/PageDST810.cpp         | 34 ++--------
 lib/obp60task/PageFluid.cpp          | 52 +++++++--------
 lib/obp60task/PageFourValues.cpp     | 32 ++-------
 lib/obp60task/PageFourValues2.cpp    | 32 ++-------
 lib/obp60task/PageGenerator.cpp      | 29 ++-------
 lib/obp60task/PageKeelPosition.cpp   | 45 ++++---------
 lib/obp60task/PageOneValue.cpp       | 21 +-----
 lib/obp60task/PageRollPitch.cpp      | 59 ++++++-----------
 lib/obp60task/PageRudderPosition.cpp | 39 ++++-------
 lib/obp60task/PageSolar.cpp          | 29 ++-------
 lib/obp60task/PageThreeValues.cpp    | 27 +-------
 lib/obp60task/PageTwoValues.cpp      | 23 +------
 lib/obp60task/PageVoltage.cpp        | 33 ++--------
 lib/obp60task/PageWindRose.cpp       | 52 +++++----------
 lib/obp60task/PageWindRoseFlex.cpp   | 52 +++++----------
 lib/obp60task/PageXTETrack.cpp       | 26 +++-----
 lib/obp60task/Pagedata.h             |  2 +
 lib/obp60task/obp60task.cpp          | 97 +++++++++++-----------------
 24 files changed, 224 insertions(+), 651 deletions(-)

diff --git a/lib/obp60task/OBP60QRWiFi.h b/lib/obp60task/OBP60QRWiFi.h
index 6e83067..3bd7646 100644
--- a/lib/obp60task/OBP60QRWiFi.h
+++ b/lib/obp60task/OBP60QRWiFi.h
@@ -5,21 +5,7 @@
 #include "OBP60Extensions.h"
 #include "qrcode.h"
   
-void qrWiFi(String ssid, String passwd, String displaycolor){
-  // Set display color
-  int textcolor = GxEPD_BLACK;
-  int pixelcolor = GxEPD_BLACK;
-  int bgcolor = GxEPD_WHITE;
-  if(displaycolor == "Normal"){
-      textcolor = GxEPD_BLACK;
-      pixelcolor = GxEPD_BLACK;
-      bgcolor = GxEPD_WHITE;
-  }
-  else{
-      textcolor = GxEPD_WHITE;
-      pixelcolor = GxEPD_WHITE;
-      bgcolor = GxEPD_BLACK;
-  }
+void qrWiFi(String ssid, String passwd, uint16_t fgcolor, uint16_t bgcolor){
 
   // Set start point and pixel size
   int16_t box_x = 100;      // X offset
@@ -40,7 +26,7 @@ void qrWiFi(String ssid, String passwd, String displaycolor){
     // Each horizontal module
     for (uint8_t x = 0; x < qrcode.size; x++) {
       if(qrcode_getModule(&qrcode, x, y)){
-        getdisplay().fillRect(box_x, box_y, box_s, box_s, pixelcolor);
+        getdisplay().fillRect(box_x, box_y, box_s, box_s, fgcolor);
       } else {
         getdisplay().fillRect(box_x, box_y, box_s, box_s, bgcolor);
       }
@@ -50,10 +36,10 @@ void qrWiFi(String ssid, String passwd, String displaycolor){
     box_x = init_x;
   }
   getdisplay().setFont(&Ubuntu_Bold32pt7b);
-  getdisplay().setTextColor(textcolor);
+  getdisplay().setTextColor(fgcolor);
   getdisplay().setCursor(140, 285);
   getdisplay().print("WiFi");
   getdisplay().nextPage();                 // Full Refresh
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageApparentWind.cpp b/lib/obp60task/PageApparentWind.cpp
index 92849c3..50be31c 100644
--- a/lib/obp60task/PageApparentWind.cpp
+++ b/lib/obp60task/PageApparentWind.cpp
@@ -54,7 +54,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -90,25 +89,12 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show values AWS
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 50);
         if(holdvalues == false){
@@ -127,7 +113,6 @@ public:
         }
 
         // Show values AWD
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 260);
         if(holdvalues == false){
@@ -154,8 +139,8 @@ public:
         static int16_t y2 = y0;
 
         //Draw instrument
-        getdisplay().fillCircle(x0, y0, lp + 5, pixelcolor); // Black circle
-        getdisplay().fillCircle(x0, y0, lp + 1, bgcolor);    // White circle
+        getdisplay().fillCircle(x0, y0, lp + 5, commonData.fgcolor);
+        getdisplay().fillCircle(x0, y0, lp + 1, commonData.bgcolor);
 
         // Calculation end point of pointer
         value2 = value2 - 3.14 / 2;
@@ -163,10 +148,9 @@ public:
         y1 = y0 + sin(value2) * lp * 0.6;
         x2 = x0 + cos(value2) * lp;
         y2 = y0 + sin(value2) * lp;
-        getdisplay().drawLine(x1, y1, x2, y2, pixelcolor);
+        getdisplay().drawLine(x1, y1, x2, y2, commonData.fgcolor);
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -205,4 +189,4 @@ PageDescription registerPageApparentWind(
     true                // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageBME280.cpp b/lib/obp60task/PageBME280.cpp
index 7c17b73..9ec77f0 100644
--- a/lib/obp60task/PageBME280.cpp
+++ b/lib/obp60task/PageBME280.cpp
@@ -34,7 +34,6 @@ class PageBME280 : public Page
         // Get config data
         String tempformat = config->getString(config->tempFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
         String useenvsensor = config->getString(config->useEnvSensor);
@@ -105,33 +104,19 @@ class PageBME280 : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 55);
         getdisplay().print(name1);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 90);
         getdisplay().print(unit1);                           // Unit
@@ -146,18 +131,16 @@ class PageBME280 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 145);
         getdisplay().print(name2);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 180);
         getdisplay().print(unit2);                           // Unit
@@ -172,18 +155,16 @@ class PageBME280 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
 
         // ############### Value 3 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 235);
         getdisplay().print(name3);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 270);
         getdisplay().print(unit3);                           // Unit
@@ -198,7 +179,6 @@ class PageBME280 : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageBattery.cpp b/lib/obp60task/PageBattery.cpp
index 3cb3fc7..6322981 100644
--- a/lib/obp60task/PageBattery.cpp
+++ b/lib/obp60task/PageBattery.cpp
@@ -47,7 +47,6 @@ class PageBattery : public Page
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
         String powsensor1 = config->getString(config->usePowSensor1);
@@ -153,25 +152,11 @@ class PageBattery : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // Show average settings
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         switch (average) {
             case 0:
@@ -219,13 +204,11 @@ class PageBattery : public Page
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 55);
         getdisplay().print(name1);                           // Value name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 90);
         getdisplay().print(unit1);                           // Unit
@@ -245,18 +228,16 @@ class PageBattery : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 145);
         getdisplay().print(name2);                           // Value name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 180);
         getdisplay().print(unit2);                           // Unit
@@ -276,18 +257,16 @@ class PageBattery : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
 
         // ############### Value 3 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 235);
         getdisplay().print(name3);                           // Value name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 270);
         getdisplay().print(unit3);                           // Unit
@@ -308,7 +287,6 @@ class PageBattery : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(10, 290);
diff --git a/lib/obp60task/PageBattery2.cpp b/lib/obp60task/PageBattery2.cpp
index d2c3e47..8c3bd44 100644
--- a/lib/obp60task/PageBattery2.cpp
+++ b/lib/obp60task/PageBattery2.cpp
@@ -53,7 +53,6 @@ public:
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String batVoltage = config->getString(config->batteryVoltage);
@@ -178,37 +177,22 @@ public:
         // Draw page
         //***********************************************************
 
-        // Clear display, set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(10, 65);
         getdisplay().print("Bat.");
 
          // Show battery type
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(90, 65);
         getdisplay().print(batType);
 
         // Show voltage type
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 140);
         int bvoltage = 0;
@@ -219,7 +203,6 @@ public:
         getdisplay().print("V");
 
         // Show battery capacity
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 200);
         if(batCapacity <= 999) getdisplay().print(batCapacity, 0);
@@ -236,10 +219,9 @@ public:
         getdisplay().print("Battery Type");
 
         // Show battery with fill level
-        batteryGraphic(150, 45, batPercentage, pixelcolor, bgcolor);
+        batteryGraphic(150, 45, batPercentage, commonData.fgcolor, commonData.bgcolor);
 
         // Show average settings
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(150, 145);
         switch (average) {
@@ -261,7 +243,6 @@ public:
         } 
 
         // Show fill level in percent
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(150, 200);
         getdisplay().print(batPercentage);
@@ -269,7 +250,6 @@ public:
         getdisplay().print("%");
 
         // Show time to full discharge
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(150, 260);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -297,7 +277,6 @@ public:
         getdisplay().print("Sensor Modul");
 
         // Reading bus data or using simulation data
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 140);
         if(simulation == true){
@@ -326,7 +305,6 @@ public:
         getdisplay().print("V");
 
         // Show actual current in A
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 200);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -339,7 +317,6 @@ public:
         getdisplay().print("A");
 
         // Show actual consumption in W
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 260);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -352,7 +329,6 @@ public:
         getdisplay().print("W");
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(10, 290);
diff --git a/lib/obp60task/PageClock.cpp b/lib/obp60task/PageClock.cpp
index 29cea4b..c93949b 100644
--- a/lib/obp60task/PageClock.cpp
+++ b/lib/obp60task/PageClock.cpp
@@ -44,7 +44,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -108,25 +107,12 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show values GPS date
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(10, 65);
         if(holdvalues == false) getdisplay().print(svalue2); // Value
@@ -136,10 +122,9 @@ public:
         getdisplay().print("Date");                          // Name
 
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
 
         // Show values GPS time
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(10, 250);
         if(holdvalues == false) getdisplay().print(svalue1); // Value
@@ -155,7 +140,6 @@ public:
             svalue5old = sunrise;
         }
 
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(335, 65);
         if(holdvalues == false) getdisplay().print(sunrise); // Value
@@ -165,7 +149,7 @@ public:
         getdisplay().print("SunR");                          // Name
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
 
         // Show values sunset
         String sunset = "---";
@@ -174,7 +158,6 @@ public:
             svalue6old = sunset;
         }
 
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(335, 250);
         if(holdvalues == false) getdisplay().print(sunset);  // Value
@@ -189,8 +172,8 @@ public:
         int rInstrument = 110;     // Radius of clock
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor);        // Outer circle     
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
 
         for(int i=0; i<360; i=i+1)
         {
@@ -231,7 +214,7 @@ public:
              if(i % 6 == 0){
                 float x1c = 200 + rInstrument*sin(i/180.0*pi);
                 float y1c = 150 - rInstrument*cos(i/180.0*pi);
-                getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
+                getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
                 sinx=sin(i/180.0*pi);
                 cosx=cos(i/180.0*pi);
              }
@@ -245,23 +228,20 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);  
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
             }
         }
 
         // Print Unit in clock
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setFont(&Ubuntu_Bold12pt7b);
+        getdisplay().setCursor(175, 110);
         if(holdvalues == false){
-            getdisplay().setFont(&Ubuntu_Bold12pt7b);
-            getdisplay().setCursor(175, 110);
             getdisplay().print(unit2);                       // Unit
         }
         else{
-            getdisplay().setFont(&Ubuntu_Bold12pt7b);
-            getdisplay().setCursor(175, 110);
             getdisplay().print(unit2old);                    // Unit
         }
 
@@ -290,7 +270,7 @@ public:
             float yy2 = -(rInstrument * 0.5); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -300,7 +280,7 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
         }
 
         // Draw minute pointer
@@ -316,7 +296,7 @@ public:
             float yy2 = -(rInstrument - 15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -326,16 +306,15 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
 
 //*******************************************************************************************
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageDST810.cpp b/lib/obp60task/PageDST810.cpp
index dff5ea3..89f6e7b 100644
--- a/lib/obp60task/PageDST810.cpp
+++ b/lib/obp60task/PageDST810.cpp
@@ -37,7 +37,6 @@ class PageDST810 : public Page
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -91,33 +90,19 @@ class PageDST810 : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
-        
+
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 55);
         getdisplay().print("Depth");                         // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 90);
         if(holdvalues == false){
@@ -146,18 +131,16 @@ class PageDST810 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 145);
         getdisplay().print("Speed");                         // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 180);
         if(holdvalues == false){
@@ -186,18 +169,16 @@ class PageDST810 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
 
         // ############### Value 3 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 220);
         getdisplay().print("Log");                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(20, 240);
         if(holdvalues == false){
@@ -226,18 +207,16 @@ class PageDST810 : public Page
         // ############### Vertical Line ################
 
         // Vertical line 3 pix
-        getdisplay().fillRect(200, 195, 3, 75, pixelcolor);
+        getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor);
 
         // ############### Value 4 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(220, 220);
         getdisplay().print("Temp");                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(220, 240);
         if(holdvalues == false){
@@ -267,7 +246,6 @@ class PageDST810 : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageFluid.cpp b/lib/obp60task/PageFluid.cpp
index 76764ef..37dc2dc 100644
--- a/lib/obp60task/PageFluid.cpp
+++ b/lib/obp60task/PageFluid.cpp
@@ -46,7 +46,7 @@ std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& p
      return rotatedPoints;
 }
 
-void fillPoly4(const std::vector<Point>& p4, int color) {
+void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
     getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
     getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
 }
@@ -96,10 +96,12 @@ static unsigned char gasoline_bits[] = {
 
 class PageFluid : public Page{
     bool keylock = false;               // Keylock
+    int fluidtype;
 
     public:
     PageFluid(CommonData &common){
         common.logger->logDebug(GwLog::LOG,"Show PageFluid");
+        fluidtype = common.config->getInt("page" + String(common.data.actpage) + "fluid", 0);
     }
 
     virtual int handleKey(int key){
@@ -116,7 +118,6 @@ class PageFluid : public Page{
 
         // Get config data
         String flashLED = config->getString(config->flashLED);
-        String displaycolor = config->getString(config->displaycolor);
         String backlightMode = config->getString(config->backlight);
 
         // Optical warning by limit violation (unused)
@@ -133,23 +134,14 @@ class PageFluid : public Page{
         double value1 = bvalue1->value;
         bool valid1 = bvalue1->valid;
 
-        int fluidtype = config->getInt("page" + String(commonData.data.actpage) + "fluid", 0);
-
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor != "Normal"){
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height());
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // descriptions
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 60);
@@ -166,11 +158,11 @@ class PageFluid : public Page{
         uint8_t r = 110;
 
         // circular frame
-        getdisplay().drawCircle(c.x, c.y, r+5, pixelcolor);
-        getdisplay().fillCircle(c.x, c.y, r+2, pixelcolor);
-        getdisplay().fillCircle(c.x, c.y, r-1, bgcolor);
+        getdisplay().drawCircle(c.x, c.y, r+5, commonData.fgcolor);
+        getdisplay().fillCircle(c.x, c.y, r+2, commonData.fgcolor);
+        getdisplay().fillCircle(c.x, c.y, r-1, commonData.bgcolor);
         // center of pointer as dot 
-        getdisplay().fillCircle(c.x, c.y, 8, pixelcolor);
+        getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
 
         // value down centered
         char buffer[6];
@@ -184,19 +176,19 @@ class PageFluid : public Page{
         // draw symbol (as bitmap)
         switch (fluidtype) {
             case 0:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, pixelcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData.fgcolor);
                 break;
             case 1:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, pixelcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData.fgcolor);
                 break;
             case 4:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, pixelcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData.fgcolor);
                 break;
             case 5:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, pixelcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData.fgcolor);
                 break;
             case 6:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, pixelcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData.fgcolor);
                 break;
         }
 
@@ -225,11 +217,11 @@ class PageFluid : public Page{
             {c.x + 2, c.y - (r - 16)},
             {c.x - 2, c.y - (r - 16)} 
         };
-        fillPoly4(rotatePoints(c, pts, -120), pixelcolor);
-        fillPoly4(rotatePoints(c, pts, -60), pixelcolor);
-        fillPoly4(rotatePoints(c, pts, 0), pixelcolor);
-        fillPoly4(rotatePoints(c, pts, 60), pixelcolor);
-        fillPoly4(rotatePoints(c, pts, 120), pixelcolor);
+        fillPoly4(rotatePoints(c, pts, -120), commonData.fgcolor);
+        fillPoly4(rotatePoints(c, pts, -60), commonData.fgcolor);
+        fillPoly4(rotatePoints(c, pts, 0), commonData.fgcolor);
+        fillPoly4(rotatePoints(c, pts, 60), commonData.fgcolor);
+        fillPoly4(rotatePoints(c, pts, 120), commonData.fgcolor);
 
         // dots
         // rotate 0 to 360 in 12 degree steps
@@ -238,7 +230,7 @@ class PageFluid : public Page{
                 continue;
             }
             p = rotatePoint(c, {c.x, c.y - r + 10}, angle);
-            getdisplay().fillCircle(p.x, p.y, 3, pixelcolor);
+            getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
         }
 
         // pointer
@@ -249,9 +241,9 @@ class PageFluid : public Page{
                 {c.x + 6, c.y + 15},
                 {c.x - 6, c.y + 15}
             };
-            fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), pixelcolor);
+            fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), commonData.fgcolor);
             // Pointer axis is white
-            getdisplay().fillCircle(c.x, c.y, 6, bgcolor);
+            getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
         }
  
         // Key Layout
diff --git a/lib/obp60task/PageFourValues.cpp b/lib/obp60task/PageFourValues.cpp
index 546f903..1bad689 100644
--- a/lib/obp60task/PageFourValues.cpp
+++ b/lib/obp60task/PageFourValues.cpp
@@ -37,7 +37,6 @@ class PageFourValues : public Page
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -91,33 +90,19 @@ class PageFourValues : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().setCursor(20, 45);
         getdisplay().print(name1);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(20, 65);
         if(holdvalues == false){
@@ -156,18 +141,16 @@ class PageFourValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 80, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 80, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().setCursor(20, 113);
         getdisplay().print(name2);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(20, 133);
         if(holdvalues == false){
@@ -206,18 +189,16 @@ class PageFourValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 146, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 146, 400, 3, commonData.fgcolor);
 
         // ############### Value 3 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().setCursor(20, 181);
         getdisplay().print(name3);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(20, 201);
         if(holdvalues == false){
@@ -256,18 +237,16 @@ class PageFourValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 214, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 214, 400, 3, commonData.fgcolor);
 
         // ############### Value 4 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().setCursor(20, 249);
         getdisplay().print(name4);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(20, 269);
         if(holdvalues == false){
@@ -307,7 +286,6 @@ class PageFourValues : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageFourValues2.cpp b/lib/obp60task/PageFourValues2.cpp
index 8d05485..c7f5a1a 100644
--- a/lib/obp60task/PageFourValues2.cpp
+++ b/lib/obp60task/PageFourValues2.cpp
@@ -37,7 +37,6 @@ class PageFourValues2 : public Page
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -91,33 +90,19 @@ class PageFourValues2 : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 55);
         getdisplay().print(name1);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 90);
         if(holdvalues == false){
@@ -156,18 +141,16 @@ class PageFourValues2 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 145);
         getdisplay().print(name2);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 180);
         if(holdvalues == false){
@@ -206,18 +189,16 @@ class PageFourValues2 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
 
         // ############### Value 3 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 220);
         getdisplay().print(name3);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(20, 240);
         if(holdvalues == false){
@@ -256,18 +237,16 @@ class PageFourValues2 : public Page
         // ############### Vertical Line ################
 
         // Vertical line 3 pix
-        getdisplay().fillRect(200, 195, 3, 75, pixelcolor);
+        getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor);
 
         // ############### Value 4 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(220, 220);
         getdisplay().print(name4);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(220, 240);
         if(holdvalues == false){
@@ -307,7 +286,6 @@ class PageFourValues2 : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageGenerator.cpp b/lib/obp60task/PageGenerator.cpp
index 3a496ee..aa8ac8d 100644
--- a/lib/obp60task/PageGenerator.cpp
+++ b/lib/obp60task/PageGenerator.cpp
@@ -29,7 +29,6 @@ public:
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String batVoltage = config->getString(config->batteryVoltage);
@@ -85,25 +84,12 @@ public:
         // Draw page
         //***********************************************************
 
-        // Clear display, set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(10, 65);
         getdisplay().print("Power");
@@ -112,7 +98,6 @@ public:
         getdisplay().print("Generator");
 
         // Show voltage type
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 140);
         int bvoltage = 0;
@@ -123,7 +108,6 @@ public:
         getdisplay().print("V");
 
         // Show solar power
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 200);
         if(genPower <= 999) getdisplay().print(genPower, 0);
@@ -140,10 +124,9 @@ public:
         getdisplay().print("Power Modul");
 
         // Show generator
-        generatorGraphic(200, 95, pixelcolor, bgcolor);
+        generatorGraphic(200, 95, commonData.fgcolor, commonData.bgcolor);
 
         // Show load level in percent
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(150, 200);
         getdisplay().print(genPercentage);
@@ -171,7 +154,6 @@ public:
         getdisplay().print("Sensor Modul");
 
         // Reading bus data or using simulation data
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 140);
         if(simulation == true){
@@ -200,7 +182,6 @@ public:
         getdisplay().print("V");
 
         // Show actual current in A
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 200);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -213,7 +194,6 @@ public:
         getdisplay().print("A");
 
         // Show actual consumption in W
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 260);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -226,7 +206,6 @@ public:
         getdisplay().print("W");
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -264,4 +243,4 @@ PageDescription registerPageGenerator(
     true            // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageKeelPosition.cpp b/lib/obp60task/PageKeelPosition.cpp
index ecdb11e..1d02c3e 100644
--- a/lib/obp60task/PageKeelPosition.cpp
+++ b/lib/obp60task/PageKeelPosition.cpp
@@ -33,7 +33,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -69,20 +68,6 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
@@ -92,9 +77,9 @@ public:
         int rInstrument = 110;     // Radius of KeelPosition
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor);        // Outer circle
-        getdisplay().fillRect(0, 30, 400, 122, bgcolor);                    // Delete half top circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);       // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);        // Outer circle
+        getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor);                    // Delete half top circle
 
         for(int i=90; i<=270; i=i+10)
         {
@@ -132,7 +117,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -145,10 +130,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);  
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
             }
 
         }
@@ -182,7 +167,7 @@ public:
             float yy2 = -(rInstrument * 0.6); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -192,20 +177,19 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
 
             // Draw counterweight
-            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, pixelcolor);
+            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 140, startwidth + 22, bgcolor);
-        getdisplay().fillCircle(200, 140, startwidth + 20, pixelcolor);      // Boat circle
-        getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, bgcolor);      // Delete half top of boat circle
-        getdisplay().fillRect(150, 150, 100, 4, pixelcolor);                 // Water line
+        getdisplay().fillCircle(200, 140, startwidth + 22, commonData.bgcolor);
+        getdisplay().fillCircle(200, 140, startwidth + 20, commonData.fgcolor);      // Boat circle
+        getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData.bgcolor);      // Delete half top of boat circle
+        getdisplay().fillRect(150, 150, 100, 4, commonData.fgcolor);                 // Water line
 
         // Print label
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().setCursor(100, 70);
         getdisplay().print("Keel Position");                 // Label
@@ -225,7 +209,6 @@ public:
 
 //*******************************************************************************************
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -264,4 +247,4 @@ PageDescription registerPageKeelPosition(
     true              // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageOneValue.cpp b/lib/obp60task/PageOneValue.cpp
index 283fc4f..708c611 100644
--- a/lib/obp60task/PageOneValue.cpp
+++ b/lib/obp60task/PageOneValue.cpp
@@ -30,7 +30,6 @@ class PageOneValue : public Page{
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -57,31 +56,16 @@ class PageOneValue : public Page{
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         /// Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // Show name
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(20, 100);
         getdisplay().print(name1);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(270, 100);
         if(holdvalues == false){
@@ -118,7 +102,6 @@ class PageOneValue : public Page{
         }
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -157,4 +140,4 @@ PageDescription registerPageOneValue(
     true            // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageRollPitch.cpp b/lib/obp60task/PageRollPitch.cpp
index 0674e2b..bb5b0e3 100644
--- a/lib/obp60task/PageRollPitch.cpp
+++ b/lib/obp60task/PageRollPitch.cpp
@@ -38,7 +38,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -118,25 +117,12 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show roll limit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 65);
         getdisplay().print(rolllimit);                   // Value
@@ -150,10 +136,9 @@ public:
         getdisplay().print("DEG");
         
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
 
         // Show roll value
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 270);
         if(holdvalues == false) getdisplay().print(svalue1); // Value
@@ -166,10 +151,9 @@ public:
         getdisplay().print("Deg");
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
 
         // Show pitch value
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(295, 270);
         if(holdvalues == false) getdisplay().print(svalue2); // Value
@@ -187,8 +171,8 @@ public:
         int rInstrument = 100;     // Radius of instrument
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor);        // Outer circle     
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
 
         for(int i=0; i<360; i=i+10)
         {
@@ -196,7 +180,7 @@ public:
             if((i >= 0 && i <= 60) ||  (i >= 300 && i <= 360)){
                 // Scaling values
                 float x = 200 + (rInstrument+25)*sin(i/180.0*pi);  //  x-coordinate dots
-                float y = 150 - (rInstrument+25)*cos(i/180.0*pi);  //  y-coordinate cots 
+                float y = 150 - (rInstrument+25)*cos(i/180.0*pi);  //  y-coordinate cots
                 const char *ii = "";
                 switch (i)
                 {
@@ -223,7 +207,7 @@ public:
                 // Draw sub scale with dots
                 float x1c = 200 + rInstrument*sin(i/180.0*pi);
                 float y1c = 150 - rInstrument*cos(i/180.0*pi);
-                getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
+                getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
                 float sinx=sin(i/180.0*pi);
                 float cosx=cos(i/180.0*pi); 
 
@@ -236,10 +220,10 @@ public:
                     float yy2 =  -(rInstrument+10);
                     getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                             200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                            200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
+                            200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
                     getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                             200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                            200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);  
+                            200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
                 }
             }
         }
@@ -260,7 +244,7 @@ public:
             float yy2 = -(rInstrument * 0.7); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -270,26 +254,26 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
 
             // Draw counterweight
-            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, pixelcolor);
+            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 22, bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 20, pixelcolor);      // Boat circle
+        getdisplay().fillCircle(200, 150, startwidth + 22, commonData.bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 20, commonData.fgcolor);      // Boat circle
         int x0 = 200;
         int y0 = 150;
         int x1 = x0 + 50*cos(value1);
         int y1 = y0 + 50*sin(value1);
         int x2 = x0 + 50*cos(value1 - pi/2);
         int y2 = y0 + 50*sin(value1 - pi/2);
-        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, bgcolor);          // Clear half top side of boat circle (right triangle)
+        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor);          // Clear half top side of boat circle (right triangle)
         x1 = x0 + 50*cos(value1 + pi);
         y1 = y0 + 50*sin(value1 + pi);
-        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, bgcolor);          // Clear half top side of boat circle (left triangle)
-        getdisplay().fillRect(150, 160, 100, 4, pixelcolor);                 // Water line
+        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor);          // Clear half top side of boat circle (left triangle)
+        getdisplay().fillRect(150, 160, 100, 4, commonData.fgcolor);                 // Water line
 
         // Draw roll pointer
         startwidth = 4;     // Start width of pointer
@@ -304,7 +288,7 @@ public:
             float yy2 = -(rInstrument - 15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -314,7 +298,7 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
         }
         else{
             // Print sensor info
@@ -325,7 +309,6 @@ public:
 
 //*******************************************************************************************
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -365,4 +348,4 @@ PageDescription registerPageRollPitch(
     true                // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageRudderPosition.cpp b/lib/obp60task/PageRudderPosition.cpp
index 02125a0..5f88f0e 100644
--- a/lib/obp60task/PageRudderPosition.cpp
+++ b/lib/obp60task/PageRudderPosition.cpp
@@ -34,7 +34,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -74,20 +73,6 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
@@ -97,9 +82,9 @@ public:
         int rInstrument = 110;     // Radius of RudderPosition
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor);        // Outer circle
-        getdisplay().fillRect(0, 30, 400, 122, bgcolor);                      // Delete half top circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);        // Outer circle
+        getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor);                      // Delete half top circle
 
         for(int i=90; i<=270; i=i+10)
         {
@@ -137,7 +122,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -150,16 +135,15 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);  
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
             }
 
         }
 
         // Print label
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().setCursor(80, 70);
         getdisplay().print("Rudder Position");               // Label
@@ -206,7 +190,7 @@ public:
             float yy2 = -(rInstrument * 0.5); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -216,16 +200,15 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
 
 //*******************************************************************************************
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -263,4 +246,4 @@ PageDescription registerPageRudderPosition(
     true                // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageSolar.cpp b/lib/obp60task/PageSolar.cpp
index 06b5022..d3b1acd 100644
--- a/lib/obp60task/PageSolar.cpp
+++ b/lib/obp60task/PageSolar.cpp
@@ -29,7 +29,6 @@ public:
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String batVoltage = config->getString(config->batteryVoltage);
@@ -85,31 +84,17 @@ public:
         // Draw page
         //***********************************************************
 
-        // Clear display, set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(10, 65);
         getdisplay().print("Solar");
 
         // Show voltage type
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 140);
         int bvoltage = 0;
@@ -120,7 +105,6 @@ public:
         getdisplay().print("V");
 
         // Show solar power
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 200);
         if(solPower <= 999) getdisplay().print(solPower, 0);
@@ -137,10 +121,9 @@ public:
         getdisplay().print("Solar Modul");
 
         // Show solar panel
-        solarGraphic(150, 45, pixelcolor, bgcolor);
+        solarGraphic(150, 45, commonData.fgcolor, commonData.bgcolor);
 
         // Show load level in percent
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(150, 200);
         getdisplay().print(solPercentage);
@@ -168,7 +151,6 @@ public:
         getdisplay().print("Sensor Modul");
 
         // Reading bus data or using simulation data
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 140);
         if(simulation == true){
@@ -197,7 +179,6 @@ public:
         getdisplay().print("V");
 
         // Show actual current in A
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 200);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -210,7 +191,6 @@ public:
         getdisplay().print("A");
 
         // Show actual consumption in W
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(260, 260);
         if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
@@ -223,7 +203,6 @@ public:
         getdisplay().print("W");
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
@@ -261,4 +240,4 @@ PageDescription registerPageSolar(
     true            // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageThreeValues.cpp b/lib/obp60task/PageThreeValues.cpp
index 8759570..08de8f3 100644
--- a/lib/obp60task/PageThreeValues.cpp
+++ b/lib/obp60task/PageThreeValues.cpp
@@ -35,7 +35,6 @@ class PageThreeValues : public Page
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -80,33 +79,18 @@ class PageThreeValues : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         /// Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 55);
         getdisplay().print(name1);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 90);
         if(holdvalues == false){
@@ -145,18 +129,16 @@ class PageThreeValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 145);
         getdisplay().print(name2);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 180);
         if(holdvalues == false){
@@ -195,18 +177,16 @@ class PageThreeValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
 
         // ############### Value 3 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 235);
         getdisplay().print(name3);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 270);
         if(holdvalues == false){
@@ -246,7 +226,6 @@ class PageThreeValues : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageTwoValues.cpp b/lib/obp60task/PageTwoValues.cpp
index 48e8210..01469d9 100644
--- a/lib/obp60task/PageTwoValues.cpp
+++ b/lib/obp60task/PageTwoValues.cpp
@@ -33,7 +33,6 @@ class PageTwoValues : public Page
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         // bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -69,33 +68,18 @@ class PageTwoValues : public Page
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 80);
         getdisplay().print(name1);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 130);
         if(holdvalues == false){
@@ -134,18 +118,16 @@ class PageTwoValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 145, 400, 3, pixelcolor);
+        getdisplay().fillRect(0, 145, 400, 3, commonData.fgcolor);
 
         // ############### Value 2 ################
 
         // Show name
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 190);
         getdisplay().print(name2);                           // Page name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         getdisplay().setCursor(20, 240);
         if(holdvalues == false){
@@ -185,7 +167,6 @@ class PageTwoValues : public Page
         // ############### Key Layout ################
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp
index cc1f9bb..e187d60 100644
--- a/lib/obp60task/PageVoltage.cpp
+++ b/lib/obp60task/PageVoltage.cpp
@@ -45,7 +45,6 @@ public:
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String batVoltage = config->getString(config->batteryVoltage);
@@ -133,43 +132,26 @@ public:
         // Draw page
         //***********************************************************
 
-        // Clear display, set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // Show name
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(20, 100);
         getdisplay().print(name1);                           // Value name
 
         // Show unit
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(270, 100);
         getdisplay().print("V");
 
         // Show battery type
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(295, 100);
         getdisplay().print(batType);
 
         // Show average settings
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(320, 84);
         switch (average) {
@@ -191,7 +173,6 @@ public:
         } 
 
         // Reading bus data or using simulation data
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
         getdisplay().setCursor(20, 240);
         if(simulation == true){
@@ -226,23 +207,23 @@ public:
         // Trend indicator
         // Show trend indicator
         if(trend == true){
-            getdisplay().fillRect(310, 240, 40, 120, bgcolor);   // Clear area
-            getdisplay().fillRect(315, 183, 35, 4, textcolor);   // Draw separator
+            getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
+            getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor);   // Draw separator
             if(int(raw * 10) > int(valueTrend * 10)){
-                displayTrendHigh(320, 174, 11, textcolor);  // Show high indicator
+                displayTrendHigh(320, 174, 11, commonData.fgcolor);  // Show high indicator
             }
             if(int(raw * 10) < int(valueTrend * 10)){
-                displayTrendLow(320, 195, 11, textcolor);   // Show low indicator
+                displayTrendLow(320, 195, 11, commonData.fgcolor);   // Show low indicator
             }
         }
         // No trend indicator
         else{
-            getdisplay().fillRect(310, 240, 40, 120, bgcolor);   // Clear area
+            getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
         }
 
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(10, 290);
diff --git a/lib/obp60task/PageWindRose.cpp b/lib/obp60task/PageWindRose.cpp
index 61aabd2..82700f3 100644
--- a/lib/obp60task/PageWindRose.cpp
+++ b/lib/obp60task/PageWindRose.cpp
@@ -44,7 +44,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -141,25 +140,12 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show values AWA
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 65);
         getdisplay().print(svalue1);                     // Value
@@ -177,10 +163,9 @@ public:
         }
 
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
 
         // Show values AWS
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 270);
         getdisplay().print(svalue2);                     // Value
@@ -198,7 +183,6 @@ public:
         }
 
         // Show values TWD
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(295, 65);
         if(valid3 == true){
@@ -221,10 +205,9 @@ public:
         }
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
 
         // Show values TWS
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(295, 270);
         getdisplay().print(svalue4);                     // Value
@@ -247,16 +230,16 @@ public:
         int rInstrument = 110;     // Radius of grafic instrument
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor);        // Outer circle     
-        getdisplay().fillCircle(200, 150, rInstrument - 10, pixelcolor);    // Inner circle
-        getdisplay().fillCircle(200, 150, rInstrument - 13, bgcolor);       // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor);    // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor);    // Inner circle
 
         for(int i=0; i<360; i=i+10)
         {
             // Scaling values
             float x = 200 + (rInstrument-30)*sin(i/180.0*pi);  //  x-coordinate dots
-            float y = 150 - (rInstrument-30)*cos(i/180.0*pi);  //  y-coordinate cots 
+            float y = 150 - (rInstrument-30)*cos(i/180.0*pi);  //  y-coordinate cots
             const char *ii = "";
             switch (i)
             {
@@ -288,7 +271,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -301,10 +284,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);  
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
             }
         }
 
@@ -321,7 +304,7 @@ public:
             float yy2 = -(rInstrument-15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -331,17 +314,16 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
 
 //*******************************************************************************************
 
         // Show values DBT
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
         getdisplay().setCursor(160, 200);
         getdisplay().print(svalue5);                     // Value
@@ -356,7 +338,6 @@ public:
         }
 
         // Show values STW
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
         getdisplay().setCursor(160, 130);
         getdisplay().print(svalue6);                     // Value
@@ -371,7 +352,6 @@ public:
         }
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageWindRoseFlex.cpp b/lib/obp60task/PageWindRoseFlex.cpp
index f71018a..e33b869 100644
--- a/lib/obp60task/PageWindRoseFlex.cpp
+++ b/lib/obp60task/PageWindRoseFlex.cpp
@@ -44,7 +44,6 @@ public:
         // Get config data
         String lengthformat = config->getString(config->lengthFormat);
         bool simulation = config->getBool(config->useSimuData);
-        String displaycolor = config->getString(config->displaycolor);
         bool holdvalues = config->getBool(config->holdvalues);
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -141,25 +140,12 @@ public:
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            pixelcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // Show values AWA
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 65);
         getdisplay().print(svalue1);                     // Value
@@ -177,10 +163,9 @@ public:
         }
 
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
 
         // Show values AWS
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(10, 270);
         getdisplay().print(svalue2);                     // Value
@@ -198,7 +183,6 @@ public:
         }
 
         // Show values TWD
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(295, 65);
         if(valid3 == true){
@@ -221,10 +205,9 @@ public:
         }
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
 
         // Show values TWS
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(295, 270);
         getdisplay().print(svalue4);                     // Value
@@ -247,16 +230,16 @@ public:
         int rInstrument = 110;     // Radius of grafic instrument
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor);        // Outer circle     
-        getdisplay().fillCircle(200, 150, rInstrument - 10, pixelcolor);    // Inner circle
-        getdisplay().fillCircle(200, 150, rInstrument - 13, bgcolor);       // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor);    // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor);    // Inner circle
 
         for(int i=0; i<360; i=i+10)
         {
             // Scaling values
             float x = 200 + (rInstrument-30)*sin(i/180.0*pi);  //  x-coordinate dots
-            float y = 150 - (rInstrument-30)*cos(i/180.0*pi);  //  y-coordinate cots 
+            float y = 150 - (rInstrument-30)*cos(i/180.0*pi);  //  y-coordinate dots
             const char *ii = "";
             switch (i)
             {
@@ -288,7 +271,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -301,10 +284,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);  
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
             }
         }
 
@@ -321,7 +304,7 @@ public:
             float yy2 = -(rInstrument-15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -331,17 +314,16 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
 
 //*******************************************************************************************
 
         // Show values DBT
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
         getdisplay().setCursor(160, 200);
         getdisplay().print(svalue5);                     // Value
@@ -356,7 +338,6 @@ public:
         }
 
         // Show values STW
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
         getdisplay().setCursor(160, 130);
         getdisplay().print(svalue6);                     // Value
@@ -371,7 +352,6 @@ public:
         }
 
         // Key Layout
-        getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         if(keylock == false){
             getdisplay().setCursor(130, 290);
diff --git a/lib/obp60task/PageXTETrack.cpp b/lib/obp60task/PageXTETrack.cpp
index b16f9ab..91afff1 100644
--- a/lib/obp60task/PageXTETrack.cpp
+++ b/lib/obp60task/PageXTETrack.cpp
@@ -65,7 +65,6 @@ class PageXTETrack : public Page{
 
         // Get config data
         String flashLED = config->getString(config->flashLED);
-        String displaycolor = config->getString(config->displaycolor);
         String backlightMode = config->getString(config->backlight);
 
         String trackStep = config->getString(config->trackStep);
@@ -83,18 +82,11 @@ class PageXTETrack : public Page{
         // Draw page
         //***********************************************************
 
-        // Set background color and text color
-        int textcolor = GxEPD_BLACK;
-        int pixelcolor = GxEPD_BLACK;
-        int bgcolor = GxEPD_WHITE;
-        if(displaycolor != "Normal"){
-            textcolor = GxEPD_WHITE;
-            pixelcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
+        getdisplay().setTextColor(commonData.fgcolor);
+
         // descriptions
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(50, 188);
@@ -141,7 +133,7 @@ class PageXTETrack : public Page{
         // XTETrack view
 
         // draw ship symbol (as bitmap)
-        getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, pixelcolor);
+        getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData.fgcolor);
 
         // draw next waypoint name
         String sval_wpname = "no data";
@@ -196,13 +188,13 @@ class PageXTETrack : public Page{
         }
 
         // left segments
-        drawSegment(0, 54, 46, 24, 75, 24, 0, 90, pixelcolor, seg[2]);
-        drawSegment(0, 100, 82, 24, 112, 24, 50, 100, pixelcolor, seg[1]);
-        drawSegment(60, 100, 117, 24, 147, 24, 110, 100, pixelcolor,seg[0]);
+        drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData.fgcolor, seg[2]);
+        drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData.fgcolor, seg[1]);
+        drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData.fgcolor,seg[0]);
         // right segments
-        drawSegment(340, 100, 283, 24, 253, 24, 290, 100, pixelcolor, seg[3]);
-        drawSegment(399, 100, 318, 24, 289, 24, 350, 100, pixelcolor, seg[4]);
-        drawSegment(399, 54, 354, 24, 325, 24, 399, 90, pixelcolor, seg[5]);
+        drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData.fgcolor, seg[3]);
+        drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData.fgcolor, seg[4]);
+        drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData.fgcolor, seg[5]);
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h
index e4ff852..f4374c3 100644
--- a/lib/obp60task/Pagedata.h
+++ b/lib/obp60task/Pagedata.h
@@ -68,6 +68,8 @@ typedef struct{
   SunData sundata;
   GwApi::BoatValue *time=NULL;
   GwApi::BoatValue *date=NULL;
+  uint16_t fgcolor;
+  uint16_t bgcolor;
 } CommonData;
 
 //a base class that all pages must inherit from
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 3e1dacf..3b4c52d 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -249,12 +249,8 @@ void registerAllPages(PageList &list){
 }
 
 // Undervoltage detection for shutdown display
-void underVoltageDetection(GwApi *api){
-    int textcolor = GxEPD_BLACK;
-    int pixelcolor = GxEPD_BLACK;
-    int bgcolor = GxEPD_WHITE;
+void underVoltageDetection(GwApi *api, CommonData &common){
     // Read settings
-    String displaycolor = api->getConfig()->getConfigItem(api->getConfig()->displaycolor,true)->asString();
     float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
     float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
     // Read supplay voltage
@@ -267,17 +263,9 @@ void underVoltageDetection(GwApi *api){
         buzzer(TONE4, 20);                      // Buzzer tone 4kHz 20ms
         setPortPin(OBP_POWER_50, false);        // Power rail 5.0V Off
         // Shutdown EInk display
-        if(displaycolor == "Normal"){
-            textcolor = GxEPD_BLACK;
-            bgcolor = GxEPD_WHITE;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-            bgcolor = GxEPD_BLACK;
-        }
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
-        getdisplay().fillScreen(bgcolor);       // Clear screen
-        getdisplay().setTextColor(textcolor);
+        getdisplay().fillScreen(common.bgcolor);       // Clear screen
+        getdisplay().setTextColor(common.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(65, 150);
         getdisplay().print("Undervoltage");
@@ -300,6 +288,9 @@ void OBP60Task(GwApi *api){
     startLedTask(api);
     PageList allPages;
     registerAllPages(allPages);
+    CommonData commonData;
+    commonData.logger=logger;
+    commonData.config=config;
 
     tN2kMsg N2kMsg;
 
@@ -311,14 +302,19 @@ void OBP60Task(GwApi *api){
     // Init E-Ink display
     String displaymode = api->getConfig()->getConfigItem(api->getConfig()->display,true)->asString();
     String displaycolor = api->getConfig()->getConfigItem(api->getConfig()->displaycolor,true)->asString();
+    if (displaycolor == "Normal") {
+        commonData.fgcolor = GxEPD_BLACK;
+        commonData.bgcolor = GxEPD_WHITE;
+    }
+    else{
+        commonData.fgcolor = GxEPD_WHITE;
+        commonData.bgcolor = GxEPD_BLACK;
+    }
     String systemname = api->getConfig()->getConfigItem(api->getConfig()->systemName,true)->asString();
     String wifipass = api->getConfig()->getConfigItem(api->getConfig()->apPassword,true)->asString();
     bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
     String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
     uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
-    int textcolor = GxEPD_BLACK;
-    int pixelcolor = GxEPD_BLACK;
-    int bgcolor = GxEPD_WHITE;
 
     #ifdef DISPLAY_GDEY042T81
         getdisplay().init(115200, true, 2, false);  // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse
@@ -327,39 +323,29 @@ void OBP60Task(GwApi *api){
     #endif
 
     getdisplay().setRotation(0);                 // Set display orientation (horizontal)
-    if(displaycolor == "Normal"){
-        textcolor = GxEPD_BLACK;
-        pixelcolor = GxEPD_BLACK;
-        bgcolor = GxEPD_WHITE;
-    }
-    else{
-        textcolor = GxEPD_WHITE;
-        pixelcolor = GxEPD_WHITE;
-        bgcolor = GxEPD_BLACK;
-    }
     getdisplay().setFullWindow();                // Set full Refresh
     getdisplay().firstPage();                    // set first page
-    getdisplay().fillScreen(bgcolor);            // Draw white sreen
-    getdisplay().setTextColor(textcolor);        // Set display color
+    getdisplay().fillScreen(commonData.bgcolor);
+    getdisplay().setTextColor(commonData.fgcolor);
     getdisplay().nextPage();                     // Full Refresh
     getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
-    getdisplay().fillScreen(bgcolor);            // Draw white sreen
+    getdisplay().fillScreen(commonData.bgcolor);
     getdisplay().nextPage();                     // Fast Refresh
     getdisplay().nextPage();                     // Fast Refresh
     if(String(displaymode) == "Logo + QR Code" || String(displaymode) == "Logo"){
-        getdisplay().fillScreen(bgcolor);        // Draw white sreen
-        getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), pixelcolor); // Draw start logo
+        getdisplay().fillScreen(commonData.bgcolor);
+        getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData.fgcolor); // Draw start logo
         getdisplay().nextPage();                 // Fast Refresh
         getdisplay().nextPage();                 // Fast Refresh
         delay(SHOW_TIME);                        // Logo show time
         if(String(displaymode) == "Logo + QR Code"){
-            getdisplay().fillScreen(bgcolor);    // Draw white sreen
-            qrWiFi(systemname, wifipass, displaycolor);  // Show QR code for WiFi connection
+            getdisplay().fillScreen(commonData.bgcolor);
+            qrWiFi(systemname, wifipass, commonData.fgcolor, commonData.bgcolor);  // Show QR code for WiFi connection
             getdisplay().nextPage();             // Fast Refresh
             getdisplay().nextPage();             // Fast Refresh
             delay(SHOW_TIME);                    // QR code show time
         }
-        getdisplay().fillScreen(bgcolor);        // Draw white sreen
+        getdisplay().fillScreen(commonData.bgcolor);
         getdisplay().nextPage();                 // Fast Refresh
         getdisplay().nextPage();                 // Fast Refresh
     }
@@ -367,9 +353,6 @@ void OBP60Task(GwApi *api){
     // Init pages
     int numPages=1;
     PageStruct pages[MAX_PAGE_NUMBER];
-    CommonData commonData;
-    commonData.logger=logger;
-    commonData.config=config;
     BoatValueList boatValues; //all the boat values for the api query
     //commonData.distanceformat=config->getString(xxx);
     //add all necessary data to common data
@@ -439,10 +422,6 @@ void OBP60Task(GwApi *api){
     uint hdopAccuracy = uint(api->getConfig()->getConfigItem(api->getConfig()->hdopAccuracy,true)->asInt());
 
     // refreshmode defined in init section
-    // displaycolor defined in init section
-    // textcolor defined in init section
-    // pixelcolor defined in init section
-    // bgcolor defined in init section
 
     // Boat values for main loop
     GwApi::BoatValue *date = boatValues.findValueOrCreate("GPSD");      // Load GpsDate
@@ -477,7 +456,7 @@ void OBP60Task(GwApi *api){
     
         // Undervoltage detection
         if(uvoltage == true){
-            underVoltageDetection(api);
+            underVoltageDetection(api, commonData);
         }  
 
         // Set CPU speed after boot after 1min 
@@ -587,10 +566,10 @@ void OBP60Task(GwApi *api){
                 getdisplay().setFullWindow();    // Set full update
                 getdisplay().nextPage();
                 if(fastrefresh == "false"){
-                    getdisplay().fillScreen(pixelcolor);// Clear display
-                    getdisplay().nextPage();            // Full update
-                    getdisplay().fillScreen(bgcolor);   // Clear display
-                    getdisplay().nextPage();            // Full update
+                    getdisplay().fillScreen(commonData.fgcolor); // Clear display
+                    getdisplay().nextPage();                     // Full update
+                    getdisplay().fillScreen(commonData.bgcolor); // Clear display
+                    getdisplay().nextPage();                     // Full update
                 }
                 delayedDisplayUpdate = false;
             }
@@ -604,10 +583,10 @@ void OBP60Task(GwApi *api){
                 getdisplay().setFullWindow();    // Set full update
                 getdisplay().nextPage();
                 if(fastrefresh == "false"){
-                    getdisplay().fillScreen(pixelcolor);// Clear display
-                    getdisplay().nextPage();            // Full update
-                    getdisplay().fillScreen(bgcolor);   // Clear display
-                    getdisplay().nextPage();            // Full update
+                    getdisplay().fillScreen(commonData.fgcolor); // Clear display
+                    getdisplay().nextPage();                     // Full update
+                    getdisplay().fillScreen(commonData.bgcolor); // Clear display
+                    getdisplay().nextPage();                     // Full update
                 }
             }
 
@@ -618,10 +597,10 @@ void OBP60Task(GwApi *api){
                 getdisplay().setFullWindow();    // Set full update
                 getdisplay().nextPage();
                 if(fastrefresh == "false"){
-                    getdisplay().fillScreen(pixelcolor);// Clear display
-                    getdisplay().nextPage();            // Full update
-                    getdisplay().fillScreen(bgcolor);   // Clear display
-                    getdisplay().nextPage();            // Full update
+                    getdisplay().fillScreen(commonData.fgcolor); // Clear display
+                    getdisplay().nextPage();                     // Full update
+                    getdisplay().fillScreen(commonData.bgcolor); // Clear display
+                    getdisplay().nextPage();                     // Full update
                 }
             }
             
@@ -633,10 +612,10 @@ void OBP60Task(GwApi *api){
                 api->getStatus(commonData.status);
 
                 // Show header if enabled
-                getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), bgcolor);   // Clear display
+                getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);   // Clear display
                 if (pages[pageNumber].description && pages[pageNumber].description->header){
                     //build some header and footer using commonData
-                    getdisplay().fillScreen(bgcolor);             // Clear display
+                    getdisplay().fillScreen(commonData.bgcolor);             // Clear display
                     displayHeader(commonData, date, time, hdop);  // Sown header
                 }
                 
@@ -662,4 +641,4 @@ void OBP60Task(GwApi *api){
 
 }
 
-#endif
\ No newline at end of file
+#endif

From a129d865c964db4cb233cf2f70505730e0c8f4fc Mon Sep 17 00:00:00 2001
From: wellenvogel <andreas@wellenvogel.de>
Date: Tue, 10 Dec 2024 19:16:11 +0100
Subject: [PATCH 04/35] warn the user if page translation is enabled for
 cibuild

---
 webinstall/cibuild.html |  4 ++--
 webinstall/cibuild.js   | 22 ++++++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/webinstall/cibuild.html b/webinstall/cibuild.html
index 4f41c1a..78ce76d 100644
--- a/webinstall/cibuild.html
+++ b/webinstall/cibuild.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html lang="en">
 
 <head>
 	<script type="module" src="cibuild.js"></script>
@@ -83,4 +83,4 @@
     </form>
 </div>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/webinstall/cibuild.js b/webinstall/cibuild.js
index 26443b0..690da1d 100644
--- a/webinstall/cibuild.js
+++ b/webinstall/cibuild.js
@@ -867,5 +867,27 @@ class PipelineInfo{
         buildSelectors(ROOT_PATH,structure.config.children,true);
         if (! isRunning()) findPipeline();
         updateStatus();
+        const translationCheck=()=>{
+            const lang = document.documentElement.lang;
+            if (lang != "en"){
+                alert(
+                    "This page will not work correctly with translation enabled"
+                );
+            }
+        }
+        // Works at least for Chrome, Firefox, Safari and probably more. Not Microsoft
+        // Edge though. They're special.
+        // Yell at clouds if a translator doesn't change it
+        const observer = new MutationObserver(() => {
+            translationCheck();
+        });
+        observer.observe(document.documentElement, {
+            attributes: true,
+            attributeFilter: ['lang'],
+            childList: false,
+            characterData: false,
+        });
+        translationCheck();
+
     }
 })();
\ No newline at end of file

From 6828d1c67c0b2c85516082c47a4d4dbb4fa60054 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Tue, 17 Dec 2024 19:40:41 +0100
Subject: [PATCH 05/35] Fix air pressure handling

---
 lib/obp60task/OBPSensorTask.cpp | 22 +++++++++++-----------
 lib/obp60task/PageBME280.cpp    |  4 ++--
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp
index be9f1b1..9466463 100644
--- a/lib/obp60task/OBPSensorTask.cpp
+++ b/lib/obp60task/OBPSensorTask.cpp
@@ -198,7 +198,7 @@ void sensorTask(void *param){
         else{
             api->getLogger()->logDebug(GwLog::LOG,"Modul BME280 found");
             sensors.airTemperature = bme280.readTemperature();
-            sensors.airPressure = bme280.readPressure()/100;
+            sensors.airPressure = bme280.readPressure();
             sensors.airHumidity = bme280.readHumidity();
             BME280_ready = true;
         }
@@ -210,7 +210,7 @@ void sensorTask(void *param){
         else{
             api->getLogger()->logDebug(GwLog::LOG,"Modul BMP280 found");
             sensors.airTemperature = bmp280.readTemperature();
-            sensors.airPressure  =bmp280.readPressure()/100;
+            sensors.airPressure = bmp280.readPressure();
             BMP280_ready = true;
         }
     }
@@ -221,7 +221,7 @@ void sensorTask(void *param){
         else{
             api->getLogger()->logDebug(GwLog::LOG,"Modul BMP085/BMP180 found");
             sensors.airTemperature = bmp085.readTemperature();
-            sensors.airPressure  =bmp085.readPressure()/100;
+            sensors.airPressure = bmp085.readPressure();
             BMP180_ready = true;
         }
     }
@@ -479,10 +479,10 @@ void sensorTask(void *param){
             starttime6 = millis();
             unsigned char TempSource = 2;       // Inside temperature
             unsigned char PressureSource = 0;   // Atmospheric pressure
-            unsigned char HumiditySource=0;     // Inside humidity
+            unsigned char HumiditySource = 0;   // Inside humidity
             if(envsensor == "BME280" && BME280_ready == true){
                 sensors.airTemperature = bme280.readTemperature();
-                sensors.airPressure = bme280.readPressure()/100;
+                sensors.airPressure = bme280.readPressure();
                 sensors.airHumidity = bme280.readHumidity();
                 // Send to NMEA200 bus
                 if(!isnan(sensors.airTemperature)){
@@ -494,33 +494,33 @@ void sensorTask(void *param){
                     api->sendN2kMessage(N2kMsg);
                 }
                 if(!isnan(sensors.airPressure)){
-                    SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) mBarToPascal(PressureSource), sensors.airPressure);
+                    SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) PressureSource, sensors.airPressure);
                     api->sendN2kMessage(N2kMsg);
                 }
             }
             else if(envsensor == "BMP280" && BMP280_ready == true){
                 sensors.airTemperature = bmp280.readTemperature();
-                sensors.airPressure  =bmp280.readPressure()/100;
+                sensors.airPressure = bmp280.readPressure();
                 // Send to NMEA200 bus
                 if(!isnan(sensors.airTemperature)){
                     SetN2kPGN130312(N2kMsg, 0, 0,(tN2kTempSource) TempSource, CToKelvin(sensors.airTemperature), N2kDoubleNA);
                     api->sendN2kMessage(N2kMsg);
                 }
                 if(!isnan(sensors.airPressure)){
-                    SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) mBarToPascal(PressureSource), sensors.airPressure);
+                    SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) PressureSource, sensors.airPressure);
                     api->sendN2kMessage(N2kMsg);
                 }
             }
             else if((envsensor == "BMP085" || envsensor == "BMP180") && BMP180_ready == true){
                 sensors.airTemperature = bmp085.readTemperature();
-                sensors.airPressure  =bmp085.readPressure()/100;
+                sensors.airPressure = bmp085.readPressure();
                 // Send to NMEA200 bus
                 if(!isnan(sensors.airTemperature)){
                     SetN2kPGN130312(N2kMsg, 0, 0,(tN2kTempSource) TempSource, CToKelvin(sensors.airTemperature), N2kDoubleNA);
                     api->sendN2kMessage(N2kMsg);
                 }
                 if(!isnan(sensors.airPressure)){
-                    SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) mBarToPascal(PressureSource), sensors.airPressure);
+                    SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) PressureSource, sensors.airPressure);
                     api->sendN2kMessage(N2kMsg);
                 }
             }
@@ -698,4 +698,4 @@ void sensorTask(void *param){
 void createSensorTask(SharedData *shared){
     xTaskCreate(sensorTask,"readSensors",10000,shared,3,NULL);
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageBME280.cpp b/lib/obp60task/PageBME280.cpp
index 7c17b73..24654b7 100644
--- a/lib/obp60task/PageBME280.cpp
+++ b/lib/obp60task/PageBME280.cpp
@@ -86,7 +86,7 @@ class PageBME280 : public Page
         }
         // Display data when sensor activated
         if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){
-            svalue3 = String(value3, 0);                // Formatted value as string including unit conversion and switching decimal places
+            svalue3 = String(value3 / 100, 1);          // Formatted value as string including unit conversion and switching decimal places
         }
         else{
             svalue3 = "---";
@@ -190,7 +190,7 @@ class PageBME280 : public Page
 
         // Switch font if format for any values
         getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
-        getdisplay().setCursor(180, 270);
+        getdisplay().setCursor(140, 270);
 
         // Show bus data
         getdisplay().print(svalue3);                         // Real value as formated string

From 21ae96c8d71d0abf3e99ebab7231aa36d65edc92 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Sun, 22 Dec 2024 14:07:18 +0100
Subject: [PATCH 06/35] Added screenshot feature

---
 lib/obp60task/OBP60Extensions.cpp | 43 ++++++++++++++++++++++++++++++-
 lib/obp60task/OBP60Extensions.h   |  4 ++-
 lib/obp60task/OBP60Hardware.h     |  5 ----
 lib/obp60task/Pagedata.h          |  9 +++++++
 lib/obp60task/config.json         | 16 ++++++++++++
 lib/obp60task/obp60task.cpp       | 19 +++++++-------
 lib/obp60task/platformio.ini      |  3 ++-
 7 files changed, 81 insertions(+), 18 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 282a1e2..5fa9521 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -11,6 +11,7 @@
 #include "Pagedata.h"
 #include "OBP60Hardware.h"
 #include "OBP60Extensions.h"
+#include "imglib.h"
 
 // Character sets
 #include "Ubuntu_Bold8pt7b.h"
@@ -404,4 +405,44 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
         getdisplay().print("G");
 }
 
-#endif
\ No newline at end of file
+// Function to handle HTTP image request
+void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request) {
+    GwLog *logger = api->getLogger();
+
+    String imgformat = api->getConfig()->getConfigItem(api->getConfig()->imageFormat,true)->asString();
+    imgformat.toLowerCase();
+    String filename = "Page" + String(*pageno) + "_" +  pages[*pageno].description->pageName + "." + imgformat;
+
+    logger->logDebug(GwLog::LOG,"handle image request [%s]: %s", imgformat, filename);
+
+    uint8_t *fb = getdisplay().getBuffer(); // EPD framebuffer
+    std::vector<uint8_t> imageBuffer;       // image in webserver transferbuffer
+    String mimetype;
+
+    if (imgformat == "gif") {
+        // GIF is commpressed with LZW, so small
+        mimetype = "image/gif";
+        if (!createGIF(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT)) {
+             logger->logDebug(GwLog::LOG,"GIF creation failed: Hashtable init error!");
+             return;
+        }
+    }
+    else if (imgformat == "bmp") {
+        // Microsoft BMP bitmap
+        mimetype = "image/bmp";
+        createBMP(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
+    }
+    else {
+        // PBM simple portable bitmap
+        mimetype = "image/x-portable-bitmap";
+        createPBM(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
+    }
+
+    AsyncWebServerResponse *response = request->beginResponse_P(200, mimetype, (const uint8_t*)imageBuffer.data(), imageBuffer.size());
+    response->addHeader("Content-Disposition", "inline; filename=" + filename);
+    request->send(response);
+
+    imageBuffer.clear();
+}
+
+#endif
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index e02cd8b..0c7c117 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -70,4 +70,6 @@ void solarGraphic(uint x, uint y, int pcolor, int bcolor);                  // S
 void generatorGraphic(uint x, uint y, int pcolor, int bcolor);              // Generator graphic with fill level
 void startLedTask(GwApi *api);
 
-#endif
\ No newline at end of file
+void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
+
+#endif
diff --git a/lib/obp60task/OBP60Hardware.h b/lib/obp60task/OBP60Hardware.h
index 7f0abe2..f450790 100644
--- a/lib/obp60task/OBP60Hardware.h
+++ b/lib/obp60task/OBP60Hardware.h
@@ -39,11 +39,6 @@
     #define OBP_SPI_DIN 48
     #define SHOW_TIME 6000        // Show time in [ms] for logo and WiFi QR code
     #define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
-    #define MAX_PAGE_NUMBER 10    // Max number of pages for show data
-    #define FONT1 "Ubuntu_Bold8pt7b"
-    #define FONT2 "Ubuntu_Bold24pt7b"
-    #define FONT3 "Ubuntu_Bold32pt7b"
-    #define FONT4 "DSEG7Classic_BoldItalic80pt7b"
 
     // GPS (NEO-6M, NEO-M8N, ATGM336H)
     #define OBP_GPS_RX 2
diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h
index f4374c3..526d9b5 100644
--- a/lib/obp60task/Pagedata.h
+++ b/lib/obp60task/Pagedata.h
@@ -4,6 +4,8 @@
 #include <functional>
 #include <vector>
 
+#define MAX_PAGE_NUMBER 10    // Max number of pages for show data
+
 typedef std::vector<GwApi::BoatValue *> ValueList;
 typedef struct{
   String pageName;
@@ -114,6 +116,13 @@ class PageDescription{
         }
 };
 
+class PageStruct{
+    public:
+        Page *page=NULL;
+        PageData parameters;
+        PageDescription *description=NULL;
+};
+
 // Structure for formated boat values
 typedef struct{
   double value;
diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json
index ca57f33..bac0db1 100644
--- a/lib/obp60task/config.json
+++ b/lib/obp60task/config.json
@@ -898,6 +898,22 @@
             "obp60":"true"
         }
     },
+    {
+        "name": "imageFormat",
+        "label": "Screenshot Format",
+        "type": "list",
+        "default":"PBM",
+        "description": "Graphics file format for screenshots [GIF|PBM|BMP]",
+        "list": [
+            {"l":"Compressed image (GIF)","v":"GIF"},
+            {"l":"Portable bitmap (PBM)","v":"PBM"},
+            {"l":"Windows bitmap (BMP)","v":"BMP"}
+        ],
+        "category":"OBP60 Pages",
+        "capabilities": {
+            "obp60":"true"
+        }
+    },
     {
         "name": "page1type",
         "label": "Type",
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 3b4c52d..7f65bbc 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -183,13 +183,6 @@ class PageList{
         }
 };
 
-class PageStruct{
-    public:
-        Page *page=NULL;
-        PageData parameters;
-        PageDescription *description=NULL;
-};
-
 /**
  * this function will add all the pages we know to the pagelist
  * each page should have defined a registerXXXPage variable of type
@@ -353,6 +346,10 @@ void OBP60Task(GwApi *api){
     // Init pages
     int numPages=1;
     PageStruct pages[MAX_PAGE_NUMBER];
+    // Set start page
+    int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
+    int lastPage=pageNumber;
+
     BoatValueList boatValues; //all the boat values for the api query
     //commonData.distanceformat=config->getString(xxx);
     //add all necessary data to common data
@@ -395,6 +392,11 @@ void OBP60Task(GwApi *api){
             pages[i].parameters.values.push_back(value); 
        }
     }
+
+    api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
+        doImageRequest(api, &pageNumber, pages, request);
+    });
+
     //now we have prepared the page data
     //we start a separate task that will fetch our keys...
     MyData allParameters;
@@ -431,9 +433,6 @@ void OBP60Task(GwApi *api){
     GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP");       // Load GpsHDOP
 
     LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
-    // Set start page
-    int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
-    int lastPage=pageNumber;
     
     commonData.time = boatValues.findValueOrCreate("GPST");      // Load GpsTime
     commonData.date = boatValues.findValueOrCreate("GPSD");      // Load GpsTime
diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index dc919a9..14bd788 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -23,8 +23,9 @@ lib_deps =
     blemasle/MCP23017@2.0.0
     adafruit/Adafruit BusIO@1.5.0
     adafruit/Adafruit GFX Library@1.11.9
-    zinggjm/GxEPD2@1.5.8
+    #zinggjm/GxEPD2@1.5.8
     #https://github.com/ZinggJM/GxEPD2
+    https://github.com/thooge/GxEPD2
     sstaub/Ticker@4.4.0
     adafruit/Adafruit BMP280 Library@2.6.2
     adafruit/Adafruit BME280 Library@2.2.2

From c7b6bafde857ad584ff87d4f51e9d43ace1475af Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Sun, 22 Dec 2024 14:10:46 +0100
Subject: [PATCH 07/35] Added missing imglib files

---
 lib/obp60task/imglib.cpp | 347 +++++++++++++++++++++++++++++++++++++++
 lib/obp60task/imglib.h   |  70 ++++++++
 2 files changed, 417 insertions(+)
 create mode 100644 lib/obp60task/imglib.cpp
 create mode 100644 lib/obp60task/imglib.h

diff --git a/lib/obp60task/imglib.cpp b/lib/obp60task/imglib.cpp
new file mode 100644
index 0000000..80b795e
--- /dev/null
+++ b/lib/obp60task/imglib.cpp
@@ -0,0 +1,347 @@
+/******************************************************************************
+ * Image functions:
+ *   - Convert a 1bit framebuffer in RAM to
+ *     - GIF, compressed, based on giflib and gif_hash
+ *     - PBM, portable bitmap, very simple copy
+ *     - BMP, bigger with a little bit fiddling around
+ *
+ * SPDX-License-Identifier: MIT
+ *****************************************************************************/
+
+#include <Arduino.h>  // needed for PROGMEM
+#include <vector>
+#include "GwLog.h"    // needed for logger
+#include "imglib.h"
+
+GifFilePrivateType gifprivate;
+
+void ClearHashTable(GifHashTableType *HashTable) {
+    memset(HashTable->HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
+}
+
+GifHashTableType *InitHashTable(void) {
+    GifHashTableType *HashTable;
+    if ((HashTable = (GifHashTableType *)ps_malloc(sizeof(GifHashTableType))) == NULL) {
+        return NULL;
+    }
+    ClearHashTable(HashTable);
+    return HashTable;
+}
+
+static int KeyItem(uint32_t Item) {
+    return ((Item >> 12) ^ Item) & HT_KEY_MASK;
+}
+
+void InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code) {
+    int HKey = KeyItem(Key);
+    uint32_t *HTable = HashTable->HTable;
+    while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
+        HKey = (HKey + 1) & HT_KEY_MASK;
+    }
+    HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
+}
+
+int ExistsHashTable(GifHashTableType *HashTable, uint32_t Key) {
+    int HKey = KeyItem(Key);
+    uint32_t *HTable = HashTable->HTable, HTKey;
+    while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
+        if (Key == HTKey) {
+            return HT_GET_CODE(HTable[HKey]);
+        }
+        HKey = (HKey + 1) & HT_KEY_MASK;
+    }
+    return -1;
+}
+
+/******************************************************************************
+ Put 2 bytes (a word) into the given file in little-endian order:
+******************************************************************************/
+void GifPutWord(std::vector<uint8_t>* gifBuffer, uint16_t Word) {
+    /*cuint8_t c[2];
+    [0] = LOBYTE(Word);
+    c[1] = HIBYTE(Word);
+    gifBuffer->push_back(c[0]);
+    gifBuffer->push_back(c[1]); */
+    gifBuffer->push_back(LOBYTE(Word));
+    gifBuffer->push_back(HIBYTE(Word));
+}
+
+/******************************************************************************
+ This routines buffers the given characters until 255 characters are ready
+ to be output. If Code is equal to -1 the buffer is flushed (EOF).
+ The buffer is Dumped with first byte as its size, as GIF format requires.
+******************************************************************************/
+void GifBufferedOutput(std::vector<uint8_t>* gifBuffer, GifByteType *Buf, int c) {
+    if (c == FLUSH_OUTPUT) {
+        // Flush everything out.
+        for (int i = 0; i < Buf[0] + 1; i++) {
+           gifBuffer->push_back(Buf[i]);
+        }
+        // Mark end of compressed data, by an empty block (see GIF doc):
+        Buf[0] = 0;
+        gifBuffer->push_back(0);
+    } else {
+        if (Buf[0] == 255) {
+            // Dump out this buffer - it is full:
+            for (int i = 0; i < Buf[0] + 1; i++) {
+                gifBuffer->push_back(Buf[i]);
+            }
+            Buf[0] = 0;
+        }
+        Buf[++Buf[0]] = c;
+    }
+}
+
+/******************************************************************************
+ The LZ compression output routine:
+ This routine is responsible for the compression of the bit stream into
+ 8 bits (bytes) packets.
+******************************************************************************/
+void GifCompressOutput(std::vector<uint8_t>* gifBuffer, const int Code) {
+
+    if (Code == FLUSH_OUTPUT) {
+        while (gifprivate.CrntShiftState > 0) {
+            // Get Rid of what is left in DWord, and flush it.
+            GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
+            gifprivate.CrntShiftDWord >>= 8;
+            gifprivate.CrntShiftState -= 8;
+        }
+        gifprivate.CrntShiftState = 0; // For next time.
+        GifBufferedOutput(gifBuffer, gifprivate.Buf, FLUSH_OUTPUT);
+    } else {
+        gifprivate.CrntShiftDWord |= ((long)Code) << gifprivate.CrntShiftState;
+        gifprivate.CrntShiftState += gifprivate.RunningBits;
+        while (gifprivate.CrntShiftState >= 8) {
+            // Dump out full bytes:
+            GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
+            gifprivate.CrntShiftDWord >>= 8;
+            gifprivate.CrntShiftState -= 8;
+        }
+    }
+
+    /* If code cannt fit into RunningBits bits, must raise its size. Note */
+    /* however that codes above LZ_MAX_CODE are used for special signaling.      */
+    if (gifprivate.RunningCode >= gifprivate.MaxCode1 && Code <= LZ_MAX_CODE) {
+        gifprivate.MaxCode1 = 1 << ++gifprivate.RunningBits;
+    }
+}
+
+/******************************************************************************
+ Setup the LZ compression for this image:
+******************************************************************************/
+void GifSetupCompress(std::vector<uint8_t>* gifBuffer) {
+    gifBuffer->push_back(0x02);// Bits per pixel wit minimum 2
+
+    gifprivate.Buf[0] = 0; // Nothing was output yet
+    gifprivate.BitsPerPixel = 2; // Minimum is 2
+    gifprivate.ClearCode = (1 << 2);
+    gifprivate.EOFCode = gifprivate.ClearCode + 1;
+    gifprivate.RunningCode = gifprivate.EOFCode + 1;
+    gifprivate.RunningBits = 2 + 1; // Number of bits per code
+    gifprivate.MaxCode1 = 1 << gifprivate.RunningBits; // Max. code + 1
+    gifprivate.CrntCode = FIRST_CODE; // Signal that this is first one!
+    gifprivate.CrntShiftState = 0;    // No information in CrntShiftDWord
+    gifprivate.CrntShiftDWord = 0;
+
+    GifCompressOutput(gifBuffer, gifprivate.ClearCode);
+}
+
+void createGifHeader(std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
+
+    // SCREEN DESCRIPTOR
+    gifBuffer->push_back('G');
+    gifBuffer->push_back('I');
+    gifBuffer->push_back('F');
+    gifBuffer->push_back('8');
+    gifBuffer->push_back('7');
+    gifBuffer->push_back('a');
+
+    GifPutWord(gifBuffer, width);
+    GifPutWord(gifBuffer, height);
+
+    gifBuffer->push_back(0x80 | (1 << 4));
+    gifBuffer->push_back(0x00); // Index into the ColorTable for background color
+    gifBuffer->push_back(0x00); // Pixel Aspect Ratio
+
+    // Colormap
+    gifBuffer->push_back(0xff); // Color 0
+    gifBuffer->push_back(0xff);
+    gifBuffer->push_back(0xff);
+    gifBuffer->push_back(0x00); // Color 1
+    gifBuffer->push_back(0x00);
+    gifBuffer->push_back(0x00);
+
+    // IMAGE DESCRIPTOR
+    gifBuffer->push_back(DESCRIPTOR_INTRODUCER);
+
+    GifPutWord(gifBuffer, 0);
+    GifPutWord(gifBuffer, 0);
+    GifPutWord(gifBuffer, width);
+    GifPutWord(gifBuffer, height);
+
+    gifBuffer->push_back(0x00); // No colormap here , we use the global one
+}
+
+/******************************************************************************
+ The LZ compression routine:
+ This version compresses the given buffer Line of length LineLen.
+ This routine can be called a few times (one per scan line, for example), in
+ order to complete the whole image.
+******************************************************************************/
+void GifCompressLine(std::vector<uint8_t>* gifBuffer, const GifPixelType *Line, const int LineLen) {
+    int i = 0, CrntCode;
+    GifHashTableType *HashTable;
+
+    HashTable = gifprivate.HashTable;
+
+    if (gifprivate.CrntCode == FIRST_CODE) { // Its first time!
+        CrntCode = Line[i++];
+    } else {
+        CrntCode =
+            gifprivate.CrntCode; // Get last code in compression
+    }
+    while (i < LineLen) { // Decode LineLen items
+        GifPixelType Pixel = Line[i++]; // Get next pixel from stream.
+        /* Form a new unique key to search hash table for the code
+         * combines CrntCode as Prefix string with Pixel as postfix
+         * char.
+         */
+        int NewCode;
+        unsigned long NewKey = (((uint32_t)CrntCode) << 8) + Pixel;
+        if ((NewCode = ExistsHashTable(HashTable, NewKey)) >= 0) {
+            /* This Key is already there, or the string is old one,
+             * so simple take new code as our CrntCode:
+             */
+            CrntCode = NewCode;
+        } else {
+            /* Put it in hash table, output the prefix code, and
+             * make our CrntCode equal to Pixel.
+             */
+            GifCompressOutput(gifBuffer, CrntCode);
+            CrntCode = Pixel;
+
+            /* If however the HashTable if full, we send a clear
+             * first and Clear the hash table.
+             */
+            if (gifprivate.RunningCode >= LZ_MAX_CODE) {
+                // Time to do some clearance:
+                GifCompressOutput(gifBuffer, gifprivate.ClearCode);
+                gifprivate.RunningCode = gifprivate.EOFCode + 1;
+                gifprivate.RunningBits = gifprivate.BitsPerPixel + 1;
+                gifprivate.MaxCode1 = 1 << gifprivate.RunningBits;
+                ClearHashTable(HashTable);
+            } else {
+                // Put this unique key with its relative Code in hash table:
+                InsertHashTable(HashTable, NewKey, gifprivate.RunningCode++);
+            }
+        }
+    }
+
+    // Preserve the current state of the compression algorithm:
+    gifprivate.CrntCode = CrntCode;
+
+    if (gifprivate.PixelCount == 0) {
+        // We are done - output last Code and flush output buffers:
+        GifCompressOutput(gifBuffer, CrntCode);
+        GifCompressOutput(gifBuffer, gifprivate.EOFCode);
+        GifCompressOutput(gifBuffer, FLUSH_OUTPUT);
+    }
+}
+
+bool createBMP(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
+    // For BMP the line size has to be a multiple of 4 bytes.
+    // So padding is needed. Also the lines have to be in reverded
+    // order compared to plain buffer
+
+    // BMP header for black-and-white image (1 bit per pixel)
+    const uint8_t bmp_header[] PROGMEM = {
+      // BITMAPFILEHEADER (14 Bytes)
+      0x42, 0x4D,             // bfType: 'BM' signature
+      0x2e, 0x3d, 0x00, 0x00, // bfSize: file size in bytes
+      0x00, 0x00,             // bfReserved1
+      0x00, 0x00,             // bfReserved2
+      0x3e, 0x00, 0x00, 0x00, // bfOffBits: offset in bytes to pixeldata
+      // BITMAPINFOHEADER (40 Bytes)
+      0x28, 0x00, 0x00, 0x00, // biSize: DIB header size
+      (uint8_t)LOBYTE(width), (uint8_t)HIBYTE(width), 0x00, 0x00,   // biWidth
+      (uint8_t)LOBYTE(height), (uint8_t)HIBYTE(height), 0x00, 0x00, // biHeight
+      0x01, 0x00, // biPlanes: Number of color planes (1)
+      0x01, 0x00, // biBitCount: Color depth (1 bit per pixel)
+      0x00, 0x00, 0x00, 0x00, // biCompression: Compression (none)
+      0xf0, 0x3c, 0x00, 0x00, // biSizeImage: Image data size (calculate)
+      0x13, 0x0b, 0x00, 0x00, // biXPelsPerMeter: Horizontal resolution (2835 pixels/meter)
+      0x13, 0x0b, 0x00, 0x00, // biYPelsPerMeter: Vertical resolution (2835 pixels/meter)
+      0x02, 0x00, 0x00, 0x00, // biClrUsed: Colors in color palette (2)
+      0x00, 0x00, 0x00, 0x00, // biClrImportant: Important colors (all)
+      // PALETTE: COLORTRIPLES of RGBQUAD (n * 4 Bytes)
+      0x00, 0x00, 0x00, 0x00, // Color palette: Black
+      0xff, 0xff, 0xff, 0x00  // Color palette: White
+    };
+    size_t bmp_headerSize = sizeof(bmp_header);
+
+    size_t lineSize = (width / 8);
+    size_t paddingSize = 0;
+    if (lineSize % 4 != 0) {
+        paddingSize = 4 - lineSize % 4;
+    }
+    size_t imageSize = bmp_headerSize + (lineSize + paddingSize) * height;
+
+    imageBuffer->resize(imageSize);
+    memcpy(imageBuffer->data(), bmp_header, bmp_headerSize);
+    for (int y = 0; y < height; y++) {
+        uint8_t* srcRow = frameBuffer + (y * lineSize);
+        uint8_t* destRow = imageBuffer->data() + bmp_headerSize + ((height - 1 - y) * (lineSize + paddingSize));
+        memcpy(destRow, srcRow, lineSize);
+        for (int j = 0; j < paddingSize; j++) {
+            destRow[lineSize + j] = 0x00;
+        }
+    }
+    return true;
+}
+
+bool createPBM(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
+    // creates binary PBM image inside imagebuffer 
+    // returns bytesize of created image 
+    const char pbm_header[] PROGMEM = "P4\n#Created by OBP60\n400 300\n";
+    size_t pbm_headerSize = sizeof(pbm_header) - 1; // We don't want trailing zero
+    size_t imageSize = pbm_headerSize + width / 8 * height;
+    imageBuffer->resize(imageSize);
+    memcpy(imageBuffer->data(), pbm_header, pbm_headerSize);
+    memcpy(imageBuffer->data() + pbm_headerSize, frameBuffer, width / 8 * height);
+    return true;
+}
+
+bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
+
+    size_t imageSize = 0;
+    uint16_t bufOffset = 0;  // Offset into imageBuffer for next write access
+
+    gifprivate.HashTable = InitHashTable();
+    if (gifprivate.HashTable == NULL) {
+        return false;
+    }
+    gifprivate.PixelCount = width * height;
+
+    createGifHeader(gifBuffer, width, height);
+
+    // Reset compress algorithm parameters.
+    GifSetupCompress(gifBuffer);
+
+    gifBuffer->reserve(4096); // to avoid lots of alloactions
+    GifPixelType line[width];
+    for (int y = 0; y < height; y++) {
+        // convert uint8_t pixels to single pixels
+        for (int x = 0; x < width; x++) {
+            int byteIndex = (y * width + x) / 8;
+            uint8_t bitIndex = 7 - ((y * width + x) % 8);
+            line[x] = (framebuffer[byteIndex] & (uint8_t)(1 << bitIndex)) == 0;
+        }
+        gifprivate.PixelCount -= width;
+        GifCompressLine(gifBuffer, line, width);
+    }
+
+    gifBuffer->push_back(TERMINATOR_INTRODUCER);
+    free((GifHashTableType *)gifprivate.HashTable);
+
+    return true;
+}
diff --git a/lib/obp60task/imglib.h b/lib/obp60task/imglib.h
new file mode 100644
index 0000000..1299a7b
--- /dev/null
+++ b/lib/obp60task/imglib.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * imglib.h
+ *
+ * SPDX-License-Identifier: MIT
+ *****************************************************************************/
+ 
+#ifndef _IMGLIB_H_
+#define _IMGLIB_H_ 1
+
+// extract bytes from an unsigned word
+#define LOBYTE(x) ((x)&0xff)
+#define HIBYTE(x) (((x) >> 8) & 0xff)
+
+// GIF  encoding constants
+#define DESCRIPTOR_INTRODUCER 0x2c
+#define TERMINATOR_INTRODUCER 0x3b
+
+#define LZ_MAX_CODE 4095 // Biggest code possible in 12 bits
+#define LZ_BITS 12
+
+#define FLUSH_OUTPUT 4096 // Impossible code, to signal flush
+#define FIRST_CODE 4097   // Impossible code, to signal first
+#define NO_SUCH_CODE 4098 // Impossible code, to signal empty
+
+// magfic constants and declarations for GIF LZW
+
+#define HT_SIZE 8192       /* 12bits = 4096 or twice as big! */
+#define HT_KEY_MASK 0x1FFF /* 13bits keys */
+#define HT_KEY_NUM_BITS 13 /* 13bits keys */
+#define HT_MAX_KEY 8191    /* 13bits - 1, maximal code possible */
+#define HT_MAX_CODE 4095   /* Biggest code possible in 12 bits. */
+
+/* The 32 bits of the long are divided into two parts for the key & code:   */
+/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
+/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits.       */
+/* The key is the upper 20 bits.  The code is the lower 12. */
+#define HT_GET_KEY(l) (l >> 12)
+#define HT_GET_CODE(l) (l & 0x0FFF)
+#define HT_PUT_KEY(l) (l << 12)
+#define HT_PUT_CODE(l) (l & 0x0FFF)
+
+typedef unsigned char GifPixelType;
+typedef unsigned char GifByteType;
+
+typedef struct GifHashTableType {
+    uint32_t HTable[HT_SIZE];
+} GifHashTableType;
+
+typedef struct GifFilePrivateType {
+    uint8_t BitsPerPixel;           // Bits per pixel (Codes uses at least this + 1)
+    uint16_t ClearCode;             // The CLEAR LZ code
+    uint16_t EOFCode;               // The EOF LZ code
+    uint16_t RunningCode;           // The next code algorithm can generate
+    uint16_t RunningBits;           // The number of bits required to represent RunningCode
+    uint16_t MaxCode1;              // 1 bigger than max. possible code, in RunningBits bits
+    uint16_t LastCode;              // The code before the current code.
+    uint16_t CrntCode;              // Current algorithm code
+    uint16_t CrntShiftState;        // Number of bits in CrntShiftDWord
+    uint32_t CrntShiftDWord;        // For bytes decomposition into codes
+    uint32_t PixelCount;            // Number of pixels in image
+    GifByteType Buf[256];           // Compressed input is buffered here
+    GifHashTableType *HashTable;    
+} GifFilePrivateType;
+
+bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
+bool createBMP(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
+bool createPBM(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height);
+
+#endif /* _IMGLIB_H */

From 0274b5d75555e307e7c8caf76a22fbde0bdf5ce1 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Tue, 24 Dec 2024 20:24:48 +0100
Subject: [PATCH 08/35] Added analog voltage display

---
 lib/obp60task/OBP60Extensions.cpp |  42 +++++
 lib/obp60task/OBP60Extensions.h   |  11 ++
 lib/obp60task/PageFluid.cpp       |  49 +----
 lib/obp60task/PageVoltage.cpp     | 285 ++++++++++++++++++++++--------
 4 files changed, 268 insertions(+), 119 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 5fa9521..5ef81d8 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -180,6 +180,48 @@ String xdrDelete(String input){
     return input;
 }
 
+Point rotatePoint(const Point& origin, const Point& p, double angle) {
+    // rotate poind around origin by degrees
+    Point rotated;
+    double phi = angle * M_PI / 180.0;
+    double dx = p.x - origin.x;
+    double dy = p.y - origin.y;
+    rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
+    rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
+    return rotated;
+}
+
+std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
+    std::vector<Point> rotatedPoints;
+    for (const auto& p : pts) {
+         rotatedPoints.push_back(rotatePoint(origin, p, angle));
+    }
+     return rotatedPoints;
+}
+
+void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
+    getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
+    getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
+}
+
+// Draw centered text
+void drawTextCenter(int16_t cx, int16_t cy, String text) {
+    int16_t x1, y1;
+    uint16_t w, h;
+    getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
+    getdisplay().setCursor(cx - w / 2, cy + h / 2);
+    getdisplay().print(text);
+}
+
+// Draw right aligned text
+void drawTextRalign(int16_t x, int16_t y, String text) {
+    int16_t x1, y1;
+    uint16_t w, h;
+    getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
+    getdisplay().setCursor(x - w, y);
+    getdisplay().print(text);
+}
+
 // Show a triangle for trend direction high (x, y is the left edge)
 void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){
     getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index 0c7c117..c07bd54 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -39,6 +39,14 @@ GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
 GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
 #endif
 
+struct Point {
+    double x;
+    double y;
+};
+Point rotatePoint(const Point& origin, const Point& p, double angle);
+std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
+void fillPoly4(const std::vector<Point>& p4, uint16_t color);
+
 void hardwareInit();
 
 void setPortPin(uint pin, bool value);          // Set port pin for extension port
@@ -58,6 +66,9 @@ void setBuzzerPower(uint power);                // Set buzzer power
 
 String xdrDelete(String input);                 // Delete xdr prefix from string
 
+void drawTextCenter(int16_t cx, int16_t cy, String text);
+void drawTextRalign(int16_t x, int16_t y, String text);
+
 void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
 void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
 
diff --git a/lib/obp60task/PageFluid.cpp b/lib/obp60task/PageFluid.cpp
index 37dc2dc..ae7349e 100644
--- a/lib/obp60task/PageFluid.cpp
+++ b/lib/obp60task/PageFluid.cpp
@@ -22,43 +22,6 @@ TODO
 
 */
 
-struct Point {
-    double x;
-    double y;
-};
-
-Point rotatePoint(const Point& origin, const Point& p, double angle) {
-    // rotate poind around origin by degrees
-    Point rotated;
-    double phi = angle * M_PI / 180.0;
-    double dx = p.x - origin.x;
-    double dy = p.y - origin.y;
-    rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
-    rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
-    return rotated;
-}
-
-std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
-    std::vector<Point> rotatedPoints;
-    for (const auto& p : pts) {
-         rotatedPoints.push_back(rotatePoint(origin, p, angle));
-    }
-     return rotatedPoints;
-}
-
-void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
-    getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
-    getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
-}
-
-void drawTextCentered(int16_t tx, int16_t ty, String text) {
-    int16_t x, y;
-    uint16_t w, h;
-    getdisplay().getTextBounds(text, 0, 0, &x, &y, &w, &h);
-    getdisplay().setCursor(tx - w / 2, ty + h / 2);
-    getdisplay().print(text);
-}
-
 #define fuel_width 16
 #define fuel_height 16
 static unsigned char fuel_bits[] = {
@@ -171,7 +134,7 @@ class PageFluid : public Page{
         } else {
             strcpy(buffer, "---");
         }
-        drawTextCentered(c.x, c.y + r - 20, String(buffer));
+        drawTextCenter(c.x, c.y + r - 20, String(buffer));
 
         // draw symbol (as bitmap)
         switch (fluidtype) {
@@ -197,18 +160,18 @@ class PageFluid : public Page{
         // scale texts
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         p = {c.x, c.y - r + 30};
-        drawTextCentered(p.x, p.y, "1/2");
+        drawTextCenter(p.x, p.y, "1/2");
         pr = rotatePoint(c, p, -60);
-        drawTextCentered(pr.x, pr.y, "1/4");
+        drawTextCenter(pr.x, pr.y, "1/4");
         pr = rotatePoint(c, p, 60);
-        drawTextCentered(pr.x, pr.y, "3/4");
+        drawTextCenter(pr.x, pr.y, "3/4");
 
         // empty and full
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
         p = rotatePoint(c, {c.x, c.y - r + 30}, -130);
-        drawTextCentered(p.x, p.y, "E");
+        drawTextCenter(p.x, p.y, "E");
         p = rotatePoint(c, {c.x, c.y - r + 30}, 130);
-        drawTextCentered(p.x, p.y, "F");
+        drawTextCenter(p.x, p.y, "F");
 
         // lines
         std::vector<Point> pts = {
diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp
index e187d60..a1e95fa 100644
--- a/lib/obp60task/PageVoltage.cpp
+++ b/lib/obp60task/PageVoltage.cpp
@@ -11,6 +11,7 @@ bool keylock = false;               // Keylock
 int average = 0;                    // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
 bool trend = true;                  // Trend indicator [0|1], 0=off, 1=on
 double raw = 0;
+char mode = 'D';                    // display mode (A)nalog | (D)igital
 
 public:
     PageVoltage(CommonData &common){
@@ -24,6 +25,16 @@ public:
             return 0;                   // Commit the key
         }
 
+        // Switch display mode
+        if (key == 2) {
+            if (mode == 'A') {
+                mode = 'D';
+            } else {
+                mode = 'A';
+            }
+            return 0;
+        }
+
         // Trend indicator
         if(key == 5){
             trend = !trend;
@@ -38,6 +49,41 @@ public:
         return key;
     }
 
+    void printAvg(int avg, uint16_t x, uint16_t y, bool prefix) {
+        getdisplay().setFont(&Ubuntu_Bold8pt7b);
+        getdisplay().setCursor(x, y);
+        if (prefix) {
+            getdisplay().print("Avg: ");
+        }
+        switch (average) {
+            case 0:
+                getdisplay().print("1s");
+                break;
+            case 1:
+                getdisplay().print("10s");
+                break;
+            case 2:
+                getdisplay().print("60s");
+                break;
+            case 3:
+                getdisplay().print("300s");
+                break;
+            default:
+                getdisplay().print("1s");
+                break;
+        }
+    }
+
+    void printVoltageSymbol(uint16_t x, uint16_t y, uint16_t color) {
+        getdisplay().setFont(&Ubuntu_Bold16pt7b);
+        getdisplay().setCursor(x, y);
+        getdisplay().print("V");
+        getdisplay().fillRect(x, y + 6, 22, 3, color);
+        getdisplay().fillRect(x, y + 11, 6, 3, color);
+        getdisplay().fillRect(x + 8, y + 11, 6, 3, color);
+        getdisplay().fillRect(x + 16, y + 11, 6, 3, color);
+    }
+
     virtual void displayPage(CommonData &commonData, PageData &pageData)
     {
         GwConfigHandler *config = commonData.config;
@@ -135,92 +181,177 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        // Show name
-        getdisplay().setTextColor(commonData.fgcolor);
-        getdisplay().setFont(&Ubuntu_Bold32pt7b);
-        getdisplay().setCursor(20, 100);
-        getdisplay().print(name1);                           // Value name
+        if (mode == 'D') {
+            // Display mode digital
 
-        // Show unit
-        getdisplay().setFont(&Ubuntu_Bold20pt7b);
-        getdisplay().setCursor(270, 100);
-        getdisplay().print("V");
+            // Show name
+            getdisplay().setTextColor(commonData.fgcolor);
+            getdisplay().setFont(&Ubuntu_Bold32pt7b);
+            getdisplay().setCursor(20, 100);
+            getdisplay().print(name1);                           // Value name
 
-        // Show battery type
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        getdisplay().setCursor(295, 100);
-        getdisplay().print(batType);
+            // Show unit
+            getdisplay().setFont(&Ubuntu_Bold20pt7b);
+            getdisplay().setCursor(270, 100);
+            getdisplay().print("V");
 
-        // Show average settings
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        getdisplay().setCursor(320, 84);
-        switch (average) {
-            case 0:
-                getdisplay().print("Avg: 1s");
-                break;
-            case 1:
-                getdisplay().print("Avg: 10s");
-                break;
-            case 2:
-                getdisplay().print("Avg: 60s");
-                break;
-            case 3:
-                getdisplay().print("Avg: 300s");
-                break;
-            default:
-                getdisplay().print("Avg: 1s");
-                break;
-        } 
+            // Show battery type
+            getdisplay().setFont(&Ubuntu_Bold8pt7b);
+            getdisplay().setCursor(295, 100);
+            getdisplay().print(batType);
 
-        // Reading bus data or using simulation data
-        getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
-        getdisplay().setCursor(20, 240);
-        if(simulation == true){
-            if(batVoltage == "12V"){
-                value1 = 12.0;
-            }
-            if(batVoltage == "24V"){
-                value1 = 24.0;
-            }
-            value1 += float(random(0, 5)) / 10;         // Simulation data
-            getdisplay().print(value1,1);
-        }
-        else{
-            // Check for valid real data, display also if hold values activated
-            if(valid1 == true || holdvalues == true){
-                // Resolution switching
-                if(value1 < 10){
-                    getdisplay().print(value1,2);
+            // Show average settings
+            printAvg(average, 320, 84, true);
+
+            // Reading bus data or using simulation data
+            getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
+            getdisplay().setCursor(20, 240);
+            if(simulation == true){
+                if(batVoltage == "12V"){
+                    value1 = 12.0;
                 }
-                if(value1 >= 10 && value1 < 100){
-                    getdisplay().print(value1,1);
-                }
-                if(value1 >= 100){
-                    getdisplay().print(value1,0);
+                if(batVoltage == "24V"){
+                    value1 = 24.0;
                 }
+                value1 += float(random(0, 5)) / 10;         // Simulation data
+                getdisplay().print(value1,1);
             }
             else{
-            getdisplay().print("---");                       // Missing bus data
-            }  
-        }
-
-        // Trend indicator
-        // Show trend indicator
-        if(trend == true){
-            getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
-            getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor);   // Draw separator
-            if(int(raw * 10) > int(valueTrend * 10)){
-                displayTrendHigh(320, 174, 11, commonData.fgcolor);  // Show high indicator
+                // Check for valid real data, display also if hold values activated
+                if(valid1 == true || holdvalues == true){
+                    // Resolution switching
+                    if(value1 < 10){
+                        getdisplay().print(value1,2);
+                    }
+                    if(value1 >= 10 && value1 < 100){
+                        getdisplay().print(value1,1);
+                    }
+                    if(value1 >= 100){
+                        getdisplay().print(value1,0);
+                    }
+                }
+                else{
+                getdisplay().print("---");                       // Missing bus data
+                }
             }
-            if(int(raw * 10) < int(valueTrend * 10)){
-                displayTrendLow(320, 195, 11, commonData.fgcolor);   // Show low indicator
-            }
-        }
-        // No trend indicator
-        else{
-            getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
-        }
 
+            // Trend indicator
+            // Show trend indicator
+            if(trend == true){
+                getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
+                getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor);   // Draw separator
+                if(int(raw * 10) > int(valueTrend * 10)){
+                    displayTrendHigh(320, 174, 11, commonData.fgcolor);  // Show high indicator
+                }
+                if(int(raw * 10) < int(valueTrend * 10)){
+                    displayTrendLow(320, 195, 11, commonData.fgcolor);   // Show low indicator
+                }
+            }
+            // No trend indicator
+            else{
+                getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
+            }
+
+        }
+        else {
+            // Display mode analog
+
+            // center
+            Point c = {260, 270};
+            uint8_t r = 240;
+
+            Point p1, p2;
+            std::vector<Point> pts;
+
+            // Instrument
+            getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData.fgcolor);
+            getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData.fgcolor);
+            getdisplay().drawCircleHelper(c.x, c.y, r    , 0x01, commonData.fgcolor);
+
+            // Scale
+            // angle to voltage scale mapping
+            std::map<int, String> mapping = {
+                {15, "10"}, {30, "11"}, {45, "12"}, {60, "13"}, {75, "14"}
+            };
+            pts = {
+                {c.x - r, c.y - 1},
+                {c.x - r + 12, c.y - 1},
+                {c.x - r + 12, c.y + 1},
+                {c.x - r, c.y + 1}
+            };
+            getdisplay().setFont(&Ubuntu_Bold10pt7b);
+            for (int angle = 3; angle < 90; angle += 3) {
+                if (angle % 15 == 0) {
+                    fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
+                    p1 = rotatePoint(c, {c.x - r + 30, c.y}, angle);
+                    drawTextCenter(p1.x, p1.y, mapping[angle]);
+                }
+                else {
+                    p1 = rotatePoint(c, {c.x - r, c.y}, angle);
+                    p2 = rotatePoint(c, {c.x - r + 6, c.y}, angle);
+                    getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData.fgcolor);
+                }
+            }
+
+            // Pointer rotation and limits
+            double angle;
+            if (not valid1) {
+                angle = -0.5;
+            }
+            else {
+                if (value1 > 15.0) {
+                    angle = 91;
+                }
+                else if (value1 <= 9) {
+                    angle = -0.5;
+                }
+                else {
+                    angle = (value1 - 9) * 15;
+                }
+            }
+
+            // Pointer
+            // thick part
+            pts = {
+                {c.x - 2, c.y + 3},
+                {c.x - r + 38, c.y + 2},
+                {c.x - r + 38, c.y - 2},
+                {c.x - 2, c.y - 3}
+            };
+            fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
+            // thin part
+            pts = {
+                {c.x - r + 40, c.y + 1},
+                {c.x - r + 5, c.y + 1},
+                {c.x - r + 5, c.y -1},
+                {c.x - r + 40, c.y - 1},
+            };
+            fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
+
+            // base
+            getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
+            getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
+
+            // Symbol
+            printVoltageSymbol(40, 60, commonData.fgcolor);
+
+            // Additional informatio at right side
+            getdisplay().setFont(&Ubuntu_Bold8pt7b);
+            getdisplay().setCursor(300, 60);
+            getdisplay().print("Source:");
+            getdisplay().setCursor(300, 80);
+            getdisplay().print(name1);
+
+            getdisplay().setCursor(300, 110);
+            getdisplay().print("Type:");
+            getdisplay().setCursor(300, 130);
+            getdisplay().print(batType);
+
+            getdisplay().setCursor(300, 160);
+            getdisplay().print("Avg:");
+            printAvg(average, 300, 180, false);
+
+        }
 
         // Key Layout
         getdisplay().setTextColor(commonData.fgcolor);
@@ -228,6 +359,8 @@ public:
         if(keylock == false){
             getdisplay().setCursor(10, 290);
             getdisplay().print("[AVG]");
+            getdisplay().setCursor(62, 290);
+            getdisplay().print("[MODE]");
             getdisplay().setCursor(130, 290);
             getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
             getdisplay().setCursor(293, 290);

From 3bc0082bb8b5689035ff1f8b82b947eb3d12c91a Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Tue, 24 Dec 2024 20:31:45 +0100
Subject: [PATCH 09/35] Fix pointer base display

---
 lib/obp60task/PageVoltage.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp
index a1e95fa..8a30006 100644
--- a/lib/obp60task/PageVoltage.cpp
+++ b/lib/obp60task/PageVoltage.cpp
@@ -329,8 +329,8 @@ public:
             fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
 
             // base
-            getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
-            getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
+            getdisplay().fillCircle(c.x, c.y, 7, commonData.fgcolor);
+            getdisplay().fillCircle(c.x, c.y, 4, commonData.bgcolor);
 
             // Symbol
             printVoltageSymbol(40, 60, commonData.fgcolor);

From daaefc7eba2825103622bc542f5b4610da8cf52f Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Wed, 25 Dec 2024 19:23:44 +0100
Subject: [PATCH 10/35] Use I2C FRAM module if available to store page voltage
 state

---
 lib/obp60task/OBP60Extensions.cpp | 28 ++++++++++++++++++++++++++--
 lib/obp60task/OBP60Extensions.h   | 22 +++++++++++++++++++++-
 lib/obp60task/OBP60Hardware.h     |  2 ++
 lib/obp60task/PageVoltage.cpp     | 19 ++++++++++++++++---
 lib/obp60task/obp60task.cpp       |  2 +-
 lib/obp60task/platformio.ini      |  1 +
 6 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 5ef81d8..c288bd8 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -61,6 +61,10 @@ GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){r
 // Horter I2C moduls
 PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
 
+// FRAM
+Adafruit_FRAM_I2C fram;
+bool hasFRAM = false;
+
 // Global vars
 bool blinkingLED = false;       // Enable / disable blinking flash LED
 bool statusLED = false;         // Actual status of flash LED on/off
@@ -70,7 +74,7 @@ int uvDuration = 0;             // Under voltage duration in n x 100ms
 
 LedTaskData *ledTaskData=nullptr;
 
-void hardwareInit()
+void hardwareInit(GwApi *api)
 {
     Wire.begin();
     // Init PCF8574 digital outputs
@@ -78,7 +82,27 @@ void hardwareInit()
     if(pcf8574_Out.begin()){        // Initialize PCF8574
         pcf8574_Out.write8(255);    // Clear all outputs
     }
-
+    fram = Adafruit_FRAM_I2C();
+    if (esp_reset_reason() ==  ESP_RST_POWERON) {
+        // help initialize FRAM
+        api->getLogger()->logDebug(GwLog::LOG,"Delaying I2C init for 250ms due to cold boot");
+        delay(250);
+    }
+    // FRAM (e.g. MB85RC256V)
+    if (fram.begin(FRAM_I2C_ADDR)) {
+        hasFRAM = true;
+        uint16_t manufacturerID;
+        uint16_t productID;
+        fram.getDeviceID(&manufacturerID, &productID);
+        // Boot counter
+        uint8_t framcounter = fram.read(0x0000);
+        fram.write(0x0000, framcounter+1);
+        api->getLogger()->logDebug(GwLog::LOG,"FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
+    }
+    else {
+        hasFRAM = false;
+        api->getLogger()->logDebug(GwLog::LOG,"NO FRAM detected");
+    }
 }
 
 void startLedTask(GwApi *api){
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index c07bd54..a0be7cd 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -8,6 +8,19 @@
 #define FASTLED_ESP32_FLASH_LOCK 1
 #include "LedSpiTask.h"
 #include <GxEPD2_BW.h>                  // E-paper lib V2
+#include <Adafruit_FRAM_I2C.h>          // I2C FRAM
+
+// FRAM address reservations 32kB: 0x0000 - 0x7FFF
+// 0x0000 - 0x03ff: single variables
+#define FRAM_VOLTAGE_AVG 0x000A
+#define FRAM_VOLTAGE_TREND 0x000B
+#define FRAM_VOLTAGE_MODE 0x000C
+// Barograph history data
+#define FRAM_BAROGRAPH_START 0x0400
+#define FRAM_BAROGRAPH_END 0x13FF
+
+extern Adafruit_FRAM_I2C fram;
+extern bool hasFRAM;
 
 // Fonts declarations for display (#inclues see OBP60Extensions.cpp)
 extern const GFXfont Ubuntu_Bold8pt7b;
@@ -47,7 +60,7 @@ Point rotatePoint(const Point& origin, const Point& p, double angle);
 std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
 void fillPoly4(const std::vector<Point>& p4, uint16_t color);
 
-void hardwareInit();
+void hardwareInit(GwApi *api);
 
 void setPortPin(uint pin, bool value);          // Set port pin for extension port
 
@@ -83,4 +96,11 @@ void startLedTask(GwApi *api);
 
 void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
 
+#define fram_width 16
+#define fram_height 16
+static unsigned char fram_bits[] PROGMEM = {
+   0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
+   0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
+   0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
+
 #endif
diff --git a/lib/obp60task/OBP60Hardware.h b/lib/obp60task/OBP60Hardware.h
index f450790..4782b4c 100644
--- a/lib/obp60task/OBP60Hardware.h
+++ b/lib/obp60task/OBP60Hardware.h
@@ -30,6 +30,8 @@
     #define INA226_I2C_ADDR3 0x45   // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
     // Horter modules
     #define PCF8574_I2C_ADDR1 0x20  // First digital out module
+    // FRAM (e.g. MB85RC256V)
+    #define FRAM_I2C_ADDR 0x50
     // SPI (E-Ink display, Extern Bus)
     #define OBP_SPI_CS 39
     #define OBP_SPI_DC 40
diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp
index 8a30006..cdee817 100644
--- a/lib/obp60task/PageVoltage.cpp
+++ b/lib/obp60task/PageVoltage.cpp
@@ -8,20 +8,26 @@ class PageVoltage : public Page
 {
 bool init = false;                  // Marker for init done
 bool keylock = false;               // Keylock
-int average = 0;                    // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
+uint8_t average = 0;                // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
 bool trend = true;                  // Trend indicator [0|1], 0=off, 1=on
 double raw = 0;
 char mode = 'D';                    // display mode (A)nalog | (D)igital
 
 public:
     PageVoltage(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageVoltage");
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageVoltage");
+        if (hasFRAM) {
+            average = fram.read(FRAM_VOLTAGE_AVG);
+            trend = fram.read(FRAM_VOLTAGE_TREND);
+            mode = fram.read(FRAM_VOLTAGE_MODE);
+        }
     }
     virtual int handleKey(int key){
          // Change average
         if(key == 1){
             average ++;
             average = average % 4;      // Modulo 4
+            if (hasFRAM) fram.write(FRAM_VOLTAGE_AVG, average);
             return 0;                   // Commit the key
         }
 
@@ -32,12 +38,14 @@ public:
             } else {
                 mode = 'A';
             }
+            if (hasFRAM) fram.write(FRAM_VOLTAGE_MODE, mode);
             return 0;
         }
 
         // Trend indicator
         if(key == 5){
             trend = !trend;
+            if (hasFRAM) fram.write(FRAM_VOLTAGE_TREND, trend);
             return 0;                   // Commit the key
         }
 
@@ -335,7 +343,7 @@ public:
             // Symbol
             printVoltageSymbol(40, 60, commonData.fgcolor);
 
-            // Additional informatio at right side
+            // Additional information at right side
             getdisplay().setFont(&Ubuntu_Bold8pt7b);
             getdisplay().setCursor(300, 60);
             getdisplay().print("Source:");
@@ -351,6 +359,11 @@ public:
             getdisplay().print("Avg:");
             printAvg(average, 300, 180, false);
 
+            // FRAM indicator
+            if (hasFRAM) {
+                getdisplay().drawXBitmap(300, 240, fram_bits, fram_width, fram_height, commonData.fgcolor);
+            }
+
         }
 
         // Key Layout
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 7f65bbc..40a00c7 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -43,7 +43,7 @@ void OBP60Init(GwApi *api){
     
 
     // Init hardware
-    hardwareInit();
+    hardwareInit(api);
 
     // Init power rail 5.0V
     String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index 14bd788..63f1085 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -35,6 +35,7 @@ lib_deps =
     paulstoffregen/OneWire@2.3.8
     milesburton/DallasTemperature@3.11.0
     signetica/SunRise@2.0.2
+    adafruit/Adafruit FRAM I2C@^2.0.3
 build_flags=
     #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
 #    -D ARDUINO_USB_MODE=1           #0=OTG (to implement other external devices), 1=CDC (is a serial device) 

From 6e256e136a209071e60e7e43a8ee9b9192867122 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Mon, 30 Dec 2024 12:16:46 +0100
Subject: [PATCH 11/35] Fix page fluid data and fluidtype selection

---
 lib/obp60task/PageFluid.cpp |  8 ++++++--
 lib/obp60task/Pagedata.h    |  1 +
 lib/obp60task/config.json   | 20 ++++++++++----------
 lib/obp60task/obp60task.cpp |  1 +
 4 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/lib/obp60task/PageFluid.cpp b/lib/obp60task/PageFluid.cpp
index 37dc2dc..064a41c 100644
--- a/lib/obp60task/PageFluid.cpp
+++ b/lib/obp60task/PageFluid.cpp
@@ -100,8 +100,7 @@ class PageFluid : public Page{
 
     public:
     PageFluid(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageFluid");
-        fluidtype = common.config->getInt("page" + String(common.data.actpage) + "fluid", 0);
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageFluid");
     }
 
     virtual int handleKey(int key){
@@ -112,6 +111,11 @@ class PageFluid : public Page{
         return key;
     }
 
+    virtual void displayNew(CommonData &commonData, PageData &pageData){
+        fluidtype = commonData.config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
+        commonData.logger->logDebug(GwLog::LOG,"New PageFluid: fluidtype=%d", fluidtype);
+    }
+
     virtual void displayPage(CommonData &commonData, PageData &pageData){
         GwConfigHandler *config = commonData.config;
         GwLog *logger=commonData.logger;
diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h
index 526d9b5..d18452f 100644
--- a/lib/obp60task/Pagedata.h
+++ b/lib/obp60task/Pagedata.h
@@ -9,6 +9,7 @@
 typedef std::vector<GwApi::BoatValue *> ValueList;
 typedef struct{
   String pageName;
+  uint8_t pageNumber; // page number in sequence of visible pages
   //the values will always contain the user defined values first
   ValueList values;
 } PageData;
diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json
index bac0db1..9ba0fab 100644
--- a/lib/obp60task/config.json
+++ b/lib/obp60task/config.json
@@ -936,7 +936,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page1type":"OneValue"},{"page1type":"TwoValues"},{"page1type":"ThreeValues"},{"page1type":"FourValues"},{"page1type":"FourValues2"},{"page1type":"WindRoseFlex"}]
+        "condition":[{"page1type":"OneValue"},{"page1type":"TwoValues"},{"page1type":"ThreeValues"},{"page1type":"FourValues"},{"page1type":"FourValues2"},{"page1type":"WindRoseFlex"},{"page1type":"Fluid"}]
     },
     {
         "name": "page1value2",
@@ -1042,7 +1042,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page2type":"OneValue"},{"page2type":"TwoValues"},{"page2type":"ThreeValues"},{"page2type":"FourValues"},{"page2type":"FourValues2"},{"page2type":"WindRoseFlex"}]
+        "condition":[{"page2type":"OneValue"},{"page2type":"TwoValues"},{"page2type":"ThreeValues"},{"page2type":"FourValues"},{"page2type":"FourValues2"},{"page2type":"WindRoseFlex"},{"page2type":"Fluid"}]
     },
     {
         "name": "page2value2",
@@ -1148,7 +1148,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page3type":"OneValue"},{"page3type":"TwoValues"},{"page3type":"ThreeValues"},{"page3type":"FourValues"},{"page3type":"FourValues2"},{"page3type":"WindRoseFlex"}]
+        "condition":[{"page3type":"OneValue"},{"page3type":"TwoValues"},{"page3type":"ThreeValues"},{"page3type":"FourValues"},{"page3type":"FourValues2"},{"page3type":"WindRoseFlex"},{"page3type":"Fluid"}]
     },
     {
         "name": "page3value2",
@@ -1254,7 +1254,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page4type":"OneValue"},{"page4type":"TwoValues"},{"page4type":"ThreeValues"},{"page4type":"FourValues"},{"page4type":"FourValues2"},{"page4type":"WindRoseFlex"}]
+        "condition":[{"page4type":"OneValue"},{"page4type":"TwoValues"},{"page4type":"ThreeValues"},{"page4type":"FourValues"},{"page4type":"FourValues2"},{"page4type":"WindRoseFlex"},{"page4type":"Fluid"}]
     },
     {
         "name": "page4value2",
@@ -1360,7 +1360,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page5type":"OneValue"},{"page5type":"TwoValues"},{"page5type":"ThreeValues"},{"page5type":"FourValues"},{"page5type":"FourValues2"},{"page4type":"WindRoseFlex"}]
+        "condition":[{"page5type":"OneValue"},{"page5type":"TwoValues"},{"page5type":"ThreeValues"},{"page5type":"FourValues"},{"page5type":"FourValues2"},{"page4type":"WindRoseFlex"},{"page5type":"Fluid"}]
     },
     {
         "name": "page5value2",
@@ -1466,7 +1466,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page6type":"OneValue"},{"page6type":"TwoValues"},{"page6type":"ThreeValues"},{"page6type":"FourValues"},{"page6type":"FourValues2"},{"page6type":"WindRoseFlex"}]
+        "condition":[{"page6type":"OneValue"},{"page6type":"TwoValues"},{"page6type":"ThreeValues"},{"page6type":"FourValues"},{"page6type":"FourValues2"},{"page6type":"WindRoseFlex"},{"page6type":"Fluid"}]
     },
     {
         "name": "page6value2",
@@ -1572,7 +1572,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page7type":"OneValue"},{"page7type":"TwoValues"},{"page7type":"ThreeValues"},{"page7type":"FourValues"},{"page7type":"FourValues2"},{"page7type":"WindRoseFlex"}]
+        "condition":[{"page7type":"OneValue"},{"page7type":"TwoValues"},{"page7type":"ThreeValues"},{"page7type":"FourValues"},{"page7type":"FourValues2"},{"page7type":"WindRoseFlex"},{"page7type":"Fluid"}]
     },
     {
         "name": "page7value2",
@@ -1678,7 +1678,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page8type":"OneValue"},{"page8type":"TwoValues"},{"page8type":"ThreeValues"},{"page8type":"FourValues"},{"page8type":"FourValues2"},{"page8type":"WindRoseFlex"}]
+        "condition":[{"page8type":"OneValue"},{"page8type":"TwoValues"},{"page8type":"ThreeValues"},{"page8type":"FourValues"},{"page8type":"FourValues2"},{"page8type":"WindRoseFlex"},{"page8type":"Fluid"}]
     },
     {
         "name": "page8value2",
@@ -1784,7 +1784,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page9type":"OneValue"},{"page9type":"TwoValues"},{"page9type":"ThreeValues"},{"page9type":"FourValues"},{"page9type":"FourValues2"},{"page9type":"WindRoseFlex"}]
+        "condition":[{"page9type":"OneValue"},{"page9type":"TwoValues"},{"page9type":"ThreeValues"},{"page9type":"FourValues"},{"page9type":"FourValues2"},{"page9type":"WindRoseFlex"},{"page9type":"Fluid"}]
     },
     {
         "name": "page9value2",
@@ -1890,7 +1890,7 @@
         "capabilities": {
             "obp60":"true"
         },
-        "condition":[{"page10type":"OneValue"},{"page10type":"TwoValues"},{"page10type":"ThreeValues"},{"page10type":"FourValues"},{"page10type":"FourValues2"},{"page10type":"WindRoseFlex"}]
+        "condition":[{"page10type":"OneValue"},{"page10type":"TwoValues"},{"page10type":"ThreeValues"},{"page10type":"FourValues"},{"page10type":"FourValues2"},{"page10type":"WindRoseFlex"},{"page10type":"Fluid"}]
     },
     {
         "name": "page10value2",
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 7f65bbc..7580aa1 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -373,6 +373,7 @@ void OBP60Task(GwApi *api){
        pages[i].description=description;
        pages[i].page=description->creator(commonData);
        pages[i].parameters.pageName=pageType;
+       pages[i].parameters.pageNumber = i + 1;
        LOG_DEBUG(GwLog::DEBUG,"found page %s for number %d",pageType.c_str(),i);
        //fill in all the user defined parameters
        for (int uid=0;uid<description->userParam;uid++){

From 319f3f3e68a344fc8d7e4bd56e6490a6b4e97545 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Mon, 30 Dec 2024 19:46:54 +0100
Subject: [PATCH 12/35] Improve FRAM icon

---
 lib/obp60task/OBP60Extensions.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index a0be7cd..79695ef 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -98,8 +98,8 @@ void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUM
 
 #define fram_width 16
 #define fram_height 16
-static unsigned char fram_bits[] PROGMEM = {
-   0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
+static unsigned char fram_bits[] = {
+   0xf8, 0x1f, 0xff, 0xff, 0x9f, 0xff, 0x98, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
    0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
    0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
 

From 6637b804007018589448a1f75c9ebe0a0b466a01 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Thu, 2 Jan 2025 19:55:39 +0100
Subject: [PATCH 13/35] Some small typo fixes

---
 lib/obp60task/OBP60Hardware.h   | 4 ++--
 lib/obp60task/OBPSensorTask.cpp | 2 +-
 lib/obp60task/obp60task.cpp     | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/obp60task/OBP60Hardware.h b/lib/obp60task/OBP60Hardware.h
index 4782b4c..292068b 100644
--- a/lib/obp60task/OBP60Hardware.h
+++ b/lib/obp60task/OBP60Hardware.h
@@ -54,7 +54,7 @@
     #define TONE3 3500          // 3500Hz
     #define TONE4 4000          // 4000Hz
     // Analog Input
-    #define OBP_ANALOG0 4       // Analog input for voltage power supplay
+    #define OBP_ANALOG0 4       // Analog input for voltage power supply
     #define MIN_VOLTAGE 10.0    // Min voltage for under voltage detection (then goto deep sleep)
     #define POWER_FAIL_TIME 2   // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
     // Touch buttons
@@ -69,7 +69,7 @@
     #define NUM_FLASH_LED 1         // Number of flash LED
     #define OBP_FLASH_LED 7         // GPIO port
     // Backlight LEDs (6x WS2812B)
-    #define NUM_BACKLIGHT_LED 6     // Numebr of Backlight LEDs
+    #define NUM_BACKLIGHT_LED 6     // Number of Backlight LEDs
     #define OBP_BACKLIGHT_LED 15    // GPIO port
     // Power Rail
     #define OBP_POWER_50 5          // 5.0V power rail
diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp
index 9466463..e2faa5d 100644
--- a/lib/obp60task/OBPSensorTask.cpp
+++ b/lib/obp60task/OBPSensorTask.cpp
@@ -456,7 +456,7 @@ void sensorTask(void *param){
             }
         }
 
-        // Send supplay voltage value all 1s
+        // Send supply voltage value all 1s
         if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
             starttime5 = millis();
             sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20;   // Vin = 1/20
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index dca6202..85f9a07 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -246,7 +246,7 @@ void underVoltageDetection(GwApi *api, CommonData &common){
     // Read settings
     float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
     float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
-    // Read supplay voltage
+    // Read supply voltage
     float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20;   // V = 1/20 * Vin
     actVoltage = actVoltage * vslope + voffset;
     if(actVoltage < MIN_VOLTAGE){

From b142470c1de8aa4d48868d8091951fca3abec2c1 Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Sat, 4 Jan 2025 22:24:33 +0100
Subject: [PATCH 14/35] Docu

---
 lib/obp60task/OBP60Extensions.cpp | 1 +
 lib/obp60task/obp60task.cpp       | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index c288bd8..bae2602 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -472,6 +472,7 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
 }
 
 // Function to handle HTTP image request
+// http://192.168.15.1/api/user/OBP60Task/screenshot
 void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request) {
     GwLog *logger = api->getLogger();
 
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 85f9a07..73bd9fe 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -394,6 +394,8 @@ void OBP60Task(GwApi *api){
        }
     }
 
+    // Display screenshot handler for HTTP request
+    // http://192.168.15.1/api/user/OBP60Task/screenshot
     api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
         doImageRequest(api, &pageNumber, pages, request);
     });

From a8d10804290125dd6b61f1f1e1145355aae64c42 Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Sat, 4 Jan 2025 22:26:15 +0100
Subject: [PATCH 15/35] Delete FastLED includes

---
 lib/obp60task/OBP60Extensions.cpp | 5 +----
 lib/obp60task/OBP60Extensions.h   | 3 ---
 2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index bae2602..26e5c2b 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -1,9 +1,6 @@
 #ifdef BOARD_OBP60S3
 
 #include <Arduino.h>
-#define FASTLED_ALL_PINS_HARDWARE_SPI
-#define FASTLED_ESP32_SPI_BUS FSPI
-#define FASTLED_ESP32_FLASH_LOCK 1
 #include <PCF8574.h>      // Driver for PCF8574 output modul from Horter
 #include <Wire.h>         // I2C
 #include <RTClib.h>       // Driver for DS1388 RTC
@@ -468,7 +465,7 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
         getdisplay().setTextColor(pcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(xb-22, yb+20);
-        getdisplay().print("G");
+        getdisplay().print("G");Function to handle HTTP image request
 }
 
 // Function to handle HTTP image request
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index 79695ef..5ab4caa 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -3,9 +3,6 @@
 
 #include <Arduino.h>
 #include "OBP60Hardware.h"
-#define FASTLED_ALL_PINS_HARDWARE_SPI
-#define FASTLED_ESP32_SPI_BUS FSPI
-#define FASTLED_ESP32_FLASH_LOCK 1
 #include "LedSpiTask.h"
 #include <GxEPD2_BW.h>                  // E-paper lib V2
 #include <Adafruit_FRAM_I2C.h>          // I2C FRAM

From 83f3e6f24bc2d666dd2f9f4e1dff5257441512f0 Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Sat, 4 Jan 2025 22:32:19 +0100
Subject: [PATCH 16/35] Fix error

---
 lib/obp60task/OBP60Extensions.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 26e5c2b..2fa4bc6 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -465,7 +465,7 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
         getdisplay().setTextColor(pcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(xb-22, yb+20);
-        getdisplay().print("G");Function to handle HTTP image request
+        getdisplay().print("G");
 }
 
 // Function to handle HTTP image request

From 9930769073f00c5220a250b5a92e042a14aa7fdd Mon Sep 17 00:00:00 2001
From: Tobias E <Tobias.edler@gmail.com>
Date: Mon, 6 Jan 2025 14:36:51 +0000
Subject: [PATCH 17/35] PageRollPitch now accepts 2 config options Fixed
 conversion issue in PageWindRoseFlex gen_set.pl is now obsolete, new version
 in python. modified config.json (mostly reformatting due to gen_set.py),
 added 2 config fields for PageRollPitch

---
 lib/obp60task/PageRollPitch.cpp    |    4 +-
 lib/obp60task/PageWindRoseFlex.cpp |    3 +-
 lib/obp60task/config.json          | 1973 +++++++++++++++++++++++-----
 lib/obp60task/gen_set.pl           |    5 +-
 lib/obp60task/gen_set.py           |  123 ++
 5 files changed, 1805 insertions(+), 303 deletions(-)
 create mode 100755 lib/obp60task/gen_set.py

diff --git a/lib/obp60task/PageRollPitch.cpp b/lib/obp60task/PageRollPitch.cpp
index bb5b0e3..40ba9f5 100644
--- a/lib/obp60task/PageRollPitch.cpp
+++ b/lib/obp60task/PageRollPitch.cpp
@@ -342,9 +342,9 @@ static Page *createPage(CommonData &common){
 PageDescription registerPageRollPitch(
     "RollPitch",        // Page name
     createPage,         // Action
-    0,                  // Number of bus values depends on selection in Web configuration
+    2,                  // Number of bus values depends on selection in Web configuration
    // {"xdrROLL", "xdrPTCH"},// Bus values we need in the page
-    {"xdrRoll", "xdrPitch"},// Bus values we need in the page
+    //{"xdrRoll", "xdrPitch"},// Bus values we need in the page
     true                // Show display header on/off
 );
 
diff --git a/lib/obp60task/PageWindRoseFlex.cpp b/lib/obp60task/PageWindRoseFlex.cpp
index e33b869..7689777 100644
--- a/lib/obp60task/PageWindRoseFlex.cpp
+++ b/lib/obp60task/PageWindRoseFlex.cpp
@@ -186,7 +186,8 @@ public:
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
         getdisplay().setCursor(295, 65);
         if(valid3 == true){
-            getdisplay().print(abs(value3 * 180 / PI), 0);   // Value
+           // getdisplay().print(abs(value3 * 180 / PI), 0);   // Value          
+            getdisplay().print(svalue3);     // Value
         }
         else{
             getdisplay().print("---");                   // Value
diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json
index 9ba0fab..e28a2d6 100644
--- a/lib/obp60task/config.json
+++ b/lib/obp60task/config.json
@@ -920,11 +920,66 @@
         "type": "list",
         "default": "Voltage",
         "description": "Type of page for page 1",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
-        }
+            "obp60": "true"
+        },
+        "condition": [
+            {
+                "visiblePages": 1
+            },
+            {
+                "visiblePages": 2
+            },
+            {
+                "visiblePages": 3
+            },
+            {
+                "visiblePages": 4
+            },
+            {
+                "visiblePages": 5
+            },
+            {
+                "visiblePages": 6
+            },
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page1value1",
@@ -934,9 +989,31 @@
         "description": "The display for field one",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"OneValue"},{"page1type":"TwoValues"},{"page1type":"ThreeValues"},{"page1type":"FourValues"},{"page1type":"FourValues2"},{"page1type":"WindRoseFlex"},{"page1type":"Fluid"}]
+        "condition": [
+            {
+                "page1type": "FourValues"
+            },
+            {
+                "page1type": "FourValues2"
+            },
+            {
+                "page1type": "OneValue"
+            },
+            {
+                "page1type": "RollPitch"
+            },
+            {
+                "page1type": "ThreeValues"
+            },
+            {
+                "page1type": "TwoValues"
+            },
+            {
+                "page1type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page1value2",
@@ -946,57 +1023,107 @@
         "description": "The display for field two",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"TwoValues"},{"page1type":"ThreeValues"},{"page1type":"FourValues"},{"page1type":"FourValues2"},{"page1type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page1type": "FourValues"
+            },
+            {
+                "page1type": "FourValues2"
+            },
+            {
+                "page1type": "RollPitch"
+            },
+            {
+                "page1type": "ThreeValues"
+            },
+            {
+                "page1type": "TwoValues"
+            },
+            {
+                "page1type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page1value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"ThreeValues"},{"page1type":"FourValues"},{"page1type":"FourValues2"},{"page1type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page1type": "FourValues"
+            },
+            {
+                "page1type": "FourValues2"
+            },
+            {
+                "page1type": "ThreeValues"
+            },
+            {
+                "page1type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page1value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"FourValues"},{"page1type":"FourValues2"},{"page1type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page1type": "FourValues"
+            },
+            {
+                "page1type": "FourValues2"
+            },
+            {
+                "page1type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page1value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page1type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page1value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page1type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page1fluid",
@@ -1004,20 +1131,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 1",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page1type":"Fluid"}]
+        "condition": [
+            {
+                "page1type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page2type",
@@ -1025,12 +1177,63 @@
         "type": "list",
         "default": "WindRose",
         "description": "Type of page for page 2",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"2"},{"visiblePages":"3"},{"visiblePages":"4"},{"visiblePages":"5"},{"visiblePages":"6"},{"visiblePages":"7"},{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 2
+            },
+            {
+                "visiblePages": 3
+            },
+            {
+                "visiblePages": 4
+            },
+            {
+                "visiblePages": 5
+            },
+            {
+                "visiblePages": 6
+            },
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page2value1",
@@ -1040,9 +1243,31 @@
         "description": "The display for field one",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"OneValue"},{"page2type":"TwoValues"},{"page2type":"ThreeValues"},{"page2type":"FourValues"},{"page2type":"FourValues2"},{"page2type":"WindRoseFlex"},{"page2type":"Fluid"}]
+        "condition": [
+            {
+                "page2type": "FourValues"
+            },
+            {
+                "page2type": "FourValues2"
+            },
+            {
+                "page2type": "OneValue"
+            },
+            {
+                "page2type": "RollPitch"
+            },
+            {
+                "page2type": "ThreeValues"
+            },
+            {
+                "page2type": "TwoValues"
+            },
+            {
+                "page2type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page2value2",
@@ -1052,57 +1277,107 @@
         "description": "The display for field two",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"TwoValues"},{"page2type":"ThreeValues"},{"page2type":"FourValues"},{"page2type":"FourValues2"},{"page2type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page2type": "FourValues"
+            },
+            {
+                "page2type": "FourValues2"
+            },
+            {
+                "page2type": "RollPitch"
+            },
+            {
+                "page2type": "ThreeValues"
+            },
+            {
+                "page2type": "TwoValues"
+            },
+            {
+                "page2type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page2value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"ThreeValues"},{"page2type":"FourValues"},{"page2type":"FourValues2"},{"page2type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page2type": "FourValues"
+            },
+            {
+                "page2type": "FourValues2"
+            },
+            {
+                "page2type": "ThreeValues"
+            },
+            {
+                "page2type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page2value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"FourValues"},{"page2type":"FourValues2"},{"page2type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page2type": "FourValues"
+            },
+            {
+                "page2type": "FourValues2"
+            },
+            {
+                "page2type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page2value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page2type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page2value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page2type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page2fluid",
@@ -1110,20 +1385,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 2",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page2type":"Fluid"}]
+        "condition": [
+            {
+                "page2type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page3type",
@@ -1131,24 +1431,94 @@
         "type": "list",
         "default": "OneValue",
         "description": "Type of page for page 3",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"3"},{"visiblePages":"4"},{"visiblePages":"5"},{"visiblePages":"6"},{"visiblePages":"7"},{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 3
+            },
+            {
+                "visiblePages": 4
+            },
+            {
+                "visiblePages": 5
+            },
+            {
+                "visiblePages": 6
+            },
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page3value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "AWA",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"OneValue"},{"page3type":"TwoValues"},{"page3type":"ThreeValues"},{"page3type":"FourValues"},{"page3type":"FourValues2"},{"page3type":"WindRoseFlex"},{"page3type":"Fluid"}]
+        "condition": [
+            {
+                "page3type": "FourValues"
+            },
+            {
+                "page3type": "FourValues2"
+            },
+            {
+                "page3type": "OneValue"
+            },
+            {
+                "page3type": "RollPitch"
+            },
+            {
+                "page3type": "ThreeValues"
+            },
+            {
+                "page3type": "TwoValues"
+            },
+            {
+                "page3type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page3value2",
@@ -1158,57 +1528,107 @@
         "description": "The display for field two",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"TwoValues"},{"page3type":"ThreeValues"},{"page3type":"FourValues"},{"page3type":"FourValues2"},{"page3type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page3type": "FourValues"
+            },
+            {
+                "page3type": "FourValues2"
+            },
+            {
+                "page3type": "RollPitch"
+            },
+            {
+                "page3type": "ThreeValues"
+            },
+            {
+                "page3type": "TwoValues"
+            },
+            {
+                "page3type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page3value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"ThreeValues"},{"page3type":"FourValues"},{"page3type":"FourValues2"},{"page3type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page3type": "FourValues"
+            },
+            {
+                "page3type": "FourValues2"
+            },
+            {
+                "page3type": "ThreeValues"
+            },
+            {
+                "page3type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page3value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"FourValues"},{"page3type":"FourValues2"},{"page3type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page3type": "FourValues"
+            },
+            {
+                "page3type": "FourValues2"
+            },
+            {
+                "page3type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page3value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page3type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page3value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page3type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page3fluid",
@@ -1216,20 +1636,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 3",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page3type":"Fluid"}]
+        "condition": [
+            {
+                "page3type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page4type",
@@ -1237,84 +1682,201 @@
         "type": "list",
         "default": "TwoValues",
         "description": "Type of page for page 4",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"4"},{"visiblePages":"5"},{"visiblePages":"6"},{"visiblePages":"7"},{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 4
+            },
+            {
+                "visiblePages": 5
+            },
+            {
+                "visiblePages": 6
+            },
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page4value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "STW",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"OneValue"},{"page4type":"TwoValues"},{"page4type":"ThreeValues"},{"page4type":"FourValues"},{"page4type":"FourValues2"},{"page4type":"WindRoseFlex"},{"page4type":"Fluid"}]
+        "condition": [
+            {
+                "page4type": "FourValues"
+            },
+            {
+                "page4type": "FourValues2"
+            },
+            {
+                "page4type": "OneValue"
+            },
+            {
+                "page4type": "RollPitch"
+            },
+            {
+                "page4type": "ThreeValues"
+            },
+            {
+                "page4type": "TwoValues"
+            },
+            {
+                "page4type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page4value2",
         "label": "Field 2",
         "type": "boatData",
-        "default": "DBT",
+        "default": "",
         "description": "The display for field two",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"TwoValues"},{"page4type":"ThreeValues"},{"page4type":"FourValues"},{"page4type":"FourValues2"},{"page4type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page4type": "FourValues"
+            },
+            {
+                "page4type": "FourValues2"
+            },
+            {
+                "page4type": "RollPitch"
+            },
+            {
+                "page4type": "ThreeValues"
+            },
+            {
+                "page4type": "TwoValues"
+            },
+            {
+                "page4type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page4value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"ThreeValues"},{"page4type":"FourValues"},{"page4type":"FourValues2"},{"page4type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page4type": "FourValues"
+            },
+            {
+                "page4type": "FourValues2"
+            },
+            {
+                "page4type": "ThreeValues"
+            },
+            {
+                "page4type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page4value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"FourValues"},{"page4type":"FourValues2"},{"page4type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page4type": "FourValues"
+            },
+            {
+                "page4type": "FourValues2"
+            },
+            {
+                "page4type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page4value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page4type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page4value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page4type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page4fluid",
@@ -1322,20 +1884,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 4",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page4type":"Fluid"}]
+        "condition": [
+            {
+                "page4type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page5type",
@@ -1343,84 +1930,198 @@
         "type": "list",
         "default": "ThreeValues",
         "description": "Type of page for page 5",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"5"},{"visiblePages":"6"},{"visiblePages":"7"},{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 5
+            },
+            {
+                "visiblePages": 6
+            },
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page5value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "COG",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"OneValue"},{"page5type":"TwoValues"},{"page5type":"ThreeValues"},{"page5type":"FourValues"},{"page5type":"FourValues2"},{"page4type":"WindRoseFlex"},{"page5type":"Fluid"}]
+        "condition": [
+            {
+                "page5type": "FourValues"
+            },
+            {
+                "page5type": "FourValues2"
+            },
+            {
+                "page5type": "OneValue"
+            },
+            {
+                "page5type": "RollPitch"
+            },
+            {
+                "page5type": "ThreeValues"
+            },
+            {
+                "page5type": "TwoValues"
+            },
+            {
+                "page5type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page5value2",
         "label": "Field 2",
         "type": "boatData",
-        "default": "STW",
+        "default": "",
         "description": "The display for field two",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"TwoValues"},{"page5type":"ThreeValues"},{"page5type":"FourValues"},{"page5type":"FourValues2"},{"page4type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page5type": "FourValues"
+            },
+            {
+                "page5type": "FourValues2"
+            },
+            {
+                "page5type": "RollPitch"
+            },
+            {
+                "page5type": "ThreeValues"
+            },
+            {
+                "page5type": "TwoValues"
+            },
+            {
+                "page5type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page5value3",
         "label": "Field 3",
         "type": "boatData",
-        "default": "DBT",
-        "description": "The display for field 3",
+        "default": "",
+        "description": "The display for field three",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"ThreeValues"},{"page5type":"FourValues"},{"page5type":"FourValues2"},{"page5type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page5type": "FourValues"
+            },
+            {
+                "page5type": "FourValues2"
+            },
+            {
+                "page5type": "ThreeValues"
+            },
+            {
+                "page5type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page5value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"FourValues"},{"page5type":"FourValues2"},{"page5type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page5type": "FourValues"
+            },
+            {
+                "page5type": "FourValues2"
+            },
+            {
+                "page5type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page5value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page5type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page5value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page5type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page5fluid",
@@ -1428,20 +2129,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 5",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page5type":"Fluid"}]
+        "condition": [
+            {
+                "page5type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page6type",
@@ -1449,84 +2175,195 @@
         "type": "list",
         "default": "FourValues",
         "description": "Type of page for page 6",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"6"},{"visiblePages":"7"},{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 6
+            },
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page6value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "AWA",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"OneValue"},{"page6type":"TwoValues"},{"page6type":"ThreeValues"},{"page6type":"FourValues"},{"page6type":"FourValues2"},{"page6type":"WindRoseFlex"},{"page6type":"Fluid"}]
+        "condition": [
+            {
+                "page6type": "FourValues"
+            },
+            {
+                "page6type": "FourValues2"
+            },
+            {
+                "page6type": "OneValue"
+            },
+            {
+                "page6type": "RollPitch"
+            },
+            {
+                "page6type": "ThreeValues"
+            },
+            {
+                "page6type": "TwoValues"
+            },
+            {
+                "page6type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page6value2",
         "label": "Field 2",
         "type": "boatData",
-        "default": "AWS",
+        "default": "",
         "description": "The display for field two",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"TwoValues"},{"page6type":"ThreeValues"},{"page6type":"FourValues"},{"page6type":"FourValues2"},{"page6type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page6type": "FourValues"
+            },
+            {
+                "page6type": "FourValues2"
+            },
+            {
+                "page6type": "RollPitch"
+            },
+            {
+                "page6type": "ThreeValues"
+            },
+            {
+                "page6type": "TwoValues"
+            },
+            {
+                "page6type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page6value3",
         "label": "Field 3",
         "type": "boatData",
-        "default": "COG",
-        "description": "The display for field 3",
+        "default": "",
+        "description": "The display for field three",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"ThreeValues"},{"page6type":"FourValues"},{"page6type":"FourValues2"},{"page6type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page6type": "FourValues"
+            },
+            {
+                "page6type": "FourValues2"
+            },
+            {
+                "page6type": "ThreeValues"
+            },
+            {
+                "page6type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page6value4",
         "label": "Field 4",
         "type": "boatData",
-        "default": "STW",
-        "description": "The display for field 4",
+        "default": "",
+        "description": "The display for field four",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"FourValues"},{"page6type":"FourValues2"},{"page6type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page6type": "FourValues"
+            },
+            {
+                "page6type": "FourValues2"
+            },
+            {
+                "page6type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page6value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page6type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page6value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page6type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page6fluid",
@@ -1534,20 +2371,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 6",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page6type":"Fluid"}]
+        "condition": [
+            {
+                "page6type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page7type",
@@ -1555,84 +2417,192 @@
         "type": "list",
         "default": "FourValues2",
         "description": "Type of page for page 7",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"7"},{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 7
+            },
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page7value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "AWA",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"OneValue"},{"page7type":"TwoValues"},{"page7type":"ThreeValues"},{"page7type":"FourValues"},{"page7type":"FourValues2"},{"page7type":"WindRoseFlex"},{"page7type":"Fluid"}]
+        "condition": [
+            {
+                "page7type": "FourValues"
+            },
+            {
+                "page7type": "FourValues2"
+            },
+            {
+                "page7type": "OneValue"
+            },
+            {
+                "page7type": "RollPitch"
+            },
+            {
+                "page7type": "ThreeValues"
+            },
+            {
+                "page7type": "TwoValues"
+            },
+            {
+                "page7type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page7value2",
         "label": "Field 2",
         "type": "boatData",
-        "default": "AWS",
+        "default": "",
         "description": "The display for field two",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"TwoValues"},{"page7type":"ThreeValues"},{"page7type":"FourValues"},{"page7type":"FourValues2"},{"page7type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page7type": "FourValues"
+            },
+            {
+                "page7type": "FourValues2"
+            },
+            {
+                "page7type": "RollPitch"
+            },
+            {
+                "page7type": "ThreeValues"
+            },
+            {
+                "page7type": "TwoValues"
+            },
+            {
+                "page7type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page7value3",
         "label": "Field 3",
         "type": "boatData",
-        "default": "COG",
-        "description": "The display for field 3",
+        "default": "",
+        "description": "The display for field three",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"ThreeValues"},{"page7type":"FourValues"},{"page7type":"FourValues2"},{"page7type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page7type": "FourValues"
+            },
+            {
+                "page7type": "FourValues2"
+            },
+            {
+                "page7type": "ThreeValues"
+            },
+            {
+                "page7type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page7value4",
         "label": "Field 4",
         "type": "boatData",
-        "default": "STW",
-        "description": "The display for field 4",
+        "default": "",
+        "description": "The display for field four",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"FourValues"},{"page7type":"FourValues2"},{"page7type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page7type": "FourValues"
+            },
+            {
+                "page7type": "FourValues2"
+            },
+            {
+                "page7type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page7value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page7type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page7value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page7type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page7fluid",
@@ -1640,20 +2610,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 7",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page7type":"Fluid"}]
+        "condition": [
+            {
+                "page7type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page8type",
@@ -1661,24 +2656,79 @@
         "type": "list",
         "default": "Clock",
         "description": "Type of page for page 8",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"8"},{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 8
+            },
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page8value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "AWS",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"OneValue"},{"page8type":"TwoValues"},{"page8type":"ThreeValues"},{"page8type":"FourValues"},{"page8type":"FourValues2"},{"page8type":"WindRoseFlex"},{"page8type":"Fluid"}]
+        "condition": [
+            {
+                "page8type": "FourValues"
+            },
+            {
+                "page8type": "FourValues2"
+            },
+            {
+                "page8type": "OneValue"
+            },
+            {
+                "page8type": "RollPitch"
+            },
+            {
+                "page8type": "ThreeValues"
+            },
+            {
+                "page8type": "TwoValues"
+            },
+            {
+                "page8type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page8value2",
@@ -1688,57 +2738,107 @@
         "description": "The display for field two",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"TwoValues"},{"page8type":"ThreeValues"},{"page8type":"FourValues"},{"page8type":"FourValues2"},{"page8type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page8type": "FourValues"
+            },
+            {
+                "page8type": "FourValues2"
+            },
+            {
+                "page8type": "RollPitch"
+            },
+            {
+                "page8type": "ThreeValues"
+            },
+            {
+                "page8type": "TwoValues"
+            },
+            {
+                "page8type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page8value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"ThreeValues"},{"page8type":"FourValues"},{"page8type":"FourValues2"},{"page8type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page8type": "FourValues"
+            },
+            {
+                "page8type": "FourValues2"
+            },
+            {
+                "page8type": "ThreeValues"
+            },
+            {
+                "page8type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page8value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"FourValues"},{"page8type":"FourValues2"},{"page88type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page8type": "FourValues"
+            },
+            {
+                "page8type": "FourValues2"
+            },
+            {
+                "page8type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page8value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page8type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page8value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page8type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page8fluid",
@@ -1746,20 +2846,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 8",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page8type":"Fluid"}]
+        "condition": [
+            {
+                "page8type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page9type",
@@ -1767,24 +2892,76 @@
         "type": "list",
         "default": "RollPitch",
         "description": "Type of page for page 9",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"9"},{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 9
+            },
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page9value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "AWS",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"OneValue"},{"page9type":"TwoValues"},{"page9type":"ThreeValues"},{"page9type":"FourValues"},{"page9type":"FourValues2"},{"page9type":"WindRoseFlex"},{"page9type":"Fluid"}]
+        "condition": [
+            {
+                "page9type": "FourValues"
+            },
+            {
+                "page9type": "FourValues2"
+            },
+            {
+                "page9type": "OneValue"
+            },
+            {
+                "page9type": "RollPitch"
+            },
+            {
+                "page9type": "ThreeValues"
+            },
+            {
+                "page9type": "TwoValues"
+            },
+            {
+                "page9type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page9value2",
@@ -1794,57 +2971,107 @@
         "description": "The display for field two",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"TwoValues"},{"page9type":"ThreeValues"},{"page9type":"FourValues"},{"page9type":"FourValues2"},{"page9type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page9type": "FourValues"
+            },
+            {
+                "page9type": "FourValues2"
+            },
+            {
+                "page9type": "RollPitch"
+            },
+            {
+                "page9type": "ThreeValues"
+            },
+            {
+                "page9type": "TwoValues"
+            },
+            {
+                "page9type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page9value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"ThreeValues"},{"page9type":"FourValues"},{"page9type":"FourValues2"},{"page9type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page9type": "FourValues"
+            },
+            {
+                "page9type": "FourValues2"
+            },
+            {
+                "page9type": "ThreeValues"
+            },
+            {
+                "page9type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page9value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"FourValues"},{"page9type":"FourValues2"},{"page9type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page9type": "FourValues"
+            },
+            {
+                "page9type": "FourValues2"
+            },
+            {
+                "page9type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page9value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page9type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page9value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page9type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page9fluid",
@@ -1852,20 +3079,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 9",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page9type":"Fluid"}]
+        "condition": [
+            {
+                "page9type": "Fluid"
+            }
+        ]
     },
     {
         "name": "page10type",
@@ -1873,24 +3125,73 @@
         "type": "list",
         "default": "Battery2",
         "description": "Type of page for page 10",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list": [
+            "ApparentWind",
+            "BME280",
+            "Battery",
+            "Battery2",
+            "Clock",
+            "DST810",
+            "Fluid",
+            "FourValues",
+            "FourValues2",
+            "Generator",
+            "KeelPosition",
+            "OneValue",
+            "RollPitch",
+            "RudderPosition",
+            "Solar",
+            "ThreeValues",
+            "TwoValues",
+            "Voltage",
+            "White",
+            "WindRose",
+            "WindRoseFlex",
+            "XTETrack"
+        ],
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"visiblePages":"10"}]
+        "condition": [
+            {
+                "visiblePages": 10
+            }
+        ]
     },
     {
         "name": "page10value1",
         "label": "Field 1",
         "type": "boatData",
-        "default": "AWS",
+        "default": "",
         "description": "The display for field one",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"OneValue"},{"page10type":"TwoValues"},{"page10type":"ThreeValues"},{"page10type":"FourValues"},{"page10type":"FourValues2"},{"page10type":"WindRoseFlex"},{"page10type":"Fluid"}]
+        "condition": [
+            {
+                "page10type": "FourValues"
+            },
+            {
+                "page10type": "FourValues2"
+            },
+            {
+                "page10type": "OneValue"
+            },
+            {
+                "page10type": "RollPitch"
+            },
+            {
+                "page10type": "ThreeValues"
+            },
+            {
+                "page10type": "TwoValues"
+            },
+            {
+                "page10type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page10value2",
@@ -1900,57 +3201,107 @@
         "description": "The display for field two",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"TwoValues"},{"page10type":"ThreeValues"},{"page10type":"FourValues"},{"page10type":"FourValues2"},{"page10type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page10type": "FourValues"
+            },
+            {
+                "page10type": "FourValues2"
+            },
+            {
+                "page10type": "RollPitch"
+            },
+            {
+                "page10type": "ThreeValues"
+            },
+            {
+                "page10type": "TwoValues"
+            },
+            {
+                "page10type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page10value3",
         "label": "Field 3",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 3",
+        "description": "The display for field three",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"ThreeValues"},{"page10type":"FourValues"},{"page10type":"FourValues2"},{"page10type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page10type": "FourValues"
+            },
+            {
+                "page10type": "FourValues2"
+            },
+            {
+                "page10type": "ThreeValues"
+            },
+            {
+                "page10type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page10value4",
         "label": "Field 4",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 4",
+        "description": "The display for field four",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"FourValues"},{"page10type":"FourValues2"},{"page10type":"WindRoseFlex"}]
-    },   
+        "condition": [
+            {
+                "page10type": "FourValues"
+            },
+            {
+                "page10type": "FourValues2"
+            },
+            {
+                "page10type": "WindRoseFlex"
+            }
+        ]
+    },
     {
         "name": "page10value5",
         "label": "Field 5",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 5",
+        "description": "The display for field five",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page10type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page10value6",
         "label": "Field 6",
         "type": "boatData",
         "default": "",
-        "description": "The display for field 6",
+        "description": "The display for field six",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"WindRoseFlex"}]
+        "condition": [
+            {
+                "page10type": "WindRoseFlex"
+            }
+        ]
     },
     {
         "name": "page10fluid",
@@ -1958,19 +3309,45 @@
         "type": "list",
         "default": "0",
         "list": [
-            {"l":"Fuel (0)","v":"0"},
-            {"l":"Water (1)","v":"1"},
-            {"l":"Gray Water (2)","v":"2"},
-            {"l":"Live Well (3)","v":"3"},
-            {"l":"Oil (4)","v":"4"},
-            {"l":"Black Water (5)","v":"5"},
-            {"l":"Fuel Gasoline (6)","v":"6"}
+            {
+                "l": "Fuel (0)",
+                "v": "0"
+            },
+            {
+                "l": "Water (1)",
+                "v": "1"
+            },
+            {
+                "l": "Gray Water (2)",
+                "v": "2"
+            },
+            {
+                "l": "Live Well (3)",
+                "v": "3"
+            },
+            {
+                "l": "Oil (4)",
+                "v": "4"
+            },
+            {
+                "l": "Black Water (5)",
+                "v": "5"
+            },
+            {
+                "l": "Fuel Gasoline (6)",
+                "v": "6"
+            }
         ],
         "description": "Fluid type in tank",
         "category": "OBP60 Page 10",
         "capabilities": {
-            "obp60":"true"
+            "obp60": "true"
         },
-        "condition":[{"page10type":"Fluid"}]
+        "condition": [
+            {
+                "page10type": "Fluid"
+            }
+        ]
     }
 ]
+
diff --git a/lib/obp60task/gen_set.pl b/lib/obp60task/gen_set.pl
index 0f7c588..3c74904 100755
--- a/lib/obp60task/gen_set.pl
+++ b/lib/obp60task/gen_set.pl
@@ -1,6 +1,7 @@
 #!/bin/perl -w
 #A tool to generate the part of config.json that deals with pages and fields.
-
+#DEPRECATED, moved to get_set.py
+die "Please use gen_set.py instead";
 #List of all pages and the number of parameters they expect.
 %NoOfFieldsPerPage=qw( 
                 ApparentWind    0
@@ -81,7 +82,7 @@ for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
         print "\t",'"condition":[';
         foreach $page (@Pages) {
             if($NoOfFieldsPerPage{$page}>=$FieldNo){ 
-                print '{"page1type":"',$page,'"},';
+                print '{"page',$PageNo,'type":"',$page,'"},';
             } 
         } 
         print "\b],\n";
diff --git a/lib/obp60task/gen_set.py b/lib/obp60task/gen_set.py
new file mode 100755
index 0000000..d0ff7e5
--- /dev/null
+++ b/lib/obp60task/gen_set.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python3
+# A tool to generate that part of config.json  that deals with pages and fields.
+
+import json
+
+# List of all pages and the number of parameters they expect.
+no_of_fields_per_page = {
+    "ApparentWind": 0,
+    "XTETrack": 0,
+    "Battery2": 0,
+    "Battery": 0,
+    "BME280": 0,
+    "Clock": 0,
+    "DST810": 0,
+    "Fluid": 0,
+    "FourValues2": 4,
+    "FourValues": 4,
+    "Generator": 0,
+    "KeelPosition": 0,
+    "OneValue": 1,
+    "RollPitch": 2,
+    "RudderPosition": 0,
+    "Solar": 0,
+    "ThreeValues": 3,
+    "TwoValues": 2,
+    "Voltage": 0,
+    "White": 0,
+    "WindRose": 0,
+    "WindRoseFlex": 6,
+}
+
+# No changes needed beyond this point
+# max number of pages supported by OBP60
+no_of_pages = 10
+# Default selection for each page
+default_pages = [
+    "Voltage",
+    "WindRose",
+    "OneValue",
+    "TwoValues",
+    "ThreeValues",
+    "FourValues",
+    "FourValues2",
+    "Clock",
+    "RollPitch",
+    "Battery2",
+]
+numbers = [
+    "one",
+    "two",
+    "three",
+    "four",
+    "five",
+    "six",
+    "seven",
+    "eight",
+    "nine",
+    "ten",
+]
+pages = sorted(no_of_fields_per_page.keys())
+max_no_of_fields_per_page = max(no_of_fields_per_page.values())
+
+output = []
+
+for page_no in range(1, no_of_pages + 1):
+    page_data = {
+        "name": f"page{page_no}type",
+        "label": "Type",
+        "type": "list",
+        "default": default_pages[page_no - 1],
+        "description": f"Type of page for page {page_no}",
+        "list": pages,
+        "category": f"OBP60 Page {page_no}",
+        "capabilities": {"obp60": "true"},
+        "condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
+        #"fields": [],
+    }
+    output.append(page_data)
+
+    for field_no in range(1, max_no_of_fields_per_page + 1):
+        field_data = {
+            "name": f"page{page_no}value{field_no}",
+            "label": f"Field {field_no}",
+            "type": "boatData",
+            "default": "",
+            "description": f"The display for field {numbers[field_no - 1]}",
+            "category": f"OBP60 Page {page_no}",
+            "capabilities": {"obp60": "true"},
+            "condition": [
+                {f"page{page_no}type": page}
+                for page in pages
+                if no_of_fields_per_page[page] >= field_no
+            ],
+        }
+        output.append(field_data)
+
+    fluid_data ={
+        "name": f"page{page_no}fluid",
+        "label": "Fluid type",
+        "type": "list",
+        "default": "0",
+        "list": [
+        {"l":"Fuel (0)","v":"0"},
+        {"l":"Water (1)","v":"1"},
+        {"l":"Gray Water (2)","v":"2"},
+        {"l":"Live Well (3)","v":"3"},
+        {"l":"Oil (4)","v":"4"},
+        {"l":"Black Water (5)","v":"5"},
+        {"l":"Fuel Gasoline (6)","v":"6"}
+        ],
+        "description": "Fluid type in tank",
+        "category": f"OBP60 Page {page_no}",
+        "capabilities": {
+        "obp60":"true"
+        },
+        "condition":[{f"page{page_no}type":"Fluid"}]
+        } 
+    output.append(fluid_data)
+
+json_output = json.dumps(output, indent=4)
+# print omitting first and last line containing [ ] of JSON array
+print(json_output[1:-1])
+# print(",")
\ No newline at end of file

From be48929c40888d85795372378c5b2ab4f1d5b4d0 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Wed, 8 Jan 2025 14:26:52 +0100
Subject: [PATCH 18/35] Changed ApparentWind to Wind with modes and lens
 function

---
 lib/obp60task/OBP60Extensions.h    |   3 +
 lib/obp60task/PageApparentWind.cpp | 192 ---------
 lib/obp60task/PageWind.cpp         | 650 +++++++++++++++++++++++++++++
 lib/obp60task/config.json          |  20 +-
 lib/obp60task/obp60task.cpp        |   4 +-
 5 files changed, 665 insertions(+), 204 deletions(-)
 delete mode 100644 lib/obp60task/PageApparentWind.cpp
 create mode 100644 lib/obp60task/PageWind.cpp

diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index 5ab4caa..fcb1f29 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -12,6 +12,9 @@
 #define FRAM_VOLTAGE_AVG 0x000A
 #define FRAM_VOLTAGE_TREND 0x000B
 #define FRAM_VOLTAGE_MODE 0x000C
+#define FRAM_WIND_SIZE 0x000D
+#define FRAM_WIND_SRC 0x000E
+#define FRAM_WIND_MODE 0x000F
 // Barograph history data
 #define FRAM_BAROGRAPH_START 0x0400
 #define FRAM_BAROGRAPH_END 0x13FF
diff --git a/lib/obp60task/PageApparentWind.cpp b/lib/obp60task/PageApparentWind.cpp
deleted file mode 100644
index 50be31c..0000000
--- a/lib/obp60task/PageApparentWind.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-#ifdef BOARD_OBP60S3
-
-#include "Pagedata.h"
-#include "OBP60Extensions.h"
-
-class PageApparentWind : public Page
-{
-bool keylock = false;               // Keylock
-int16_t lp = 80;                    // Pointer length
-
-public:
-    PageApparentWind(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageApparentWind");
-    }
-
-    // Key functions
-    virtual int handleKey(int key){
-        // Reduce instrument size
-        if(key == 2){               // Code for reduce
-            lp = lp - 10;
-            if(lp < 10){
-                lp = 10;
-            }
-            return 0;               // Commit the key
-        }
-
-        // Enlarge instrument size
-        if(key == 5){               // Code for enlarge
-            lp = lp + 10;
-            if(lp > 80){
-                lp = 80;
-            }
-            return 0;               // Commit the key
-        }
-
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
-            return 0;               // Commit the key
-        }
-        return key;
-    }
-
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
-
-        static String svalue1old = "";
-        static String unit1old = "";
-        static String svalue2old = "";
-        static String unit2old = "";
-
-        // Get config data
-        String lengthformat = config->getString(config->lengthFormat);
-        // bool simulation = config->getBool(config->useSimuData);
-        bool holdvalues = config->getBool(config->holdvalues);
-        String flashLED = config->getString(config->flashLED);
-        String backlightMode = config->getString(config->backlight);
-
-        // Get boat values for AWS
-        GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
-        String name1 = bvalue1->getName().c_str();      // Value name
-        name1 = name1.substring(0, 6);                  // String length limit for value name
-        double value1 = bvalue1->value;                 // Value as double in SI unit
-        // bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
-
-        // Get boat values for AWD
-        GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
-        String name2 = bvalue2->getName().c_str();      // Value name
-        name2 = name2.substring(0, 6);                  // String length limit for value name
-        double value2 = bvalue2->value;                 // Value as double in SI unit
-        // bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
-
-        // Optical warning by limit violation (unused)
-        if(String(flashLED) == "Limit Violation"){
-            setBlinkingLED(false);
-            setFlashLED(false); 
-        }
-
-        // Logging boat values
-        if (bvalue1 == NULL) return;
-        LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f,  %s:%f", name1.c_str(), value1, name2.c_str(), value2);
-
-        // Draw page
-        //***********************************************************
-
-        // Set display in partial refresh mode
-        getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
-
-        getdisplay().setTextColor(commonData.fgcolor);
-
-        // Show values AWS
-        getdisplay().setFont(&Ubuntu_Bold20pt7b);
-        getdisplay().setCursor(20, 50);
-        if(holdvalues == false){
-            getdisplay().print(name1);                       // Value name
-            getdisplay().print(": ");
-            getdisplay().print(svalue1);                     // Value
-            getdisplay().print(" ");
-            getdisplay().print(unit1);                       // Unit
-        }
-        else{
-            getdisplay().print(name1);                       // Value name
-            getdisplay().print(": ");
-            getdisplay().print(svalue1old);                  // Value old
-            getdisplay().print(" ");
-            getdisplay().print(unit1old);                    // Unit old
-        }
-
-        // Show values AWD
-        getdisplay().setFont(&Ubuntu_Bold20pt7b);
-        getdisplay().setCursor(20, 260);
-        if(holdvalues == false){
-            getdisplay().print(name2);                       // Value name
-            getdisplay().print(": ");
-            getdisplay().print(svalue2);                     // Value
-            getdisplay().print(" ");
-            getdisplay().print(unit2);                       // Unit
-        }
-        else{
-            getdisplay().print(name2);                       // Value name
-            getdisplay().print(": ");
-            getdisplay().print(svalue2old);                  // Value old
-            getdisplay().print(" ");
-            getdisplay().print(unit2old);                    // Unit old
-        }
-
-        // Draw wind pointer
-        static int16_t x0 = 200;    // Center point
-        static int16_t y0 = 145;
-        static int16_t x1 = x0;     // Start point for pointer
-        static int16_t y1 = y0;
-        static int16_t x2 = x0;     // End point for pointer
-        static int16_t y2 = y0;
-
-        //Draw instrument
-        getdisplay().fillCircle(x0, y0, lp + 5, commonData.fgcolor);
-        getdisplay().fillCircle(x0, y0, lp + 1, commonData.bgcolor);
-
-        // Calculation end point of pointer
-        value2 = value2 - 3.14 / 2;
-        x1 = x0 + cos(value2) * lp * 0.6;
-        y1 = y0 + sin(value2) * lp * 0.6;
-        x2 = x0 + cos(value2) * lp;
-        y2 = y0 + sin(value2) * lp;
-        getdisplay().drawLine(x1, y1, x2, y2, commonData.fgcolor);
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
-
-        // Update display
-        getdisplay().nextPage();     // Partial update (fast)
-
-    };
-};
-
-static Page *createPage(CommonData &common){
-    return new PageApparentWind(common);
-}
-/**
- * with the code below we make this page known to the PageTask
- * we give it a type (name) that can be selected in the config
- * we define which function is to be called
- * and we provide the number of user parameters we expect (0 here)
- * and will will provide the names of the fixed values we need
- */
-PageDescription registerPageApparentWind(
-    "ApparentWind",     // Page name
-    createPage,         // Action
-    0,                  // Number of bus values depends on selection in Web configuration
-    {"AWS","AWA"},      // Bus values we need in the page
-    true                // Show display header on/off
-);
-
-#endif
diff --git a/lib/obp60task/PageWind.cpp b/lib/obp60task/PageWind.cpp
new file mode 100644
index 0000000..c28caa9
--- /dev/null
+++ b/lib/obp60task/PageWind.cpp
@@ -0,0 +1,650 @@
+#ifdef BOARD_OBP60S3
+
+#include "Pagedata.h"
+#include "OBP60Extensions.h"
+#include "N2kMessages.h"
+
+#define front_width 120
+#define front_height 162
+static unsigned char front_bits[] PROGMEM = {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x03,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xfc, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0x7f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+   0xff, 0xf3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xc0, 0xff, 0xe1, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xc1, 0xff, 0x01, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x80, 0xff,
+   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+   0x7f, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xf0, 0x7f, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0xfe, 0x0f, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0xfe,
+   0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+   0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xf0,
+   0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+   0x03, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x80, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x01, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x80,
+   0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
+   0x00, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00,
+   0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f,
+   0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
+   0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07,
+   0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
+   0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x00,
+   0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
+   0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
+   0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
+   0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0,
+   0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
+   0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
+   0x07, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0,
+   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00,
+   0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+   0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
+   0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
+   0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x80, 0x0f,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00,
+   0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x03,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
+   0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0xe0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x01,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
+   0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x80, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x78, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
+   0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x3e, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
+   0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0e, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
+   0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xf8, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01,
+   0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
+   0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
+   0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+   0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x0f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
+   0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+   0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x18, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+   0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+   0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+   0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
+   0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+   0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
+   0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
+   0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 };
+
+class PageWind : public Page
+{
+bool keylock = false;               // Keylock
+int8_t lp = 80;                     // Pointer length
+char mode = 'N';                    // page mode (N)ormal | (L)ens | e(X)ample
+char source = 'A';                  // data source (A)pparent | (T)rue
+
+public:
+    PageWind(CommonData &common){
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageWind");
+        if (hasFRAM) {
+            lp = fram.read(FRAM_WIND_SIZE);
+            source = fram.read(FRAM_WIND_SRC);
+            mode = fram.read(FRAM_WIND_MODE);
+        }
+    }
+
+    // Key functions
+    virtual int handleKey(int key){
+
+        if(key == 1){               // Mode switch
+            if(mode == 'N'){
+                mode = 'L';
+            } else if (mode == 'L') {
+                mode = 'X';
+            } else {
+                mode = 'N';
+            }
+            if (hasFRAM) fram.write(FRAM_WIND_MODE, mode);
+            return 0;               // Commit the key
+        }
+
+        if(key == 3){               // Source switch
+            if(source == 'A'){
+                source = 'T';
+            } else {
+                source = 'A';
+            }
+            if (hasFRAM) fram.write(FRAM_WIND_SRC, source);
+            return 0;               // Commit the key
+        }
+
+        // Reduce instrument size
+        if(key == 2 && mode == 'N'){    // Code for reduce
+            lp = lp - 10;
+            if(lp < 10){
+                lp = 10;
+            }
+            if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
+            return 0;               // Commit the key
+        }
+
+        // Enlarge instrument size
+        if(key == 5 && mode == 'N'){    // Code for enlarge
+            lp = lp + 10;
+            if(lp > 80){
+                lp = 80;
+            }
+            if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
+            return 0;               // Commit the key
+        }
+
+        // Keylock function
+        if(key == 11){              // Code for keylock
+            keylock = !keylock;     // Toggle keylock
+            return 0;               // Commit the key
+        }
+        return key;
+    }
+
+    virtual void displayPage(CommonData &commonData, PageData &pageData)
+    {
+        GwConfigHandler *config = commonData.config;
+        GwLog *logger=commonData.logger;
+
+        static String svalue1old = "";
+        static String unit1old = "";
+        static String svalue2old = "";
+        static String unit2old = "";
+
+        // Get config data
+        String lengthformat = config->getString(config->lengthFormat);
+        // bool simulation = config->getBool(config->useSimuData);
+        bool holdvalues = config->getBool(config->holdvalues);
+        String flashLED = config->getString(config->flashLED);
+        String backlightMode = config->getString(config->backlight);
+
+        GwApi::BoatValue *bvalue1; // Value 1 for speed on top
+        GwApi::BoatValue *bvalue2; // Value 2 for angle on bottom
+
+        // Get boat values for speed (AWS/TWS)
+        if (source == 'A') {
+            bvalue1 = pageData.values[0];
+        } else {
+            bvalue1 = pageData.values[2];
+        }
+        String name1 = bvalue1->getName().c_str();      // Value name
+        name1 = name1.substring(0, 6);                  // String length limit for value name
+        double value1 = bvalue1->value;                 // Value as double in SI unit
+        // bool valid1 = bvalue1->valid;                   // Valid information
+        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+
+        // Get boat values for angle (AWD/TWD)
+        if (source == 'A') {
+            bvalue2 = pageData.values[1];
+        } else {
+            bvalue2 = pageData.values[3];
+        }
+        String name2 = bvalue2->getName().c_str();      // Value name
+        name2 = name2.substring(0, 6);                  // String length limit for value name
+        double value2 = bvalue2->value;                 // Value as double in SI unit
+        // bool valid2 = bvalue2->valid;                   // Valid information
+        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+
+        // Optical warning by limit violation (unused)
+        if(String(flashLED) == "Limit Violation"){
+            setBlinkingLED(false);
+            setFlashLED(false); 
+        }
+
+        // Logging boat values
+        if (bvalue1 == NULL) return;
+        LOG_DEBUG(GwLog::LOG,"Drawing at PageWind, %s:%f,  %s:%f", name1.c_str(), value1, name2.c_str(), value2);
+
+        // Draw page
+        //***********************************************************
+
+        // Set display in partial refresh mode
+        getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
+
+        getdisplay().setTextColor(commonData.fgcolor);
+
+
+        if (mode == 'X') {
+            // Original example code with scaling circle
+
+            // Show values AWS/TWS
+            getdisplay().setFont(&Ubuntu_Bold20pt7b);
+            getdisplay().setCursor(20, 50);
+            getdisplay().print(name1);                       // Value name
+            getdisplay().print(": ");
+            if(holdvalues == false){
+                getdisplay().print(svalue1);                     // Value
+                getdisplay().print(" ");
+                getdisplay().print(unit1);                       // Unit
+            }
+            else{
+                getdisplay().print(svalue1old);                  // Value old
+                getdisplay().print(" ");
+                getdisplay().print(unit1old);                    // Unit old
+            }
+
+            // Show values AWD/TWD
+            getdisplay().setFont(&Ubuntu_Bold20pt7b);
+            getdisplay().setCursor(20, 260);
+            getdisplay().print(name2);                       // Value name
+            getdisplay().print(": ");
+            if(holdvalues == false){
+                getdisplay().print(svalue2);                     // Value
+                getdisplay().print(" ");
+                getdisplay().print(unit2);                       // Unit
+            }
+            else{
+                getdisplay().print(svalue2old);                  // Value old
+                getdisplay().print(" ");
+                getdisplay().print(unit2old);                    // Unit old
+            }
+
+            Point c = {200, 145};
+
+            // Draw instrument
+            getdisplay().fillCircle(c.x, c.y, lp + 5, commonData.fgcolor);
+            getdisplay().fillCircle(c.x, c.y, lp + 1, commonData.bgcolor);
+
+            // Wind pointer
+            if (bvalue2->valid) {
+                uint8_t lp0 = lp * 0.6; // effective pointer outside size
+                uint8_t lp1 = lp * 0.4; // effective pointer inside size
+                // zero position
+                std::vector<Point> pts = {
+                    {c.x, c.y - lp},
+                    {c.x - 7, c.y - lp + lp0},
+                    {c.x, c.y - lp + lp1},
+                    {c.x + 7, c.y - lp + lp0}
+                };
+                fillPoly4(rotatePoints(c, pts, RadToDeg(value2)), commonData.fgcolor);
+            } else {
+                getdisplay().setFont(&Ubuntu_Bold12pt7b);
+                drawTextCenter(c.x, c.y, "no data");
+            }
+
+        } else if (mode == 'L') { // Mode (L)ens
+
+            Point c = {200, 155};
+            uint16_t r = 150;
+
+            Point p;
+            std::vector<Point> pts = { // polygon lines
+                {c.x - 2, c.y - r},
+                {c.x + 2, c.y - r},
+                {c.x + 2, c.y - (r - 16)},
+                {c.x - 2, c.y - (r - 16)}
+            };
+            int angle;
+
+            getdisplay().setFont(&Ubuntu_Bold12pt7b);
+
+            // starbord
+            // text with line
+            angle = 20;
+            for (int i = 30; i < 150; i += 30) {
+                  p = rotatePoint(c, {c.x, c.y - r + 40}, i);
+                  drawTextCenter(p.x, p.y, String(angle));
+                  angle += 10;
+                  fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
+            }
+            // dots
+            for (int i = 30; i < 138; i += 6) {
+                 if (i % 15 != 0) {
+                      p = rotatePoint(c, {c.x, c.y - r + 5}, i);
+                      getdisplay().fillCircle(p.x, p.y, 2, commonData.fgcolor);
+                 }
+            }
+
+            // port
+            angle = 50;
+            // text with line
+            for (int i = 240; i <= 330; i += 30) {
+                  p = rotatePoint(c, {c.x, c.y - r + 40}, i);
+                  drawTextCenter(p.x, p.y, String(angle));
+                  angle -= 10;
+                  fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
+            }
+            // dots
+            for (int i = 228; i < 330; i += 6) {
+                 if (i % 15 != 0) {
+                      p = rotatePoint(c, {c.x, c.y - r + 5}, i);
+                      getdisplay().fillCircle(p.x, p.y, 2, commonData.fgcolor);
+                 }
+            }
+
+            // data source
+            getdisplay().setFont(&Ubuntu_Bold12pt7b);
+            getdisplay().setCursor(8, 50);
+            if (source == 'A') {
+                getdisplay().print("APP");
+            } else {
+                getdisplay().print("TRUE");
+            }
+
+            // Wind pointer (angle)
+            if (bvalue2->valid) {
+                float alpha = RadToDeg(value2);
+                bool port = (alpha > 180);
+                if (port) {
+                    alpha = 360 - alpha;
+                }
+                if (alpha < 15) {
+                    alpha = 15; // stop at start of scale
+                } else if (alpha > 55) {
+                    alpha = 55; // stop at end of scale
+                }
+                alpha = 3 * alpha - 30; // convert to lens scale
+                if (port) {
+                    alpha *= -1;
+                }
+
+                getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
+                pts = {
+                    {c.x - 1, c.y - (r - 20)},
+                    {c.x + 1, c.y - (r - 20)},
+                    {c.x + 6, c.y + 15},
+                    {c.x - 6, c.y + 15}
+                };
+                fillPoly4(rotatePoints(c, pts, alpha), commonData.fgcolor);
+                getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
+            } else {
+                getdisplay().setFont(&Ubuntu_Bold12pt7b);
+                drawTextCenter(c.x, c.y, "no data");
+            }
+
+            // Wind speed as decimal number
+            getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
+            getdisplay().setCursor(150, 250);
+            if (holdvalues == false) {
+                getdisplay().print(svalue1);
+            } else {
+                getdisplay().print(svalue1old);
+            }
+            // unit
+            getdisplay().setFont(&Ubuntu_Bold8pt7b);
+            getdisplay().setCursor(220, 265);
+            getdisplay().print("kts");
+        }
+        else {
+            // Normal mode
+
+            // data source
+            getdisplay().setFont(&Ubuntu_Bold12pt7b);
+            getdisplay().setCursor(8, 50);
+            if (source == 'A') {
+                getdisplay().print("APP");
+            } else {
+                getdisplay().print("TRUE");
+            }
+
+            // draw ship front symbol (as bitmap)
+            getdisplay().drawXBitmap(140, 30, front_bits, front_width, front_height, commonData.fgcolor);
+
+            Point c = {200, 155};
+            uint16_t r = 150;
+
+            Point p;
+            std::vector<Point> pts = { // polygon lines
+                {c.x - 2, c.y - r},
+                {c.x + 2, c.y - r},
+                {c.x + 2, c.y - (r - 16)},
+                {c.x - 2, c.y - (r - 16)}
+            };
+            int angle;
+
+            // starbord
+            // text with line
+            for (int i = 30; i < 150; i += 30) {
+                  p = rotatePoint(c, {c.x, c.y - r + 40}, i);
+                  drawTextCenter(p.x, p.y, String(i));
+                  fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
+            }
+            // dots
+            for (int i = 30; i < 150; i += 10) {
+                 if (i % 30 != 0) {
+                      p = rotatePoint(c, {c.x, c.y - r + 5}, i);
+                      getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
+                 }
+            }
+
+            // port
+            // text with line
+            angle = 120;
+            for (int i = 240; i <= 330; i += 30) {
+                  p = rotatePoint(c, {c.x, c.y - r + 40}, i);
+                  drawTextCenter(p.x, p.y, String(angle));
+                  angle -= 30;
+                  fillPoly4(rotatePoints(c, pts, i), commonData.fgcolor);
+            }
+            // dots
+            for (int i = 210; i < 340; i += 10) {
+                 if (i % 30 != 0) {
+                      p = rotatePoint(c, {c.x, c.y - r + 5}, i);
+                      getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
+                 }
+            }
+
+            // Wind speed as decimal number
+            getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
+            getdisplay().setCursor(150, 250);
+            if (holdvalues == false) {
+                getdisplay().print(svalue1);
+            } else {
+                getdisplay().print(svalue1old);
+            }
+            // unit
+            getdisplay().setFont(&Ubuntu_Bold8pt7b);
+            getdisplay().setCursor(220, 265);
+            getdisplay().print("kts");
+
+            // Wind pointer (angle)
+            if (bvalue2->valid) {
+                float alpha = RadToDeg(value2);
+                getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
+                pts = {
+                    {c.x - 1, c.y - (r - 20)},
+                    {c.x + 1, c.y - (r - 20)},
+                    {c.x + 6, c.y + 15},
+                    {c.x - 6, c.y + 15}
+                };
+                fillPoly4(rotatePoints(c, pts, alpha), commonData.fgcolor);
+                getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
+            } else {
+                getdisplay().setFont(&Ubuntu_Bold12pt7b);
+                drawTextCenter(c.x, c.y, "no data");
+            }
+
+        }
+
+        // Key Layout
+        getdisplay().setFont(&Ubuntu_Bold8pt7b);
+        if(keylock == false){
+            getdisplay().setCursor(10, 290);
+            getdisplay().print("[MODE]");
+            getdisplay().setCursor(130, 290);
+            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+
+            if (mode == 'X') {
+                getdisplay().setCursor(85, 290);
+                getdisplay().print("[ - ]");
+                getdisplay().setCursor(295, 290);
+                getdisplay().print("[ + ]");
+            }
+
+            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
+                getdisplay().setCursor(343, 290);
+                getdisplay().print("[ILUM]");
+            }
+        }
+        else{
+            getdisplay().setCursor(130, 290);
+            getdisplay().print(" [    Keylock active    ]");
+        }
+
+        // Update display
+        getdisplay().nextPage();     // Partial update (fast)
+
+    };
+};
+
+static Page *createPage(CommonData &common){
+    return new PageWind(common);
+}
+/**
+ * with the code below we make this page known to the PageTask
+ * we give it a type (name) that can be selected in the config
+ * we define which function is to be called
+ * and we provide the number of user parameters we expect (0 here)
+ * and will will provide the names of the fixed values we need
+ */
+PageDescription registerPageWind(
+    "Wind",             // Page name
+    createPage,         // Action
+    0,                  // Number of bus values depends on selection in Web configuration
+    {"AWS","AWA", "TWS", "TWA"}, // Bus values we need in the page
+    true                // Show display header on/off
+);
+
+#endif
diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json
index 9ba0fab..2b4c528 100644
--- a/lib/obp60task/config.json
+++ b/lib/obp60task/config.json
@@ -920,7 +920,7 @@
         "type": "list",
         "default": "Voltage",
         "description": "Type of page for page 1",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 1",
         "capabilities": {
             "obp60":"true"
@@ -1025,7 +1025,7 @@
         "type": "list",
         "default": "WindRose",
         "description": "Type of page for page 2",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 2",
         "capabilities": {
             "obp60":"true"
@@ -1131,7 +1131,7 @@
         "type": "list",
         "default": "OneValue",
         "description": "Type of page for page 3",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 3",
         "capabilities": {
             "obp60":"true"
@@ -1237,7 +1237,7 @@
         "type": "list",
         "default": "TwoValues",
         "description": "Type of page for page 4",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 4",
         "capabilities": {
             "obp60":"true"
@@ -1343,7 +1343,7 @@
         "type": "list",
         "default": "ThreeValues",
         "description": "Type of page for page 5",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 5",
         "capabilities": {
             "obp60":"true"
@@ -1449,7 +1449,7 @@
         "type": "list",
         "default": "FourValues",
         "description": "Type of page for page 6",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 6",
         "capabilities": {
             "obp60":"true"
@@ -1555,7 +1555,7 @@
         "type": "list",
         "default": "FourValues2",
         "description": "Type of page for page 7",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 7",
         "capabilities": {
             "obp60":"true"
@@ -1661,7 +1661,7 @@
         "type": "list",
         "default": "Clock",
         "description": "Type of page for page 8",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 8",
         "capabilities": {
             "obp60":"true"
@@ -1767,7 +1767,7 @@
         "type": "list",
         "default": "RollPitch",
         "description": "Type of page for page 9",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 9",
         "capabilities": {
             "obp60":"true"
@@ -1873,7 +1873,7 @@
         "type": "list",
         "default": "Battery2",
         "description": "Type of page for page 10",
-        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","ApparentWind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
+        "list":["OneValue","TwoValues","ThreeValues","FourValues","FourValues2","Wind","WindRose","WindRoseFlex","Voltage","DST810","Clock","WhitePage","BME280","RudderPosition","KeelPosition","Battery","Battery2","RollPitch","Solar","Generator","XTETrack","Fluid"],
         "category": "OBP60 Page 10",
         "capabilities": {
             "obp60":"true"
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 73bd9fe..a2bf5a9 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -205,8 +205,8 @@ void registerAllPages(PageList &list){
     list.add(&registerPageFourValues);
     extern PageDescription registerPageFourValues2;
     list.add(&registerPageFourValues2);
-    extern PageDescription registerPageApparentWind;
-    list.add(&registerPageApparentWind);
+    extern PageDescription registerPageWind;
+    list.add(&registerPageWind);
     extern PageDescription registerPageWindRose;
     list.add(&registerPageWindRose);
     extern PageDescription registerPageWindRoseFlex;

From 8d43189140829882744389cc9b468f4b9e6c4b64 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Wed, 8 Jan 2025 14:52:44 +0100
Subject: [PATCH 19/35] Fix zoom keycodes

---
 lib/obp60task/PageWind.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/PageWind.cpp b/lib/obp60task/PageWind.cpp
index c28caa9..d37801a 100644
--- a/lib/obp60task/PageWind.cpp
+++ b/lib/obp60task/PageWind.cpp
@@ -254,7 +254,7 @@ public:
         }
 
         // Reduce instrument size
-        if(key == 2 && mode == 'N'){    // Code for reduce
+        if(key == 2 && mode == 'X'){    // Code for reduce
             lp = lp - 10;
             if(lp < 10){
                 lp = 10;
@@ -264,7 +264,7 @@ public:
         }
 
         // Enlarge instrument size
-        if(key == 5 && mode == 'N'){    // Code for enlarge
+        if(key == 5 && mode == 'X'){    // Code for enlarge
             lp = lp + 10;
             if(lp > 80){
                 lp = 80;

From e4af7cf731cad3b66d2b5173717a86b9a2550e0c Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Fri, 10 Jan 2025 19:41:55 +0100
Subject: [PATCH 20/35] Move page number, swipe and lock indicator to header

---
 lib/obp60task/OBP60Extensions.cpp    | 19 ++++---
 lib/obp60task/OBP60Extensions.h      | 20 +++++++-
 lib/obp60task/PageApparentWind.cpp   | 40 ++++++---------
 lib/obp60task/PageBME280.cpp         | 36 ++++++-------
 lib/obp60task/PageBattery.cpp        | 56 +++++++++-----------
 lib/obp60task/PageBattery2.cpp       | 60 ++++++++++------------
 lib/obp60task/PageClock.cpp          | 69 +++++++++++--------------
 lib/obp60task/PageDST810.cpp         | 50 ++++++++----------
 lib/obp60task/PageFluid.cpp          | 66 +++++++++++-------------
 lib/obp60task/PageFourValues.cpp     | 48 ++++++++---------
 lib/obp60task/PageFourValues2.cpp    | 48 ++++++++---------
 lib/obp60task/PageGenerator.cpp      | 34 +++++-------
 lib/obp60task/PageKeelPosition.cpp   | 55 +++++++++-----------
 lib/obp60task/PageOneValue.cpp       | 33 +++++-------
 lib/obp60task/PageRollPitch.cpp      | 62 ++++++++++------------
 lib/obp60task/PageRudderPosition.cpp | 48 ++++++++---------
 lib/obp60task/PageSolar.cpp          | 35 +++++--------
 lib/obp60task/PageThreeValues.cpp    | 42 +++++++--------
 lib/obp60task/PageTwoValues.cpp      | 32 ++++++------
 lib/obp60task/PageVoltage.cpp        | 73 ++++++++++++--------------
 lib/obp60task/PageWhite.cpp          | 16 +++---
 lib/obp60task/PageWindRose.cpp       | 77 +++++++++++++---------------
 lib/obp60task/PageWindRoseFlex.cpp   | 77 +++++++++++++---------------
 lib/obp60task/PageXTETrack.cpp       | 51 +++++++++---------
 lib/obp60task/Pagedata.h             |  7 ++-
 lib/obp60task/obp60task.cpp          |  5 +-
 26 files changed, 527 insertions(+), 632 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 2fa4bc6..85393e1 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -314,16 +314,23 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
         usbRxOld = commonData.status.usbRx;
         usbTxOld = commonData.status.usbTx;
 
+        // Display key lock status
+        if (commonData.keylock) {
+            getdisplay().drawXBitmap(150, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
+        } else {
+            getdisplay().drawXBitmap(150, 1, swipe_bits, icon_width, icon_height, commonData.fgcolor);
+        }
+
+        // Current page number in a small box
+        getdisplay().setFont(&Ubuntu_Bold8pt7b);
+        getdisplay().drawRect(170, 2, 20, 15, textcolor);
+        drawTextCenter(179, 9, String(commonData.data.actpage));
+
         // Heartbeat as dot
         getdisplay().setTextColor(textcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(205, 14);
-        if(heartbeat == true){
-        getdisplay().print(".");
-        }
-        else{
-        getdisplay().print(" ");
-        }
+        getdisplay().print(heartbeat ? "." : " ");
         heartbeat = !heartbeat; 
 
         // Date and time
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index 5ab4caa..effeddd 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -9,6 +9,8 @@
 
 // FRAM address reservations 32kB: 0x0000 - 0x7FFF
 // 0x0000 - 0x03ff: single variables
+#define FRAM_PAGE_NO 0x0002
+// Voltage page
 #define FRAM_VOLTAGE_AVG 0x000A
 #define FRAM_VOLTAGE_TREND 0x000B
 #define FRAM_VOLTAGE_MODE 0x000C
@@ -19,7 +21,7 @@
 extern Adafruit_FRAM_I2C fram;
 extern bool hasFRAM;
 
-// Fonts declarations for display (#inclues see OBP60Extensions.cpp)
+// Fonts declarations for display (#includes see OBP60Extensions.cpp)
 extern const GFXfont Ubuntu_Bold8pt7b;
 extern const GFXfont Ubuntu_Bold10pt7b;
 extern const GFXfont Ubuntu_Bold12pt7b;
@@ -32,7 +34,21 @@ extern const GFXfont DSEG7Classic_BoldItalic30pt7b;
 extern const GFXfont DSEG7Classic_BoldItalic42pt7b;
 extern const GFXfont DSEG7Classic_BoldItalic60pt7b;
 
-// Gloabl functions
+// Icons
+#define icon_width 16
+#define icon_height 16
+
+static unsigned char swipe_bits[] PROGMEM = {
+   0x80, 0x03, 0xe0, 0x06, 0xb0, 0x0a, 0xa8, 0x0a, 0xa8, 0x0a, 0xa8, 0x3a,
+   0x28, 0x28, 0x08, 0x28, 0x08, 0x28, 0x08, 0x26, 0x08, 0x21, 0x08, 0x10,
+   0x10, 0x08, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00 };
+
+static unsigned char lock_bits[] PROGMEM = {
+   0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
+   0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
+   0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
+
+// Global functions
 #ifdef DISPLAY_GDEW042T2
 GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
 #endif
diff --git a/lib/obp60task/PageApparentWind.cpp b/lib/obp60task/PageApparentWind.cpp
index 50be31c..6f0713b 100644
--- a/lib/obp60task/PageApparentWind.cpp
+++ b/lib/obp60task/PageApparentWind.cpp
@@ -5,12 +5,12 @@
 
 class PageApparentWind : public Page
 {
-bool keylock = false;               // Keylock
 int16_t lp = 80;                    // Pointer length
 
 public:
     PageApparentWind(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageApparentWind");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageApparentWind");
     }
 
     // Key functions
@@ -33,18 +33,18 @@ public:
             return 0;               // Commit the key
         }
 
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
+    virtual void displayPage(PageData &pageData)
     {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         static String svalue1old = "";
         static String unit1old = "";
@@ -64,8 +64,8 @@ public:
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         // bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Get boat values for AWD
         GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
@@ -73,8 +73,8 @@ public:
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         // bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -92,7 +92,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show values AWS
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -139,8 +139,8 @@ public:
         static int16_t y2 = y0;
 
         //Draw instrument
-        getdisplay().fillCircle(x0, y0, lp + 5, commonData.fgcolor);
-        getdisplay().fillCircle(x0, y0, lp + 1, commonData.bgcolor);
+        getdisplay().fillCircle(x0, y0, lp + 5, commonData->fgcolor);
+        getdisplay().fillCircle(x0, y0, lp + 1, commonData->bgcolor);
 
         // Calculation end point of pointer
         value2 = value2 - 3.14 / 2;
@@ -148,22 +148,16 @@ public:
         y1 = y0 + sin(value2) * lp * 0.6;
         x2 = x0 + cos(value2) * lp;
         y2 = y0 + sin(value2) * lp;
-        getdisplay().drawLine(x1, y1, x2, y2, commonData.fgcolor);
+        getdisplay().drawLine(x1, y1, x2, y2, commonData->fgcolor);
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();     // Partial update (fast)
diff --git a/lib/obp60task/PageBME280.cpp b/lib/obp60task/PageBME280.cpp
index d7893d2..3b68de6 100644
--- a/lib/obp60task/PageBME280.cpp
+++ b/lib/obp60task/PageBME280.cpp
@@ -5,24 +5,24 @@
 
 class PageBME280 : public Page
 {
-    bool keylock = false;               // Keylock
-
     public:
     PageBME280(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageBME280");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageBME280");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         double value1 = 0;
         double value2 = 0;
@@ -42,7 +42,7 @@ class PageBME280 : public Page
         String name1 = "Temp";                          // Value name
         name1 = name1.substring(0, 6);                  // String length limit for value name
         if(simulation == false){
-            value1 = commonData.data.airTemperature;    // Value as double in SI unit 
+            value1 = commonData->data.airTemperature;    // Value as double in SI unit
         }
         else{
             value1 = 23.0 + float(random(0, 10)) / 10.0;
@@ -60,7 +60,7 @@ class PageBME280 : public Page
         String name2 = "Humid";                         // Value name
         name2 = name2.substring(0, 6);                  // String length limit for value name
         if(simulation == false){
-            value2 = commonData.data.airHumidity;       // Value as double in SI unit 
+            value2 = commonData->data.airHumidity;       // Value as double in SI unit
         }
         else{
             value2 = 43 + float(random(0, 4));
@@ -78,7 +78,7 @@ class PageBME280 : public Page
         String name3 = "Press";                         // Value name
         name3 = name3.substring(0, 6);                  // String length limit for value name
          if(simulation == false){
-            value3 = commonData.data.airPressure;       // Value as double in SI unit 
+            value3 = commonData->data.airPressure;       // Value as double in SI unit
         }
         else{
             value3 = 1006 + float(random(0, 5));
@@ -107,7 +107,7 @@ class PageBME280 : public Page
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // ############### Value 1 ################
 
@@ -131,7 +131,7 @@ class PageBME280 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -155,7 +155,7 @@ class PageBME280 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
 
         // ############### Value 3 ################
 
@@ -180,18 +180,12 @@ class PageBME280 : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageBattery.cpp b/lib/obp60task/PageBattery.cpp
index 6322981..1b12d93 100644
--- a/lib/obp60task/PageBattery.cpp
+++ b/lib/obp60task/PageBattery.cpp
@@ -5,12 +5,12 @@
 
 class PageBattery : public Page
 {
-    bool keylock = false;               // Keylock
     int average = 0;                    // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
 
     public:
     PageBattery(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageBattery");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery");
     }
 
     virtual int handleKey(int key){
@@ -23,15 +23,15 @@ class PageBattery : public Page
 
         // Code for keylock
         if(key == 11){
-            keylock = !keylock;         // Toggle keylock
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
         
         // Old values for hold function
         double value1 = 0;
@@ -58,19 +58,19 @@ class PageBattery : public Page
             // Switch average values
             switch (average) {
                 case 0:
-                    value1 = commonData.data.batteryVoltage;        // Live data
+                    value1 = commonData->data.batteryVoltage;        // Live data
                     break;
                 case 1:
-                    value1 = commonData.data.batteryVoltage10;      // Average 10s
+                    value1 = commonData->data.batteryVoltage10;      // Average 10s
                     break;
                 case 2:
-                    value1 = commonData.data.batteryVoltage60;      // Average 60s
+                    value1 = commonData->data.batteryVoltage60;      // Average 60s
                     break;
                 case 3:
-                    value1 = commonData.data.batteryVoltage300;     // Average 300s
+                    value1 = commonData->data.batteryVoltage300;     // Average 300s
                     break;
                 default:
-                     value1 = commonData.data.batteryVoltage;       // Default
+                     value1 = commonData->data.batteryVoltage;       // Default
                     break;
             }
         }
@@ -87,19 +87,19 @@ class PageBattery : public Page
         if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
             switch (average) {
                 case 0:
-                    value2 = commonData.data.batteryCurrent;        // Live data
+                    value2 = commonData->data.batteryCurrent;        // Live data
                     break;
                 case 1:
-                    value2 = commonData.data.batteryCurrent10;      // Average 10s
+                    value2 = commonData->data.batteryCurrent10;      // Average 10s
                     break;
                 case 2:
-                    value2 = commonData.data.batteryCurrent60;      // Average 60s
+                    value2 = commonData->data.batteryCurrent60;      // Average 60s
                     break;
                 case 3:
-                    value2 = commonData.data.batteryCurrent300;     // Average 300s
+                    value2 = commonData->data.batteryCurrent300;     // Average 300s
                     break;
                 default:
-                     value2 = commonData.data.batteryCurrent;       // Default
+                     value2 = commonData->data.batteryCurrent;       // Default
                     break;
             }
         }
@@ -116,19 +116,19 @@ class PageBattery : public Page
         if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
             switch (average) {
                 case 0:
-                    value3 = commonData.data.batteryPower;        // Live data
+                    value3 = commonData->data.batteryPower;        // Live data
                     break;
                 case 1:
-                    value3 = commonData.data.batteryPower10;      // Average 10s
+                    value3 = commonData->data.batteryPower10;      // Average 10s
                     break;
                 case 2:
-                    value3 = commonData.data.batteryPower60;      // Average 60s
+                    value3 = commonData->data.batteryPower60;      // Average 60s
                     break;
                 case 3:
-                    value3 = commonData.data.batteryPower300;     // Average 300s
+                    value3 = commonData->data.batteryPower300;     // Average 300s
                     break;
                 default:
-                     value3 = commonData.data.batteryPower;       // Default
+                     value3 = commonData->data.batteryPower;       // Default
                     break;
             }
         }
@@ -156,7 +156,7 @@ class PageBattery : public Page
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // Show average settings
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         switch (average) {
             case 0:
@@ -228,7 +228,7 @@ class PageBattery : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -257,7 +257,7 @@ class PageBattery : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
 
         // ############### Value 3 ################
 
@@ -288,20 +288,14 @@ class PageBattery : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
+        if(commonData->keylock == false){
             getdisplay().setCursor(10, 290);
             getdisplay().print("[AVG]");
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
             if(String(backlightMode) == "Control by Key"){              // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageBattery2.cpp b/lib/obp60task/PageBattery2.cpp
index 8c3bd44..4cb4a40 100644
--- a/lib/obp60task/PageBattery2.cpp
+++ b/lib/obp60task/PageBattery2.cpp
@@ -7,14 +7,14 @@
 class PageBattery2 : public Page
 {
 bool init = false;                  // Marker for init done
-bool keylock = false;               // Keylock
 int average = 0;                    // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
 bool trend = true;                  // Trend indicator [0|1], 0=off, 1=on
 double raw = 0;
 
 public:
     PageBattery2(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageBattery2");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery2");
     }
     virtual int handleKey(int key){
          // Change average
@@ -32,16 +32,16 @@ public:
 
         // Code for keylock
         if(key == 11){
-            keylock = !keylock;         // Toggle keylock
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
+    virtual void displayPage(PageData &pageData)
     {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Polynominal coefficients second order for battery energy level calculation
         // index 0 = Pb, 1 = Gel, 2 = AGM, 3 = LiFePo4
@@ -71,42 +71,42 @@ public:
 
         // Create trend value
         if(init == false){          // Load start values for first page run
-            valueTrend = commonData.data.batteryVoltage10;
+            valueTrend = commonData->data.batteryVoltage10;
             init = true;
         }
         else{                       // Reading trend value
-            valueTrend = commonData.data.batteryVoltage10;
+            valueTrend = commonData->data.batteryVoltage10;
         }
 
         // Get raw value for trend indicator
-        raw = commonData.data.batteryVoltage;        // Live data
+        raw = commonData->data.batteryVoltage;        // Live data
 
         // Switch average values
         switch (average) {
             case 0:
-                value1 = commonData.data.batteryVoltage;        // Live data
-                value2 = commonData.data.batteryCurrent;
-                value3 = commonData.data.batteryPower;
+                value1 = commonData->data.batteryVoltage;        // Live data
+                value2 = commonData->data.batteryCurrent;
+                value3 = commonData->data.batteryPower;
                 break;
             case 1:
-                value1 = commonData.data.batteryVoltage10;      // Average 10s
-                value2 = commonData.data.batteryCurrent10;
-                value3 = commonData.data.batteryPower10;
+                value1 = commonData->data.batteryVoltage10;      // Average 10s
+                value2 = commonData->data.batteryCurrent10;
+                value3 = commonData->data.batteryPower10;
                 break;
             case 2:
-                value1 = commonData.data.batteryVoltage60;      // Average 60s
-                value2 = commonData.data.batteryCurrent60;
-                value3 = commonData.data.batteryPower60;
+                value1 = commonData->data.batteryVoltage60;      // Average 60s
+                value2 = commonData->data.batteryCurrent60;
+                value3 = commonData->data.batteryPower60;
                 break;
             case 3:
-                value1 = commonData.data.batteryVoltage300;     // Average 300s
-                value2 = commonData.data.batteryCurrent300;
-                value3 = commonData.data.batteryPower300;
+                value1 = commonData->data.batteryVoltage300;     // Average 300s
+                value2 = commonData->data.batteryCurrent300;
+                value3 = commonData->data.batteryPower300;
                 break;
             default:
-                value1 = commonData.data.batteryVoltage;        // Default
-                value2 = commonData.data.batteryCurrent;
-                value3 = commonData.data.batteryPower;
+                value1 = commonData->data.batteryVoltage;        // Default
+                value2 = commonData->data.batteryCurrent;
+                value3 = commonData->data.batteryPower;
                 break;
         }
         bool valid1 = true;
@@ -180,7 +180,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show name
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -219,7 +219,7 @@ public:
         getdisplay().print("Battery Type");
 
         // Show battery with fill level
-        batteryGraphic(150, 45, batPercentage, commonData.fgcolor, commonData.bgcolor);
+        batteryGraphic(150, 45, batPercentage, commonData->fgcolor, commonData->bgcolor);
 
         // Show average settings
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -330,20 +330,14 @@ public:
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
+        if(commonData->keylock == false){
             getdisplay().setCursor(10, 290);
             getdisplay().print("[AVG]");
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
             if(String(backlightMode) == "Control by Key"){              // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageClock.cpp b/lib/obp60task/PageClock.cpp
index c93949b..f99679a 100644
--- a/lib/obp60task/PageClock.cpp
+++ b/lib/obp60task/PageClock.cpp
@@ -5,27 +5,26 @@
 
 class PageClock : public Page
 {
-bool keylock = false;               // Keylock
-
 public:
     PageClock(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageClock");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageClock");
     }
 
     // Key functions
     virtual int handleKey(int key){
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+         // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
+    virtual void displayPage(PageData &pageData)
     {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         static String svalue1old = "";
         static String unit1old = "";
@@ -61,8 +60,8 @@ public:
             value1 = 38160;                             // Simulation data for time value 11:36 in seconds
         }                                               // Other simulation data see OBP60Formater.cpp
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
         if(valid1 == true){
             svalue1old = svalue1;   	                // Save old value
             unit1old = unit1;                           // Save old unit
@@ -74,8 +73,8 @@ public:
         name2 = name2.substring(0, 6);                  // String length limit for value name
         value2 = bvalue2->value;                        // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
         if(valid2 == true){
             svalue2old = svalue2;   	                // Save old value
             unit2old = unit2;                           // Save old unit
@@ -87,8 +86,8 @@ public:
         name3 = name3.substring(0, 6);                  // String length limit for value name
         value3 = bvalue3->value;                        // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
         if(valid3 == true){
             svalue3old = svalue3;   	                // Save old value
             unit3old = unit3;                           // Save old unit
@@ -110,7 +109,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show values GPS date
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -122,7 +121,7 @@ public:
         getdisplay().print("Date");                          // Name
 
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
 
         // Show values GPS time
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -136,7 +135,7 @@ public:
         // Show values sunrise
         String sunrise = "---";
         if(valid1 == true && valid2 == true && valid3 == true){
-            sunrise = String(commonData.sundata.sunriseHour) + ":" + String(commonData.sundata.sunriseMinute + 100).substring(1);
+            sunrise = String(commonData->sundata.sunriseHour) + ":" + String(commonData->sundata.sunriseMinute + 100).substring(1);
             svalue5old = sunrise;
         }
 
@@ -149,12 +148,12 @@ public:
         getdisplay().print("SunR");                          // Name
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
 
         // Show values sunset
         String sunset = "---";
         if(valid1 == true && valid2 == true && valid3 == true){
-            sunset = String(commonData.sundata.sunsetHour) + ":" +  String(commonData.sundata.sunsetMinute + 100).substring(1);
+            sunset = String(commonData->sundata.sunsetHour) + ":" +  String(commonData->sundata.sunsetMinute + 100).substring(1);
             svalue6old = sunset;
         }
 
@@ -172,8 +171,8 @@ public:
         int rInstrument = 110;     // Radius of clock
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor);     // Outer circle
 
         for(int i=0; i<360; i=i+1)
         {
@@ -214,7 +213,7 @@ public:
              if(i % 6 == 0){
                 float x1c = 200 + rInstrument*sin(i/180.0*pi);
                 float y1c = 150 - rInstrument*cos(i/180.0*pi);
-                getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
+                getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
                 sinx=sin(i/180.0*pi);
                 cosx=cos(i/180.0*pi);
              }
@@ -228,10 +227,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
             }
         }
 
@@ -270,7 +269,7 @@ public:
             float yy2 = -(rInstrument * 0.5); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -280,7 +279,7 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
         }
 
         // Draw minute pointer
@@ -296,7 +295,7 @@ public:
             float yy2 = -(rInstrument - 15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -306,28 +305,22 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
 
 //*******************************************************************************************
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageDST810.cpp b/lib/obp60task/PageDST810.cpp
index 89f6e7b..568e3e2 100644
--- a/lib/obp60task/PageDST810.cpp
+++ b/lib/obp60task/PageDST810.cpp
@@ -5,24 +5,24 @@
 
 class PageDST810 : public Page
 {
-    bool keylock = false;               // Keylock
-
-    public:
+public:
     PageDST810(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageDST810");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageDST810");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Old values for hold function
         static String svalue1old = "";
@@ -47,8 +47,8 @@ class PageDST810 : public Page
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Get boat values #2
         GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ class PageDST810 : public Page
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
 
         // Get boat values #3
         GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ class PageDST810 : public Page
         name3 = name3.substring(0, 6);                  // String length limit for value name
         double value3 = bvalue3->value;                 // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
 
         // Get boat values #4
         GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ class PageDST810 : public Page
         name4 = name4.substring(0, 6);                  // String length limit for value name
         double value4 = bvalue4->value;                 // Value as double in SI unit
         bool valid4 = bvalue4->valid;                   // Valid information 
-        String svalue4 = formatValue(bvalue4, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit4 = formatValue(bvalue4, commonData).unit;        // Unit of value
+        String svalue4 = formatValue(bvalue4, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit4 = formatValue(bvalue4, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -93,7 +93,7 @@ class PageDST810 : public Page
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // ############### Value 1 ################
 
@@ -131,7 +131,7 @@ class PageDST810 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -169,7 +169,7 @@ class PageDST810 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
 
         // ############### Value 3 ################
 
@@ -207,7 +207,7 @@ class PageDST810 : public Page
         // ############### Vertical Line ################
 
         // Vertical line 3 pix
-        getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor);
+        getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
 
         // ############### Value 4 ################
 
@@ -247,18 +247,12 @@ class PageDST810 : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageFluid.cpp b/lib/obp60task/PageFluid.cpp
index 9d4a092..6c12635 100644
--- a/lib/obp60task/PageFluid.cpp
+++ b/lib/obp60task/PageFluid.cpp
@@ -57,31 +57,33 @@ static unsigned char gasoline_bits[] = {
    0x98, 0xcf, 0x38, 0xe7, 0x78, 0xf0, 0xf8, 0xfa, 0xf8, 0xfa, 0x78, 0xf0,
    0x38, 0xe7, 0x98, 0xcf, 0xf8, 0xff, 0xf0, 0x7f };
 
-class PageFluid : public Page{
-    bool keylock = false;               // Keylock
+class PageFluid : public Page
+{
     int fluidtype;
 
     public:
     PageFluid(CommonData &common){
+        commonData = &common;
         common.logger->logDebug(GwLog::LOG,"Instantiate PageFluid");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayNew(CommonData &commonData, PageData &pageData){
-        fluidtype = commonData.config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
-        commonData.logger->logDebug(GwLog::LOG,"New PageFluid: fluidtype=%d", fluidtype);
+    virtual void displayNew(PageData &pageData){
+        fluidtype = commonData->config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
+        commonData->logger->logDebug(GwLog::LOG,"New PageFluid: fluidtype=%d", fluidtype);
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Get config data
         String flashLED = config->getString(config->flashLED);
@@ -107,7 +109,7 @@ class PageFluid : public Page{
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height());
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // descriptions
         getdisplay().setFont(&Ubuntu_Bold12pt7b);
@@ -125,11 +127,11 @@ class PageFluid : public Page{
         uint8_t r = 110;
 
         // circular frame
-        getdisplay().drawCircle(c.x, c.y, r+5, commonData.fgcolor);
-        getdisplay().fillCircle(c.x, c.y, r+2, commonData.fgcolor);
-        getdisplay().fillCircle(c.x, c.y, r-1, commonData.bgcolor);
+        getdisplay().drawCircle(c.x, c.y, r+5, commonData->fgcolor);
+        getdisplay().fillCircle(c.x, c.y, r+2, commonData->fgcolor);
+        getdisplay().fillCircle(c.x, c.y, r-1, commonData->bgcolor);
         // center of pointer as dot 
-        getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor);
+        getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
 
         // value down centered
         char buffer[6];
@@ -143,19 +145,19 @@ class PageFluid : public Page{
         // draw symbol (as bitmap)
         switch (fluidtype) {
             case 0:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData.fgcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData->fgcolor);
                 break;
             case 1:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData.fgcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData->fgcolor);
                 break;
             case 4:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData.fgcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData->fgcolor);
                 break;
             case 5:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData.fgcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData->fgcolor);
                 break;
             case 6:
-                getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData.fgcolor);
+                getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData->fgcolor);
                 break;
         }
 
@@ -184,11 +186,11 @@ class PageFluid : public Page{
             {c.x + 2, c.y - (r - 16)},
             {c.x - 2, c.y - (r - 16)} 
         };
-        fillPoly4(rotatePoints(c, pts, -120), commonData.fgcolor);
-        fillPoly4(rotatePoints(c, pts, -60), commonData.fgcolor);
-        fillPoly4(rotatePoints(c, pts, 0), commonData.fgcolor);
-        fillPoly4(rotatePoints(c, pts, 60), commonData.fgcolor);
-        fillPoly4(rotatePoints(c, pts, 120), commonData.fgcolor);
+        fillPoly4(rotatePoints(c, pts, -120), commonData->fgcolor);
+        fillPoly4(rotatePoints(c, pts, -60), commonData->fgcolor);
+        fillPoly4(rotatePoints(c, pts, 0), commonData->fgcolor);
+        fillPoly4(rotatePoints(c, pts, 60), commonData->fgcolor);
+        fillPoly4(rotatePoints(c, pts, 120), commonData->fgcolor);
 
         // dots
         // rotate 0 to 360 in 12 degree steps
@@ -197,7 +199,7 @@ class PageFluid : public Page{
                 continue;
             }
             p = rotatePoint(c, {c.x, c.y - r + 10}, angle);
-            getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor);
+            getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
         }
 
         // pointer
@@ -208,25 +210,19 @@ class PageFluid : public Page{
                 {c.x + 6, c.y + 15},
                 {c.x - 6, c.y + 15}
             };
-            fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), commonData.fgcolor);
+            fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), commonData->fgcolor);
             // Pointer axis is white
-            getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor);
+            getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
         }
  
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 296);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 296);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 296);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageFourValues.cpp b/lib/obp60task/PageFourValues.cpp
index 1bad689..e0c418f 100644
--- a/lib/obp60task/PageFourValues.cpp
+++ b/lib/obp60task/PageFourValues.cpp
@@ -5,24 +5,24 @@
 
 class PageFourValues : public Page
 {
-    bool keylock = false;               // Keylock
-
     public:
     PageFourValues(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageFourValues");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Old values for hold function
         static String svalue1old = "";
@@ -47,8 +47,8 @@ class PageFourValues : public Page
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Get boat values #2
         GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ class PageFourValues : public Page
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
 
         // Get boat values #3
         GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ class PageFourValues : public Page
         name3 = name3.substring(0, 6);                  // String length limit for value name
         double value3 = bvalue3->value;                 // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
 
         // Get boat values #4
         GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ class PageFourValues : public Page
         name4 = name4.substring(0, 6);                  // String length limit for value name
         double value4 = bvalue4->value;                 // Value as double in SI unit
         bool valid4 = bvalue4->valid;                   // Valid information 
-        String svalue4 = formatValue(bvalue4, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit4 = formatValue(bvalue4, commonData).unit;        // Unit of value
+        String svalue4 = formatValue(bvalue4, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit4 = formatValue(bvalue4, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -93,7 +93,7 @@ class PageFourValues : public Page
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // ############### Value 1 ################
 
@@ -141,7 +141,7 @@ class PageFourValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 80, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 80, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -189,7 +189,7 @@ class PageFourValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 146, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 146, 400, 3, commonData->fgcolor);
 
         // ############### Value 3 ################
 
@@ -237,7 +237,7 @@ class PageFourValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 214, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 214, 400, 3, commonData->fgcolor);
 
         // ############### Value 4 ################
 
@@ -287,18 +287,12 @@ class PageFourValues : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageFourValues2.cpp b/lib/obp60task/PageFourValues2.cpp
index c7f5a1a..9f3f07b 100644
--- a/lib/obp60task/PageFourValues2.cpp
+++ b/lib/obp60task/PageFourValues2.cpp
@@ -5,24 +5,24 @@
 
 class PageFourValues2 : public Page
 {
-    bool keylock = false;               // Keylock
-
     public:
     PageFourValues2(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageFourValues2");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues2");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;         // Toggle keylock
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Old values for hold function
         static String svalue1old = "";
@@ -47,8 +47,8 @@ class PageFourValues2 : public Page
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Get boat values #2
         GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ class PageFourValues2 : public Page
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
 
         // Get boat values #3
         GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ class PageFourValues2 : public Page
         name3 = name3.substring(0, 6);                  // String length limit for value name
         double value3 = bvalue3->value;                 // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
 
         // Get boat values #4
         GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ class PageFourValues2 : public Page
         name4 = name4.substring(0, 6);                  // String length limit for value name
         double value4 = bvalue4->value;                 // Value as double in SI unit
         bool valid4 = bvalue4->valid;                   // Valid information 
-        String svalue4 = formatValue(bvalue4, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit4 = formatValue(bvalue4, commonData).unit;        // Unit of value
+        String svalue4 = formatValue(bvalue4, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit4 = formatValue(bvalue4, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -93,7 +93,7 @@ class PageFourValues2 : public Page
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // ############### Value 1 ################
 
@@ -141,7 +141,7 @@ class PageFourValues2 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -189,7 +189,7 @@ class PageFourValues2 : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
 
         // ############### Value 3 ################
 
@@ -237,7 +237,7 @@ class PageFourValues2 : public Page
         // ############### Vertical Line ################
 
         // Vertical line 3 pix
-        getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor);
+        getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
 
         // ############### Value 4 ################
 
@@ -287,18 +287,12 @@ class PageFourValues2 : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageGenerator.cpp b/lib/obp60task/PageGenerator.cpp
index aa8ac8d..fc0c402 100644
--- a/lib/obp60task/PageGenerator.cpp
+++ b/lib/obp60task/PageGenerator.cpp
@@ -6,26 +6,24 @@
 
 class PageGenerator : public Page
 {
-bool init = false;                  // Marker for init done
-bool keylock = false;               // Keylock
-
 public:
     PageGenerator(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageGenerator");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageGenerator");
     }
     virtual int handleKey(int key){
         // Code for keylock
         if(key == 11){
-            keylock = !keylock;         // Toggle keylock
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
+    virtual void displayPage(PageData &pageData)
     {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
@@ -47,13 +45,13 @@ public:
 
         // Get raw value for trend indicator
         if(powerSensor != "off"){
-            value1 = commonData.data.generatorVoltage;  // Use voltage from external sensor
+            value1 = commonData->data.generatorVoltage;  // Use voltage from external sensor
         }
         else{
-            value1 = commonData.data.batteryVoltage; // Use internal voltage sensor
+            value1 = commonData->data.batteryVoltage; // Use internal voltage sensor
         }
-        value2 = commonData.data.generatorCurrent;
-        value3 = commonData.data.generatorPower;
+        value2 = commonData->data.generatorCurrent;
+        value3 = commonData->data.generatorPower;
         genPercentage = value3 * 100 / (double)genPower;    // Load value
         // Limits for battery level
         if(genPercentage < 0) genPercentage = 0;
@@ -87,7 +85,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show name
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -124,7 +122,7 @@ public:
         getdisplay().print("Power Modul");
 
         // Show generator
-        generatorGraphic(200, 95, commonData.fgcolor, commonData.bgcolor);
+        generatorGraphic(200, 95, commonData->fgcolor, commonData->bgcolor);
 
         // Show load level in percent
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -207,18 +205,12 @@ public:
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){              // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageKeelPosition.cpp b/lib/obp60task/PageKeelPosition.cpp
index 1d02c3e..6ecaf61 100644
--- a/lib/obp60task/PageKeelPosition.cpp
+++ b/lib/obp60task/PageKeelPosition.cpp
@@ -5,27 +5,26 @@
 
 class PageKeelPosition : public Page
 {
-bool keylock = false;               // Keylock
-
 public:
     PageKeelPosition(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageKeelPosition");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageKeelPosition");
     }
 
     // Key functions
     virtual int handleKey(int key){
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
+    virtual void displayPage(PageData &pageData)
     {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         double value1 = 0;
         double value1old = 0;
@@ -40,9 +39,9 @@ public:
         String rotfunction = config->getString(config->rotFunction);
 
         // Get boat values for Keel position
-        bool valid1 = commonData.data.validRotAngle;    // Valid information 
+        bool valid1 = commonData->data.validRotAngle;    // Valid information 
         if(simulation == false && rotsensor == "AS5600" && rotfunction == "Keel"){
-            value1 = commonData.data.rotationAngle; // Raw value without unit convertion
+            value1 = commonData->data.rotationAngle; // Raw value without unit convertion
         }
         else{
             value1 = 0;
@@ -77,9 +76,9 @@ public:
         int rInstrument = 110;     // Radius of KeelPosition
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);       // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);        // Outer circle
-        getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor);                    // Delete half top circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor);       // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor);        // Outer circle
+        getdisplay().fillRect(0, 30, 400, 122, commonData->bgcolor);                    // Delete half top circle
 
         for(int i=90; i<=270; i=i+10)
         {
@@ -117,7 +116,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -130,10 +129,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
             }
 
         }
@@ -167,7 +166,7 @@ public:
             float yy2 = -(rInstrument * 0.6); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -177,17 +176,17 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
 
             // Draw counterweight
-            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor);
+            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 140, startwidth + 22, commonData.bgcolor);
-        getdisplay().fillCircle(200, 140, startwidth + 20, commonData.fgcolor);      // Boat circle
-        getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData.bgcolor);      // Delete half top of boat circle
-        getdisplay().fillRect(150, 150, 100, 4, commonData.fgcolor);                 // Water line
+        getdisplay().fillCircle(200, 140, startwidth + 22, commonData->bgcolor);
+        getdisplay().fillCircle(200, 140, startwidth + 20, commonData->fgcolor);      // Boat circle
+        getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData->bgcolor);   // Delete half top of boat circle
+        getdisplay().fillRect(150, 150, 100, 4, commonData->fgcolor);                 // Water line
 
         // Print label
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
@@ -210,18 +209,12 @@ public:
 //*******************************************************************************************
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageOneValue.cpp b/lib/obp60task/PageOneValue.cpp
index 708c611..6910890 100644
--- a/lib/obp60task/PageOneValue.cpp
+++ b/lib/obp60task/PageOneValue.cpp
@@ -3,25 +3,26 @@
 #include "Pagedata.h"
 #include "OBP60Extensions.h"
 
-class PageOneValue : public Page{
-    bool keylock = false;               // Keylock
-
+class PageOneValue : public Page
+{
     public:
     PageOneValue(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageOneValue");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageOneValue");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Old values for hold function
         static String svalue1old = "";
@@ -40,8 +41,8 @@ class PageOneValue : public Page{
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -60,7 +61,7 @@ class PageOneValue : public Page{
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
         // Show name
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(20, 100);
         getdisplay().print(name1);                           // Page name
@@ -103,18 +104,12 @@ class PageOneValue : public Page{
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageRollPitch.cpp b/lib/obp60task/PageRollPitch.cpp
index bb5b0e3..019a3b7 100644
--- a/lib/obp60task/PageRollPitch.cpp
+++ b/lib/obp60task/PageRollPitch.cpp
@@ -5,27 +5,25 @@
 
 class PageRollPitch : public Page
 {
-bool keylock = false;               // Keylock
-
 public:
     PageRollPitch(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageRollPitch");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageRollPitch");
     }
 
     // Key functions
     virtual int handleKey(int key){
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         double value1 = 0;
         double value2 = 0;
@@ -120,7 +118,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show roll limit
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -136,7 +134,7 @@ public:
         getdisplay().print("DEG");
         
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
 
         // Show roll value
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -151,7 +149,7 @@ public:
         getdisplay().print("Deg");
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
 
         // Show pitch value
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -171,8 +169,8 @@ public:
         int rInstrument = 100;     // Radius of instrument
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor);     // Outer circle
 
         for(int i=0; i<360; i=i+10)
         {
@@ -207,7 +205,7 @@ public:
                 // Draw sub scale with dots
                 float x1c = 200 + rInstrument*sin(i/180.0*pi);
                 float y1c = 150 - rInstrument*cos(i/180.0*pi);
-                getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
+                getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
                 float sinx=sin(i/180.0*pi);
                 float cosx=cos(i/180.0*pi); 
 
@@ -220,10 +218,10 @@ public:
                     float yy2 =  -(rInstrument+10);
                     getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                             200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                            200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
+                            200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
                     getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                             200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                            200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
+                            200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
                 }
             }
         }
@@ -244,7 +242,7 @@ public:
             float yy2 = -(rInstrument * 0.7); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -254,26 +252,26 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
 
             // Draw counterweight
-            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor);
+            getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 22, commonData.bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 20, commonData.fgcolor);      // Boat circle
+        getdisplay().fillCircle(200, 150, startwidth + 22, commonData->bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 20, commonData->fgcolor);      // Boat circle
         int x0 = 200;
         int y0 = 150;
         int x1 = x0 + 50*cos(value1);
         int y1 = y0 + 50*sin(value1);
         int x2 = x0 + 50*cos(value1 - pi/2);
         int y2 = y0 + 50*sin(value1 - pi/2);
-        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor);          // Clear half top side of boat circle (right triangle)
+        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor);          // Clear half top side of boat circle (right triangle)
         x1 = x0 + 50*cos(value1 + pi);
         y1 = y0 + 50*sin(value1 + pi);
-        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor);          // Clear half top side of boat circle (left triangle)
-        getdisplay().fillRect(150, 160, 100, 4, commonData.fgcolor);                 // Water line
+        getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor);          // Clear half top side of boat circle (left triangle)
+        getdisplay().fillRect(150, 160, 100, 4, commonData->fgcolor);                 // Water line
 
         // Draw roll pointer
         startwidth = 4;     // Start width of pointer
@@ -288,7 +286,7 @@ public:
             float yy2 = -(rInstrument - 15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -298,7 +296,7 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
         }
         else{
             // Print sensor info
@@ -310,18 +308,12 @@ public:
 //*******************************************************************************************
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageRudderPosition.cpp b/lib/obp60task/PageRudderPosition.cpp
index 5f88f0e..afceeb4 100644
--- a/lib/obp60task/PageRudderPosition.cpp
+++ b/lib/obp60task/PageRudderPosition.cpp
@@ -5,27 +5,25 @@
 
 class PageRudderPosition : public Page
 {
-bool keylock = false;               // Keylock
-
 public:
     PageRudderPosition(CommonData &common){
+        commonData = &common;
         common.logger->logDebug(GwLog::LOG,"Show PageRudderPosition");
     }
 
     // Key functions
     virtual int handleKey(int key){
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         static String unit1old = "";
         double value1 = 0.1;
@@ -44,8 +42,8 @@ public:
         name1 = name1.substring(0, 6);                  // String length limit for value name
         value1 = bvalue1->value;                        // Raw value without unit convertion
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
         if(valid1 == true){
             value1old = value1;   	                    // Save old value
             unit1old = unit1;                           // Save old unit
@@ -82,9 +80,9 @@ public:
         int rInstrument = 110;     // Radius of RudderPosition
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);        // Outer circle
-        getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor);                      // Delete half top circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor);        // Outer circle
+        getdisplay().fillRect(0, 30, 400, 122, commonData->bgcolor);                      // Delete half top circle
 
         for(int i=90; i<=270; i=i+10)
         {
@@ -122,7 +120,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -135,10 +133,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
             }
 
         }
@@ -190,7 +188,7 @@ public:
             float yy2 = -(rInstrument * 0.5); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -200,28 +198,22 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
 
 //*******************************************************************************************
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageSolar.cpp b/lib/obp60task/PageSolar.cpp
index d3b1acd..786dfe7 100644
--- a/lib/obp60task/PageSolar.cpp
+++ b/lib/obp60task/PageSolar.cpp
@@ -6,26 +6,23 @@
 
 class PageSolar : public Page
 {
-bool init = false;                  // Marker for init done
-bool keylock = false;               // Keylock
-
 public:
     PageSolar(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageSolar");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageSolar");
     }
     virtual int handleKey(int key){
         // Code for keylock
         if(key == 11){
-            keylock = !keylock;         // Toggle keylock
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
@@ -47,13 +44,13 @@ public:
 
         // Get raw value for trend indicator
         if(powerSensor != "off"){
-            value1 = commonData.data.solarVoltage;  // Use voltage from external sensor
+            value1 = commonData->data.solarVoltage;  // Use voltage from external sensor
         }
         else{
-            value1 = commonData.data.batteryVoltage; // Use internal voltage sensor
+            value1 = commonData->data.batteryVoltage; // Use internal voltage sensor
         }
-        value2 = commonData.data.solarCurrent;
-        value3 = commonData.data.solarPower;
+        value2 = commonData->data.solarCurrent;
+        value3 = commonData->data.solarPower;
         solPercentage = value3 * 100 / (double)solPower;    // Load value
         // Limits for battery level
         if(solPercentage < 0) solPercentage = 0;
@@ -87,7 +84,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show name
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -121,7 +118,7 @@ public:
         getdisplay().print("Solar Modul");
 
         // Show solar panel
-        solarGraphic(150, 45, commonData.fgcolor, commonData.bgcolor);
+        solarGraphic(150, 45, commonData->fgcolor, commonData->bgcolor);
 
         // Show load level in percent
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -204,18 +201,12 @@ public:
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){              // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageThreeValues.cpp b/lib/obp60task/PageThreeValues.cpp
index 08de8f3..a4fbf90 100644
--- a/lib/obp60task/PageThreeValues.cpp
+++ b/lib/obp60task/PageThreeValues.cpp
@@ -5,24 +5,24 @@
 
 class PageThreeValues : public Page
 {
-    bool keylock = false;               // Keylock
-
     public:
     PageThreeValues(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageThreeValue");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageThreeValue");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Old values for hold function
         static String svalue1old = "";
@@ -45,8 +45,8 @@ class PageThreeValues : public Page
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Get boat values #2
         GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -54,8 +54,8 @@ class PageThreeValues : public Page
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
 
         // Get boat values #3
         GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -63,8 +63,8 @@ class PageThreeValues : public Page
         name3 = name3.substring(0, 6);                  // String length limit for value name
         double value3 = bvalue3->value;                 // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -85,7 +85,7 @@ class PageThreeValues : public Page
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 55);
         getdisplay().print(name1);                           // Page name
@@ -129,7 +129,7 @@ class PageThreeValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -177,7 +177,7 @@ class PageThreeValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
 
         // ############### Value 3 ################
 
@@ -227,18 +227,12 @@ class PageThreeValues : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageTwoValues.cpp b/lib/obp60task/PageTwoValues.cpp
index 01469d9..e8dcf40 100644
--- a/lib/obp60task/PageTwoValues.cpp
+++ b/lib/obp60task/PageTwoValues.cpp
@@ -5,24 +5,24 @@
 
 class PageTwoValues : public Page
 {
-    bool keylock = false;               // Keylock
-
     public:
     PageTwoValues(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageTwoValue");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageTwoValue");
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Old values for hold function
         static String svalue1old = "";
@@ -43,8 +43,8 @@ class PageTwoValues : public Page
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information 
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
 
         // Get boat values #2
         GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -52,8 +52,8 @@ class PageTwoValues : public Page
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
 
         // Optical warning by limit violation (unused)
         if(String(flashLED) == "Limit Violation"){
@@ -74,7 +74,7 @@ class PageTwoValues : public Page
         // ############### Value 1 ################
 
         // Show name
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
         getdisplay().setFont(&Ubuntu_Bold20pt7b);
         getdisplay().setCursor(20, 80);
         getdisplay().print(name1);                           // Page name
@@ -118,7 +118,7 @@ class PageTwoValues : public Page
         // ############### Horizontal Line ################
 
         // Horizontal line 3 pix
-        getdisplay().fillRect(0, 145, 400, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 145, 400, 3, commonData->fgcolor);
 
         // ############### Value 2 ################
 
@@ -168,9 +168,7 @@ class PageTwoValues : public Page
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp
index cdee817..76d67e2 100644
--- a/lib/obp60task/PageVoltage.cpp
+++ b/lib/obp60task/PageVoltage.cpp
@@ -7,7 +7,6 @@
 class PageVoltage : public Page
 {
 bool init = false;                  // Marker for init done
-bool keylock = false;               // Keylock
 uint8_t average = 0;                // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
 bool trend = true;                  // Trend indicator [0|1], 0=off, 1=on
 double raw = 0;
@@ -15,6 +14,7 @@ char mode = 'D';                    // display mode (A)nalog | (D)igital
 
 public:
     PageVoltage(CommonData &common){
+        commonData = &common;
         common.logger->logDebug(GwLog::LOG,"Instantiate PageVoltage");
         if (hasFRAM) {
             average = fram.read(FRAM_VOLTAGE_AVG);
@@ -51,7 +51,7 @@ public:
 
         // Code for keylock
         if(key == 11){
-            keylock = !keylock;         // Toggle keylock
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
@@ -92,10 +92,9 @@ public:
         getdisplay().fillRect(x + 16, y + 11, 6, 3, color);
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
         
         // Get config data
         bool simulation = config->getBool(config->useSimuData);
@@ -113,32 +112,32 @@ public:
 
         // Create trend value
         if(init == false){          // Load start values for first page run
-            valueTrend = commonData.data.batteryVoltage10;
+            valueTrend = commonData->data.batteryVoltage10;
             init = true;
         }
         else{                       // Reading trend value
-            valueTrend = commonData.data.batteryVoltage10;
+            valueTrend = commonData->data.batteryVoltage10;
         }
 
         // Get raw value for trend indicator
-        raw = commonData.data.batteryVoltage;        // Live data
+        raw = commonData->data.batteryVoltage;        // Live data
 
         // Switch average values
         switch (average) {
             case 0:
-                value1 = commonData.data.batteryVoltage;        // Live data
+                value1 = commonData->data.batteryVoltage;        // Live data
                 break;
             case 1:
-                value1 = commonData.data.batteryVoltage10;      // Average 10s
+                value1 = commonData->data.batteryVoltage10;      // Average 10s
                 break;
             case 2:
-                value1 = commonData.data.batteryVoltage60;      // Average 60s
+                value1 = commonData->data.batteryVoltage60;      // Average 60s
                 break;
             case 3:
-                value1 = commonData.data.batteryVoltage300;     // Average 300s
+                value1 = commonData->data.batteryVoltage300;     // Average 300s
                 break;
             default:
-                value1 = commonData.data.batteryVoltage;        // Default
+                value1 = commonData->data.batteryVoltage;        // Default
                 break;
         }
         bool valid1 = true;
@@ -193,7 +192,7 @@ public:
             // Display mode digital
 
             // Show name
-            getdisplay().setTextColor(commonData.fgcolor);
+            getdisplay().setTextColor(commonData->fgcolor);
             getdisplay().setFont(&Ubuntu_Bold32pt7b);
             getdisplay().setCursor(20, 100);
             getdisplay().print(name1);                           // Value name
@@ -246,18 +245,18 @@ public:
             // Trend indicator
             // Show trend indicator
             if(trend == true){
-                getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
-                getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor);   // Draw separator
+                getdisplay().fillRect(310, 240, 40, 120, commonData->bgcolor);   // Clear area
+                getdisplay().fillRect(315, 183, 35, 4, commonData->fgcolor);   // Draw separator
                 if(int(raw * 10) > int(valueTrend * 10)){
-                    displayTrendHigh(320, 174, 11, commonData.fgcolor);  // Show high indicator
+                    displayTrendHigh(320, 174, 11, commonData->fgcolor);  // Show high indicator
                 }
                 if(int(raw * 10) < int(valueTrend * 10)){
-                    displayTrendLow(320, 195, 11, commonData.fgcolor);   // Show low indicator
+                    displayTrendLow(320, 195, 11, commonData->fgcolor);   // Show low indicator
                 }
             }
             // No trend indicator
             else{
-                getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor);   // Clear area
+                getdisplay().fillRect(310, 240, 40, 120, commonData->bgcolor);   // Clear area
             }
 
         }
@@ -272,9 +271,9 @@ public:
             std::vector<Point> pts;
 
             // Instrument
-            getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData.fgcolor);
-            getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData.fgcolor);
-            getdisplay().drawCircleHelper(c.x, c.y, r    , 0x01, commonData.fgcolor);
+            getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData->fgcolor);
+            getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData->fgcolor);
+            getdisplay().drawCircleHelper(c.x, c.y, r    , 0x01, commonData->fgcolor);
 
             // Scale
             // angle to voltage scale mapping
@@ -290,14 +289,14 @@ public:
             getdisplay().setFont(&Ubuntu_Bold10pt7b);
             for (int angle = 3; angle < 90; angle += 3) {
                 if (angle % 15 == 0) {
-                    fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
+                    fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
                     p1 = rotatePoint(c, {c.x - r + 30, c.y}, angle);
                     drawTextCenter(p1.x, p1.y, mapping[angle]);
                 }
                 else {
                     p1 = rotatePoint(c, {c.x - r, c.y}, angle);
                     p2 = rotatePoint(c, {c.x - r + 6, c.y}, angle);
-                    getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData.fgcolor);
+                    getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
                 }
             }
 
@@ -326,7 +325,7 @@ public:
                 {c.x - r + 38, c.y - 2},
                 {c.x - 2, c.y - 3}
             };
-            fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
+            fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
             // thin part
             pts = {
                 {c.x - r + 40, c.y + 1},
@@ -334,14 +333,14 @@ public:
                 {c.x - r + 5, c.y -1},
                 {c.x - r + 40, c.y - 1},
             };
-            fillPoly4(rotatePoints(c, pts, angle), commonData.fgcolor);
+            fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
 
             // base
-            getdisplay().fillCircle(c.x, c.y, 7, commonData.fgcolor);
-            getdisplay().fillCircle(c.x, c.y, 4, commonData.bgcolor);
+            getdisplay().fillCircle(c.x, c.y, 7, commonData->fgcolor);
+            getdisplay().fillCircle(c.x, c.y, 4, commonData->bgcolor);
 
             // Symbol
-            printVoltageSymbol(40, 60, commonData.fgcolor);
+            printVoltageSymbol(40, 60, commonData->fgcolor);
 
             // Additional information at right side
             getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -361,32 +360,26 @@ public:
 
             // FRAM indicator
             if (hasFRAM) {
-                getdisplay().drawXBitmap(300, 240, fram_bits, fram_width, fram_height, commonData.fgcolor);
+                getdisplay().drawXBitmap(300, 240, fram_bits, fram_width, fram_height, commonData->fgcolor);
             }
 
         }
 
         // Key Layout
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
+        if(commonData->keylock == false){
             getdisplay().setCursor(10, 290);
             getdisplay().print("[AVG]");
             getdisplay().setCursor(62, 290);
             getdisplay().print("[MODE]");
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
             getdisplay().setCursor(293, 290);
-                getdisplay().print("[TRD]");
+            getdisplay().print("[TRD]");
             if(String(backlightMode) == "Control by Key"){              // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageWhite.cpp b/lib/obp60task/PageWhite.cpp
index e941732..4c9d0c7 100644
--- a/lib/obp60task/PageWhite.cpp
+++ b/lib/obp60task/PageWhite.cpp
@@ -3,17 +3,17 @@
 #include "Pagedata.h"
 #include "OBP60Extensions.h"
 
-class PageWhite : public Page{
-    bool keylock = false;               // Keylock
-
+class PageWhite : public Page
+{
     public:
     PageWhite(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageWhite");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageWhite");
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Get config data
         String flashLED = config->getString(config->flashLED);
@@ -60,4 +60,4 @@ PageDescription registerPageWhite(
     false           // Show display header on/off
 );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageWindRose.cpp b/lib/obp60task/PageWindRose.cpp
index 82700f3..be3d468 100644
--- a/lib/obp60task/PageWindRose.cpp
+++ b/lib/obp60task/PageWindRose.cpp
@@ -5,28 +5,27 @@
 
 class PageWindRose : public Page
 {
-bool keylock = false;               // Keylock
 int16_t lp = 80;                    // Pointer length
 
 public:
     PageWindRose(CommonData &common){
+        commonData = &common;
         common.logger->logDebug(GwLog::LOG,"Show PageWindRose");
     }
 
     // Key functions
     virtual int handleKey(int key){
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         static String svalue1old = "";
         static String unit1old = "";
@@ -54,9 +53,9 @@ public:
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information
-        value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
         if(valid1 == true){
             svalue1old = svalue1;   	                // Save old value
             unit1old = unit1;                           // Save old unit
@@ -68,8 +67,8 @@ public:
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
         if(valid2 == true){
             svalue2old = svalue2;   	                // Save old value
             unit2old = unit2;                           // Save old unit
@@ -81,8 +80,8 @@ public:
         name3 = name3.substring(0, 6);                  // String length limit for value name
         double value3 = bvalue3->value;                 // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
         if(valid3 == true){
             svalue3old = svalue3;   	                // Save old value
             unit3old = unit3;                           // Save old unit
@@ -94,8 +93,8 @@ public:
         name4 = name4.substring(0, 6);                  // String length limit for value name
         double value4 = bvalue4->value;                 // Value as double in SI unit
         bool valid4 = bvalue4->valid;                   // Valid information 
-        String svalue4 = formatValue(bvalue4, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit4 = formatValue(bvalue4, commonData).unit;        // Unit of value
+        String svalue4 = formatValue(bvalue4, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit4 = formatValue(bvalue4, *commonData).unit;        // Unit of value
         if(valid4 == true){
             svalue4old = svalue4;   	                // Save old value
             unit4old = unit4;                           // Save old unit
@@ -107,8 +106,8 @@ public:
         name5 = name5.substring(0, 6);                  // String length limit for value name
         double value5 = bvalue5->value;                 // Value as double in SI unit
         bool valid5 = bvalue5->valid;                   // Valid information 
-        String svalue5 = formatValue(bvalue5, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit5 = formatValue(bvalue5, commonData).unit;        // Unit of value
+        String svalue5 = formatValue(bvalue5, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit5 = formatValue(bvalue5, *commonData).unit;        // Unit of value
         if(valid5 == true){
             svalue5old = svalue5;   	                // Save old value
             unit5old = unit5;                           // Save old unit
@@ -120,8 +119,8 @@ public:
         name6 = name6.substring(0, 6);                  // String length limit for value name
         double value6 = bvalue6->value;                 // Value as double in SI unit
         bool valid6 = bvalue6->valid;                   // Valid information 
-        String svalue6 = formatValue(bvalue6, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit6 = formatValue(bvalue6, commonData).unit;        // Unit of value
+        String svalue6 = formatValue(bvalue6, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit6 = formatValue(bvalue6, *commonData).unit;        // Unit of value
         if(valid6 == true){
             svalue6old = svalue6;   	                // Save old value
             unit6old = unit6;                           // Save old unit
@@ -143,7 +142,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show values AWA
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -163,7 +162,7 @@ public:
         }
 
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
 
         // Show values AWS
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -205,7 +204,7 @@ public:
         }
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
 
         // Show values TWS
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -230,10 +229,10 @@ public:
         int rInstrument = 110;     // Radius of grafic instrument
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor);    // Inner circle
-        getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor);    // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor);     // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument - 10, commonData->fgcolor);    // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument - 13, commonData->bgcolor);    // Inner circle
 
         for(int i=0; i<360; i=i+10)
         {
@@ -271,7 +270,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -284,10 +283,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
             }
         }
 
@@ -304,7 +303,7 @@ public:
             float yy2 = -(rInstrument-15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -314,12 +313,12 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
 
 //*******************************************************************************************
 
@@ -353,18 +352,12 @@ public:
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageWindRoseFlex.cpp b/lib/obp60task/PageWindRoseFlex.cpp
index e33b869..ad5cfde 100644
--- a/lib/obp60task/PageWindRoseFlex.cpp
+++ b/lib/obp60task/PageWindRoseFlex.cpp
@@ -5,28 +5,27 @@
 
 class PageWindRoseFlex : public Page
 {
-bool keylock = false;               // Keylock
 int16_t lp = 80;                    // Pointer length
 
 public:
     PageWindRoseFlex(CommonData &common){
+        commonData = &common;
         common.logger->logDebug(GwLog::LOG,"Show PageWindRoseFlex");
     }
 
     // Key functions
     virtual int handleKey(int key){
-        // Keylock function
-        if(key == 11){              // Code for keylock
-            keylock = !keylock;     // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;               // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData)
-    {
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         static String svalue1old = "";
         static String unit1old = "";
@@ -54,9 +53,9 @@ public:
         name1 = name1.substring(0, 6);                  // String length limit for value name
         double value1 = bvalue1->value;                 // Value as double in SI unit
         bool valid1 = bvalue1->valid;                   // Valid information
-        value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer
-        String svalue1 = formatValue(bvalue1, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit1 = formatValue(bvalue1, commonData).unit;        // Unit of value
+        value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
+        String svalue1 = formatValue(bvalue1, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit1 = formatValue(bvalue1, *commonData).unit;        // Unit of value
         if(valid1 == true){
             svalue1old = svalue1;   	                // Save old value
             unit1old = unit1;                           // Save old unit
@@ -68,8 +67,8 @@ public:
         name2 = name2.substring(0, 6);                  // String length limit for value name
         double value2 = bvalue2->value;                 // Value as double in SI unit
         bool valid2 = bvalue2->valid;                   // Valid information 
-        String svalue2 = formatValue(bvalue2, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit2 = formatValue(bvalue2, commonData).unit;        // Unit of value
+        String svalue2 = formatValue(bvalue2, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit2 = formatValue(bvalue2, *commonData).unit;        // Unit of value
         if(valid2 == true){
             svalue2old = svalue2;   	                // Save old value
             unit2old = unit2;                           // Save old unit
@@ -81,8 +80,8 @@ public:
         name3 = name3.substring(0, 6);                  // String length limit for value name
         double value3 = bvalue3->value;                 // Value as double in SI unit
         bool valid3 = bvalue3->valid;                   // Valid information 
-        String svalue3 = formatValue(bvalue3, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit3 = formatValue(bvalue3, commonData).unit;        // Unit of value
+        String svalue3 = formatValue(bvalue3, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit3 = formatValue(bvalue3, *commonData).unit;        // Unit of value
         if(valid3 == true){
             svalue3old = svalue3;   	                // Save old value
             unit3old = unit3;                           // Save old unit
@@ -94,8 +93,8 @@ public:
         name4 = name4.substring(0, 6);                  // String length limit for value name
         double value4 = bvalue4->value;                 // Value as double in SI unit
         bool valid4 = bvalue4->valid;                   // Valid information 
-        String svalue4 = formatValue(bvalue4, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit4 = formatValue(bvalue4, commonData).unit;        // Unit of value
+        String svalue4 = formatValue(bvalue4, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit4 = formatValue(bvalue4, *commonData).unit;        // Unit of value
         if(valid4 == true){
             svalue4old = svalue4;   	                // Save old value
             unit4old = unit4;                           // Save old unit
@@ -107,8 +106,8 @@ public:
         name5 = name5.substring(0, 6);                  // String length limit for value name
         double value5 = bvalue5->value;                 // Value as double in SI unit
         bool valid5 = bvalue5->valid;                   // Valid information 
-        String svalue5 = formatValue(bvalue5, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit5 = formatValue(bvalue5, commonData).unit;        // Unit of value
+        String svalue5 = formatValue(bvalue5, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit5 = formatValue(bvalue5, *commonData).unit;        // Unit of value
         if(valid5 == true){
             svalue5old = svalue5;   	                // Save old value
             unit5old = unit5;                           // Save old unit
@@ -120,8 +119,8 @@ public:
         name6 = name6.substring(0, 6);                  // String length limit for value name
         double value6 = bvalue6->value;                 // Value as double in SI unit
         bool valid6 = bvalue6->valid;                   // Valid information 
-        String svalue6 = formatValue(bvalue6, commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
-        String unit6 = formatValue(bvalue6, commonData).unit;        // Unit of value
+        String svalue6 = formatValue(bvalue6, *commonData).svalue;    // Formatted value as string including unit conversion and switching decimal places
+        String unit6 = formatValue(bvalue6, *commonData).unit;        // Unit of value
         if(valid6 == true){
             svalue6old = svalue6;   	                // Save old value
             unit6old = unit6;                           // Save old unit
@@ -143,7 +142,7 @@ public:
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // Show values AWA
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -163,7 +162,7 @@ public:
         }
 
         // Horizintal separator left
-        getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor);
+        getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
 
         // Show values AWS
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -205,7 +204,7 @@ public:
         }
 
         // Horizintal separator right
-        getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor);
+        getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
 
         // Show values TWS
         getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -230,10 +229,10 @@ public:
         int rInstrument = 110;     // Radius of grafic instrument
         float pi = 3.141592;
 
-        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor);    // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor);     // Outer circle
-        getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor);    // Inner circle
-        getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor);    // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor);    // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor);     // Outer circle
+        getdisplay().fillCircle(200, 150, rInstrument - 10, commonData->fgcolor);    // Inner circle
+        getdisplay().fillCircle(200, 150, rInstrument - 13, commonData->bgcolor);    // Inner circle
 
         for(int i=0; i<360; i=i+10)
         {
@@ -271,7 +270,7 @@ public:
             // Draw sub scale with dots
             float x1c = 200 + rInstrument*sin(i/180.0*pi);
             float y1c = 150 - rInstrument*cos(i/180.0*pi);
-            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor);
+            getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
             float sinx=sin(i/180.0*pi);
             float cosx=cos(i/180.0*pi); 
 
@@ -284,10 +283,10 @@ public:
                 float yy2 =  -(rInstrument+10);
                 getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                         200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
                 getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
                         200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
-                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor);
+                        200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
             }
         }
 
@@ -304,7 +303,7 @@ public:
             float yy2 = -(rInstrument-15); 
             getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
                 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
-                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor);   
+                200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
             // Inverted pointer
             // Pointer as triangle with center base 2*width
             float endwidth = 2;         // End width of pointer
@@ -314,12 +313,12 @@ public:
             float iy2 = -endwidth;
             getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
                 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
-                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor);
+                200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
         }
 
         // Center circle
-        getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor);
-        getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
+        getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
 
 //*******************************************************************************************
 
@@ -353,18 +352,12 @@ public:
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 290);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 290);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/PageXTETrack.cpp b/lib/obp60task/PageXTETrack.cpp
index 91afff1..d16a8b7 100644
--- a/lib/obp60task/PageXTETrack.cpp
+++ b/lib/obp60task/PageXTETrack.cpp
@@ -26,12 +26,12 @@ static unsigned char ship_bits[] PROGMEM = {
    0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
    0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-class PageXTETrack : public Page{
-    bool keylock = false;               // Keylock
-
+class PageXTETrack : public Page
+{
     public:
     PageXTETrack(CommonData &common){
-        common.logger->logDebug(GwLog::LOG,"Show PageXTETrack");
+        commonData = &common;
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageXTETrack");
     }
 
     void drawSegment(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
@@ -52,16 +52,17 @@ class PageXTETrack : public Page{
     }
 
     virtual int handleKey(int key){
-        if(key == 11){                  // Code for keylock
-            keylock = !keylock;         // Toggle keylock
+        // Code for keylock
+        if(key == 11){
+            commonData->keylock = !commonData->keylock;
             return 0;                   // Commit the key
         }
         return key;
     }
 
-    virtual void displayPage(CommonData &commonData, PageData &pageData){
-        GwConfigHandler *config = commonData.config;
-        GwLog *logger=commonData.logger;
+    virtual void displayPage(PageData &pageData){
+        GwConfigHandler *config = commonData->config;
+        GwLog *logger = commonData->logger;
 
         // Get config data
         String flashLED = config->getString(config->flashLED);
@@ -85,7 +86,7 @@ class PageXTETrack : public Page{
         // Set display in partial refresh mode
         getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
 
-        getdisplay().setTextColor(commonData.fgcolor);
+        getdisplay().setTextColor(commonData->fgcolor);
 
         // descriptions
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -105,25 +106,25 @@ class PageXTETrack : public Page{
         uint16_t w, h;
 
         GwApi::BoatValue *bv_xte = pageData.values[0]; // XTE
-        String sval_xte = formatValue(bv_xte, commonData).svalue;
+        String sval_xte = formatValue(bv_xte, *commonData).svalue;
         getdisplay().getTextBounds(sval_xte, 0, 0, &x, &y, &w, &h);
         getdisplay().setCursor(160-w, 170);
         getdisplay().print(sval_xte);
 
         GwApi::BoatValue *bv_cog = pageData.values[1]; // COG
-        String sval_cog = formatValue(bv_cog, commonData).svalue;
+        String sval_cog = formatValue(bv_cog, *commonData).svalue;
         getdisplay().getTextBounds(sval_cog, 0, 0, &x, &y, &w, &h);
         getdisplay().setCursor(360-w, 170);
         getdisplay().print(sval_cog);
 
         GwApi::BoatValue *bv_dtw = pageData.values[2]; // DTW
-        String sval_dtw = formatValue(bv_dtw, commonData).svalue;
+        String sval_dtw = formatValue(bv_dtw, *commonData).svalue;
         getdisplay().getTextBounds(sval_dtw, 0, 0, &x, &y, &w, &h);
         getdisplay().setCursor(160-w, 257);
         getdisplay().print(sval_dtw);
 
         GwApi::BoatValue *bv_btw = pageData.values[3]; // BTW
-        String sval_btw = formatValue(bv_btw, commonData).svalue;
+        String sval_btw = formatValue(bv_btw, *commonData).svalue;
         getdisplay().getTextBounds(sval_btw, 0, 0, &x, &y, &w, &h);
         getdisplay().setCursor(360-w, 257);
         getdisplay().print(sval_btw);
@@ -133,7 +134,7 @@ class PageXTETrack : public Page{
         // XTETrack view
 
         // draw ship symbol (as bitmap)
-        getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData.fgcolor);
+        getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData->fgcolor);
 
         // draw next waypoint name
         String sval_wpname = "no data";
@@ -188,28 +189,22 @@ class PageXTETrack : public Page{
         }
 
         // left segments
-        drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData.fgcolor, seg[2]);
-        drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData.fgcolor, seg[1]);
-        drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData.fgcolor,seg[0]);
+        drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData->fgcolor, seg[2]);
+        drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData->fgcolor, seg[1]);
+        drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData->fgcolor,seg[0]);
         // right segments
-        drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData.fgcolor, seg[3]);
-        drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData.fgcolor, seg[4]);
-        drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData.fgcolor, seg[5]);
+        drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData->fgcolor, seg[3]);
+        drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData->fgcolor, seg[4]);
+        drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData->fgcolor, seg[5]);
 
         // Key Layout
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(keylock == false){
-            getdisplay().setCursor(130, 296);
-            getdisplay().print("[  <<<<  " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + "  >>>>  ]");
+        if(commonData->keylock == false){
             if(String(backlightMode) == "Control by Key"){                  // Key for illumination
                 getdisplay().setCursor(343, 296);
                 getdisplay().print("[ILUM]");
             }
         }
-        else{
-            getdisplay().setCursor(130, 296);
-            getdisplay().print(" [    Keylock active    ]");
-        }
 
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h
index d18452f..9f9764c 100644
--- a/lib/obp60task/Pagedata.h
+++ b/lib/obp60task/Pagedata.h
@@ -73,13 +73,16 @@ typedef struct{
   GwApi::BoatValue *date=NULL;
   uint16_t fgcolor;
   uint16_t bgcolor;
+  bool keylock = false;
 } CommonData;
 
 //a base class that all pages must inherit from
 class Page{
+  protected:
+    CommonData *commonData;
   public:
-    virtual void displayPage(CommonData &commonData, PageData &pageData)=0;
-    virtual void displayNew(CommonData &commonData, PageData &pageData){}
+    virtual void displayPage(PageData &pageData)=0;
+    virtual void displayNew(PageData &pageData){}
     //return -1 if handled by the page
     virtual int handleKey(int key){return key;}
 };
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 73bd9fe..f85e746 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -629,12 +629,13 @@ void OBP60Task(GwApi *api){
                 }
                 else{
                     if (lastPage != pageNumber){
-                        currentPage->displayNew(commonData,pages[pageNumber].parameters);
+                        if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember page for device restart
+                        currentPage->displayNew(pages[pageNumber].parameters);
                         lastPage=pageNumber;
                     }
                     //call the page code
                     LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber);
-                    currentPage->displayPage(commonData,pages[pageNumber].parameters);
+                    currentPage->displayPage(pages[pageNumber].parameters);
                 }
             }
         }

From 970d05191c4a3ca8b10af51bd52de0849306596a Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Sun, 12 Jan 2025 18:01:54 +0100
Subject: [PATCH 21/35] Fix missing data bindings for page fluid

---
 lib/obp60task/PageFluid.cpp | 16 +++++++++++-----
 lib/obp60task/config.json   | 31 +++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/lib/obp60task/PageFluid.cpp b/lib/obp60task/PageFluid.cpp
index 9d4a092..c01e83b 100644
--- a/lib/obp60task/PageFluid.cpp
+++ b/lib/obp60task/PageFluid.cpp
@@ -59,11 +59,13 @@ static unsigned char gasoline_bits[] = {
 
 class PageFluid : public Page{
     bool keylock = false;               // Keylock
+    bool holdvalues = false;
     int fluidtype;
 
     public:
     PageFluid(CommonData &common){
         common.logger->logDebug(GwLog::LOG,"Instantiate PageFluid");
+        holdvalues = common.config->getBool(common.config->holdvalues);
     }
 
     virtual int handleKey(int key){
@@ -83,6 +85,9 @@ class PageFluid : public Page{
         GwConfigHandler *config = commonData.config;
         GwLog *logger=commonData.logger;
 
+        // Old values for hold function
+        static double value1old;
+
         // Get config data
         String flashLED = config->getString(config->flashLED);
         String backlightMode = config->getString(config->backlight);
@@ -93,13 +98,14 @@ class PageFluid : public Page{
             setFlashLED(false);
         }
 
-        // Logging boat values
-        LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid");
-
         GwApi::BoatValue *bvalue1 = pageData.values[0];
         String name1 = bvalue1->getName();
-        double value1 = bvalue1->value;
-        bool valid1 = bvalue1->valid;
+        if (holdvalues and bvalue1->valid) {
+            value1old = bvalue1->value;
+        }
+
+        // Logging boat values
+        LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid: value=%f", bvalue1->value);
 
         // Draw page
         //***********************************************************
diff --git a/lib/obp60task/config.json b/lib/obp60task/config.json
index 30dbb76..49ac39d 100644
--- a/lib/obp60task/config.json
+++ b/lib/obp60task/config.json
@@ -1012,6 +1012,9 @@
             },
             {
                 "page1type": "WindRoseFlex"
+            },
+            {
+                "page1type": "Fluid"
             }
         ]
     },
@@ -1266,7 +1269,11 @@
             },
             {
                 "page2type": "WindRoseFlex"
+            },
+            {
+                "page2type": "Fluid"
             }
+
         ]
     },
     {
@@ -1517,6 +1524,9 @@
             },
             {
                 "page3type": "WindRoseFlex"
+            },
+            {
+                "page3type": "Fluid"
             }
         ]
     },
@@ -1765,6 +1775,9 @@
             },
             {
                 "page4type": "WindRoseFlex"
+            },
+            {
+                "page4type": "Fluid"
             }
         ]
     },
@@ -2010,6 +2023,9 @@
             },
             {
                 "page5type": "WindRoseFlex"
+            },
+            {
+                "page5type": "Fluid"
             }
         ]
     },
@@ -2252,6 +2268,9 @@
             },
             {
                 "page6type": "WindRoseFlex"
+            },
+            {
+                "page6type": "Fluid"
             }
         ]
     },
@@ -2491,6 +2510,9 @@
             },
             {
                 "page7type": "WindRoseFlex"
+            },
+            {
+                "page7type": "Fluid"
             }
         ]
     },
@@ -2727,6 +2749,9 @@
             },
             {
                 "page8type": "WindRoseFlex"
+            },
+            {
+                "page8type": "Fluid"
             }
         ]
     },
@@ -2960,6 +2985,9 @@
             },
             {
                 "page9type": "WindRoseFlex"
+            },
+            {
+                "page9type": "Fluid"
             }
         ]
     },
@@ -3190,6 +3218,9 @@
             },
             {
                 "page10type": "WindRoseFlex"
+            },
+            {
+                "page10type": "Fluid"
             }
         ]
     },

From 71673e78bd96a2be1e12fddd6c098d61aef1332a Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Sun, 12 Jan 2025 18:22:40 +0100
Subject: [PATCH 22/35] First version for OBP 60 Light

---
 boards/obp60_s3_light_n8r8.json       |  56 +++++
 lib/obp60task/LedSpiTask.h            |   2 -
 lib/obp60task/OBP60Extensions.cpp     |  10 +-
 lib/obp60task/OBP60Hardware.h         |  84 +++++++
 lib/obp60task/OBP60Keypad.h           | 332 +++++++++++++++-----------
 lib/obp60task/obp60task.cpp           |   2 +
 lib/obp60task/obp60task.h             |  31 ++-
 lib/obp60task/platformio.ini          |  15 +-
 lib/obp60task/platformio.ini.light    |  61 +++++
 variants/obp60s3_light/pins_arduino.h |  74 ++++++
 10 files changed, 507 insertions(+), 160 deletions(-)
 create mode 100644 boards/obp60_s3_light_n8r8.json
 create mode 100644 lib/obp60task/platformio.ini.light
 create mode 100644 variants/obp60s3_light/pins_arduino.h

diff --git a/boards/obp60_s3_light_n8r8.json b/boards/obp60_s3_light_n8r8.json
new file mode 100644
index 0000000..b7b808a
--- /dev/null
+++ b/boards/obp60_s3_light_n8r8.json
@@ -0,0 +1,56 @@
+{
+  "build": {
+    "arduino":{
+      "ldscript": "esp32s3_out.ld",
+      "partitions": "default_8MB.csv",
+      "memory_type": "qio_opi"
+    },
+    "core": "esp32",
+    "extra_flags": [
+      "-DBOARD_HAS_PSRAM",
+      "-DARDUINO_ESP32S3_DEV",
+      "-DARDUINO_USB_MODE=1",
+      "-DARDUINO_USB_CDC_ON_BOOT=1",
+      "-DARDUINO_RUNNING_CORE=1",
+      "-DARDUINO_EVENT_RUNNING_CORE=1"
+    ],
+    "f_cpu": "240000000L",
+    "f_flash": "80000000L",
+    "flash_mode": "qio",
+    "hwids": [
+      [
+        "0x303A",
+        "0x1001"
+      ]
+    ],
+    "mcu": "esp32s3",
+    "variant": "obp60s3_light"
+  },
+  "connectivity": [
+    "bluetooth",
+    "wifi"
+  ],
+  "debug": {
+    "default_tool": "esp-builtin",
+    "onboard_tools": [
+      "esp-builtin"
+    ],
+    "openocd_target": "esp32s3.cfg"
+  },
+  "frameworks": [
+    "arduino",
+    "espidf"
+  ],
+  "name": "OBP60 Light ESP32-S3-N8R8 (8 MB QD, 8 MB PSRAM)",
+  "upload": {
+    "flash_size": "8MB",
+    "maximum_ram_size": 327680,
+    "maximum_size": 8388608,
+    "use_1200bps_touch": true,
+    "wait_for_upload_port": true,
+    "require_upload_port": true,
+    "speed": 460800
+  },
+  "url": "https://open-boat-projects.org/en/diy-multifunktionsdisplay-obp-60/",
+  "vendor": "Open Boat Projects"
+}
diff --git a/lib/obp60task/LedSpiTask.h b/lib/obp60task/LedSpiTask.h
index 5c2e82c..171281e 100644
--- a/lib/obp60task/LedSpiTask.h
+++ b/lib/obp60task/LedSpiTask.h
@@ -4,7 +4,6 @@
 #include "GwApi.h"
 #include "OBP60Hardware.h"
 
-
 class Color{
     public:
     uint8_t r;
@@ -92,5 +91,4 @@ class LedTaskData{
 //task function
 void createSpiLedTask(LedTaskData *param);
 
-
 #endif
\ No newline at end of file
diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 2fa4bc6..f908f58 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -102,11 +102,6 @@ void hardwareInit(GwApi *api)
     }
 }
 
-void startLedTask(GwApi *api){
-    ledTaskData=new LedTaskData(api);
-    createSpiLedTask(ledTaskData);
-}
-
 void setPortPin(uint pin, bool value){
     pinMode(pin, OUTPUT);
     digitalWrite(pin, value);
@@ -117,6 +112,11 @@ void togglePortPin(uint pin){
     digitalWrite(pin, !digitalRead(pin));
 }
 
+void startLedTask(GwApi *api){
+    ledTaskData=new LedTaskData(api);
+    createSpiLedTask(ledTaskData);
+}
+
 // Valid colors see hue
 Color colorMapping(const String &colorString){
     Color color = COLOR_RED;
diff --git a/lib/obp60task/OBP60Hardware.h b/lib/obp60task/OBP60Hardware.h
index 292068b..f146d13 100644
--- a/lib/obp60task/OBP60Hardware.h
+++ b/lib/obp60task/OBP60Hardware.h
@@ -1,6 +1,7 @@
     // General hardware definitions
     // CAN and RS485 bus pin definitions see obp60task.h
 
+#ifdef HARDWARE_V21
     // Direction pin for RS485 NMEA0183
     #define OBP_DIRECTION_PIN 18
     // I2C
@@ -73,5 +74,88 @@
     #define OBP_BACKLIGHT_LED 15    // GPIO port
     // Power Rail
     #define OBP_POWER_50 5          // 5.0V power rail
+#endif
 
+// Hardware configuration for OBP60 LIGHT
+
+#ifdef HARDWARE_LIGHT
+    // Direction pin for RS485 NMEA0183
+    #define OBP_DIRECTION_PIN 8
+    // I2C
+    #define I2C_SPEED 10000UL       // 10kHz clock speed on I2C bus
+    #define OBP_I2C_SDA 21
+    #define OBP_I2C_SCL 38
+    // DS1388 RTC
+    #define DS1388_I2C_ADDR 0x68    // Addr. 0x68
+    // BME280
+    #define BME280_I2C_ADDR 0x76    // Addr. 0x76 (0x77)
+    // BMP280
+    #define BMP280_I2C_ADDR 0x77    // Addr. 0x77 (0x76) Attention: Pull up resistor
+    // BMP085 / BMP180
+    #define BMP180_I2C_ADDR 0x77    // Addr. 0x77 (fix)
+    // SHT21 / HUT21
+    #define SHT21_I2C_ADDR 0x40     // Addr. 0x40 (fix)
+    // AS5600
+    #define AS5600_I2C_ADDR 0x36    // Addr. 0x36 (fix)
+    // INA219
+    #define SHUNT_VOLTAGE 0.075     // Shunt voltage in V by max. current (75mV)
+    #define INA219_I2C_ADDR1 0x40   // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
+    #define INA219_I2C_ADDR2 0x41   // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
+    #define INA219_I2C_ADDR3 0x45   // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
+    // INA226
+    #define INA226_I2C_ADDR1 0x41   // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
+    #define INA226_I2C_ADDR2 0x44   // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
+    #define INA226_I2C_ADDR3 0x45   // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
+    // Horter modules
+    #define PCF8574_I2C_ADDR1 0x20  // First digital out module
+    // FRAM (e.g. MB85RC256V)
+    #define FRAM_I2C_ADDR 0x50
+    // SPI (E-Ink display, Extern Bus)
+    #define OBP_SPI_CS 45
+    #define OBP_SPI_DC 46
+    #define OBP_SPI_RST 47
+    #define OBP_SPI_BUSY 48
+    #define OBP_SPI_CLK 12
+    #define OBP_SPI_DIN 11
+    #define SHOW_TIME 6000        // Show time in [ms] for logo and WiFi QR code
+    #define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
+    // SPI SD-Card
+    #define SD_SPI_CS 10
+    #define SD_SPI_MOSI 40
+    #define SD_SPI_CLK 39
+    #define SD_SPI_MISO 13
+
+    // GPS (NEO-6M, NEO-M8N, ATGM336H)
+    #define OBP_GPS_RX 19
+    #define OBP_GPS_TX 20
+    // 1Wire (DS18B20)
+    #define OBP_1WIRE 17        // External 1Wire
+    // Buzzer
+    #define OBP_BUZZER 18
+    #define TONE1 1500          // 1500Hz
+    #define TONE2 2500          // 2500Hz
+    #define TONE3 3500          // 3500Hz
+    #define TONE4 4000          // 4000Hz
+    // Analog Input
+    #define OBP_ANALOG0 3       // Analog input for voltage power supply
+    #define MIN_VOLTAGE 10.0    // Min voltage for under voltage detection (then goto deep sleep)
+    #define POWER_FAIL_TIME 2   // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
+    // Buttons
+    #define UP 6                // Wheel up
+    #define DOWN 4              // Wheel down
+    #define CONF 5              // Wheel press
+    #define MENUE 2             // Button top
+    #define EXIT 1              // Button bottom
+
+    // Flash LED (1x WS2812B)
+    #define NUM_FLASH_LED 1         // Number of flash LED
+    #define OBP_FLASH_LED 10        // GPIO port
+    // Backlight LEDs (6x WS2812B)
+    #define NUM_BACKLIGHT_LED 6     // Number of Backlight LEDs
+    #define OBP_BACKLIGHT_LED 40    // GPIO port
+    // Power Rail
+    #define OBP_POWER_50 41         // Power LED
+    #define OBP_POWER_EPD 7         // ePaper power
+    #define OBP_POWER_SD 42         // SD card power
+#endif
 
diff --git a/lib/obp60task/OBP60Keypad.h b/lib/obp60task/OBP60Keypad.h
index e51fe9d..7ad6f9b 100644
--- a/lib/obp60task/OBP60Keypad.h
+++ b/lib/obp60task/OBP60Keypad.h
@@ -14,167 +14,223 @@ int keycode = 0;        // Keycode of pressed key [0...8], 0 = nothing touched
 int keycode2 = 0;       // Keycode of very short pressed key [0...8], 0 = nothing touched
 int keycodeold = 0;     // Old keycode
 int keycodeold2 = 0;    // Old keycode for short pressed key
+int keystatus = 0;      // Status of key [0...11]
 bool keyoff = false;    // Disable all keys
 int keydelay = 250;     // Delay after key pressed in  [ms]
 bool keylock = false;   // Key lock after pressed key is valid (repeat protection by conginous pressing)
 long starttime = 0;     // Start time point for pressed key
 
+  #ifdef HARDWARE_V21
+  // Keypad functions for original OBP60 hardware
+  int readKeypad(uint thSensitivity) {
+    
+    // Touch sensor values
+    // 35000 - Not touched
+    // 50000 - Light toched with fingertip
+    // 70000 - Touched
+    // 170000 - Strong touched
+    uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
 
-int readKeypad(uint thSensitivity) {
-  
-  // Touch sensor values
-  // 35000 - Not touched
-  // 50000 - Light toched with fingertip
-  // 70000 - Touched
-  // 170000 - Strong touched
-  uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
+    keystatus = 0;      // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
+    keycode = 0;
 
-  int keystatus = 0;      // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
-  keycode = 0;
-
-  // Read key code
-  if(touchRead(14) > touchthreshold){ // Touch pad 1
-    keypad[1] = 1;
-  }
-  else{
-    keypad[1] = 0;
-  }
-  if(touchRead(13) > touchthreshold){ // Touch pad 2
-    keypad[2] = 1;
-  }
-  else{
-    keypad[2] = 0;
-  }
-  if(touchRead(12) > touchthreshold){ // Touch pad 3
-    keypad[3] = 1;
-  }
-  else{
-    keypad[3] = 0;
-  }
-  if(touchRead(11) > touchthreshold){ // Touch pad 4
-    keypad[4] = 1;
-  }
-  else{
-    keypad[4] = 0;
-  }
-  if(touchRead(10) > touchthreshold){ // Touch pad 5
-    keypad[5] = 1;
-  }
-  else{
-    keypad[5] = 0;
-  }
-  if(touchRead(9) > touchthreshold){  // Touch pad 6
-    keypad[6] = 1;
-  }
-  else{
-    keypad[6] = 0;
-  }
-  // Nothing touched
-  if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 &&  keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
-    keypad[0] = 1;
-  }
-  else{
-    keypad[0] = 0;
-  } 
-
-  for (int i = 0; i < 9; i++) {
-      if(i > 0){
-          // Convert keypad to keycode
-          if(keypad[i] == 1){
-            key = 1;
-          }
-          else{
-            key = 0;
-          }
-          keycode += key * i;
-      }
-  }
-
-  // Detect short keynumber
-  if (keycode > 0 ){ 
-    if(keylock == false){
-      starttime = millis();
-      keylock = true;
+    // Read key code
+    if(touchRead(14) > touchthreshold){ // Touch pad 1
+      keypad[1] = 1;
     }
-    if (keycode != keycodeold){
-      keylock = false;
+    else{
+      keypad[1] = 0;
     }
-    // Detect a very short keynumber (10ms)
-    if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
-      // Process only valid keys
-      if(keycode == 1 || keycode == 6){
-        keycode2 = keycode;
+    if(touchRead(13) > touchthreshold){ // Touch pad 2
+      keypad[2] = 1;
+    }
+    else{
+      keypad[2] = 0;
+    }
+    if(touchRead(12) > touchthreshold){ // Touch pad 3
+      keypad[3] = 1;
+    }
+    else{
+      keypad[3] = 0;
+    }
+    if(touchRead(11) > touchthreshold){ // Touch pad 4
+      keypad[4] = 1;
+    }
+    else{
+      keypad[4] = 0;
+    }
+    if(touchRead(10) > touchthreshold){ // Touch pad 5
+      keypad[5] = 1;
+    }
+    else{
+      keypad[5] = 0;
+    }
+    if(touchRead(9) > touchthreshold){  // Touch pad 6
+      keypad[6] = 1;
+    }
+    else{
+      keypad[6] = 0;
+    }
+    // Nothing touched
+    if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 &&  keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
+      keypad[0] = 1;
+    }
+    else{
+      keypad[0] = 0;
+    } 
+
+    for (int i = 0; i < 9; i++) {
+        if(i > 0){
+            // Convert keypad to keycode
+            if(keypad[i] == 1){
+              key = 1;
+            }
+            else{
+              key = 0;
+            }
+            keycode += key * i;
+        }
+    }
+
+    // Detect short keynumber
+    if (keycode > 0 ){ 
+      if(keylock == false){
+        starttime = millis();
+        keylock = true;
       }
-      // Clear by unvalid keys
-      else{
+      if (keycode != keycodeold){
+        keylock = false;
+      }
+      // Detect a very short keynumber (10ms)
+      if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
+        // Process only valid keys
+        if(keycode == 1 || keycode == 6){
+          keycode2 = keycode;
+        }
+        // Clear by unvalid keys
+        else{
+          keycode2 = 0;
+          keycodeold2 = 0;
+        }
+      }
+      // Timeout for very short pressed key
+      if(millis() > starttime + 200){
+        keycode2 = 0;
+      }
+      // Detect a short keynumber (200ms)
+      if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
+        keystatus = keycode;
+        keycode = 0;
+        keycodeold = 0;
         keycode2 = 0;
         keycodeold2 = 0;
+        buzzer(TONE4, 100);
+        keylock = false;
+        delay(keydelay);
       }
     }
-    // Timeout for very short pressed key
-    if(millis() > starttime + 200){
-      keycode2 = 0;
-    }
-    // Detect a short keynumber (200ms)
-    if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
-      keystatus = keycode;
+
+    // Key lock with key 1 and 6 or 6 and 1 in fast series
+    if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
       keycode = 0;
       keycodeold = 0;
       keycode2 = 0;
       keycodeold2 = 0;
-      buzzer(TONE4, 100);
+      buzzer(TONE4, 1000);
       keylock = false;
       delay(keydelay);
+      keyoff = !keyoff;
+      keystatus = 11;
     }
+
+    // Detect swipe right
+    if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
+    //if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
+      keycode = 0;
+      keycodeold = 0;
+      keycode2 = 0;
+      keycodeold2 = 0;
+      keystatus = 9;
+      buzzer(TONE3, 150);
+      buzzer(TONE4, 150);
+    }
+
+    // Detect swipe left
+    if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
+    //if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){  
+      keycode = 0;
+      keycodeold = 0;
+      keycode2 = 0;
+      keycodeold2 = 0;
+      keystatus = 10;
+      buzzer(TONE4, 150);
+      buzzer(TONE3, 150);
+    }
+
+    // Reset keylock after release
+    if (keycode == 0){
+      keylock = false;
+    }
+
+    // Copy keycode
+    keycodeold = keycode;
+    keycodeold2 = keycode2;
+
+    return keystatus;
   }
+  #endif
 
-  // Key lock with key 1 and 6 or 6 and 1 in fast series
-  if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
-    keycode = 0;
-    keycodeold = 0;
-    keycode2 = 0;
-    keycodeold2 = 0;
-    buzzer(TONE4, 1000);
-    keylock = false;
-    delay(keydelay);
-    keyoff = !keyoff;
-    keystatus = 11;
+  #ifdef HARDWARE_LIGHT
+  // Keypad functions for OBP60 clone (thSensitivity is inactiv)
+  int readKeypad(uint thSensitivity) {
+    pinMode(UP, INPUT);
+    pinMode(DOWN, INPUT);
+    pinMode(CONF, INPUT);
+    pinMode(MENUE, INPUT);
+    pinMode(EXIT, INPUT);
+
+    // Read key code 
+    if(digitalRead(UP) == LOW){
+      keycode = 10; // Left swipe
+    }
+    else if(digitalRead(DOWN) == LOW){
+      keycode = 9;  // Right swipe
+    }
+    else if(digitalRead(CONF) == LOW){
+      keycode = 3;  // Key 3
+    }
+    else if(digitalRead(MENUE) == LOW){
+      keycode = 1;  // Key 1
+    }
+    else if(digitalRead(EXIT) == LOW){
+      keycode = 2;  // Key 2
+    }
+    else{
+      keycode = 0;  // No key activ
+    }
+
+    // Detect key
+    if (keycode > 0 ){
+      if(keycode != keycodeold){
+        starttime = millis();   // Start key pressed
+        keycodeold = keycode;
+      }
+      // If key pressed longer than 200ms
+      if(millis() > starttime + 200 && keycode == keycodeold) {
+        keystatus = keycode;
+        // Copy keycode
+        keycodeold = keycode;
+        delay(keydelay);
+      }
+    }
+    else{
+      keycode = 0;
+      keycodeold = 0;
+      keystatus = 0;
+    }
+
+    return keystatus;
   }
-
-  // Detect swipe right
-  if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
-  //if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
-    keycode = 0;
-    keycodeold = 0;
-    keycode2 = 0;
-    keycodeold2 = 0;
-    keystatus = 9;
-    buzzer(TONE3, 150);
-    buzzer(TONE4, 150);
-  }
-
-  // Detect swipe left
-  if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
-  //if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){  
-    keycode = 0;
-    keycodeold = 0;
-    keycode2 = 0;
-    keycodeold2 = 0;
-    keystatus = 10;
-    buzzer(TONE4, 150);
-    buzzer(TONE3, 150);
-  }
-
-  // Reset keylock after release
-  if (keycode == 0){
-    keylock = false;
-  }
-
-  // Copy keycode
-  keycodeold = keycode;
-  keycodeold2 = keycode2;
-
-  return keystatus;
-}
+  #endif
 
 #endif
\ No newline at end of file
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index a2bf5a9..30413a2 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -50,9 +50,11 @@ void OBP60Init(GwApi *api){
     api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
     if(powermode == "Max Power" || powermode == "Only 5.0V"){
         setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
+        setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
     }
     else{
         setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
+        setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
     }
 
     // Settings for e-paper display
diff --git a/lib/obp60task/obp60task.h b/lib/obp60task/obp60task.h
index aecada9..97bd73a 100644
--- a/lib/obp60task/obp60task.h
+++ b/lib/obp60task/obp60task.h
@@ -3,15 +3,28 @@
 //we only compile for some boards
 #ifdef BOARD_OBP60S3
     #define USBSerial Serial
-    // CAN NMEA2000
-    #define ESP32_CAN_TX_PIN 46
-    #define ESP32_CAN_RX_PIN 3
-    // Bus load in 50mA steps
-    #define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
-    // RS485 NMEA0183
-    #define GWSERIAL_TX 17
-    #define GWSERIAL_RX 8
-    #define GWSERIAL_MODE "UNI"
+    #ifdef HARDWARE_V21
+        // CAN NMEA2000
+        #define ESP32_CAN_TX_PIN 46
+        #define ESP32_CAN_RX_PIN 3
+        // Bus load in 50mA steps
+        #define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
+        // RS485 NMEA0183
+        #define GWSERIAL_TX 17
+        #define GWSERIAL_RX 8
+        #define GWSERIAL_MODE "UNI"
+    #endif
+    #ifdef HARDWARE_LIGHT
+        // CAN NMEA2000
+        #define ESP32_CAN_TX_PIN 15
+        #define ESP32_CAN_RX_PIN 16
+        // Bus load in 50mA steps
+        #define N2K_LOAD_LEVEL 2 // 5x50mA = 100mA max bus load with back light on
+        // RS485 NMEA0183
+        #define GWSERIAL_TX 9
+        #define GWSERIAL_RX 14
+        #define GWSERIAL_MODE "UNI"
+    #endif    
     // Allowed to set a new password for access point
     #define FORCE_AP_PWCHANGE
 
diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index 63f1085..d11edcf 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -9,9 +9,10 @@ board_build.variants_dir = variants
 #board = obp60_s3_n8     #ESP32-S3 N8, 8MB flash, no PSRAM
 #board = obp60_s3_n16    #ESP32-S3 N16,16MB flash, no PSRAM, zero series
 #board = obp60_s3_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
-board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
-#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
-board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
+#board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
+board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
+board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
+#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
 framework = arduino
 lib_deps = 
     ${basedeps.lib_deps}
@@ -44,15 +45,17 @@ build_flags=
 #    -D TIME=$UNIX_TIME              #Set PC time for RTC (only settable via VSC)
     -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib
     -D BOARD_OBP60S3                #Board OBP60 V2.1 with ESP32S3
-#    -D HARDWARE_V20                 #Hardware revision V2.0
-    -D HARDWARE_V21                 #Hardware revision V2.1
+#    -D HARDWARE_V20                 #OBP60 hardware revision V2.0
+#    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
+    -D HARDWARE_LIGHT               #OBP60 hardware clone
 #    -D DISPLAY_GDEW042T2            #old E-Ink display from Waveshare, R10 0.47 ohm
     -D DISPLAY_GDEY042T81           #new E-Ink display from Waveshare, R10 2.2 ohm
 #    -D DISPLAY_GYE042A87            #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
 #    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
     ${env.build_flags}
 #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
-upload_port = /dev/ttyACM0
+#upload_port = /dev/ttyACM0          #OBP60 original
+upload_port = /dev/ttyUSB0          #OBP60 clone
 upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
 upload_speed = 230400
 monitor_speed = 115200
diff --git a/lib/obp60task/platformio.ini.light b/lib/obp60task/platformio.ini.light
new file mode 100644
index 0000000..d11edcf
--- /dev/null
+++ b/lib/obp60task/platformio.ini.light
@@ -0,0 +1,61 @@
+[platformio]
+#if you want a pio run to only build
+#your special environments you can set this here
+#by uncommenting the next line
+default_envs = obp60_s3
+[env:obp60_s3]
+platform = espressif32@6.8.1
+board_build.variants_dir = variants
+#board = obp60_s3_n8     #ESP32-S3 N8, 8MB flash, no PSRAM
+#board = obp60_s3_n16    #ESP32-S3 N16,16MB flash, no PSRAM, zero series
+#board = obp60_s3_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
+#board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
+board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
+board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
+#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
+framework = arduino
+lib_deps = 
+    ${basedeps.lib_deps}
+    Wire
+    SPI
+    esphome/AsyncTCP-esphome@2.0.1
+    robtillaart/PCF8574@0.3.9
+    adafruit/Adafruit Unified Sensor @ 1.1.13
+    blemasle/MCP23017@2.0.0
+    adafruit/Adafruit BusIO@1.5.0
+    adafruit/Adafruit GFX Library@1.11.9
+    #zinggjm/GxEPD2@1.5.8
+    #https://github.com/ZinggJM/GxEPD2
+    https://github.com/thooge/GxEPD2
+    sstaub/Ticker@4.4.0
+    adafruit/Adafruit BMP280 Library@2.6.2
+    adafruit/Adafruit BME280 Library@2.2.2
+    adafruit/Adafruit BMP085 Library@1.2.1
+    enjoyneering/HTU21D@1.2.1
+    robtillaart/INA226@0.2.0
+    paulstoffregen/OneWire@2.3.8
+    milesburton/DallasTemperature@3.11.0
+    signetica/SunRise@2.0.2
+    adafruit/Adafruit FRAM I2C@^2.0.3
+build_flags=
+    #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
+#    -D ARDUINO_USB_MODE=1           #0=OTG (to implement other external devices), 1=CDC (is a serial device) 
+#    -D ARDUINO_USB_CDC_ON_BOOT=1    #0=JTAG, 1=CDC (serial device)
+#    -D CORE_DEBUG_LEVEL=1           #Debug level for CPU core via CDC (seral device)
+#    -D TIME=$UNIX_TIME              #Set PC time for RTC (only settable via VSC)
+    -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib
+    -D BOARD_OBP60S3                #Board OBP60 V2.1 with ESP32S3
+#    -D HARDWARE_V20                 #OBP60 hardware revision V2.0
+#    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
+    -D HARDWARE_LIGHT               #OBP60 hardware clone
+#    -D DISPLAY_GDEW042T2            #old E-Ink display from Waveshare, R10 0.47 ohm
+    -D DISPLAY_GDEY042T81           #new E-Ink display from Waveshare, R10 2.2 ohm
+#    -D DISPLAY_GYE042A87            #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
+#    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
+    ${env.build_flags}
+#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
+#upload_port = /dev/ttyACM0          #OBP60 original
+upload_port = /dev/ttyUSB0          #OBP60 clone
+upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
+upload_speed = 230400
+monitor_speed = 115200
diff --git a/variants/obp60s3_light/pins_arduino.h b/variants/obp60s3_light/pins_arduino.h
new file mode 100644
index 0000000..3e1fdeb
--- /dev/null
+++ b/variants/obp60s3_light/pins_arduino.h
@@ -0,0 +1,74 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <stdint.h>
+#include "soc/soc_caps.h"
+
+#define USB_VID 0x303a
+#define USB_PID 0x1001
+
+/*
+#define EXTERNAL_NUM_INTERRUPTS 46
+#define NUM_DIGITAL_PINS        48
+#define NUM_ANALOG_INPUTS       20
+
+// Multi Function Display OBP60 V2.0
+static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT+48;
+#define BUILTIN_LED  LED_BUILTIN // backward compatibility
+#define LED_BUILTIN LED_BUILTIN
+#define RGB_BUILTIN LED_BUILTIN
+#define RGB_BRIGHTNESS 64
+
+#define analogInputToDigitalPin(p)  (((p)<20)?(analogChannelToDigitalPin(p)):-1)
+#define digitalPinToInterrupt(p)    (((p)<48)?(p):-1)
+#define digitalPinHasPWM(p)         (p < 46)
+*/
+
+static const uint8_t TX = 43;
+static const uint8_t RX = 44;
+
+static const uint8_t SDA = 21;
+static const uint8_t SCL = 38;
+
+static const uint8_t SS    = 45;
+static const uint8_t MOSI  = 11;
+static const uint8_t MISO  = 13;
+static const uint8_t SCK   = 12;
+
+static const uint8_t A0 = 1;
+static const uint8_t A1 = 2;
+static const uint8_t A2 = 3;
+static const uint8_t A3 = 4;
+static const uint8_t A4 = 5;
+static const uint8_t A5 = 6;
+static const uint8_t A6 = 7;
+static const uint8_t A7 = 8;
+static const uint8_t A8 = 9;
+static const uint8_t A9 = 10;
+static const uint8_t A10 = 11;
+static const uint8_t A11 = 12;
+static const uint8_t A12 = 13;
+static const uint8_t A13 = 14;
+static const uint8_t A14 = 15;
+static const uint8_t A15 = 16;
+static const uint8_t A16 = 17;
+static const uint8_t A17 = 18;
+static const uint8_t A18 = 19;
+static const uint8_t A19 = 20;
+
+static const uint8_t T1 = 1;
+static const uint8_t T2 = 2;
+static const uint8_t T3 = 3;
+static const uint8_t T4 = 4;
+static const uint8_t T5 = 5;
+static const uint8_t T6 = 6;
+static const uint8_t T7 = 7;
+static const uint8_t T8 = 8;
+static const uint8_t T9 = 9;
+static const uint8_t T10 = 10;
+static const uint8_t T11 = 11;
+static const uint8_t T12 = 12;
+static const uint8_t T13 = 13;
+static const uint8_t T14 = 14;
+
+#endif /* Pins_Arduino_h */

From dfc79c80dc6e2baf9f96064c686014780dafbc9e Mon Sep 17 00:00:00 2001
From: Tobias E <Tobias.edler@gmail.com>
Date: Sun, 12 Jan 2025 21:40:39 +0000
Subject: [PATCH 23/35] Add SixValues and fix Fluid in gen_set.py

---
 lib/obp60task/gen_set.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/gen_set.py b/lib/obp60task/gen_set.py
index d0ff7e5..a0f7b6d 100755
--- a/lib/obp60task/gen_set.py
+++ b/lib/obp60task/gen_set.py
@@ -5,14 +5,14 @@ import json
 
 # List of all pages and the number of parameters they expect.
 no_of_fields_per_page = {
-    "ApparentWind": 0,
+    "Wind": 0,
     "XTETrack": 0,
     "Battery2": 0,
     "Battery": 0,
     "BME280": 0,
     "Clock": 0,
     "DST810": 0,
-    "Fluid": 0,
+    "Fluid": 1,
     "FourValues2": 4,
     "FourValues": 4,
     "Generator": 0,
@@ -27,6 +27,7 @@ no_of_fields_per_page = {
     "White": 0,
     "WindRose": 0,
     "WindRoseFlex": 6,
+    "SixValues" : 6,
 }
 
 # No changes needed beyond this point

From 9fc090a5a8c7f89c794ec6f23ea544c442ef779c Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Sun, 12 Jan 2025 23:50:38 +0100
Subject: [PATCH 24/35] Fix flag error in platformio.ini

---
 lib/obp60task/platformio.ini      | 12 +++---
 lib/obp60task/platformio.ini.orig | 61 +++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 6 deletions(-)
 create mode 100644 lib/obp60task/platformio.ini.orig

diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index d11edcf..9485522 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -9,10 +9,10 @@ board_build.variants_dir = variants
 #board = obp60_s3_n8     #ESP32-S3 N8, 8MB flash, no PSRAM
 #board = obp60_s3_n16    #ESP32-S3 N16,16MB flash, no PSRAM, zero series
 #board = obp60_s3_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
-#board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
-board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
-board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
-#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
+board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
+#board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
+#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
+board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
 framework = arduino
 lib_deps = 
     ${basedeps.lib_deps}
@@ -46,8 +46,8 @@ build_flags=
     -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib
     -D BOARD_OBP60S3                #Board OBP60 V2.1 with ESP32S3
 #    -D HARDWARE_V20                 #OBP60 hardware revision V2.0
-#    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
-    -D HARDWARE_LIGHT               #OBP60 hardware clone
+    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
+#    -D HARDWARE_LIGHT               #OBP60 hardware clone
 #    -D DISPLAY_GDEW042T2            #old E-Ink display from Waveshare, R10 0.47 ohm
     -D DISPLAY_GDEY042T81           #new E-Ink display from Waveshare, R10 2.2 ohm
 #    -D DISPLAY_GYE042A87            #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
diff --git a/lib/obp60task/platformio.ini.orig b/lib/obp60task/platformio.ini.orig
new file mode 100644
index 0000000..9485522
--- /dev/null
+++ b/lib/obp60task/platformio.ini.orig
@@ -0,0 +1,61 @@
+[platformio]
+#if you want a pio run to only build
+#your special environments you can set this here
+#by uncommenting the next line
+default_envs = obp60_s3
+[env:obp60_s3]
+platform = espressif32@6.8.1
+board_build.variants_dir = variants
+#board = obp60_s3_n8     #ESP32-S3 N8, 8MB flash, no PSRAM
+#board = obp60_s3_n16    #ESP32-S3 N16,16MB flash, no PSRAM, zero series
+#board = obp60_s3_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
+board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
+#board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
+#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
+board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
+framework = arduino
+lib_deps = 
+    ${basedeps.lib_deps}
+    Wire
+    SPI
+    esphome/AsyncTCP-esphome@2.0.1
+    robtillaart/PCF8574@0.3.9
+    adafruit/Adafruit Unified Sensor @ 1.1.13
+    blemasle/MCP23017@2.0.0
+    adafruit/Adafruit BusIO@1.5.0
+    adafruit/Adafruit GFX Library@1.11.9
+    #zinggjm/GxEPD2@1.5.8
+    #https://github.com/ZinggJM/GxEPD2
+    https://github.com/thooge/GxEPD2
+    sstaub/Ticker@4.4.0
+    adafruit/Adafruit BMP280 Library@2.6.2
+    adafruit/Adafruit BME280 Library@2.2.2
+    adafruit/Adafruit BMP085 Library@1.2.1
+    enjoyneering/HTU21D@1.2.1
+    robtillaart/INA226@0.2.0
+    paulstoffregen/OneWire@2.3.8
+    milesburton/DallasTemperature@3.11.0
+    signetica/SunRise@2.0.2
+    adafruit/Adafruit FRAM I2C@^2.0.3
+build_flags=
+    #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
+#    -D ARDUINO_USB_MODE=1           #0=OTG (to implement other external devices), 1=CDC (is a serial device) 
+#    -D ARDUINO_USB_CDC_ON_BOOT=1    #0=JTAG, 1=CDC (serial device)
+#    -D CORE_DEBUG_LEVEL=1           #Debug level for CPU core via CDC (seral device)
+#    -D TIME=$UNIX_TIME              #Set PC time for RTC (only settable via VSC)
+    -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib
+    -D BOARD_OBP60S3                #Board OBP60 V2.1 with ESP32S3
+#    -D HARDWARE_V20                 #OBP60 hardware revision V2.0
+    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
+#    -D HARDWARE_LIGHT               #OBP60 hardware clone
+#    -D DISPLAY_GDEW042T2            #old E-Ink display from Waveshare, R10 0.47 ohm
+    -D DISPLAY_GDEY042T81           #new E-Ink display from Waveshare, R10 2.2 ohm
+#    -D DISPLAY_GYE042A87            #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
+#    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
+    ${env.build_flags}
+#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
+#upload_port = /dev/ttyACM0          #OBP60 original
+upload_port = /dev/ttyUSB0          #OBP60 clone
+upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
+upload_speed = 230400
+monitor_speed = 115200

From 574deac6f8f13ebd7fee84ebc77fcb4448c42543 Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Tue, 14 Jan 2025 20:19:31 +0100
Subject: [PATCH 25/35] Fix for obptask.cpp

---
 lib/obp60task/obp60task.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index 30413a2..536e36a 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -49,12 +49,20 @@ void OBP60Init(GwApi *api){
     String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
     api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
     if(powermode == "Max Power" || powermode == "Only 5.0V"){
+        #ifdef HARDWARE_V21
         setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
+        #endif
+        #ifdef HARDWARE_LIGHT
         setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
+        #endif
     }
     else{
+        #ifdef HARDWARE_V21
         setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
+        #endif
+        #ifdef HARDWARE_LIGHT
         setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
+        #endif
     }
 
     // Settings for e-paper display

From 6ffa974354cfb40fb6647c48934672cd22af47ba Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Tue, 14 Jan 2025 20:25:36 +0100
Subject: [PATCH 26/35] Fix platformio.ini

---
 lib/obp60task/platformio.ini | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index 9485522..4010a82 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -54,8 +54,8 @@ build_flags=
 #    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
     ${env.build_flags}
 #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
-#upload_port = /dev/ttyACM0          #OBP60 original
-upload_port = /dev/ttyUSB0          #OBP60 clone
+upload_port = /dev/ttyACM0          #OBP60 original
+#upload_port = /dev/ttyUSB0          #OBP60 clone
 upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
 upload_speed = 230400
 monitor_speed = 115200

From 47db247471c66d807346a2cb8c65a1d1091f70c4 Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Tue, 14 Jan 2025 20:28:41 +0100
Subject: [PATCH 27/35] Fix backup platformio.ini

---
 lib/obp60task/platformio.ini.orig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/obp60task/platformio.ini.orig b/lib/obp60task/platformio.ini.orig
index 9485522..4010a82 100644
--- a/lib/obp60task/platformio.ini.orig
+++ b/lib/obp60task/platformio.ini.orig
@@ -54,8 +54,8 @@ build_flags=
 #    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
     ${env.build_flags}
 #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
-#upload_port = /dev/ttyACM0          #OBP60 original
-upload_port = /dev/ttyUSB0          #OBP60 clone
+upload_port = /dev/ttyACM0          #OBP60 original
+#upload_port = /dev/ttyUSB0          #OBP60 clone
 upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
 upload_speed = 230400
 monitor_speed = 115200

From 519af68befe6ca9b57ff4f4b9739ec502ae16c71 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Wed, 15 Jan 2025 18:08:39 +0100
Subject: [PATCH 28/35] Footer function for improved key labels, icons
 implemented

---
 lib/obp60task/Atari16px8b.h          | 338 +++++++++++++++++++++++++++
 lib/obp60task/LedSpiTask.h           |   3 +-
 lib/obp60task/OBP60Extensions.cpp    |  59 +++++
 lib/obp60task/OBP60Extensions.h      |  77 ++++--
 lib/obp60task/OBP60Keypad.h          |  34 ++-
 lib/obp60task/PageBME280.cpp         |  11 -
 lib/obp60task/PageBattery.cpp        |  19 +-
 lib/obp60task/PageBattery2.cpp       |  17 +-
 lib/obp60task/PageClock.cpp          |  10 -
 lib/obp60task/PageDST810.cpp         |  12 -
 lib/obp60task/PageFluid.cpp          |  22 +-
 lib/obp60task/PageFourValues.cpp     |  12 -
 lib/obp60task/PageFourValues2.cpp    |  12 -
 lib/obp60task/PageGenerator.cpp      |   9 -
 lib/obp60task/PageKeelPosition.cpp   |  10 -
 lib/obp60task/PageOneValue.cpp       |   9 -
 lib/obp60task/PageRollPitch.cpp      |  10 -
 lib/obp60task/PageRudderPosition.cpp |  10 -
 lib/obp60task/PageSolar.cpp          |   9 -
 lib/obp60task/PageThreeValues.cpp    |  12 -
 lib/obp60task/PageTwoValues.cpp      |  16 --
 lib/obp60task/PageVoltage.cpp        |  32 +--
 lib/obp60task/PageWind.cpp           |  62 +++--
 lib/obp60task/PageWindRose.cpp       |  11 +-
 lib/obp60task/PageWindRoseFlex.cpp   |  11 +-
 lib/obp60task/PageXTETrack.cpp       |   9 -
 lib/obp60task/Pagedata.h             |  31 +++
 lib/obp60task/obp60task.cpp          |  53 +++--
 28 files changed, 620 insertions(+), 300 deletions(-)
 create mode 100644 lib/obp60task/Atari16px8b.h

diff --git a/lib/obp60task/Atari16px8b.h b/lib/obp60task/Atari16px8b.h
new file mode 100644
index 0000000..c12a5ba
--- /dev/null
+++ b/lib/obp60task/Atari16px8b.h
@@ -0,0 +1,338 @@
+const uint8_t Atari16pxBitmaps[] PROGMEM = {
+  0x00, 0xFF, 0xFF, 0x0F, 0xCF, 0x3C, 0xF3, 0xCF, 0x30, 0x66, 0x66, 0xFF,
+  0xFF, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66, 0x30, 0xC7, 0xFF, 0xC3, 0x0F,
+  0x9F, 0x0C, 0x3F, 0xFE, 0x30, 0xC0, 0xCF, 0x3D, 0x86, 0x30, 0xC6, 0x1B,
+  0xCF, 0x30, 0x38, 0xF9, 0xB3, 0x63, 0x87, 0x1C, 0x38, 0xDF, 0xBF, 0x36,
+  0x6F, 0xEE, 0xC0, 0xFF, 0xF0, 0x36, 0xEC, 0xCC, 0xCC, 0xCE, 0x63, 0xC6,
+  0x73, 0x33, 0x33, 0x37, 0x6C, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF, 0x3C,
+  0x3C, 0x66, 0x66, 0x30, 0xC3, 0x3F, 0xFC, 0xC3, 0x0C, 0x6D, 0xBD, 0x00,
+  0xFF, 0xF0, 0xFF, 0x0C, 0x30, 0xC6, 0x18, 0xC3, 0x18, 0x63, 0x0C, 0x30,
+  0x7B, 0xFC, 0xF3, 0xCF, 0x7E, 0xF3, 0xCF, 0x3F, 0xDE, 0x30, 0xC7, 0x1C,
+  0x30, 0xC3, 0x0C, 0x30, 0xCF, 0xFF, 0x7B, 0xFC, 0xF3, 0x18, 0x63, 0x0C,
+  0x61, 0x8F, 0xFF, 0xFF, 0xF1, 0x86, 0x30, 0xC1, 0x86, 0xCF, 0x3F, 0xDE,
+  0x18, 0x63, 0x8E, 0x79, 0xED, 0xB6, 0xFF, 0xF1, 0x86, 0xFF, 0xFC, 0x30,
+  0xFB, 0xF0, 0xC3, 0x0F, 0x3F, 0xDE, 0x39, 0xEE, 0x30, 0xC3, 0xEF, 0xF3,
+  0xCF, 0x3F, 0xDE, 0xFF, 0xF0, 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x86, 0x18,
+  0x7B, 0xFC, 0xF3, 0x79, 0xEC, 0xF3, 0xCF, 0x3F, 0xDE, 0x7B, 0xFC, 0xF3,
+  0xFD, 0xF0, 0xC3, 0x0C, 0x77, 0x9C, 0xFF, 0x0F, 0xF0, 0x6D, 0xB0, 0x1B,
+  0x6F, 0x40, 0x0E, 0x38, 0xE3, 0x8E, 0x0E, 0x0E, 0x0E, 0x0E, 0xFF, 0xF0,
+  0x00, 0xFF, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE3, 0x8E, 0x38, 0xE0, 0x7B,
+  0xFC, 0xF3, 0x18, 0x63, 0x0C, 0x30, 0x03, 0x0C, 0x38, 0xFB, 0x9E, 0x1D,
+  0xBA, 0xF5, 0xEE, 0xC1, 0xC5, 0xF9, 0xE0, 0x31, 0xEF, 0xF3, 0xCF, 0x3F,
+  0xFF, 0xCF, 0x3C, 0xF3, 0xFB, 0xFC, 0xF3, 0xFF, 0xEC, 0xF3, 0xCF, 0x3F,
+  0xFE, 0x7B, 0xFC, 0xF3, 0xC3, 0x0C, 0x30, 0xCF, 0x3F, 0xDE, 0xF3, 0xED,
+  0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x7F, 0xBC, 0xFF, 0xFC, 0x30, 0xFB, 0xEC,
+  0x30, 0xC3, 0x0F, 0xFF, 0xFF, 0xFC, 0x30, 0xFB, 0xEC, 0x30, 0xC3, 0x0C,
+  0x30, 0x7F, 0xFC, 0x30, 0xDF, 0x7C, 0xF3, 0xCF, 0x3F, 0xDE, 0xCF, 0x3C,
+  0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFF, 0xF3, 0x0C, 0x30, 0xC3,
+  0x0C, 0x30, 0xCF, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0xCF, 0x3F,
+  0xDE, 0xCD, 0x9B, 0x66, 0xCF, 0x1E, 0x36, 0x6C, 0xCD, 0x9B, 0x1E, 0x30,
+  0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0F, 0xFF, 0xC7, 0x8F, 0xBF,
+  0x7F, 0xFA, 0xF5, 0xE3, 0xC7, 0x8F, 0x1E, 0x30, 0xCF, 0x3C, 0xFB, 0xEF,
+  0xFF, 0xF7, 0xDF, 0x3C, 0xF3, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF,
+  0x3F, 0xDE, 0xFB, 0xFC, 0xF3, 0xCF, 0x3F, 0xFE, 0xC3, 0x0C, 0x30, 0x7B,
+  0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x5F, 0x9B, 0xF9, 0xFB, 0x36, 0x6C,
+  0xDF, 0xBE, 0x6C, 0xCD, 0x9B, 0x1E, 0x30, 0x7F, 0xFC, 0x30, 0xE1, 0xC3,
+  0x87, 0x0C, 0x3F, 0xFE, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3,
+  0x0C, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDE, 0xCF, 0x3C,
+  0xF3, 0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0xC7, 0x8F, 0x1E, 0x3C, 0x7A,
+  0xF5, 0xFF, 0xFF, 0xDF, 0x1C, 0x10, 0xCF, 0x3C, 0xDE, 0x78, 0xC3, 0x1E,
+  0x7B, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0x30, 0xC3, 0x0C,
+  0xFF, 0xF1, 0x86, 0x30, 0xC6, 0x18, 0xC3, 0x0F, 0xFF, 0xFF, 0xCC, 0xCC,
+  0xCC, 0xCC, 0xFF, 0xC3, 0x0C, 0x18, 0x60, 0xC3, 0x06, 0x18, 0x30, 0xC3,
+  0xFF, 0x33, 0x33, 0x33, 0x33, 0xFF, 0x10, 0x20, 0xE1, 0xC6, 0xCD, 0xB1,
+  0xE3, 0xFF, 0xFC, 0x86, 0x38, 0xE3, 0x8C, 0x20, 0x79, 0xF0, 0xDF, 0xFF,
+  0x3C, 0xFF, 0x7C, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3F, 0xFE,
+  0x7B, 0xEC, 0x30, 0xC3, 0x0C, 0x3F, 0x7C, 0x0C, 0x30, 0xDF, 0xFF, 0x3C,
+  0xF3, 0xCF, 0x3F, 0xDF, 0x7B, 0xFC, 0xF3, 0xFF, 0x0C, 0x3F, 0x7C, 0x1C,
+  0xF3, 0x0C, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x7F, 0xFC, 0xF3, 0xCF,
+  0x3F, 0xDF, 0x0F, 0xFF, 0x80, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF,
+  0x3C, 0xF3, 0x66, 0x0E, 0xE6, 0x66, 0x66, 0xFF, 0x18, 0xC0, 0x31, 0x8C,
+  0x63, 0x18, 0xC6, 0x3F, 0xF8, 0xC1, 0x83, 0x06, 0x6D, 0xDF, 0x3C, 0x7C,
+  0xD9, 0x9B, 0x3E, 0x30, 0xEE, 0x66, 0x66, 0x66, 0x66, 0xFF, 0x6D, 0xFF,
+  0xFE, 0xBD, 0x7A, 0xF1, 0xE3, 0xC6, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3,
+  0xCC, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0xFB, 0xFC, 0xF3, 0xCF,
+  0x3C, 0xFF, 0xFB, 0x0C, 0x00, 0x7F, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C,
+  0x30, 0xC0, 0xFB, 0xFC, 0xF0, 0xC3, 0x0C, 0x30, 0xC0, 0x7F, 0xFC, 0x38,
+  0x78, 0x70, 0xFF, 0xF8, 0x30, 0xCF, 0xFF, 0x30, 0xC3, 0x0C, 0x30, 0xF1,
+  0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0xCF, 0x3C, 0xF3, 0xCD,
+  0xE7, 0x8C, 0x30, 0xC7, 0x8F, 0x5E, 0xBF, 0xFF, 0xFB, 0xE3, 0x82, 0xCF,
+  0x37, 0x9E, 0x31, 0xE7, 0xB3, 0xCC, 0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDF,
+  0x0F, 0xFF, 0x80, 0xFF, 0xF1, 0x8C, 0x31, 0x86, 0x3F, 0xFC, 0x0E, 0x30,
+  0x60, 0xC1, 0x87, 0x3C, 0x78, 0x38, 0x30, 0x60, 0xC1, 0x81, 0xC0, 0xFF,
+  0xFF, 0xFF, 0xF0, 0xE0, 0x60, 0xC1, 0x83, 0x07, 0x07, 0x8F, 0x38, 0x60,
+  0xC1, 0x83, 0x1C, 0x00, 0x63, 0xE6, 0xFC, 0xE0, 0xFC, 0x63, 0x18, 0xC6,
+  0x31, 0x8C, 0x7E, 0x00, 0xF3, 0xFF, 0xFF, 0x30, 0xC7, 0xBF, 0xCF, 0x0C,
+  0x33, 0xFD, 0xE3, 0x0C, 0x0E, 0x1E, 0x38, 0x30, 0x30, 0x30, 0x30, 0xFE,
+  0x30, 0x30, 0x30, 0x7F, 0xFF, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E,
+  0xCF, 0x3C, 0xF3, 0xFD, 0xE3, 0x3F, 0x30, 0xC3, 0x0C, 0xFC, 0x63, 0x18,
+  0xC6, 0x31, 0x8C, 0x7E, 0x39, 0xB6, 0x4C, 0x7B, 0x3C, 0xDE, 0x32, 0x6D,
+  0x9C, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0x7D, 0x8E, 0x0D, 0xDA,
+  0x34, 0x68, 0xDD, 0x83, 0x8D, 0xF0, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF,
+  0x7C, 0x0F, 0xC0, 0x1A, 0x6D, 0xB6, 0xC6, 0xC6, 0xC6, 0x80, 0xFF, 0xF0,
+  0xC3, 0x0C, 0xFF, 0x7D, 0x8E, 0x0D, 0xDA, 0xB6, 0x6E, 0xD5, 0x83, 0x8D,
+  0xF0, 0xFF, 0xFC, 0x76, 0xE3, 0xB7, 0x00, 0x30, 0xC3, 0x3F, 0xFC, 0xC3,
+  0x0C, 0x03, 0xFF, 0xC0, 0x69, 0x36, 0xCF, 0xF3, 0x63, 0x96, 0xFC, 0x63,
+  0x18, 0xC6, 0x31, 0x8C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F,
+  0x5D, 0xC0, 0x80, 0x7B, 0x97, 0x2E, 0x5C, 0xB9, 0x5E, 0x85, 0x0A, 0x14,
+  0x28, 0x50, 0x6F, 0xF6, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0xD5,
+  0x50, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0F, 0xC0, 0xB1, 0xB1,
+  0xB1, 0xB6, 0xDB, 0x2C, 0x00, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E,
+  0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0xFC, 0x63, 0x18, 0xC6, 0x31,
+  0x8C, 0x7E, 0x30, 0xC0, 0x0C, 0x30, 0xC6, 0x18, 0xCF, 0x3F, 0xDE, 0xC1,
+  0x83, 0x00, 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x0C, 0x63,
+  0x00, 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x31, 0xEC, 0xC0,
+  0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x67, 0xD9, 0x80, 0x7B,
+  0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0xCF, 0x33, 0x1E, 0xFF, 0x3C,
+  0xFF, 0xFF, 0x3C, 0xF3, 0xCC, 0x7B, 0x37, 0x8C, 0x7B, 0xFC, 0xF3, 0xFF,
+  0xFC, 0xF3, 0xCF, 0x30, 0x3E, 0xFF, 0xE6, 0xCD, 0x9B, 0xF7, 0xFC, 0xF9,
+  0xB3, 0x66, 0xFD, 0xE0, 0x7B, 0xFC, 0xF3, 0xC3, 0x0C, 0x30, 0xCF, 0x3F,
+  0xDE, 0x19, 0xC0, 0xC1, 0x83, 0x00, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30,
+  0xFF, 0xF0, 0x0C, 0x63, 0x00, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30, 0xFF,
+  0xF0, 0x31, 0xEC, 0xC0, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30, 0xFF, 0xF0,
+  0xCF, 0x30, 0x3F, 0xFF, 0x0F, 0xBE, 0xC3, 0x0C, 0x3F, 0xFC, 0xC1, 0x83,
+  0x00, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0x0C, 0x63, 0x00,
+  0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0x31, 0xEC, 0xC0, 0xFF,
+  0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0xCF, 0x30, 0x3F, 0xFC, 0xC3,
+  0x0C, 0x30, 0xC3, 0x3F, 0xFC, 0x78, 0xF9, 0xBB, 0x36, 0x7E, 0xFD, 0xB3,
+  0x66, 0xDD, 0xF3, 0xC0, 0x67, 0xD9, 0x80, 0xCF, 0x3E, 0xFF, 0xFF, 0x7C,
+  0xF3, 0xCC, 0xC1, 0x83, 0x00, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD,
+  0xE0, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0,
+  0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0x67,
+  0xD9, 0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0xCF, 0x30,
+  0x1E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0xCD, 0xE3, 0x1E, 0xCC,
+  0x01, 0x3D, 0x7E, 0x66, 0x66, 0x6E, 0x6E, 0x76, 0x76, 0x66, 0x66, 0x7E,
+  0xBC, 0x80, 0xC1, 0x83, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD,
+  0xE0, 0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0,
+  0x31, 0xEC, 0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0xCF,
+  0x30, 0x33, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0C, 0x63, 0x00,
+  0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0x30, 0xC0, 0xC3, 0x0F, 0xBF, 0xCF,
+  0x3C, 0xFF, 0xFB, 0x0C, 0x30, 0x31, 0xEC, 0xF3, 0xCF, 0xEC, 0xF3, 0xCF,
+  0xED, 0xB0, 0x80, 0xC1, 0x83, 0x00, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF,
+  0x7C, 0x0C, 0x63, 0x00, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0x31,
+  0xEC, 0xC0, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0x67, 0xD9, 0x80,
+  0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0xCF, 0x30, 0x1E, 0x7C, 0x37,
+  0xFF, 0xCF, 0x3F, 0xDF, 0x39, 0xB3, 0x80, 0x79, 0xF0, 0xDF, 0xFF, 0x3C,
+  0xFF, 0x7C, 0x76, 0x7F, 0x1B, 0x7B, 0xFF, 0xD8, 0xD8, 0xFF, 0x7F, 0x7B,
+  0xEC, 0x30, 0xC3, 0x0C, 0x3F, 0x7C, 0x67, 0x00, 0xC1, 0x83, 0x00, 0x7B,
+  0xFC, 0xF3, 0xFF, 0x0C, 0x3F, 0x7C, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3,
+  0xFF, 0x0C, 0x3F, 0x7C, 0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xFF, 0x0C,
+  0x3F, 0x7C, 0xCF, 0x30, 0x1E, 0xFF, 0x3C, 0xFF, 0xC3, 0x0F, 0xDF, 0xC3,
+  0x0C, 0x07, 0x38, 0xC6, 0x31, 0x8C, 0xF7, 0x80, 0x19, 0x98, 0x0E, 0x71,
+  0x8C, 0x63, 0x19, 0xEF, 0x00, 0x31, 0xEC, 0xC0, 0x71, 0xC3, 0x0C, 0x30,
+  0xC3, 0x1E, 0x78, 0xCF, 0x30, 0x1C, 0x70, 0xC3, 0x0C, 0x30, 0xC7, 0x9E,
+  0x78, 0xC7, 0x86, 0x7F, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x67, 0xD9,
+  0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCC, 0xC1, 0x83, 0x00, 0x7B,
+  0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3,
+  0xCF, 0x3C, 0xFF, 0x78, 0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C,
+  0xFF, 0x78, 0x67, 0xD9, 0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78,
+  0xCF, 0x30, 0x1E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDE, 0x30, 0xC0, 0x3F,
+  0xFC, 0x03, 0x0C, 0x01, 0x3D, 0x7E, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x7E,
+  0xBC, 0x80, 0xC1, 0x83, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C,
+  0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0x31, 0xEC,
+  0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0xCF, 0x30, 0x33, 0xCF,
+  0x3C, 0xF3, 0xCF, 0x3F, 0xDF, 0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF,
+  0x3F, 0xDF, 0x0F, 0xFF, 0x80, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF,
+  0x3F, 0xFE, 0xC3, 0x00, 0xCF, 0x30, 0x33, 0xCF, 0x3C, 0xF3, 0xCF, 0xF7,
+  0xC3, 0xFF, 0xE0 };
+
+const GFXglyph Atari16pxGlyphs[] PROGMEM = {
+  {     0,   1,   1,   8,    0,    0 },   // 0x20 ' ' U+0020
+  {     1,   2,  12,   8,    3,  -11 },   // 0x21 '!' U+0021
+  {     4,   6,   6,   8,    1,  -11 },   // 0x22 '"' U+0022
+  {     9,   8,  10,   8,    0,  -11 },   // 0x23 '#' U+0023
+  {    19,   6,  14,   8,    1,  -13 },   // 0x24 '$' U+0024
+  {    30,   6,  10,   8,    1,  -11 },   // 0x25 '%' U+0025
+  {    38,   7,  14,   8,    0,  -13 },   // 0x26 '&' U+0026
+  {    51,   2,   6,   8,    3,  -11 },   // 0x27 ''' U+0027
+  {    53,   4,  12,   8,    3,  -11 },   // 0x28 '(' U+0028
+  {    59,   4,  12,   8,    1,  -11 },   // 0x29 ')' U+0029
+  {    65,   8,  10,   8,    0,  -11 },   // 0x2a '*' U+002A
+  {    75,   6,   8,   8,    1,  -10 },   // 0x2b '+' U+002B
+  {    81,   3,   6,   8,    2,   -3 },   // 0x2c ',' U+002C
+  {    84,   6,   2,   8,    1,   -7 },   // 0x2d '-' U+002D
+  {    86,   2,   4,   8,    3,   -3 },   // 0x2e '.' U+002E
+  {    87,   6,  12,   8,    1,  -11 },   // 0x2f '/' U+002F
+  {    96,   6,  12,   8,    1,  -11 },   // 0x30 '0' U+0030
+  {   105,   6,  12,   8,    1,  -11 },   // 0x31 '1' U+0031
+  {   114,   6,  12,   8,    1,  -11 },   // 0x32 '2' U+0032
+  {   123,   6,  12,   8,    1,  -11 },   // 0x33 '3' U+0033
+  {   132,   6,  12,   8,    1,  -11 },   // 0x34 '4' U+0034
+  {   141,   6,  12,   8,    1,  -11 },   // 0x35 '5' U+0035
+  {   150,   6,  12,   8,    1,  -11 },   // 0x36 '6' U+0036
+  {   159,   6,  12,   8,    1,  -11 },   // 0x37 '7' U+0037
+  {   168,   6,  12,   8,    1,  -11 },   // 0x38 '8' U+0038
+  {   177,   6,  12,   8,    1,  -11 },   // 0x39 '9' U+0039
+  {   186,   2,  10,   8,    3,   -9 },   // 0x3a ':' U+003A
+  {   189,   3,  12,   8,    2,   -9 },   // 0x3b ';' U+003B
+  {   194,   7,   9,   8,    0,  -10 },   // 0x3c '<' U+003C
+  {   202,   6,   6,   8,    1,   -9 },   // 0x3d '=' U+003D
+  {   207,   7,   9,   8,    0,  -10 },   // 0x3e '>' U+003E
+  {   215,   6,  12,   8,    1,  -11 },   // 0x3f '?' U+003F
+  {   224,   7,  12,   8,    0,  -11 },   // 0x40 '@' U+0040
+  {   235,   6,  12,   8,    1,  -11 },   // 0x41 'A' U+0041
+  {   244,   6,  12,   8,    1,  -11 },   // 0x42 'B' U+0042
+  {   253,   6,  12,   8,    1,  -11 },   // 0x43 'C' U+0043
+  {   262,   6,  12,   8,    1,  -11 },   // 0x44 'D' U+0044
+  {   271,   6,  12,   8,    1,  -11 },   // 0x45 'E' U+0045
+  {   280,   6,  12,   8,    1,  -11 },   // 0x46 'F' U+0046
+  {   289,   6,  12,   8,    1,  -11 },   // 0x47 'G' U+0047
+  {   298,   6,  12,   8,    1,  -11 },   // 0x48 'H' U+0048
+  {   307,   6,  12,   8,    1,  -11 },   // 0x49 'I' U+0049
+  {   316,   6,  12,   8,    1,  -11 },   // 0x4a 'J' U+004A
+  {   325,   7,  12,   8,    0,  -11 },   // 0x4b 'K' U+004B
+  {   336,   6,  12,   8,    1,  -11 },   // 0x4c 'L' U+004C
+  {   345,   7,  12,   8,    0,  -11 },   // 0x4d 'M' U+004D
+  {   356,   6,  12,   8,    1,  -11 },   // 0x4e 'N' U+004E
+  {   365,   6,  12,   8,    1,  -11 },   // 0x4f 'O' U+004F
+  {   374,   6,  12,   8,    1,  -11 },   // 0x50 'P' U+0050
+  {   383,   6,  12,   8,    1,  -11 },   // 0x51 'Q' U+0051
+  {   392,   7,  12,   8,    0,  -11 },   // 0x52 'R' U+0052
+  {   403,   6,  12,   8,    1,  -11 },   // 0x53 'S' U+0053
+  {   412,   6,  12,   8,    1,  -11 },   // 0x54 'T' U+0054
+  {   421,   6,  12,   8,    1,  -11 },   // 0x55 'U' U+0055
+  {   430,   6,  12,   8,    1,  -11 },   // 0x56 'V' U+0056
+  {   439,   7,  12,   8,    0,  -11 },   // 0x57 'W' U+0057
+  {   450,   6,  12,   8,    1,  -11 },   // 0x58 'X' U+0058
+  {   459,   6,  12,   8,    1,  -11 },   // 0x59 'Y' U+0059
+  {   468,   6,  12,   8,    1,  -11 },   // 0x5a 'Z' U+005A
+  {   477,   4,  12,   8,    3,  -11 },   // 0x5b '[' U+005B
+  {   483,   6,  12,   8,    1,  -11 },   // 0x5c '\' U+005C
+  {   492,   4,  12,   8,    1,  -11 },   // 0x5d ']' U+005D
+  {   498,   7,   8,   8,    0,  -12 },   // 0x5e '^' U+005E
+  {   505,   7,   2,   8,    0,   -1 },   // 0x5f '_' U+005F
+  {   507,   5,   7,   8,    1,  -13 },   // 0x60 '`' U+0060
+  {   512,   6,   9,   8,    1,   -8 },   // 0x61 'a' U+0061
+  {   519,   6,  12,   8,    1,  -11 },   // 0x62 'b' U+0062
+  {   528,   6,   9,   8,    1,   -8 },   // 0x63 'c' U+0063
+  {   535,   6,  12,   8,    1,  -11 },   // 0x64 'd' U+0064
+  {   544,   6,   9,   8,    1,   -8 },   // 0x65 'e' U+0065
+  {   551,   6,  12,   8,    1,  -11 },   // 0x66 'f' U+0066
+  {   560,   6,  11,   8,    1,   -8 },   // 0x67 'g' U+0067
+  {   569,   6,  12,   8,    1,  -11 },   // 0x68 'h' U+0068
+  {   578,   4,  12,   8,    2,  -11 },   // 0x69 'i' U+0069
+  {   584,   5,  14,   8,    1,  -11 },   // 0x6a 'j' U+006A
+  {   593,   7,  12,   8,    0,  -11 },   // 0x6b 'k' U+006B
+  {   604,   4,  12,   8,    2,  -11 },   // 0x6c 'l' U+006C
+  {   610,   7,   9,   8,    0,   -8 },   // 0x6d 'm' U+006D
+  {   618,   6,   9,   8,    1,   -8 },   // 0x6e 'n' U+006E
+  {   625,   6,   9,   8,    1,   -8 },   // 0x6f 'o' U+006F
+  {   632,   6,  11,   8,    1,   -8 },   // 0x70 'p' U+0070
+  {   641,   6,  11,   8,    1,   -8 },   // 0x71 'q' U+0071
+  {   650,   6,   9,   8,    1,   -8 },   // 0x72 'r' U+0072
+  {   657,   6,   9,   8,    1,   -8 },   // 0x73 's' U+0073
+  {   664,   6,  11,   8,    1,  -10 },   // 0x74 't' U+0074
+  {   673,   6,   9,   8,    1,   -8 },   // 0x75 'u' U+0075
+  {   680,   6,   9,   8,    1,   -8 },   // 0x76 'v' U+0076
+  {   687,   7,   9,   8,    0,   -8 },   // 0x77 'w' U+0077
+  {   695,   6,   9,   8,    1,   -8 },   // 0x78 'x' U+0078
+  {   702,   6,  11,   8,    1,   -8 },   // 0x79 'y' U+0079
+  {   711,   6,   9,   8,    1,   -8 },   // 0x7a 'z' U+007A
+  {   718,   7,  14,   8,    0,  -12 },   // 0x7b '{' U+007B
+  {   731,   2,  14,   8,    3,  -12 },   // 0x7c '|' U+007C
+  {   735,   7,  14,   8,    0,  -12 },   // 0x7d '}' U+007D
+  {   748,   7,   4,   8,    0,   -8 },   // 0x7e '~' U+007E
+  {   752,   5,  11,   8,    1,  -10 },   // 0x7f 'REPLACEMENT CHARACTER *' U+2370
+  {   759,   1,   1,   8,    0,    0 },   // 0x80 'NO-BREAK SPACE' U+00A0
+  {   760,   2,  12,   8,    3,  -10 },   // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
+  {   763,   6,  12,   8,    1,  -11 },   // 0x82 'CENT SIGN' U+00A2
+  {   772,   8,  13,   8,    0,  -12 },   // 0x83 'POUND SIGN' U+00A3
+  {   785,   5,  11,   8,    1,  -10 },   // 0x84 'CURRENCY SIGN' U+00A4
+  {   792,   6,  12,   8,    1,  -11 },   // 0x85 'YEN SIGN' U+00A5
+  {   801,   5,  11,   8,    1,  -10 },   // 0x86 'BROKEN BAR' U+00A6
+  {   808,   6,  12,   8,    1,  -11 },   // 0x87 'SECTION SIGN' U+00A7
+  {   817,   5,  11,   8,    1,  -10 },   // 0x88 'DIAERESIS' U+00A8
+  {   824,   7,  11,   8,    0,  -11 },   // 0x89 'COPYRIGHT SIGN' U+00A9
+  {   834,   6,  11,   8,    1,   -9 },   // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
+  {   843,   7,   7,   8,    0,   -7 },   // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
+  {   850,   6,   5,   8,    1,   -4 },   // 0x8c 'NOT SIGN' U+00AC
+  {   854,   4,   2,   8,    2,   -4 },   // 0x8d 'SOFT HYPHEN' U+00AD
+  {   855,   7,  11,   8,    0,  -11 },   // 0x8e 'REGISTERED SIGN' U+00AE
+  {   865,   7,   2,   8,    0,  -12 },   // 0x8f 'MACRON' U+00AF
+  {   867,   5,   5,   8,    1,  -12 },   // 0x90 'DEGREE SIGN' U+00B0
+  {   871,   6,  11,   8,    1,  -10 },   // 0x91 'PLUS-MINUS SIGN' U+00B1
+  {   880,   4,   6,   8,    1,  -11 },   // 0x92 'SUPERSCRIPT TWO' U+00B2
+  {   883,   4,   6,   8,    1,  -11 },   // 0x93 'SUPERSCRIPT THREE' U+00B3
+  {   886,   5,  11,   8,    1,  -10 },   // 0x94 'ACUTE ACCENT' U+00B4
+  {   893,   8,  10,   8,    0,   -8 },   // 0x95 'MICRO SIGN' U+00B5
+  {   903,   7,  12,   8,    0,  -11 },   // 0x96 'PILCROW SIGN' U+00B6
+  {   914,   4,   4,   8,    2,   -6 },   // 0x97 'MIDDLE DOT' U+00B7
+  {   916,   5,  11,   8,    1,  -10 },   // 0x98 'CEDILLA' U+00B8
+  {   923,   2,   6,   8,    1,  -11 },   // 0x99 'SUPERSCRIPT ONE' U+00B9
+  {   925,   6,  11,   8,    1,   -9 },   // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
+  {   934,   7,   7,   8,    0,   -7 },   // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
+  {   941,   5,  11,   8,    1,  -10 },   // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
+  {   948,   5,  11,   8,    1,  -10 },   // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
+  {   955,   5,  11,   8,    1,  -10 },   // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
+  {   962,   6,  12,   8,    1,  -11 },   // 0x9f 'INVERTED QUESTION MARK' U+00BF
+  {   971,   6,  14,   8,    1,  -13 },   // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
+  {   982,   6,  14,   8,    1,  -13 },   // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
+  {   993,   6,  14,   8,    1,  -13 },   // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
+  {  1004,   6,  14,   8,    1,  -13 },   // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
+  {  1015,   6,  13,   8,    1,  -12 },   // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
+  {  1025,   6,  14,   8,    1,  -13 },   // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
+  {  1036,   7,  13,   8,    0,  -12 },   // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
+  {  1048,   6,  14,   8,    1,  -11 },   // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
+  {  1059,   6,  14,   8,    1,  -13 },   // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
+  {  1070,   6,  14,   8,    1,  -13 },   // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
+  {  1081,   6,  14,   8,    1,  -13 },   // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
+  {  1092,   6,  13,   8,    1,  -12 },   // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
+  {  1102,   6,  14,   8,    1,  -13 },   // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
+  {  1113,   6,  14,   8,    1,  -13 },   // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
+  {  1124,   6,  14,   8,    1,  -13 },   // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
+  {  1135,   6,  13,   8,    1,  -12 },   // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
+  {  1145,   7,  12,   8,    0,  -11 },   // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
+  {  1156,   6,  13,   8,    1,  -12 },   // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
+  {  1166,   6,  14,   8,    1,  -13 },   // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
+  {  1177,   6,  14,   8,    1,  -13 },   // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
+  {  1188,   6,  14,   8,    1,  -13 },   // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
+  {  1199,   6,  14,   8,    1,  -13 },   // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
+  {  1210,   6,  13,   8,    1,  -12 },   // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
+  {  1220,   6,   5,   8,    1,   -6 },   // 0xb7 'MULTIPLICATION SIGN' U+00D7
+  {  1224,   8,  14,   8,    0,  -12 },   // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
+  {  1238,   6,  14,   8,    1,  -13 },   // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
+  {  1249,   6,  14,   8,    1,  -13 },   // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
+  {  1260,   6,  14,   8,    1,  -13 },   // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
+  {  1271,   6,  13,   8,    1,  -12 },   // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
+  {  1281,   6,  14,   8,    1,  -13 },   // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
+  {  1292,   6,  12,   8,    1,  -11 },   // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
+  {  1301,   6,  13,   8,    1,  -11 },   // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
+  {  1311,   6,  13,   8,    1,  -12 },   // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
+  {  1321,   6,  13,   8,    1,  -12 },   // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
+  {  1331,   6,  13,   8,    1,  -12 },   // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
+  {  1341,   6,  13,   8,    1,  -12 },   // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
+  {  1351,   6,  12,   8,    1,  -11 },   // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
+  {  1360,   6,  13,   8,    1,  -12 },   // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
+  {  1370,   8,   9,   8,    0,   -8 },   // 0xc6 'LATIN SMALL LETTER AE' U+00E6
+  {  1379,   6,  11,   8,    1,   -8 },   // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
+  {  1388,   6,  13,   8,    1,  -12 },   // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
+  {  1398,   6,  13,   8,    1,  -12 },   // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
+  {  1408,   6,  13,   8,    1,  -12 },   // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
+  {  1418,   6,  12,   8,    1,  -11 },   // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
+  {  1427,   5,  13,   8,    1,  -12 },   // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
+  {  1436,   5,  13,   8,    2,  -12 },   // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
+  {  1445,   6,  13,   8,    1,  -12 },   // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
+  {  1455,   6,  12,   8,    1,  -11 },   // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
+  {  1464,   6,  13,   8,    1,  -12 },   // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
+  {  1474,   6,  13,   8,    1,  -12 },   // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
+  {  1484,   6,  13,   8,    1,  -12 },   // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
+  {  1494,   6,  13,   8,    1,  -12 },   // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
+  {  1504,   6,  13,   8,    1,  -12 },   // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
+  {  1514,   6,  13,   8,    1,  -12 },   // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
+  {  1524,   6,  12,   8,    1,  -11 },   // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
+  {  1533,   6,   8,   8,    1,  -10 },   // 0xd7 'DIVISION SIGN' U+00F7
+  {  1539,   8,  11,   8,    0,   -9 },   // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
+  {  1550,   6,  13,   8,    1,  -12 },   // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
+  {  1560,   6,  13,   8,    1,  -12 },   // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
+  {  1570,   6,  13,   8,    1,  -12 },   // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
+  {  1580,   6,  12,   8,    1,  -11 },   // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
+  {  1589,   6,  15,   8,    1,  -12 },   // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
+  {  1601,   6,  14,   8,    1,  -11 },   // 0xde 'LATIN SMALL LETTER THORN' U+00FE
+  {  1612,   6,  14,   8,    1,  -11 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
+
+const GFXfont Atari16px PROGMEM = {
+  (uint8_t  *)Atari16pxBitmaps,
+  (GFXglyph *)Atari16pxGlyphs,
+  0x20, 0xDF, 16 };
+
+// Approx. 2974 bytes
diff --git a/lib/obp60task/LedSpiTask.h b/lib/obp60task/LedSpiTask.h
index 5c2e82c..c21a65e 100644
--- a/lib/obp60task/LedSpiTask.h
+++ b/lib/obp60task/LedSpiTask.h
@@ -33,6 +33,7 @@ static Color COLOR_BLACK=Color(0,0,0);
 
 Color setBrightness(const Color &color,uint8_t brightness);
 
+enum BacklightMode {OFF, ON, SUN, BUS, TIME, KEY};
 
 class LedInterface {
     private:
@@ -93,4 +94,4 @@ class LedTaskData{
 void createSpiLedTask(LedTaskData *param);
 
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 85393e1..30a85ee 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -22,6 +22,7 @@
 #include "DSEG7Classic-BoldItalic30pt7b.h"
 #include "DSEG7Classic-BoldItalic42pt7b.h"
 #include "DSEG7Classic-BoldItalic60pt7b.h"
+#include "Atari16px8b.h" // Key label font
 
 // E-Ink Display
 #define GxEPD_WIDTH 400     // Display width
@@ -130,6 +131,21 @@ Color colorMapping(const String &colorString){
     return color;
 }
 
+BacklightMode backlightMapping(const String &backlightString) {
+    static std::map<String, BacklightMode> const table = {
+        {"Off", BacklightMode::OFF},
+        {"Control by Bus", BacklightMode::BUS},
+        {"Control by Time", BacklightMode::TIME},
+        {"Control by Key", BacklightMode::KEY},
+        {"On", BacklightMode::ON},
+    };
+    auto it = table.find(backlightString);
+    if (it != table.end()) {
+        return it->second;
+    }
+    return BacklightMode::OFF;
+}
+
 // All defined colors see pixeltypes.h in FastLED lib
 void setBacklightLED(uint brightness, const Color &color){
     if (ledTaskData == nullptr) return;
@@ -364,6 +380,49 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
     }
 }
 
+void displayFooter(CommonData &commonData) {
+
+    static const uint16_t cx[6] = {35, 101, 167, 233, 299, 365}; // label center positions
+    static const uint16_t cy = 290;
+
+    getdisplay().setFont(&Atari16px);
+    getdisplay().setTextColor(commonData.fgcolor);
+
+    // Frame around key icon area
+    getdisplay().drawLine(0, 280, 399, 280, commonData.fgcolor);
+    getdisplay().drawLine(68, 280, 68, 299, commonData.fgcolor);
+    getdisplay().drawLine(134, 280, 134, 299, commonData.fgcolor);
+    getdisplay().drawLine(200, 280, 200, 299, commonData.fgcolor);
+    getdisplay().drawLine(266, 280, 266, 299, commonData.fgcolor);
+    getdisplay().drawLine(332, 280, 332, 299, commonData.fgcolor);
+
+    for (int i=0; i<6; i++) {
+        uint16_t x, y;
+        if (commonData.keydata[i].label.length() > 0) {
+            // check if icon is enabled
+            String icon_name = commonData.keydata[i].label.substring(1);
+            if (commonData.keydata[i].label[0] == '#') {
+                if (iconmap.find(icon_name) != iconmap.end()) {
+                    x = commonData.keydata[i].x + (commonData.keydata[i].w - icon_width) / 2;
+                    y = commonData.keydata[i].y + (commonData.keydata[i].h - icon_height) / 2;
+                    getdisplay().drawXBitmap(x, y, iconmap[icon_name], icon_width, icon_height, commonData.fgcolor);
+                } else {
+                    // icon is missing, use name instead
+                    x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
+                    y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
+                    drawTextCenter(x, y, icon_name);
+                }
+            } else {
+                //drawTextCenter(cx[i], cy, commonData.keydata[i].label);
+                x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
+                y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
+                drawTextCenter(x, y, commonData.keydata[i].label);
+            }
+        }
+    }
+
+}
+
 // Sunset und sunrise calculation
 SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone){
     GwLog *logger=api->getLogger();
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index ac0c189..e94c535 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -37,20 +37,6 @@ extern const GFXfont DSEG7Classic_BoldItalic30pt7b;
 extern const GFXfont DSEG7Classic_BoldItalic42pt7b;
 extern const GFXfont DSEG7Classic_BoldItalic60pt7b;
 
-// Icons
-#define icon_width 16
-#define icon_height 16
-
-static unsigned char swipe_bits[] PROGMEM = {
-   0x80, 0x03, 0xe0, 0x06, 0xb0, 0x0a, 0xa8, 0x0a, 0xa8, 0x0a, 0xa8, 0x3a,
-   0x28, 0x28, 0x08, 0x28, 0x08, 0x28, 0x08, 0x26, 0x08, 0x21, 0x08, 0x10,
-   0x10, 0x08, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00 };
-
-static unsigned char lock_bits[] PROGMEM = {
-   0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
-   0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
-   0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
-
 // Global functions
 #ifdef DISPLAY_GDEW042T2
 GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
@@ -85,6 +71,7 @@ void togglePortPin(uint pin);                   // Toggle extension port pin
 Color colorMapping(const String &colorString);          // Color mapping string to CHSV colors
 void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs
 void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs
+BacklightMode backlightMapping(const String &backlightString);// Configuration string to value
 
 void setFlashLED(bool status);                  // Set flash LED
 void blinkingFlashLED();                        // Blinking function for flash LED
@@ -102,6 +89,7 @@ void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
 void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
 
 void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header
+void displayFooter(CommonData &commonData);
 
 SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise
 
@@ -112,11 +100,68 @@ void startLedTask(GwApi *api);
 
 void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
 
-#define fram_width 16
-#define fram_height 16
+// Icons
+#define icon_width 16
+#define icon_height 16
+
+static unsigned char left_bits[] PROGMEM = {
+   0x00, 0x00, 0xc0, 0x01, 0xe0, 0x01, 0xf0, 0x01, 0xf8, 0x01, 0xfc, 0x7f,
+   0xfe, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x01,
+   0xf0, 0x01, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0x00 };
+
+static unsigned char right_bits[] PROGMEM = {
+   0x00, 0x00, 0x80, 0x03, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x1f, 0xfe, 0x3f,
+   0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x80, 0x1f,
+   0x80, 0x0f, 0x80, 0x07, 0x80, 0x03, 0x00, 0x00 };
+
+static unsigned char swipe_bits[] PROGMEM = {
+   0x80, 0x03, 0xe0, 0x06, 0xb0, 0x0a, 0xa8, 0x0a, 0xa8, 0x0a, 0xa8, 0x3a,
+   0x28, 0x28, 0x08, 0x28, 0x08, 0x28, 0x08, 0x26, 0x08, 0x21, 0x08, 0x10,
+   0x10, 0x08, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00 };
+
+static unsigned char lock_bits[] PROGMEM = {
+   0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
+   0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
+   0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
+
+static unsigned char plus_bits[] = {
+   0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0xc4, 0x08, 0xc2, 0x10,
+   0xf2, 0x13, 0xf2, 0x13, 0xc2, 0x10, 0xc4, 0x08, 0x04, 0x0c, 0x18, 0x1e,
+   0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
+
+static unsigned char minus_bits[] = {
+   0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x04, 0x08, 0x02, 0x10,
+   0xf2, 0x13, 0xf2, 0x13, 0x02, 0x10, 0x04, 0x08, 0x04, 0x0c, 0x18, 0x1e,
+   0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
+
 static unsigned char fram_bits[] = {
    0xf8, 0x1f, 0xff, 0xff, 0x9f, 0xff, 0x98, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
    0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
    0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
 
+static std::map<String, unsigned char *> iconmap = {
+    {"LEFT", left_bits},
+    {"RIGHT", right_bits},
+    {"SWIPE", swipe_bits},
+    {"LOCK", lock_bits},
+    {"PLUS", plus_bits},
+    {"MINUS", minus_bits}
+};
+
+// Other symbols
+#define exclamation_width 32
+#define exclamation_height 32
+static unsigned char exclamation_bits[] = {
+   0x00, 0xc0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xb0, 0x0d, 0x00,
+   0x00, 0xd8, 0x1b, 0x00, 0x00, 0xec, 0x37, 0x00, 0x00, 0xf6, 0x6f, 0x00,
+   0x00, 0x3b, 0xdc, 0x00, 0x80, 0x3d, 0xbc, 0x01, 0xc0, 0x3e, 0x7c, 0x03,
+   0x60, 0x3f, 0xfc, 0x06, 0xb0, 0x3f, 0xfc, 0x0d, 0xd8, 0x3f, 0xfc, 0x1b,
+   0xec, 0x3f, 0xfc, 0x37, 0xf6, 0x3f, 0xfc, 0x6f, 0xfb, 0x3f, 0xfc, 0xdf,
+   0xfd, 0x3f, 0xfc, 0xbf, 0xfd, 0x3f, 0xfc, 0xbf, 0xfb, 0x3f, 0xfc, 0xdf,
+   0xf6, 0x3f, 0xfc, 0x6f, 0xec, 0x3f, 0xfc, 0x37, 0xd8, 0xff, 0xff, 0x1b,
+   0xb0, 0xff, 0xff, 0x0d, 0x60, 0x3f, 0xfc, 0x06, 0xc0, 0x3e, 0x7c, 0x03,
+   0x80, 0x3d, 0xbc, 0x01, 0x00, 0x3b, 0xdc, 0x00, 0x00, 0xf6, 0x6f, 0x00,
+   0x00, 0xec, 0x37, 0x00, 0x00, 0xd8, 0x1b, 0x00, 0x00, 0xb0, 0x0d, 0x00,
+   0x00, 0x60, 0x06, 0x00, 0x00, 0xc0, 0x03, 0x00 };
+
 #endif
diff --git a/lib/obp60task/OBP60Keypad.h b/lib/obp60task/OBP60Keypad.h
index e51fe9d..017d07f 100644
--- a/lib/obp60task/OBP60Keypad.h
+++ b/lib/obp60task/OBP60Keypad.h
@@ -19,6 +19,38 @@ int keydelay = 250;     // Delay after key pressed in  [ms]
 bool keylock = false;   // Key lock after pressed key is valid (repeat protection by conginous pressing)
 long starttime = 0;     // Start time point for pressed key
 
+void initKeys(CommonData &commonData) {
+    // coordinates for virtual keyboard keys
+    commonData.keydata[0].x = 1;
+    commonData.keydata[0].y = 281;
+    commonData.keydata[0].w = 67;
+    commonData.keydata[0].h = 18;
+
+    commonData.keydata[1].x = 69;
+    commonData.keydata[1].y = 281;
+    commonData.keydata[1].w = 66;
+    commonData.keydata[1].h = 18;
+
+    commonData.keydata[2].x = 135;
+    commonData.keydata[2].y = 281;
+    commonData.keydata[2].w = 66;
+    commonData.keydata[2].h = 18;
+
+    commonData.keydata[3].x = 201;
+    commonData.keydata[3].y = 281;
+    commonData.keydata[3].w = 66;
+    commonData.keydata[3].h = 18;
+
+    commonData.keydata[4].x = 267;
+    commonData.keydata[4].y = 281;
+    commonData.keydata[4].w = 66;
+    commonData.keydata[4].h = 18;
+
+    commonData.keydata[5].x = 333;
+    commonData.keydata[5].y = 281;
+    commonData.keydata[5].w = 66;
+    commonData.keydata[5].h = 18;
+}
 
 int readKeypad(uint thSensitivity) {
   
@@ -177,4 +209,4 @@ int readKeypad(uint thSensitivity) {
   return keystatus;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/lib/obp60task/PageBME280.cpp b/lib/obp60task/PageBME280.cpp
index 3b68de6..f0f02c0 100644
--- a/lib/obp60task/PageBME280.cpp
+++ b/lib/obp60task/PageBME280.cpp
@@ -176,17 +176,6 @@ class PageBME280 : public Page
         // Show bus data
         getdisplay().print(svalue3);                         // Real value as formated string
 
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageBattery.cpp b/lib/obp60task/PageBattery.cpp
index 1b12d93..bbde098 100644
--- a/lib/obp60task/PageBattery.cpp
+++ b/lib/obp60task/PageBattery.cpp
@@ -13,6 +13,11 @@ class PageBattery : public Page
         common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery");
     }
 
+    virtual void setupKeys(){
+        Page::setupKeys();
+        commonData->keydata[0].label = "AVG";
+    }
+
     virtual int handleKey(int key){
         // Change average
         if(key == 1){
@@ -283,20 +288,6 @@ class PageBattery : public Page
             getdisplay().print("---");                       // No sensor data (sensor is off)
         }
 
-
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            getdisplay().setCursor(10, 290);
-            getdisplay().print("[AVG]");
-            if(String(backlightMode) == "Control by Key"){              // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageBattery2.cpp b/lib/obp60task/PageBattery2.cpp
index 4cb4a40..b8694a7 100644
--- a/lib/obp60task/PageBattery2.cpp
+++ b/lib/obp60task/PageBattery2.cpp
@@ -16,6 +16,12 @@ public:
         commonData = &common;
         common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery2");
     }
+
+    virtual void setupKeys(){
+        Page::setupKeys();
+        commonData->keydata[0].label = "AVG";
+    }
+
     virtual int handleKey(int key){
          // Change average
         if(key == 1){
@@ -328,17 +334,6 @@ public:
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().print("W");
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            getdisplay().setCursor(10, 290);
-            getdisplay().print("[AVG]");
-            if(String(backlightMode) == "Control by Key"){              // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageClock.cpp b/lib/obp60task/PageClock.cpp
index f99679a..3442797 100644
--- a/lib/obp60task/PageClock.cpp
+++ b/lib/obp60task/PageClock.cpp
@@ -312,16 +312,6 @@ public:
         getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
         getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
 
-//*******************************************************************************************
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageDST810.cpp b/lib/obp60task/PageDST810.cpp
index 568e3e2..0da67ff 100644
--- a/lib/obp60task/PageDST810.cpp
+++ b/lib/obp60task/PageDST810.cpp
@@ -242,18 +242,6 @@ public:
             unit4old = unit4;                                           // Save the old unit
         }
 
-
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageFluid.cpp b/lib/obp60task/PageFluid.cpp
index 6c12635..e03c814 100644
--- a/lib/obp60task/PageFluid.cpp
+++ b/lib/obp60task/PageFluid.cpp
@@ -57,6 +57,13 @@ static unsigned char gasoline_bits[] = {
    0x98, 0xcf, 0x38, 0xe7, 0x78, 0xf0, 0xf8, 0xfa, 0xf8, 0xfa, 0x78, 0xf0,
    0x38, 0xe7, 0x98, 0xcf, 0xf8, 0xff, 0xf0, 0x7f };
 
+#define fish_width 16
+#define fish_height 16
+static unsigned char fish_bits[] = {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xf0, 0x03, 0xf8, 0x37,
+   0xfc, 0x7f, 0xfc, 0x7f, 0xec, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x37,
+   0xf0, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00 };
+
 class PageFluid : public Page
 {
     int fluidtype;
@@ -150,6 +157,12 @@ class PageFluid : public Page
             case 1:
                 getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData->fgcolor);
                 break;
+            case 2: // gray water no symbol yet
+                // getdisplay().drawXBitmap(c.x-8, c.y-50, gray_bits, gray_width, gray_height, commonData->fgcolor);
+                break;
+            case 3:
+                getdisplay().drawXBitmap(c.x-8, c.y-50, fish_bits, fish_width, fish_height, commonData->fgcolor);
+                break;
             case 4:
                 getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData->fgcolor);
                 break;
@@ -215,15 +228,6 @@ class PageFluid : public Page
             getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
         }
  
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 296);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageFourValues.cpp b/lib/obp60task/PageFourValues.cpp
index e0c418f..73329e4 100644
--- a/lib/obp60task/PageFourValues.cpp
+++ b/lib/obp60task/PageFourValues.cpp
@@ -282,18 +282,6 @@ class PageFourValues : public Page
             unit4old = unit4;                                           // Save the old unit
         }
 
-
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageFourValues2.cpp b/lib/obp60task/PageFourValues2.cpp
index 9f3f07b..6ac5981 100644
--- a/lib/obp60task/PageFourValues2.cpp
+++ b/lib/obp60task/PageFourValues2.cpp
@@ -282,18 +282,6 @@ class PageFourValues2 : public Page
             unit4old = unit4;                                           // Save the old unit
         }
 
-
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageGenerator.cpp b/lib/obp60task/PageGenerator.cpp
index fc0c402..20e7652 100644
--- a/lib/obp60task/PageGenerator.cpp
+++ b/lib/obp60task/PageGenerator.cpp
@@ -203,15 +203,6 @@ public:
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().print("W");
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){              // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageKeelPosition.cpp b/lib/obp60task/PageKeelPosition.cpp
index 6ecaf61..f3eac49 100644
--- a/lib/obp60task/PageKeelPosition.cpp
+++ b/lib/obp60task/PageKeelPosition.cpp
@@ -206,16 +206,6 @@ public:
             getdisplay().print("No sensor data");            // Info missing sensor
         }
 
-//*******************************************************************************************
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageOneValue.cpp b/lib/obp60task/PageOneValue.cpp
index 6910890..84aff6d 100644
--- a/lib/obp60task/PageOneValue.cpp
+++ b/lib/obp60task/PageOneValue.cpp
@@ -102,15 +102,6 @@ class PageOneValue : public Page
             unit1old = unit1;                                           // Save the old unit
         }
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageRollPitch.cpp b/lib/obp60task/PageRollPitch.cpp
index b7c4c57..320e43f 100644
--- a/lib/obp60task/PageRollPitch.cpp
+++ b/lib/obp60task/PageRollPitch.cpp
@@ -305,16 +305,6 @@ public:
             getdisplay().print("No sensor data");            // Info missing sensor
         }
 
-//*******************************************************************************************
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/PageRudderPosition.cpp b/lib/obp60task/PageRudderPosition.cpp
index afceeb4..6ed0d4c 100644
--- a/lib/obp60task/PageRudderPosition.cpp
+++ b/lib/obp60task/PageRudderPosition.cpp
@@ -205,16 +205,6 @@ public:
         getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
         getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
 
-//*******************************************************************************************
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageSolar.cpp b/lib/obp60task/PageSolar.cpp
index 786dfe7..646a568 100644
--- a/lib/obp60task/PageSolar.cpp
+++ b/lib/obp60task/PageSolar.cpp
@@ -199,15 +199,6 @@ public:
         getdisplay().setFont(&Ubuntu_Bold16pt7b);
         getdisplay().print("W");
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){              // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageThreeValues.cpp b/lib/obp60task/PageThreeValues.cpp
index a4fbf90..c740b30 100644
--- a/lib/obp60task/PageThreeValues.cpp
+++ b/lib/obp60task/PageThreeValues.cpp
@@ -222,18 +222,6 @@ class PageThreeValues : public Page
             unit3old = unit3;                                           // Save the old unit
         }
 
-
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageTwoValues.cpp b/lib/obp60task/PageTwoValues.cpp
index e8dcf40..6b8d0d1 100644
--- a/lib/obp60task/PageTwoValues.cpp
+++ b/lib/obp60task/PageTwoValues.cpp
@@ -163,22 +163,6 @@ class PageTwoValues : public Page
             unit2old = unit2;                                           // Save the old unit
         }
 
-
-        // ############### Key Layout ################
-
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-        else{
-            getdisplay().setCursor(130, 290);
-            getdisplay().print(" [    Keylock active    ]");
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp
index 76d67e2..cc77b01 100644
--- a/lib/obp60task/PageVoltage.cpp
+++ b/lib/obp60task/PageVoltage.cpp
@@ -22,6 +22,14 @@ public:
             mode = fram.read(FRAM_VOLTAGE_MODE);
         }
     }
+
+    virtual void setupKeys(){
+        Page::setupKeys();
+        commonData->keydata[0].label = "AVG";
+        commonData->keydata[1].label = "MODE";
+        commonData->keydata[4].label = "TRD";
+    }
+
     virtual int handleKey(int key){
          // Change average
         if(key == 1){
@@ -242,10 +250,8 @@ public:
                 }
             }
 
-            // Trend indicator
             // Show trend indicator
             if(trend == true){
-                getdisplay().fillRect(310, 240, 40, 120, commonData->bgcolor);   // Clear area
                 getdisplay().fillRect(315, 183, 35, 4, commonData->fgcolor);   // Draw separator
                 if(int(raw * 10) > int(valueTrend * 10)){
                     displayTrendHigh(320, 174, 11, commonData->fgcolor);  // Show high indicator
@@ -254,10 +260,6 @@ public:
                     displayTrendLow(320, 195, 11, commonData->fgcolor);   // Show low indicator
                 }
             }
-            // No trend indicator
-            else{
-                getdisplay().fillRect(310, 240, 40, 120, commonData->bgcolor);   // Clear area
-            }
 
         }
         else {
@@ -360,27 +362,11 @@ public:
 
             // FRAM indicator
             if (hasFRAM) {
-                getdisplay().drawXBitmap(300, 240, fram_bits, fram_width, fram_height, commonData->fgcolor);
+                getdisplay().drawXBitmap(300, 240, fram_bits, icon_width, icon_height, commonData->fgcolor);
             }
 
         }
 
-        // Key Layout
-        getdisplay().setTextColor(commonData->fgcolor);
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            getdisplay().setCursor(10, 290);
-            getdisplay().print("[AVG]");
-            getdisplay().setCursor(62, 290);
-            getdisplay().print("[MODE]");
-            getdisplay().setCursor(293, 290);
-            getdisplay().print("[TRD]");
-            if(String(backlightMode) == "Control by Key"){              // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageWind.cpp b/lib/obp60task/PageWind.cpp
index 39f6a67..3702613 100644
--- a/lib/obp60task/PageWind.cpp
+++ b/lib/obp60task/PageWind.cpp
@@ -229,6 +229,17 @@ public:
         }
     }
 
+    virtual void setupKeys(){
+        Page::setupKeys();
+        commonData->keydata[0].label = "MODE";
+        if (mode == 'X') {
+            commonData->keydata[1].label = "#MINUS";
+            commonData->keydata[4].label = "#PLUS";
+        } else {
+            commonData->keydata[1].label = "SRC";
+        }
+    }
+
     // Key functions
     virtual int handleKey(int key){
 
@@ -241,26 +252,28 @@ public:
                 mode = 'N';
             }
             if (hasFRAM) fram.write(FRAM_WIND_MODE, mode);
+            setupKeys();
             return 0;               // Commit the key
         }
 
-        if(key == 3){               // Source switch
-            if(source == 'A'){
-                source = 'T';
+        // Set source or reduce instrument size
+        if(key == 2){
+            if(mode == 'X'){
+                // Code for reduce
+                lp = lp - 10;
+                if(lp < 10){
+                    lp = 10;
+                }
+                if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
             } else {
-                source = 'A';
+                // Code for set source
+                if(source == 'A'){
+                    source = 'T';
+                } else {
+                    source = 'A';
+                }
+                if (hasFRAM) fram.write(FRAM_WIND_SRC, source);
             }
-            if (hasFRAM) fram.write(FRAM_WIND_SRC, source);
-            return 0;               // Commit the key
-        }
-
-        // Reduce instrument size
-        if(key == 2 && mode == 'X'){    // Code for reduce
-            lp = lp - 10;
-            if(lp < 10){
-                lp = 10;
-            }
-            if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
             return 0;               // Commit the key
         }
 
@@ -599,25 +612,6 @@ public:
 
         }
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            getdisplay().setCursor(10, 290);
-            getdisplay().print("[MODE]");
-
-            if (mode == 'X') {
-                getdisplay().setCursor(85, 290);
-                getdisplay().print("[ - ]");
-                getdisplay().setCursor(295, 290);
-                getdisplay().print("[ + ]");
-            }
-
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();     // Partial update (fast)
 
diff --git a/lib/obp60task/PageWindRose.cpp b/lib/obp60task/PageWindRose.cpp
index be3d468..88c490f 100644
--- a/lib/obp60task/PageWindRose.cpp
+++ b/lib/obp60task/PageWindRose.cpp
@@ -10,7 +10,7 @@ int16_t lp = 80;                    // Pointer length
 public:
     PageWindRose(CommonData &common){
         commonData = &common;
-        common.logger->logDebug(GwLog::LOG,"Show PageWindRose");
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageWindRose");
     }
 
     // Key functions
@@ -350,15 +350,6 @@ public:
             getdisplay().print(unit6old);                // Unit
         }
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageWindRoseFlex.cpp b/lib/obp60task/PageWindRoseFlex.cpp
index a01e73f..ba4b029 100644
--- a/lib/obp60task/PageWindRoseFlex.cpp
+++ b/lib/obp60task/PageWindRoseFlex.cpp
@@ -10,7 +10,7 @@ int16_t lp = 80;                    // Pointer length
 public:
     PageWindRoseFlex(CommonData &common){
         commonData = &common;
-        common.logger->logDebug(GwLog::LOG,"Show PageWindRoseFlex");
+        common.logger->logDebug(GwLog::LOG,"Instantiate PageWindRoseFlex");
     }
 
     // Key functions
@@ -351,15 +351,6 @@ public:
             getdisplay().print(unit6old);                // Unit
         }
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 290);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
     };
diff --git a/lib/obp60task/PageXTETrack.cpp b/lib/obp60task/PageXTETrack.cpp
index d16a8b7..7b5f487 100644
--- a/lib/obp60task/PageXTETrack.cpp
+++ b/lib/obp60task/PageXTETrack.cpp
@@ -197,15 +197,6 @@ class PageXTETrack : public Page
         drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData->fgcolor, seg[4]);
         drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData->fgcolor, seg[5]);
 
-        // Key Layout
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        if(commonData->keylock == false){
-            if(String(backlightMode) == "Control by Key"){                  // Key for illumination
-                getdisplay().setCursor(343, 296);
-                getdisplay().print("[ILUM]");
-            }
-        }
-
         // Update display
         getdisplay().nextPage();    // Partial update (fast)
 
diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h
index 9f9764c..2a72ba6 100644
--- a/lib/obp60task/Pagedata.h
+++ b/lib/obp60task/Pagedata.h
@@ -3,6 +3,7 @@
 #include "GwApi.h"
 #include <functional>
 #include <vector>
+#include "LedSpiTask.h"
 
 #define MAX_PAGE_NUMBER 10    // Max number of pages for show data
 
@@ -63,12 +64,30 @@ typedef struct{
   bool sunDown = true;
 } SunData;
 
+typedef struct{
+  String label = "";
+  bool selected = false;    // for virtual keyboard function
+  uint16_t x;
+  uint16_t y;
+  uint16_t w;
+  uint16_t h;
+} TouchKeyData;
+
+typedef struct{
+    Color color;        // red, orange, yellow, green, blue, aqua, violet, white
+    BacklightMode mode; // off, on, sun, bus, time, key
+    uint8_t brightness; // 0% (off), user setting from 20% to 100% full power
+    bool on;            // fast on/off detector
+} BacklightData;
+
 typedef struct{
   GwApi::Status status;
   GwLog *logger=NULL;
   GwConfigHandler *config=NULL;
   SensorData data;
   SunData sundata;
+  TouchKeyData keydata[6];
+  BacklightData backlight;
   GwApi::BoatValue *time=NULL;
   GwApi::BoatValue *date=NULL;
   uint16_t fgcolor;
@@ -83,6 +102,18 @@ class Page{
   public:
     virtual void displayPage(PageData &pageData)=0;
     virtual void displayNew(PageData &pageData){}
+    virtual void setupKeys() {
+        commonData->keydata[0].label = "";
+        commonData->keydata[1].label = "";
+        commonData->keydata[2].label = "#LEFT";
+        commonData->keydata[3].label = "#RIGHT";
+        commonData->keydata[4].label = "";
+        if (commonData->backlight.mode == KEY) {
+            commonData->keydata[5].label = "ILUM";
+        } else {
+            commonData->keydata[5].label = "";
+        }
+    }
     //return -1 if handled by the page
     virtual int handleKey(int key){return key;}
 };
diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp
index ade14fa..f336f68 100644
--- a/lib/obp60task/obp60task.cpp
+++ b/lib/obp60task/obp60task.cpp
@@ -76,10 +76,10 @@ void OBP60Init(GwApi *api){
     if(String(backlightMode) == "On"){
            setBacklightLED(brightness, colorMapping(backlightColor));
     }
-    if(String(backlightMode) == "Off"){
+    else if(String(backlightMode) == "Off"){
            setBacklightLED(0, COLOR_BLACK); // Backlight LEDs off (blue without britghness)
     }
-    if(String(backlightMode) == "Control by Key"){
+    else if(String(backlightMode) == "Control by Key"){
            setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
     }
 
@@ -285,13 +285,16 @@ void OBP60Task(GwApi *api){
     commonData.logger=logger;
     commonData.config=config;
 
+    // Keyboard coordinates for page footer
+    initKeys(commonData);
+
     tN2kMsg N2kMsg;
 
     LOG_DEBUG(GwLog::LOG,"obp60task started");
     for (auto it=allPages.pages.begin();it != allPages.pages.end();it++){
         LOG_DEBUG(GwLog::LOG,"found registered page %s",(*it)->pageName.c_str());
     }
-    
+
     // Init E-Ink display
     String displaymode = api->getConfig()->getConfigItem(api->getConfig()->display,true)->asString();
     String displaycolor = api->getConfig()->getConfigItem(api->getConfig()->displaycolor,true)->asString();
@@ -416,12 +419,13 @@ void OBP60Task(GwApi *api){
 
     // Configuration values for main loop
     String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
-    String backlight = api->getConfig()->getConfigItem(api->getConfig()->backlight,true)->asString();
     String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
     String tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asString();
-    String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString();
-    Color color = colorMapping(backlightColor);
-    uint brightness = 2.55 * uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt());
+
+    commonData.backlight.mode = backlightMapping(config->getConfigItem(config->backlight,true)->asString());
+    commonData.backlight.color = colorMapping(config->getConfigItem(config->blColor,true)->asString());
+    commonData.backlight.brightness = 2.55 * uint(config->getConfigItem(config->blBrightness,true)->asInt());
+
     bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
     String cpuspeed = api->getConfig()->getConfigItem(api->getConfig()->cpuSpeed,true)->asString();
     uint hdopAccuracy = uint(api->getConfig()->getConfigItem(api->getConfig()->hdopAccuracy,true)->asInt());
@@ -448,7 +452,9 @@ void OBP60Task(GwApi *api){
     long starttime3 = millis();     // Display update all 1s
     long starttime4 = millis();     // Delayed display update after 4s when select a new page
     long starttime5 = millis();     // Calculate sunrise and sunset all 1s
-    
+
+    pages[pageNumber].page->setupKeys(); // Initialize keys for first page
+
     // Main loop runs with 100ms
     //####################################################################################
     
@@ -505,14 +511,15 @@ void OBP60Task(GwApi *api){
                 {
                     // Decoding all key codes
                     // #6 Backlight on if key controled
-                    if(String(backlight) == "Control by Key"){
+                    if (commonData.backlight.mode == BacklightMode::KEY) {
+                    // if(String(backlight) == "Control by Key"){
                         if(keyboardMessage == 6){
                             LOG_DEBUG(GwLog::LOG,"Toggle Backlight LED");
-                            toggleBacklightLED(brightness, color);
+                            toggleBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
                         }
                     }
-                    // #9 Swipe right
-                    if (keyboardMessage == 9)
+                    // #9 Swipe right or #4 key right
+                    if ((keyboardMessage == 9) or (keyboardMessage == 4))
                     {
                         pageNumber++;
                         if (pageNumber >= numPages){
@@ -521,8 +528,8 @@ void OBP60Task(GwApi *api){
                         commonData.data.actpage = pageNumber + 1;
                         commonData.data.maxpage = numPages;
                     }
-                    // #10 Swipe left
-                    if (keyboardMessage == 10)
+                    // #10 Swipe left or #3 key left
+                    if ((keyboardMessage == 10) or (keyboardMessage == 3))
                     {
                         pageNumber--;
                         if (pageNumber < 0){
@@ -549,9 +556,10 @@ void OBP60Task(GwApi *api){
                     // Provide sundata to all pages
                     commonData.sundata = calcSunsetSunrise(api, time->value , date->value, lat->value, lon->value, tz.toDouble());
                     // Backlight with sun control
-                    if(String(backlight) == "Control by Sun"){
+                    if (commonData.backlight.mode == BacklightMode::SUN) {
+                    // if(String(backlight) == "Control by Sun"){
                         if(commonData.sundata.sunDown == true){
-                            setBacklightLED(brightness, color);
+                            setBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
                         }
                         else{
                             setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
@@ -616,11 +624,11 @@ void OBP60Task(GwApi *api){
                 // Show header if enabled
                 getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);   // Clear display
                 if (pages[pageNumber].description && pages[pageNumber].description->header){
-                    //build some header and footer using commonData
-                    getdisplay().fillScreen(commonData.bgcolor);             // Clear display
-                    displayHeader(commonData, date, time, hdop);  // Sown header
+                    // build header using commonData
+                    getdisplay().fillScreen(commonData.bgcolor);  // Clear display
+                    displayHeader(commonData, date, time, hdop);  // Show page header
                 }
-                
+
                 // Call the particular page
                 Page *currentPage=pages[pageNumber].page;
                 if (currentPage == NULL){
@@ -630,11 +638,16 @@ void OBP60Task(GwApi *api){
                 else{
                     if (lastPage != pageNumber){
                         if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember page for device restart
+                        currentPage->setupKeys();
                         currentPage->displayNew(pages[pageNumber].parameters);
                         lastPage=pageNumber;
                     }
                     //call the page code
                     LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber);
+                    // Show footer if enabled (together with header)
+                    if (pages[pageNumber].description && pages[pageNumber].description->header){
+                        displayFooter(commonData);
+                    }
                     currentPage->displayPage(pages[pageNumber].parameters);
                 }
             }

From f690cf3a3491a0a32719011ca24cf41789684983 Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Thu, 16 Jan 2025 19:39:35 +0100
Subject: [PATCH 29/35] Hide key labels in keylock mode, improved swipe icon

---
 lib/obp60task/OBP60Extensions.cpp | 69 ++++++++++++++-----------------
 lib/obp60task/OBP60Extensions.h   | 14 +++----
 2 files changed, 39 insertions(+), 44 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 2e4ae1c..146f3c9 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -287,15 +287,11 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
 
     if(commonData.config->getBool(commonData.config->statusLine) == true){
 
-        if(commonData.config->getString(commonData.config->displaycolor) == "Normal"){
-            textcolor = GxEPD_BLACK;
-        }
-        else{
-            textcolor = GxEPD_WHITE;
-        }
+        // Header separator line (optional)
+        // getdisplay().drawLine(0, 19, 399, 19, commonData.fgcolor);
 
         // Show status info
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(0, 15);
         if(commonData.status.wifiApOn){
@@ -339,18 +335,18 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
 
         // Current page number in a small box
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        getdisplay().drawRect(170, 2, 20, 15, textcolor);
+        getdisplay().drawRect(170, 2, 20, 15, commonData.fgcolor);
         drawTextCenter(179, 9, String(commonData.data.actpage));
 
         // Heartbeat as dot
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
         getdisplay().setCursor(205, 14);
         getdisplay().print(heartbeat ? "." : " ");
         heartbeat = !heartbeat; 
 
         // Date and time
-        getdisplay().setTextColor(textcolor);
+        getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold8pt7b);
         getdisplay().setCursor(230, 15);
         // Show date and time if date present
@@ -382,45 +378,44 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
 
 void displayFooter(CommonData &commonData) {
 
-    static const uint16_t cx[6] = {35, 101, 167, 233, 299, 365}; // label center positions
-    static const uint16_t cy = 290;
-
     getdisplay().setFont(&Atari16px);
     getdisplay().setTextColor(commonData.fgcolor);
 
     // Frame around key icon area
     getdisplay().drawLine(0, 280, 399, 280, commonData.fgcolor);
-    getdisplay().drawLine(68, 280, 68, 299, commonData.fgcolor);
-    getdisplay().drawLine(134, 280, 134, 299, commonData.fgcolor);
-    getdisplay().drawLine(200, 280, 200, 299, commonData.fgcolor);
-    getdisplay().drawLine(266, 280, 266, 299, commonData.fgcolor);
-    getdisplay().drawLine(332, 280, 332, 299, commonData.fgcolor);
-
-    for (int i=0; i<6; i++) {
-        uint16_t x, y;
-        if (commonData.keydata[i].label.length() > 0) {
-            // check if icon is enabled
-            String icon_name = commonData.keydata[i].label.substring(1);
-            if (commonData.keydata[i].label[0] == '#') {
-                if (iconmap.find(icon_name) != iconmap.end()) {
-                    x = commonData.keydata[i].x + (commonData.keydata[i].w - icon_width) / 2;
-                    y = commonData.keydata[i].y + (commonData.keydata[i].h - icon_height) / 2;
-                    getdisplay().drawXBitmap(x, y, iconmap[icon_name], icon_width, icon_height, commonData.fgcolor);
+    if (! commonData.keylock) {
+        getdisplay().drawLine(68, 280, 68, 299, commonData.fgcolor);
+        getdisplay().drawLine(134, 280, 134, 299, commonData.fgcolor);
+        getdisplay().drawLine(200, 280, 200, 299, commonData.fgcolor);
+        getdisplay().drawLine(266, 280, 266, 299, commonData.fgcolor);
+        getdisplay().drawLine(332, 280, 332, 299, commonData.fgcolor);
+        for (int i = 0; i < 6; i++) {
+            uint16_t x, y;
+            if (commonData.keydata[i].label.length() > 0) {
+                // check if icon is enabled
+                String icon_name = commonData.keydata[i].label.substring(1);
+                if (commonData.keydata[i].label[0] == '#') {
+                    if (iconmap.find(icon_name) != iconmap.end()) {
+                        x = commonData.keydata[i].x + (commonData.keydata[i].w - icon_width) / 2;
+                        y = commonData.keydata[i].y + (commonData.keydata[i].h - icon_height) / 2;
+                        getdisplay().drawXBitmap(x, y, iconmap[icon_name], icon_width, icon_height, commonData.fgcolor);
+                    } else {
+                        // icon is missing, use name instead
+                        x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
+                        y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
+                        drawTextCenter(x, y, icon_name);
+                    }
                 } else {
-                    // icon is missing, use name instead
                     x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
                     y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
-                    drawTextCenter(x, y, icon_name);
+                    drawTextCenter(x, y, commonData.keydata[i].label);
                 }
-            } else {
-                //drawTextCenter(cx[i], cy, commonData.keydata[i].label);
-                x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
-                y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
-                drawTextCenter(x, y, commonData.keydata[i].label);
             }
         }
+    } else {
+        getdisplay().setCursor(65, 295);
+        getdisplay().print("Press 1 and 6 fast to unlock keys");
     }
-
 }
 
 // Sunset und sunrise calculation
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index e94c535..6665dc3 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -114,27 +114,27 @@ static unsigned char right_bits[] PROGMEM = {
    0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x80, 0x1f,
    0x80, 0x0f, 0x80, 0x07, 0x80, 0x03, 0x00, 0x00 };
 
-static unsigned char swipe_bits[] PROGMEM = {
-   0x80, 0x03, 0xe0, 0x06, 0xb0, 0x0a, 0xa8, 0x0a, 0xa8, 0x0a, 0xa8, 0x3a,
-   0x28, 0x28, 0x08, 0x28, 0x08, 0x28, 0x08, 0x26, 0x08, 0x21, 0x08, 0x10,
-   0x10, 0x08, 0x10, 0x04, 0x10, 0x04, 0x00, 0x00 };
+static unsigned char swipe_bits[] = {
+   0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0xc8, 0x05, 0x48, 0x0e,
+   0x4a, 0x12, 0x4d, 0x32, 0x09, 0x50, 0x41, 0x44, 0x62, 0x4c, 0xf2, 0x5f,
+   0x64, 0x2c, 0x48, 0x24, 0x10, 0x10, 0xe0, 0x0f };
 
 static unsigned char lock_bits[] PROGMEM = {
    0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
    0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
    0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
 
-static unsigned char plus_bits[] = {
+static unsigned char plus_bits[] PROGMEM = {
    0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0xc4, 0x08, 0xc2, 0x10,
    0xf2, 0x13, 0xf2, 0x13, 0xc2, 0x10, 0xc4, 0x08, 0x04, 0x0c, 0x18, 0x1e,
    0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
 
-static unsigned char minus_bits[] = {
+static unsigned char minus_bits[] PROGMEM = {
    0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x04, 0x08, 0x02, 0x10,
    0xf2, 0x13, 0xf2, 0x13, 0x02, 0x10, 0x04, 0x08, 0x04, 0x0c, 0x18, 0x1e,
    0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
 
-static unsigned char fram_bits[] = {
+static unsigned char fram_bits[] PROGMEM = {
    0xf8, 0x1f, 0xff, 0xff, 0x9f, 0xff, 0x98, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
    0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
    0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };

From 49be7f117a24fb408528be3c15387c57231827fe Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Fri, 17 Jan 2025 18:00:32 +0100
Subject: [PATCH 30/35] Modify pad detectionfor OBP60 Light

---
 lib/obp60task/OBP60Keypad.h        | 45 +++++++++++++++++-------------
 lib/obp60task/platformio.ini       | 18 ++++++------
 lib/obp60task/platformio.ini.light |  2 +-
 3 files changed, 36 insertions(+), 29 deletions(-)

diff --git a/lib/obp60task/OBP60Keypad.h b/lib/obp60task/OBP60Keypad.h
index 7ad6f9b..54935be 100644
--- a/lib/obp60task/OBP60Keypad.h
+++ b/lib/obp60task/OBP60Keypad.h
@@ -181,6 +181,29 @@ long starttime = 0;     // Start time point for pressed key
   #endif
 
   #ifdef HARDWARE_LIGHT
+  int readSensorpads(){
+      // Read key code 
+      if(digitalRead(UP) == LOW){
+        keycode = 10; // Left swipe
+      }
+      else if(digitalRead(DOWN) == LOW){
+        keycode = 9;  // Right swipe
+      }
+      else if(digitalRead(CONF) == LOW){
+        keycode = 3;  // Key 3
+      }
+      else if(digitalRead(MENUE) == LOW){
+        keycode = 1;  // Key 1
+      }
+      else if(digitalRead(EXIT) == LOW){
+        keycode = 2;  // Key 2
+      }
+      else{
+        keycode = 0;  // No key activ
+      }
+      return keycode;
+    }
+
   // Keypad functions for OBP60 clone (thSensitivity is inactiv)
   int readKeypad(uint thSensitivity) {
     pinMode(UP, INPUT);
@@ -189,25 +212,8 @@ long starttime = 0;     // Start time point for pressed key
     pinMode(MENUE, INPUT);
     pinMode(EXIT, INPUT);
 
-    // Read key code 
-    if(digitalRead(UP) == LOW){
-      keycode = 10; // Left swipe
-    }
-    else if(digitalRead(DOWN) == LOW){
-      keycode = 9;  // Right swipe
-    }
-    else if(digitalRead(CONF) == LOW){
-      keycode = 3;  // Key 3
-    }
-    else if(digitalRead(MENUE) == LOW){
-      keycode = 1;  // Key 1
-    }
-    else if(digitalRead(EXIT) == LOW){
-      keycode = 2;  // Key 2
-    }
-    else{
-      keycode = 0;  // No key activ
-    }
+    // Raed pad values
+    readSensorpads();
 
     // Detect key
     if (keycode > 0 ){
@@ -220,6 +226,7 @@ long starttime = 0;     // Start time point for pressed key
         keystatus = keycode;
         // Copy keycode
         keycodeold = keycode;
+        while(readSensorpads() > 0){} // Wait for pad lesease
         delay(keydelay);
       }
     }
diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index 4010a82..6d6ae65 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -9,10 +9,10 @@ board_build.variants_dir = variants
 #board = obp60_s3_n8     #ESP32-S3 N8, 8MB flash, no PSRAM
 #board = obp60_s3_n16    #ESP32-S3 N16,16MB flash, no PSRAM, zero series
 #board = obp60_s3_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
-board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
-#board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
-#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
-board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
+#board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
+board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
+board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
+#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
 framework = arduino
 lib_deps = 
     ${basedeps.lib_deps}
@@ -40,22 +40,22 @@ lib_deps =
 build_flags=
     #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
 #    -D ARDUINO_USB_MODE=1           #0=OTG (to implement other external devices), 1=CDC (is a serial device) 
-#    -D ARDUINO_USB_CDC_ON_BOOT=1    #0=JTAG, 1=CDC (serial device)
+    -D ARDUINO_USB_CDC_ON_BOOT=0    #Serial output via RX/TX
 #    -D CORE_DEBUG_LEVEL=1           #Debug level for CPU core via CDC (seral device)
 #    -D TIME=$UNIX_TIME              #Set PC time for RTC (only settable via VSC)
     -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib
     -D BOARD_OBP60S3                #Board OBP60 V2.1 with ESP32S3
 #    -D HARDWARE_V20                 #OBP60 hardware revision V2.0
-    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
-#    -D HARDWARE_LIGHT               #OBP60 hardware clone
+#    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
+    -D HARDWARE_LIGHT               #OBP60 hardware clone
 #    -D DISPLAY_GDEW042T2            #old E-Ink display from Waveshare, R10 0.47 ohm
     -D DISPLAY_GDEY042T81           #new E-Ink display from Waveshare, R10 2.2 ohm
 #    -D DISPLAY_GYE042A87            #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
 #    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
     ${env.build_flags}
 #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
-upload_port = /dev/ttyACM0          #OBP60 original
-#upload_port = /dev/ttyUSB0          #OBP60 clone
+#upload_port = /dev/ttyACM0          #OBP60 original
+upload_port = /dev/ttyUSB0          #OBP60 clone
 upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
 upload_speed = 230400
 monitor_speed = 115200
diff --git a/lib/obp60task/platformio.ini.light b/lib/obp60task/platformio.ini.light
index d11edcf..6d6ae65 100644
--- a/lib/obp60task/platformio.ini.light
+++ b/lib/obp60task/platformio.ini.light
@@ -40,7 +40,7 @@ lib_deps =
 build_flags=
     #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
 #    -D ARDUINO_USB_MODE=1           #0=OTG (to implement other external devices), 1=CDC (is a serial device) 
-#    -D ARDUINO_USB_CDC_ON_BOOT=1    #0=JTAG, 1=CDC (serial device)
+    -D ARDUINO_USB_CDC_ON_BOOT=0    #Serial output via RX/TX
 #    -D CORE_DEBUG_LEVEL=1           #Debug level for CPU core via CDC (seral device)
 #    -D TIME=$UNIX_TIME              #Set PC time for RTC (only settable via VSC)
     -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib

From 24386d4d4274fd3742d30a81be7e672233c8fa39 Mon Sep 17 00:00:00 2001
From: Tobias E <Tobias.edler@gmail.com>
Date: Fri, 17 Jan 2025 19:23:26 +0000
Subject: [PATCH 31/35] add explanation to gen_set.py

---
 lib/obp60task/gen_set.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/obp60task/gen_set.py b/lib/obp60task/gen_set.py
index a0f7b6d..c848a91 100755
--- a/lib/obp60task/gen_set.py
+++ b/lib/obp60task/gen_set.py
@@ -1,5 +1,9 @@
 #!/usr/bin/env python3
 # A tool to generate that part of config.json  that deals with pages and fields.
+#
+#Usage: 1. modify this script (e.g.add a page, change number of fields, etc.)
+#       2. Delete all lines from config.json from the curly backet before "name": "page1type"  to o the end of the file (as of today, delete from line 917 to the end of the File)
+#       3. run ./gen_set.py >> config.json
 
 import json
 
@@ -120,5 +124,5 @@ for page_no in range(1, no_of_pages + 1):
 
 json_output = json.dumps(output, indent=4)
 # print omitting first and last line containing [ ] of JSON array
-print(json_output[1:-1])
+print(json_output[1:])
 # print(",")
\ No newline at end of file

From 10552763fbc3b485ff1581aa73492968eed1097d Mon Sep 17 00:00:00 2001
From: Tobias E <Tobias.edler@gmail.com>
Date: Fri, 17 Jan 2025 19:24:16 +0000
Subject: [PATCH 32/35] add explanation to gen_set.py

---
 lib/obp60task/gen_set.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/obp60task/gen_set.py b/lib/obp60task/gen_set.py
index c848a91..bf40b6c 100755
--- a/lib/obp60task/gen_set.py
+++ b/lib/obp60task/gen_set.py
@@ -124,5 +124,7 @@ for page_no in range(1, no_of_pages + 1):
 
 json_output = json.dumps(output, indent=4)
 # print omitting first and last line containing [ ] of JSON array
+#print(json_output[1:-1])
+# print omitting first line containing [  of JSON array
 print(json_output[1:])
 # print(",")
\ No newline at end of file

From e917a7fc765b821bf83f6011928412a380b5c9bc Mon Sep 17 00:00:00 2001
From: Thomas Hooge <thomas@hoogi.de>
Date: Fri, 17 Jan 2025 21:23:41 +0100
Subject: [PATCH 33/35] Modification of footer layout and new swipe icon

---
 lib/obp60task/OBP60Extensions.cpp | 32 +++++++++++--------
 lib/obp60task/OBP60Extensions.h   | 30 ++++++++++++-----
 lib/obp60task/OBP60Keypad.h       | 53 +++++++++++++++++--------------
 3 files changed, 70 insertions(+), 45 deletions(-)

diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp
index 146f3c9..153ecbb 100644
--- a/lib/obp60task/OBP60Extensions.cpp
+++ b/lib/obp60task/OBP60Extensions.cpp
@@ -328,16 +328,11 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
 
         // Display key lock status
         if (commonData.keylock) {
-            getdisplay().drawXBitmap(150, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
+            getdisplay().drawXBitmap(170, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
         } else {
-            getdisplay().drawXBitmap(150, 1, swipe_bits, icon_width, icon_height, commonData.fgcolor);
+            getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
         }
 
-        // Current page number in a small box
-        getdisplay().setFont(&Ubuntu_Bold8pt7b);
-        getdisplay().drawRect(170, 2, 20, 15, commonData.fgcolor);
-        drawTextCenter(179, 9, String(commonData.data.actpage));
-
         // Heartbeat as dot
         getdisplay().setTextColor(commonData.fgcolor);
         getdisplay().setFont(&Ubuntu_Bold32pt7b);
@@ -382,13 +377,21 @@ void displayFooter(CommonData &commonData) {
     getdisplay().setTextColor(commonData.fgcolor);
 
     // Frame around key icon area
-    getdisplay().drawLine(0, 280, 399, 280, commonData.fgcolor);
     if (! commonData.keylock) {
-        getdisplay().drawLine(68, 280, 68, 299, commonData.fgcolor);
-        getdisplay().drawLine(134, 280, 134, 299, commonData.fgcolor);
-        getdisplay().drawLine(200, 280, 200, 299, commonData.fgcolor);
-        getdisplay().drawLine(266, 280, 266, 299, commonData.fgcolor);
-        getdisplay().drawLine(332, 280, 332, 299, commonData.fgcolor);
+        // horizontal elements
+        const uint16_t top = 280;
+        const uint16_t bottom = 299;
+        getdisplay().drawLine(commonData.keydata[0].x, top, commonData.keydata[0].x+10, top, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[1].x-10, top, commonData.keydata[1].x+10, top, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[2].x-10, top, commonData.keydata[2].x+10, top, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[4].x-10, top, commonData.keydata[4].x+10, top, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[5].x-10, top, commonData.keydata[5].x+10, top, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[5].x + commonData.keydata[5].w - 10, top, commonData.keydata[5].x + commonData.keydata[5].w + 1, top, commonData.fgcolor);
+        // vertical key separators
+        getdisplay().drawLine(commonData.keydata[0].x + commonData.keydata[0].w, top, commonData.keydata[0].x + commonData.keydata[0].w, bottom, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[1].x + commonData.keydata[1].w, top, commonData.keydata[1].x + commonData.keydata[1].w, bottom, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[3].x + commonData.keydata[3].w, top, commonData.keydata[3].x + commonData.keydata[3].w, bottom, commonData.fgcolor);
+        getdisplay().drawLine(commonData.keydata[4].x + commonData.keydata[4].w, top, commonData.keydata[4].x + commonData.keydata[4].w, bottom, commonData.fgcolor);
         for (int i = 0; i < 6; i++) {
             uint16_t x, y;
             if (commonData.keydata[i].label.length() > 0) {
@@ -412,6 +415,9 @@ void displayFooter(CommonData &commonData) {
                 }
             }
         }
+        // Current page number in a small box
+        getdisplay().drawRect(190, 280, 23, 19, commonData.fgcolor);
+        drawTextCenter(200, 289, String(commonData.data.actpage));
     } else {
         getdisplay().setCursor(65, 295);
         getdisplay().print("Press 1 and 6 fast to unlock keys");
diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h
index 6665dc3..a529da7 100644
--- a/lib/obp60task/OBP60Extensions.h
+++ b/lib/obp60task/OBP60Extensions.h
@@ -114,11 +114,6 @@ static unsigned char right_bits[] PROGMEM = {
    0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x80, 0x1f,
    0x80, 0x0f, 0x80, 0x07, 0x80, 0x03, 0x00, 0x00 };
 
-static unsigned char swipe_bits[] = {
-   0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0xc8, 0x05, 0x48, 0x0e,
-   0x4a, 0x12, 0x4d, 0x32, 0x09, 0x50, 0x41, 0x44, 0x62, 0x4c, 0xf2, 0x5f,
-   0x64, 0x2c, 0x48, 0x24, 0x10, 0x10, 0xe0, 0x0f };
-
 static unsigned char lock_bits[] PROGMEM = {
    0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
    0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
@@ -139,19 +134,38 @@ static unsigned char fram_bits[] PROGMEM = {
    0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
    0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
 
+static unsigned char ap_bits[] = {
+   0xe0, 0x03, 0x18, 0x0c, 0x04, 0x10, 0xc2, 0x21, 0x30, 0x06, 0x08, 0x08,
+   0xc0, 0x01, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xc0, 0x01,
+   0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
+
+static unsigned char dish_bits[] PROGMEM= {
+   0x3c, 0x00, 0x42, 0x18, 0xfa, 0x1b, 0x02, 0x04, 0x02, 0x0a, 0x02, 0x09,
+   0x82, 0x08, 0x06, 0x0a, 0x0e, 0x1b, 0x9c, 0x2b, 0x38, 0x2b, 0x74, 0x20,
+   0xec, 0x1f, 0x1c, 0x00, 0xf4, 0x00, 0xfe, 0x03 };
+
 static std::map<String, unsigned char *> iconmap = {
     {"LEFT", left_bits},
     {"RIGHT", right_bits},
-    {"SWIPE", swipe_bits},
     {"LOCK", lock_bits},
     {"PLUS", plus_bits},
-    {"MINUS", minus_bits}
+    {"MINUS", minus_bits},
+    {"DISH", dish_bits},
+    {"AP", ap_bits}
 };
 
 // Other symbols
+#define swipe_width 24
+#define swipe_height 16
+static unsigned char swipe_bits[] PROGMEM = {
+   0x00, 0x06, 0x00, 0x24, 0x09, 0x24, 0x12, 0x09, 0x48, 0x7f, 0x09, 0xfe,
+   0x12, 0xb9, 0x48, 0x24, 0xc9, 0x25, 0x40, 0x49, 0x02, 0xa0, 0x49, 0x06,
+   0x20, 0x01, 0x0a, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08,
+   0x80, 0x00, 0x04, 0x00, 0x01, 0x04, 0x00, 0x02, 0x02, 0x00, 0xfc, 0x01 };
+
 #define exclamation_width 32
 #define exclamation_height 32
-static unsigned char exclamation_bits[] = {
+static unsigned char exclamation_bits[] PROGMEM = {
    0x00, 0xc0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xb0, 0x0d, 0x00,
    0x00, 0xd8, 0x1b, 0x00, 0x00, 0xec, 0x37, 0x00, 0x00, 0xf6, 0x6f, 0x00,
    0x00, 0x3b, 0xdc, 0x00, 0x80, 0x3d, 0xbc, 0x01, 0xc0, 0x3e, 0x7c, 0x03,
diff --git a/lib/obp60task/OBP60Keypad.h b/lib/obp60task/OBP60Keypad.h
index c06c163..5c2f928 100644
--- a/lib/obp60task/OBP60Keypad.h
+++ b/lib/obp60task/OBP60Keypad.h
@@ -22,35 +22,40 @@ long starttime = 0;     // Start time point for pressed key
 
 void initKeys(CommonData &commonData) {
     // coordinates for virtual keyboard keys
-    commonData.keydata[0].x = 1;
-    commonData.keydata[0].y = 281;
-    commonData.keydata[0].w = 67;
-    commonData.keydata[0].h = 18;
 
-    commonData.keydata[1].x = 69;
-    commonData.keydata[1].y = 281;
-    commonData.keydata[1].w = 66;
-    commonData.keydata[1].h = 18;
+    static uint16_t top = 281;
+    static uint16_t width = 65;
+    static uint16_t height = 18;
 
-    commonData.keydata[2].x = 135;
-    commonData.keydata[2].y = 281;
-    commonData.keydata[2].w = 66;
-    commonData.keydata[2].h = 18;
+    commonData.keydata[0].x = 0;
+    commonData.keydata[0].y = top;
+    commonData.keydata[0].w = width + 1;
+    commonData.keydata[0].h = height;
 
-    commonData.keydata[3].x = 201;
-    commonData.keydata[3].y = 281;
-    commonData.keydata[3].w = 66;
-    commonData.keydata[3].h = 18;
+    commonData.keydata[1].x = commonData.keydata[0].x + commonData.keydata[0].w + 1;
+    commonData.keydata[1].y = top;
+    commonData.keydata[1].w = width;
+    commonData.keydata[1].h = height;
 
-    commonData.keydata[4].x = 267;
-    commonData.keydata[4].y = 281;
-    commonData.keydata[4].w = 66;
-    commonData.keydata[4].h = 18;
+    commonData.keydata[2].x = commonData.keydata[1].x + commonData.keydata[1].w + 1;
+    commonData.keydata[2].y = top;
+    commonData.keydata[2].w = width;
+    commonData.keydata[2].h = height;
 
-    commonData.keydata[5].x = 333;
-    commonData.keydata[5].y = 281;
-    commonData.keydata[5].w = 66;
-    commonData.keydata[5].h = 18;
+    commonData.keydata[3].x = commonData.keydata[2].x + commonData.keydata[2].w + 1;
+    commonData.keydata[3].y = top;
+    commonData.keydata[3].w = width;
+    commonData.keydata[3].h = height;
+
+    commonData.keydata[4].x = commonData.keydata[3].x + commonData.keydata[3].w + 1;
+    commonData.keydata[4].y = top;
+    commonData.keydata[4].w = width;
+    commonData.keydata[4].h = height;
+
+    commonData.keydata[5].x = commonData.keydata[4].x + commonData.keydata[4].w + 1;
+    commonData.keydata[5].y = top;
+    commonData.keydata[5].w = width;
+    commonData.keydata[5].h = height;
 }
 
   #ifdef HARDWARE_V21

From 27b02c4860a84cbec4e3453c8ace1d1b5d7815ac Mon Sep 17 00:00:00 2001
From: Tobias E <Tobias.edler@gmail.com>
Date: Sat, 18 Jan 2025 13:59:37 +0000
Subject: [PATCH 34/35] removed obsolete perl script gen_set.pl

---
 lib/obp60task/Create_new_pages.txt |   2 +-
 lib/obp60task/gen_set.pl           | 112 -----------------------------
 2 files changed, 1 insertion(+), 113 deletions(-)
 delete mode 100755 lib/obp60task/gen_set.pl

diff --git a/lib/obp60task/Create_new_pages.txt b/lib/obp60task/Create_new_pages.txt
index 5ad71fd..b318985 100644
--- a/lib/obp60task/Create_new_pages.txt
+++ b/lib/obp60task/Create_new_pages.txt
@@ -2,5 +2,5 @@ Craete new page for OBP60
 1. Create page under /lib/obp60task/PageXXXX.cpp
 2. Set page name in PageXXXX.cpp on file name
 3. Register new page in  /lib/obp60task/obp60task.cpp line 242 (registerAllPages)
-4. Add new page in /lib/obp60task/config.json for each page type or add new page to gen_set.pl and run it to auto-generate the relevant section of  config.json
+4. Add new page in /lib/obp60task/config.json for each page type or add new page to gen_set.py and run it to auto-generate the relevant section of  config.json
 
diff --git a/lib/obp60task/gen_set.pl b/lib/obp60task/gen_set.pl
deleted file mode 100755
index 3c74904..0000000
--- a/lib/obp60task/gen_set.pl
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/perl -w
-#A tool to generate the part of config.json that deals with pages and fields.
-#DEPRECATED, moved to get_set.py
-die "Please use gen_set.py instead";
-#List of all pages and the number of parameters they expect.
-%NoOfFieldsPerPage=qw( 
-                ApparentWind    0
-                XTETrack    0
-                Battery2    0
-                Battery     0
-                BME280      0
-                Clock       0
-                DST810      0
-                FourValues2  4
-                FourValues 4
-                Generator   0
-                KeelPosition 0
-                OneValue    1
-                RollPitch   0
-                RudderPosition  0
-                Solar       0
-                ThreeValues 3
-                TwoValues   2
-                Voltage     0
-                White       0
-                WindRose    0
-                WindRoseFlex    6
-                );
-# No changes needed beyond this point
-#max number of pages supported by OBP60
-$NoOfPages=10;
-#Default selection for each page
-@Defaults=qw(Voltage WindRose OneValue TwoValues ThreeValues FourValues FourValues2 Clock RollPitch Battery2);
-@Numbers=qw(one two three four five six seven eight nine ten);
-@Pages=sort(keys(%NoOfFieldsPerPage));
-$MaxNoOfFieldsPerPage=0; # inital value, gets updated with maximum entry from %NoOfFieldsPerPage
-
-
-#find max. number of fields without additional modules
- foreach (values(%NoOfFieldsPerPage)){
-    if ($_ > $MaxNoOfFieldsPerPage){
-        $MaxNoOfFieldsPerPage=$_;
-    }
- }
-
-for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
-    print "{\n"; 
-    print "\t","\"name\": \"page", $PageNo,"type\",\n";
-    print "\t","\"label\": \"Type\",\n";
-    print "\t",'"type": "list",',"\n";
-    print "\t",'"default": "';
-    print "$Defaults[$PageNo-1]";
-    print'"',"\n";
-    print "\t",'"description": "Type of page for page ',$PageNo,'",',"\n";
-    print "\t",'"list": [';
-    for ($p=0;$p<=$#Pages;$p++) {
-        print '"', $Pages[$p], '"' ;
-        if ($p < $#Pages){print ","} 
-        } 
-    print "]\n";
-    print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
-    print "\t",'"capabilities": {',"\n";
-    print "\t\t",'"obp60":"true"',"\n";
-    print "\t",'}',"\n";
-    print "\t",'"condition":[';
-    for ($vp=$PageNo;$vp<=$NoOfPages;$vp++){ 
-        print '"{visiblePages":"',$vp,'"},';
-    } 
-    print "\b",']',"\n";
-    print '},',"\n";
-    for ($FieldNo=1; $FieldNo<=$MaxNoOfFieldsPerPage;$FieldNo++){  
-        print "{\n";
-        print "\t",'"name": "page',$PageNo,'value',$FieldNo,'",',"\n";
-        print "\t",'"label": "Field ',$FieldNo,'",',"\n";
-        print "\t",'"type": "boatData",',"\n";
-        print "\t",'"default": "",',"\n";
-        print "\t",'"description": "The display for field ',$Numbers[$FieldNo-1],'",',"\n";
-        print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
-        print "\t",'"capabilities": {',"\n";
-        print "\t",'    "obp60":"true"',"\n";
-        print "\t",'}, ',"\n";
-        print "\t",'"condition":[';
-        foreach $page (@Pages) {
-            if($NoOfFieldsPerPage{$page}>=$FieldNo){ 
-                print '{"page',$PageNo,'type":"',$page,'"},';
-            } 
-        } 
-        print "\b],\n";
-    print '},',"\n";
-    } 
-    print "{\n";
-    print "\t","\"name\": \"page", $PageNo,"fluid\",\n";
-    print "\t",'"label": "Fluid type",',"\n";
-    print "\t",'"type": "list",',"\n";
-    print "\t",'"default": "0",',"\n";
-    print "\t",'"list": [',"\n";
-    print "\t",'{"l":"Fuel (0)","v":"0"},',"\n";
-    print "\t",'{"l":"Water (1)","v":"1"},',"\n";
-    print "\t",'{"l":"Gray Water (2)","v":"2"},',"\n";
-    print "\t",'{"l":"Live Well (3)","v":"3"},',"\n";
-    print "\t",'{"l":"Oil (4)","v":"4"},',"\n";
-    print "\t",'{"l":"Black Water (5)","v":"5"},',"\n";
-    print "\t",'{"l":"Fuel Gasoline (6)","v":"6"}',"\n";
-    print "\t",'],',"\n";
-    print "\t",'"description": "Fluid type in tank",',"\n";
-    print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
-    print "\t",'"capabilities": {',"\n";
-    print "\t",'"obp60":"true"',"\n";
-    print "\t",'},',"\n";
-    print "\t",'"condition":[{"page',$PageNo,'type":"Fluid"}]',"\n";
-    print '},',"\n";
-} 

From 87a7a79358ea3b894d3ce8be59cd11821ec1d7ed Mon Sep 17 00:00:00 2001
From: norbert-walter <norbert-walter@web.de>
Date: Sun, 19 Jan 2025 00:23:22 +0100
Subject: [PATCH 35/35] Change back to plaformio.ini OBP60

---
 lib/obp60task/platformio.ini | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini
index 6d6ae65..4010a82 100644
--- a/lib/obp60task/platformio.ini
+++ b/lib/obp60task/platformio.ini
@@ -9,10 +9,10 @@ board_build.variants_dir = variants
 #board = obp60_s3_n8     #ESP32-S3 N8, 8MB flash, no PSRAM
 #board = obp60_s3_n16    #ESP32-S3 N16,16MB flash, no PSRAM, zero series
 #board = obp60_s3_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM
-#board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
-board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
-board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
-#board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
+board = obp60_s3_n16r8  #ESP32-S3 N16R8, 16MB flash, 8MB PSRAM, production series
+#board = obp60_s3_light_n8r8   #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone
+#board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
+board_build.partitions = default_16MB.csv #ESP32-S3 N16, 16MB flash
 framework = arduino
 lib_deps = 
     ${basedeps.lib_deps}
@@ -40,22 +40,22 @@ lib_deps =
 build_flags=
     #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
 #    -D ARDUINO_USB_MODE=1           #0=OTG (to implement other external devices), 1=CDC (is a serial device) 
-    -D ARDUINO_USB_CDC_ON_BOOT=0    #Serial output via RX/TX
+#    -D ARDUINO_USB_CDC_ON_BOOT=1    #0=JTAG, 1=CDC (serial device)
 #    -D CORE_DEBUG_LEVEL=1           #Debug level for CPU core via CDC (seral device)
 #    -D TIME=$UNIX_TIME              #Set PC time for RTC (only settable via VSC)
     -D DISABLE_DIAGNOSTIC_OUTPUT    #Disable diagnostic output for GxEPD2 lib
     -D BOARD_OBP60S3                #Board OBP60 V2.1 with ESP32S3
 #    -D HARDWARE_V20                 #OBP60 hardware revision V2.0
-#    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
-    -D HARDWARE_LIGHT               #OBP60 hardware clone
+    -D HARDWARE_V21                 #OBP60 hardware revision V2.1
+#    -D HARDWARE_LIGHT               #OBP60 hardware clone
 #    -D DISPLAY_GDEW042T2            #old E-Ink display from Waveshare, R10 0.47 ohm
     -D DISPLAY_GDEY042T81           #new E-Ink display from Waveshare, R10 2.2 ohm
 #    -D DISPLAY_GYE042A87            #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
 #    -D DISPLAY_SE0420NQ04           #alternativ E-Ink display from SID Technology, R10 2.2 ohm
     ${env.build_flags}
 #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
-#upload_port = /dev/ttyACM0          #OBP60 original
-upload_port = /dev/ttyUSB0          #OBP60 clone
+upload_port = /dev/ttyACM0          #OBP60 original
+#upload_port = /dev/ttyUSB0          #OBP60 clone
 upload_protocol = esptool           #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 
 upload_speed = 230400
 monitor_speed = 115200