diff --git a/src/OpenThermTask.h b/src/OpenThermTask.h index 2b66047..9b1d72a 100644 --- a/src/OpenThermTask.h +++ b/src/OpenThermTask.h @@ -351,6 +351,35 @@ protected: // These parameters will be updated every minute if (millis() - this->prevUpdateNonEssentialVars > 60000) { + // Set date & time + if (settings.opentherm.options.setDateAndTime) { + struct tm ti; + + if (getLocalTime(&ti)) { + if (this->setYear(&ti)) { + Log.sinfoln(FPSTR(L_OT), F("Year of date set successfully")); + + } else { + Log.sinfoln(FPSTR(L_OT), F("Failed set year of date")); + } + + if (this->setDayAndMonth(&ti)) { + Log.sinfoln(FPSTR(L_OT), F("Day and month of date set successfully")); + + } else { + Log.sinfoln(FPSTR(L_OT), F("Failed set day and month of date")); + } + + if (this->setTime(&ti)) { + Log.sinfoln(FPSTR(L_OT), F("Time set successfully")); + + } else { + Log.sinfoln(FPSTR(L_OT), F("Failed set time")); + } + } + } + + // Get min modulation level & max power if (this->updateMinModulationLevel()) { Log.snoticeln( FPSTR(L_OT), F("Received min modulation: %hhu%%, max power: %.2f kW"), @@ -1370,6 +1399,65 @@ protected: return true; } + bool setYear(const struct tm *ptm) { + const unsigned int request = (ptm->tm_year + 1900) & 0xFFFF; + const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest( + OpenThermRequestType::WRITE_DATA, + OpenThermMessageID::Year, + request + )); + + if (!CustomOpenTherm::isValidResponse(response)) { + return false; + + } else if (!CustomOpenTherm::isValidResponseId(response, OpenThermMessageID::Year)) { + return false; + } + + return CustomOpenTherm::getUInt(response) == request; + } + + bool setDayAndMonth(const struct tm *ptm) { + const unsigned int request = ((ptm->tm_mon + 1) & 0xFF << 8) + | (ptm->tm_mday & 0xFF); + + const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest( + OpenThermRequestType::WRITE_DATA, + OpenThermMessageID::Date, + request + )); + + if (!CustomOpenTherm::isValidResponse(response)) { + return false; + + } else if (!CustomOpenTherm::isValidResponseId(response, OpenThermMessageID::Date)) { + return false; + } + + return CustomOpenTherm::getUInt(response) == request; + } + + bool setTime(const struct tm *ptm) { + const uint8_t dayOfWeek = ptm->tm_wday == 0 ? 6 : ptm->tm_wday - 1; + const unsigned int request = ((dayOfWeek & 0x07) << 13) + | ((ptm->tm_hour & 0x1F) << 8) + | (ptm->tm_min & 0x3F); + + const unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest( + OpenThermRequestType::WRITE_DATA, + OpenThermMessageID::DayTime, + request + )); + + if (!CustomOpenTherm::isValidResponse(response)) { + return false; + + } else if (!CustomOpenTherm::isValidResponseId(response, OpenThermMessageID::DayTime)) { + return false; + } + + return CustomOpenTherm::getUInt(response) == request; + } bool setMaxModulationLevel(const uint8_t value) { const unsigned int request = CustomOpenTherm::toFloat(value); diff --git a/src/Settings.h b/src/Settings.h index 3b204db..f939fbf 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -76,6 +76,7 @@ struct Settings { bool ignoreDiagState = false; bool autoFaultReset = false; bool autoDiagReset = false; + bool setDateAndTime = false; bool nativeHeatingControl = false; bool immergasFix = false; } options; diff --git a/src/strings.h b/src/strings.h index 641a906..cd0c96b 100644 --- a/src/strings.h +++ b/src/strings.h @@ -175,6 +175,7 @@ const char S_SENSORS[] PROGMEM = "sensors"; const char S_SERIAL[] PROGMEM = "serial"; const char S_SERVER[] PROGMEM = "server"; const char S_SETTINGS[] PROGMEM = "settings"; +const char S_SET_DATE_AND_TIME[] PROGMEM = "setDateAndTime"; const char S_SIGNAL_QUALITY[] PROGMEM = "signalQuality"; const char S_SIZE[] PROGMEM = "size"; const char S_SLAVE[] PROGMEM = "slave"; diff --git a/src/utils.h b/src/utils.h index d87c640..614dd3b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -466,6 +466,7 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { otOptions[FPSTR(S_IGNORE_DIAG_STATE)] = src.opentherm.options.ignoreDiagState; otOptions[FPSTR(S_AUTO_FAULT_RESET)] = src.opentherm.options.autoFaultReset; otOptions[FPSTR(S_AUTO_DIAG_RESET)] = src.opentherm.options.autoDiagReset; + otOptions[FPSTR(S_SET_DATE_AND_TIME)] = src.opentherm.options.setDateAndTime; otOptions[FPSTR(S_NATIVE_HEATING_CONTROL)] = src.opentherm.options.nativeHeatingControl; otOptions[FPSTR(S_IMMERGAS_FIX)] = src.opentherm.options.immergasFix; @@ -967,6 +968,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_SET_DATE_AND_TIME)].is()) { + bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_SET_DATE_AND_TIME)].as(); + + if (value != dst.opentherm.options.setDateAndTime) { + dst.opentherm.options.setDateAndTime = value; + changed = true; + } + } + if (src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_HEATING_CONTROL)].is()) { bool value = src[FPSTR(S_OPENTHERM)][FPSTR(S_OPTIONS)][FPSTR(S_NATIVE_HEATING_CONTROL)].as(); diff --git a/src_data/locales/en.json b/src_data/locales/en.json index 2c355ef..44785f1 100644 --- a/src_data/locales/en.json +++ b/src_data/locales/en.json @@ -409,6 +409,7 @@ "ignoreDiagState": "Ignore diag state", "autoFaultReset": "Auto fault reset (not recommended!)", "autoDiagReset": "Auto diag reset (not recommended!)", + "setDateAndTime": "Set date & time on boiler", "immergasFix": "Fix for Immergas boilers" }, diff --git a/src_data/locales/it.json b/src_data/locales/it.json index db7ffa8..72455f2 100644 --- a/src_data/locales/it.json +++ b/src_data/locales/it.json @@ -409,6 +409,7 @@ "ignoreDiagState": "Ignora lo stato diagnostico", "autoFaultReset": "Ripristino automatico degli errori (sconsigliato!)", "autoDiagReset": "Ripristino diagnostico automatica (sconsigliato!)", + "setDateAndTime": "Imposta data e ora sulla caldaia", "immergasFix": "Fix per caldiaie Immergas" }, diff --git a/src_data/locales/ru.json b/src_data/locales/ru.json index bdb946c..40aa7f1 100644 --- a/src_data/locales/ru.json +++ b/src_data/locales/ru.json @@ -409,6 +409,7 @@ "ignoreDiagState": "Игнорировать состояние диагностики", "autoFaultReset": "Автоматический сброс ошибок (не рекомендуется!)", "autoDiagReset": "Автоматический сброс диагностики (не рекомендуется!)", + "setDateAndTime": "Устанавливать время и дату на котле", "immergasFix": "Фикс для котлов Immergas" }, diff --git a/src_data/pages/settings.html b/src_data/pages/settings.html index 3df4da0..a1eccb5 100644 --- a/src_data/pages/settings.html +++ b/src_data/pages/settings.html @@ -551,6 +551,11 @@ settings.ot.options.autoDiagReset + +