From 7ca593f3746caaa79b0fdd8445ffa2e0c732b4e2 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:12:42 +0200 Subject: [PATCH 1/7] enlarge json buffer to hold sensor and boiler values --- src/EMSESPDevicesService.cpp | 4 ++-- src/EMSESPDevicesService.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/EMSESPDevicesService.cpp b/src/EMSESPDevicesService.cpp index 15368789a..8fccbdc32 100644 --- a/src/EMSESPDevicesService.cpp +++ b/src/EMSESPDevicesService.cpp @@ -44,7 +44,7 @@ void EMSESPDevicesService::scan_devices(AsyncWebServerRequest * request) { } void EMSESPDevicesService::all_devices(AsyncWebServerRequest * request) { - AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_STATUS_SIZE); + AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_DEVICE_SIZE); JsonObject root = response->getRoot(); JsonArray devices = root.createNestedArray("devices"); @@ -78,7 +78,7 @@ void EMSESPDevicesService::device_data(AsyncWebServerRequest * request, JsonVari if (json.is()) { uint8_t id = json["id"]; // get id from selected table row - AsyncJsonResponse * response = new AsyncJsonResponse(false, 1024); + AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_DEVICE_SIZE); #ifndef EMSESP_STANDALONE EMSESP::device_info(id, (JsonObject &)response->getRoot()); #endif diff --git a/src/EMSESPDevicesService.h b/src/EMSESPDevicesService.h index 05cc58577..b542e82fc 100644 --- a/src/EMSESPDevicesService.h +++ b/src/EMSESPDevicesService.h @@ -24,7 +24,8 @@ #include #include -#define MAX_EMSESP_STATUS_SIZE 1024 +// #define MAX_EMSESP_STATUS_SIZE 1024 +#define MAX_EMSESP_DEVICE_SIZE 1280 #define EMSESP_DEVICES_SERVICE_PATH "/rest/allDevices" #define SCAN_DEVICES_SERVICE_PATH "/rest/scanDevices" From 6a434f0cef2bd165436c00a3f213e84313e2830d Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:14:49 +0200 Subject: [PATCH 2/7] round sensor values, no yield for esp32 (dualcore) --- src/sensors.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sensors.cpp b/src/sensors.cpp index 306457f43..76bf98c39 100644 --- a/src/sensors.cpp +++ b/src/sensors.cpp @@ -23,6 +23,12 @@ MAKE_PSTR(logger_name, "sensors") +#ifdef ESP32 +#define YIELD +#else +#define YIELD yield() +#endif + namespace emsesp { uuid::log::Logger Sensors::logger_{F_(logger_name), uuid::log::Facility::DAEMON}; @@ -63,7 +69,7 @@ void Sensors::loop() { if (time_now - last_activity_ >= READ_INTERVAL_MS) { // LOG_DEBUG(F("Read sensor temperature")); // uncomment for debug if (bus_.reset()) { - yield(); + YIELD; bus_.skip(); bus_.write(CMD_CONVERT_TEMP); @@ -155,17 +161,17 @@ float Sensors::get_temperature_c(const uint8_t addr[]) { LOG_ERROR(F("Bus reset failed before reading scratchpad from %s"), Device(addr).to_string().c_str()); return NAN; } - yield(); + YIELD; uint8_t scratchpad[SCRATCHPAD_LEN] = {0}; bus_.select(addr); bus_.write(CMD_READ_SCRATCHPAD); bus_.read_bytes(scratchpad, SCRATCHPAD_LEN); - yield(); + YIELD; if (!bus_.reset()) { LOG_ERROR(F("Bus reset failed after reading scratchpad from %s"), Device(addr).to_string().c_str()); return NAN; } - yield(); + YIELD; if (bus_.crc8(scratchpad, SCRATCHPAD_LEN - 1) != scratchpad[SCRATCHPAD_LEN - 1]) { LOG_WARNING(F("Invalid scratchpad CRC: %02X%02X%02X%02X%02X%02X%02X%02X%02X from device %s"), scratchpad[0], @@ -202,7 +208,8 @@ float Sensors::get_temperature_c(const uint8_t addr[]) { break; } - return (float)raw_value / 16; + uint32_t raw = (raw_value *625) / 100; // round to 0.01 + return (float)raw / 100; #else return NAN; #endif From d6c5321a5f73e3c28624c1f877af7be3ff44fd06 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:17:31 +0200 Subject: [PATCH 3/7] update uarts --- src/uart/emsuart_esp32.cpp | 67 +++++++------------ src/uart/emsuart_esp32.h | 14 ++-- src/uart/emsuart_esp8266.cpp | 124 ++++++++--------------------------- src/uart/emsuart_esp8266.h | 13 ++-- 4 files changed, 68 insertions(+), 150 deletions(-) diff --git a/src/uart/emsuart_esp32.cpp b/src/uart/emsuart_esp32.cpp index e699bb59b..db9381136 100644 --- a/src/uart/emsuart_esp32.cpp +++ b/src/uart/emsuart_esp32.cpp @@ -34,8 +34,8 @@ static hw_timer_t * timer = NULL; bool drop_next_rx = true; uint8_t tx_mode_ = 0xFF; uint8_t emsTxBuf[EMS_MAXBUFFERSIZE]; -uint8_t emsTxBufIdx; -uint8_t emsTxBufLen; +uint8_t emsTxBufIdx = 0; +uint8_t emsTxBufLen = 0; uint32_t emsTxWait; /* @@ -88,12 +88,15 @@ void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { portENTER_CRITICAL(&mux); if (emsTxBufIdx < emsTxBufLen) { EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx]; - timerAlarmWrite(timer, emsTxWait, true); + if (emsTxBufIdx == 1) { + timerAlarmWrite(timer, emsTxWait, true); + } } else if (emsTxBufIdx == emsTxBufLen) { EMS_UART.conf0.txd_inv = 1; - timerAlarmWrite(timer, EMSUART_TX_WAIT_BRK, true); + timerAlarmWrite(timer, EMSUART_TX_BRK_TIMER, true); } else if (emsTxBufIdx == emsTxBufLen + 1) { EMS_UART.conf0.txd_inv = 0; + emsTxBufLen = 0; timerAlarmDisable(timer); } emsTxBufIdx++; @@ -130,7 +133,7 @@ void EMSuart::start(const uint8_t tx_mode) { xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL); timer = timerBegin(0, 80, true); // timer prescale to 1 us, countup - timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, false); // Timer with level interrupt + timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, true); // Timer with edge interrupt restart(); } @@ -140,6 +143,9 @@ void EMSuart::start(const uint8_t tx_mode) { void EMSuart::stop() { EMS_UART.int_ena.val = 0; // disable all intr. EMS_UART.conf0.txd_inv = 0; // stop break + if (emsTxBufLen > 0) { + timerAlarmDisable(timer); + } }; /* @@ -165,44 +171,11 @@ void EMSuart::restart() { } } -/* - * Sends a 11-bit break by inverting the tx-port - */ -void EMSuart::tx_brk() { - EMS_UART.conf0.txd_inv = 1; - delayMicroseconds(EMSUART_TX_WAIT_BRK); - EMS_UART.conf0.txd_inv = 0; -} - /* * Sends a 1-byte poll, ending with a */ void EMSuart::send_poll(const uint8_t data) { - if (tx_mode_ > 5) { // timer controlled modes - emsTxBuf[0] = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - timerAlarmWrite(timer, emsTxWait, true); // start timer with autoreload - timerAlarmEnable(timer); // first interrupt comes immediately - } else if (tx_mode_ == EMS_TXMODE_DEFAULT) { - volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt; - uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; - EMS_UART.fifo.rw_byte = data; - while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) { - delayMicroseconds(EMSUART_TX_BUSY_WAIT); - } - tx_brk(); - } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { - EMS_UART.fifo.rw_byte = data; - delayMicroseconds(EMSUART_TX_WAIT_PLUS); - tx_brk(); - } else if (tx_mode_ == EMS_TXMODE_HT3) { - EMS_UART.fifo.rw_byte = data; - delayMicroseconds(EMSUART_TX_WAIT_HT3); - tx_brk(); - } else { - EMS_UART.fifo.rw_byte = data; - } + transmit(&data, 1); } /* @@ -221,7 +194,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { } emsTxBufIdx = 0; emsTxBufLen = len; - if (tx_mode_ > 100) { + if (tx_mode_ > 100 && len > 1) { timerAlarmWrite(timer, EMSUART_TX_WAIT_REPLY, true); } else { timerAlarmWrite(timer, emsTxWait, true); // start with autoreload @@ -242,7 +215,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { EMS_UART.fifo.rw_byte = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_PLUS); } - tx_brk(); + EMS_UART.conf0.txd_inv = 1; // send + delayMicroseconds(EMSUART_TX_BRK_PLUS); + EMS_UART.conf0.txd_inv = 0; return EMS_TX_STATUS_OK; } @@ -251,11 +226,13 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { EMS_UART.fifo.rw_byte = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_HT3); } - tx_brk(); + EMS_UART.conf0.txd_inv = 1; // send + delayMicroseconds(EMSUART_TX_BRK_HT3); + EMS_UART.conf0.txd_inv = 0; return EMS_TX_STATUS_OK; } - // mode 1 + // mode 1: wait for echo after each byte // flush fifos -- not supported in ESP32 uart #2! // EMS_UART.conf0.rxfifo_rst = 1; // EMS_UART.conf0.txfifo_rst = 1; @@ -267,7 +244,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) { delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } - tx_brk(); + EMS_UART.conf0.txd_inv = 1; + delayMicroseconds(EMSUART_TX_BRK_EMS); + EMS_UART.conf0.txd_inv = 0; return EMS_TX_STATUS_OK; } diff --git a/src/uart/emsuart_esp32.h b/src/uart/emsuart_esp32.h index ab2d1fd45..df29566b4 100644 --- a/src/uart/emsuart_esp32.h +++ b/src/uart/emsuart_esp32.h @@ -46,20 +46,25 @@ #define EMS_TXMODE_NEW 4 // for michael's testing // LEGACY -#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud -#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 10) // 10 bt -#define EMSUART_TX_WAIT_REPLY 100000 // delay 100ms after first byte +#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud + +// Timer controlled modes +#define EMSUART_TX_BRK_TIMER (EMSUART_TX_BIT_TIME * 10 + 28) // 10.25 bit times +#define EMSUART_TX_WAIT_REPLY 100000 // delay 100ms after first byte // EMS 1.0 #define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 -#define EMSUART_TX_TIMEOUT (32 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 256 +#define EMSUART_TX_TIMEOUT (20 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) +#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10) // HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. // since we use a faster processor the lag is negligible #define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) // 1768 +#define EMSUART_TX_BRK_HT3 (EMSUART_TX_BIT_TIME * 11) // EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime. #define EMSUART_TX_WAIT_PLUS (EMSUART_TX_BIT_TIME * 20) // 2080 +#define EMSUART_TX_BRK_PLUS (EMSUART_TX_BIT_TIME * 11) // customize the GPIO pins for RX and TX here @@ -91,7 +96,6 @@ class EMSuart { static void emsuart_recvTask(void * para); static void IRAM_ATTR emsuart_rx_intr_handler(void * para); static void IRAM_ATTR emsuart_tx_timer_intr_handler(); - static void tx_brk(); }; } // namespace emsesp diff --git a/src/uart/emsuart_esp8266.cpp b/src/uart/emsuart_esp8266.cpp index f168d3f13..3816fed86 100644 --- a/src/uart/emsuart_esp8266.cpp +++ b/src/uart/emsuart_esp8266.cpp @@ -95,10 +95,10 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() { timer1_write(emsTxWait); } else if (emsTxBufIdx == emsTxBufLen) { USC0(EMSUART_UART) |= (1 << UCBRK); // set - timer1_write(EMSUART_TX_WAIT_BRK * 5); + timer1_write(EMSUART_TX_BRK_TIMER); } else { USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset - sending_ = false; + sending_ = false; } } @@ -114,11 +114,6 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() { * init UART0 driver */ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { - if (tx_mode_ > 100) { - emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode - 90); - } else { - emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait to next bytes - } if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart tx_mode_ = tx_mode; restart(); @@ -133,7 +128,6 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { } pEMSRxBuf = paEMSRxBuf[0]; // reset EMS Rx Buffer - ETS_UART_INTR_DISABLE(); ETS_UART_INTR_ATTACH(nullptr, nullptr); // pin settings @@ -153,22 +147,14 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { // UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127) // see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf // - // change: we set UCFFT to 1 to get an immediate indicator about incoming traffic. - // Otherwise, we're only noticed by UCTOT or RxBRK! // change: don't care, we do not use these interrupts - USC1(EMSUART_UART) = 0; // reset config first + USC1(EMSUART_UART) = 0; // reset config // USC1(EMSUART_UART) = (0x7F << UCFFT) | (0x01 << UCTOT) | (1 << UCTOE); // enable interupts // set interrupts for triggers USIC(EMSUART_UART) = 0xFFFF; // clear all interupts USIE(EMSUART_UART) = 0; // disable all interrupts - // enable rx break, fifo full and timeout. - // but not frame error UIFR (because they are too frequent) or overflow UIOF because our buffer is only max 32 bytes - // change: we don't care about Rx Timeout - it may lead to wrong readouts - // change:we don't care about Fifo full and read only on break-detect - USIE(EMSUART_UART) = (1 << UIBD) | (0 << UIFF) | (0 << UITO); - // set up interrupt callbacks for Rx system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen); @@ -182,10 +168,9 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) { drop_next_rx = true; // for sending with large delay in EMS+ mode we use a timer interrupt - timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function - timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer - ETS_UART_INTR_ENABLE(); - USIE(EMSUART_UART) = (1 << UIBD); + timer1_attachInterrupt(emsuart_tx_timer_intr_handler); + + restart(); } /* @@ -204,67 +189,25 @@ void ICACHE_FLASH_ATTR EMSuart::stop() { */ void ICACHE_FLASH_ATTR EMSuart::restart() { if (USIR(EMSUART_UART) & ((1 << UIBD))) { - USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt + USIC(EMSUART_UART) = (1 << UIBD); // INT clear the detect interrupt drop_next_rx = true; } + if (tx_mode_ > 100) { + emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode_ - 90); + } else { + emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode_ + 10); // bittimes wait to next bytes + } emsTxBufIdx = 0; emsTxBufLen = 0; timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); - USIE(EMSUART_UART) = (1 << UIBD); -} - -/* - * Send a BRK signal - * Which is a 11-bit set of zero's (11 cycles) - */ -void ICACHE_FLASH_ATTR EMSuart::tx_brk() { - // make sure Tx FIFO is empty - while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) { - } - USC0(EMSUART_UART) |= (1 << UCBRK); // set bit - // also for EMS+ there is no need to wait longer, we are finished and can free the bus. - delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144 - USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit + USIE(EMSUART_UART) = (1 << UIBD); // enable interrupt } /* * Sends a 1-byte poll, ending with a - * It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking */ -void EMSuart::send_poll(uint8_t data) { - // reset tx-brk, just in case it is accidentally set - USC0(EMSUART_UART) &= ~(1 << UCBRK); - sending_ = true; - - if (tx_mode_ >= 5) { // timer controlled modes - emsTxBuf[0] = data; - emsTxBufIdx = 0; - emsTxBufLen = 1; - timer1_write(emsTxWait); - } else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes - USF(EMSUART_UART) = data; - USC0(EMSUART_UART) |= (1 << UCBRK); - } else if (tx_mode_ == EMS_TXMODE_HT3) { - USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_WAIT_HT3); - tx_brk(); // send - sending_ = false; - } else if (tx_mode_ == EMS_TXMODE_EMSPLUS) { - USF(EMSUART_UART) = data; - delayMicroseconds(EMSUART_TX_WAIT_PLUS); - tx_brk(); // send - sending_ = false; - } else { - // tx_mode 1 - volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; - USF(EMSUART_UART) = data; - uint16_t timeoutcnt = EMSUART_TX_TIMEOUT; - while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) { - delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... - } - tx_brk(); // send - sending_ = false; - } +void ICACHE_FLASH_ATTR EMSuart::send_poll(uint8_t data) { + transmit(&data, 1); } /* @@ -276,20 +219,18 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { if (len == 0 || len >= EMS_MAXBUFFERSIZE) { return EMS_TX_STATUS_ERR; // nothing or to much to send } - // reset tx-brk, just in case it is accidentally set - USC0(EMSUART_UART) &= ~(1 << UCBRK); - sending_ = true; // timer controlled modes with extra delay if (tx_mode_ >= 5) { + sending_ = true; for (uint8_t i = 0; i < len; i++) { emsTxBuf[i] = buf[i]; } USF(EMSUART_UART) = buf[0]; // send first byte emsTxBufIdx = 0; emsTxBufLen = len; - if (tx_mode_ > 100) { - timer1_write(EMSUART_TX_WAIT_REPLY); + if (tx_mode_ > 100 && len > 1) { + timer1_write(EMSUART_TX_WAIT_REPLY); // large delay after first byte } else { timer1_write(emsTxWait); } @@ -301,7 +242,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; } - USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end + USC0(EMSUART_UART) |= (1 << UCBRK); // send at the end, clear by interrupt return EMS_TX_STATUS_OK; } @@ -311,8 +252,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { USF(EMSUART_UART) = buf[i]; delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070 } - tx_brk(); // send - sending_ = false; + USC0(EMSUART_UART) |= (1 << UCBRK); // set break + delayMicroseconds(EMSUART_TX_BRK_PLUS); + USC0(EMSUART_UART) &= ~(1 << UCBRK); return EMS_TX_STATUS_OK; } @@ -326,8 +268,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { // wait until bits are sent on wire delayMicroseconds(EMSUART_TX_WAIT_HT3); } - tx_brk(); // send - sending_ = false; + USC0(EMSUART_UART) |= (1 << UCBRK); // set break bit + delayMicroseconds(EMSUART_TX_BRK_HT3); + USC0(EMSUART_UART) &= ~(1 << UCBRK); return EMS_TX_STATUS_OK; } @@ -356,9 +299,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { * */ - // disable rx interrupt // clear Rx status register, resetting the Rx FIFO and flush it - // ETS_UART_INTR_DISABLE(); emsuart_flush_fifos(); // send the bytes along the serial line @@ -371,18 +312,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) { delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles... } } - - // we got the whole telegram in the Rx buffer - // on Rx-BRK (bus collision), we simply enable Rx and leave it - // otherwise we send the final Tx-BRK - // worst case, we'll see an additional Rx-BRK... - // neither bus collision nor timeout - send terminating BRK signal - if (!(USIS(EMSUART_UART) & (1 << UIBD))) { - // no bus collision - send terminating BRK signal - tx_brk(); - } - // ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving - sending_ = false; + USC0(EMSUART_UART) |= (1 << UCBRK); // snd break + delayMicroseconds(EMSUART_TX_BRK_EMS); + USC0(EMSUART_UART) &= ~(1 << UCBRK); return EMS_TX_STATUS_OK; // send the Tx ok status back } diff --git a/src/uart/emsuart_esp8266.h b/src/uart/emsuart_esp8266.h index 01407e54e..be4d1d9fa 100644 --- a/src/uart/emsuart_esp8266.h +++ b/src/uart/emsuart_esp8266.h @@ -40,22 +40,26 @@ #define EMS_TXMODE_NEW 4 // for michael's testing // LEGACY -#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud -#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 10) -#define EMSUART_TX_WAIT_REPLY 500000 // delay 100ms after first byte +#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud + +// TIMER modes +#define EMSUART_TX_BRK_TIMER (EMSUART_TX_BIT_TIME * 52) // > 10 bittimes for timer modes +#define EMSUART_TX_WAIT_REPLY 500000 // delay 100ms after first byte // EMS 1.0 #define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13 -// #define EMSUART_TX_TIMEOUT (22 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 176 // #define EMSUART_TX_TIMEOUT (32 * 8) // 256 for tx_mode 1 - see https://github.com/proddy/EMS-ESP/issues/398#issuecomment-645886277 #define EMSUART_TX_TIMEOUT (220 * 8) // 1760 as in v1.9 (180 ms) +#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10) // HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation. // since we use a faster processor the lag is negligible #define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) // 1768 +#define EMSUART_TX_BRK_HT3 (EMSUART_TX_BIT_TIME * 11) // EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime. #define EMSUART_TX_WAIT_PLUS (EMSUART_TX_BIT_TIME * 20) // 2080 +#define EMSUART_TX_BRK_PLUS (EMSUART_TX_BIT_TIME * 11) namespace emsesp { @@ -85,7 +89,6 @@ class EMSuart { static void ICACHE_RAM_ATTR emsuart_rx_intr_handler(void * para); static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events); static void ICACHE_FLASH_ATTR emsuart_flush_fifos(); - static void ICACHE_FLASH_ATTR tx_brk(); static void ICACHE_RAM_ATTR emsuart_tx_timer_intr_handler(); static bool sending_; }; From 2936de3e3ff8eeb6429efdde566c9ae145fe8042 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:18:20 +0200 Subject: [PATCH 4/7] add boler values --- src/devices/boiler.cpp | 193 ++++++++++++++++++++++++++++------------- src/devices/boiler.h | 17 +++- 2 files changed, 147 insertions(+), 63 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index be8026789..64adca5d2 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -30,7 +30,6 @@ MAKE_PSTR_WORD(intelligent) MAKE_PSTR_WORD(hot) MAKE_PSTR_WORD(maxpower) MAKE_PSTR_WORD(minpower) -MAKE_PSTR_WORD(temp) MAKE_PSTR(comfort_mandatory, "") @@ -106,18 +105,50 @@ void Boiler::boiler_cmd(const char * message) { uint8_t t = doc["wwtemp"]; set_warmwater_temp(t); } + if (nullptr != doc["boilhyston"]) { + int8_t t = doc["boilhyston"]; + set_hyst_on(t); + } + if (nullptr != doc["boilhystoff"]) { + uint8_t t = doc["boilhystoff"]; + set_hyst_off(t); + } + if (nullptr != doc["burnperiod"]) { + uint8_t t = doc["burnperiod"]; + set_burn_period(t); + } + if (nullptr != doc["burnminpower"]) { + uint8_t p = doc["burnminpower"]; + set_min_power(p); + } + if (nullptr != doc["burnmaxpower"]) { + uint8_t p = doc["burnmaxpower"]; + set_max_power(p); + } + if (nullptr != doc["pumpdelay"]) { + uint8_t t = doc["pumpdelay"]; + set_pump_delay(t); + } + + if (nullptr != doc["comfort"]) { + const char * data = doc["comfort"]; + if (strcmp((char *)data, "hot") == 0) { + set_warmwater_mode(1); + } else if (strcmp((char *)data, "eco") == 0) { + set_warmwater_mode(2); + } else if (strcmp((char *)data, "intelligent") == 0) { + set_warmwater_mode(3); + } + } const char * command = doc["cmd"]; - if (command == nullptr) { + if (command == nullptr || doc["data"] == nullptr) { return; } // boiler ww comfort setting if (strcmp(command, "comfort") == 0) { const char * data = doc["data"]; - if (data == nullptr) { - return; - } if (strcmp((char *)data, "hot") == 0) { set_warmwater_mode(1); } else if (strcmp((char *)data, "eco") == 0) { @@ -131,36 +162,45 @@ void Boiler::boiler_cmd(const char * message) { // boiler flowtemp setting if (strcmp(command, "flowtemp") == 0) { uint8_t t = doc["data"]; - if (t) { - set_flow_temp(t); - } + set_flow_temp(t); return; } - - // boiler temp setting - if (strcmp(command, "temp") == 0) { + if (strcmp(command, "wwtemp") == 0) { uint8_t t = doc["data"]; - if (t) { - set_temp(t); - } + set_warmwater_temp(t); return; } - // boiler max power setting - if (strcmp(command, "maxpower") == 0) { + if (strcmp(command, "burnmaxpower") == 0) { uint8_t p = doc["data"]; - if (p) { - set_max_power(p); - } + set_max_power(p); return; } // boiler min power setting - if (strcmp(command, "minpower") == 0) { + if (strcmp(command, "burnminpower") == 0) { uint8_t p = doc["data"]; - if (p) { - set_min_power(p); - } + set_min_power(p); + return; + } + if (strcmp(command, "boilhyston") == 0) { + int8_t t = doc["data"]; + set_hyst_on(t); + return; + } + if (strcmp(command, "boilhystoff") == 0) { + uint8_t t = doc["data"]; + set_hyst_off(t); + return; + } + if (strcmp(command, "burnperiod") == 0) { + uint8_t t = doc["data"]; + set_burn_period(t); + return; + } + if (strcmp(command, "pumpdelay") == 0) { + uint8_t t = doc["data"]; + set_pump_delay(t); return; } } @@ -216,7 +256,7 @@ void Boiler::device_info(JsonArray & root) { // publish values via MQTT void Boiler::publish_values() { - const size_t capacity = JSON_OBJECT_SIZE(50); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/ + const size_t capacity = JSON_OBJECT_SIZE(56); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/ DynamicJsonDocument doc(capacity); char s[10]; // for formatting strings @@ -328,7 +368,7 @@ void Boiler::publish_values() { doc["flameCurr"] = (float)(int16_t)flameCurr_ / 10; } if (Helpers::hasValue(heatPmp_, VALUE_BOOL)) { - doc["heatPmp"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL); + doc["heatPump"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL); } if (Helpers::hasValue(fanWork_, VALUE_BOOL)) { doc["fanWork"] = Helpers::render_value(s, fanWork_, EMS_VALUE_BOOL); @@ -340,13 +380,37 @@ void Boiler::publish_values() { doc["wWHeat"] = Helpers::render_value(s, wWHeat_, EMS_VALUE_BOOL); } if (Helpers::hasValue(heating_temp_)) { - doc["heating_temp"] = heating_temp_; + doc["heatingTemp"] = heating_temp_; } if (Helpers::hasValue(pump_mod_max_)) { - doc["pump_mod_max"] = pump_mod_max_; + doc["pumpModMax"] = pump_mod_max_; } if (Helpers::hasValue(pump_mod_min_)) { - doc["pump_mod_min"] = pump_mod_min_; + doc["pumpModMin"] = pump_mod_min_; + } + if (Helpers::hasValue(pumpDelay_)) { + doc["pumpDelay"] = pumpDelay_; + } + if (Helpers::hasValue(burnPeriod_)) { + doc["burnMinPeriod"] = burnPeriod_; + } + if (Helpers::hasValue(burnPowermin_)) { + doc["burnMinPower"] = burnPowermin_; + } + if (Helpers::hasValue(burnPowermax_)) { + doc["burnMaxPower"] = burnPowermax_; + } + if (Helpers::hasValue(boilTemp_on_)) { + doc["boilHystOn"] = boilTemp_on_; + } + if (Helpers::hasValue(boilTemp_off_)) { + doc["boilHystOff"] = boilTemp_off_; + } + if (Helpers::hasValue(setFlowTemp_)) { + doc["setFlowTemp"] = setFlowTemp_; + } + if (Helpers::hasValue(setWWPumpPow_)) { + doc["wWSetPumpPower"] = setWWPumpPow_; } if (Helpers::hasValue(wWStarts_)) { doc["wWStarts"] = wWStarts_; @@ -366,17 +430,6 @@ void Boiler::publish_values() { if (Helpers::hasValue(heatWorkMin_)) { doc["heatWorkMin"] = heatWorkMin_; } - - if (Helpers::hasValue(temp_)) { - doc["heatWorkMin"] = temp_; - } - if (Helpers::hasValue(maxpower_)) { - doc["heatWorkMin"] = maxpower_; - } - if (Helpers::hasValue(setpointpower_)) { - doc["heatWorkMin"] = setpointpower_; - } - if (Helpers::hasValue(serviceCode_)) { doc["serviceCode"] = serviceCodeChar_; doc["serviceCodeNumber"] = serviceCode_; @@ -474,11 +527,17 @@ void Boiler::show_values(uuid::console::Shell & shell) { print_value(shell, 2, F("Heating temperature setting on the boiler"), heating_temp_, F_(degrees)); print_value(shell, 2, F("Boiler circuit pump modulation max power"), pump_mod_max_, F_(percent)); print_value(shell, 2, F("Boiler circuit pump modulation min power"), pump_mod_min_, F_(percent)); + print_value(shell, 2, F("Boiler circuit pump delay time"), pumpDelay_, F("min")); + print_value(shell, 2, F("Boiler temp hysteresis on"), boilTemp_on_, F_(degrees)); + print_value(shell, 2, F("Boiler temp hysteresis off"), boilTemp_off_, F_(degrees)); + print_value(shell, 2, F("Boiler burner min period"), burnPeriod_, F("min")); + print_value(shell, 2, F("Boiler burner min power"), burnPowermin_, F_(percent)); + print_value(shell, 2, F("Boiler burner max power"), burnPowermax_, F_(percent)); // UBASetPoint - these may differ from the above - print_value(shell, 2, F("Boiler temp"), temp_, F_(degrees)); - print_value(shell, 2, F("Max output power"), maxpower_, F_(percent)); - print_value(shell, 2, F("Set power"), setpointpower_, F_(percent)); + print_value(shell, 2, F("Set Flow temperature"), setFlowTemp_, F_(degrees)); + print_value(shell, 2, F("Boiler burner set power"), setBurnPow_, F_(percent)); + print_value(shell, 2, F("Warm Water pump set power"), setWWPumpPow_, F_(percent)); // UBAMonitorSlow if (Helpers::hasValue(extTemp_)) { @@ -591,6 +650,12 @@ void Boiler::process_UBATotalUptime(std::shared_ptr telegram) { */ void Boiler::process_UBAParameters(std::shared_ptr telegram) { telegram->read_value(heating_temp_, 1); + telegram->read_value(burnPowermax_,2); + telegram->read_value(burnPowermin_,3); + telegram->read_value(boilTemp_off_,4); + telegram->read_value(boilTemp_on_,5); + telegram->read_value(burnPeriod_,6); + telegram->read_value(pumpDelay_,8); telegram->read_value(pump_mod_max_, 9); telegram->read_value(pump_mod_min_, 10); } @@ -717,9 +782,9 @@ void Boiler::process_UBAOutdoorTemp(std::shared_ptr telegram) { // UBASetPoint 0x1A void Boiler::process_UBASetPoints(std::shared_ptr telegram) { - telegram->read_value(temp_, 0); // boiler flow temp - telegram->read_value(maxpower_, 1); // max output power in % - telegram->read_value(setpointpower_, 14); // ww pump speed/power? + telegram->read_value(setFlowTemp_, 0); // boiler set temp from thermostat + telegram->read_value(setBurnPow_, 1); // max output power in % + telegram->read_value(setWWPumpPow_, 2); // ww pump speed/power? } #pragma GCC diagnostic push @@ -766,12 +831,6 @@ void Boiler::set_flow_temp(const uint8_t temperature) { write_command(EMS_TYPE_UBASetPoints, 0, temperature); } -// set heating temp -void Boiler::set_temp(const uint8_t temperature) { - LOG_INFO(F("Setting boiler temperature to %d C"), temperature); - write_command(EMS_TYPE_UBAParameters, 1, temperature); -} - // set min boiler output void Boiler::set_min_power(const uint8_t power) { LOG_INFO(F("Setting boiler min power to "), power); @@ -784,6 +843,30 @@ void Boiler::set_max_power(const uint8_t power) { write_command(EMS_TYPE_UBAParameters, 2, power); } +// set oiler on hysteresis +void Boiler::set_hyst_on(const uint8_t temp) { + LOG_INFO(F("Setting boiler hysteresis on to %d C"), temp); + write_command(EMS_TYPE_UBAParameters, 5, temp); +} + +// set boiler off hysteresis +void Boiler::set_hyst_off(const uint8_t temp) { + LOG_INFO(F("Setting boiler hysteresis off to %d C"), temp); + write_command(EMS_TYPE_UBAParameters, 4, temp); +} + +// set min burner period +void Boiler::set_burn_period(const uint8_t t) { + LOG_INFO(F("Setting burner min. period to %d min"), t); + write_command(EMS_TYPE_UBAParameters, 6, t); +} + +// set pump delay +void Boiler::set_pump_delay(const uint8_t t) { + LOG_INFO(F("Setting boiler pump delay to %d min"), t); + write_command(EMS_TYPE_UBAParameters, 8, t); +} + // 1=hot, 2=eco, 3=intelligent // note some boilers do not have this setting, than it's done by thermostat // on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3) @@ -888,14 +971,6 @@ void Boiler::console_commands(Shell & shell, unsigned int context) { set_flow_temp(Helpers::atoint(arguments.front().c_str())); }); - EMSESPShell::commands->add_command(ShellContext::BOILER, - CommandFlags::ADMIN, - flash_string_vector{F_(temp)}, - flash_string_vector{F_(degrees_mandatory)}, - [=](Shell & shell __attribute__((unused)), const std::vector & arguments) { - set_temp(Helpers::atoint(arguments.front().c_str())); - }); - EMSESPShell::commands->add_command(ShellContext::BOILER, CommandFlags::ADMIN, flash_string_vector{F_(maxpower)}, diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 125ff0f04..fc77d7e28 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -121,11 +121,17 @@ class Boiler : public EMSdevice { uint8_t heating_temp_ = EMS_VALUE_UINT_NOTSET; // Heating temperature setting on the boiler uint8_t pump_mod_max_ = EMS_VALUE_UINT_NOTSET; // Boiler circuit pump modulation max. power % uint8_t pump_mod_min_ = EMS_VALUE_UINT_NOTSET; // Boiler circuit pump modulation min. power + uint8_t burnPowermin_ = EMS_VALUE_UINT_NOTSET; + uint8_t burnPowermax_ = EMS_VALUE_UINT_NOTSET; + int8_t boilTemp_off_ = EMS_VALUE_INT_NOTSET; + int8_t boilTemp_on_ = EMS_VALUE_UINT_NOTSET; + uint8_t burnPeriod_ = EMS_VALUE_UINT_NOTSET; + uint8_t pumpDelay_ = EMS_VALUE_UINT_NOTSET; // UBASetPoint - uint8_t temp_ = EMS_VALUE_UINT_NOTSET; // boiler flow temp - uint8_t maxpower_ = EMS_VALUE_UINT_NOTSET; // max output power in % - uint8_t setpointpower_ = EMS_VALUE_UINT_NOTSET; // ww pump speed/power? + uint8_t setFlowTemp_ = EMS_VALUE_UINT_NOTSET; // boiler setpoint temp + uint8_t setBurnPow_ = EMS_VALUE_UINT_NOTSET; // max output power in % + uint8_t setWWPumpPow_ = EMS_VALUE_UINT_NOTSET; // ww pump speed/power? // other internal calculated params uint8_t tap_water_active_ = EMS_VALUE_BOOL_NOTSET; // Hot tap water is on/off @@ -161,9 +167,12 @@ class Boiler : public EMSdevice { void set_tapwarmwater_activated(const bool activated); void set_warmwater_onetime(const bool activated); void set_warmwater_circulation(const bool activated); - void set_temp(const uint8_t temperature); void set_min_power(const uint8_t power); void set_max_power(const uint8_t power); + void set_hyst_on(const uint8_t temp); + void set_hyst_off(const uint8_t temp); + void set_burn_period(const uint8_t t); + void set_pump_delay(const uint8_t t); // mqtt callbacks From bbc40e5bfb0d7c04635f40bab82353454c965394 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:19:01 +0200 Subject: [PATCH 5/7] add solar values --- src/devices/solar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index a8b49a9fe..30f8974a7 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -266,11 +266,14 @@ void Solar::process_ISM1StatusMessage(std::shared_ptr telegram) if (Wh != 0xFFFF) { energyLastHour_ = Wh * 10; // set to *10 } + telegram->read_bitvalue(pump_, 8, 0); // Solar pump on (1) or off (0) + telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes telegram->read_bitvalue(collectorOnOff_, 9, 0); // collector shutdown on/off telegram->read_bitvalue(tankHeated_, 9, 2); // tank full } /* + * Junkers ISM1 Solar Module - type 0x0101 EMS+ for setting values * e.g. 90 30 FF 06 00 01 50 */ void Solar::process_ISM1Set(std::shared_ptr telegram) { From d2549d025b3677250109308f1f7c83874fde1bee Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:20:16 +0200 Subject: [PATCH 6/7] add thermostat values, change output thermostat mqtt-custom to single format --- src/devices/thermostat.cpp | 81 +++++++++++++++++++++++++++----------- src/devices/thermostat.h | 1 + 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 85916655f..ef61c55d5 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -207,7 +207,17 @@ void Thermostat::device_info(JsonArray & root) { std::string mode_str(15, '\0'); snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str()); dataElement["name"] = mode_str; - dataElement["value"] = mode_tostring(hc->get_mode(flags)); + std::string modetype_str(20, '\0'); + if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) { + snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - summer"), mode_tostring(hc->get_mode(flags)).c_str()); + } else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) { + snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - holiday"), mode_tostring(hc->get_mode(flags)).c_str()); + } else if (Helpers::hasValue(hc->mode_type)) { + snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - %s"), mode_tostring(hc->get_mode(flags)).c_str(), mode_tostring(hc->get_mode_type(flags)).c_str()); + } else { + snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, mode_tostring(hc->get_mode(flags)).c_str()); + } + dataElement["value"] = modetype_str; } } } @@ -301,7 +311,7 @@ void Thermostat::thermostat_cmd(const char * message) { set_holiday(holiday.c_str(), hc_num); } } - + // commands without heatingcircuit if (nullptr != doc["wwmode"]) { std::string mode = doc["wwmode"]; set_ww_mode(mode); @@ -406,10 +416,10 @@ void Thermostat::thermostat_cmd(const char * message) { // check for commands like {"hc":2,"cmd":"temp","data":21} const char * command = doc["cmd"]; - if (command == nullptr) { + if (command == nullptr || doc["data"] == nullptr) { return; } - + // ok, we have command and data if (strcmp(command, "temp") == 0) { float f = doc["data"]; if (f) { @@ -595,7 +605,8 @@ void Thermostat::publish_values() { } // send this specific data using the thermostat_data topic - if ((mqtt_format_ == MQTT_format::SINGLE) || (mqtt_format_ == MQTT_format::HA)) { + // if ((mqtt_format_ == MQTT_format::SINGLE) || (mqtt_format_ == MQTT_format::HA)) { + if (mqtt_format_ != MQTT_format::NESTED) { Mqtt::publish("thermostat_data", doc); rootThermostat = doc.to(); // clear object } @@ -609,7 +620,8 @@ void Thermostat::publish_values() { has_data = true; // if the MQTT format is 'nested' or 'ha' then create the parent object hc - if (mqtt_format_ != MQTT_format::SINGLE) { + // if (mqtt_format_ != MQTT_format::SINGLE) { + if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::HA)) { char hc_name[10]; // hc{1-4} strlcpy(hc_name, "hc", 10); char s[3]; @@ -698,7 +710,8 @@ void Thermostat::publish_values() { // if format is single, send immediately and clear object for next hc // the topic will have the hc number appended - if (mqtt_format_ == MQTT_format::SINGLE) { + // if (mqtt_format_ == MQTT_format::SINGLE) { + if ((mqtt_format_ == MQTT_format::SINGLE) || (mqtt_format_ == MQTT_format::CUSTOM)) { char topic[30]; char s[3]; strlcpy(topic, "thermostat_data", 30); @@ -717,10 +730,9 @@ void Thermostat::publish_values() { } // if we're using nested json, send all in one go under one topic called thermostat_data + // if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::CUSTOM)) { if (mqtt_format_ == MQTT_format::NESTED) { Mqtt::publish("thermostat_data", doc); - } else if (mqtt_format_ == MQTT_format::CUSTOM) { - Mqtt::publish("thermostat_data", doc); } } @@ -1030,7 +1042,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) { shell.printfln(F(" Display: time")); } else if (ibaMainDisplay_ == 7) { shell.printfln(F(" Display: date")); - } else if (ibaMainDisplay_ == 9) { + } else if (ibaMainDisplay_ == 8) { shell.printfln(F(" Display: smoke temperature")); } } @@ -1209,7 +1221,7 @@ void Thermostat::process_EasyMonitor(std::shared_ptr telegram) { void Thermostat::process_IBASettings(std::shared_ptr telegram) { // 22 - display line on RC35 telegram->read_value(ibaMainDisplay_, - 0); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp + 0); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 8 smoke temp telegram->read_value(ibaLanguage_, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian telegram->read_value(ibaCalIntTemperature_, 2); // offset int. temperature sensor, by * 0.1 Kelvin telegram->read_value(ibaBuildingType_, 6); // building type: 0 = light, 1 = medium, 2 = heavy @@ -1351,11 +1363,16 @@ void Thermostat::process_RCTime(std::shared_ptr telegram) { if (flags() == EMS_DEVICE_FLAG_EASY) { return; // not supported } - + if (telegram->message_length < 7) { + return; + } + if (telegram->message_data[7] & 0x0C) { // date and time not valid + set_datetime("NTP"); // set from NTP + return; + } if (datetime_.empty()) { datetime_.resize(25, '\0'); } - // render time to HH:MM:SS DD/MM/YYYY // had to create separate buffers because of how printf works char buf1[6]; @@ -1510,18 +1527,38 @@ void Thermostat::set_party(const uint8_t hrs, const uint8_t hc_num) { } } -// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst +// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time // 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 (strcmp(dt,"NTP") == 0) { + time_t now = time(nullptr); + tm * tm_ = localtime(&now); + if (tm_->tm_year < 110) { // no NTP time + LOG_WARNING(F("No NTP time. Cannot set RCtime")); + return; + } + data[0] = tm_->tm_year - 100; // Bosch counts from 2000 + data[1] = tm_->tm_mon; + data[2] = tm_->tm_hour; + data[3] = tm_->tm_mday; + data[4] = tm_->tm_min; + data[5] = tm_->tm_sec; + data[6] = (tm_->tm_wday + 6) % 7; // Bosch counts from Mo, time from Su + data[7] = tm_->tm_isdst + 2; // set DST and flag for ext. clock + char time_string[25]; + strftime(time_string, 25, "%FT%T%z", tm_); + LOG_INFO(F("Date and time: %s"), time_string); + } else { + 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') + 2; // DST and flag + } 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); diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index ee019b87b..e0db67f99 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -31,6 +31,7 @@ #include "mqtt.h" #include +#include namespace emsesp { From e735ac03385e5497c7902eecd841a7baf803bd56 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Sat, 1 Aug 2020 12:20:55 +0200 Subject: [PATCH 7/7] update readme (add mqtt) --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 517879735..01dc95c21 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,6 @@ boiler wwonetime wwtemp read - temp maxpower <%> minpower <%> @@ -113,6 +112,61 @@ thermostat ``` ---------- +### **mqtt commands** + +commands can be written as `{"cmd": ,"data": }` or direct. +To set thermostat commands depending on heatingcircuits add `"hc": ` or nest the command. Without `"hc":` the first ative heatingcircuit is set. +These commands are equivalent: +`{"hc":2,"cmd":"daytemp","data":21}` or `{"hc":2,"daytemp":21}`or `{"hc2"{"daytemp":21}}` +In direct commands it's possible to combine commands, i.e. `{"hc1":{"daytemp":21,"nighttemp":17},"hc2":{"daytemp":20}}` +``` +*boiler_cmd* + comfort + flowtemp + wwtemp + boilhyston (negative value) + boilhystoff (positive value) + burnperiod + burnminpower <%> + burnmaxpower <%> + pumpdelay + +*thermostat_cmd* +--- without hc --- + wwmode + calinttemp + minexttemp + building + language (0=de, 1=nl, 2=fr, 3=it) only RC30 + display (0=int temp, 1= int set, 2=ext. temp, 3=burner, 4=ww, 5=mode, 6=time, 7=date, 8=smoke) only RC30 + clockoffset (only RC30) +--- with hc --- + mode + temp + nighttemp + daytemp + nofrosttemp + ecotemp + heattemp + summertemp + designtemp + offsettemp + holidaytemp + remotetemp + control <0 | 1 | 2> + pause + party + holiday + date + +*cmd* + send <"0B XX XX .."> + D0 <0 | 1> + D1 <0 | 1> + D2 <0 | 1> + D3 <0 | 1> + +``` ### **Basic Design Principles**