Skip to content

Commit

Permalink
fixing dtu conn handling at dtu shutdown and tft nightmode showing no…
Browse files Browse the repository at this point in the history
… power at 0
  • Loading branch information
ohAnd committed Sep 11, 2024
1 parent 91a408d commit 95c5a41
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 53 deletions.
1 change: 1 addition & 0 deletions include/base/platformData.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct baseDataStruct
#elif defined(ESP32)
uint64_t chipID = ESP.getEfuseMac();
#endif
boolean esp32 = false;
String espUniqueName = String(AP_NAME_START) + "_" + chipID;

const char *fwVersion = VERSION;
Expand Down
1 change: 1 addition & 0 deletions include/dtuInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class DTUInterface {


void checkingDataUpdate();
void checkingForLastDataReceived();
boolean cloudPauseActiveControl();

// Protobuf functions
Expand Down
6 changes: 3 additions & 3 deletions include/version.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#define VERSION "1.9.857_localDev"
#define BUILDTIME "09.09.2024 - 12:39:02"
#define BUILDTIMESTAMP "1725878342"
#define VERSION "2.0.55_localDev"
#define BUILDTIME "11.09.2024 - 21:58:24"
#define BUILDTIMESTAMP "1726084704"
8 changes: 4 additions & 4 deletions include/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.9.857_localDev",
"versiondate": "09.09.2024 - 12:39:02",
"linksnapshot": "https://github.com/ohAnd/dtuGateway/releases/download/snapshot/dtuGateway_snapshot_1.9.857_localDev.bin",
"link": "https://github.com/ohAnd/dtuGateway/releases/latest/download/dtuGateway_release_1.9.857_localDev.bin"
"version": "2.0.55_localDev",
"versiondate": "11.09.2024 - 21:58:24",
"linksnapshot": "https://github.com/ohAnd/dtuGateway/releases/download/snapshot/dtuGateway_snapshot_2.0.55_localDev.bin",
"link": "https://github.com/ohAnd/dtuGateway/releases/latest/download/dtuGateway_release_2.0.55_localDev.bin"
}
7 changes: 3 additions & 4 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
monitor_port = COM8
upload_port = COM8
monitor_port = COM6
upload_port = COM6
upload_speed = 921600
lib_deps =
arduino-libraries/NTPClient @ ^3.2.1
Expand All @@ -23,7 +23,6 @@ lib_deps =
gyverlibs/UnixTime @ ^1.1
bblanchon/ArduinoJson @ ^7.0.0
knolleary/PubSubClient @ ^2.8
khoih-prog/ESP32TimerInterrupt @ ^2.3.0
olikraus/U8g2 @ ^2.35.19
bodmer/TFT_eSPI @ ^2.5.43
me-no-dev/AsyncTCP @ ^1.1.1
Expand All @@ -36,6 +35,7 @@ custom_nanopb_protos =
extra_scripts = pre:version_inc.py
board_build.partitions = min_spiffs.csv
monitor_filters =
esp32_exception_decoder
default
time
build_flags =
Expand Down Expand Up @@ -73,7 +73,6 @@ lib_deps =
nanopb/Nanopb @ ^0.4.8
gyverlibs/UnixTime @ ^1.1
bblanchon/ArduinoJson @ ^7.0.0
khoih-prog/ESP8266TimerInterrupt @ ^1.6.0
knolleary/PubSubClient @ ^2.8
me-no-dev/ESPAsyncTCP @ ^1.2.2
me-no-dev/ESP Async WebServer @ ^1.2.3
Expand Down
31 changes: 22 additions & 9 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@


## problem
The new series of Hoymiles inverter with internal wireless access point and wireless client have no direct API to include this endpoint in smarthome installations/ IFTT environments.
The newer series of Hoymiles inverter with internal wireless access point and wireless client have no direct API to include this endpoint in smarthome installations/ IFTT environments.

Usually there should be no need for an extra device to "translate" the connection to common APIs or bindings. Unfortunately the interface on the dtu is unlikely unstable/ or not really stable.

Expand Down Expand Up @@ -77,10 +77,10 @@ So I decided to put this abstraction in an **ESP8266** to have a stable abstract
- automatic reboot of DTU, if there is an error detected (e.g. inplausible not changed values)

