From 7eb0e94e461327bf2d688db8bcb7568f030f93c1 Mon Sep 17 00:00:00 2001 From: Michael Stegen Date: Thu, 17 Oct 2024 11:25:10 +0200 Subject: [PATCH] Add Sensorbox-2 WiFi menu option. Only visible when Sensorbox 2 with suitable firmware is connected over RS485. --- SmartEVSE-3/include/evse.h | 17 ++++++++++++++--- SmartEVSE-3/include/meter.h | 1 + SmartEVSE-3/src/evse.cpp | 11 ++++++++++- SmartEVSE-3/src/glcd.cpp | 32 ++++++++++++++++++++++++++++++++ SmartEVSE-3/src/meter.cpp | 33 +++++++++++++++++++++++++++++++++ SmartEVSE-3/src/modbus.cpp | 4 +++- 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/SmartEVSE-3/include/evse.h b/SmartEVSE-3/include/evse.h index 6b786785..3302f255 100644 --- a/SmartEVSE-3/include/evse.h +++ b/SmartEVSE-3/include/evse.h @@ -255,6 +255,7 @@ extern RemoteDebug Debug; #define SOLARSTARTTIME 40 // Seconds to keep chargecurrent at 6A #define OCPP_MODE 0 #define AUTOUPDATE 0 // default for Automatic Firmware Update: 0 = disabled, 1 = enabled +#define SB2_WIFI_MODE 0 // Mode settings #define MODE_NORMAL 0 @@ -385,7 +386,7 @@ extern RemoteDebug Debug; #define MENU_MODE 12 // 0x0200: EVSE mode #define MENU_CIRCUIT 13 // 0x0201: EVSE Circuit max Current #define MENU_GRID 14 // 0x0202: Grid type to which the Sensorbox is connected -#define MENU_UNUSED 15 // 0x0203: Unused +#define MENU_SB2_WIFI 15 // 0x0203: WiFi mode of the Sensorbox 2 #define MENU_MAINS 16 // 0x0204: Max Mains Current #define MENU_START 17 // 0x0205: Surplus energy start Current #define MENU_STOP 18 // 0x0206: Stop solar charging at 6A after this time @@ -465,6 +466,7 @@ extern struct tm timeinfo; extern uint8_t Mode; // EVSE mode extern uint8_t LoadBl; // Load Balance Setting (Disable, Master or Node) extern uint8_t Grid; +extern uint8_t SB2_WIFImode; #if FAKE_RFID extern uint8_t Show_RFID; #endif @@ -531,7 +533,7 @@ const struct { {"MODE", "Normal, Smart or Solar EVSE mode", 0, 2, MODE}, {"CIRCUIT", "EVSE Circuit max Current", 10, 160, MAX_CIRCUIT}, {"GRID", "Grid type to which the Sensorbox is connected", 0, 1, GRID}, - {"Unused", "Unused", 0, 1, 0}, + {"SB2 WIFI","Connect Sensorbox-2 to WiFi", 0, 2, SB2_WIFI_MODE}, {"MAINS", "Max MAINS Current (per phase)", 10, 200, MAX_MAINS}, {"START", "Surplus energy start Current (sum of phases)", 0, 48, START_CURRENT}, {"STOP", "Stop solar charging at 6A after this time", 0, 60, STOP_TIME}, @@ -550,7 +552,7 @@ const struct { {"ENE REGI","Register for Energy (kWh) of custom electric meter", 0, 65534, EMCUSTOM_EREGISTER}, {"ENE DIVI","Divisor for Energy (kWh) of custom electric meter", 0, 7, EMCUSTOM_EDIVISOR}, {"READ MAX","Max register read at once of custom electric meter", 3, 255, 3}, - {"WIFI", "Use ESPTouch APP on your phone", 0, 2, WIFI_MODE}, + {"WIFI", "Connect SmartEVSE to WiFi", 0, 2, WIFI_MODE}, {"AUTOUPDAT","Automatic Firmware Update", 0, 1, AUTOUPDATE}, {"CONTACT 2","Contactor2 (C2) behaviour", 0, sizeof(StrEnableC2) / sizeof(StrEnableC2[0])-1, ENABLE_C2}, {"MAX TEMP","Maximum temperature for the EVSE module", 40, 75, MAX_TEMPERATURE}, @@ -588,6 +590,15 @@ struct DelayedTimeStruct { int32_t diff; // StartTime minus current time in seconds }; +struct Sensorbox { + uint8_t SoftwareVer; // Sensorbox 2 software version + uint8_t WiFiConnected; // 0:not connected / 1:connected to WiFi + uint8_t WiFiAPSTA; // 0:no portal / 1: portal active + uint8_t WIFImode; // 0:Wifi Off / 1:WiFi On / 2: Portal Start + uint8_t IP[4]; + uint8_t APpassword[8]; +}; + #define EPOCH2_OFFSET 1672531200 extern struct DelayedTimeStruct DelayedStartTime; diff --git a/SmartEVSE-3/include/meter.h b/SmartEVSE-3/include/meter.h index fb76bbed..7719f266 100644 --- a/SmartEVSE-3/include/meter.h +++ b/SmartEVSE-3/include/meter.h @@ -31,6 +31,7 @@ extern struct EMstruct EMConfig[EM_CUSTOM + 1]; extern struct ModBus MB; +extern struct Sensorbox SB2; class Meter { public: diff --git a/SmartEVSE-3/src/evse.cpp b/SmartEVSE-3/src/evse.cpp index 5afc3b7d..9768bb65 100644 --- a/SmartEVSE-3/src/evse.cpp +++ b/SmartEVSE-3/src/evse.cpp @@ -146,6 +146,7 @@ struct DelayedTimeStruct DelayedStartTime; struct DelayedTimeStruct DelayedStopTime; uint8_t DelayedRepeat; // 0 = no repeat, 1 = daily repeat uint8_t Grid = GRID; // Type of Grid connected to Sensorbox (0:4Wire / 1:3Wire ) +uint8_t SB2_WIFImode = SB2_WIFI_MODE; // Sensorbox-2 WiFi Mode (0:Disabled / 1:Enabled / 2:Start Portal) uint8_t RFIDReader = RFID_READER; // RFID Reader (0:Disabled / 1:Enabled / 2:Enable One / 3:Learn / 4:Delete / 5:Delete All / 6: Remote via OCPP) #if FAKE_RFID uint8_t Show_RFID = 0; @@ -1387,7 +1388,7 @@ Regis Access Description Unit Values 0x0200 R/W EVSE mode 0:Normal / 1:Smart / 2:Solar 0x0201 R/W EVSE Circuit max Current A 10 - 160 0x0202 R/W Grid type to which the Sensorbox is connected 0:4Wire / 1:3Wire -0x0203 R/W CT calibration value 0.01 Multiplier +0x0203 R/W Sensorbox 2 WiFi Mode 0:Disabled / 1:Enabled / 2:Portal 0x0204 R/W Max Mains Current A 10 - 200 0x0205 R/W Surplus energy start Current A 1 - 16 0x0206 R/W Stop solar charging at 6A after this time min 0:Disable / 1 - 60 @@ -1728,6 +1729,9 @@ uint8_t setItemValue(uint8_t nav, uint16_t val) { case MENU_GRID: Grid = val; break; + case MENU_SB2_WIFI: + SB2_WIFImode = val; + break; case MENU_MAINSMETER: MainsMeter.Type = val; break; @@ -1866,6 +1870,8 @@ uint16_t getItemValue(uint8_t nav) { return RCmon; case MENU_GRID: return Grid; + case MENU_SB2_WIFI: + return SB2_WIFImode; case MENU_MAINSMETER: return MainsMeter.Type; case MENU_MAINSMETERADDRESS: @@ -3328,6 +3334,7 @@ void Timer1S(void * parameter) { // but in Normal mode we just want to charge ChargeCurrent, irrespective of communication problems. ErrorFlags |= CT_NOCOMM; setStatePowerUnavailable(); + SB2.SoftwareVer = 0; _LOG_W("Error, MainsMeter communication error!\n"); } else { if (MainsMeter.Timeout) MainsMeter.Timeout--; @@ -3774,6 +3781,7 @@ void read_settings() { StopTime = preferences.getUShort("StopTime", STOP_TIME); ImportCurrent = preferences.getUShort("ImportCurrent",IMPORT_CURRENT); Grid = preferences.getUChar("Grid",GRID); + SB2_WIFImode = preferences.getUChar("SB2WIFImode",SB2_WIFI_MODE); RFIDReader = preferences.getUChar("RFIDReader",RFID_READER); MainsMeter.Type = preferences.getUChar("MainsMeter", MAINS_METER); @@ -3852,6 +3860,7 @@ void write_settings(void) { preferences.putUShort("StopTime", StopTime); preferences.putUShort("ImportCurrent", ImportCurrent); preferences.putUChar("Grid", Grid); + preferences.putUChar("SB2WIFImode", SB2_WIFImode); preferences.putUChar("RFIDReader", RFIDReader); preferences.putUChar("MainsMeter", MainsMeter.Type); diff --git a/SmartEVSE-3/src/glcd.cpp b/SmartEVSE-3/src/glcd.cpp index 31bc29ab..1dd0508e 100644 --- a/SmartEVSE-3/src/glcd.cpp +++ b/SmartEVSE-3/src/glcd.cpp @@ -428,6 +428,34 @@ void GLCD(void) { else if (RFIDstatus == 6) GLCD_print_buf(0, (const char*) "Card storage full!"); else glcd_clrln(0, 0x00); // Clear line LCDTimer = 0; // reset timer, so it will not exit the menu when learning/deleting cards + // Sensorbox 2 WiFi settings + } else if (LCDNav == MENU_SB2_WIFI) { + // wait for sensorbox to switch to selected mode + if ( (SB2.WIFImode != SB2_WIFImode) && SubMenu && SB2_WIFImode !=2) { + GLCD_write_buf_str(0,0, "one moment please...", GLCD_ALIGN_LEFT); + + } else if (SB2_WIFImode == 1) { // Enable WiFi on Sensorbox 2 + + if (SB2.WiFiConnected) { + sprintf(Str, "SB2: %u.%u.%u.%u",SB2.IP[0],SB2.IP[1],SB2.IP[2],SB2.IP[3]); + GLCD_write_buf_str(0,0, Str, GLCD_ALIGN_LEFT); + } else GLCD_write_buf_str(0,0, "Not connected to WiFi", GLCD_ALIGN_LEFT); + + } else if (SB2_WIFImode == 2) { // Enable Portal on Sensorbox 2 + if (SubMenu) { + sprintf(Str, "O button starts config"); + GLCD_write_buf_str(0,0, Str, GLCD_ALIGN_LEFT); + } else { + // Show Portal Password + sprintf(Str, "Password: %s", SB2.APpassword); + GLCD_write_buf_str(0, 0, Str, GLCD_ALIGN_LEFT); + GLCD_sendbuf(7, 1); + GLCD_buffer_clr(); + sprintf(Str, "Now connect to portal"); + GLCD_write_buf_str(0, 0, Str, GLCD_ALIGN_LEFT); + } + } + } else { // When connected to Wifi, display IP and time in top row uint8_t WIFImode = getItemValue(MENU_WIFI); @@ -990,6 +1018,7 @@ const char * getMenuItemOption(uint8_t nav) { case MENU_RFIDREADER: return StrRFIDReader[value]; case MENU_WIFI: + case MENU_SB2_WIFI: return StrWiFi[value]; case MENU_EXIT: return StrExitMenu; @@ -1019,6 +1048,9 @@ uint8_t getMenuItems (void) { MenuItems[m++] = MENU_MAINSMETER; // - - Type of Mains electric meter (0: Disabled / Constants EM_*) if (MainsMeter.Type == EM_SENSORBOX) { // - - ? Sensorbox? if (GridActive == 1) MenuItems[m++] = MENU_GRID; + if (SB2.SoftwareVer >= 0x01) { + MenuItems[m++] = MENU_SB2_WIFI; // Sensorbox-2 Wifi 0:Disabled / 1:Enabled / 2:Portal + } } else if (MainsMeter.Type && MainsMeter.Type != EM_API) { // - - ? Other? MenuItems[m++] = MENU_MAINSMETERADDRESS; // - - - Address of Mains electric meter (9 - 247) } diff --git a/SmartEVSE-3/src/meter.cpp b/SmartEVSE-3/src/meter.cpp index 67bdf5f5..becbd6aa 100644 --- a/SmartEVSE-3/src/meter.cpp +++ b/SmartEVSE-3/src/meter.cpp @@ -33,6 +33,7 @@ struct EMstruct EMConfig[EM_CUSTOM + 1] = { {"Custom", ENDIANESS_LBF_LWF, 4, MB_DATATYPE_INT32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Last entry! }; +struct Sensorbox SB2; Meter::Meter(uint8_t type, uint8_t address, uint8_t timeout) { for (int x = 1; x < 3; x++) { @@ -180,6 +181,38 @@ uint8_t Meter::receiveCurrentMeasurement(uint8_t *buf) { if ((var[x] > -1) && (var[x] < 1)) var[x] = 0; } } + // Store Sensorbox software version + SB2.SoftwareVer = buf[0]; + // Make sure the version and datalength are correct before processing the data. + // the version alone does not indicate that we have read the extended registers. + if (SB2.SoftwareVer >= 1 && MB.DataLength == 64) { + // Read Status, IP, AP Password from Sensorbox + SB2.WiFiConnected = buf[40]>>1 & 1; + SB2.WiFiAPSTA = buf[40]>>2 & 1; + SB2.WIFImode = buf[41]; + _LOG_I("SB2 WiFiMode:%u\n",SB2.WIFImode); + SB2.IP[0] = buf[48]; + SB2.IP[1] = buf[49]; + SB2.IP[2] = buf[50]; + SB2.IP[3] = buf[51]; + for (x = 0; x < 8; x++) { + SB2.APpassword[7-x] = buf[56 + x]; + } + + if (SB2_WIFImode == 2 && SB2.WiFiConnected && !SubMenu) { + SB2_WIFImode = 1; // Portal active and connected? Switch back to Enabled. + write_settings(); + LCDNav = 0; + } + + // Send new mode to Sensorbox 2 when mode differs from local SB2_WiFimode + // for mode "SetupWifi" only send mode when -not- in Submenu. + if ( (SB2.WIFImode != SB2_WIFImode) && (SB2_WIFImode != 2 || !SubMenu) ) { + _LOG_I("New SB2 mode:%u\n", SB2_WIFImode); + ModbusWriteSingleRequest(0x0A, 0x801, SB2_WIFImode); // Send new WiFi mode to Sensorbox + } + } + // Set Sensorbox 2 to 3/4 Wire configuration (and phase Rotation) (v2.16) if (buf[1] >= 0x10 && offset == 7) { GridActive = 1; // Enable the GRID menu option diff --git a/SmartEVSE-3/src/modbus.cpp b/SmartEVSE-3/src/modbus.cpp index e828eb34..92c3671d 100644 --- a/SmartEVSE-3/src/modbus.cpp +++ b/SmartEVSE-3/src/modbus.cpp @@ -335,7 +335,9 @@ void requestCurrentMeasurement(uint8_t Meter, uint8_t Address) { case EM_API: break; case EM_SENSORBOX: - ModbusReadInputRequest(Address, 4, 0, 20); + if (SB2.SoftwareVer >= 1) { + ModbusReadInputRequest(Address, 4, 0, 32); + } else ModbusReadInputRequest(Address, 4, 0, 20); break; case EM_EASTRON1P: case EM_EASTRON3P: