From 51e52846f07f52ff50bdd331426887d3ed25847e Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Thu, 2 Jul 2020 16:46:41 +0200 Subject: [PATCH 1/5] mode settings, RC35 temperature factor, UART modes --- src/devices/thermostat.cpp | 58 ++++++++-------- src/emsesp.cpp | 21 ++++-- src/telegram.h | 4 +- src/uart/emsuart_esp32.cpp | 131 ++++++++++++----------------------- src/uart/emsuart_esp32.h | 7 +- src/uart/emsuart_esp8266.cpp | 98 +++++++++++++------------- src/version.h | 2 +- 7 files changed, 144 insertions(+), 177 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index a8f158db2..bbbba6a1a 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -304,7 +304,7 @@ void Thermostat::thermostat_cmd(const char * message) { } if (nullptr != doc["building"]) { std::string bds = doc["building"]; - uint8_t bd = doc["building"]; + uint8_t bd = doc["building"]; if (strcmp(bds.c_str(), "light") == 0) { bd = 0; } else if (strcmp(bds.c_str(), "medium") == 0) { @@ -821,21 +821,21 @@ uint8_t Thermostat::HeatingCircuit::get_mode_type(uint8_t flags) const { if (flags == EMS_DEVICE_FLAG_JUNKERS) { if (mode_type == 3) { return HeatingCircuit::Mode::HEAT; - } else if (mode == 2) { + } else if (mode_type == 2) { return HeatingCircuit::Mode::ECO; - } else if (mode == 1) { + } else if (mode_type == 1) { return HeatingCircuit::Mode::NOFROST; } } else if ((flags == EMS_DEVICE_FLAG_RC35) || (flags == EMS_DEVICE_FLAG_RC30_1)) { if (mode_type == 0) { return HeatingCircuit::Mode::NIGHT; - } else if (mode == 1) { + } else if (mode_type == 1) { return HeatingCircuit::Mode::DAY; } } else if (flags == EMS_DEVICE_FLAG_RC300) { if (mode_type == 0) { return HeatingCircuit::Mode::ECO; - } else if (mode == 1) { + } else if (mode_type == 1) { return HeatingCircuit::Mode::COMFORT; } } else if (flags == EMS_DEVICE_FLAG_RC100) { @@ -1012,7 +1012,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) { - shell.printfln(F(" Program is set to Summer mode")); + shell.printfln(F(" Program is set to Summer mode")); } else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) { shell.printfln(F(" Program is set to Holiday mode")); } @@ -1146,8 +1146,8 @@ void Thermostat::process_JunkersMonitor(std::shared_ptr telegram telegram->read_value(hc->curr_roomTemp, 4); // value is * 10 telegram->read_value(hc->setpoint_roomTemp, 2); // value is * 10 - telegram->read_value(hc->mode_type, 0); // 1 = nofrost, 2 = eco, 3 = heat - telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto + telegram->read_value(hc->mode_type, 0); // 1 = nofrost, 2 = eco, 3 = heat + telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto } // type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 @@ -1356,13 +1356,13 @@ void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) { // sets the thermostat ww working mode, where mode is a string void Thermostat::set_ww_mode(const std::string & mode) { - if (strcasecmp("off",mode.c_str()) == 0) { + if (strcasecmp("off", mode.c_str()) == 0) { LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str()); write_command(EMS_TYPE_wwSettings, 2, 0); - } else if (strcasecmp("on",mode.c_str()) == 0) { + } else if (strcasecmp("on", mode.c_str()) == 0) { LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str()); write_command(EMS_TYPE_wwSettings, 2, 1); - } else if (strcasecmp("auto",mode.c_str()) == 0) { + } else if (strcasecmp("auto", mode.c_str()) == 0) { LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str()); write_command(EMS_TYPE_wwSettings, 2, 2); } else { @@ -1388,8 +1388,8 @@ void Thermostat::set_mode(const std::string & mode, const uint8_t hc_num) { set_mode(HeatingCircuit::Mode::NOFROST, hc_num); } else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) { set_mode(HeatingCircuit::Mode::ECO, hc_num); - } else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) { - set_mode(HeatingCircuit::Mode::HOLIDAY, hc_num); + // } else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) { + // set_mode(HeatingCircuit::Mode::HOLIDAY, hc_num); } else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) { set_mode(HeatingCircuit::Mode::COMFORT, hc_num); } else { @@ -1413,7 +1413,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) { uint8_t set_mode_value, offset; uint16_t validate_typeid = 0; - uint8_t hc_p = hc->hc_num(); + uint8_t hc_p = hc->hc_num() - 1; // set the value to send via EMS depending on the mode type switch (mode) { @@ -1431,7 +1431,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) { default: case HeatingCircuit::Mode::AUTO: - case HeatingCircuit::Mode::HOLIDAY: + // case HeatingCircuit::Mode::HOLIDAY: case HeatingCircuit::Mode::ECO: set_mode_value = 2; break; @@ -1453,7 +1453,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) { case EMSdevice::EMS_DEVICE_FLAG_RC35: case EMSdevice::EMS_DEVICE_FLAG_RC30_1: offset = EMS_OFFSET_RC35Set_mode; - validate_typeid = set_typeids[hc_p]; + validate_typeid = monitor_typeids[hc_p]; break; case EMSdevice::EMS_DEVICE_FLAG_RC300: case EMSdevice::EMS_DEVICE_FLAG_RC100: @@ -1491,7 +1491,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) { // add the write command to the Tx queue // post validate is the corresponding monitor or set type IDs as they can differ per model - write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid); + write_command(set_typeids[hc_p], offset, set_mode_value, validate_typeid); } // sets the thermostat temp, where mode is a string @@ -1539,6 +1539,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co uint8_t model = flags() & 0x0F; int8_t offset = -1; // we use -1 to check if there is a value + uint8_t factor = 2; // some temperatures only use 1 if (model == EMS_DEVICE_FLAG_RC10) { offset = EMS_OFFSET_RC10Set_temp; @@ -1584,12 +1585,15 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co break; case HeatingCircuit::Mode::DESIGN: offset = EMS_OFFSET_RC35Set_temp_design; + factor = 1; break; case HeatingCircuit::Mode::SUMMER: offset = EMS_OFFSET_RC35Set_temp_summer; + factor = 1; break; case HeatingCircuit::Mode::NOFROST: offset = EMS_OFFSET_RC35Set_temp_nofrost; + factor = 1; break; default: case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code @@ -1629,7 +1633,8 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co default: case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code uint8_t mode_type = hc->get_mode_type(flags()); - offset = (mode_type == HeatingCircuit::Mode::NIGHT || mode_type == HeatingCircuit::Mode::ECO) ? EMS_OFFSET_JunkersSetMessage_night_temp : EMS_OFFSET_JunkersSetMessage_day_temp; + offset = (mode_type == HeatingCircuit::Mode::NIGHT || mode_type == HeatingCircuit::Mode::ECO) ? EMS_OFFSET_JunkersSetMessage_night_temp + : EMS_OFFSET_JunkersSetMessage_day_temp; break; } @@ -1661,9 +1666,8 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co mode_tostring(mode).c_str()); // add the write command to the Tx queue - // value is *2 // post validate is the corresponding monitor type_id - write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)2), monitor_typeids[hc->hc_num() - 1]); + write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), monitor_typeids[hc->hc_num() - 1]); } } @@ -1720,7 +1724,7 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) { flash_string_vector{F_(change), F_(mode)}, flash_string_vector{F_(mode_mandatory), F_(hc_optional)}, [=](Shell & shell __attribute__((unused)), const std::vector & arguments) { - uint8_t hc = (arguments.size() == 2) ? arguments[1].at(0) - '0' : DEFAULT_HEATING_CIRCUIT; + uint8_t hc = (arguments.size() == 2) ? arguments[1].at(0) - '0' : AUTO_HEATING_CIRCUIT; set_mode(arguments.front(), hc); }, [](Shell & shell __attribute__((unused)), const std::vector & arguments __attribute__((unused))) -> const std::vector { @@ -1731,7 +1735,7 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) { read_flash_string(F("eco")), read_flash_string(F("comfort")), read_flash_string(F("heat")), - read_flash_string(F("holiday")), + // read_flash_string(F("holiday")), read_flash_string(F("nofrost")), read_flash_string(F("auto")) @@ -1743,14 +1747,10 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) { CommandFlags::ADMIN, flash_string_vector{F_(change), F_(wwmode)}, flash_string_vector{F_(mode_mandatory)}, - [=](Shell & shell __attribute__((unused)), const std::vector & arguments) { - set_ww_mode(arguments.front()); - }, + [=](Shell & shell __attribute__((unused)), const std::vector & arguments) { set_ww_mode(arguments.front()); }, [](Shell & shell __attribute__((unused)), const std::vector & arguments __attribute__((unused))) -> const std::vector { - return std::vector{read_flash_string(F("off")), - read_flash_string(F("on")), - read_flash_string(F("auto")) - + return std::vector{read_flash_string(F("off")), read_flash_string(F("on")), read_flash_string(F("auto")) + }; }); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 7a56927b5..aa209fa8e 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -585,7 +585,7 @@ void EMSESP::send_write_request(const uint16_t type_id, // the CRC check is not done here, only when it's added to the Rx queue with add() void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { #ifdef EMSESP_DEBUG - static uint32_t tx_time_ = 0; + static uint32_t rx_time_ = 0; #endif // check first for echo uint8_t first_value = data[0]; @@ -593,8 +593,7 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { // if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20 Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); #ifdef EMSESP_DEBUG - // get_uptime is only updated once per loop, does not give the right time - LOG_DEBUG(F("[DEBUG] Echo after %d ms: %s"), ::millis() - tx_time_, Helpers::data_to_hex(data, length).c_str()); + LOG_TRACE(F("[DEBUG] Echo after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str()); #endif return; // it's an echo } @@ -642,19 +641,29 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) { // check for poll if (length == 1) { +#ifdef EMSESP_DEBUG + char s[4]; + if(first_value & 0x80) { + LOG_TRACE(F("[DEBUG] next Poll %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_); + // time measurement starts here, use millis because get_uptime is only updated once per loop + rx_time_ = ::millis(); + } else { + LOG_TRACE(F("[DEBUG] Poll ack %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_); + } +#endif // check for poll to us, if so send top message from Tx queue immediately and quit // if ht3 poll must be ems_bus_id else if Buderus poll must be (ems_bus_id | 0x80) if ((first_value ^ 0x80 ^ rxservice_.ems_mask()) == txservice_.ems_bus_id()) { EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active -#ifdef EMSESP_DEBUG - tx_time_ = ::millis(); // get_uptime is only updated once per loop, does not give the right time -#endif txservice_.send(); } // send remote room temperature if active Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask()); return; } else { +#ifdef EMSESP_DEBUG + LOG_TRACE(F("[DEBUG] Reply after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str()); +#endif // check if there is a message for the roomcontroller Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); // add to RxQueue, what ever it is. diff --git a/src/telegram.h b/src/telegram.h index 249e18603..e42c42ca1 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -88,7 +88,7 @@ class Telegram { // reads a bit value from a given telegram position void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const { uint8_t abs_index = (index - offset); - if (abs_index >= message_length) { + if (abs_index >= message_length - 1) { return; // out of bounds } @@ -104,7 +104,7 @@ class Telegram { // s is to override number of bytes read (e.g. use 3 to simulat a uint24_t) void read_value(Value & value, const uint8_t index, uint8_t s = 0) const { uint8_t size = (!s) ? sizeof(Value) : s; - int8_t abs_index = ((index - offset + size - 1) >= message_length) ? -1 : (index - offset); + int8_t abs_index = ((index - offset + size - 1) >= message_length - 1) ? -1 : (index - offset); if (abs_index < 0) { return; // out of bounds, we don't change the value } diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index 580ea3ac7..d31e173e7 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -61,20 +61,9 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { static uint8_t rxbuf[EMS_MAXBUFFERSIZE]; static uint8_t length; - if (EMS_UART.int_st.rxfifo_full) { - EMS_UART.int_clr.rxfifo_full = 1; - emsTxBufIdx++; - if (emsTxBufIdx < emsTxBufLen) { - EMS_UART.conf1.rxfifo_full_thrhd = emsTxBufIdx + 1; - EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; - } else if (emsTxBufIdx == emsTxBufLen) { - EMS_UART.conf0.txd_brk = 1; // after send - EMS_UART.int_ena.rxfifo_full = 0; - EMS_UART.conf1.rxfifo_full_thrhd = 0x7F; - } - } if (EMS_UART.int_st.brk_det) { EMS_UART.int_clr.brk_det = 1; // clear flag + EMS_UART.conf0.txd_brk = 0; // disable if (emsTxBufIdx < emsTxBufLen) { // timer tx_mode is interrupted by emsTxBufIdx = emsTxBufLen; // stop timer mode drop_next_rx = true; // we have trash in buffer @@ -98,26 +87,32 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { - if (emsTxBufIdx > EMS_MAXBUFFERSIZE) { - return; - } - - emsTxBufIdx++; - - if (emsTxBufIdx < emsTxBufLen) { - EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; - timerAlarmWrite(timer, emsTxWait, false); - timerAlarmEnable(timer); - } else if (emsTxBufIdx == emsTxBufLen) { + if(tx_mode_ > 50) { + for (uint8_t i = 0; i< emsTxBufLen, i++) { + EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; + } EMS_UART.conf0.txd_brk = 1; // after send + timerAlarmDisable(timer); + } else { + if (emsTxBufIdx < emsTxBufLen) { + EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; + } else if (emsTxBufIdx == emsTxBufLen) { + EMS_UART.conf0.txd_brk = 1; // after send + timerAlarmDisable(timer); + } + emsTxBufIdx++; } } /* * init UART driver */ -void EMSuart::start(uint8_t tx_mode) { - emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode + 10); +void EMSuart::start(const uint8_t tx_mode) { + if(tx_mode > 50) { + emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode - 50); + } else if (tx_mode > 5) { + emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode + 10); + } if (tx_mode_ != 0xFF) { // uart already initialized tx_mode_ = tx_mode; restart(); @@ -137,12 +132,13 @@ void EMSuart::start(uint8_t tx_mode) { EMS_UART.int_ena.val = 0; // disable all intr. EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit - EMS_UART.idle_conf.rx_idle_thrhd = 256; + // EMS_UART.idle_conf.rx_idle_thrhd = 0; drop_next_rx = true; buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL); EMS_UART.int_ena.brk_det = 1; // activate only break + // EMS_UART.int_ena.frm_err = 1; emsTxBufIdx = 0; emsTxBufLen = 0; @@ -174,44 +170,18 @@ void EMSuart::restart() { /* * Sends a 1-byte poll, ending with a */ -void EMSuart::send_poll(uint8_t data) { - // if (tx_mode_ >= 6 || tx_mode_ < 4) { // modes 1, 2, 3 also here - if (tx_mode_ >= 5) { - EMS_UART.fifo.rw_byte = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - timerAlarmWrite(timer, emsTxWait, false); - timerAlarmEnable(timer); - } else if (tx_mode_ == 5) { - EMS_UART.fifo.rw_byte = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - EMS_UART.conf1.rxfifo_full_thrhd = 1; - EMS_UART.int_ena.rxfifo_full = 1; - } else if (tx_mode_ == EMS_TXMODE_NEW) { - EMS_UART.fifo.rw_byte = data; - EMS_UART.conf0.txd_brk = 1; // after send - } else if (tx_mode_ == EMS_TXMODE_HT3) { - EMS_UART.fifo.rw_byte = data; - delayMicroseconds(EMSUART_TX_WAIT_HT3); - EMS_UART.conf0.txd_brk = 1; // - // delayMicroseconds(EMSUART_TX_WAIT_BRK); - // EMS_UART.conf0.txd_brk = 0; - } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { - EMS_UART.fifo.rw_byte = data; +void EMSuart::send_poll(const uint8_t data) { + EMS_UART.conf0.txd_brk = 0; + EMS_UART.fifo.rw_byte = data; + if (tx_mode_ == EMS_TXMODE_EMSPLUS) { delayMicroseconds(EMSUART_TX_WAIT_PLUS); - EMS_UART.conf0.txd_brk = 1; // - // delayMicroseconds(EMSUART_TX_WAIT_BRK); - // EMS_UART.conf0.txd_brk = 0; - } else { - volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; - EMS_UART.fifo.rw_byte = data; - uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; - while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) { - delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... - } - EMS_UART.conf0.txd_brk = 1; // + } else if (tx_mode_ == EMS_TXMODE_HT3) { + delayMicroseconds(EMSUART_TX_WAIT_HT3); + } else if (tx_mode_ == 1) { + delayMicroseconds(EMSUART_TX_WAIT_BRK); } + EMS_UART.conf0.txd_brk = 1; // after send + return; } /* @@ -219,36 +189,32 @@ void EMSuart::send_poll(uint8_t data) { * buf contains the CRC and len is #bytes including the CRC * returns code, 1=success */ -uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { +uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) { return EMS_TX_STATUS_ERR; } + // needs to be disabled for the delayed modes otherwise the uart makes a after every byte + EMS_UART.conf0.txd_brk = 0; - // if (tx_mode_ >= 6 || tx_mode_ < 4) { // timer controlled modes, also modes 1, 2, 3 because delays not working - if (tx_mode_ >= 5) { // timer controlled modes + if (tx_mode_ > 5) { // timer controlled modes for (uint8_t i = 0; i < len; i++) { emsTxBuf[i] = buf[i]; } - EMS_UART.fifo.rw_byte = buf[0]; - emsTxBufIdx = 0; - emsTxBufLen = len; - timerAlarmWrite(timer, emsTxWait, false); + emsTxBufIdx = 0; + emsTxBufLen = len; + timerAlarmWrite(timer, emsTxWait, true); timerAlarmEnable(timer); return EMS_TX_STATUS_OK; } - if (tx_mode_ == 5) { + if (tx_mode_ == 5) { // wait before sending + vTaskDelay(3 / portTICK_PERIOD_MS); for (uint8_t i = 0; i < len; i++) { - emsTxBuf[i] = buf[i]; + EMS_UART.fifo.rw_byte = buf[i]; } - EMS_UART.fifo.rw_byte = buf[0]; - emsTxBufIdx = 0; - emsTxBufLen = len; - EMS_UART.conf1.rxfifo_full_thrhd = 1; - EMS_UART.int_ena.rxfifo_full = 1; + EMS_UART.conf0.txd_brk = 1; // after send return EMS_TX_STATUS_OK; } - if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes for (uint8_t i = 0; i < len; i++) { EMS_UART.fifo.rw_byte = buf[i]; @@ -263,19 +229,16 @@ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { delayMicroseconds(EMSUART_TX_WAIT_PLUS); } EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send - // delayMicroseconds(EMSUART_TX_WAIT_BRK); - // EMS_UART.conf0.txd_brk = 0; return EMS_TX_STATUS_OK; } if (tx_mode_ == EMS_TXMODE_HT3) { // HT3 with 7 bittimes delay - for (uint8_t i = 0; i < len; i++) { + for (uint8_t i = 0; i < len - 1; i++) { EMS_UART.fifo.rw_byte = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_HT3); } + EMS_UART.fifo.rw_byte = buf[len - 1]; EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send - // delayMicroseconds(EMSUART_TX_WAIT_BRK); - // EMS_UART.conf0.txd_brk = 0; return EMS_TX_STATUS_OK; } @@ -288,12 +251,10 @@ uint16_t EMSuart::transmit(uint8_t * buf, uint8_t len) { EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) { - delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... + delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send - // delayMicroseconds(EMSUART_TX_WAIT_BRK); - // EMS_UART.conf0.txd_brk = 0; return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index b1528ef3c..7ec8c4e1e 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -32,6 +32,7 @@ #include "freertos/ringbuf.h" #include "freertos/queue.h" #include +#include #define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK @@ -79,11 +80,11 @@ class EMSuart { EMSuart() = default; ~EMSuart() = default; - static void start(uint8_t tx_mode); - static void send_poll(uint8_t data); + static void start(const uint8_t tx_mode); + static void send_poll(const uint8_t data); static void stop(); static void restart(); - static uint16_t transmit(uint8_t * buf, uint8_t len); + static uint16_t transmit(const uint8_t * buf, const uint8_t len); private: static void emsuart_recvTask(void * para); diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index a2f7dfc6f..947d60f05 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -44,18 +44,6 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { static uint8_t length = 0; static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2]; - if (USIS(EMSUART_UART) & ((1 << UIFF))) { // Fifo full, sending in Mode 5 - USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo interrupt - emsTxBufIdx++; - if (emsTxBufIdx < emsTxBufLen) { - USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; // send next byte - USC1(EMSUART_UART) = ((emsTxBufIdx + 1) << UCFFT); // increase fifo full - } else if (emsTxBufIdx == emsTxBufLen) { - USC0(EMSUART_UART) |= (1 << UCBRK); // set - USIE(EMSUART_UART) &= ~(1 << UIFF); // disable fifo-full irq - USC1(EMSUART_UART) = (0x7F << UCFFT); // fifo full to max - } - } if (USIS(EMSUART_UART) & ((1 << UIBD))) { // BREAK detection = End of EMS data block USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset tx-brk if (emsTxBufIdx < emsTxBufLen) { // irq tx_mode is interrupted by @@ -110,15 +98,22 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { // ISR to Fire when Timer is triggered void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { - if (emsTxBufIdx > EMS_MAXBUFFERSIZE) { - return; - } - emsTxBufIdx++; - if (emsTxBufIdx < emsTxBufLen) { - USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; - timer1_write(emsTxWait); - } else if (emsTxBufIdx == emsTxBufLen) { + if ( tx_mode_ > 50) { + for (uint8_t i = 0; i < emsTxBufLen; i++) { + USF(EMSUART_UART) = emsTxBuf[i]; + } USC0(EMSUART_UART) |= (1 << UCBRK); // set + } else { + if (emsTxBufIdx > emsTxBufLen) { + return; + } + if (emsTxBufIdx < emsTxBufLen) { + USF(EMSUART_UART) = emsTxBuf[emsTxBufIdx]; + timer1_write(emsTxWait); + } else if (emsTxBufIdx == emsTxBufLen) { + USC0(EMSUART_UART) |= (1 << UCBRK); // set + } + emsTxBufIdx++; } } @@ -126,8 +121,10 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { * init UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { - if (tx_mode >= 5) { - emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes for tx_mode + if (tx_mode > 50) { + emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode - 50); // bittimes wait before sending + } else if (tx_mode > 5) { + emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait between bytes } if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart tx_mode_ = tx_mode; @@ -222,12 +219,6 @@ void ICACHE_FLASH_ATTR EMSuart::restart() { emsTxBufIdx = 0; emsTxBufLen = 0; timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); - if (tx_mode_ == 5) { - USC0(EMSUART_UART) = 0x2C; // 8N1.5 - } else { - USC0(EMSUART_UART) = EMSUART_CONFIG; // 8N1 - } - } /* @@ -260,21 +251,22 @@ void EMSuart::send_poll(uint8_t data) { USC0(EMSUART_UART) &= ~(1 << UCBRK); sending_ = true; - if (tx_mode_ > 5) { // timer controlled modes - USF(EMSUART_UART) = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; + if (tx_mode_ > 50) { // timer controlled modes + emsTxBuf[0] = data; + emsTxBufLen = 1; timer1_write(emsTxWait); - } else if (tx_mode_ == 5) { // reload sendbuffer in irq - USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo-full irq - USC1(EMSUART_UART) = (0x01 << UCFFT); // fifo full to 1 - USF(EMSUART_UART) = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - USIE(EMSUART_UART) |= (1 << UIFF); // enable fifo-full irq + } else if (tx_mode_ > 5) { // timer controlled modes + emsTxBuf[0] = data; + emsTxBufIdx = 0; + emsTxBufLen = 1; + timer1_write(emsTxWait); + }else if (tx_mode_ == 5) { + delayMicroseconds(3000); + USF(EMSUART_UART) = data; + USC0(EMSUART_UART) |= (1 << UCBRK); } else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes USF(EMSUART_UART) = data; - USC0(EMSUART_UART) |= (1 << UCBRK); // brk after sendout + USC0(EMSUART_UART) |= (1 << UCBRK); } else if (tx_mode_ == EMS_TXMODE_HT3) { USF(EMSUART_UART) = data; delayMicroseconds(EMSUART_TX_WAIT_HT3); @@ -316,28 +308,32 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { USC0(EMSUART_UART) &= ~(1 << UCBRK); sending_ = true; + // all at once after a inititial timer delay + if (tx_mode_ > 50) { + for (uint8_t i = 0; i < len; i++) { + emsTxBuf[i] = buf[i]; + } + emsTxBufLen = len; + timer1_write(emsTxWait); + return EMS_TX_STATUS_OK; + } // timer controlled modes with extra delay if (tx_mode_ > 5) { for (uint8_t i = 0; i < len; i++) { emsTxBuf[i] = buf[i]; } - emsTxBufIdx = 0; - emsTxBufLen = len; - USF(EMSUART_UART) = buf[0]; + emsTxBufIdx = 0; + emsTxBufLen = len; timer1_write(emsTxWait); return EMS_TX_STATUS_OK; } - // interrupt controlled mode: readback in rx-irq and send next byte + // fixed dealy before sending if (tx_mode_ == 5) { + delayMicroseconds(3000); for (uint8_t i = 0; i < len; i++) { - emsTxBuf[i] = buf[i]; + USF(EMSUART_UART) = buf[i]; } - USIC(EMSUART_UART) |= (1 << UIFF); // clear fifo-full irq - emsTxBufIdx = 0; - emsTxBufLen = len; - USC1(EMSUART_UART) = (0x01 << UCFFT); // fifo full to 1 - USIE(EMSUART_UART) |= (1 << UIFF); // enable fifo-full irq - USF(EMSUART_UART) = buf[0]; + USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end return EMS_TX_STATUS_OK; } diff --git a/src/version.h b/src/version.h index 96124d601..36bec20b1 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "2.0.0a30" +#define EMSESP_APP_VERSION "2.0.0a31" From d9fd27c22b55c1f248e4f18c0f92e0193f621ea4 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 3 Jul 2020 10:32:10 +0200 Subject: [PATCH 2/5] esp32 uart tx-modes working --- src/uart/emsuart_esp32.cpp | 65 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index d31e173e7..3cea6bfb7 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -87,18 +87,22 @@ void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) { void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { + if(emsTxBufLen == 0) { + return; + } if(tx_mode_ > 50) { - for (uint8_t i = 0; i< emsTxBufLen, i++) { - EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; + for (uint8_t i = 0; i < emsTxBufLen; i++) { + EMS_UART.fifo.rw_byte = emsTxBuf[i]; } EMS_UART.conf0.txd_brk = 1; // after send - timerAlarmDisable(timer); } else { - if (emsTxBufIdx < emsTxBufLen) { + if (emsTxBufIdx + 1 < emsTxBufLen) { + EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; + timerAlarmWrite(timer, emsTxWait, false); + timerAlarmEnable(timer); + } else if (emsTxBufIdx + 1 == emsTxBufLen) { EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; - } else if (emsTxBufIdx == emsTxBufLen) { EMS_UART.conf0.txd_brk = 1; // after send - timerAlarmDisable(timer); } emsTxBufIdx++; } @@ -108,11 +112,6 @@ void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { * init UART driver */ void EMSuart::start(const uint8_t tx_mode) { - if(tx_mode > 50) { - emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode - 50); - } else if (tx_mode > 5) { - emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode + 10); - } if (tx_mode_ != 0xFF) { // uart already initialized tx_mode_ = tx_mode; restart(); @@ -132,18 +131,15 @@ void EMSuart::start(const uint8_t tx_mode) { EMS_UART.int_ena.val = 0; // disable all intr. EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit - // EMS_UART.idle_conf.rx_idle_thrhd = 0; + EMS_UART.idle_conf.rx_idle_thrhd = 256; drop_next_rx = true; buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT); uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle); xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL); - EMS_UART.int_ena.brk_det = 1; // activate only break - // EMS_UART.int_ena.frm_err = 1; - emsTxBufIdx = 0; - emsTxBufLen = 0; - timer = timerBegin(1, 80, true); // timer prescale to 1 µs, countup + timer = timerBegin(1, 80, true); // timer prescale to 1 µs, countup timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, true); // Timer with edge interrupt + restart(); } /* @@ -165,21 +161,30 @@ void EMSuart::restart() { EMS_UART.int_ena.brk_det = 1; // activate only break emsTxBufIdx = 0; emsTxBufLen = 0; + if (tx_mode_ == 1) { + EMS_UART.idle_conf.tx_idle_num = 5; + } else if (tx_mode_ == 2) { + EMS_UART.idle_conf.tx_idle_num = 10; + } else if (tx_mode_ == 3) { + EMS_UART.idle_conf.tx_idle_num = 7; + } else if (tx_mode_ == 4) { + EMS_UART.idle_conf.tx_idle_num = 2; + } else if (tx_mode_ == 5) { + EMS_UART.idle_conf.tx_idle_num = 2; + } else if (tx_mode_ <= 50) { + EMS_UART.idle_conf.tx_idle_num = tx_mode_; + emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ + 10); + } else { + EMS_UART.idle_conf.tx_idle_num = 2; + emsTxWait = EMSUART_TX_BIT_TIME * (tx_mode_ - 50); + } } /* * Sends a 1-byte poll, ending with a */ void EMSuart::send_poll(const uint8_t data) { - EMS_UART.conf0.txd_brk = 0; EMS_UART.fifo.rw_byte = data; - if (tx_mode_ == EMS_TXMODE_EMSPLUS) { - delayMicroseconds(EMSUART_TX_WAIT_PLUS); - } else if (tx_mode_ == EMS_TXMODE_HT3) { - delayMicroseconds(EMSUART_TX_WAIT_HT3); - } else if (tx_mode_ == 1) { - delayMicroseconds(EMSUART_TX_WAIT_BRK); - } EMS_UART.conf0.txd_brk = 1; // after send return; } @@ -202,13 +207,13 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { } emsTxBufIdx = 0; emsTxBufLen = len; - timerAlarmWrite(timer, emsTxWait, true); + timerAlarmWrite(timer, emsTxWait, false); timerAlarmEnable(timer); return EMS_TX_STATUS_OK; } if (tx_mode_ == 5) { // wait before sending - vTaskDelay(3 / portTICK_PERIOD_MS); + vTaskDelay(4 / portTICK_PERIOD_MS); for (uint8_t i = 0; i < len; i++) { EMS_UART.fifo.rw_byte = buf[i]; } @@ -224,10 +229,11 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { } if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ with long delay - for (uint8_t i = 0; i < len; i++) { + for (uint8_t i = 0; i < len - 1; i++) { EMS_UART.fifo.rw_byte = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_PLUS); } + EMS_UART.fifo.rw_byte = buf[len - 1]; EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send return EMS_TX_STATUS_OK; } @@ -246,7 +252,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { // flush fifos -- not supported in ESP32 uart #2! // EMS_UART.conf0.rxfifo_rst = 1; // EMS_UART.conf0.txfifo_rst = 1; - for (uint8_t i = 0; i < len; i++) { + for (uint8_t i = 0; i < len - 1; i++) { volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; EMS_UART.fifo.rw_byte = buf[i]; // send each Tx byte uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; @@ -254,6 +260,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } + EMS_UART.fifo.rw_byte = buf[len - 1]; // send each Tx byte EMS_UART.conf0.txd_brk = 1; // after send, cleard by hardware after send return EMS_TX_STATUS_OK; } From 627807d57f97b8601f3230925377adac4371f4a5 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 5 Jul 2020 13:37:34 +0200 Subject: [PATCH 3/5] sensor conversion time set to min 1 sec. --- src/sensors.cpp | 2 +- src/sensors.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sensors.cpp b/src/sensors.cpp index d9457ee93..742972e37 100644 --- a/src/sensors.cpp +++ b/src/sensors.cpp @@ -73,7 +73,7 @@ void Sensors::loop() { last_activity_ = time_now; } } else if (state_ == State::READING) { - if (temperature_convert_complete()) { + if (temperature_convert_complete() && (time_now - last_activity_ > CONVERSION_MS)) { // LOG_DEBUG(F("Scanning for sensors")); // uncomment for debug bus_.reset_search(); found_.clear(); diff --git a/src/sensors.h b/src/sensors.h index c8dedf664..f11ed826f 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -89,6 +89,7 @@ class Sensors { static constexpr uint8_t TYPE_DS1825 = 0x3B; static constexpr uint32_t READ_INTERVAL_MS = 5000; // 5 seconds + static constexpr uint32_t CONVERSION_MS = 1000; // 1 seconds static constexpr uint32_t READ_TIMEOUT_MS = 2000; // 2 seconds static constexpr uint32_t SCAN_TIMEOUT_MS = 30000; // 30 seconds From eb5ce5fb3380e2ae575e58569b2a23a796e2a756 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 5 Jul 2020 13:40:15 +0200 Subject: [PATCH 4/5] validate read to queue front --- src/telegram.cpp | 23 ++++++++++++++++------- src/telegram.h | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/telegram.cpp b/src/telegram.cpp index 7b78a96f2..4eec422aa 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -421,7 +421,7 @@ void TxService::send_telegram(const uint8_t * data, const uint8_t length) { // builds a Tx telegram and adds to queue // given some details like the destination, type, offset and message block -void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length) { +void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const bool front) { auto telegram = std::make_shared(operation, ems_bus_id(), dest, type_id, offset, message_data, message_length); #ifdef EMSESP_DEBUG LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); @@ -432,14 +432,18 @@ void TxService::add(const uint8_t operation, const uint8_t dest, const uint16_t tx_telegrams_.pop_front(); } - tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // first tx, no retry + if (front) { + tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } else { + tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } } // builds a Tx telegram and adds to queue // this is used by the retry() function to put the last failed Tx back into the queue // format is EMS 1.0 (src, dest, type_id, offset, data) // length is the length of the whole telegram data, excluding the CRC -void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t length) { +void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t length, const bool front) { // build header. src, dest and offset have fixed positions uint8_t src = data[0]; uint8_t dest = data[1]; @@ -494,8 +498,11 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt #ifdef EMSESP_DEBUG LOG_DEBUG(F("[DEBUG] New Tx [#%d] telegram, length %d"), tx_telegram_id_, message_length); #endif - - tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + if (front) { + tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } else { + tx_telegrams_.emplace_back(tx_telegram_id_++, std::move(telegram), false); // add to back of queue + } } // send a Tx telegram to request data from an EMS device @@ -583,8 +590,10 @@ bool TxService::is_last_tx(const uint8_t src, const uint8_t dest) const { // sends a type_id read request to fetch values after a successful Tx write operation void TxService::post_send_query() { if (telegram_last_post_send_query_) { - uint8_t dest = (telegram_last_->dest & 0x7F); - read_request(telegram_last_post_send_query_, dest, 0); // no offset + uint8_t dest = (telegram_last_->dest & 0x7F); + uint8_t message_data[1] = {EMS_MAX_TELEGRAM_LENGTH}; // request all data, 32 bytes + add(Telegram::Operation::TX_READ, dest, telegram_last_post_send_query_, 0, message_data, 1, true); + // read_request(telegram_last_post_send_query_, dest, 0); // no offset LOG_DEBUG(F("Sending post validate read, type ID 0x%02X to dest 0x%02X"), telegram_last_post_send_query_, dest); } } diff --git a/src/telegram.h b/src/telegram.h index e42c42ca1..b01e3f7ec 100644 --- a/src/telegram.h +++ b/src/telegram.h @@ -270,8 +270,8 @@ class TxService : public EMSbus { void loop(); void send(); - void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length); - void add(const uint8_t operation, const uint8_t * data, const uint8_t length); + void add(const uint8_t operation, const uint8_t dest, const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const bool front = false); + void add(const uint8_t operation, const uint8_t * data, const uint8_t length, const bool front = false); void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0); From be0951b2c391b41e638fc5cc9bc0113dc5c0a2da Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sun, 5 Jul 2020 13:42:58 +0200 Subject: [PATCH 5/5] thermostat: add times for pause/party/holiday, validate typeids changed --- src/devices/thermostat.cpp | 137 ++++++++++++++++++++++++++++++++----- src/devices/thermostat.h | 5 ++ 2 files changed, 126 insertions(+), 16 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index cb90b27b6..f09c1611b 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -54,6 +54,7 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i } else if ((flags == EMSdevice::EMS_DEVICE_FLAG_RC35) || (flags == EMSdevice::EMS_DEVICE_FLAG_RC30_1)) { monitor_typeids = {0x3E, 0x48, 0x52, 0x5C}; set_typeids = {0x3D, 0x47, 0x51, 0x5B}; + timer_typeids = {0x3F, 0x49, 0x53, 0x5D}; for (uint8_t i = 0; i < monitor_typeids.size(); i++) { register_telegram_type(monitor_typeids[i], F("RC35Monitor"), false, std::bind(&Thermostat::process_RC35Monitor, this, _1)); register_telegram_type(set_typeids[i], F("RC35Set"), false, std::bind(&Thermostat::process_RC35Set, this, _1)); @@ -230,7 +231,8 @@ void Thermostat::add_context_menu() { } // general MQTT command for controlling thermostat -// e.g. { "cmd":"daytemp2", "data": 20 } +// e.g. { "hc": 1, "cmd":"daytemp", "data": 20 } +// or { "hc": 1, "daytemp": 20 } or { "hc2": { "daytemp":20 }} void Thermostat::thermostat_cmd(const char * message) { StaticJsonDocument doc; DeserializationError error = deserializeJson(doc, message); @@ -246,7 +248,7 @@ void Thermostat::thermostat_cmd(const char * message) { uint8_t hc_num = hc->hc_num(); strlcat(hc_name, Helpers::itoa(s, hc_num), 6); if (nullptr != doc[hc_name]["mode"]) { - std::string mode = doc[hc_name]["mode"]; // first check mode + std::string mode = doc[hc_name]["mode"]; set_mode(mode, hc_num); } if (float f = doc[hc_name]["temp"]) { @@ -290,7 +292,19 @@ void Thermostat::thermostat_cmd(const char * message) { uint8_t ctrl = doc[hc_name]["control"]; set_control(ctrl, hc_num); } - } + if (nullptr != doc[hc_name]["pause"]) { + uint8_t p = doc[hc_name]["pause"]; + set_pause(p, hc_num); + } + if (nullptr != doc[hc_name]["party"]) { + uint8_t p = doc[hc_name]["party"]; + set_party(p, hc_num); + } + if (nullptr != doc[hc_name]["holiday"]) { + std::string holiday = doc[hc_name]["holiday"]; + set_holiday(holiday.c_str(), hc_num); + } + } if (nullptr != doc["wwmode"]) { std::string mode = doc["wwmode"]; set_ww_mode(mode); @@ -332,7 +346,7 @@ void Thermostat::thermostat_cmd(const char * message) { // check for unnested commands like {"temp":21} or {"hc":2,"temp":21,"mode":"auto"} if (nullptr != doc["mode"]) { - std::string mode = doc["mode"]; // first check mode + std::string mode = doc["mode"]; set_mode(mode, hc_num); } if (float f = doc["temp"]) { @@ -376,6 +390,22 @@ void Thermostat::thermostat_cmd(const char * message) { uint8_t ctrl = doc["control"]; set_control(ctrl, hc_num); } + if (nullptr != doc["pause"]) { + uint8_t p = doc["pause"]; + set_pause(p, hc_num); + } + if (nullptr != doc["party"]) { + uint8_t p = doc["party"]; + set_party(p, hc_num); + } + if (nullptr != doc["holiday"]) { + std::string holiday = doc["holiday"]; + set_holiday(holiday.c_str(), hc_num); + } + if (nullptr != doc["date"]) { + std::string date = doc["date"]; + set_datetime(date.c_str()); + } // check for commands like {"hc":2,"cmd":"temp","data":21} const char * command = doc["cmd"]; @@ -1339,18 +1369,18 @@ void Thermostat::set_settings_language(const uint8_t lg) { void Thermostat::set_control(const uint8_t ctrl, const uint8_t hc_num) { std::shared_ptr hc = heating_circuit(hc_num); if (hc == nullptr) { - LOG_WARNING(F("set control: Heating Circuit %d not found or activated"), hc_num); + LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num); return; } if (ctrl > 2) { - LOG_WARNING(F("set control: Invalid control mode: %d"), ctrl); + LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl); return; } if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl); write_command(set_typeids[hc->hc_num() - 1], 26, ctrl); } else { - LOG_INFO(F("set circuit-control not supported")); + LOG_INFO(F("Set circuit-control not supported")); } } @@ -1366,7 +1396,79 @@ void Thermostat::set_ww_mode(const std::string & mode) { LOG_INFO(F("Setting thermostat warm water mode to %s"), mode.c_str()); write_command(EMS_TYPE_wwSettings, 2, 2); } else { - LOG_WARNING(F("set thermostat warm water mode: Invalid mode: %s"), mode.c_str()); + LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), mode.c_str()); + } +} + +// set the holiday as string dd.mm.yyyy-dd.mm.yyyy +void Thermostat::set_holiday(const char * hd, const uint8_t hc_num) { + std::shared_ptr hc = heating_circuit(hc_num); + if (hc == nullptr) { + LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); + return; + } + uint8_t data[6]; + data[0] = (hd[0] - '0') * 10 + (hd[1] - '0'); + data[1] = (hd[3] - '0') * 10 + (hd[4] - '0'); + data[2] = (hd[7] - '0') * 100 + (hd[8] - '0') * 10 + (hd[9] - '0'); + data[3] = (hd[11] - '0') * 10 + (hd[11] - '0'); + data[4] = (hd[14] - '0') * 10 + (hd[15] - '0'); + data[5] = (hd[18] - '0') * 100 + (hd[19] - '0') * 10 + (hd[20] - '0'); + if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { + LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num()); + write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0); + } else { + LOG_INFO(F("Set holiday not supported")); + } +} + +// set pause in hours +void Thermostat::set_pause(const uint8_t hrs, const uint8_t hc_num) { + std::shared_ptr hc = heating_circuit(hc_num); + if (hc == nullptr) { + LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); + return; + } + if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { + LOG_INFO(F("Setting pause: %d hours, hc: %d"), hrs, hc->hc_num()); + write_command(timer_typeids[hc->hc_num() - 1], 85, hrs); + } else { + LOG_INFO(F("Set pause not supported")); + } +} + +// set partymode in hours +void Thermostat::set_party(const uint8_t hrs, const uint8_t hc_num) { + std::shared_ptr hc = heating_circuit(hc_num); + if (hc == nullptr) { + LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); + return; + } + if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { + LOG_INFO(F("Setting party: %d hours, hc: %d"), hrs, hc->hc_num()); + write_command(timer_typeids[hc->hc_num() - 1], 86, hrs); + } else { + LOG_INFO(F("Set party not supported")); + } +} + +// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst +// dw - day of week (0..6), dst- summertime (0/1) + void Thermostat::set_datetime(const char * dt) { + uint8_t data[9]; + data[0] = (dt[16] - '0') * 100 + (dt[17] - '0') * 10 + (dt[18] - '0'); // year + data[1] = (dt[12] - '0') * 10 + (dt[13] - '0'); // month + data[2] = (dt[0] - '0') * 10 + (dt[1] - '0'); // hour + data[3] = (dt[9] - '0') * 10 + (dt[10] - '0'); // day + data[4] = (dt[3] - '0') * 10 + (dt[4] - '0'); // min + data[5] = (dt[6] - '0') * 10 + (dt[7] - '0'); // sec + data[6] = (dt[20] - '0'); // day of week + data[7] = (dt[22] - '0'); // summerime + if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) { + LOG_INFO(F("Setting date and time")); + write_command(6, 0, data, 8, 0); + } else { + LOG_INFO(F("Set date not supported")); } } @@ -1407,7 +1509,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) { // get hc based on number std::shared_ptr hc = heating_circuit(hc_num); if (hc == nullptr) { - LOG_WARNING(F("set mode: Heating Circuit %d not found or activated"), hc_num); + LOG_WARNING(F("Set mode: Heating Circuit %d not found or activated"), hc_num); return; } @@ -1453,7 +1555,7 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) { case EMSdevice::EMS_DEVICE_FLAG_RC35: case EMSdevice::EMS_DEVICE_FLAG_RC30_1: offset = EMS_OFFSET_RC35Set_mode; - validate_typeid = monitor_typeids[hc_p]; + validate_typeid = set_typeids[hc_p]; break; case EMSdevice::EMS_DEVICE_FLAG_RC300: case EMSdevice::EMS_DEVICE_FLAG_RC100: @@ -1533,13 +1635,14 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co // get hc based on number std::shared_ptr hc = heating_circuit(hc_num); if (hc == nullptr) { - LOG_WARNING(F("set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); + LOG_WARNING(F("Set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, device_id()); return; } - uint8_t model = flags() & 0x0F; - int8_t offset = -1; // we use -1 to check if there is a value - uint8_t factor = 2; // some temperatures only use 1 + uint8_t model = flags() & 0x0F; + int8_t offset = -1; // we use -1 to check if there is a value + uint8_t factor = 2; // some temperatures only use 1 + uint16_t validate_typeid = monitor_typeids[hc->hc_num() - 1]; if (model == EMS_DEVICE_FLAG_RC10) { offset = EMS_OFFSET_RC10Set_temp; @@ -1551,6 +1654,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co offset = EMS_OFFSET_RC30Set_temp; } else if ((model == EMS_DEVICE_FLAG_RC300) || (model == EMS_DEVICE_FLAG_RC100)) { + validate_typeid = set_typeids[hc->hc_num() - 1]; if (mode == HeatingCircuit::Mode::AUTO) { offset = 0x08; // auto offset } else if (mode == HeatingCircuit::Mode::MANUAL) { @@ -1570,6 +1674,7 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co } } else if ((model == EMS_DEVICE_FLAG_RC35) || (model == EMS_DEVICE_FLAG_RC30_1)) { + validate_typeid = set_typeids[hc->hc_num() - 1]; switch (mode) { case HeatingCircuit::Mode::NIGHT: // change the night temp offset = EMS_OFFSET_RC35Set_temp_night; @@ -1666,8 +1771,8 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co mode_tostring(mode).c_str()); // add the write command to the Tx queue - // post validate is the corresponding monitor type_id - write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), monitor_typeids[hc->hc_num() - 1]); + // post validate is the corresponding monitor or set type IDs as they can differ per model + write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid); } } diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index badfdabf7..a76332a80 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -104,6 +104,7 @@ class Thermostat : public EMSdevice { // each thermostat has a list of heating controller type IDs for reading and writing std::vector monitor_typeids; std::vector set_typeids; + std::vector timer_typeids; private: static uuid::log::Logger logger_; @@ -251,6 +252,10 @@ class Thermostat : public EMSdevice { void set_settings_language(const uint8_t lg); void set_control(const uint8_t ctrl, const uint8_t hc_num); void set_ww_mode(const std::string & mode); + void set_holiday(const char * hd, const uint8_t hc_num); + void set_datetime(const char * dt); + void set_pause(const uint8_t hrs, const uint8_t hc_num); + void set_party(const uint8_t hrs, const uint8_t hc_num); void set_mode(const uint8_t mode, const uint8_t hc_num); void set_mode(const std::string & mode, const uint8_t hc_num); void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);