From 3cf22bb65a99373378887950fae6ef4dc5db7250 Mon Sep 17 00:00:00 2001 From: Rainer Stransky Date: Sat, 18 Jul 2020 12:31:16 +0200 Subject: [PATCH 1/2] V2.1 18.07.20 added support for ESP8266 based Wifi Kit 8 (by Pulsar07/ (https://heltec.org/project/wifi-kit-8/) R.Stransky is a ESP8266 with * a build in OLED 128x32 * battery connector with charging management * reset and GPIO0 button support for a tare button (PIN_TARE_BUTTON) bug fixed: wifi password now with up to 64 chars bug fixed: wifi data (ssid/passwd) with special character (e.g. +) is now supported for specified battery type, voltage is displayed using uncompressed html files makes WEB GUI much faster --- CG_scale.ino | 377 ++++++++++----- README.md | 2 +- data/index.html | 880 ++++++++++++++++++++++++++++++++++ data/index.html.gz | Bin 20389 -> 0 bytes data/models.html | 531 +++++++++++++++++++++ data/models.html.gz | Bin 19906 -> 0 bytes data/settings.html | 1062 +++++++++++++++++++++++++++++++++++++++++ data/settings.html.gz | Bin 16034 -> 0 bytes settings_ESP8266.h | 42 +- 9 files changed, 2759 insertions(+), 135 deletions(-) create mode 100755 data/index.html delete mode 100755 data/index.html.gz create mode 100755 data/models.html delete mode 100755 data/models.html.gz create mode 100755 data/settings.html delete mode 100755 data/settings.html.gz diff --git a/CG_scale.ino b/CG_scale.ino index f12a3dc..574a802 100644 --- a/CG_scale.ino +++ b/CG_scale.ino @@ -4,11 +4,23 @@ (c) 2019 by M. Lehmann ------------------------------------------------------------------ */ -#define CGSCALE_VERSION "2.0" +#define CGSCALE_VERSION "2.1" /* ****************************************************************** history: + V2.1 18.07.20 added support for ESP8266 based Wifi Kit 8 + (by Pulsar07/ (https://heltec.org/project/wifi-kit-8/) + R.Stransky is a ESP8266 with + * a build in OLED 128x32 + * battery connector with charging management + * reset and GPIO0 button + support for a tare button (PIN_TARE_BUTTON) + bug fixed: wifi password now with up to 64 chars + bug fixed: wifi data (ssid/passwd) with special + character (e.g. +) is now supported + for specified battery type, voltage is displayed + using uncompressed html files makes WEB GUI much faster V2.0 26.01.20 Webpage rewritten, no bootstrap framework needed add translation to webpage (en, de) optimized for measuring with landinggears @@ -155,6 +167,206 @@ void(* resetCPU) (void) = 0; void resetCPU() {} #endif +void initOLED() { + oledDisplay.begin(); + + const uint8_t *font; + font = u8g2_font_6x12_tr; + int displayHeight = oledDisplay.getDisplayHeight(); + int displayWidth = oledDisplay.getDisplayWidth(); + if (displayHeight <= 32) { + font = u8g2_font_6x12_tr; + } + int ylineHeight = displayHeight/3; + + oledDisplay.firstPage(); + do { + if (displayHeight <= 32) { + oledDisplay.drawXBMP(5, 0, 18, 18, CGImage); + } else { + oledDisplay.drawXBMP(20, 12, 18, 18, CGImage); + } + oledDisplay.setFont(u8g2_font_helvR12_tr); + if (displayHeight <= 32) { + oledDisplay.setCursor(30, 12); + } else { + oledDisplay.setCursor(45, 28); + } + oledDisplay.print(F("CG scale")); + + oledDisplay.setFont(u8g2_font_5x7_tr); + if (displayHeight <= 32) { + oledDisplay.setCursor(30, 22); + } else { + oledDisplay.setCursor(35, 55); + } + oledDisplay.print(F("Version: ")); + oledDisplay.print(CGSCALE_VERSION); + if (displayHeight <= 32) { + oledDisplay.setCursor(5, 31); + } else { + oledDisplay.setCursor(20, 64); + } + oledDisplay.print(F("(c) 2019 M.Lehmann et al.")); + + } while ( oledDisplay.nextPage() ); +} + +void printOLED(String aLine1, String aLine2, String aLine3=String("")); + +void printOLED(String aLine1, String aLine2, String aLine3) { + const uint8_t *font; + font = u8g2_font_6x12_tr; + int displayHeight = oledDisplay.getDisplayHeight(); + int displayWidth = oledDisplay.getDisplayWidth(); + font = u8g2_font_helvR10_tr; + if (displayHeight <= 32) { + font = u8g2_font_6x12_tr; + } + int ylineHeight = displayHeight/3; + + oledDisplay.firstPage(); + do { + oledDisplay.setFont(u8g2_font_6x12_tr); + oledDisplay.setCursor(0, ylineHeight*1); + oledDisplay.print(aLine1); + oledDisplay.setCursor(0, ylineHeight*2); + oledDisplay.print(aLine2); + if (aLine3 == "") { + oledDisplay.drawLine(0, ylineHeight*2 + 2, displayWidth, ylineHeight*2+2); + oledDisplay.setFont(u8g2_font_4x6_tr); + oledDisplay.setCursor(0, displayHeight); + String signature = "CG scale: V" + String(CGSCALE_VERSION); + oledDisplay.setCursor(displayWidth - oledDisplay.getStrWidth(signature.c_str()), displayHeight); + oledDisplay.print(signature); + } else { + oledDisplay.setCursor(0, displayHeight); + oledDisplay.print(aLine3); + } + } while ( oledDisplay.nextPage() ); +} + +void printScaleOLED() { + // print to display + char buff[8]; + int pos_weightTotal = 7; + int pos_CG_length = 28; + if (nLoadcells == 2) { + pos_weightTotal = 17; + pos_CG_length = 45; + if (batType == 0) { + pos_weightTotal = 12; + pos_CG_length = 40; + } + } + + const uint8_t *font; + int linestart = 14; + int linedist = 25; + int col0=0; + int col1=28; + font = u8g2_font_helvR12_tr; + if (oledDisplay.getDisplayHeight() <=32) { + font = u8g2_font_6x12_tr; + linestart = 8; + linedist = 12; + col0=0; + col1=28; + } + oledDisplay.firstPage(); + do { + if (errMsgCnt == 0) { + // print battery + if (batType > B_OFF) { + oledDisplay.drawXBMP(48, 1, 12, 6, batteryImage); + float percentVolt = percentBat(batVolt / batCells); + dtostrf(percentVolt, 3, 0, buff); + oledDisplay.drawBox(49, 2, (percentVolt / (100 / 8)), 4); + + oledDisplay.setFont(u8g2_font_5x7_tr); + oledDisplay.setCursor(78 - oledDisplay.getStrWidth(buff), 7); + if (batType > B_VOLT) { + dtostrf(percentVolt, 3, 0, buff); + oledDisplay.print(buff); + oledDisplay.print(F("%/")); + } + dtostrf(batVolt, 2, 2, buff); + oledDisplay.print(buff); + oledDisplay.print(F("V")); + } + + // print total weight + oledDisplay.setFont(font); + if (oledDisplay.getDisplayHeight() <= 32) { + oledDisplay.setCursor(1, 18); + oledDisplay.print(F("M = ")); + } else { + oledDisplay.drawXBMP(2, pos_weightTotal, 18, 18, weightImage); + oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), pos_weightTotal + 17); + } + dtostrf(weightTotal, 5, 1, buff); + oledDisplay.print(buff); + oledDisplay.print(F("g")); + + // print CG longitudinal axis + if (oledDisplay.getDisplayHeight() <=32) { + oledDisplay.setCursor(1, 32); + oledDisplay.print(F("CG = ")); + } else { + oledDisplay.drawXBMP(2, pos_CG_length, 18, 18, CGImage); + oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), pos_CG_length + 16); + } + dtostrf(CG_length, 5, 1, buff); + oledDisplay.print(buff); + oledDisplay.print(F("mm")); + + // print CG transverse axis + if (nLoadcells == 3) { + if (oledDisplay.getDisplayHeight() <=32) { + oledDisplay.setCursor(78, 32); + oledDisplay.print(F("LR=")); + dtostrf(CG_trans, 3, 0, buff); + } else { + oledDisplay.drawXBMP(2, 47, 18, 18, CGtransImage); + oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), 64); + dtostrf(CG_trans, 5, 1, buff); + } + oledDisplay.print(buff); + oledDisplay.print(F("mm")); + } + } else { + oledDisplay.setFont(u8g2_font_5x7_tr); + for (int i = 1; i <= errMsgCnt; i++) { + oledDisplay.setCursor(0, 7 * i); + oledDisplay.print(errMsg[i]); + } + } + + } while ( oledDisplay.nextPage() ); +} + +#ifdef PIN_TARE_BUTTON +void handleTareBtn() { + static unsigned long lastTaraBtn = 0; + if ((millis() - lastTaraBtn) > 20) { + lastTaraBtn = millis(); + static int tareBtnCnt = 0; + if(digitalRead(PIN_TARE_BUTTON)) { + tareBtnCnt = 0; + } else { + tareBtnCnt++; + if (tareBtnCnt > 10) { + Serial.println("tare button pressed"); + printOLED("TARE ==>"," tare load cells ..."); + // avoid keybounce + tareBtnCnt = -1000; + tareLoadcells(); + delay(2000); + } + } + } +} +#endif // save calibration factor void saveCalFactor(int nLC) { @@ -278,8 +490,9 @@ int percentBat(float cellVoltage) { void setup() { // init serial - Serial.begin(9600); + Serial.begin(115200); Serial.println(); + delay(1000); #if defined(ESP8266) printConsole(T_BOOT, "startup CG scale V" + String(CGSCALE_VERSION)); @@ -367,23 +580,9 @@ void setup() { // init OLED display #if defined(ESP8266) - printConsole(T_BOOT, "init OLED display"); + printConsole(T_BOOT, "init OLED display: " + String(oledDisplay.getDisplayWidth())+ String("x") + String(oledDisplay.getDisplayHeight())); #endif - oledDisplay.begin(); - oledDisplay.firstPage(); - do { - oledDisplay.drawXBMP(20, 12, 18, 18, CGImage); - oledDisplay.setFont(u8g2_font_helvR12_tr); - oledDisplay.setCursor(45, 28); - oledDisplay.print(F("CG scale")); - - oledDisplay.setFont(u8g2_font_5x7_tr); - oledDisplay.setCursor(35, 55); - oledDisplay.print(F("Version: ")); - oledDisplay.print(CGSCALE_VERSION); - oledDisplay.setCursor(20, 64); - oledDisplay.print(F("(c) 2019 M. Lehmann")); - } while ( oledDisplay.nextPage() ); + initOLED(); // init & tare Loadcells for (int i = LC1; i <= LC3; i++) { @@ -408,6 +607,7 @@ void setup() { #if defined(ESP8266) // Start by connecting to a WiFi network + WiFi.persistent(false); WiFi.mode(WIFI_STA); WiFi.begin(ssid_STA, password_STA); @@ -417,18 +617,20 @@ void setup() { while (WiFi.status() != WL_CONNECTED) { delay(500); + Serial.print("."); if (WiFi.status() == WL_NO_SSID_AVAIL) { - printConsole(T_ERROR, "Wifi: No SSID available"); + printConsole(T_ERROR, "\nWifi: No SSID available"); break; } else if (WiFi.status() == WL_CONNECT_FAILED) { - printConsole(T_ERROR, "Wifi: Connection failed"); + printConsole(T_ERROR, "\nWifi: Connection failed"); break; } else if ((millis() - timeoutWiFi) > TIMEOUT_CONNECT) { - printConsole(T_ERROR, "Wifi: Timeout"); + printConsole(T_ERROR, "\nWifi: Timeout"); break; } } + if (WiFi.status() != WL_CONNECTED) { // if WiFi not connected, switch to access point mode wifiSTAmode = false; @@ -457,34 +659,16 @@ void setup() { } #endif + if (wifiSTAmode) { + printOLED("WiFi: " + String(ssid_STA), + "Host: " + String(hostname), + "IP : " + WiFi.localIP().toString()); + } else { + printOLED("WiFi: " + String(ssid_AP), + "Host: " + String(hostname), + "IP : " + WiFi.softAPIP().toString()); + } - // print wifi status - oledDisplay.firstPage(); - do { - oledDisplay.setFont(u8g2_font_5x7_tr); - oledDisplay.setCursor(0, 14); - oledDisplay.print(F("WiFi:")); - oledDisplay.setCursor(0, 39); - oledDisplay.print(F("Host:")); - oledDisplay.setCursor(0, 64); - oledDisplay.print(F("IP:")); - - oledDisplay.setFont(u8g2_font_helvR10_tr); - oledDisplay.setCursor(28, 14); - if (wifiSTAmode) { - oledDisplay.print(ssid_STA); - } else { - oledDisplay.print(ssid_AP); - } - oledDisplay.setCursor(28, 39); - oledDisplay.print(hostname); - oledDisplay.setCursor(28, 64); - if (wifiSTAmode) { - oledDisplay.print(WiFi.localIP()); - } else { - oledDisplay.print(WiFi.softAPIP()); - } - } while ( oledDisplay.nextPage() ); delay(3000); // When the client requests data @@ -589,6 +773,10 @@ void loop() { server.handleClient(); #endif + #ifdef PIN_TARE_BUTTON + handleTareBtn(); + #endif + updateLoadcells(); // update loadcell values @@ -606,6 +794,7 @@ void loop() { } } + // update display and serial menu if ((millis() - lastTimeMenu) > UPDATE_INTERVAL_OLED_MENU) { @@ -642,80 +831,10 @@ void loop() { // read battery voltage if (batType > B_OFF) { batVolt = (analogRead(VOLTAGE_PIN) / 1024.0) * V_REF * ((resistor[R1] + resistor[R2]) / resistor[R2]) / 1000.0; -#if ENABLE_PERCENTLIST - if (batType > B_VOLT) { - batVolt = percentBat(batVolt / batCells); - } -#endif } - // print to display - char buff[8]; - int pos_weightTotal = 7; - int pos_CG_length = 28; - if (nLoadcells == 2) { - pos_weightTotal = 17; - pos_CG_length = 45; - if (batType == 0) { - pos_weightTotal = 12; - pos_CG_length = 40; - } - } + printScaleOLED(); - oledDisplay.firstPage(); - do { - if (errMsgCnt == 0) { - // print battery - if (batType > B_OFF) { - oledDisplay.drawXBMP(88, 1, 12, 6, batteryImage); - if (batType == B_VOLT) { - dtostrf(batVolt, 2, 2, buff); - } else { - dtostrf(batVolt, 3, 0, buff); - oledDisplay.drawBox(89, 2, (batVolt / (100 / 8)), 4); - } - oledDisplay.setFont(u8g2_font_5x7_tr); - oledDisplay.setCursor(123 - oledDisplay.getStrWidth(buff), 7); - oledDisplay.print(buff); - if (batType == B_VOLT) { - oledDisplay.print(F("V")); - } else { - oledDisplay.print(F("%")); - } - } - - // print total weight - oledDisplay.drawXBMP(2, pos_weightTotal, 18, 18, weightImage); - dtostrf(weightTotal, 5, 1, buff); - oledDisplay.setFont(u8g2_font_helvR12_tr); - oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), pos_weightTotal + 17); - oledDisplay.print(buff); - oledDisplay.print(F(" g")); - - // print CG longitudinal axis - oledDisplay.drawXBMP(2, pos_CG_length, 18, 18, CGImage); - dtostrf(CG_length, 5, 1, buff); - oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), pos_CG_length + 16); - oledDisplay.print(buff); - oledDisplay.print(F(" mm")); - - // print CG transverse axis - if (nLoadcells == 3) { - oledDisplay.drawXBMP(2, 47, 18, 18, CGtransImage); - dtostrf(CG_trans, 5, 1, buff); - oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), 64); - oledDisplay.print(buff); - oledDisplay.print(F(" mm")); - } - } else { - oledDisplay.setFont(u8g2_font_5x7_tr); - for (int i = 1; i <= errMsgCnt; i++) { - oledDisplay.setCursor(0, 7 * i); - oledDisplay.print(errMsg[i]); - } - } - - } while ( oledDisplay.nextPage() ); // serial connection if (Serial) { @@ -838,7 +957,7 @@ void loop() { switch (menuPage) { case MENU_HOME: { - Serial.print(F("\n\n********************************************\nCG scale by M.Lehmann - V")); + Serial.print(F("\n\n********************************************\nCG scale by M.Lehmann et al. - V")); Serial.print(CGSCALE_VERSION); Serial.print(F("\n\n")); @@ -1111,10 +1230,16 @@ void getValue() { response += buff; response += "V"; } else { - dtostrf(batVolt, 5, 0, buff); + float percentVolt = percentBat(batVolt / batCells); + dtostrf(percentVolt, 5, 0, buff); response += buff; - response += "%"; + response += "%/"; + dtostrf(batVolt, 5, 2, buff); + response += buff; + response += "V"; } + Serial.print("send response: "); + Serial.println(response); server.send(200, "text/html", response); } @@ -1137,9 +1262,13 @@ void getRawValue() { response += buff; response += "V"; } else { - dtostrf(batVolt, 5, 0, buff); + float percentVolt = percentBat(batVolt / batCells); + dtostrf(percentVolt, 5, 0, buff); response += buff; - response += "%"; + response += "%/"; + dtostrf(batVolt, 5, 2, buff); + response += buff; + response += "V"; } server.send(200, "text/html", response); } diff --git a/README.md b/README.md index 32693bb..9ad3449 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Schwerpunktwaage auf Arduinobasis zum auswiegen von Flugmodellen. Es werden rela Die wichtigsten Funktionen: - unterstützt Waagen mit 2 oder 3 Wiegezellen -- unterstützt ESP8266 und Arduino mit ATmega328, ATmega32u4 +- unterstützt ESP8266 (auch Wifi Kit 8) und Arduino mit ATmega328, ATmega32u4 - automatische Kalibrierung anhand eines Referenzobjekts, dadurch kein mühsames eruieren der Kalibrierwerte - Anzeige durch OLED Display - Batteriespannnung kann gemessen werden diff --git a/data/index.html b/data/index.html new file mode 100755 index 0000000..19c1bbe --- /dev/null +++ b/data/index.html @@ -0,0 +1,880 @@ + + + + + + + + CG scale by M. Lehmann + + + + + + + +
+
+ +
+
+ + +
+
+ +
+
+ +
+ + +
+
+ +
+
-
+
+
+
+ +
+ +
+
-
+
+
+
+
+ +
+
-
+
+
+
+
+ +
+
+
+
+ + +
+
+ +
+
+ min: + +
+
+ max: + +
+
+ +
+
+
+
+
+ +
(c) 2019 M. Lehmann - Version: --
+ + + diff --git a/data/index.html.gz b/data/index.html.gz deleted file mode 100755 index 3a6266192726a308df89670ac714ee9346b32ccb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20389 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 U{3raW;o0B+8_iQJ-)qhQ03VZzI{*Lx diff --git a/data/models.html b/data/models.html new file mode 100755 index 0000000..b7fd767 --- /dev/null +++ b/data/models.html @@ -0,0 +1,531 @@ + + + + + + + + CG scale by M. Lehmann + + + + + + + + +
+
+ +
+
+ +
+
+ +
+ + + + + + + + +
+
+ +
(c) 2019 M. Lehmann - Version: --
+ + + diff --git a/data/models.html.gz b/data/models.html.gz deleted file mode 100755 index dec398dc4f0be33c1468e2a476c456678b4db814..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19906 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 F0042Sr*r@S diff --git a/data/settings.html b/data/settings.html new file mode 100755 index 0000000..ed54e8e --- /dev/null +++ b/data/settings.html @@ -0,0 +1,1062 @@ + + + + + + + + CG scale by M. Lehmann + + + + + + + +
+
+ +
+
+ +
+
+ +
+
+
+ + +
+

+
+ + + +
+
+ + +
+
+ + + +
+
+ + + +
+
+ + +
+
+ + +
+

+
+
+
+ +
+ + + +
+ +
+
+ + +
+ +
+
+
+
+ +

+
+ +
+ +
+
+

+
+ +
+ +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
+ - + - + - +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ + +
+
+ + + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+
+ +
(c) 2019 M. Lehmann - Version: --
+ + + diff --git a/data/settings.html.gz b/data/settings.html.gz deleted file mode 100755 index 12a8a32a7b8aa4381865783c5c25517c478da363..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16034 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 c!SVItB%$pQLO`w+kUAJzjg4|Br+0A9PXdjJ3c diff --git a/settings_ESP8266.h b/settings_ESP8266.h index e43080c..76e319c 100644 --- a/settings_ESP8266.h +++ b/settings_ESP8266.h @@ -45,15 +45,33 @@ CG scale with 3 Loadcells: */ -#define PIN_LOADCELL1_DOUT D6 -#define PIN_LOADCELL1_PD_SCK D5 -#define PIN_LOADCELL2_DOUT D2 -#define PIN_LOADCELL2_PD_SCK D1 +// Wifi Kit 8 (https://heltec.org/project/wifi-kit-8/) +// is a ESP8266 based board, with integrated OLED and battery management +// #define WIFI_KIT_8 1 +#ifdef WIFI_KIT_8 + #define PIN_LOADCELL1_DOUT D6 + #define PIN_LOADCELL1_PD_SCK D7 -#define PIN_LOADCELL3_DOUT D7 -#define PIN_LOADCELL3_PD_SCK D0 + #define PIN_LOADCELL2_DOUT D3 + + #define PIN_LOADCELL2_PD_SCK D8 + + #define PIN_LOADCELL3_DOUT D0 + #define PIN_LOADCELL3_PD_SCK D0 + // D3 can be used in parallel to the load cell with Wifi Kit 8 + #define PIN_TARE_BUTTON D3 +#else + #define PIN_LOADCELL1_DOUT D6 + #define PIN_LOADCELL1_PD_SCK D5 + + #define PIN_LOADCELL2_DOUT D2 + #define PIN_LOADCELL2_PD_SCK D1 + + #define PIN_LOADCELL3_DOUT D7 + #define PIN_LOADCELL3_PD_SCK D0 +#endif // **** Measurement settings **** @@ -81,9 +99,13 @@ CG scale with 3 Loadcells: // Please UNCOMMENT the display used -U8G2_SH1106_128X64_NONAME_1_HW_I2C oledDisplay(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ D3, /* data=*/ D4); -//U8G2_SSD1306_128X64_NONAME_1_HW_I2C oledDisplay(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ D3, /* data=*/ D4); - +#ifdef WIFI_KIT_8 + // Wifi Kit 8 has a fixed wired 128x32 display + U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C oledDisplay(U8G2_R0, /* reset=*/ 16, /* clock=*/ 5, /* data=*/ 4); +#else + U8G2_SH1106_128X64_NONAME_1_HW_I2C oledDisplay(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ D3, /* data=*/ D4); + //U8G2_SSD1306_128X64_NONAME_1_HW_I2C oledDisplay(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ D3, /* data=*/ D4); +#endif // **** Voltage measurement settings **** @@ -129,7 +151,7 @@ U8G2_SH1106_128X64_NONAME_1_HW_I2C oledDisplay(U8G2_R0, /* reset=*/ U8X8_PIN_NON // **** Wifi settings **** -#define MAX_SSID_PW_LENGHT 32 +#define MAX_SSID_PW_LENGHT 64 // Station mode: connect to available network #define SSID_STA "myWiFi" From f7293003fbc54ca8cf7e80589a0700e6a3bc7dc0 Mon Sep 17 00:00:00 2001 From: Rainer Stransky Date: Wed, 19 Aug 2020 12:35:14 +0200 Subject: [PATCH 2/2] code is now compatible with standard OLED displays and original code base (default pw length = 32) --- CG_scale.ino | 252 ++++++++++++++++++++++----------------------- settings_ESP8266.h | 8 +- 2 files changed, 131 insertions(+), 129 deletions(-) diff --git a/CG_scale.ino b/CG_scale.ino index 574a802..48c9fa7 100644 --- a/CG_scale.ino +++ b/CG_scale.ino @@ -4,29 +4,31 @@ (c) 2019 by M. Lehmann ------------------------------------------------------------------ */ -#define CGSCALE_VERSION "2.1" +#define CGSCALE_VERSION "2.2" /* ****************************************************************** history: + V2.2 18.08.20 code is now compatible with standard OLED displays + and original code base (default pw length = 32) V2.1 18.07.20 added support for ESP8266 based Wifi Kit 8 (by Pulsar07/ (https://heltec.org/project/wifi-kit-8/) - R.Stransky is a ESP8266 with - * a build in OLED 128x32 - * battery connector with charging management - * reset and GPIO0 button + R.Stransky is a ESP8266 with + a build in OLED 128x32 + battery connector with charging management + reset and GPIO0 button support for a tare button (PIN_TARE_BUTTON) bug fixed: wifi password now with up to 64 chars - bug fixed: wifi data (ssid/passwd) with special + bug fixed: wifi data (ssid/passwd) with special character (e.g. +) is now supported - for specified battery type, voltage is displayed + for specified battery type, voltage is displayed using uncompressed html files makes WEB GUI much faster V2.0 26.01.20 Webpage rewritten, no bootstrap framework needed add translation to webpage (en, de) optimized for measuring with landinggears updated to ArduinoJson V6 firmware update over web interface - V1.2.1 31.03.19 small bug fixed + V1.2.1 31.03.19 small bug fixed values in model database are rounded mDNS and OTA did not work in AP mode V1.2 23.02.19 Add OTA (over the air update) @@ -98,7 +100,7 @@ #endif // HX711 constructor array (dout pin, sck pint): -HX711_ADC LoadCell[]{HX711_ADC(PIN_LOADCELL1_DOUT, PIN_LOADCELL1_PD_SCK),HX711_ADC(PIN_LOADCELL2_DOUT, PIN_LOADCELL2_PD_SCK),HX711_ADC(PIN_LOADCELL3_DOUT, PIN_LOADCELL3_PD_SCK)}; +HX711_ADC LoadCell[] {HX711_ADC(PIN_LOADCELL1_DOUT, PIN_LOADCELL1_PD_SCK), HX711_ADC(PIN_LOADCELL2_DOUT, PIN_LOADCELL2_PD_SCK), HX711_ADC(PIN_LOADCELL3_DOUT, PIN_LOADCELL3_PD_SCK)}; // webserver constructor #if defined(ESP8266) @@ -153,6 +155,12 @@ bool updateMenu = true; int menuPage = 0; String errMsg[5]; int errMsgCnt = 0; +int oledDisplayHeight; +int oledDisplayWidth; +const uint8_t *oledFontLarge; +const uint8_t *oledFontNormal; +const uint8_t *oledFontSmall; +const uint8_t *oledFontTiny; #if defined(ESP8266) String updateMsg = ""; bool wifiSTAmode = true; @@ -169,40 +177,50 @@ void resetCPU() {} void initOLED() { oledDisplay.begin(); + oledDisplayHeight = oledDisplay.getDisplayHeight(); + oledDisplayWidth = oledDisplay.getDisplayWidth(); + printConsole(T_BOOT, "init OLED display: " + String(oledDisplayWidth) + String("x") + String(oledDisplayHeight)); - const uint8_t *font; - font = u8g2_font_6x12_tr; - int displayHeight = oledDisplay.getDisplayHeight(); - int displayWidth = oledDisplay.getDisplayWidth(); - if (displayHeight <= 32) { - font = u8g2_font_6x12_tr; + + oledFontLarge = u8g2_font_helvR12_tr; + oledFontNormal = u8g2_font_helvR10_tr; + oledFontSmall = u8g2_font_5x7_tr; + oledFontTiny = u8g2_font_4x6_tr; + + if (oledDisplayHeight <= 32) { + oledFontLarge = u8g2_font_helvR10_tr; + oledFontNormal = u8g2_font_6x12_tr; } - int ylineHeight = displayHeight/3; + int ylineHeight = oledDisplayHeight / 3; + + oledDisplay.setFont(oledFontNormal); oledDisplay.firstPage(); do { - if (displayHeight <= 32) { + oledDisplay.setFont(oledFontLarge); + if (oledDisplayHeight <= 32) { oledDisplay.drawXBMP(5, 0, 18, 18, CGImage); } else { oledDisplay.drawXBMP(20, 12, 18, 18, CGImage); } - oledDisplay.setFont(u8g2_font_helvR12_tr); - if (displayHeight <= 32) { + oledDisplay.setFont(oledFontLarge); + + if (oledDisplayHeight <= 32) { oledDisplay.setCursor(30, 12); } else { oledDisplay.setCursor(45, 28); } oledDisplay.print(F("CG scale")); - oledDisplay.setFont(u8g2_font_5x7_tr); - if (displayHeight <= 32) { + oledDisplay.setFont(oledFontSmall); + if (oledDisplayHeight <= 32) { oledDisplay.setCursor(30, 22); } else { oledDisplay.setCursor(35, 55); } oledDisplay.print(F("Version: ")); oledDisplay.print(CGSCALE_VERSION); - if (displayHeight <= 32) { + if (oledDisplayHeight <= 32) { oledDisplay.setCursor(5, 31); } else { oledDisplay.setCursor(20, 64); @@ -212,35 +230,28 @@ void initOLED() { } while ( oledDisplay.nextPage() ); } -void printOLED(String aLine1, String aLine2, String aLine3=String("")); +void printOLED(String aLine1, String aLine2, String aLine3 = String("")); void printOLED(String aLine1, String aLine2, String aLine3) { - const uint8_t *font; - font = u8g2_font_6x12_tr; - int displayHeight = oledDisplay.getDisplayHeight(); - int displayWidth = oledDisplay.getDisplayWidth(); - font = u8g2_font_helvR10_tr; - if (displayHeight <= 32) { - font = u8g2_font_6x12_tr; - } - int ylineHeight = displayHeight/3; + int ylineHeight = oledDisplayHeight / 3; oledDisplay.firstPage(); do { - oledDisplay.setFont(u8g2_font_6x12_tr); - oledDisplay.setCursor(0, ylineHeight*1); + oledDisplay.setFont(oledFontNormal); + oledDisplay.setCursor(0, ylineHeight * 1); oledDisplay.print(aLine1); - oledDisplay.setCursor(0, ylineHeight*2); + oledDisplay.setCursor(0, ylineHeight * 2); oledDisplay.print(aLine2); if (aLine3 == "") { - oledDisplay.drawLine(0, ylineHeight*2 + 2, displayWidth, ylineHeight*2+2); - oledDisplay.setFont(u8g2_font_4x6_tr); - oledDisplay.setCursor(0, displayHeight); + oledDisplay.drawLine(0, ylineHeight * 2 + 2, oledDisplayWidth, ylineHeight * 2 + 2); + oledDisplay.setFont(oledFontTiny); + oledDisplay.setCursor(0, oledDisplayHeight); + oledDisplay.print("IP:" + WiFi.localIP().toString()); String signature = "CG scale: V" + String(CGSCALE_VERSION); - oledDisplay.setCursor(displayWidth - oledDisplay.getStrWidth(signature.c_str()), displayHeight); + oledDisplay.setCursor(oledDisplayWidth - oledDisplay.getStrWidth(signature.c_str()), oledDisplayHeight); oledDisplay.print(signature); } else { - oledDisplay.setCursor(0, displayHeight); + oledDisplay.setCursor(0, oledDisplayHeight); oledDisplay.print(aLine3); } } while ( oledDisplay.nextPage() ); @@ -248,7 +259,9 @@ void printOLED(String aLine1, String aLine2, String aLine3) { void printScaleOLED() { // print to display - char buff[8]; + char buff1[8]; + char buff[12]; + char buff2[8]; int pos_weightTotal = 7; int pos_CG_length = 28; if (nLoadcells == 2) { @@ -260,19 +273,6 @@ void printScaleOLED() { } } - const uint8_t *font; - int linestart = 14; - int linedist = 25; - int col0=0; - int col1=28; - font = u8g2_font_helvR12_tr; - if (oledDisplay.getDisplayHeight() <=32) { - font = u8g2_font_6x12_tr; - linestart = 8; - linedist = 12; - col0=0; - col1=28; - } oledDisplay.firstPage(); do { if (errMsgCnt == 0) { @@ -283,7 +283,7 @@ void printScaleOLED() { dtostrf(percentVolt, 3, 0, buff); oledDisplay.drawBox(49, 2, (percentVolt / (100 / 8)), 4); - oledDisplay.setFont(u8g2_font_5x7_tr); + oledDisplay.setFont(oledFontSmall); oledDisplay.setCursor(78 - oledDisplay.getStrWidth(buff), 7); if (batType > B_VOLT) { dtostrf(percentVolt, 3, 0, buff); @@ -294,48 +294,48 @@ void printScaleOLED() { oledDisplay.print(buff); oledDisplay.print(F("V")); } - + // print total weight - oledDisplay.setFont(font); - if (oledDisplay.getDisplayHeight() <= 32) { + oledDisplay.setFont(oledFontNormal); + dtostrf(weightTotal, 7, 1, buff); + if (oledDisplayHeight <= 32) { oledDisplay.setCursor(1, 18); oledDisplay.print(F("M = ")); } else { oledDisplay.drawXBMP(2, pos_weightTotal, 18, 18, weightImage); oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), pos_weightTotal + 17); } - dtostrf(weightTotal, 5, 1, buff); oledDisplay.print(buff); - oledDisplay.print(F("g")); + oledDisplay.print(F(" g")); // print CG longitudinal axis - if (oledDisplay.getDisplayHeight() <=32) { + dtostrf(CG_length, 7, 1, buff); + if (oledDisplayHeight <= 32) { oledDisplay.setCursor(1, 32); oledDisplay.print(F("CG = ")); } else { oledDisplay.drawXBMP(2, pos_CG_length, 18, 18, CGImage); oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), pos_CG_length + 16); } - dtostrf(CG_length, 5, 1, buff); oledDisplay.print(buff); - oledDisplay.print(F("mm")); + oledDisplay.print(F(" mm")); // print CG transverse axis if (nLoadcells == 3) { - if (oledDisplay.getDisplayHeight() <=32) { + if (oledDisplayHeight <= 32) { oledDisplay.setCursor(78, 32); oledDisplay.print(F("LR=")); dtostrf(CG_trans, 3, 0, buff); } else { oledDisplay.drawXBMP(2, 47, 18, 18, CGtransImage); oledDisplay.setCursor(93 - oledDisplay.getStrWidth(buff), 64); - dtostrf(CG_trans, 5, 1, buff); + dtostrf(CG_trans, 7, 1, buff); } oledDisplay.print(buff); - oledDisplay.print(F("mm")); + oledDisplay.print(F(" mm")); } } else { - oledDisplay.setFont(u8g2_font_5x7_tr); + oledDisplay.setFont(oledFontSmall); for (int i = 1; i <= errMsgCnt; i++) { oledDisplay.setCursor(0, 7 * i); oledDisplay.print(errMsg[i]); @@ -345,19 +345,21 @@ void printScaleOLED() { } while ( oledDisplay.nextPage() ); } + + #ifdef PIN_TARE_BUTTON void handleTareBtn() { static unsigned long lastTaraBtn = 0; if ((millis() - lastTaraBtn) > 20) { lastTaraBtn = millis(); static int tareBtnCnt = 0; - if(digitalRead(PIN_TARE_BUTTON)) { + if (digitalRead(PIN_TARE_BUTTON)) { tareBtnCnt = 0; } else { tareBtnCnt++; if (tareBtnCnt > 10) { Serial.println("tare button pressed"); - printOLED("TARE ==>"," tare load cells ..."); + printOLED("TARE ==>", " tare load cells ..."); // avoid keybounce tareBtnCnt = -1000; tareLoadcells(); @@ -378,7 +380,7 @@ void saveCalFactor(int nLC) { } -void updateLoadcells(){ +void updateLoadcells() { for (int i = LC1; i <= LC3; i++) { if (i < nLoadcells) { LoadCell[i].update(); @@ -387,7 +389,7 @@ void updateLoadcells(){ } -void tareLoadcells(){ +void tareLoadcells() { for (int i = LC1; i <= LC3; i++) { if (i < nLoadcells) { LoadCell[i].tare(); @@ -396,7 +398,7 @@ void tareLoadcells(){ } -void printNewValueText(){ +void printNewValueText() { Serial.print(F("Set new value:")); } @@ -421,7 +423,7 @@ bool runAutoCalibrate() { calFactorLoadcell[i] = calFactorLoadcell[i] / (toWeightLoadCell[i] / weightLoadCell[i]); saveCalFactor(i); } - + // finish Serial.println(F("done")); } @@ -461,7 +463,7 @@ int percentBat(float cellVoltage) { break; } } - + float cellempty = pgm_read_float( &percentList[batTypeArray][0][0]); float cellfull = pgm_read_float( &percentList[batTypeArray][elementCount][0]); @@ -473,9 +475,9 @@ int percentBat(float cellVoltage) { for (int i = 0; i <= elementCount; i++) { float curVolt = pgm_read_float(&percentList[batTypeArray][i][0]); if (curVolt >= cellVoltage && i > 0) { - float lastVolt = pgm_read_float(&percentList[batTypeArray][i-1][0]); + float lastVolt = pgm_read_float(&percentList[batTypeArray][i - 1][0]); float curPercent = pgm_read_float(&percentList[batTypeArray][i][1]); - float lastPercent = pgm_read_float(&percentList[batTypeArray][i-1][1]); + float lastPercent = pgm_read_float(&percentList[batTypeArray][i - 1][1]); result = float((cellVoltage - lastVolt) / (curVolt - lastVolt)) * (curPercent - lastPercent) + lastPercent; break; } @@ -496,7 +498,7 @@ void setup() { #if defined(ESP8266) printConsole(T_BOOT, "startup CG scale V" + String(CGSCALE_VERSION)); - + // init filesystem SPIFFS.begin(); EEPROM.begin(EEPROM_SIZE); @@ -579,9 +581,6 @@ void setup() { #endif // init OLED display -#if defined(ESP8266) - printConsole(T_BOOT, "init OLED display: " + String(oledDisplay.getDisplayWidth())+ String("x") + String(oledDisplay.getDisplayHeight())); -#endif initOLED(); // init & tare Loadcells @@ -590,7 +589,7 @@ void setup() { LoadCell[i].begin(); LoadCell[i].setCalFactor(calFactorLoadcell[i]); #if defined(ESP8266) - printConsole(T_BOOT, "init Loadcell " + String(i+1)); + printConsole(T_BOOT, "init Loadcell " + String(i + 1)); #endif } } @@ -606,12 +605,13 @@ void setup() { #if defined(ESP8266) + printConsole(T_BOOT, "Wifi: STA mode - connecing with: " + String(ssid_STA)); + // Start by connecting to a WiFi network WiFi.persistent(false); WiFi.mode(WIFI_STA); WiFi.begin(ssid_STA, password_STA); - printConsole(T_BOOT, "Wifi: STA mode - connect with: " + String(ssid_STA)); long timeoutWiFi = millis(); @@ -643,7 +643,7 @@ void setup() { printConsole(T_RUN, "Wifi: Connected, IP: " + String(WiFi.localIP().toString())); } - + // Set Hostname String hostname = "disabled"; #if ENABLE_MDNS @@ -653,7 +653,7 @@ void setup() { if (!MDNS.begin(hostname, WiFi.localIP())) { hostname = "mDNS failed"; printConsole(T_ERROR, "Wifi: " + hostname); - }else{ + } else { hostname += ".local"; printConsole(T_RUN, "Wifi: " + hostname); } @@ -703,10 +703,10 @@ void setup() { printConsole(T_RUN, "Webserver is up and running"); // init OTA (over the air update) - if(enableOTA){ + if (enableOTA) { ArduinoOTA.setHostname(ssid_AP); ArduinoOTA.setPassword(password_AP); - + ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) { @@ -718,16 +718,16 @@ void setup() { updateMsg = "Updating " + type; printConsole(T_UPDATE, type); }); - + ArduinoOTA.onEnd([]() { updateMsg = "successful.."; printUpdateProgress(100, 100); }); - + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { printUpdateProgress(progress, total); }); - + ArduinoOTA.onError([](ota_error_t error) { if (error == OTA_AUTH_ERROR) { updateMsg = "Auth Failed"; @@ -746,14 +746,14 @@ void setup() { ArduinoOTA.begin(); printConsole(T_RUN, "OTA is up and running"); } - - // https update + + // https update httpsClient.setInsecure(); - if(enableUpdate){ + if (enableUpdate) { // check for update httpsUpdate(PROBE_UPDATE); } - + #endif } @@ -767,15 +767,15 @@ void loop() { MDNS.update(); #endif - if(enableOTA){ + if (enableOTA) { ArduinoOTA.handle(); } server.handleClient(); #endif - #ifdef PIN_TARE_BUTTON +#ifdef PIN_TARE_BUTTON handleTareBtn(); - #endif +#endif updateLoadcells(); @@ -811,9 +811,9 @@ void loop() { CG_length = ((weightLoadCell[LC2] * model.distance[X2]) / weightTotal) + model.distance[X1]; #if defined(ESP8266) - if(model.mechanicsType == 2){ + if (model.mechanicsType == 2) { CG_length = ((weightLoadCell[LC2] * model.distance[X2]) / weightTotal) - model.distance[X1]; - }else if(model.mechanicsType == 3){ + } else if (model.mechanicsType == 3) { CG_length = ((weightLoadCell[LC2] * model.distance[X2]) / weightTotal) * -1 + model.distance[X1]; } #endif @@ -835,7 +835,6 @@ void loop() { printScaleOLED(); - // serial connection if (Serial) { if (Serial.available() > 0) { @@ -969,7 +968,7 @@ void loop() { for (int i = X1; i <= X3; i++) { Serial.print(MENU_DISTANCE_X1 + i); Serial.print(F(" - Set distance X")); - Serial.print(i+1); + Serial.print(i + 1); Serial.print(F(" (")); Serial.print(model.distance[i]); Serial.print(F("mm)\n")); @@ -990,9 +989,9 @@ void loop() { for (int i = LC1; i <= LC3; i++) { Serial.print(MENU_LOADCELL1_CALIBRATION_FACTOR + i); - if((MENU_LOADCELL1_CALIBRATION_FACTOR + i) < 10) Serial.print(F(" ")); + if ((MENU_LOADCELL1_CALIBRATION_FACTOR + i) < 10) Serial.print(F(" ")); Serial.print(F(" - Set calibration factor of load cell ")); - Serial.print(i+1); + Serial.print(i + 1); Serial.print(F(" (")); Serial.print(calFactorLoadcell[i]); Serial.print(F(")\n")); @@ -1001,7 +1000,7 @@ void loop() { for (int i = R1; i <= R2; i++) { Serial.print(MENU_RESISTOR_R1 + i); Serial.print(F(" - Set value of resistor R")); - Serial.print(i+1); + Serial.print(i + 1); Serial.print(F(" (")); Serial.print(resistor[i]); Serial.print(F("ohm)\n")); @@ -1362,14 +1361,14 @@ void getWiFiNetworks() { bool ssidSTAavailable = false; String response = ""; int n = WiFi.scanNetworks(); - + if (n > 0) { for (int i = 0; i < n; ++i) { response += WiFi.SSID(i); - if(WiFi.SSID(i) == ssid_STA) ssidSTAavailable = true; + if (WiFi.SSID(i) == ssid_STA) ssidSTAavailable = true; if (i < n - 1) response += "&"; } - if(!ssidSTAavailable){ + if (!ssidSTAavailable) { response += "&"; response += ssid_STA; } @@ -1421,7 +1420,7 @@ void saveParameter() { EEPROM.put(P_ENABLE_OTA, enableOTA); EEPROM.commit(); - if(model.name != ""){ + if (model.name != "") { saveModelJson(model.name); } @@ -1682,7 +1681,7 @@ bool deleteModelJson(String modelName) { void writeModelData(JsonObject object) { char buff[8]; String stringBuff; - + dtostrf(weightTotal, 5, 1, buff); stringBuff = buff; stringBuff.trim(); @@ -1707,14 +1706,13 @@ void writeModelData(JsonObject object) { // print update progress screen void printUpdateProgress(unsigned int progress, unsigned int total) { printConsole(T_UPDATE, updateMsg); - + oledDisplay.firstPage(); do { - oledDisplay.setFont(u8g2_font_helvR08_tr); + oledDisplay.setFont(oledFontSmall); oledDisplay.setCursor(0, 12); oledDisplay.print(updateMsg); - oledDisplay.setFont(u8g2_font_5x7_tr); oledDisplay.setCursor(107, 35); oledDisplay.printf("%u%%\r", (progress / (total / 100))); @@ -1739,10 +1737,10 @@ char * TimeToString(unsigned long t) return str; } -void printConsole(int t, String msg){ +void printConsole(int t, String msg) { Serial.print(TimeToString(millis())); Serial.print(" ["); - switch(t) { + switch (t) { case T_BOOT: Serial.print("BOOT"); break; @@ -1768,7 +1766,7 @@ void printConsole(int t, String msg){ // https update -bool httpsUpdate(uint8_t command){ +bool httpsUpdate(uint8_t command) { if (!httpsClient.connect(HOST, HTTPS_PORT)) { printConsole(T_ERROR, "Wifi: connection to GIT failed"); return false; @@ -1776,44 +1774,44 @@ bool httpsUpdate(uint8_t command){ const char * headerKeys[] = {"Location"} ; const size_t numberOfHeaders = 1; - + HTTPClient https; https.setUserAgent("cgscale"); https.setRedirectLimit(0); https.setFollowRedirects(true); String url = "https://" + String(HOST) + String(URL); - if (https.begin(httpsClient, url)) { + if (https.begin(httpsClient, url)) { https.collectHeaders(headerKeys, numberOfHeaders); printConsole(T_HTTPS, "GET: " + url); int httpCode = https.GET(); - if (httpCode > 0) { + if (httpCode > 0) { // response - if (httpCode == HTTP_CODE_FOUND) { + if (httpCode == HTTP_CODE_FOUND) { String newUrl = https.header("Location"); - gitVersion = newUrl.substring(newUrl.lastIndexOf('/')+2).toFloat(); - if(gitVersion > String(CGSCALE_VERSION).toFloat()){ + gitVersion = newUrl.substring(newUrl.lastIndexOf('/') + 2).toFloat(); + if (gitVersion > String(CGSCALE_VERSION).toFloat()) { printConsole(T_UPDATE, "Firmware update available: V" + String(gitVersion)); - }else{ + } else { printConsole(T_UPDATE, "Firmware version found on GitHub: V" + String(gitVersion) + " - current firmware is up to date"); } - }else if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { + } else if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { Serial.println(https.getString()); - }else{ + } else { printConsole(T_ERROR, "HTTPS: GET... failed, " + https.errorToString(httpCode)); https.end(); return false; } - }else { + } else { return false; } - https.end(); - }else { + https.end(); + } else { printConsole(T_ERROR, "Wifi: Unable to connect"); return false; } - + return true; } diff --git a/settings_ESP8266.h b/settings_ESP8266.h index 76e319c..f33fe79 100644 --- a/settings_ESP8266.h +++ b/settings_ESP8266.h @@ -48,7 +48,7 @@ CG scale with 3 Loadcells: // Wifi Kit 8 (https://heltec.org/project/wifi-kit-8/) // is a ESP8266 based board, with integrated OLED and battery management -// #define WIFI_KIT_8 1 +#define WIFI_KIT_8 1 #ifdef WIFI_KIT_8 #define PIN_LOADCELL1_DOUT D6 #define PIN_LOADCELL1_PD_SCK D7 @@ -62,6 +62,8 @@ CG scale with 3 Loadcells: // D3 can be used in parallel to the load cell with Wifi Kit 8 #define PIN_TARE_BUTTON D3 + + #define MAX_SSID_PW_LENGHT 64 #else #define PIN_LOADCELL1_DOUT D6 #define PIN_LOADCELL1_PD_SCK D5 @@ -151,7 +153,9 @@ CG scale with 3 Loadcells: // **** Wifi settings **** -#define MAX_SSID_PW_LENGHT 64 +#ifndef MAX_SSID_PW_LENGHT +#define MAX_SSID_PW_LENGHT 32 +#endif // Station mode: connect to available network #define SSID_STA "myWiFi"