#### connections to the environment
- serving the readed data per /api/data
- serving the read data per /api/data.json
- configuration of bindings with seperate activation and login data setting
- binding: updating openHab instance with readed data and pulling set data from the instance
- binding: updating to a MQTT broker with readed data incl. set PowerLimit over MQTT
- binding: updating openHab instance with read data and pulling power set data from the instance
- binding: updating to a MQTT broker with read data incl. subscribing to the Set PowerLimit over MQTT
- 2 ways to configure - simple mqtt publishing with base topic or together with HA MQTT AutoDiscovery based
- for all publishing retain flag is set (keeping last seen data in broker)
- TLS connection to mqtt broker e.g. for hivemq.cloud - ! only possible for ESP32 setup
Expand All @@ -101,18 +101,30 @@ So I decided to put this abstraction in an **ESP8266** to have a stable abstract
- setting the orientation of the display via advanced web config[^2]
- OLED - 0 and 180 degrees are supported
- TFT - 0, 90, 180, 270 degrees are supported
- brightness and night mode (brightness only for OLED and TFT with connected backlight control)
- brightness and night mode (brightness only for TFT with connected backlight control and OLED)
- with night mode enabled and during the active time frame the display will be
- off/ blank (without backlight control) or
- off (with backlight control)/ blank (without backlight control) or
- show the current time and power (if greater than 0) in a reduced scope
- adjustable via web config[^2]
- brightness day [0...255] - will also be used without night mode enabled for standard brightness (falling back to this after power value changed)
- brightness night [0...255]
- brightness night [0...255] - note: 0 = backlight off
- (to disable PWM control for TFT without backlight control set both brightness values to zero)
- night mode enabled on/ off
- night mode start in minutes to start of the day - e.g. 1320 for 22:00
- night mode stop in minutes to start of the day - e.g. 360 for 6:00
- night clock enabled on/ of - on = clock will be displayed instead of dark screen
- night clock enabled on/ off - on = clock will be displayed instead of dark screen
- example settings:

| setting | value | comment |
|-----------------|-------|---------
| brightnessDay | 150 | note: 255 - ~150 only difficult to perceive
| brightnessNight | 30 |
| nightClock | true | show the clock instead of black screen during night time
| nightMode | true | night mode is enabled
| nightmodeStart | 1320 | night time will start at 22 o'clock
| nightmodeEnd | 390 | night time will end at 6:30


- display hardware types
- display SSH1106 OLED 1,3" 128x64 (other sizes with same driver (SSH1106) and resolution should also directly work)

Expand Down Expand Up @@ -486,12 +498,13 @@ With the manual login to dtu access point and forcing the storing of local wifi
- lot of single updates for power setting within few seconds (< 2-3) without any reading of values (e.g. realdata) -> it seems this creating no problems
- therefore current setup -> no time limit for power setting, but reading data only every 31 seconds is running fine
- sometimes hanging or full shutdown/ break of DTU will be prevented by sending an active reboot request to dtu (hanging detection at this time over grid voltage, should be changing at least within 10 consecutive incoming data)
- with this setup: now the device is running for days without any stops (overall system point of view: target settings will be performed everytime, readed data will be available, no manual steps needed to recover the dtu connection)
- with this setup: now the device is running for days without any stops (overall system point of view: target settings will be performed everytime, read data will be available, no manual steps needed to recover the dtu connection)


### hoymiles cloud update
- everey 15 min (0,15,30,45) -> timestamp update
- after 7 min 40 s update of graph data (if wifi not reachable, also reset of wifi AP)
- if there is at these points an active connection to the dtu and current data will be requested, the update to the cloud will be interrupted and no current data for this point in time will be stored in the cloud

### sources

Expand Down
2 changes: 2 additions & 0 deletions src/displayTFT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ void DisplayTFT::drawFooter(String time)
{
tft.setTextColor(SPECIAL_BLUE, TFT_BLACK);
tft.drawCentreString(" " + String(lastDisplayData.totalPower) + " W ", 120, 174, 4);
} else {
tft.fillRect(60, 170, 120, 37, TFT_BLACK); // clear power display
}

