mirror of https://github.com/arendst/Tasmota.git
Add experimental support for Shelly DALI Dimmer Gen3 (See template in file xdrv_75_dali.ino)
This commit is contained in:
parent
80686a8c52
commit
886221a1d6
|
@ -12,6 +12,8 @@ All notable changes to this project will be documented in this file.
|
|||
- Mitsubishi Electric HVAC Outdoor Temperature for MiElHVAC (#22345)
|
||||
- Mitsubishi Electric HVAC Compressor Frequency for MiElHVAC (#22347)
|
||||
- SolaxX1 Meter mode (#22330)
|
||||
- DALI inverted signal configuration using GPIO DALI RX_i/TX_i
|
||||
- Experimental support for Shelly DALI Dimmer Gen3 (See template in file xdrv_75_dali.ino)
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
|
@ -24,6 +26,7 @@ All notable changes to this project will be documented in this file.
|
|||
### Fixed
|
||||
|
||||
### Removed
|
||||
- DALI inverted signal configuration using compile time defines
|
||||
|
||||
## [14.3.0.1] 20241022
|
||||
### Added
|
||||
|
|
|
@ -120,6 +120,8 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
|||
- DALI command `DaliGear` to set max found gear to speed up scan response
|
||||
- DALI command `DaliGroup` to add gear to groups
|
||||
- DALI command `DaliTarget` to set light control broadcast, group number or gear number
|
||||
- DALI inverted signal configuration using GPIO DALI RX_i/TX_i
|
||||
- Experimental support for Shelly DALI Dimmer Gen3 (See template in file xdrv_75_dali.ino)
|
||||
- Mitsubishi Electric HVAC Operation time for MiElHVAC [#22334](https://github.com/arendst/Tasmota/issues/22334)
|
||||
- Mitsubishi Electric HVAC Outdoor Temperature for MiElHVAC [#22345](https://github.com/arendst/Tasmota/issues/22345)
|
||||
- Mitsubishi Electric HVAC Compressor Frequency for MiElHVAC [#22347](https://github.com/arendst/Tasmota/issues/22347)
|
||||
|
|
|
@ -224,6 +224,7 @@ enum UserSelectablePins {
|
|||
GPIO_WOOLIIS_RX, // Wooliis Battery capacity monitor Serial RX
|
||||
GPIO_ADC_VOLTAGE, GPIO_ADC_CURRENT, // Analog Voltage and Current
|
||||
GPIO_BL0906_RX, // BL0906 Serial interface
|
||||
GPIO_DALI_RX_INV, GPIO_DALI_TX_INV, // DALI
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Error as warning to rethink GPIO usage with max 2045
|
||||
|
@ -495,6 +496,7 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_WOOLIIS_RX "|"
|
||||
D_SENSOR_ADC_VOLTAGE "|" D_SENSOR_ADC_CURRENT "|"
|
||||
D_SENSOR_BL0906_RX "|"
|
||||
D_SENSOR_DALI_RX "_i|" D_SENSOR_DALI_TX "_i|"
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
|
@ -592,11 +594,6 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
* Protocol specifics
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef USE_DALI
|
||||
AGPIO(GPIO_DALI_RX), // DALI RX
|
||||
AGPIO(GPIO_DALI_TX), // DALI TX
|
||||
#endif // USE_DALI
|
||||
|
||||
#ifdef USE_I2C
|
||||
AGPIO(GPIO_I2C_SCL) + MAX_I2C, // I2C SCL
|
||||
AGPIO(GPIO_I2C_SDA) + MAX_I2C, // I2C SDA
|
||||
|
@ -834,6 +831,13 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
#endif
|
||||
#endif // USE_LIGHT
|
||||
|
||||
#ifdef USE_DALI
|
||||
AGPIO(GPIO_DALI_TX), // DALI TX
|
||||
AGPIO(GPIO_DALI_TX_INV), // DALI TX inverted
|
||||
AGPIO(GPIO_DALI_RX), // DALI RX
|
||||
AGPIO(GPIO_DALI_RX_INV), // DALI RX inverted
|
||||
#endif // USE_DALI
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Transmission sensors
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
--------------------------------------------------------------------------------------------
|
||||
Version yyyymmdd Action Description
|
||||
--------------------------------------------------------------------------------------------
|
||||
1.0.0.1 20241024 update - Change from signal invert defines to GPIO config DALI RX_i/DALI TX_i
|
||||
- Fix inverted DALI signal support
|
||||
- Experimental support for Shelly DALI Dimmer Gen3
|
||||
1.0.0.0 20241022 update - Refactor commission
|
||||
- Add receive collision detection
|
||||
0.1.0.8 20241019 update - Rename command `DaliCommission` to `DaliScan`
|
||||
|
@ -79,19 +82,16 @@
|
|||
* 16 group address 100AAAAS
|
||||
* Special command 101CCCC1 to 110CCCC1
|
||||
* A = Address bit, S = 0 Direct Arc Power control, S = 1 Command, C = Special command
|
||||
*
|
||||
* Shelly DALI Dimmer Gen3 (ESP32C3-8M)
|
||||
* Template {"NAME":"Shelly DALI Dimmer Gen3","GPIO":[34,4736,1,3840,11360,11392,128,129,1,1,576,0,0,0,0,0,0,0,0,1,1,1],"FLAG":0,"BASE":1}
|
||||
* AdcGpio1 10000,10000,4000 <- Temperature parameters
|
||||
* Backlog ButtonTopic 0; SetOption1 1; SetOption11 0; SetOption32 20
|
||||
* rule1 on button1#state=2 do dimmer + endon on button2#state=2 do dimmer - endon on button1#state=3 do power 2 endon on button2#state=3 do power 2 endon
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_75 75
|
||||
|
||||
#ifndef DALI_IN_INVERT
|
||||
#define DALI_IN_INVERT 0 // DALI RX inverted (1)
|
||||
#endif
|
||||
#ifndef DALI_OUT_INVERT
|
||||
#define DALI_OUT_INVERT 0 // DALI TX inverted (1)
|
||||
#endif
|
||||
#ifndef DALI_MAX_SHORT_ADDRESS
|
||||
#define DALI_MAX_SHORT_ADDRESS 64 // DALI default max short addresses
|
||||
#endif
|
||||
#ifndef DALI_INIT_STATE
|
||||
#define DALI_INIT_STATE 50 // DALI init dimmer state 50/254
|
||||
#endif
|
||||
|
@ -280,7 +280,7 @@ void (* const DALICommand[])(void) PROGMEM = {
|
|||
&CmndDaliSend, &CmndDaliQuery, &CmndDaliScan, &CmndDaliGroup, &CmndDaliGear };
|
||||
|
||||
struct DALI {
|
||||
uint32_t bit_time;
|
||||
uint32_t bit_cycles;
|
||||
uint32_t last_activity;
|
||||
uint32_t received_dali_data; // Data received from DALI bus
|
||||
uint8_t pin_rx;
|
||||
|
@ -295,6 +295,8 @@ struct DALI {
|
|||
bool response;
|
||||
bool light_sync;
|
||||
bool probe;
|
||||
bool invert_rx;
|
||||
bool invert_tx;
|
||||
} *Dali = nullptr;
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -334,7 +336,7 @@ uint32_t DaliAddress2Target(uint32_t adr) {
|
|||
|
||||
void DaliEnableRxInterrupt(void) {
|
||||
Dali->available = false;
|
||||
attachInterrupt(Dali->pin_rx, DaliReceiveData, FALLING);
|
||||
attachInterrupt(Dali->pin_rx, DaliReceiveData, (Dali->invert_rx) ? RISING : FALLING);
|
||||
}
|
||||
|
||||
void DaliDisableRxInterrupt(void) {
|
||||
|
@ -365,16 +367,15 @@ void DaliReceiveData(void) {
|
|||
*/
|
||||
if (Dali->available) { return; } // Skip if last input is not yet handled
|
||||
uint32_t gap_time = millis() - Dali->last_activity;
|
||||
uint32_t wait = ESP.getCycleCount() + (Dali->bit_time / 2);
|
||||
uint32_t wait = ESP.getCycleCount() + (Dali->bit_cycles / 2);
|
||||
int bit_state = 0;
|
||||
bool dali_read;
|
||||
uint32_t received_dali_data = 0;
|
||||
uint32_t bit_number = 0;
|
||||
while (bit_number < 38) {
|
||||
while (ESP.getCycleCount() < wait);
|
||||
wait += Dali->bit_time; // Auto roll-over
|
||||
dali_read = digitalRead(Dali->pin_rx);
|
||||
if (DALI_IN_INVERT) { dali_read != dali_read; }
|
||||
wait += Dali->bit_cycles; // Auto roll-over
|
||||
dali_read = (digitalRead(Dali->pin_rx) != Dali->invert_rx);
|
||||
#ifdef DALI_DEBUG
|
||||
digitalWrite(DALI_DEBUG_PIN, bit_number&1); // Add LogicAnalyzer poll indication
|
||||
#endif // DALI_DEBUG
|
||||
|
@ -465,13 +466,12 @@ void DaliSendDataOnce(uint16_t send_dali_data) {
|
|||
}
|
||||
}
|
||||
|
||||
digitalWrite(Dali->pin_tx, (pin_value == DALI_OUT_INVERT) ? LOW : HIGH);
|
||||
wait += Dali->bit_time; // Auto roll-over
|
||||
digitalWrite(Dali->pin_tx, (Dali->invert_tx) ? !pin_value : pin_value);
|
||||
wait += Dali->bit_cycles; // Auto roll-over
|
||||
while (ESP.getCycleCount() < wait);
|
||||
|
||||
if (!collision) {
|
||||
dali_read = digitalRead(Dali->pin_rx);
|
||||
if (DALI_IN_INVERT) { dali_read != dali_read; }
|
||||
dali_read = (digitalRead(Dali->pin_rx) != Dali->invert_rx);
|
||||
if ((HIGH == pin_value) && (LOW == dali_read)) { // Collision if write is 1 and bus is 0
|
||||
collision = true;
|
||||
pin_value = LOW;
|
||||
|
@ -686,7 +686,7 @@ 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);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("DLI: Set short address %d"), shortadr +1);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*/
|
||||
|
@ -738,9 +738,9 @@ uint32_t DaliCommission(uint8_t init_arg) {
|
|||
#ifdef USE_LIGHT
|
||||
DaliInitLight();
|
||||
uint32_t address = (Settings->sbflag1.dali_light) ? DaliTarget2Address(Dali->target) : DALI_BROADCAST_DP;
|
||||
DaliSendData(address, Dali->dimmer); // Restore lights
|
||||
DaliSendData(address, Dali->power); // Restore lights
|
||||
#else
|
||||
DaliSendData(DALI_BROADCAST_DP, Dali->dimmer); // Restore lights
|
||||
DaliSendData(DALI_BROADCAST_DP, Dali->power); // Restore lights
|
||||
#endif // USE_LIGHT
|
||||
return cnt;
|
||||
}
|
||||
|
@ -763,6 +763,9 @@ void ResponseDali(void) {
|
|||
|
||||
void DaliLoop(void) {
|
||||
if (!Dali->available || Dali->response) { return; }
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DLI: Rx 0x%05X"), Dali->received_dali_data);
|
||||
|
||||
if (Dali->received_dali_data &0x00010000) {
|
||||
Dali->available = false;
|
||||
return; // Rx collision
|
||||
|
@ -842,28 +845,45 @@ bool DaliSetChannels(void) {
|
|||
/*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
bool DaliInit(void) {
|
||||
if (!PinUsed(GPIO_DALI_TX) || !PinUsed(GPIO_DALI_RX)) { return false; }
|
||||
|
||||
Dali = (DALI*)calloc(sizeof(DALI), 1);
|
||||
if (!Dali) { return false; }
|
||||
|
||||
Dali->pin_rx = Pin(GPIO_DALI_RX);
|
||||
Dali->pin_tx = -1;
|
||||
if (PinUsed(GPIO_DALI_TX)) {
|
||||
Dali->pin_tx = Pin(GPIO_DALI_TX);
|
||||
}
|
||||
else if (PinUsed(GPIO_DALI_TX_INV)) {
|
||||
Dali->pin_tx = Pin(GPIO_DALI_TX_INV);
|
||||
Dali->invert_tx = true;
|
||||
}
|
||||
Dali->pin_rx = -1;
|
||||
if (PinUsed(GPIO_DALI_RX)) {
|
||||
Dali->pin_rx = Pin(GPIO_DALI_RX);
|
||||
}
|
||||
else if (PinUsed(GPIO_DALI_RX_INV)) {
|
||||
Dali->pin_rx = Pin(GPIO_DALI_RX_INV);
|
||||
Dali->invert_rx = true;
|
||||
}
|
||||
if ((-1 == Dali->pin_tx) || (-1 == Dali->pin_rx)) {
|
||||
free(Dali);
|
||||
return false;
|
||||
}
|
||||
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("DLI: GPIO%d(RX) and GPIO%d(TX)"), Dali->pin_rx, Dali->pin_tx);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("DLI: GPIO%d(RX%s) and GPIO%d(TX%s)"),
|
||||
Dali->pin_rx, (Dali->invert_rx)?"i":"", Dali->pin_tx, (Dali->invert_tx)?"i":"");
|
||||
|
||||
pinMode(Dali->pin_tx, OUTPUT);
|
||||
digitalWrite(Dali->pin_tx, HIGH);
|
||||
digitalWrite(Dali->pin_tx, (Dali->invert_tx) ? LOW : HIGH); // Idle
|
||||
pinMode(Dali->pin_rx, INPUT);
|
||||
#ifdef DALI_DEBUG
|
||||
pinMode(DALI_DEBUG_PIN, OUTPUT);
|
||||
digitalWrite(DALI_DEBUG_PIN, HIGH);
|
||||
#endif // DALI_DEBUG
|
||||
|
||||
Dali->max_short_address = (DALI_MAX_SHORT_ADDRESS <= 64) ? DALI_MAX_SHORT_ADDRESS : 64;
|
||||
Dali->max_short_address = 64;
|
||||
Dali->dimmer = DALI_INIT_STATE;
|
||||
// Manchester twice 1200 bps = 2400 bps = 417 (protocol 416.76 +/- 10%) us
|
||||
Dali->bit_time = ESP.getCpuFreqMHz() * 1000000 / 2400;
|
||||
Dali->bit_cycles = ESP.getCpuFreqMHz() * 1000000 / 2400;
|
||||
|
||||
DaliEnableRxInterrupt();
|
||||
|
||||
|
|
Loading…
Reference in New Issue