Skip to content

Commit

Permalink
showing inverter and warn state in TFT display + rework of warning me…
Browse files Browse the repository at this point in the history
…ssage decoding and setting local inverter state
  • Loading branch information
ohAnd committed Dec 14, 2024
1 parent 4d04b69 commit b814094
Show file tree
Hide file tree
Showing 9 changed files with 819 additions and 81 deletions.
678 changes: 678 additions & 0 deletions include/displayTFT.h

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions include/dtuInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ struct inverterCtrl
struct warnDataBlock
{
uint16_t num = 0;
uint16_t code = 0;
char message[64] = "";
uint32_t code = 0;
char message[96] = "";
uint32_t timestampStart = 0;
uint32_t timestampStop = 0;
uint32_t data0 = 0;
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 "2.1.102_localDev"
#define BUILDTIME "12.12.2024 - 21:53:05"
#define BUILDTIMESTAMP "1734036785"
#define VERSION "2.1.150_localDev"
#define BUILDTIME "14.12.2024 - 12:19:15"
#define BUILDTIMESTAMP "1734175155"
8 changes: 4 additions & 4 deletions include/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "2.1.102_localDev",
"versiondate": "12.12.2024 - 21:53:05",
"linksnapshot": "https://github.com/ohAnd/dtuGateway/releases/download/snapshot/dtuGateway_snapshot_2.1.102_localDev.bin",
"link": "https://github.com/ohAnd/dtuGateway/releases/latest/download/dtuGateway_release_2.1.102_localDev.bin"
"version": "2.1.150_localDev",
"versiondate": "14.12.2024 - 12:19:15",
"linksnapshot": "https://github.com/ohAnd/dtuGateway/releases/download/snapshot/dtuGateway_snapshot_2.1.150_localDev.bin",
"link": "https://github.com/ohAnd/dtuGateway/releases/latest/download/dtuGateway_release_2.1.150_localDev.bin"
}
9 changes: 6 additions & 3 deletions include/web/index_html.h
Original file line number Diff line number Diff line change
Expand Up @@ -1451,14 +1451,17 @@ const char INDEX_HTML[] PROGMEM = R"=====(
$('#activeWarnings').empty();
// sort cacheDtuData.warnings by timestampStart - newest first
cacheDtuData.warnings.sort((a, b) => (a.timestampStart < b.timestampStart) ? 1 : -1);

var activeWarning = false;
for (let index = 0; index < cacheDtuData.warnings.length; index++) {
let warning = cacheDtuData.warnings[index];
if (warning.timestampStop == 0) {
numOfWarningsActive++;
activeWarning = true;
} else {
activeWarning = false;
}
let warningRow = `
<div class="warningRow" style="display: flex; justify-content: space-between;">
<div class="warningRow" style="display: flex; justify-content: space-between; ${!activeWarning ? `color: grey;` : ''}">
<div class="warningColumn" style="flex: 0 0 auto; padding: 5px;">
<div class="warningTimestamp">${new Date(warning.timestampStart * 1000).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(',', ' -')}</div>
${warning.timestampStop !== 0 ? `<div class="warningTimestamp">${new Date(warning.timestampStop * 1000).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(',', ' -')}</div>` : ''}
Expand All @@ -1467,7 +1470,7 @@ const char INDEX_HTML[] PROGMEM = R"=====(
<div class="warningMessage">${warning.num}</div>
</div>
<div class="warningColumn" style="flex: 1; padding: 5px; text-align: left;">
<div class="warningMessage">${warning.message} (${warning.code})</div>
<div class="warningMessage">${warning.message}</div>
</div>
<div class="warningColumn" style="flex: 1; padding: 5px;">
`;
Expand Down
97 changes: 61 additions & 36 deletions src/displayTFT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,52 +131,77 @@ void DisplayTFT::drawScreen(String version, String time)
}
}



