From 8ea4c7887ffd50a904b4e8ec0ea12d42f7f2a154 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:25:34 +0200 Subject: [PATCH 01/10] Move I2C2 test up front --- tasmota/include/tasmota_globals.h | 7 +++++++ tasmota/tasmota_support/support_a_i2c.ino | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tasmota/include/tasmota_globals.h b/tasmota/include/tasmota_globals.h index 2f51f860c..db8d24f0c 100644 --- a/tasmota/include/tasmota_globals.h +++ b/tasmota/include/tasmota_globals.h @@ -194,6 +194,13 @@ const char WIFI_HOSTNAME[] = WIFI_DEFAULT_HOSTNAME; // Override by user_confi #define ARDUINO_CORE_RELEASE ARDUINO_ESP32_RELEASE #endif // ARDUINO_ESP32_RELEASE +#ifdef USE_I2C_BUS2 // If defined for ESP8266 undefine first +#undef USE_I2C_BUS2 +#endif // USE_I2C_BUS2 +#if SOC_HP_I2C_NUM > 1 +#define USE_I2C_BUS2 // Redefine based on hardware support +#endif // SOC_HP_I2C_NUM + // Hardware has no ESP32 #undef USE_EXS_DIMMER #undef USE_ARMTRONIX_DIMMERS diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index d5a602207..0af7450d6 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -17,12 +17,6 @@ #endif // USE_I2C_BUS2_ESP8266 #endif // ESP8266 -#ifdef ESP32 -#if SOC_HP_I2C_NUM > 1 -#define USE_I2C_BUS2 -#endif // SOC_HP_I2C_NUM -#endif // ESP32 - const uint8_t I2C_RETRY_COUNTER = 3; struct I2Ct { From f9ee4198e11f0f2ec32a2c04ad23402bbf28cf62 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:38:04 +0200 Subject: [PATCH 02/10] Fix compile error when wire1 is unavailable --- tasmota/tasmota_support/support_a_i2c.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index 0af7450d6..c857240cd 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -63,7 +63,12 @@ bool I2cBegin(int sda, int scl, uint32_t bus, uint32_t frequency) { #endif // USE_I2C_BUS2_ESP8266 #endif // ESP8266 #ifdef ESP32 +#ifdef USE_I2C_BUS2 TwoWire& myWire = (0 == bus) ? Wire : Wire1; +#else + if (bus > 0) { return false; } + TwoWire& myWire = Wire; +#endif static bool reinit = false; if (reinit) { myWire.end(); } result = myWire.begin(sda, scl, frequency); From 154f478b5c2771eb2705bb5a63dc736d1f32e4f5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:44:05 +0200 Subject: [PATCH 03/10] Fix Berry I2C2 compilation --- tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino index 5cce357ee..9d57c0398 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino @@ -35,8 +35,10 @@ TwoWire & getWire(bvm *vm) { be_pop(vm, 1); if (1 == bus && TasmotaGlobal.i2c_enabled) { return Wire; +#ifdef USE_I2C_BUS2 } else if (2 == bus && TasmotaGlobal.i2c_enabled_2) { return Wire1; +#endif // USE_I2C_BUS2 } else { be_raise(vm, "configuration_error", "I2C bus not initiliazedd"); return *(TwoWire*)nullptr; From b53ac4a14ecf1cf814b182c2a88a56991bf3b37a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 11 Oct 2024 14:11:00 +0200 Subject: [PATCH 04/10] Fix next core I2C2 compilation --- lib/lib_display/UDisplay/uDisplay.cpp | 6 +++--- lib/lib_i2c/BM8563_RTC/src/BM8563.h | 10 +++++----- lib/lib_i2c/MPU_accel/src/MPU_accel.h | 6 +++--- tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino | 6 +++--- tasmota/tasmota_xdsp_display/xdsp_17_universal.ino | 4 ++-- tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index e4610223d..4af702125 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -242,7 +242,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { if (wire_n == 1) { wire = &Wire; } else { -#ifdef ESP32 +#if SOC_HP_I2C_NUM > 1 wire = &Wire1; #else wire = &Wire; @@ -636,7 +636,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { if (ut_mode == 1) { ut_wire = &Wire; } else { -#ifdef ESP32 +#if SOC_HP_I2C_NUM > 1 ut_wire = &Wire1; #else ut_wire = &Wire; @@ -1076,7 +1076,7 @@ Renderer *uDisplay::Init(void) { if (wire_n == 0) { wire = &Wire; } -#ifdef ESP32 +#if SOC_HP_I2C_NUM > 1 if (wire_n == 1) { wire = &Wire1; } diff --git a/lib/lib_i2c/BM8563_RTC/src/BM8563.h b/lib/lib_i2c/BM8563_RTC/src/BM8563.h index dc7867b22..fbba8d752 100644 --- a/lib/lib_i2c/BM8563_RTC/src/BM8563.h +++ b/lib/lib_i2c/BM8563_RTC/src/BM8563.h @@ -24,11 +24,11 @@ typedef struct class BM8563 { public: BM8563(); - #ifdef ESP32 - void setBus(uint32_t _bus) { myWire = _bus ? &Wire1 : &Wire; }; - #else - void setBus(uint32_t _bus) { myWire = &Wire; }; - #endif +#if SOC_HP_I2C_NUM > 1 + void setBus(uint32_t _bus) { myWire = _bus ? &Wire1 : &Wire; }; +#else + void setBus(uint32_t _bus) { myWire = &Wire; }; +#endif void begin(void); void GetBm8563Time(void); diff --git a/lib/lib_i2c/MPU_accel/src/MPU_accel.h b/lib/lib_i2c/MPU_accel/src/MPU_accel.h index 7b522a836..f3f027a21 100755 --- a/lib/lib_i2c/MPU_accel/src/MPU_accel.h +++ b/lib/lib_i2c/MPU_accel/src/MPU_accel.h @@ -74,11 +74,11 @@ class MPU_accel { uint32_t model = 6886; // MPU model number public: MPU_accel(void) {}; - #ifdef ESP32 +#if SOC_HP_I2C_NUM > 1 void setBus(uint32_t _bus) { myWire = _bus ? &Wire1 : &Wire; }; - #else +#else void setBus(uint32_t _bus) { myWire = &Wire; }; - #endif +#endif int Init(void); uint32_t getModel(void) const { return model; } void getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 0f6dbccb2..df86f9e6b 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -13160,7 +13160,7 @@ uint32_t script_i2c(uint8_t sel, uint16_t val, uint32_t val1) { switch (sel) { case 0: glob_script_mem.script_i2c_addr = val; -#ifdef ESP32 +#if defined(ESP32) && defined(USE_I2C_BUS2) if (val1 == 0) glob_script_mem.script_i2c_wire = &Wire; else glob_script_mem.script_i2c_wire = &Wire1; #else @@ -13209,7 +13209,7 @@ uint32_t script_i2c(uint8_t sel, uint16_t val, uint32_t val1) { glob_script_mem.script_i2c_wire->endTransmission(); break; case 14: - #ifdef ESP32 +#if defined(ESP32) && defined(USE_I2C_BUS2) Wire1.end(); Wire1.begin(val & 0x7f, val1); glob_script_mem.script_i2c_wire = &Wire1; @@ -13217,7 +13217,7 @@ uint32_t script_i2c(uint8_t sel, uint16_t val, uint32_t val1) { if (val & 128) { XsnsCall(FUNC_INIT); } - #endif +#endif break; } return rval; diff --git a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino index f376ee8c2..5c19209fa 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino @@ -397,7 +397,7 @@ Renderer *Init_uDisplay(const char *desc) { if (!wire_n) { GT911_Touch_Init(&Wire, irq, rst, xs, ys); } -#ifdef ESP32 +#if defined(ESP32) && defined(USE_I2C_BUS2) else { GT911_Touch_Init(&Wire1, irq, rst, xs, ys); } @@ -414,7 +414,7 @@ Renderer *Init_uDisplay(const char *desc) { if (!wire_n) { FT5206_Touch_Init(Wire); } -#ifdef ESP32 +#if defined(ESP32) && defined(USE_I2C_BUS2) else { FT5206_Touch_Init(Wire1); } diff --git a/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino b/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino index be21ff1e9..7d014bd1a 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino @@ -75,7 +75,7 @@ void sen5x_Init(void) { sen5x = new SensirionI2CSen5x(); if (1 == usingI2cBus) { -#ifdef ESP32 +#if defined(ESP32) && defined(USE_I2C_BUS2) sen5x->begin(Wire1); #else sen5x->begin(Wire); From 4b06cb27b0395d62b0e52465d1cd00e65c63e835 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:27:12 +0200 Subject: [PATCH 05/10] Adhere to DALI naming --- CHANGELOG.md | 8 ++++---- RELEASENOTES.md | 8 ++++---- tasmota/include/tasmota_template.h | 2 +- tasmota/include/tasmota_types.h | 2 +- tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1bcfd51b..b4b30c4e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,8 @@ All notable changes to this project will be documented in this file. - Support for Sonoff SPM v1.3.0 (#13447) - LVGL port `colorwheel` from LVGL 8 (#22244) - HASPmota `cpicker` and `msgbox` (#22244) -- Support for DALI 1 on ESP8266 -- Command ``DaliWeb 1`` to enable light control for Dali broadcast address +- Support for DALI on ESP8266 +- Command ``DaliWeb 1`` to enable light control for DALI broadcast address ### Breaking Changed @@ -23,8 +23,8 @@ All notable changes to this project will be documented in this file. - ESP32 Range Extender compile error with core 3.0.0 (#22205) - HASPmota error when page '1' is not defined (#22220) - ESP32-S3 uDisplay force cache writes to RGB display (#22222) -- ESP32 Dali compile error with core 3.x (#22214) -- Dali received data decoding +- ESP32 DALI compile error with core 3.x (#22214) +- DALI received data decoding - ESP32 Ethernet using EthClockMode 3 (#22248) - ESP32 disable SPI DMA for uDisplay (broken since esp-idf 5.3 (core 3.1.0)) (#22264) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 86402535f..ec8df8087 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -117,12 +117,12 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ## Changelog v14.2.0.6 ### Added - Command ``SetOption69 1`` to enable Serial Bridge inverted Receive [#22000](https://github.com/arendst/Tasmota/issues/22000) -- Command ``DaliWeb 1`` to enable light control for Dali broadcast address +- Command ``DaliWeb 1`` to enable light control for DALI broadcast address - HX711 optional calibration precision option on command ``Sensor34 2 `` where `` is 1 to 20 [#13983](https://github.com/arendst/Tasmota/issues/13983) - ESP8266 support for one-wire M1601 temperature sensor on DS18x20 GPIO [#21376](https://github.com/arendst/Tasmota/issues/21376) - ESP8266 support for I2C CLK on GPIO16 [#22199](https://github.com/arendst/Tasmota/issues/22199) - Support for I2C M5Unit (Mini)Scales using HX711 driver -- Support for DALI 1 on ESP8266 +- Support for DALI on ESP8266 - Support for RX8010 RTC as used in IOTTIMER [#21376](https://github.com/arendst/Tasmota/issues/21376) - Support for BL0906 up to 6 channel energy monitor as used in Athom EM2/EM6 [#22167](https://github.com/arendst/Tasmota/issues/22167) - Support for Sonoff SPM v1.3.0 [#13447](https://github.com/arendst/Tasmota/issues/13447) @@ -161,7 +161,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - HASPmota `delete` instead of `delete()` [#22245](https://github.com/arendst/Tasmota/issues/22245) ### Fixed -- Dali received data decoding +- DALI received data decoding - Compilation exception when metrics not found [#22170](https://github.com/arendst/Tasmota/issues/22170) - Crash when calling TasmotaSerial destructor when initialized with incorrect arguments [#22036](https://github.com/arendst/Tasmota/issues/22036) - Energy calculation [#20653](https://github.com/arendst/Tasmota/issues/20653) @@ -177,7 +177,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Zigbee avoid disabling console serial on ESP32 and improved log messages [#22082](https://github.com/arendst/Tasmota/issues/22082) - Zigbee flashing CC2562P with latest firmware [#22117](https://github.com/arendst/Tasmota/issues/22117) - ESP32 Range Extender compile error with core 3.x [#22205](https://github.com/arendst/Tasmota/issues/22205) -- ESP32 Dali compile error with core 3.x [#22214](https://github.com/arendst/Tasmota/issues/22214) +- ESP32 DALI compile error with core 3.x [#22214](https://github.com/arendst/Tasmota/issues/22214) - ESP32 Ethernet using EthClockMode 3 [#22248](https://github.com/arendst/Tasmota/issues/22248) - ESP32 disable SPI DMA for uDisplay (broken since esp-idf 5.3 (core 3.1.0)) [#22264](https://github.com/arendst/Tasmota/issues/22264) - Berry avoid `readbytes()` from crashing when file is too large [#22057](https://github.com/arendst/Tasmota/issues/22057) diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 59f108fe1..053782636 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -198,7 +198,7 @@ enum UserSelectablePins { GPIO_ADE7953_RST, // ADE7953 Reset GPIO_NRG_MBS_TX, GPIO_NRG_MBS_RX, // Generic Energy Modbus device GPIO_ADE7953_CS, // ADE7953 SPI Chip Select - GPIO_DALI_RX, GPIO_DALI_TX, // Dali + GPIO_DALI_RX, GPIO_DALI_TX, // DALI GPIO_BP1658CJ_CLK, GPIO_BP1658CJ_DAT,// BP1658CJ GPIO_DINGTIAN_CLK, GPIO_DINGTIAN_SDI, GPIO_DINGTIAN_Q7, GPIO_DINGTIAN_PL, GPIO_DINGTIAN_RCK, // Dingtian relay board - 595's & 165's pins GPIO_LD2410_TX, GPIO_LD2410_RX, // HLK-LD2410 diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index a8936407e..e7fdbbf0e 100755 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -289,7 +289,7 @@ typedef union { uint32_t influxdb_sensor : 1; // bit 10 (v11.0.0.5) - CMND_IFXSENSOR - Enable sensor support in addition to teleperiod support uint32_t ex_serbridge_console : 1; // bit 11 (v11.1.0.4) - (v14.1.0.2) Replaced by CMND_SSERIALMODE uint32_t telegram_disable_af : 1; // bit 12 (v14.0.0.2) - CMND_TMSTATE 6/7 - Disable Telegram auto-fingerprint fix - uint32_t dali_web : 1; // bit 13 (v14.2.0.6) - CMND_DALIWEB - Enable Dali web controls + uint32_t dali_web : 1; // bit 13 (v14.2.0.6) - CMND_DALIWEB - Enable DALI web controls uint32_t spare14 : 1; // bit 14 uint32_t spare15 : 1; // bit 15 uint32_t spare16 : 1; // bit 16 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino index 2789ca948..da1fab749 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino @@ -22,11 +22,11 @@ 0.1.0.3 20241010 update - Change DaliDimmer range from 0..254 to 0..100 - Add command DaliWeb 0|1 to enable persistent Web light controls 0.1.0.2 20241008 update - Better receive error detection - 0.1.0.1 20241007 update - To stablizie communication send Dali datagram twice like Busch-Jaeger does + 0.1.0.1 20241007 update - To stablizie communication send DALI datagram twice like Busch-Jaeger does - Change DaliPower 0..2 to act like Tasmota Power (Off, On, Toggle) - Keep last Dimmer value as default power on 0.1.0.0 20241006 rewrite - Add support for ESP8266 - - Fix decoding of received Dali 1 data + - Fix decoding of received DALI data - Refactor command `DaliPower 0..254` controlling Broadcast devices - Add command `DaliDimmer 0..254` controlling Broadcast devices 0.0.0.1 20221027 publish - Initial version From 63d44c8b30697dcb52b77858f7ff898dfe11b3b9 Mon Sep 17 00:00:00 2001 From: Grzegorz Date: Sun, 13 Oct 2024 11:09:51 +0200 Subject: [PATCH 06/10] Add prohibit function for MiElHVAC (#22269) Add Prohibit functions: * Power * Temperature * Mode and all combinations of this functions Updated VaneV names for better identify --- .../tasmota_xdrv_driver/xdrv_44_miel_hvac.ino | 80 +++++++++++++++++-- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino index 0d0661d6c..3b7e6da5d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino @@ -42,6 +42,7 @@ #define D_CMND_MIEL_HVAC_SETSWINGV "HVACSetSwingV" #define D_CMND_MIEL_HVAC_SETSWINGH "HVACSetSwingH" #define D_CMND_MIEL_HVAC_SETAIRDIRECTION "HVACSetAirDirection" +#define D_CMND_MIEL_HVAC_SETPROHIBIT "HVACSetProhibit" #define D_CMND_MIEL_HVAC_REMOTETEMP "HVACRemoteTemp" #include @@ -71,7 +72,8 @@ struct miel_hvac_data_settings { uint8_t temp; uint8_t fan; uint8_t vane; - uint8_t _pad2[2]; + uint8_t prohibit; + uint8_t _pad2[1]; uint8_t widevane; #define MIEL_HVAC_SETTTINGS_WIDEVANE_MASK \ 0x0f @@ -120,6 +122,7 @@ CTASSERT(offsetof(struct miel_hvac_data, data.settings.mode) == 4); CTASSERT(offsetof(struct miel_hvac_data, data.settings.temp) == 5); CTASSERT(offsetof(struct miel_hvac_data, data.settings.fan) == 6); CTASSERT(offsetof(struct miel_hvac_data, data.settings.vane) == 7); +CTASSERT(offsetof(struct miel_hvac_data, data.settings.prohibit) == 8); CTASSERT(offsetof(struct miel_hvac_data, data.settings.widevane) == 10); CTASSERT(offsetof(struct miel_hvac_data, data.settings.temp05) == 11); CTASSERT(offsetof(struct miel_hvac_data, data.settings.airdirection) == 14); @@ -155,7 +158,8 @@ struct miel_hvac_msg_update { #define MIEL_HVAC_UPDATE_F_TEMP (1 << 10) #define MIEL_HVAC_UPDATE_F_FAN (1 << 11) #define MIEL_HVAC_UPDATE_F_VANE (1 << 12) -#define MIEL_HVAC_UPDATE_F_AIRDIRECTION (1 << 13) +#define MIEL_HVAC_UPDATE_F_PROHIBIT (1 << 13) +#define MIEL_HVAC_UPDATE_F_AIRDIRECTION (1 << 14) uint8_t power; #define MIEL_HVAC_UPDATE_POWER_OFF 0x00 #define MIEL_HVAC_UPDATE_POWER_ON 0x01 @@ -190,7 +194,16 @@ struct miel_hvac_msg_update { #define MIEL_HVAC_UPDATE_VANE_4 0x04 #define MIEL_HVAC_UPDATE_VANE_5 0x05 #define MIEL_HVAC_UPDATE_VANE_SWING 0x07 - uint8_t _pad1[5]; + uint8_t prohibit; +#define MIEL_HVAC_UPDATE_PROHIBIT_OFF 0x00 +#define MIEL_HVAC_UPDATE_PROHIBIT_POWER 0x01 +#define MIEL_HVAC_UPDATE_PROHIBIT_MODE 0x02 +#define MIEL_HVAC_UPDATE_PROHIBIT_MODE_POWER 0x03 +#define MIEL_HVAC_UPDATE_PROHIBIT_TEMP 0x04 +#define MIEL_HVAC_UPDATE_PROHIBIT_TEMP_POWER 0x05 +#define MIEL_HVAC_UPDATE_PROHIBIT_TEMP_MODE 0x06 +#define MIEL_HVAC_UPDATE_PROHIBIT_ALL 0x07 + uint8_t _pad1[4]; uint8_t widevane; #define MIEL_HVAC_UPDATE_WIDEVANE_MASK 0x0f #define MIEL_HVAC_UPDATE_WIDEVANE_ISEE 0x00 @@ -217,6 +230,7 @@ CTASSERT(offsetof(struct miel_hvac_msg_update, mode) == MIEL_HVAC_OFFS(9)); CTASSERT(offsetof(struct miel_hvac_msg_update, temp) == MIEL_HVAC_OFFS(10)); CTASSERT(offsetof(struct miel_hvac_msg_update, fan) == MIEL_HVAC_OFFS(11)); CTASSERT(offsetof(struct miel_hvac_msg_update, vane) == MIEL_HVAC_OFFS(12)); +CTASSERT(offsetof(struct miel_hvac_msg_update, prohibit) == MIEL_HVAC_OFFS(13)); CTASSERT(offsetof(struct miel_hvac_msg_update, widevane) == MIEL_HVAC_OFFS(18)); CTASSERT(offsetof(struct miel_hvac_msg_update, temp05) == MIEL_HVAC_OFFS(19)); CTASSERT(offsetof(struct miel_hvac_msg_update, airdirection) == MIEL_HVAC_OFFS(20)); @@ -312,11 +326,11 @@ static const struct miel_hvac_map miel_hvac_fan_map[] = { static const struct miel_hvac_map miel_hvac_vane_map[] = { { MIEL_HVAC_UPDATE_VANE_AUTO, "auto" }, - { MIEL_HVAC_UPDATE_VANE_1, "1" }, - { MIEL_HVAC_UPDATE_VANE_2, "2" }, - { MIEL_HVAC_UPDATE_VANE_3, "3" }, - { MIEL_HVAC_UPDATE_VANE_4, "4" }, - { MIEL_HVAC_UPDATE_VANE_5, "5" }, + { MIEL_HVAC_UPDATE_VANE_1, "up" }, + { MIEL_HVAC_UPDATE_VANE_2, "up_middle" }, + { MIEL_HVAC_UPDATE_VANE_3, "center" }, + { MIEL_HVAC_UPDATE_VANE_4, "down_middle" }, + { MIEL_HVAC_UPDATE_VANE_5, "down" }, { MIEL_HVAC_UPDATE_VANE_SWING, "swing" }, }; @@ -331,6 +345,17 @@ static const struct miel_hvac_map miel_hvac_widevane_map[] = { { MIEL_HVAC_UPDATE_WIDEVANE_SWING, "swing" }, }; +static const struct miel_hvac_map miel_hvac_prohibit_map[] = { + { MIEL_HVAC_UPDATE_PROHIBIT_OFF, "off" }, + { MIEL_HVAC_UPDATE_PROHIBIT_POWER, "power" }, + { MIEL_HVAC_UPDATE_PROHIBIT_MODE, "mode" }, + { MIEL_HVAC_UPDATE_PROHIBIT_MODE_POWER, "mode_power" }, + { MIEL_HVAC_UPDATE_PROHIBIT_TEMP, "temp" }, + { MIEL_HVAC_UPDATE_PROHIBIT_TEMP_POWER, "temp_power" }, + { MIEL_HVAC_UPDATE_PROHIBIT_TEMP_MODE, "temp_mode" }, + { MIEL_HVAC_UPDATE_PROHIBIT_ALL, "all" }, +}; + static const struct miel_hvac_map miel_hvac_airdirection_map[] = { { MIEL_HVAC_UPDATE_AIRDIRECTION_EVEN, "even" }, { MIEL_HVAC_UPDATE_AIRDIRECTION_INDIRECT, "indirect" }, @@ -789,6 +814,29 @@ miel_hvac_cmnd_setvane(void) ResponseCmndChar_P(e->name); } +static void +miel_hvac_cmnd_setprohibit(void) +{ + struct miel_hvac_softc *sc = miel_hvac_sc; + struct miel_hvac_msg_update *update = &sc->sc_update; + const struct miel_hvac_map *e; + + if (XdrvMailbox.data_len == 0) + return; + + e = miel_hvac_map_byname(XdrvMailbox.data, + miel_hvac_prohibit_map, nitems(miel_hvac_prohibit_map)); + if (e == NULL) { + miel_hvac_respond_unsupported(); + return; + } + + update->flags |= htons(MIEL_HVAC_UPDATE_F_PROHIBIT); + update->prohibit = e->byte; + + ResponseCmndChar_P(e->name); +} + static void miel_hvac_cmnd_setwidevane(void) { @@ -1001,6 +1049,13 @@ miel_hvac_publish_settings(struct miel_hvac_softc *sc) name_swing_h == "isee" ? name : "OFF"); } + name = miel_hvac_map_byval(set->prohibit, + miel_hvac_prohibit_map, nitems(miel_hvac_prohibit_map)); + if (name != NULL) { + ResponseAppend_P(PSTR(",\"Prohibit\":\"%s\""), + name); + } + ResponseAppend_P(PSTR(",\"Bytes\":\"%s\""), ToHex_P((uint8_t *)&sc->sc_settings, sizeof(sc->sc_settings), hex, sizeof(hex))); @@ -1231,6 +1286,13 @@ miel_hvac_sensor(struct miel_hvac_softc *sc) name_swing_h == "isee" ? name : "OFF"); } + name = miel_hvac_map_byval(set->prohibit, + miel_hvac_prohibit_map, nitems(miel_hvac_prohibit_map)); + if (name != NULL) { + ResponseAppend_P(PSTR(",\"Prohibit\":\"%s\""), + name); + } + ResponseAppend_P(PSTR(",\"Bytes\":\"%s\""), ToHex_P((uint8_t *)&sc->sc_settings, sizeof(sc->sc_settings), hex, sizeof(hex))); @@ -1395,6 +1457,7 @@ static const char miel_hvac_cmnd_names[] PROGMEM = "|" D_CMND_MIEL_HVAC_SETSWINGV "|" D_CMND_MIEL_HVAC_SETSWINGH "|" D_CMND_MIEL_HVAC_SETAIRDIRECTION + "|" D_CMND_MIEL_HVAC_SETPROHIBIT "|" D_CMND_MIEL_HVAC_REMOTETEMP #ifdef MIEL_HVAC_DEBUG "|" "HVACRequest" @@ -1409,6 +1472,7 @@ static void (*const miel_hvac_cmnds[])(void) PROGMEM = { &miel_hvac_cmnd_setvane, &miel_hvac_cmnd_setwidevane, &miel_hvac_cmnd_setairdirection, + &miel_hvac_cmnd_setprohibit, &miel_hvac_cmnd_remotetemp, #ifdef MIEL_HVAC_DEBUG &miel_hvac_cmnd_request, From c07b8a59c000ec490f77601762a9a7485b9fa1a5 Mon Sep 17 00:00:00 2001 From: sfromis <47082390+sfromis@users.noreply.github.com> Date: Sun, 13 Oct 2024 11:10:27 +0200 Subject: [PATCH 07/10] Fixing build error xdrv_13_display.ino with JPEG_PICTS (#22265) On ESP32, with `#define JPEG_PICTS` without the scripter, build fails due to the function `Draw_jpeg` being defined after use. Order swapped to satisfy the compiler. Change tested to compile without errors, but not being 100% sure of when/how it is supposed to work, no verification of this. --- .../tasmota_xdrv_driver/xdrv_13_display.ino | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index 545040ef9..a7afe6d47 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -2442,6 +2442,28 @@ void Draw_RGB_Bitmap(char *file, uint16_t xp, uint16_t yp, uint8_t scale, bool i #ifdef ESP32 #ifdef JPEG_PICTS #define JPG_DEFSIZE 150000 +void Draw_jpeg(uint8_t *mem, uint16_t jpgsize, uint16_t xp, uint16_t yp, uint8_t scale) { + if (mem[0] == 0xff && mem[1] == 0xd8) { + uint16_t xsize; + uint16_t ysize; + get_jpeg_size(mem, jpgsize, &xsize, &ysize); + //AddLog(LOG_LEVEL_INFO, PSTR("Pict size %d - %d - %d"), xsize, ysize, jpgsize); + scale &= 3; + uint8_t fac = 1 << scale; + xsize /= fac; + ysize /= fac; + renderer->setAddrWindow(xp, yp, xp + xsize, yp + ysize); + uint8_t *rgbmem = (uint8_t *)special_malloc(xsize * ysize * 2); + if (rgbmem) { + //jpg2rgb565(mem, jpgsize, rgbmem, JPG_SCALE_NONE); + jpg2rgb565(mem, jpgsize, rgbmem, (jpg_scale_t)scale); + renderer->pushColors((uint16_t*)rgbmem, xsize * ysize, true); + free(rgbmem); + } + renderer->setAddrWindow(0, 0, 0, 0); + } +} + void Draw_JPG_from_URL(char *url, uint16_t xp, uint16_t yp, uint8_t scale) { uint8_t *mem = 0; WiFiClient http_client; @@ -2484,28 +2506,6 @@ void Draw_JPG_from_URL(char *url, uint16_t xp, uint16_t yp, uint8_t scale) { } if (mem) free(mem); } - -void Draw_jpeg(uint8_t *mem, uint16_t jpgsize, uint16_t xp, uint16_t yp, uint8_t scale) { - if (mem[0] == 0xff && mem[1] == 0xd8) { - uint16_t xsize; - uint16_t ysize; - get_jpeg_size(mem, jpgsize, &xsize, &ysize); - //AddLog(LOG_LEVEL_INFO, PSTR("Pict size %d - %d - %d"), xsize, ysize, jpgsize); - scale &= 3; - uint8_t fac = 1 << scale; - xsize /= fac; - ysize /= fac; - renderer->setAddrWindow(xp, yp, xp + xsize, yp + ysize); - uint8_t *rgbmem = (uint8_t *)special_malloc(xsize * ysize * 2); - if (rgbmem) { - //jpg2rgb565(mem, jpgsize, rgbmem, JPG_SCALE_NONE); - jpg2rgb565(mem, jpgsize, rgbmem, (jpg_scale_t)scale); - renderer->pushColors((uint16_t*)rgbmem, xsize * ysize, true); - free(rgbmem); - } - renderer->setAddrWindow(0, 0, 0, 0); - } -} #endif // JPEG_PICTS #endif // ESP32 From 0c7e8c67f33c7aa2b77b0cd3914364040061fdca Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 13 Oct 2024 12:03:31 +0200 Subject: [PATCH 08/10] Update changelogs --- CHANGELOG.md | 4 ++++ RELEASENOTES.md | 4 ++++ tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino | 11 ++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b30c4e0..864eda1c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,10 @@ All notable changes to this project will be documented in this file. - ESP8266 experimental support for second I2C bus - Berry improve `int64` constructor (#22172) - MQTT warning if trying to connect without TLS on a port that normally uses TLS (#22175) +- Misubishi Electric HVAC Heat/Dry/Cool ISEE operation mode (#22216) +- Misubishi Electric HVAC Bridge to HomeBridge/Homekit locally (#22236) +- Misubishi Electric HVAC Air Direction Control (#22241) +- Misubishi Electric HVAC prohibit function (#22269) ### Changed - Refactored I2C drivers HTU21, BH1750, SHT3x, iAQ and HYT diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ec8df8087..10e2f87c2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -134,6 +134,10 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Support nexus protocol and calculation of separation limit to rc-switch library [#21886](https://github.com/arendst/Tasmota/issues/21886) - KNX additional KnxTx functions and define KNX_USE_DPT9 [#22071](https://github.com/arendst/Tasmota/issues/22071) - SML multi TRX line [#22056](https://github.com/arendst/Tasmota/issues/22056) +- Misubishi Electric HVAC Heat/Dry/Cool ISEE operation mode [#22216](https://github.com/arendst/Tasmota/issues/22216) +- Misubishi Electric HVAC Bridge to HomeBridge/Homekit locally [#22236](https://github.com/arendst/Tasmota/issues/22236) +- Misubishi Electric HVAC Air Direction Control [#22241](https://github.com/arendst/Tasmota/issues/22241) +- Misubishi Electric HVAC prohibit function [#22269](https://github.com/arendst/Tasmota/issues/22269) - Zigbee Koenkk firmware 20240710 for Sonoff Zigbee ZBPro [#22076](https://github.com/arendst/Tasmota/issues/22076) - Berry Zigbee improvements to prepare Matter [#22083](https://github.com/arendst/Tasmota/issues/22083) - Berry virtual Energy driver [#22134](https://github.com/arendst/Tasmota/issues/22134) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino index da1fab749..f59478848 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino @@ -19,6 +19,7 @@ -------------------------------------------------------------------------------------------- Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + 0.1.0.4 20241013 update - Fix intermittent bad send timing 0.1.0.3 20241010 update - Change DaliDimmer range from 0..254 to 0..100 - Add command DaliWeb 0|1 to enable persistent Web light controls 0.1.0.2 20241008 update - Better receive error detection @@ -148,9 +149,7 @@ void DaliSendDataOnce(uint16_t send_dali_data) { bool pin_value = bit_value ? LOW : HIGH; // Invert bit digitalWrite(Dali->pin_tx, (pin_value == DALI_OUT_INVERT) ? LOW : HIGH); wait += Dali->bit_time; // Auto roll-over - while (ESP.getCycleCount() < wait) { - optimistic_yield(1); - } + while (ESP.getCycleCount() < wait); } } @@ -169,8 +168,10 @@ void DaliSendData(uint8_t firstByte, uint8_t secondByte) { DaliDisableRxInterrupt(); delay(3); // Settling time between forward and backward frame DaliSendDataOnce(send_dali_data); // Takes 14.5 ms - delay(14); // As used by Busch-Jaeger - DaliSendDataOnce(send_dali_data); // Takes 14.5 ms + if (DALI_BROADCAST_DP == firstByte) { + delay(14); // As used by Busch-Jaeger and suggested by DALI protocol (> 9.17 ms) + DaliSendDataOnce(send_dali_data); // Takes 14.7 ms + } delay(3); // Block response DaliEnableRxInterrupt(); } From 314fcd0dbc2504bc3e22ab7975bc2f034f0505bb Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 13 Oct 2024 22:15:47 +0200 Subject: [PATCH 09/10] Berry Serial `config` to change parity on-the-fly for RS-485 (#22285) --- CHANGELOG.md | 1 + .../TasmotaSerial-3.6.0/src/TasmotaSerial.cpp | 36 +++++++++++++++++++ .../TasmotaSerial-3.6.0/src/TasmotaSerial.h | 1 + .../berry_tasmota/src/be_serial_lib.c | 2 ++ .../xdrv_52_3_berry_serial.ino | 15 ++++++++ 5 files changed, 55 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 864eda1c9..47eefda92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - HASPmota `cpicker` and `msgbox` (#22244) - Support for DALI on ESP8266 - Command ``DaliWeb 1`` to enable light control for DALI broadcast address +- Berry Serial `config` to change parity on-the-fly for RS-485 ### Breaking Changed diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp index ef8f87596..119b6d149 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp @@ -476,6 +476,42 @@ size_t TasmotaSerial::write(uint8_t b) { return size; } +#ifdef ESP32 +// Add ability to change parity on the fly, for RS-485 +// See https://github.com/arendst/Tasmota/discussions/22272 +int32_t TasmotaSerial::setConfig(uint32_t config) { + + uint32_t data_bits_before = (m_config & 0xc) >> 2; + uint32_t parity_before = m_config & 0x3; + uint32_t stop_bits_before = (m_config & 0x30) >> 4; + + uint32_t data_bits = (config & 0xc) >> 2; + uint32_t parity = config & 0x3; + uint32_t stop_bits = (config & 0x30) >> 4; + + esp_err_t err; + + if (data_bits_before != data_bits) { + if (err = uart_set_word_length(m_uart, (uart_word_length_t) data_bits)) { + return (int32_t) err; + } + } + if (parity_before != parity) { + if (err = uart_set_parity(m_uart, (uart_parity_t) parity)) { + return (int32_t) err; + } + } + if (stop_bits_before != stop_bits) { + if (err = uart_set_stop_bits(m_uart, (uart_stop_bits_t) stop_bits)) { + return (int32_t) err; + } + } + + m_config = config; + return 0; // no error +} +#endif + #ifdef ESP8266 void IRAM_ATTR TasmotaSerial::rxRead(void) { if (!m_nwmode) { diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h index b380bec69..a5928d215 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h @@ -72,6 +72,7 @@ class TasmotaSerial : public Stream { #ifdef ESP32 uint32_t getUart(void) const { return m_uart; } HardwareSerial *getesp32hws(void) { return TSerial; } + int32_t setConfig(uint32_t config); #endif bool isValid(void) { return m_valid; } bool overflow(void); diff --git a/lib/libesp32/berry_tasmota/src/be_serial_lib.c b/lib/libesp32/berry_tasmota/src/be_serial_lib.c index 6592f270d..8de620c6b 100644 --- a/lib/libesp32/berry_tasmota/src/be_serial_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_serial_lib.c @@ -10,6 +10,7 @@ extern int b_serial_init(bvm *vm); extern int b_config_tx_en(bvm *vm); +extern int b_serial_config(bvm *vm); extern int b_serial_deinit(bvm *vm); extern int b_serial_write(bvm *vm); @@ -92,5 +93,6 @@ class be_class_serial (scope: global, name: serial) { read, func(b_serial_read) available, func(b_serial_available) flush, func(b_serial_flush) + config, func(b_serial_config) } @const_object_info_end */ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_serial.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_serial.ino index 810daccf6..e0efe5ae0 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_serial.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_serial.ino @@ -86,6 +86,21 @@ extern "C" { be_return_nil(vm); } + // Berry: `config(config:int) -> nil or exception` + int32_t b_serial_config(struct bvm *vm); + int32_t b_serial_config(struct bvm *vm) { + be_getmember(vm, 1, ".p"); + TasmotaSerial * ser = (TasmotaSerial *) be_tocomptr(vm, -1); + if (ser) { + uint32_t config = be_toint(vm, 2); + int32_t err = ser->setConfig(config); + if (err) { + be_raisef(vm, "internal_error", "Unable to set serial config err %d", err); + } + } + be_return_nil(vm); + } + // Berry: `deinit(void)` int32_t b_serial_deinit(struct bvm *vm); int32_t b_serial_deinit(struct bvm *vm) { From 3969c802423b2376b4027aae64306b9a82603e5c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:27:01 +0200 Subject: [PATCH 10/10] Add DALI commands (#22214) - Add command ``DaliSend
|,`` to send command (address+256 is repeat) on DALI bus - Add command ``DaliQuery
|,`` to send command (address+256 is repeat) on DALI bus and wait up to DALI_TIMEOUT ms for response --- CHANGELOG.md | 4 +- RELEASENOTES.md | 3 + tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino | 246 ++++++++++++++----- 3 files changed, 187 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47eefda92..f8b400112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ All notable changes to this project will be documented in this file. - HASPmota `cpicker` and `msgbox` (#22244) - Support for DALI on ESP8266 - Command ``DaliWeb 1`` to enable light control for DALI broadcast address -- Berry Serial `config` to change parity on-the-fly for RS-485 +- Command ``DaliSend
|,`` to send command (address+256 is repeat) on DALI bus +- Command ``DaliQuery
|,`` to send command (address+256 is repeat) on DALI bus and wait up to DALI_TIMEOUT ms for response +- Berry Serial `config` to change parity on-the-fly for RS-485 (#22285) ### Breaking Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 10e2f87c2..0863a74ae 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -118,6 +118,8 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Added - Command ``SetOption69 1`` to enable Serial Bridge inverted Receive [#22000](https://github.com/arendst/Tasmota/issues/22000) - Command ``DaliWeb 1`` to enable light control for DALI broadcast address +- Command ``DaliSend
|,`` to send command (address+256 is repeat) on DALI bus +- Command ``DaliQuery
|,`` to send command (address+256 is repeat) on DALI bus and wait up to DALI_TIMEOUT ms for response - HX711 optional calibration precision option on command ``Sensor34 2 `` where `` is 1 to 20 [#13983](https://github.com/arendst/Tasmota/issues/13983) - ESP8266 support for one-wire M1601 temperature sensor on DS18x20 GPIO [#21376](https://github.com/arendst/Tasmota/issues/21376) - ESP8266 support for I2C CLK on GPIO16 [#22199](https://github.com/arendst/Tasmota/issues/22199) @@ -142,6 +144,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Berry Zigbee improvements to prepare Matter [#22083](https://github.com/arendst/Tasmota/issues/22083) - Berry virtual Energy driver [#22134](https://github.com/arendst/Tasmota/issues/22134) - Berry improve `int64` constructor [#22172](https://github.com/arendst/Tasmota/issues/22172) +- Berry Serial `config` to change parity on-the-fly for RS-485 [#22285](https://github.com/arendst/Tasmota/issues/22285) - LVGL port `colorwheel` from LVGL 8 [#22244](https://github.com/arendst/Tasmota/issues/22244) - HASPmota `cpicker` and `msgbox` [#22244](https://github.com/arendst/Tasmota/issues/22244) - Matter support for Zigbee Temperature, Humidity and Pressure sensors [#22084](https://github.com/arendst/Tasmota/issues/22084) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino index f59478848..3ede93568 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino @@ -19,9 +19,13 @@ -------------------------------------------------------------------------------------------- Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + 0.1.0.5 20241014 update - Add command `DaliSend [repeat]
,` + - Add command `DaliQuery [repeat]
,` + - Send frame twice (repeat) for DALI defined commands + - Add support for receiving backward frame 0.1.0.4 20241013 update - Fix intermittent bad send timing 0.1.0.3 20241010 update - Change DaliDimmer range from 0..254 to 0..100 - - Add command DaliWeb 0|1 to enable persistent Web light controls + - Add command `DaliWeb 0|1` to enable persistent Web light controls 0.1.0.2 20241008 update - Better receive error detection 0.1.0.1 20241007 update - To stablizie communication send DALI datagram twice like Busch-Jaeger does - Change DaliPower 0..2 to act like Tasmota Power (Off, On, Toggle) @@ -42,7 +46,7 @@ #define XDRV_75 75 #ifndef DALI_IN_INVERT -#define DALI_IN_INVERT 0 // DALI RX inverted ? +#define DALI_IN_INVERT 0 // DALI RX inverted #endif #ifndef DALI_OUT_INVERT #define DALI_OUT_INVERT 0 // DALI TX inverted @@ -50,6 +54,9 @@ #ifndef DALI_INIT_STATE #define DALI_INIT_STATE 50 // DALI init dimmer state 50/254 #endif +#ifndef DALI_TIMEOUT +#define DALI_TIMEOUT 50 // DALI backward frame receive timeout (ms) +#endif //#define DALI_DEBUG #ifndef DALI_DEBUG_PIN @@ -66,14 +73,14 @@ const char kDALICommands[] PROGMEM = D_PRFX_DALI "|" // Prefix #ifdef USE_LIGHT "|Web" #endif // USE_LIGHT - "|" D_CMND_DIMMER ; + "|" D_CMND_DIMMER "|Send|Query" ; void (* const DALICommand[])(void) PROGMEM = { &CmndDali, &CmndDaliPower, #ifdef USE_LIGHT &CmndDaliWeb, #endif // USE_LIGHT - &CmndDaliDimmer }; + &CmndDaliDimmer, &CmndDaliSend, &CmndDaliQuery }; struct DALI { uint32_t bit_time; @@ -85,6 +92,7 @@ struct DALI { uint8_t dimmer; bool power; bool available; + bool response; } *Dali = nullptr; /*********************************************************************************************\ @@ -92,6 +100,7 @@ struct DALI { \*********************************************************************************************/ void DaliEnableRxInterrupt(void) { + Dali->available = false; attachInterrupt(Dali->pin_rx, DaliReceiveData, FALLING); } @@ -103,30 +112,65 @@ void DaliDisableRxInterrupt(void) { void IRAM_ATTR DaliReceiveData(void); // Fix ESP8266 ISR not in IRAM! exception void DaliReceiveData(void) { + /* + Forward frame (1 Start bit + 16 data bits) * 2 bits/bit (manchester encoding) + 2 * 2 Stop bits = 38 bits + DALI data 0xFE64 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 Forward frame + Start and Stop bits 1 1 1 + Manchester data 0101010101010101101001011010011010 + Stop bits 1111 + + Backward frame (1 Start bit + 8 data bits) * 2 bits/bit (manchester encoding) + 2 * 2 Stop bits = 22 bits + DALI data 0x64 0 1 1 0 0 1 0 0 Backward frame + Start and Stop bits 1 1 1 + Manchester data 011001011010011010 + Stop bits 1111 + + Bit number 01234567890123456789012345678901234567 + 1 2 3 + */ if (Dali->available) { return; } // Skip if last input is not yet handled uint32_t wait = ESP.getCycleCount() + (Dali->bit_time / 2); int bit_state = 0; bool dali_read; uint32_t received_dali_data = 0; - uint32_t bit_pos = 15; - for (uint32_t i = 0; i < 36; i++) { // (1 Start bit, 16 data bits, 1 stop bit) * 2 bits/bit (manchester encoding) + uint32_t bit_number = 0; + while (bit_number < 38) { while (ESP.getCycleCount() < wait); wait += Dali->bit_time; // Auto roll-over - if (abs(bit_state) <= 2) { // Manchester encoding max 2 consecutive equal bits - dali_read = digitalRead(Dali->pin_rx); + dali_read = digitalRead(Dali->pin_rx); #ifdef DALI_DEBUG - digitalWrite(DALI_DEBUG_PIN, i&1); // Add LogicAnalyzer poll indication + digitalWrite(DALI_DEBUG_PIN, bit_number&1); // Add LogicAnalyzer poll indication #endif // DALI_DEBUG + if (bit_number < 34) { // 34 manchester encoded bits bit_state += (dali_read) ? 1 : -1; - if ((i >= 2) && (i <= 34)) { // 32 manchester encoded data bits - if (i &1) { // 16 data bits - received_dali_data |= ((DALI_IN_INVERT) ? !dali_read : dali_read << bit_pos--); + if (0 == bit_state) { // Manchester encoding total 2 bits is always 0 + if (bit_number > 2) { // Skip start bit + received_dali_data <<= 1; + received_dali_data |= (DALI_IN_INVERT) ? !dali_read : dali_read; } } + else if ((2 == bit_state) && + (bit_number == 19)) { // Possible backward frame detected - Chk stop bits + bit_state = 0; + bit_number = 35; + } + else if (abs(bit_state) > 1) { // Invalid manchester data + break; + } + } else { // 4 high Stop bits + if (bit_state != 0) { // Invalid manchester data + break; + } + else if (dali_read != 1) { // Invalid level of stop bit + bit_state = 1; + break; + } } + bit_number++; } - if (abs(bit_state) <= 2) { // Valid Manchester encoding including start and stop bits - if (Dali->received_dali_data != received_dali_data) { // Skip duplicates + if (0 == bit_state) { // Valid Manchester encoding including start and stop bits + if (Dali->response || // Response from last message send + (Dali->received_dali_data != received_dali_data)) { // Skip duplicates Dali->received_dali_data = received_dali_data; Dali->available = true; // Valid data received } @@ -136,10 +180,20 @@ void DaliReceiveData(void) { /*************** S E N D * P R O C E D U R E ***************/ void DaliSendDataOnce(uint16_t send_dali_data) { + /* + DALI protocol forward frame + DALI data 0xFE64 1 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 + Start and Stop bits 1 1 1 + Manchester data 0101010101010101101001011010011010 + Stop bits 1111 + + Bit number 01234567890123456789012345678901234567 + 1 2 3 + */ bool bit_value; uint32_t bit_pos = 15; uint32_t wait = ESP.getCycleCount(); - for (uint32_t i = 0; i < 35; i++) { + for (uint32_t i = 0; i < 35; i++) { // 417 * 35 = 14.7 ms if (0 == (i &1)) { // Even bit // Start bit, Stop bit, Data bits bit_value = (0 == i) ? 1 : (34 == i) ? 0 : (bool)((send_dali_data >> bit_pos--) &1); // MSB first @@ -151,32 +205,66 @@ void DaliSendDataOnce(uint16_t send_dali_data) { wait += Dali->bit_time; // Auto roll-over while (ESP.getCycleCount() < wait); } +// delayMicroseconds(1100); // Adds to total 15.8 ms } -void DaliSendData(uint8_t firstByte, uint8_t secondByte) { - Dali->address = firstByte; - Dali->command = secondByte; - if (DALI_BROADCAST_DP == firstByte) { - Dali->power = (secondByte); // State +void DaliSendData(uint32_t adr, uint32_t cmd) { + bool repeat = (adr &0x100); // Set repeat if bit 8 is set + adr &= 0xFF; + cmd &= 0xFF; + + Dali->address = adr; + Dali->command = cmd; + if (DALI_BROADCAST_DP == adr) { + repeat = true; + Dali->power = (cmd); // State if (Dali->power) { - Dali->dimmer = secondByte; // Value + Dali->dimmer = cmd; // Value } } - uint16_t send_dali_data = firstByte << 8; - send_dali_data += secondByte & 0xff; + + if (!repeat && (adr &0x01)) { // YAAAAAA1 Commands where user didn't set repeat + if ((adr >= 0xA1) && (adr <= 0xFD)) { // Special commands + repeat = ((0xA5 == adr) || (0xA7 == adr)); + } else { + // ((cmd >=0) && (cmd <= 31)) // Arc power control commands + repeat = (((cmd >=32) && (cmd <= 143)) || // Configuration commands + ((cmd >=224) && (cmd <= 236))); // Extended configuration commands + // ((cmd >=144) && (cmd <= 223)) // Query commands + // ((cmd >=237) && (cmd <= 255)) // Extended query commands + } + } + + uint16_t send_dali_data = adr << 8 | cmd; DaliDisableRxInterrupt(); delay(3); // Settling time between forward and backward frame - DaliSendDataOnce(send_dali_data); // Takes 14.5 ms - if (DALI_BROADCAST_DP == firstByte) { + DaliSendDataOnce(send_dali_data); // Takes 14.7 ms + if (repeat) { delay(14); // As used by Busch-Jaeger and suggested by DALI protocol (> 9.17 ms) DaliSendDataOnce(send_dali_data); // Takes 14.7 ms } - delay(3); // Block response + delay(2); // Block response DaliEnableRxInterrupt(); } -void DaliPower(uint8_t val) { +int DaliSendWaitResponse(uint32_t adr, uint32_t cmd, uint32_t timeout = DALI_TIMEOUT); +int DaliSendWaitResponse(uint32_t adr, uint32_t cmd, uint32_t timeout) { + Dali->response = true; + DaliSendData(adr, cmd); + while (!Dali->available && timeout--) { // Expect backward frame within DALI_TIMEOUT ms + delay(1); + }; + int result = -1; // DALI NO or no response + if (Dali->available) { + Dali->available = false; + result = Dali->received_dali_data; + } + Dali->response = false; + return result; +} + +void DaliPower(uint32_t val) { DaliSendData(DALI_BROADCAST_DP, val); } @@ -184,7 +272,7 @@ void DaliPower(uint8_t val) { void ResponseAppendDali(void) { uint8_t dimmer = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); - ResponseAppend_P(PSTR("\"" D_PRFX_DALI "\":{\"Power\":\"%s\",\"Dimmer\":%d,\"Address\":%d,\"Command\":%d}"), + ResponseAppend_P(PSTR("\"DALI\":{\"Power\":\"%s\",\"Dimmer\":%d,\"Address\":%d,\"Command\":%d}"), GetStateText(Dali->power), dimmer, Dali->address, Dali->command); } @@ -195,47 +283,49 @@ void ResponseDali(void) { } void DaliInput(void) { - if (Dali->available) { - Dali->address = Dali->received_dali_data >> 8; - Dali->command = Dali->received_dali_data; + if (!Dali->available || Dali->response) { return; } + + Dali->address = Dali->received_dali_data >> 8; + Dali->command = Dali->received_dali_data; #ifdef USE_LIGHT - if (DALI_BROADCAST_DP == Dali->address) { - uint8_t dimmer_old = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); - uint8_t power_old = Dali->power; - Dali->power = (Dali->command); // State - if (Dali->power) { - Dali->dimmer = Dali->command; // Value - } - if (Settings->sbflag1.dali_web) { // DaliWeb 1 - uint8_t dimmer_new = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); - if (power_old != Dali->power) { - ExecuteCommandPower(LightDevice(), Dali->power, SRC_SWITCH); - } - else if (dimmer_old != dimmer_new) { - char scmnd[20]; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), dimmer_new); - ExecuteCommand(scmnd, SRC_SWITCH); - } - } + bool show_response = true; + if (DALI_BROADCAST_DP == Dali->address) { + uint8_t dimmer_old = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); + uint8_t power_old = Dali->power; + Dali->power = (Dali->command); // State + if (Dali->power) { + Dali->dimmer = Dali->command; // Value } - if (!Settings->sbflag1.dali_web) { // DaliWeb 0 - ResponseDali(); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_PRFX_DALI)); - } -#else - if (DALI_BROADCAST_DP == Dali->address) { - Dali->power = (Dali->command); // State - if (Dali->power) { - Dali->dimmer = Dali->command; // Value + if (Settings->sbflag1.dali_web) { // DaliWeb 1 + uint8_t dimmer_new = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); + if (power_old != Dali->power) { + ExecuteCommandPower(LightDevice(), Dali->power, SRC_SWITCH); } + else if (dimmer_old != dimmer_new) { + char scmnd[20]; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), dimmer_new); + ExecuteCommand(scmnd, SRC_SWITCH); + } + show_response = false; } + } + if (show_response) { ResponseDali(); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_PRFX_DALI)); + } +#else + if (DALI_BROADCAST_DP == Dali->address) { + Dali->power = (Dali->command); // State + if (Dali->power) { + Dali->dimmer = Dali->command; // Value + } + } + ResponseDali(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_PRFX_DALI)); #endif // USE_LIGHT - Dali->available = false; - } + Dali->available = false; } bool DaliInit(void) { @@ -258,7 +348,8 @@ bool DaliInit(void) { #endif // DALI_DEBUG Dali->dimmer = DALI_INIT_STATE; - Dali->bit_time = ESP.getCpuFreqMHz() * 1000000 / 2400; // Manchester twice 1200 bps = 2400 bps = 417 ms + // Manchester twice 1200 bps = 2400 bps = 417 (protocol 416.76 +/- 10%) us + Dali->bit_time = ESP.getCpuFreqMHz() * 1000000 / 2400; DaliEnableRxInterrupt(); @@ -380,14 +471,14 @@ bool DaliJsonParse(void) { int DALIindex = 0; int ADRindex = 0; int8_t DALIdim = -1; - uint8_t DALIaddr = DALI_BROADCAST_DP; + uint32_t DALIaddr = DALI_BROADCAST_DP; JsonParserToken val = root[PSTR("cmd")]; if (val) { - uint8_t cmd = val.getUInt(); + uint32_t cmd = val.getUInt(); val = root[PSTR("addr")]; if (val) { - uint8_t addr = val.getUInt(); + uint32_t addr = val.getUInt(); AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: cmd = %d, addr = %d"), cmd, addr); DaliSendData(addr, cmd); return true; @@ -397,7 +488,7 @@ bool DaliJsonParse(void) { } val = root[PSTR("addr")]; if (val) { - uint8_t addr = val.getUInt(); + uint32_t addr = val.getUInt(); if ((addr >= 0) && (addr < 64)) { DALIaddr = addr << 1; } @@ -451,6 +542,31 @@ void CmndDaliDimmer(void) { ResponseDali(); } +void CmndDaliSend(void) { + // Send command + // Setting bit 8 will repeat command twice + // DaliSend 0x1a5,255 - DALI Initialise (send twice) + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + if (2 == params) { + DaliSendData(values[0] &0x1FF, values[1] &0xFF); + ResponseCmndDone(); + } +} + +void CmndDaliQuery(void) { + // Send command and return response or -1 (no response within DALI_TIMEOUT) + // Setting bit 8 will repeat command twice + // DaliQuery 0xff,0x90 - DALI Query status + // DaliQuery 0xff,144 - DALI Query status + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + if (2 == params) { + int result = DaliSendWaitResponse(values[0] &0x1FF, values[1] &0xFF); + ResponseCmndNumber(result); + } +} + #ifdef USE_LIGHT void CmndDaliWeb(void) { // DaliWeb 0 - Disable GUI light controls