// // debug brightness
Expand Down
44 changes: 16 additions & 28 deletions src/dtuGateway.ino
Original file line number Diff line number Diff line change
Expand Up @@ -573,13 +573,13 @@ boolean getPowerSetDataFromOpenHab()
}
else
{
Serial.print("got wrong data for SetLimit: " + openhabMessage);
Serial.println("OPENHAB:\t\t got wrong data for SetLimit: " + openhabMessage);
return false;
}
if (lastOpenhabLimit != newLimit && lastOpenhabLimit != 255)
{
dtuGlobalData.powerLimitSet = newLimit;
Serial.println("OPENHAB: got new OH Limit: " + String(dtuGlobalData.powerLimitSet) + " - last OH limit: " + String(lastOpenhabLimit) + " %");
Serial.println("OPENHAB:\t\t got new OH Limit: " + String(dtuGlobalData.powerLimitSet) + " - last OH limit: " + String(lastOpenhabLimit) + " %");
}
lastOpenhabLimit = newLimit;
return true;
Expand Down Expand Up @@ -668,9 +668,9 @@ void updateValuesToMqtt(boolean haAutoDiscovery = false)
// update all apis according to current states and settings
void updateDataToApis()
{
if (!dtuConnection.dtuActiveOffToCloudUpdate)
if (!dtuConnection.dtuActiveOffToCloudUpdate) // normal update
{
if ((globalControls.getDataAuto || globalControls.getDataOnce) && dtuGlobalData.uptodate)
if (((globalControls.getDataAuto || globalControls.getDataOnce) && dtuGlobalData.uptodate) || dtuConnection.dtuErrorState == DTU_ERROR_LAST_SEND)
{
if (userConfig.openhabActive)
updateValueToOpenhab();
Expand All @@ -688,27 +688,6 @@ void updateDataToApis()
if (globalControls.getDataOnce)
globalControls.getDataOnce = false;
}
else if ((dtuGlobalData.currentTimestamp - dtuGlobalData.lastRespTimestamp) > (5 * 60) && dtuGlobalData.grid.voltage > 0) // dtuGlobalData.grid.voltage > 0 indicates dtu/ inverter working
{
dtuGlobalData.grid.power = 0;
dtuGlobalData.grid.current = 0;
dtuGlobalData.grid.voltage = 0;

dtuGlobalData.pv0.power = 0;
dtuGlobalData.pv0.current = 0;
dtuGlobalData.pv0.voltage = 0;

dtuGlobalData.pv1.power = 0;
dtuGlobalData.pv1.current = 0;
dtuGlobalData.pv1.voltage = 0;

if (userConfig.openhabActive)
updateValueToOpenhab();
if (userConfig.mqttActive)
updateValuesToMqtt(userConfig.mqttHAautoDiscoveryON);
dtuConnection.dtuErrorState = DTU_ERROR_LAST_SEND;
Serial.print(F("\n>>>>> TIMEOUT 5 min for DTU -> NIGHT - send zero values\n"));
}
}
}

Expand All @@ -728,6 +707,7 @@ void setup()
platformData.chipID |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
platformData.espUniqueName = String(AP_NAME_START) + "_" + platformData.chipID;
platformData.esp32 = true;
#endif

// initialize digital pin LED_BLINK as an output.
Expand Down Expand Up @@ -1176,7 +1156,16 @@ void loop()
// -------->
// led blink code only 5 min after startup
if ((platformData.currentNTPtime - platformData.dtuGWstarttime) < 300)
{
blinkCodeTask();
}
// turn the LED off only if OLED or TFT with ESP8266 is connected
// ESP32 has an overlapping LED with the SCK pin of the SPI interface for the TFT
else if (userConfig.displayConnected == 0 || (userConfig.displayConnected == 1 && !platformData.esp32))
{
digitalWrite(LED_BLINK, LED_BLINK_OFF);
}

serialInputTask();

if (userConfig.mqttActive)
Expand Down Expand Up @@ -1281,9 +1270,8 @@ void loop()
Serial.println("----- ----- set new power limit from " + String(dtuGlobalData.powerLimit) + " % to " + String(dtuGlobalData.powerLimitSet) + " % ----- ----- ");
dtuInterface.setPowerLimit(dtuGlobalData.powerLimitSet);
// set next normal request in 5 seconds from now on, only if last data updated within last 2 times of user setted update rate
// if (currentMillis - dtuGlobalData.lastRespTimestamp < (userConfig.dtuUpdateTime * 2))
// platformData.dtuNextUpdateCounterSeconds = currentMillis - (userConfig.dtuUpdateTime - 5);
platformData.dtuNextUpdateCounterSeconds = dtuGlobalData.currentTimestamp - userConfig.dtuUpdateTime + 5;
if (dtuGlobalData.currentTimestamp - dtuGlobalData.lastRespTimestamp < (userConfig.dtuUpdateTime * 2))
platformData.dtuNextUpdateCounterSeconds = dtuGlobalData.currentTimestamp - userConfig.dtuUpdateTime + 5;
}
}