void DisplayTFT::drawMainDTUOnline(bool pause)
{

// show a cloud upload symbol if cloud pause active
if (pause)
tft.pushImage(195, 70, cloudWidth, cloudHeight, cloud);
else
tft.fillRect(195, 70, 32, 26, TFT_BLACK); // clear icon
tft.fillRect(195, 70, cloudWidth, cloudHeight, TFT_BLACK); // clear icon

if (dtuGlobalData.warningsActive > 0)
tft.pushImage(12, 70, warningWidth, warningHeight, warning);
else
tft.fillRect(12, 70, warningWidth, warningHeight, TFT_BLACK); // clear icon

// main screen
// --- base window for wattage ----------------------------------
uint32_t wattRingColor = TFT_CYAN;
if (lastDisplayData.remoteDisplayActive)
wattRingColor = TFT_DARKGREEN;
tft.drawSmoothArc(119, 119, 75, 75 - 1, 47, 313, wattRingColor, TFT_BLACK);
tft.drawWideLine(64, 169, 64 + 109, 169, 2, wattRingColor, TFT_BLACK);

// ----------------------------------------------
// tft.pushImage(70, 200, 16, 16, wifiIcon);
// ----------------------------------------------
// current power
tft.setTextColor(TFT_DARKCYAN, TFT_BLACK);
tft.drawCentreString("W", 120, 57, 4);
// clear main space if inverterControl.stateOn changed
static bool previousStateOn = dtuGlobalData.inverterControl.stateOn;
if (previousStateOn != dtuGlobalData.inverterControl.stateOn)
{
tft.drawSmoothArc(119, 119, 75, 0, 47, 313, TFT_BLACK, TFT_BLACK);
tft.fillRect(64, 140, 109, 169, TFT_BLACK);
previousStateOn = dtuGlobalData.inverterControl.stateOn;
Serial.println("DisplayTFT:\t >> inverter state changed - clear main screen");
}

tft.setTextColor(TFT_WHITE, TFT_BLACK);
// tft.drawCentreString(String(lastDisplayData.totalPower), 120, 84, 6);
if (!dtuGlobalData.inverterControl.stateOn)
{
tft.pushImage(70, 60, power_offWidth, power_offHeight, power_off);

tft.setTextDatum(TC_DATUM); // centered datum
int padding = tft.textWidth("999.9", 6);
tft.setTextPadding(padding);
tft.drawNumber(lastDisplayData.totalPower, 120, 84, 6);
tft.setTextColor(TFT_DARKCYAN, TFT_BLACK);
tft.drawCentreString("inverter switched off", 120, 150, 2);
}
else
{
// --- base window for wattage ----------------------------------
uint32_t wattRingColor = TFT_CYAN;
if (lastDisplayData.remoteDisplayActive)
wattRingColor = TFT_DARKGREEN;
tft.drawSmoothArc(119, 119, 75, 75 - 1, 47, 313, wattRingColor, TFT_BLACK);
tft.drawWideLine(64, 169, 64 + 109, 169, 2, wattRingColor, TFT_BLACK);

// power limit
tft.setTextColor(TFT_GREENYELLOW, TFT_BLACK);
int padding = tft.textWidth("999.9", 6);

// current power
tft.setTextColor(TFT_DARKCYAN, TFT_BLACK);
tft.drawCentreString("W", 120, 57, 4);

tft.setTextColor(TFT_WHITE, TFT_BLACK);

tft.setTextDatum(TC_DATUM); // centered datum
padding = tft.textWidth("999", 6);
tft.setTextPadding(padding);
// tft.drawCentreString(String(lastDisplayData.powerLimit) + " %", 120, 130, 4);
tft.drawNumber(lastDisplayData.powerLimit, 120, 130, 4);
tft.setTextPadding(0); // reset padding
tft.setTextDatum(TC_DATUM); // centered datum
tft.setTextPadding(padding);
tft.drawNumber(lastDisplayData.totalPower, 120, 84, 6);
// power limit
tft.setTextColor(TFT_GREENYELLOW, TFT_BLACK);

tft.drawString("%", 148, 135, 2);
tft.setTextDatum(TC_DATUM); // centered datum
padding = tft.textWidth("999", 6);
tft.setTextPadding(padding);
// tft.drawCentreString(String(lastDisplayData.powerLimit) + " %", 120, 130, 4);
tft.drawNumber(lastDisplayData.powerLimit, 120, 130, 4);
tft.setTextPadding(0); // reset padding

tft.setTextColor(TFT_DARKCYAN, TFT_BLACK);
tft.drawCentreString("Power Limit", 120, 150, 2);
tft.drawString("%", 148, 135, 2);

tft.setTextColor(TFT_DARKCYAN, TFT_BLACK);
tft.drawCentreString("Power Limit", 120, 150, 2);
}


// tft.fillRoundRect(80, 120, 100, 26, 1, TFT_BLACK);
}
Expand Down Expand Up @@ -272,11 +297,11 @@ void DisplayTFT::drawFooter(String time)
tft.drawCentreString(time, 120, 174, 4);

