diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf0958ab2..d8a8bd93f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,8 +11,11 @@ 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
+- 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)
### Changed
- ESP32 platform update from 2024.09.10 to 2024.09.30 and Framework (Arduino Core) from v3.0.5 to v3.1.0.240926 (#22203)
@@ -24,8 +27,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)
@@ -55,6 +58,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 12d487b48..09da0cdfa 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -117,12 +117,14 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
## Changelog v14.3.0 Robert
### 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
+- 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)
- 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)
@@ -134,10 +136,15 @@ 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)
- 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)
@@ -161,7 +168,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 +184,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/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/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/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/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/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_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino
index d5a602207..c857240cd 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 {
@@ -69,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);
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_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
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,
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) {
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;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino
index 2789ca948..3ede93568 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino
@@ -19,14 +19,19 @@
--------------------------------------------------------------------------------------------
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
+ 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
@@ -41,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
@@ -49,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
@@ -65,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;
@@ -84,6 +92,7 @@ struct DALI {
uint8_t dimmer;
bool power;
bool available;
+ bool response;
} *Dali = nullptr;
/*********************************************************************************************\
@@ -91,6 +100,7 @@ struct DALI {
\*********************************************************************************************/
void DaliEnableRxInterrupt(void) {
+ Dali->available = false;
attachInterrupt(Dali->pin_rx, DaliReceiveData, FALLING);
}
@@ -102,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
}
@@ -135,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
@@ -148,34 +203,68 @@ 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);
}
+// 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
- delay(14); // As used by Busch-Jaeger
- DaliSendDataOnce(send_dali_data); // Takes 14.5 ms
- delay(3); // Block response
+ 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(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);
}
@@ -183,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);
}
@@ -194,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) {
@@ -257,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();
@@ -379,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;
@@ -396,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;
}
@@ -450,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
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);