Add DALI command `DaliGroupSliders 0..16` to show GUI group sliders with feedback disabling `DaliLight`

This commit is contained in:
Theo Arends 2024-10-31 17:01:36 +01:00
parent deca4d9e06
commit 49d706f54c
7 changed files with 225 additions and 82 deletions

View File

@ -3,12 +3,22 @@ All notable changes to this project will be documented in this file.
## [Unreleased] - Development ## [Unreleased] - Development
## [14.3.0.3] ## [14.3.0.4]
### Added ### Added
- Support for I2C over Serial, preliminary stub (#22388) - DALI command `DaliGroupSliders 0..16` to show GUI group sliders with feedback disabling `DaliLight`
### Breaking Changed ### Breaking Changed
### Changed
### Fixed
### Removed
## [14.3.0.3] 20241031
### Added
- Support for I2C over Serial, preliminary stub (#22388)
### Changed ### Changed
- ESP32 Platform from 2024.10.30 to 2024.11.30, Framework (Arduino Core) from v3.1.0.241023 to v3.1.0.241030 and IDF to 5.3.1.241024 (#22384) - ESP32 Platform from 2024.10.30 to 2024.11.30, Framework (Arduino Core) from v3.1.0.241023 to v3.1.0.241030 and IDF to 5.3.1.241024 (#22384)
- ESP32 LVGL library from v9.2.0 to v9.2.2 (#22385) - ESP32 LVGL library from v9.2.0 to v9.2.2 (#22385)
@ -17,8 +27,6 @@ All notable changes to this project will be documented in this file.
### Fixed ### Fixed
- ESP32 Arduino Core IPv6 zones used by Matter (#22378) - ESP32 Arduino Core IPv6 zones used by Matter (#22378)
### Removed
## [14.3.0.2] 20241030 ## [14.3.0.2] 20241030
### Added ### Added
- DALI command `DaliGear` to set max found gear to speed up scan response - DALI command `DaliGear` to set max found gear to speed up scan response

View File

@ -114,13 +114,14 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
[Complete list](BUILDS.md) of available feature and sensors. [Complete list](BUILDS.md) of available feature and sensors.
## Changelog v14.3.0.3 ## Changelog v14.3.0.4
### Added ### Added
- Command ``SetOption161 1`` to disable web page slider updates by commands - Command ``SetOption161 1`` to disable web page slider updates by commands
- DALI support for short addresses (gear) and groups - DALI support for short addresses (gear) and groups
- DALI command `DaliGear` to set max found gear to speed up scan response - DALI command `DaliGear` to set max found gear to speed up scan response
- DALI command `DaliGroup` to add gear to groups - DALI command `DaliGroup` to add gear to groups
- DALI command `DaliTarget` to set light control broadcast, group number or gear number - DALI command `DaliTarget` to set light control broadcast, group number or gear number
- DALI command `DaliGroupSliders 0..16` to show GUI group sliders with feedback disabling `DaliLight`
- DALI inverted signal configuration using GPIO DALI RX_i/TX_i - DALI inverted signal configuration using GPIO DALI RX_i/TX_i
- Support for I2C over Serial, preliminary stub [#22388](https://github.com/arendst/Tasmota/issues/22388) - Support for I2C over Serial, preliminary stub [#22388](https://github.com/arendst/Tasmota/issues/22388)
- Support for Shelly DALI Dimmer Gen3 - Support for Shelly DALI Dimmer Gen3

View File

@ -195,7 +195,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t mqtt_disable_modbus : 1; // bit 12 (v13.3.0.5) - SetOption158 - (MQTT) Disable publish ModbusReceived MQTT messages (1), you must use event trigger rules instead uint32_t mqtt_disable_modbus : 1; // bit 12 (v13.3.0.5) - SetOption158 - (MQTT) Disable publish ModbusReceived MQTT messages (1), you must use event trigger rules instead
uint32_t counter_both_edges : 1; // bit 13 (v13.3.0.5) - SetOption159 - (Counter) Enable counting on both rising and falling edge (1) uint32_t counter_both_edges : 1; // bit 13 (v13.3.0.5) - SetOption159 - (Counter) Enable counting on both rising and falling edge (1)
uint32_t ld2410_use_pin : 1; // bit 14 (v14.3.0.2) - SetOption160 - (LD2410) Disable generate moving event by sensor report - use LD2410 out pin for events (1) uint32_t ld2410_use_pin : 1; // bit 14 (v14.3.0.2) - SetOption160 - (LD2410) Disable generate moving event by sensor report - use LD2410 out pin for events (1)
uint32_t disable_slider_updates : 1; // bit 15 (v14.3.0.2) - SetOption161 - (Light) Disable slider updates (1) uint32_t disable_slider_updates : 1; // bit 15 (v14.3.0.2) - SetOption161 - (Light) Disable slider updates by commands (1)
uint32_t spare16 : 1; // bit 16 uint32_t spare16 : 1; // bit 16
uint32_t spare17 : 1; // bit 17 uint32_t spare17 : 1; // bit 17
uint32_t spare18 : 1; // bit 18 uint32_t spare18 : 1; // bit 18
@ -260,15 +260,11 @@ typedef union {
uint32_t spare16 : 1; // bit 16 uint32_t spare16 : 1; // bit 16
uint32_t spare17 : 1; // bit 17 uint32_t spare17 : 1; // bit 17
uint32_t spare18 : 1; // bit 18 uint32_t spare18 : 1; // bit 18
uint32_t spare19 : 1; // bit 19 uint32_t dali_group_sliders : 5; // bit 19.23 (v14.3.0.3) - (DALI) Number of group sliders 0 to 16
uint32_t spare20 : 1; // bit 20 uint32_t FTP_Mode : 2; // bit 24/25
uint32_t spare21 : 1; // bit 21 uint32_t tariff_forced : 2; // bit 26/27 (v12.4.0.2) - Energy forced tariff : 0=tariff change on time, 1|2=tariff forced
uint32_t spare22 : 1; // bit 22 uint32_t sunrise_dawn_angle : 2; // bit 28/29 (v12.1.1.4) -
uint32_t spare23 : 1; // bit 23 uint32_t temperature_set_res : 2; // bit 30/31 (v9.3.1.4) - (Tuya)
uint32_t FTP_Mode : 2; // bit 24, 25
uint32_t tariff_forced : 2; // bit 26..27 (v12.4.0.2) - Energy forced tariff : 0=tariff change on time, 1|2=tariff forced
uint32_t sunrise_dawn_angle : 2; // bits 28/29 (v12.1.1.4) -
uint32_t temperature_set_res : 2; // bits 30/31 (v9.3.1.4) - (Tuya)
}; };
} SysMBitfield2; } SysMBitfield2;

View File

@ -22,6 +22,6 @@
#define TASMOTA_SHA_SHORT // Filled by Github sed #define TASMOTA_SHA_SHORT // Filled by Github sed
const uint32_t TASMOTA_VERSION = 0x0E030003; // 14.3.0.3 const uint32_t TASMOTA_VERSION = 0x0E030004; // 14.3.0.4
#endif // _TASMOTA_VERSION_H_ #endif // _TASMOTA_VERSION_H_

View File

@ -1838,6 +1838,9 @@ void SettingsDelta(void) {
if (Settings->version < 0x0E030002) { // 14.3.0.2 if (Settings->version < 0x0E030002) { // 14.3.0.2
Settings->sbflag1.dali_light = 1; Settings->sbflag1.dali_light = 1;
} }
if (Settings->version < 0x0E030004) { // 14.3.0.4
Settings->mbflag2.dali_group_sliders = 2;
}
Settings->version = TASMOTA_VERSION; Settings->version = TASMOTA_VERSION;
SettingsSave(1); SettingsSave(1);

View File

@ -271,6 +271,9 @@ const char HTTP_MSG_SLIDER_GRADIENT[] PROGMEM =
"<input id='sl%d' type='range' min='%d' max='%d' value='%d' onchange='lc(\"%c\",%d,value)'>" "<input id='sl%d' type='range' min='%d' max='%d' value='%d' onchange='lc(\"%c\",%d,value)'>"
"</div>"; "</div>";
const char HTTP_MSG_SLIDER_UPDATE[] PROGMEM =
"<img style='display:none;' src onerror=";
const char HTTP_MSG_RSTRT[] PROGMEM = const char HTTP_MSG_RSTRT[] PROGMEM =
"<br><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br>"; "<br><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br>";
@ -1354,7 +1357,7 @@ void HandleRoot(void)
WSContentSpaceButton(BUTTON_FIRMWARE_UPGRADE); WSContentSpaceButton(BUTTON_FIRMWARE_UPGRADE);
#endif // ESP32 #endif // ESP32
WSContentButton(BUTTON_CONSOLE); WSContentButton(BUTTON_CONSOLE);
#else #else // Not FIRMWARE_MINIMAL
WSContentSpaceButton(BUTTON_CONFIGURATION); WSContentSpaceButton(BUTTON_CONFIGURATION);
WSContentButton(BUTTON_INFORMATION); WSContentButton(BUTTON_INFORMATION);
WSContentButton(BUTTON_FIRMWARE_UPGRADE); WSContentButton(BUTTON_FIRMWARE_UPGRADE);
@ -1534,7 +1537,8 @@ bool HandleRootStatusRefresh(void)
if (current_value != Web.slider[i]) { if (current_value != Web.slider[i]) {
Web.slider[i] = current_value; Web.slider[i] = current_value;
// https://stackoverflow.com/questions/4057236/how-to-add-onload-event-to-a-div-element // https://stackoverflow.com/questions/4057236/how-to-add-onload-event-to-a-div-element
WSContentSend_P(PSTR("<img style='display:none;' src onerror=\"eb('sl%d').value='%d';\">"), i +1, current_value); WSContentSend_P(HTTP_MSG_SLIDER_UPDATE); // "<img style='display:none;' src onerror="
WSContentSend_P(PSTR("\"eb('sl%d').value='%d';\">"), i +1, current_value);
} }
} }
} }