Expand Down
40 changes: 35 additions & 5 deletions src/dtuInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void DTUInterface::setPowerLimit(int limit)
dtuGlobalData.powerLimitSet = limit;
if (client->connected())
{
Serial.println("DTUinterface:\t setPowerLimit: " + String(limit) + " - send command to DTU ...");
Serial.println("DTUinterface:\t try to set setPowerLimit: " + String(limit) + " %");
writeReqCommand(limit);
}
else
Expand Down Expand Up @@ -129,11 +129,16 @@ void DTUInterface::dtuLoop()
{
txrxStateObserver();

// check if cloud pause is active to prevent cloud errors
if (dtuConnection.preventCloudErrors)
cloudPauseActiveControl();
else
dtuConnection.dtuActiveOffToCloudUpdate = false;

// check for last data received
checkingForLastDataReceived();

// check if we are in a cloud pause period
if (dtuConnection.dtuActiveOffToCloudUpdate)
{
if (client->connected())
Expand Down Expand Up @@ -298,7 +303,7 @@ void DTUInterface::handleError(uint8_t errorState)
{
dtuConnection.dtuErrorState = errorState;
dtuConnection.dtuConnectState = DTU_STATE_DTU_REBOOT;
Serial.print(F("+++ DTU Connection --- ERROR - try with reboot of DTU - error state: "));
Serial.print(F("DTUinterface:\t DTU Connection --- ERROR - try with reboot of DTU - error state: "));
Serial.println(errorState);
writeCommandRestartDevice();
dtuGlobalData.dtuResetRequested = dtuGlobalData.dtuResetRequested + 1;
Expand Down Expand Up @@ -618,7 +623,7 @@ void DTUInterface::checkingDataUpdate()
// Serial.println("DTUinterface:\t GridV check result: " + String(gridVoltValueHanging));
if (gridVoltValueHanging)
{
Serial.println(F("DTUinterface:\t grid voltage observer found hanging value - try to reboot DTU"));
Serial.println(F("DTUinterface:\t checkingDataUpdate -> grid voltage observer found hanging value - try to reboot DTU"));
handleError(DTU_ERROR_DATA_NO_CHANGE);
dtuGlobalData.uptodate = false;
}
Expand All @@ -632,18 +637,43 @@ void DTUInterface::checkingDataUpdate()
if (abs((int(dtuGlobalData.respTimestamp) - int(dtuGlobalData.currentTimestamp))) > 3)
{
dtuGlobalData.currentTimestamp = dtuGlobalData.respTimestamp;
Serial.print(F("\n>--> synced local time with DTU time <--<\n"));
Serial.print(F("DTUinterface:\t checkingDataUpdate ---> synced local time with DTU time\n"));
}
}
else
{
dtuGlobalData.uptodate = false;
Serial.print(F("DTUinterface:\t checkingDataUpdate -> DTU_ERROR_NO_TIME\n"));
// stopping connection to DTU when response time error - try with reconnec
handleError(DTU_ERROR_NO_TIME);
}
dtuGlobalData.lastRespTimestamp = dtuGlobalData.respTimestamp;
}

void DTUInterface::checkingForLastDataReceived()
{
// check if last data received - currentTimestamp + 5 sec (to debounce async current timestamp) - lastRespTimestamp > 3 min
if (((dtuGlobalData.currentTimestamp + 5) - dtuGlobalData.lastRespTimestamp) > (3 * 60) && dtuGlobalData.grid.voltage > 0 && dtuConnection.dtuErrorState != DTU_ERROR_LAST_SEND) // dtuGlobalData.grid.voltage > 0 indicates dtu/ inverter was working
{
dtuGlobalData.grid.power = 0;
dtuGlobalData.grid.current = 0;
dtuGlobalData.grid.voltage = 0;

dtuGlobalData.pv0.power = 0;
dtuGlobalData.pv0.current = 0;
dtuGlobalData.pv0.voltage = 0;

dtuGlobalData.pv1.power = 0;
dtuGlobalData.pv1.current = 0;
dtuGlobalData.pv1.voltage = 0;


dtuConnection.dtuErrorState = DTU_ERROR_LAST_SEND;
dtuGlobalData.updateReceived = true;
Serial.println("DTUinterface:\t checkingForLastDataReceived >>>>> TIMEOUT 5 min for DTU -> NIGHT - send zero values +++ currentTimestamp: " + String(dtuGlobalData.currentTimestamp) + " - lastRespTimestamp: " + String(dtuGlobalData.lastRespTimestamp));
}
}

void DTUInterface::writeReqAppGetHistPower()
{
uint8_t buffer[200];
Expand Down Expand Up @@ -1013,7 +1043,7 @@ boolean DTUInterface::readRespCommandRestartDevice(pb_istream_t istream)
dtuConnection.dtuTxRxState = DTU_TXRX_STATE_IDLE;
CommandReqDTO commandreqdto = CommandReqDTO_init_default;

Serial.print(" --> respCommand Restart - got remote: " + getTimeStringByTimestamp(commandreqdto.time));
Serial.print("DTUinterface:\t -readRespCommandRestartDevice - got remote: " + getTimeStringByTimestamp(commandreqdto.time));

pb_decode(&istream, &GetConfigReqDTO_msg, &commandreqdto);
Serial.printf("\ncommand req action: %i", commandreqdto.action);
Expand Down

0 comments on commit 95c5a41

Please sign in to comment.