emsesp / EMS-ESP32

ESP32 firmware to read and control EMS and Heatronic compatible equipment such as boilers, thermostats, solar modules, and heat pumps
https://emsesp.github.io/docs
GNU Lesser General Public License v3.0
542 stars 96 forks source link

NTP synchronization to thermostat panel #386

Closed sq4bja closed 2 years ago

sq4bja commented 2 years ago

Is it possible for ems-esp to automatically update the time in a thermostat, eg RC310? Manual update via SSH or JSON works fine, but can it be turned on automatically?

MichaelDvP commented 2 years ago

When reading the thermostat clock (telegram 0x06) there are bits for invalid date or time, set after a longer powercut and empty buffer battery. If time is marked as invalid and there is valid ntp time, the clock is set automatially. I've never tested it, the last long powercut stopped my heating and this was the reason to implement this automatic.

But i think you mean something different like periodical setting, or checking on every time telegram and adjust if thermostat time is a minute apart.

proddy commented 2 years ago

I think via a command, so calling /api/thermostat/setclock would take the current NTP time and apply it (if NTP is enabled, and there is a valid time and the thermostat supports it).

MichaelDvP commented 2 years ago

That's /api/thermostat/datetime with payload {"value":"ntp"}. Working for RC35 and RC300.

proddy commented 2 years ago

bingo. then @sq4bja does that work? If you're using HA you can create a trigger or a scheduled job.

MichaelDvP commented 2 years ago

I've tested a automatic correction if time is more than 1 minute apart. In process_RCTime added

    // check clock
    time_t now = time(nullptr);
    tm *   tm_ = localtime(&now);
    if (tm_->tm_year < 110) { // no NTP time
        return;
    }
    if ((tm_->tm_year - 100) != (telegram->message_data[0] & 0x7F) || tm_->tm_mon + 1 != telegram->message_data[1] || tm_->tm_mday != telegram->message_data[3]
        || tm_->tm_hour != telegram->message_data[2] || (tm_->tm_min + 1) < telegram->message_data[4] || tm_->tm_min > (telegram->message_data[4] + 1)) {
        set_datetime("ntp", -1); // set from NTP
        LOG_INFO(F("time correction from ntp"));
    }

I manually set time wrong and get the time correction message in log. Heating is a slow process, a minute does not really matter and my clock is only a few seconds a year apart. I'm now waiting for the dst-switching and see what happens.

sq4bja commented 2 years ago

Yes, that's exactly what I meant. Time is not so important to heating, but the thermostat is often used as a wall clock. In my case of the RC310, the time difference is one minute per 2 months, so such a code modification would help a lot. I know that I can trigger the time correction as an external event, eg dzVents in Domoticz, but I think that it should be done independently of external software. The idea that the update should be 1 minute difference between the thermostat time and the NTP time is very good, however I think it would be more correct to update the time every 24 hours of uptime. Regardless of your decision, any solution will be of great help.

MichaelDvP commented 2 years ago

I think for scheduled update of the clock it is better to do this from external homeautomation (homeassistant/domotics/ioBroker/...). My first approach for automatic correction need some improvments. The clock publishing on the bus can be delayed 1 or 2 seconds, giving me a lot of corrections in clock publishing is near full minute. Also we have a lot of thermostats with not writable clock, this will flood the log with correction messages. Next approach with correction on 15 sec difference:

    // check clock
    time_t now = time(nullptr);
    tm *   tm_ = localtime(&now);
    if (tm_->tm_year < 110 || !has_command(&dateTime_)) { // no NTP time or no command
        return;
    }
    tm_->tm_year      = telegram->message_data[0] + 100;
    tm_->tm_mon       = telegram->message_data[1] - 1;
    tm_->tm_mday      = telegram->message_data[3];
    tm_->tm_hour      = telegram->message_data[2];
    tm_->tm_min       = telegram->message_data[4];
    tm_->tm_sec       = telegram->message_data[5];
    tm_->tm_isdst     = telegram->message_data[7] & 0x01;
    double difference = difftime(now, mktime(tm_));
    if (difference > 15 || difference < -15) {
        set_datetime("ntp", -1); // set from NTP
        LOG_INFO(F("time correction from ntp"));
    }

(with new function EMSdevice::has_command(const void * p_value))

MichaelDvP commented 2 years ago

This should work now in both directions. NTP received, -> thermostat syncs if 15 sec apart NTP not received, but esp clock set -> thermostat is set only if thermostat clock is invalid NTP not received, esp clock not set, thermostat clock set -> esp syncs to thermostat time Command datetime ntp sent, NTP not connected, but esp clock set -> thermostat is synced, but logs a warning. @sq4bja Close this issue?