diff --git a/CHANGELOG.md b/CHANGELOG.md
index b1fc61941..ebdf907ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,10 +5,13 @@ All notable changes to this project will be documented in this file.
## [14.3.0.1]
### Added
+- BLE track devices with RPA (#22300)
+- DALI support for short addresses and groups
### Breaking Changed
### Changed
+- ESP32 platform update from 2024.09.30 to 2024.10.30 and Framework (Arduino Core) from v3.1.0.240926 to v3.1.0.241015 (#22299)
### Fixed
@@ -30,11 +33,11 @@ All notable changes to this project will be documented in this file.
- 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)
-- Misubishi Electric HVAC Heat/Dry/Cool Auto 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)
-- Misubishi Electric HVAC compressor map and operation power and energy (#22290)
+- Mitsubishi Electric HVAC Heat/Dry/Cool Auto operation mode (#22216)
+- Mitsubishi Electric HVAC Bridge to HomeBridge/Homekit locally (#22236)
+- Mitsubishi Electric HVAC Air Direction Control (#22241)
+- Mitsubishi Electric HVAC prohibit function (#22269)
+- Mitsubishi Electric HVAC compressor map and operation power and energy (#22290)
### 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)
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 17026f8f5..61b6aab1a 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -116,10 +116,13 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
## Changelog v14.3.0.1
### Added
+- DALI support for short addresses and groups
+- BLE track devices with RPA [#22300](https://github.com/arendst/Tasmota/issues/22300)
### Breaking Changed
### Changed
+- ESP32 platform update from 2024.09.30 to 2024.10.30 and Framework (Arduino Core) from v3.1.0.240926 to v3.1.0.241015 [#22299](https://github.com/arendst/Tasmota/issues/22299)
### Fixed
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino
index c11938e3d..1253fc73e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_75_dali.ino
@@ -19,6 +19,11 @@
--------------------------------------------------------------------------------------------
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
+ 0.1.0.7 20241017 update - Add command `DaliCommission 1|2` assigning short addresses
+ - Add command `DaliTarget 0, 1..64, 101..116` to select light control address
+ - Add command `DaliGroup1..16 +|-` to add/remove devices from group
+ - Extend commands `DaliPower` and `DaliDimmer` with index to control short address or group
+ - Remove non-functional MQTT interface
0.1.0.6 20241014 update - Fix received light command loop
- Add send collision detection
0.1.0.5 20241014 update - Add command `DaliSend [repeat],`
@@ -43,6 +48,29 @@
/*********************************************************************************************\
* DALI support for Tasmota
+ *
+ * Available commands:
+ * = 0..255 or 0x00..0xFF + 256/0x100 for optional repeat (send twice)
+ * = 0..255 or 0x00..0xFF - Both decimal and hexadecimal is supported
+ * = 0 - DALI default
+ * = 1..64 - DALI short address + 1
+ * = 101..116 - DALI group + 101
+ * DaliSend , - Execute DALI code and do not expect a DALI backward frame
+ * DaliQuery , - Execute DALI code and report result (DALI backward frame)
+ * DaliCommission 1|2 - Reset (0) or (1)/and commission device short addresses
+ * DaliGroup<1..16> [+]|-,... - Add(+) or Remove(-) devices to/from group
+ * DaliPower|| 0..254 - Control power (0 = Off, 1 = Last dimmer, 2 = Toggle, 3..254 = absolute light brightness)
+ * DaliDimmer|| 0..100 - Control dimmer (0 = Off, 1..100 = precentage of brightness)
+ * DaliWeb 0|1 - Enable Tasmota light control for DaliTarget device
+ * DaliTarget || - Set Tasmota light control device (0, 1..64, 101..116)
+ *
+ * Address type Address byte
+ * ------------------ --------------------
+ * Broadcast address 1111111S
+ * 64 short address 0AAAAAAS
+ * 16 group address 100AAAAS
+ * Special command 101CCCC1 to 110CCCC1
+ * A = Address bit, S = 0 Direct Arc Power control, S = 1 Command, C = Special command
\*********************************************************************************************/
#define XDRV_75 75
@@ -71,18 +99,18 @@
#define D_PRFX_DALI "Dali"
const char kDALICommands[] PROGMEM = D_PRFX_DALI "|" // Prefix
- "|" D_CMND_POWER
+ "|" D_CMND_POWER "|" D_CMND_DIMMER "|Target"
#ifdef USE_LIGHT
"|Web"
#endif // USE_LIGHT
- "|" D_CMND_DIMMER "|Send|Query" ;
+ "|Send|Query|Commission|Group";
void (* const DALICommand[])(void) PROGMEM = {
- &CmndDali, &CmndDaliPower,
+ &CmndDali, &CmndDaliPower, &CmndDaliDimmer, &CmndDaliTarget,
#ifdef USE_LIGHT
&CmndDaliWeb,
#endif // USE_LIGHT
- &CmndDaliDimmer, &CmndDaliSend, &CmndDaliQuery };
+ &CmndDaliSend, &CmndDaliQuery, &CmndDaliCommission, &CmndDaliGroup };
struct DALI {
uint32_t bit_time;
@@ -92,6 +120,7 @@ struct DALI {
uint8_t address;
uint8_t command;
uint8_t dimmer;
+ uint8_t target;
bool power;
bool available;
bool response;
@@ -102,6 +131,35 @@ struct DALI {
* DALI low level
\*********************************************************************************************/
+uint32_t DaliTarget2Address(uint32_t target) {
+ // 1..64 = Short address
+ // 101..116 = Group address
+ // Others = Broadcast
+ if ((target >= 1) && (target <= 64)) { // 1 .. 64
+ target -= 1; // Short address
+ target <<= 1;
+ }
+ else if ((target >= 101) && (target <= 116)) { // 101 .. 116
+ target -= 101;
+ target <<= 1;
+ target |= 0x80; // Group address
+ }
+ else { // Others
+ target = DALI_BROADCAST_DP; // Broadcast address
+ }
+ return target &0xFE; // Direct Arc Power Control command
+}
+/*
+uint32_t DaliAddress2Target(uint32_t adr) {
+ if (adr >= 254) { // 0b1111111S
+ return 0; // Broadcast address (0)
+ }
+ else if ((adr >= 128) && (adr <= 159)) { // 0b1000000S .. 0b1001111S
+ return (adr >> 1) +101; // Group address (101 .. 116)
+ }
+ return (adr >> 1) +1; // 0b0000000S .. 0b0111111S Short address (1 .. 64)
+}
+*/
void DaliEnableRxInterrupt(void) {
Dali->available = false;
attachInterrupt(Dali->pin_rx, DaliReceiveData, FALLING);
@@ -243,7 +301,7 @@ void DaliSendData(uint32_t adr, uint32_t cmd) {
Dali->address = adr;
Dali->command = cmd;
- if (DALI_BROADCAST_DP == adr) {
+ if (DaliTarget2Address(Dali->target) == adr) {
repeat = true;
Dali->power = (cmd); // State
if (Dali->power) {
@@ -263,6 +321,10 @@ void DaliSendData(uint32_t adr, uint32_t cmd) {
}
}
+#ifdef DALI_DEBUG
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: SendData Repeat %d, Adr 0x%02X, Cmd 0x%02x"), repeat, adr, cmd);
+#endif // DALI_DEBUG
+
uint16_t send_dali_data = adr << 8 | cmd;
DaliDisableRxInterrupt();
@@ -289,13 +351,164 @@ int DaliSendWaitResponse(uint32_t adr, uint32_t cmd, uint32_t timeout) {
result = Dali->received_dali_data;
}
Dali->response = false;
+
+#ifdef DALI_DEBUG
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: SendWaitResponse result %d = 0x%04X"), result, result);
+#endif // DALI_DEBUG
+
return result;
}
-void DaliPower(uint32_t val) {
- DaliSendData(DALI_BROADCAST_DP, val);
+/*********************************************************************************************\
+ * DALI commissioning short addresses
+ *
+ * Courtesy of https://github.com/qqqlab/DALI-Lighting-Interface
+\*********************************************************************************************/
+
+// Query commands - Send as second byte
+#define DALI_QUERY_STATUS 0x0090 // 144 - Returns "STATUS INFORMATION"
+
+// Special commands - Send as first byte
+#define DALI_TERMINATE 0x00A1 // 256 - Releases the INITIALISE state.
+#define DALI_INITIALISE 0x01A5 // 258 REPEAT - Sets the slave to the INITIALISE status for15 minutes. Commands 259 to 270 are enabled only for a slave in this status.
+#define DALI_RANDOMISE 0x01A7 // 259 REPEAT - Generates a random address.
+#define DALI_COMPARE 0x00A9 // 260 - Is the random address smaller or equal to the search address?
+#define DALI_WITHDRAW 0x00AB // 261 - Excludes slaves for which the random address and search address match from the Compare process.
+#define DALI_SEARCHADDRH 0x00B1 // 264 - Specifies the higher 8 bits of the search address.
+#define DALI_SEARCHADDRM 0x00B3 // 265 - Specifies the middle 8 bits of the search address.
+#define DALI_SEARCHADDRL 0x00B5 // 266 - Specifies the lower 8 bits of the search address.
+#define DALI_PROGRAM_SHORT_ADDRESS 0x00B7 // 267 - The slave shall store the received 6-bit address (AAA AAA) as a short address if it is selected.
+
+void DaliSetSearchAddress(uint32_t adr) {
+ // Set search address
+ DaliSendData(DALI_SEARCHADDRH, adr>>16);
+ DaliSendData(DALI_SEARCHADDRM, adr>>8);
+ DaliSendData(DALI_SEARCHADDRL, adr);
}
+void DaliSetSearchAddressDifference(uint32_t adr_new, uint32_t adr_current) {
+ // Set search address, but set only changed bytes (takes less time)
+ if ( (uint8_t)(adr_new>>16) != (uint8_t)(adr_current>>16) ) DaliSendData(DALI_SEARCHADDRH, adr_new>>16);
+ if ( (uint8_t)(adr_new>>8) != (uint8_t)(adr_current>>8) ) DaliSendData(DALI_SEARCHADDRM, adr_new>>8);
+ if ( (uint8_t)(adr_new) != (uint8_t)(adr_current) ) DaliSendData(DALI_SEARCHADDRL, adr_new);
+}
+
+bool DaliCompare() {
+ // Is the random address smaller or equal to the search address?
+ // As more than one device can reply, the reply gets garbled
+ uint8_t retry = 2;
+ while (retry > 0) {
+ // Compare is true if we received any activity on the bus as reply.
+ // Sometimes the reply is not registered... so only accept retry times 'no reply' as a real false compare
+ int rv = DaliSendWaitResponse(DALI_COMPARE, 0x00);
+ if (rv == 0xFF) return true; // Yes reply
+ retry--;
+ }
+ return false;
+}
+
+uint32_t DaliFindAddress(void) {
+ // Find addr with binary search
+ uint32_t adr = 0x800000;
+ uint32_t addsub = 0x400000;
+ uint32_t adr_last = adr;
+ DaliSetSearchAddress(adr);
+
+ while (addsub) {
+ DaliSetSearchAddressDifference(adr, adr_last);
+ adr_last = adr;
+ if (DaliCompare()) { // Returns true if searchadr > adr
+ adr -= addsub;
+ } else {
+ adr += addsub;
+ }
+ addsub >>= 1;
+ }
+ DaliSetSearchAddressDifference(adr, adr_last);
+ adr_last = adr;
+ if (!DaliCompare()) {
+ adr++;
+ DaliSetSearchAddressDifference(adr, adr_last);
+ }
+ return adr;
+}
+
+void DaliProgramShortAddress(uint8_t shortadr) {
+ // The slave shall store the received 6-bit address (AAAAAA) as a short address if it is selected.
+ DaliSendData(DALI_PROGRAM_SHORT_ADDRESS, (shortadr << 1) | 0x01);
+
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: Set short address %d"), shortadr +1);
+}
+
+uint32_t DaliCommission(uint8_t init_arg) {
+ // init_arg=11111111 : all without short address
+ // init_arg=00000000 : all
+ // init_arg=0AAAAAA1 : only for this shortadr
+ // returns number of new short addresses assigned
+ DaliSendData(DALI_BROADCAST_DP, 0); // Turn all OFF
+ delay(100); // Need 100ms pause before starting commissioning
+
+ uint8_t arr[64];
+ uint32_t sa;
+ for (sa = 0; sa < 64; sa++) {
+ arr[sa] = 0;
+ }
+
+ // Start commissioning
+ DaliSendData(DALI_INITIALISE, init_arg);
+ DaliSendData(DALI_RANDOMISE, 0x00);
+ delay(100); // Need 100ms pause after RANDOMISE
+
+ // Find used short addresses (run always, seems to work better than without...)
+ for (sa = 0; sa < 64; sa++) {
+ int rv = DaliSendWaitResponse(sa << 1 | 1, DALI_QUERY_STATUS);
+ if (rv >= 0) {
+ if (init_arg != 0b00000000) {
+ arr[sa] = 1; // Remove address from list if not in "all" mode
+ }
+ }
+ }
+
+ uint32_t cnt = 0;
+ while (true) { // Find random addresses and assign unused short addresses
+ uint32_t adr = DaliFindAddress();
+ if (adr > 0xffffff) { break; } // No more random addresses found -> exit
+ for (sa = 0; sa < 64; sa++) { // Find first unused short address
+ if (0 == arr[sa]) { break; }
+ }
+ if( sa >= 64) { break; } // All 64 short addresses assigned -> exit
+ arr[sa] = 1; // Mark short address as used
+ cnt++;
+
+ DaliProgramShortAddress(sa); // Assign short address
+ DaliSendData(DALI_WITHDRAW, 0x00); // Remove the device from the search
+
+ delay(1);
+ OsWatchLoop();
+ }
+
+ DaliSendData(DALI_TERMINATE, 0x00); // Terminate the DALI_INITIALISE command
+
+ for (sa = 0; sa < cnt; sa++) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: Flash short address %d"), sa +1);
+
+ DaliSendData(sa << 1, 200); // Flash assigned lights
+ delay(1000);
+ OsWatchLoop();
+ DaliSendData(sa << 1, 0);
+ }
+
+ return cnt;
+}
+
+/*********************************************************************************************\
+ * DALI group management
+\*********************************************************************************************/
+
+// Configuration commands - Send as second byte
+#define DALI_ADD_TO_GROUP0 0x0060 // 96 - Adds the slave to Group XXXX.
+#define DALI_REMOVE_FROM_GROUP0 0x0070 // 112 - Deletes the slave from Group XXXX.
+
/***********************************************************/
void ResponseAppendDali(void) {
@@ -318,7 +531,7 @@ void DaliInput(void) {
#ifdef USE_LIGHT
bool show_response = true;
- if (DALI_BROADCAST_DP == Dali->address) {
+ if (DaliTarget2Address(Dali->target) == Dali->address) {
uint8_t dimmer_old = changeUIntScale(Dali->dimmer, 0, 254, 0, 100);
uint8_t power_old = Dali->power;
Dali->power = (Dali->command); // State
@@ -345,7 +558,7 @@ void DaliInput(void) {
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_PRFX_DALI));
}
#else
- if (DALI_BROADCAST_DP == Dali->address) {
+ if (DaliTarget2Address(Dali->target) == Dali->address) {
Dali->power = (Dali->command); // State
if (Dali->power) {
Dali->dimmer = Dali->command; // Value
@@ -366,7 +579,7 @@ bool DaliSetChannels(void) {
} else {
uint8_t value = ((uint8_t*)XdrvMailbox.data)[0];
if (255 == value) { value = 254; } // Max Dali value
- DaliPower(value);
+ DaliSendData(DaliTarget2Address(Dali->target), value);
}
}
return true;
@@ -411,84 +624,6 @@ bool DaliInit(void) {
#endif // USE_LIGHT
}
-/*********************************************************************************************\
- * Experimental - Not functioning
-\*********************************************************************************************/
-
-bool DaliMqtt(void) {
-/*
- XdrvMailbox.topic = topic;
- XdrvMailbox.index = strlen(topic);
- XdrvMailbox.data = (char*)data;
- XdrvMailbox.data_len = data_len;
-
- This won't work as there is currently no subscribe done
-*/
- char stopic[TOPSZ];
- strncpy(stopic, XdrvMailbox.topic, TOPSZ);
- XdrvMailbox.topic[TOPSZ - 1] = 0;
-
- char *items[10];
- char *p = stopic;
- int cnt = 0;
- do {
- items[cnt] = strtok(p, "/");
- cnt++;
- p = nullptr;
- } while (items[cnt - 1]);
- cnt--; // represents the number of items
-
- AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: Cnt %d, Topic '%s', Payload '%s'"), cnt, XdrvMailbox.topic, XdrvMailbox.data);
-
- if (cnt < 3) { // not for us?
- AddLog(LOG_LEVEL_INFO, PSTR("DLI: Cnt %d < 3"), cnt);
- return false;
- }
-
- int DALIindex = 0;
- int ADRindex = 0;
- int CMDindex = 0;
- uint8_t DALIaddr = DALI_BROADCAST_DP;
-
- if (strcasecmp_P(items[cnt - 3], PSTR(DALI_TOPIC)) != 0) { // dali
- // cmnd
- if (strcasecmp_P(items[cnt - 2], PSTR(DALI_TOPIC)) != 0) { // dali
- // device
- return false; // not for us
- } else {
- // cmnd/dali/percent
- DALIindex = cnt - 2;
- CMDindex = cnt - 1;
- }
- } else {
- // dali/percent/2 20
- DALIindex = cnt - 3;
- CMDindex = cnt - 2;
- ADRindex = cnt - 1;
- DALIaddr = ((int)CharToFloat(items[ADRindex])) << 1;
- }
-
- uint8_t level;
- uint8_t value = (uint8_t)CharToFloat(XdrvMailbox.data);
- if (strcasecmp_P(items[CMDindex], PSTR("percent")) == 0) {
- // dali/percent/
- float percent = (float)(254 * value * 0.01);
- level = (uint8_t)percent;
- }
- else if (strcasecmp_P(items[CMDindex], PSTR("level")) == 0) {
- level = value;
- }
- else {
- AddLog(LOG_LEVEL_INFO,PSTR("DLI: Command not recognized: %s"), items[CMDindex]);
- return false; // not for us
- }
-
- AddLog(LOG_LEVEL_INFO,PSTR("DLI: Dali value %d on address %d"), value, DALIaddr);
- DaliSendData(DALIaddr, level);
-
- return true;
-}
-
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
@@ -548,37 +683,109 @@ void CmndDali(void) {
ResponseDali();
}
+void CmndDaliTarget(void) {
+ // DaliTarget - Set transmit target
+ // DaliTarget 0 - Set target to broadcast address
+ // DaliTarget 1..64 - Set target to short address
+ // DaliTarget 101..116 - Set target to group address
+ if (((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 64)) ||
+ ((XdrvMailbox.payload >= 101) && (XdrvMailbox.payload <= 116)) ||
+ (XdrvMailbox.payload == 0)) {
+ Dali->target = XdrvMailbox.payload;
+ }
+ ResponseCmndNumber(Dali->target);
+}
+
void CmndDaliPower(void) {
- // DaliPower 0 - Power off
- // DaliPower 1 - Power on to last dimmer state
- // DaliPower 2 - Toggle power off or last dimmer state
- // DaliPower 3..254 - Equals DaliDimmer command
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 254)) {
- if (XdrvMailbox.payload <= 2) {
- if (2 == XdrvMailbox.payload) {
- XdrvMailbox.payload = (Dali->power) ? 0 : 1;
+ // DaliPower 0 - Broadcast power off
+ // DaliPower 1 - Broadcast power on to last dimmer state
+ // DaliPower 2 - Broadcast toggle power off or last dimmer state
+ // DaliPower 3..254 - Broadcast equals DaliDimmer command
+ // DaliPower 0..254 - Broadcast control
+ // DaliPower0 0..254 - Broadcast control (= DaliPower)
+ // DaliPower1 0..254 - Short address 0 control
+ // DaliPower3 0..254 - Short address 2 control
+ if (((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= 64)) ||
+ ((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116))) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 254)) {
+ if (XdrvMailbox.payload <= 2) {
+ if (2 == XdrvMailbox.payload) {
+ XdrvMailbox.payload = (Dali->power) ? 0 : 1;
+ }
+ if (1 == XdrvMailbox.payload) {
+ XdrvMailbox.payload = Dali->dimmer;
+ }
}
- if (1 == XdrvMailbox.payload) {
- XdrvMailbox.payload = Dali->dimmer;
+ uint32_t DALIaddr = DALI_BROADCAST_DP;
+ if (XdrvMailbox.index >= 101) {
+ DALIaddr = ((XdrvMailbox.index -101) << 1) | 0x80; // Group address
}
+ else if ((XdrvMailbox.index > 0) && XdrvMailbox.usridx) {
+ DALIaddr = (XdrvMailbox.index -1) << 1; // Short address
+ }
+ DaliSendData(DALIaddr, XdrvMailbox.payload);
}
- DaliPower(XdrvMailbox.payload);
}
ResponseDali();
}
void CmndDaliDimmer(void) {
- // DaliDimmer 0..100 - Set power off or dimmer state
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
- uint8_t dimmer = changeUIntScale(XdrvMailbox.payload, 0, 100, 0, 254);
- DaliPower(dimmer);
+ // DaliDimmer 0..100 - Broadcast set power off or dimmer state
+ // DaliDimmer0 0..100 - Broadcast set power off or dimmer state
+ // DaliDimmer1 0..100 - Short address 0 set power off or dimmer state
+ // DaliDimmer3 0..100 - Short address 2 set power off or dimmer state
+ if (((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= 64)) ||
+ ((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116))) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
+ uint8_t dimmer = changeUIntScale(XdrvMailbox.payload, 0, 100, 0, 254);
+ uint32_t DALIaddr = DALI_BROADCAST_DP;
+ if (XdrvMailbox.index >= 101) {
+ DALIaddr = ((XdrvMailbox.index -101) << 1) | 0x80; // Group address
+ }
+ else if ((XdrvMailbox.index > 0) && XdrvMailbox.usridx) {
+ DALIaddr = (XdrvMailbox.index -1) << 1; // Short address
+ }
+ DaliSendData(DALIaddr, dimmer);
+ }
}
ResponseDali();
}
+void CmndDaliGroup(void) {
+ // DaliGroup1 1,2 - Add device 1 and 2 to group 1
+ // DaliGroup1 -1,2 - Remove device 1 and 2 to group 1
+ if ((XdrvMailbox.index >= 1) && (XdrvMailbox.index <= 16)) {
+ if (XdrvMailbox.data_len) {
+ uint32_t command = DALI_ADD_TO_GROUP0;
+ if ('+' == XdrvMailbox.data[0]) { // Add devices
+ XdrvMailbox.data++;
+ XdrvMailbox.data_len--;
+ }
+ else if ('-' == XdrvMailbox.data[0]) { // Remove devices
+ command = DALI_REMOVE_FROM_GROUP0;
+ XdrvMailbox.data++;
+ XdrvMailbox.data_len--;
+ }
+ uint32_t argc = ArgC(); // Number of devices
+ if (argc) {
+ command |= (XdrvMailbox.index -1);
+ uint32_t sas[argc];
+ ParseParameters(argc, sas);
+ for (uint32_t arg = 0; arg < argc; arg++) {
+ uint32_t sa = sas[arg] -1;
+ if (sa <= 63) {
+ DaliSendData(sa << 1 | 0x01, command);
+ }
+ }
+ ResponseCmndDone();
+ }
+ }
+ }
+}
+
void CmndDaliSend(void) {
// Send command
- // Setting bit 8 will repeat command twice
+ // Setting bit 8 will repeat command once
// DaliSend 0x1a5,255 - DALI Initialise (send twice)
uint32_t values[2] = { 0 };
uint32_t params = ParseParameters(2, values);
@@ -590,7 +797,7 @@ void CmndDaliSend(void) {
void CmndDaliQuery(void) {
// Send command and return response or -1 (no response within DALI_TIMEOUT)
- // Setting bit 8 will repeat command twice
+ // Setting bit 8 will repeat command once
// DaliQuery 0xff,0x90 - DALI Query status
// DaliQuery 0xff,144 - DALI Query status
uint32_t values[2] = { 0 };
@@ -601,6 +808,20 @@ void CmndDaliQuery(void) {
}
}
+void CmndDaliCommission(void) {
+ // Commission short addresses
+ // DaliCommission 1 - Reset and commission short addresses
+ // DaliCommission 2 - Commission unassigned short addresses
+ if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 2)) {
+ uint32_t init_arg = 0x00; // Commission all
+ if (2 == XdrvMailbox.payload) {
+ init_arg = 0xFF; // Commission all without short addresses
+ }
+ int result = DaliCommission(init_arg);
+ ResponseCmndNumber(result);
+ }
+}
+
#ifdef USE_LIGHT
void CmndDaliWeb(void) {
// DaliWeb 0 - Disable GUI light controls
@@ -639,9 +860,6 @@ bool Xdrv75(uint32_t function) {
case FUNC_LOOP:
DaliInput();
break;
- case FUNC_MQTT_DATA:
- result = DaliMqtt();
- break;
#ifdef USE_LIGHT
case FUNC_SET_CHANNELS:
result = DaliSetChannels();