tft.setTextColor(TFT_DARKCYAN, TFT_BLACK);
tft.drawCentreString("day", 85, 215, 1);
tft.drawCentreString("day", 85, 215, 1);
tft.drawCentreString("kWh", 120, 215, 1);
tft.drawCentreString("total", 155, 215, 1);
tft.drawCentreString("total", 155, 215, 1);
tft.drawCentreString("yield", 120, 225, 1);

tft.setTextColor(TFT_CYAN, TFT_BLACK);
tft.drawCentreString(String(lastDisplayData.totalYieldDay, 3), 85, 198, 2);
tft.drawCentreString(String(lastDisplayData.totalYieldTotal, 1), 155, 198, 2);
Expand Down Expand Up @@ -320,7 +345,7 @@ void DisplayTFT::drawFooter(String time)
int sec = (time.substring(time.lastIndexOf(":") + 1)).toInt();
int secpoint = (sec * 6) + 180;

if(userConfig.displayTFTsecondsRing == false)
if (userConfig.displayTFTsecondsRing == false)
sec = 0;

// black circle
Expand Down Expand Up @@ -420,7 +445,7 @@ void DisplayTFT::checkNightMode()
Serial.println("DisplayTFT:\t >> night mode activated - schedule: " + String(isNightBySchedule) + " - offline: " + String(isNightByOffline));
}
}
// start day mode if
// start day mode if
// offline trigger is enabled and schedule is not active and offline is not active OR
// offline trigger is dsiabled and schedule is not active
else if ((userConfig.displayNightModeOfflineTrigger && !isNightBySchedule && !isNightByOffline) || (!userConfig.displayNightModeOfflineTrigger && !isNightBySchedule))
Expand Down
6 changes: 5 additions & 1 deletion src/dtuGateway.ino
Original file line number Diff line number Diff line change
Expand Up @@ -1389,14 +1389,18 @@ void loop()
// test data
// dtuGlobalData.updateReceived = true;
// dtuGlobalData.warnDataLastTimestamp = timeClient.getEpochTime();
// dtuGlobalData.warningsActive = 1;
// dtuGlobalData.warningsActive = 2;
// dtuGlobalData.warnData[0].code = 124;
// String message = "[not approved] ??? shut down by remote control";
// strncpy(dtuGlobalData.warnData[0].message, message.c_str(), sizeof(dtuGlobalData.warnData[0].message) - 1);
// dtuGlobalData.warnData[0].timestampStart = timeClient.getEpochTime() - 1000;
// dtuGlobalData.warnData[0].timestampStop = 0;
// dtuGlobalData.warnData[0].data0 = 0;
// dtuGlobalData.warnData[0].data1 = 0;

// dtuConnection.dtuConnectionOnline = true;
// dtuConnection.dtuConnectState = DTU_STATE_CONNECTED;
// dtuGlobalData.inverterControl.stateOn = false;
}

// mid task
Expand Down
91 changes: 59 additions & 32 deletions src/dtuInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ void DTUInterface::dtuLoop()
}
}
}
// if there was a reboot of dtu, but the connection survived the reboot
else if (dtuConnection.dtuConnectState == DTU_STATE_DTU_REBOOT && client->connected())
{
dtuConnection.dtuConnectState = DTU_STATE_CONNECTED;
Serial.println("DTUinterface:\t dtuLoop - state was reboot - but connection is still alive -> set state to connected");
}
}
}

Expand Down Expand Up @@ -1694,36 +1700,53 @@ boolean DTUInterface::readRespCommandGetAlarms(pb_istream_t istream)
dtuGlobalData.warnData[i].data1 = 0;
}

// wcode = 8316 => "Inverter remote off" -> WTime1 = since
// wcode = 8402 => "PV2 no input voltage"
// wcode = 8410 => "PV2 Undervoltage" -> data1: "input voltage" - data2: "undervoltage limit" + -> WTime1 = from and WTime2 = to (or to null - then currently given)
// wcode = 16593 => "PV1 no input voltage" -> -> WTime1 = from and WTime2 = to
// wcode = 16600 => "PV1 Undervoltage" -> data1: "input voltage" - data2: "undervoltage limit" + -> WTime1 = from and WTime2 = to (or to null - then currently given)
// wcode = 28796 => "history -> Inverter was remote off - period" -> WTime1 = from and WTime2 = to

std::map<int, std::string> warningCodeMap = {
{124, "[not approved] ??? shut down by remote control"},
{208, "[text not known]"},
{209, "PV1 no input voltage - active"},
{210, "[not approved] PV2 no input voltage - active"},
{216, "PV1 Undervoltage - active"},
{218, "[not approved] PV2 Undervoltage - active"},
{8316, "Inverter remote off - active"},
{8402, "PV2 no input voltage"},
{8410, "PV2 Undervoltage"},
{16508, "[text not known] ??? shut down by remote control - period"},
{16593, "PV1 no input voltage"},
{16600, "PV1 Undervoltage"},
{28796, "Inverter was remote off - period"}};
// std::map<int, std::string> warningCodeMap = {
// {208, "[text not known]"}, // 218 in binary - 1101 0000

// {124, "inverter shut down by remote control - active"}, // 124 in binary - 0111 1100 ( 0, 124)
// {8316, "inverter shut down by remote control - active"}, // 8316 in binary - 0010 0000 0111 1100 ( 32, 124)
// {16508, "inverter shut down by remote control - period"}, // 16508 in binary - 0100 0000 0111 1100 ( 64, 124)
// {20604, "[not approved] inverter shut down by remote control - period"}, // 20604 in binary - 0101 0000 0111 1100 ( 80, 124)
// {28796, "inverter shut down by remote control - period"}, // 28796 in binary - 0111 0000 0111 1100 ( 112, 124)

// {209, "PV1 no input voltage - active"}, // 209 in binary - 1101 0001 ( 0, 209)
// {16593, "PV1 no input voltage - period"}, // 16593 in binary - 0100 0000 1101 0001 ( 64, 209)
// {20689, "PV1 no input voltage - period"}, // 20689 in binary - 0101 0000 1101 0001 ( 80, 209)


// {216, "PV1 Undervoltage - active"}, // 216 in binary - 1101 1000 ( 0, 216)
// {16600, "PV1 Undervoltage - period"}, // 16600 in binary - 0100 0000 1101 1000 ( 64, 216)
// {20696, "PV1 Undervoltage - period"}, // 20696 in binary - 0101 0000 1101 1000 ( 80, 216)

// {210, "[not approved] PV2 no input voltage - active"}, // 210 in binary - 1101 0010 ( 0, 210)
// {8402, "PV2 no input voltage - period"}, // 8402 in binary - 0010 0000 1101 0010 ( 32, 210)

// {218, "[not approved] PV2 Undervoltage - active"}, // 218 in binary - 1101 1010 ( 0, 218)
// {8410, "PV2 Undervoltage - period"}, // 8410 in binary - 0010 0000 1101 1010 ( 32, 218)
// };

std::map<int, std::string> warningCodeMap = {
{208, "[text not known]"}, // 1101 0000
{124, "inverter shut down by remote control"}, // 0111 1100
{209, "PV0 no input voltage"}, // 1101 0001
{216, "PV0 Undervoltage"}, // 1101 1000
{210, "PV1 no input voltage"}, // 1101 0010
{218, "PV1 Undervoltage"}, // 1101 1010
};