View File

@ -19,6 +19,8 @@
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
Version yyyymmdd Action Description Version yyyymmdd Action Description
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
1.1.0.0 20241031 update - Add GUI sliders with feedback when `DaliLight 0`
- Add command `DaliGroupSliders 0..16` to show GUI sliders
1.0.0.2 20241025 update - Fix GPIO detection 1.0.0.2 20241025 update - Fix GPIO detection
- Fix ESP32(C3) transmit stability by disabling interrupts - Fix ESP32(C3) transmit stability by disabling interrupts
1.0.0.1 20241024 update - Change from signal invert defines to GPIO config DALI RX_i/DALI TX_i 1.0.0.1 20241024 update - Change from signal invert defines to GPIO config DALI RX_i/DALI TX_i
@ -264,6 +266,8 @@
// Address type - Send as first byte // Address type - Send as first byte
#define DALI_BROADCAST_DP 0x00FE // 0b11111110 254 - Broadcast address #define DALI_BROADCAST_DP 0x00FE // 0b11111110 254 - Broadcast address
#define DALI_MAX_STORED 17 // Store broadcast and group states
#define DALI_TOPIC "DALI" #define DALI_TOPIC "DALI"
#define D_PRFX_DALI "Dali" #define D_PRFX_DALI "Dali"
@ -272,14 +276,16 @@ const char kDALICommands[] PROGMEM = D_PRFX_DALI "|" // Prefix
#ifdef USE_LIGHT #ifdef USE_LIGHT
"|Light" "|Light"
#endif // USE_LIGHT #endif // USE_LIGHT
"|Send|Query|Scan|Group|Gear"; "|Send|Query|Scan|Group"
"|GroupSliders|Gear";
void (* const DALICommand[])(void) PROGMEM = { void (* const DALICommand[])(void) PROGMEM = {
&CmndDali, &CmndDaliPower, &CmndDaliDimmer, &CmndDaliTarget, &CmndDali, &CmndDaliPower, &CmndDaliDimmer, &CmndDaliTarget,
#ifdef USE_LIGHT #ifdef USE_LIGHT
&CmndDaliLight, &CmndDaliLight,
#endif // USE_LIGHT #endif // USE_LIGHT
&CmndDaliSend, &CmndDaliQuery, &CmndDaliScan, &CmndDaliGroup, &CmndDaliGear }; &CmndDaliSend, &CmndDaliQuery, &CmndDaliScan, &CmndDaliGroup,
&CmndDaliGroupSliders, &CmndDaliGear };
struct DALI { struct DALI {
uint32_t bit_cycles; uint32_t bit_cycles;
@ -290,9 +296,13 @@ struct DALI {
uint8_t max_short_address; uint8_t max_short_address;
uint8_t address; uint8_t address;
uint8_t command; uint8_t command;
uint8_t dimmer; uint8_t last_dimmer;
uint8_t dimmer[DALI_MAX_STORED];
uint8_t web_dimmer[DALI_MAX_STORED];
uint8_t target; uint8_t target;
bool power; bool last_power;
bool power[DALI_MAX_STORED];
bool web_power[DALI_MAX_STORED];
bool available; bool available;
bool response; bool response;
bool light_sync; bool light_sync;
@ -305,23 +315,23 @@ struct DALI {
* DALI low level * DALI low level
\*********************************************************************************************/ \*********************************************************************************************/
uint32_t DaliTarget2Address(uint32_t target) { uint32_t DaliTarget2Address(void) {
// 1..64 = Short address // 1..64 = Short address
// 101..116 = Group address // 101..116 = Group address
// Others = Broadcast // Others = Broadcast
if ((target >= 1) && (target <= 64)) { // 1 .. 64 if ((Dali->target >= 1) && (Dali->target <= 64)) { // 1 .. 64
target -= 1; // Short address Dali->target -= 1; // Short address
target <<= 1; Dali->target <<= 1;
} }
else if ((target >= 101) && (target <= 116)) { // 101 .. 116 else if ((Dali->target >= 101) && (Dali->target <= 116)) { // 101 .. 116
target -= 101; Dali->target -= 101;
target <<= 1; Dali->target <<= 1;
target |= 0x80; // Group address Dali->target |= 0x80; // Group address
} }
else { // Others else { // Others
target = DALI_BROADCAST_DP; // Broadcast address Dali->target = DALI_BROADCAST_DP; // Broadcast address
} }
return target &0xFE; // Direct Arc Power Control command return Dali->target &0xFE; // Direct Arc Power Control command
} }
/* /*
@ -336,6 +346,34 @@ uint32_t DaliAddress2Target(uint32_t adr) {
} }
*/ */
uint32_t DaliSaveState(uint32_t adr, uint32_t cmd) {
if (adr &0x01) { return 0; } // No address
int index = -1;
if (DALI_BROADCAST_DP == adr) { // Broadcast address
index = 0;
}
adr >>= 1;
if ((adr >= 0x40) && (adr <= 0x4F)) { // Group address 0 to 15
index = adr -0x3F;
}
if (index >= 0) {
Dali->last_power = Dali->power[index];
Dali->power[index] = (cmd); // State
if (Dali->power[index]) {
Dali->last_dimmer = Dali->dimmer[index];
Dali->dimmer[index] = cmd; // Value
}
if ((0 == index) && !Dali->power[0]) { // Only on Broadcast change to power Off
for (uint32_t i = 0; i < DALI_MAX_STORED; i++) {
Dali->power[i] = false; // Log all group power as Off when Broadcast is Off
}
}
} else {
index = 0; // Use broadcast
}
return index;
}
void DaliEnableRxInterrupt(void) { void DaliEnableRxInterrupt(void) {
Dali->available = false; Dali->available = false;
attachInterrupt(Dali->pin_rx, DaliReceiveData, (Dali->invert_rx) ? RISING : FALLING); attachInterrupt(Dali->pin_rx, DaliReceiveData, (Dali->invert_rx) ? RISING : FALLING);
@ -508,13 +546,7 @@ void DaliSendData(uint32_t adr, uint32_t cmd) {
Dali->address = adr; Dali->address = adr;
Dali->command = cmd; Dali->command = cmd;
if (DaliTarget2Address(Dali->target) == adr) { DaliSaveState(adr, cmd);
repeat = true;
Dali->power = (cmd); // State
if (Dali->power) {
Dali->dimmer = cmd; // Value
}
}
if (!repeat && (adr &0x01)) { // YAAAAAA1 Commands where user didn't set repeat if (!repeat && (adr &0x01)) { // YAAAAAA1 Commands where user didn't set repeat
if ((adr >= 0xA1) && (adr <= 0xFD)) { // Special commands if ((adr >= 0xA1) && (adr <= 0xFD)) { // Special commands
@ -751,25 +783,28 @@ uint32_t DaliCommission(uint8_t init_arg) {
#ifdef USE_LIGHT #ifdef USE_LIGHT
DaliInitLight(); DaliInitLight();
uint32_t address = (Settings->sbflag1.dali_light) ? DaliTarget2Address(Dali->target) : DALI_BROADCAST_DP; uint32_t address = (Settings->sbflag1.dali_light) ? DaliTarget2Address() : DALI_BROADCAST_DP;
DaliSendData(address, Dali->power); // Restore lights DaliSendData(address, Dali->power[0]); // Restore lights
#else #else
DaliSendData(DALI_BROADCAST_DP, Dali->power); // Restore lights DaliSendData(DALI_BROADCAST_DP, Dali->power[0]); // Restore lights
#endif // USE_LIGHT #endif // USE_LIGHT
return cnt; return cnt;
} }
/*********************************************************************************************/ /*********************************************************************************************/
void ResponseAppendDali(void) { void ResponseAppendDali(uint32_t index) {
uint8_t dimmer = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); char number[12];
ResponseAppend_P(PSTR("\"DALI\":{\"Power\":\"%s\",\"Dimmer\":%d,\"Address\":%d,\"Command\":%d}"), uint8_t dimmer = changeUIntScale(Dali->dimmer[index], 0, 254, 0, 100);
GetStateText(Dali->power), dimmer, Dali->address, Dali->command); ResponseAppend_P(PSTR("\"DALI\":{\"Power%s\":\"%s\",\"Dimmer%s\":%d,\"Address\":%d,\"Command\":%d}"),
(0==index)?"":itoa(index+100, number, 10), GetStateText(Dali->power[index]),
(0==index)?"":itoa(index+100, number, 10), dimmer,
Dali->address, Dali->command);
} }
void ResponseDali(void) { void ResponseDali(uint32_t index) {
Response_P(PSTR("{")); Response_P(PSTR("{"));
ResponseAppendDali(); ResponseAppendDali(index);
ResponseJsonEnd(); ResponseJsonEnd();
} }
@ -787,45 +822,32 @@ void DaliLoop(void) {
Dali->address = Dali->received_dali_data >> 8; Dali->address = Dali->received_dali_data >> 8;
Dali->command = Dali->received_dali_data; Dali->command = Dali->received_dali_data;
uint32_t index = DaliSaveState(Dali->address, Dali->command); // Update dimmer and power
#ifdef USE_LIGHT
bool show_response = true; bool show_response = true;
if (DaliTarget2Address(Dali->target) == Dali->address) { #ifdef USE_LIGHT
uint8_t dimmer_old = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); if (DaliTarget2Address() == Dali->address) {
uint8_t power_old = Dali->power;
Dali->power = (Dali->command); // State
if (Dali->power) {
Dali->dimmer = Dali->command; // Value
}
if (Settings->sbflag1.dali_light) { // DaliLight 1 if (Settings->sbflag1.dali_light) { // DaliLight 1
uint8_t dimmer_new = changeUIntScale(Dali->dimmer, 0, 254, 0, 100); uint8_t dim_old = changeUIntScale(Dali->last_dimmer, 0, 254, 0, 100);
if (power_old != Dali->power) { uint8_t dim_new = changeUIntScale(Dali->dimmer[index], 0, 254, 0, 100);
if (Dali->last_power != Dali->power[index]) {
Dali->light_sync = true; // Block local loop Dali->light_sync = true; // Block local loop
ExecuteCommandPower(LightDevice(), Dali->power, SRC_SWITCH); ExecuteCommandPower(LightDevice(), Dali->power[index], SRC_SWITCH);
} }
else if (dimmer_old != dimmer_new) { else if (dim_old != dim_new) {
char scmnd[20]; char scmnd[20];
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), dimmer_new); snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), dim_new);
Dali->light_sync = true; // Block local loop Dali->light_sync = true; // Block local loop
ExecuteCommand(scmnd, SRC_SWITCH); ExecuteCommand(scmnd, SRC_SWITCH);
} }
show_response = false; show_response = false;
} }
} }
#endif // USE_LIGHT
if (show_response) { if (show_response) {
ResponseDali(); ResponseDali(index);
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_PRFX_DALI)); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_PRFX_DALI));
} }
#else
if (DaliTarget2Address(Dali->target) == 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;
} }
@ -850,7 +872,7 @@ bool DaliSetChannels(void) {
} else { } else {
uint8_t value = ((uint8_t*)XdrvMailbox.data)[0]; uint8_t value = ((uint8_t*)XdrvMailbox.data)[0];
if (255 == value) { value = 254; } // Max Dali value if (255 == value) { value = 254; } // Max Dali value
DaliSendData(DaliTarget2Address(Dali->target), value); DaliSendData(DaliTarget2Address(), value);
} }
} }
return true; return true;
@ -900,7 +922,10 @@ bool DaliInit(void) {
#endif // DALI_DEBUG #endif // DALI_DEBUG
Dali->max_short_address = 64; Dali->max_short_address = 64;
Dali->dimmer = DALI_INIT_STATE; for (uint32_t i = 0; i < DALI_MAX_STORED; i++) {
Dali->dimmer[i] = DALI_INIT_STATE;
}
// Manchester twice 1200 bps = 2400 bps = 417 (protocol 416.76 +/- 10%) us // Manchester twice 1200 bps = 2400 bps = 417 (protocol 416.76 +/- 10%) us
Dali->bit_cycles = ESP.getCpuFreqMHz() * 1000000 / 2400; Dali->bit_cycles = ESP.getCpuFreqMHz() * 1000000 / 2400;
@ -983,7 +1008,7 @@ void CmndDali(void) {
} }
DaliJsonParse(); DaliJsonParse();
} }
ResponseDali(); ResponseDali(0);
} }
/*-------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------*/
@ -1010,15 +1035,19 @@ void CmndDaliPower(void) {
// DaliPower0 0..254 - Broadcast control (= DaliPower) // DaliPower0 0..254 - Broadcast control (= DaliPower)
// DaliPower1 0..254 - Short address 0 control // DaliPower1 0..254 - Short address 0 control
// DaliPower3 0..254 - Short address 2 control // DaliPower3 0..254 - Short address 2 control
uint32_t index = 0; // Broadcast
if ((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116)) {
index = XdrvMailbox.index - 100; // Group1 to 16
}
if (((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= 64)) || if (((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= 64)) ||
((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116))) { ((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116))) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 254)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 254)) {
if (XdrvMailbox.payload <= 2) { if (XdrvMailbox.payload <= 2) {
if (2 == XdrvMailbox.payload) { if (2 == XdrvMailbox.payload) {
XdrvMailbox.payload = (Dali->power) ? 0 : 1; XdrvMailbox.payload = (Dali->power[index]) ? 0 : 1;
} }
if (1 == XdrvMailbox.payload) { if (1 == XdrvMailbox.payload) {
XdrvMailbox.payload = Dali->dimmer; XdrvMailbox.payload = Dali->dimmer[index];
} }
} }
uint32_t DALIaddr = DALI_BROADCAST_DP; uint32_t DALIaddr = DALI_BROADCAST_DP;
@ -1031,7 +1060,7 @@ void CmndDaliPower(void) {
DaliSendData(DALIaddr, XdrvMailbox.payload); DaliSendData(DALIaddr, XdrvMailbox.payload);
} }
} }
ResponseDali(); ResponseDali(index);
} }
void CmndDaliDimmer(void) { void CmndDaliDimmer(void) {
@ -1039,6 +1068,10 @@ void CmndDaliDimmer(void) {
// DaliDimmer0 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 // DaliDimmer1 0..100 - Short address 0 set power off or dimmer state
// DaliDimmer3 0..100 - Short address 2 set power off or dimmer state // DaliDimmer3 0..100 - Short address 2 set power off or dimmer state
uint32_t index = 0; // Broadcast
if ((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116)) {
index = XdrvMailbox.index - 100; // Group1 to 16
}
if (((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= 64)) || if (((XdrvMailbox.index >= 0) && (XdrvMailbox.index <= 64)) ||
((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116))) { ((XdrvMailbox.index >= 101) && (XdrvMailbox.index <= 116))) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
@ -1053,7 +1086,7 @@ void CmndDaliDimmer(void) {
DaliSendData(DALIaddr, dimmer); DaliSendData(DALIaddr, dimmer);
} }
} }
ResponseDali(); ResponseDali(index);
} }
void CmndDaliGroup(void) { void CmndDaliGroup(void) {
@ -1169,13 +1202,23 @@ void CmndDaliScan(void) {
} }
} }
void CmndDaliGroupSliders(void) {
// DaliGroupSliders 0..16 - Disable light controls and add group sliders
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 16)) {
Settings->sbflag1.dali_light = 0; // Disable DaliLight
Settings->mbflag2.dali_group_sliders = XdrvMailbox.payload;
TasmotaGlobal.restart_flag = 2; // Restart to update GUI
}
ResponseCmndNumber(Settings->mbflag2.dali_group_sliders);
}
#ifdef USE_LIGHT #ifdef USE_LIGHT
void CmndDaliLight(void) { void CmndDaliLight(void) {
// DaliLight 0 - Disable light controls // DaliLight 0 - Disable light controls
// DaliLight 1 - Enable light controls // DaliLight 1 - Enable light controls
if (XdrvMailbox.data_len > 0) { if (XdrvMailbox.data_len > 0) {
Settings->sbflag1.dali_light = XdrvMailbox.payload &1; Settings->sbflag1.dali_light = XdrvMailbox.payload &1;
TasmotaGlobal.restart_flag = 2; TasmotaGlobal.restart_flag = 2; // Restart to update GUI
} }
ResponseCmndStateText(Settings->sbflag1.dali_light); ResponseCmndStateText(Settings->sbflag1.dali_light);
} }
@ -1185,10 +1228,86 @@ void CmndDaliLight(void) {
* Presentation * Presentation
\*********************************************************************************************/ \*********************************************************************************************/
#ifdef USE_WEBSERVER
const char HTTP_MSG_SLIDER_DALI[] PROGMEM =
"<tr>"
"<td style='width:15%%'><button id='k75%d' style='background:#%06x;' onclick='la(\"&k75=%d\");'>%s%s</button></td>"
"<td style='width:85%%'><div class='r' style='background-image:linear-gradient(to right,#000,#FFF);'>"
"<input id='i75%d' type='range' min='1' max='100' value='%d' onchange='lc(\"i\",75%d,value)'></div></td>"
"</tr>";
void DaliWebAddMainSlider(void) {
WSContentSend_P(HTTP_TABLE100);
char number[12];
uint32_t max_sliders = 1 + Settings->mbflag2.dali_group_sliders;
for (uint32_t i = 0; i < max_sliders; i++) {
Dali->web_dimmer[i] = Dali->dimmer[i];
Dali->web_power[i] = Dali->power[i];
WSContentSend_P(HTTP_MSG_SLIDER_DALI, // Brightness - Black to White
i, // k75<i>
WebColor((Dali->web_power[i])?COL_BUTTON:COL_BACKGROUND),
i, // k75=<i>
(0==i)?"B":"G", // B (Broadcast) or G1 to G16 (Group)
(0==i)?"":itoa(i, number, 10),
i, // i75<i>
changeUIntScale(Dali->web_dimmer[i], 0, 254, 0, 100),
i // i75<i>
);
}
WSContentSend_P(PSTR("</table>"));
}
void DaliWebGetArg(void) {
char tmp[8]; // WebGetArg numbers only
char svalue[32]; // Command and number parameter
char webindex[8]; // WebGetArg name
uint32_t index;
uint32_t max_sliders = 1 + Settings->mbflag2.dali_group_sliders;
for (uint32_t i = 0; i < max_sliders; i++) {
snprintf_P(webindex, sizeof(webindex), PSTR("i75%d"), i);
WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent
if (strlen(tmp)) {
index = i;
if (index > 0) { index += 100; } // Group
snprintf_P(svalue, sizeof(svalue), PSTR("DaliDimmer%d %s"), index, tmp);
ExecuteWebCommand(svalue);
}
}
WebGetArg(PSTR("k75"), tmp, sizeof(tmp));
if (strlen(tmp)) {
index = atoi(tmp);
if (index > 0) { index += 100; } // Group
snprintf_P(svalue, sizeof(svalue), PSTR("DaliPower%d 2"), index);
ExecuteWebCommand(svalue);
}
}
#endif // USE_WEBSERVER
void DaliShow(bool json) { void DaliShow(bool json) {
if (json) { if (json) {
ResponseAppend_P(PSTR(",")); ResponseAppend_P(PSTR(","));
ResponseAppendDali(); ResponseAppendDali(0);
#ifdef USE_WEBSERVER
} else {
uint32_t max_sliders = 1 + Settings->mbflag2.dali_group_sliders;
for (uint32_t i = 0; i < max_sliders; i++) {
if (Dali->power[i] != Dali->web_power[i]) {
Dali->web_power[i] = Dali->power[i];
WSContentSend_P(HTTP_MSG_SLIDER_UPDATE); // "<img style='display:none;' src onerror="
WSContentSend_P(PSTR("\"eb('k75%d').style='background:#%06x;';\">"),
i, WebColor((Dali->web_power[i])?COL_BUTTON:COL_BACKGROUND));
WSContentSeparator(3); // Don't print separator on next WSContentSeparator(1)
}
if (Dali->dimmer[i] != Dali->web_dimmer[i]) {
Dali->web_dimmer[i] = Dali->dimmer[i];
WSContentSend_P(HTTP_MSG_SLIDER_UPDATE); // "<img style='display:none;' src onerror="
WSContentSend_P(PSTR("\"eb('i75%d').value='%d';\">"),
i, changeUIntScale(Dali->web_dimmer[i], 0, 254, 0, 100));
WSContentSeparator(3); // Don't print separator on next WSContentSeparator(1)
}
}
#endif // USE_WEBSERVER
} }
} }
@ -1220,7 +1339,19 @@ bool Xdrv75(uint32_t function) {
break; break;
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR: case FUNC_WEB_SENSOR:
DaliShow(false); if (!Settings->sbflag1.dali_light) { // DaliLight 0
DaliShow(false);
}
break;
case FUNC_WEB_ADD_MAIN_BUTTON:
if (!Settings->sbflag1.dali_light) { // DaliLight 0
DaliWebAddMainSlider();
}
break;
case FUNC_WEB_GET_ARG:
if (!Settings->sbflag1.dali_light) { // DaliLight 0
DaliWebGetArg();
}
break; break;
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
case FUNC_COMMAND: case FUNC_COMMAND: