diff --git a/src/app.cpp b/src/app.cpp index 6b197dbd1..98ffaec80 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -381,7 +381,7 @@ void app::tickSend(void) { DPRINTLN(DBG_WARN, F("NRF24 not connected!")); return; } - if (mIVCommunicationOn) { + if (mIVCommunicationOn && mTimestamp) { if (!mSys.Radio.mBufCtrl.empty()) { if (mConfig->serial.debug) { DPRINT(DBG_DEBUG, F("recbuf not empty! #")); diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 23bdd1a5b..3ea6e12ad 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -127,11 +127,13 @@ class Inverter { record_t recordInfo; // structure for info values record_t recordConfig; // structure for system config values record_t recordAlarm; // structure for alarm values - //String lastAlarmMsg; bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null) bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) uint32_t pac_sum; // average calc for chart: sum of ac power values for cur interval uint16_t pac_cnt; // average calc for chart: number of ac power values for cur interval + uint16_t alarmCode; // last Alarm + uint32_t alarmStart; + uint32_t alarmEnd; Inverter() { ivGen = IV_HM; @@ -141,9 +143,9 @@ class Inverter { mDevControlRequest = false; devControlCmd = InitDataState; initialized = false; - //lastAlarmMsg = "nothing"; alarmMesIndex = 0; isConnected = false; + alarmCode = 0; } ~Inverter() { @@ -178,9 +180,11 @@ class Inverter { uint8_t getQueuedCmd() { if (_commandQueue.empty()) { if (ivGen != IV_MI) { - if (getFwVersion() == 0) + if (getFwVersion()) { + enqueCommand(RealTimeRunData_Debug); // live data + } else { enqueCommand(InverterDevInform_All); // firmware version - enqueCommand(RealTimeRunData_Debug); // live data + } } else if (ivGen == IV_MI){ if (getFwVersion() == 0) enqueCommand(InverterDevInform_All); // firmware version; might not work, esp. for 1/2 ch hardware @@ -321,9 +325,6 @@ class Inverter { } else if (rec->assign == AlarmDataAssignment) { DPRINTLN(DBG_DEBUG, "add alarm"); - //if (getPosByChFld(0, FLD_LAST_ALARM_CODE, rec) == pos){ - // lastAlarmMsg = getAlarmStr(rec->record[pos]); - //} } else DPRINTLN(DBG_WARN, F("add with unknown assginment")); @@ -489,18 +490,22 @@ class Inverter { return 0; uint16_t wCode = ((uint16_t)pyld[startOff]) << 8 | pyld[startOff+1]; - uint32_t startTimeOffset = 0, endTimeOffset = 0; + alarmStart = 0; + alarmEnd = 0; if (((wCode >> 13) & 0x01) == 1) // check if is AM or PM - startTimeOffset = 12 * 60 * 60; + alarmStart = 12 * 60 * 60; if (((wCode >> 12) & 0x01) == 1) // check if is AM or PM - endTimeOffset = 12 * 60 * 60; + alarmEnd = 12 * 60 * 60; - *start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; - *endTime = (((uint16_t)pyld[startOff + 6] << 8) | ((uint16_t)pyld[startOff + 7])) + endTimeOffset; + alarmCode = pyld[startOff+1]; + alarmStart += (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])); + alarmEnd += (((uint16_t)pyld[startOff + 6] << 8) | ((uint16_t)pyld[startOff + 7])); + *start = alarmStart; + *endTime = alarmEnd; - DPRINTLN(DBG_INFO, "Alarm #" + String(pyld[startOff+1]) + " '" + String(getAlarmStr(pyld[startOff+1])) + "' start: " + ah::getTimeStr(*start) + ", end: " + ah::getTimeStr(*endTime)); - return pyld[startOff+1]; + DPRINTLN(DBG_INFO, "Alarm " + String(pyld[startOff+3]) + ", #" + String(alarmCode) + " '" + String(getAlarmStr(alarmCode)) + "' start: " + ah::getTimeStr(alarmStart) + ", end: " + ah::getTimeStr(alarmEnd)); + return alarmCode; } String getAlarmStr(uint16_t alarmCode) { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index c9c911598..646111921 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -100,7 +100,8 @@ class HmPayload { iv->setValue(pos, rec, 0.0f); } } - + iv->alarmCode = 0; // design: every day a new start + rec->ts = 0; // design: every day a new start notify(RealTimeRunData_Debug); } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 2a46d5bcb..a4870fe74 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -21,7 +21,6 @@ #define ALL_FRAMES 0x80 #define SINGLE_FRAME 0x81 -#define SEND_CHANNEL_QUALITY_INTEGRATOR_SIZE 4 #define SEND_CHANNEL_MAX_QUALITY 4 #define SEND_CHANNEL_MIN_QUALITY -6 #define SEND_CHANNEL_QUALITY_GOOD 2 @@ -247,7 +246,12 @@ class HmRadio { mTxBuf[10] = cmd; // cid mTxBuf[11] = 0x00; CP_U32_LittleEndian(&mTxBuf[12], ts); - if (cmd == RealTimeRunData_Debug || cmd == AlarmData ) { + + if (cmd == AlarmData) { + // ask for last signalled alarm id only (index is one less) + if (alarmMesId) { + alarmMesId--; + } mTxBuf[18] = (alarmMesId >> 8) & 0xff; mTxBuf[19] = (alarmMesId ) & 0xff; } @@ -301,7 +305,6 @@ class HmRadio { void addSendChannelQuality (int8_t quality) { - // continous averaging // assume: mTxChIdx is still the last send channel index used quality = mChQuality[mTxChIdx] + quality; if (quality < SEND_CHANNEL_MIN_QUALITY) { diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 12c3b1c25..a92c3eefb 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -181,7 +181,7 @@ class HmSystem { day(time_today), month(time_today), year(time_today)); file = LittleFS.open (file_name, "r"); if (!file) { - DPRINT (DBG_WARN, "open_hist, failed to open "); + DPRINT (DBG_VERBOSE, "open_hist, failed to open "); // typical: during night time after midnight DBGPRINTLN (file_name); } } else { @@ -236,7 +236,7 @@ class HmSystem { *pac = get_pac_average (false); return true; } - DPRINTLN (DBG_INFO, "get_cur_value: none"); + DPRINTLN (DBG_VERBOSE, "get_cur_value: none"); return false; } diff --git a/src/plugins/SML_OBIS_Parser.cpp b/src/plugins/SML_OBIS_Parser.cpp index bbcb3eeb1..bb25eee82 100644 --- a/src/plugins/SML_OBIS_Parser.cpp +++ b/src/plugins/SML_OBIS_Parser.cpp @@ -629,15 +629,6 @@ bool sml_get_list_entries (uint16_t layer) // Also: an info_len > 2 could be due to corrupt data. So better break. uint16 len_info = (*cur_serial_buf & SML_EXT_LENGTH) ? 2 : 1; -#ifdef undef - DPRINT (DBG_INFO, "get_list_entries"); - DBGPRINT (", layer " + String (layer)); - DBGPRINT (", entries " + String (sml_list_layer_entries[layer])); - DBGPRINT (", type 0x" + String (type, HEX)); - DBGPRINT (", len_info " + String (len_info)); - DBGPRINTLN (", sml_len " + String (sml_serial_len)); -#endif - if (sml_serial_len < len_info) { if (cur_serial_buf > sml_serial_buf) { memmove (sml_serial_buf, cur_serial_buf, sml_serial_len); @@ -745,9 +736,7 @@ bool sml_get_list_entries (uint16_t layer) layer++; cur_sml_list_layer = layer; sml_list_layer_entries[layer] = entry_len; -#ifdef undef - DPRINTLN(DBG_INFO, "Open layer " + String(layer) + ", entries " + String(entry_len)); -#endif + DPRINTLN(DBG_VERBOSE, "Open layer " + String(layer) + ", entries " + String(entry_len)); if (!sml_serial_len) { error = true; } @@ -779,9 +768,7 @@ bool sml_get_list_entries (uint16_t layer) } } while (!sml_list_layer_entries[layer]) { -#ifdef undef - DPRINTLN(DBG_INFO, "COMPLETE, layer " + String (layer)); -#endif + DPRINTLN(DBG_VERBOSE, "COMPLETE, layer " + String (layer)); if (layer) { layer--; cur_sml_list_layer = layer; @@ -834,9 +821,7 @@ uint16_t sml_parse_stream (uint16 len) cur_serial_buf = sml_serial_buf; } sml_state = SML_ST_FIND_VERSION; -#ifdef undef - DPRINTLN(DBG_INFO, "START_TAG, rest " + String(sml_serial_len)); -#endif + DPRINTLN(DBG_VERBOSE, "START_TAG, rest " + String(sml_serial_len)); } else { cur_serial_buf = last_serial_buf + sml_serial_len; last_serial_buf = cur_serial_buf; @@ -861,13 +846,8 @@ uint16_t sml_parse_stream (uint16 len) sml_telegram_crc = sml_calc_crc (sml_telegram_crc, sizeof (version_seq), cur_serial_buf); sml_msg_failure = 0; sml_state = SML_ST_FIND_MSG; -#ifdef undef - DPRINTLN(DBG_INFO, "VERSION, rest " + String (sml_serial_len - sizeof (version_seq))); -#endif + DPRINTLN(DBG_VERBOSE, "VERSION, rest " + String (sml_serial_len - sizeof (version_seq))); } else { -#ifdef undef - DPRINTLN(DBG_INFO, "no VERSION, rest " + String (sml_serial_len - sizeof (version_seq))); -#endif sml_state = SML_ST_FIND_START_TAG; } sml_serial_len -= sizeof (version_seq); @@ -892,10 +872,8 @@ uint16_t sml_parse_stream (uint16 len) parse_continue = true; } else if ((*cur_serial_buf & 0x70) == 0x70) { /* todo: extended list on 1st level (does this happen in real life?) */ + DPRINTLN (DBG_VERBOSE, "TOPLIST 0x" + String(*cur_serial_buf, HEX) + ", rest " + String (sml_serial_len - 1)); sml_telegram_crc = sml_calc_crc (sml_telegram_crc, 1, cur_serial_buf); -#ifdef undef - DPRINTLN (DBG_INFO, "TOPLIST 0x" + String(*cur_serial_buf, HEX) + ", rest " + String (sml_serial_len - 1)); -#endif sml_state = SML_ST_FIND_LIST_ENTRIES; cur_sml_list_layer = 0; sml_message = SML_MSG_NONE; @@ -951,9 +929,7 @@ uint16_t sml_parse_stream (uint16 len) sml_state = SML_ST_FIND_LIST_ENTRIES; sml_list_layer_entries[cur_sml_list_layer]--; while (!sml_list_layer_entries[cur_sml_list_layer]) { -#ifdef undef - DPRINTLN(DBG_INFO, "COMPLETE, layer " + String (cur_sml_list_layer)); -#endif + DPRINTLN(DBG_VERBOSE, "COMPLETE, layer " + String (cur_sml_list_layer)); if (cur_sml_list_layer) { cur_sml_list_layer--; } else { @@ -1006,7 +982,7 @@ uint16_t sml_parse_stream (uint16 len) ", Yield in " + String (obis_yield_in_all_value) + ", Yield out " + String (obis_yield_out_all_value)); #else - DPRINTLN(DBG_INFO, "Power " + String (obis_power_all_value)); + DPRINTLN(DBG_VERBOSE, "Power " + String (obis_power_all_value)); #endif sml_handle_obis_pac (obis_power_all_value); } else { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 9305f54d2..af663b200 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -511,10 +511,19 @@ class RestApi { #ifdef AHOY_SML_OBIS_SUPPORT if (mConfig->sml_obis.ir_connected) { // design: no value of inverter but I want this value to be displayed prominently - obj[F("grid_power")] = sml_get_obis_pac (); + obj[F("grid_power")] = sml_get_obis_pac (); } #endif - + if (iv->alarmCode) { + time_t midnight = mApp->getTimestamp(); + + midnight -= midnight % 86400; + obj[F("alarm_str")] = iv->getAlarmStr(iv->alarmCode); + obj[F("alarm_start")] = String(midnight + iv->alarmStart); + if (iv->alarmEnd && (iv->alarmEnd > iv->alarmStart)) { + obj[F("alarm_end")] = String(midnight + iv->alarmEnd); + } + } JsonArray ch = obj.createNestedArray("ch"); // AC diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 991113f56..05563654b 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -186,23 +186,31 @@ ]); } - function tsInfo(ts) { - var ageInfo = "Last received data requested at: "; + function tsInfo(ts, alarm_str, alarm_start, alarm_end) { + var ageInfo = "Last received data at "; + var alarmInfo = ""; if(ts > 0) { var date = new Date(ts * 1000); - ageInfo += date.toLocaleString('de-DE'); + ageInfo += date.toLocaleTimeString('de-DE'); } - else - ageInfo += "nothing received"; - - return ml("div", {class: "mb-5"}, [ - ml("div", {class: "row p-1 ts-h mx-2"}, - ml("div", {class: "col"}, "") - ), - ml("div", {class: "row p-2 ts-bg mx-2"}, - ml("div", {class: "col mx-2"}, ageInfo) - ) - ]); + else { + ageInfo += "---"; + } + if (alarm_str !== undefined) { + var start = new Date(alarm_start * 1000); + alarmInfo += alarm_str + " at "; + alarmInfo += start.toLocaleTimeString('de-DE'); + if (alarm_end !== undefined) { + var end = new Date(alarm_end * 1000); + alarmInfo += " until "; + alarmInfo += end.toLocaleTimeString('de-DE'); + } + } + return ml("div", {class: "mb-5"}, + ml("div", {class: "row p-2 ts-bg mx-2"}, [ + ml("span", {class: "col mx-2"}, ageInfo), + ml("span", {class: "col mx-2"}, alarmInfo) + ])); } function parseIv(obj) { @@ -220,7 +228,7 @@ ml("div", {}, [ ivHead(obj), ml("div", {class: "row mb-2"}, chn), - tsInfo(obj.ts_last_success) + tsInfo(obj.ts_last_success, obj.alarm_str, obj.alarm_start, obj.alarm_end) ]) );