uint8_t warningActiveCount = 0;
for (int i = 0; i < WARN_DATA_MAX_ENTRIES - 1; i++)
{
if (winforeqdto.mWInfo[i].pv_sn != 0)
{
int wcode = winforeqdto.mWInfo[i].WCode;
int wcode1 = winforeqdto.mWInfo[i].WCode & 0x000000FF;
int wcode2 = (winforeqdto.mWInfo[i].WCode & 0xFFFFFF00) >> 8;

String unknownWcode = "Unknown warning code";
std::string warningMessage = warningCodeMap.count(wcode) ? warningCodeMap[wcode] : unknownWcode.c_str();
std::string warningMessage = warningCodeMap.count(wcode1) ? warningCodeMap[wcode1] : unknownWcode.c_str();
warningMessage = warningMessage + " (" + std::to_string(wcode1) + "," + std::to_string(wcode2) + ")";

dtuGlobalData.warnData[i].code = winforeqdto.mWInfo[i].WCode;
strncpy(dtuGlobalData.warnData[i].message, warningMessage.c_str(), sizeof(dtuGlobalData.warnData[i].message) - 1);
dtuGlobalData.warnData[i].message[sizeof(dtuGlobalData.warnData[i].message) - 1] = '\0'; // Ensure null-termination
Expand All @@ -1732,18 +1755,22 @@ boolean DTUInterface::readRespCommandGetAlarms(pb_istream_t istream)
dtuGlobalData.warnData[i].timestampStop = winforeqdto.mWInfo[i].WTime2;
dtuGlobalData.warnData[i].data0 = winforeqdto.mWInfo[i].WData1;
dtuGlobalData.warnData[i].data1 = winforeqdto.mWInfo[i].WData2;

if (dtuGlobalData.warnData[i].timestampStart != 0 && dtuGlobalData.warnData[i].timestampStop == 0)
{
warningActiveCount++;
}
if (wcode == 8316)
{
dtuGlobalData.inverterControl.stateOn = false; // set to false due to an active warning "Inverter remote off"
Serial.printf("\ncommand warn%d - pv_sn: %i", i, winforeqdto.mWInfo[i].pv_sn);
Serial.printf("\ncommand warn%d - wcode: %i (%s)", i, wcode, warningMessage.c_str());
Serial.printf("\ncommand warn%d - wnum: %i", i, winforeqdto.mWInfo[i].WNum);
Serial.printf("\ncommand warn%d - wtime1: %i -> wtime2: %i (%s -> %s)", i, winforeqdto.mWInfo[i].WTime1, winforeqdto.mWInfo[i].WTime2, getTimeStringByTimestamp(winforeqdto.mWInfo[i].WTime1).c_str(), getTimeStringByTimestamp(winforeqdto.mWInfo[i].WTime2).c_str());
Serial.printf("\ncommand warn%d - WData1: %i ++ WData2: %i\n", i, winforeqdto.mWInfo[i].WData1, winforeqdto.mWInfo[i].WData2);
if (wcode1 == 124)
{
dtuGlobalData.inverterControl.stateOn = false; // set to false due to an active warning "Inverter remote off"
dtuGlobalData.powerLimit = 0;
Serial.printf("\ncommand warn%d - pv_sn: %i", i, winforeqdto.mWInfo[i].pv_sn);
Serial.printf("\ncommand warn%d - wcode: %i (%s)", i, wcode1, warningMessage.c_str());
Serial.printf("\ncommand warn%d - wnum: %i", i, winforeqdto.mWInfo[i].WNum);
Serial.printf("\ncommand warn%d - wtime1: %i -> wtime2: %i (%s -> %s)", i, winforeqdto.mWInfo[i].WTime1, winforeqdto.mWInfo[i].WTime2, getTimeStringByTimestamp(winforeqdto.mWInfo[i].WTime1).c_str(), getTimeStringByTimestamp(winforeqdto.mWInfo[i].WTime2).c_str());
Serial.printf("\ncommand warn%d - WData1: %i ++ WData2: %i\n", i, winforeqdto.mWInfo[i].WData1, winforeqdto.mWInfo[i].WData2);
} else {
dtuGlobalData.inverterControl.stateOn = false; // set to true due to NO active warning "Inverter remote off"
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/mqttHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ void MQTTHandler::publishDiscoveryMessage(const char *entity, const char *entity
if (deviceClass == "running")
{
doc["payload_on"] = "1";
doc["payload_off"] = "0";
}


Expand Down

0 comments on commit b814094

Please sign in to comment.