mirror of https://github.com/arendst/Tasmota.git
commit
13b505d427
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "TasmotaSerial",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"keywords": [
|
||||
"serial", "io", "TasmotaSerial"
|
||||
],
|
|
@ -1,5 +1,5 @@
|
|||
name=TasmotaSerial
|
||||
version=2.4.0
|
||||
version=2.4.1
|
||||
author=Theo Arends
|
||||
maintainer=Theo Arends <theo@arends.com>
|
||||
sentence=Implementation of software serial with hardware serial fallback for ESP8266.
|
|
@ -213,39 +213,68 @@ int TasmotaSerial::available()
|
|||
|
||||
#ifdef TM_SERIAL_USE_IRAM
|
||||
#define TM_SERIAL_WAIT_SND { while (ESP.getCycleCount() < (wait + start)) if (!m_high_speed) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
|
||||
#define TM_SERIAL_WAIT_SND_FAST { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
|
||||
#define TM_SERIAL_WAIT_RCV { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
|
||||
#define TM_SERIAL_WAIT_RCV_LOOP { while (ESP.getCycleCount() < (wait + start)); }
|
||||
#else
|
||||
#define TM_SERIAL_WAIT_SND { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
|
||||
#define TM_SERIAL_WAIT_SND_FAST { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
|
||||
#define TM_SERIAL_WAIT_RCV { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
|
||||
#define TM_SERIAL_WAIT_RCV_LOOP { while (ESP.getCycleCount() < (wait + start)); }
|
||||
#endif
|
||||
|
||||
#ifdef TM_SERIAL_USE_IRAM
|
||||
void ICACHE_RAM_ATTR TasmotaSerial::_fast_write(uint8_t b) {
|
||||
#else
|
||||
void TasmotaSerial::_fast_write(uint8_t b) {
|
||||
#endif
|
||||
uint32_t wait = m_bit_time;
|
||||
uint32_t start = ESP.getCycleCount();
|
||||
// Start bit;
|
||||
digitalWrite(m_tx_pin, LOW);
|
||||
TM_SERIAL_WAIT_SND_FAST;
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
|
||||
TM_SERIAL_WAIT_SND_FAST;
|
||||
b >>= 1;
|
||||
}
|
||||
// Stop bit(s)
|
||||
digitalWrite(m_tx_pin, HIGH);
|
||||
for (uint32_t i = 0; i < m_stop_bits; i++) {
|
||||
TM_SERIAL_WAIT_SND_FAST;
|
||||
}
|
||||
}
|
||||
|
||||
size_t TasmotaSerial::write(uint8_t b)
|
||||
{
|
||||
if (m_hardserial) {
|
||||
return Serial.write(b);
|
||||
} else {
|
||||
if (-1 == m_tx_pin) return 0;
|
||||
if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit
|
||||
uint32_t wait = m_bit_time;
|
||||
//digitalWrite(m_tx_pin, HIGH); // already in HIGH mode
|
||||
uint32_t start = ESP.getCycleCount();
|
||||
// Start bit;
|
||||
digitalWrite(m_tx_pin, LOW);
|
||||
TM_SERIAL_WAIT_SND;
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
|
||||
TM_SERIAL_WAIT_SND;
|
||||
b >>= 1;
|
||||
}
|
||||
// Stop bit(s)
|
||||
digitalWrite(m_tx_pin, HIGH);
|
||||
// re-enable interrupts during stop bits, it's not an issue if they are longer than expected
|
||||
if (m_high_speed) sei();
|
||||
for (uint32_t i = 0; i < m_stop_bits; i++) {
|
||||
if (m_high_speed) {
|
||||
cli(); // Disable interrupts in order to get a clean transmit
|
||||
_fast_write(b);
|
||||
sei();
|
||||
} else {
|
||||
uint32_t wait = m_bit_time;
|
||||
//digitalWrite(m_tx_pin, HIGH); // already in HIGH mode
|
||||
uint32_t start = ESP.getCycleCount();
|
||||
// Start bit;
|
||||
digitalWrite(m_tx_pin, LOW);
|
||||
TM_SERIAL_WAIT_SND;
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
|
||||
TM_SERIAL_WAIT_SND;
|
||||
b >>= 1;
|
||||
}
|
||||
// Stop bit(s)
|
||||
digitalWrite(m_tx_pin, HIGH);
|
||||
// re-enable interrupts during stop bits, it's not an issue if they are longer than expected
|
||||
for (uint32_t i = 0; i < m_stop_bits; i++) {
|
||||
TM_SERIAL_WAIT_SND;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -81,6 +81,8 @@ class TasmotaSerial : public Stream {
|
|||
bool m_high_speed = false;
|
||||
bool m_very_high_speed = false; // above 100000 bauds
|
||||
uint8_t *m_buffer;
|
||||
|
||||
void _fast_write(uint8_t b); // IRAM minimized version
|
||||
};
|
||||
|
||||
#endif // TasmotaSerial_h
|
|
@ -1,10 +1,24 @@
|
|||
/*********************************************************************************************\
|
||||
* 6.6.0.15 20191003
|
||||
* Change command PulseTime JSON message format and allow display of all pulsetimer information (#6519)
|
||||
* Add support for Chint DDSU666 Modbus energy meter by Pablo Zerón
|
||||
* Add support for SM2135 as used in Action LSC Smart Led E14 (#6495)
|
||||
* Add command SetOption72 0/1 to switch between software (0) or hardware (1) energy total counter (#6561)
|
||||
* Add Zigbee tracking of connected devices and auto-probing of Manuf/Model Ids
|
||||
*
|
||||
* 6.6.0.14 20190925
|
||||
* Change command Tariffx to allow time entries like 23 (hours), 1320 (minutes) or 23:00. NOTE: As this is development branch previous tariffs are lost! (#6488)
|
||||
* Remove support for define USE_DS18x20_LEGACY and legacy DS18x20 driver (#6486)
|
||||
* Add initial support for MQTT logging using command MqttLog <loglevel> (#6498)
|
||||
* Add Zigbee more support - collect endpoints and clusters, added ZigbeeDump command
|
||||
* Add initial support for shutters by Stefan Bode (#288)
|
||||
* Add command to MCP230xx: sensor29 pin,0/1/2 for OFF/ON/TOGGLE
|
||||
* Add initial support for PCF8574 I2C I/O Expander (currently output only) by Stefan Bode
|
||||
* Add command SetOption71 0/1 to switch between different Modbus Active Energy registers on DDS238-2 energy meters (#6531)
|
||||
* Change command SetOption43 to make it more general. Now supports PS_16_DZ driver too (#6544)
|
||||
* Change command handling by moving buffers up in chain solving MQTTlog support (#6529)
|
||||
* Change detection of non-MQTT commands by allowing non-space characters as delimiter (#6540)
|
||||
* Fix TasmotaSerial: move serial send to IRAM for high speed baud rates
|
||||
*
|
||||
* 6.6.0.13 20190922
|
||||
* Add command EnergyReset4 x,x to initialize total usage for two tarrifs
|
||||
|
|
|
@ -118,6 +118,7 @@
|
|||
#define D_JSON_PROGRAMFLASHSIZE "ProgramFlashSize"
|
||||
#define D_JSON_PROGRAMSIZE "ProgramSize"
|
||||
#define D_JSON_REFERENCETEMPERATURE "ReferenceTemperature"
|
||||
#define D_JSON_REMAINING "Remaining"
|
||||
#define D_JSON_RESET "Reset"
|
||||
#define D_JSON_RESISTANCE "Resistance"
|
||||
#define D_JSON_RESOLUTION "Resolution"
|
||||
|
@ -132,6 +133,7 @@
|
|||
#define D_JSON_SDKVERSION "SDK"
|
||||
#define D_JSON_SELECTED "selected"
|
||||
#define D_JSON_SERIALRECEIVED "SerialReceived"
|
||||
#define D_JSON_SET "Set"
|
||||
#define D_JSON_SSID "SSId"
|
||||
#define D_JSON_STARTDST "StartDST" // Start Daylight Savings Time
|
||||
#define D_JSON_STARTED "Started"
|
||||
|
@ -456,12 +458,13 @@
|
|||
|
||||
// Commands xdrv_23_zigbee.ino
|
||||
#define D_CMND_ZIGBEE_PERMITJOIN "ZigbeePermitJoin"
|
||||
#define D_CMND_ZIGBEE_DUMP "ZigbeeDump"
|
||||
#define D_CMND_ZIGBEE_STATUS "ZigbeeStatus"
|
||||
#define D_CMND_ZIGBEEZNPSEND "ZigbeeZNPSend"
|
||||
#define D_JSON_ZIGBEE_STATUS "ZigbeeStatus"
|
||||
#define D_JSON_ZIGBEEZNPRECEIVED "ZigbeeZNPReceived"
|
||||
#define D_JSON_ZIGBEEZNPSENT "ZigbeeZNPSent"
|
||||
#define D_JSON_ZIGBEEZCLRECEIVED "ZigbeeZCLReceived"
|
||||
#define D_JSON_ZIGBEEZCL_RECEIVED "ZigbeeZCLReceived"
|
||||
#define D_JSON_ZIGBEEZCL_RAW_RECEIVED "ZigbeeZCLRawReceived"
|
||||
#define D_JSON_ZIGBEEZCLSENT "ZigbeeZCLSent"
|
||||
|
||||
// Commands xdrv_25_A4988_Stepper.ino
|
||||
|
@ -557,7 +560,6 @@ const char S_JSON_COMMAND_INDEX_LVALUE[] PROGMEM = "{\"%s%d\":%lu}";
|
|||
const char S_JSON_COMMAND_INDEX_SVALUE[] PROGMEM = "{\"%s%d\":\"%s\"}";
|
||||
const char S_JSON_COMMAND_INDEX_ASTERISK[] PROGMEM = "{\"%s%d\":\"" D_ASTERISK_PWD "\"}";
|
||||
const char S_JSON_COMMAND_INDEX_SVALUE_SVALUE[] PROGMEM = "{\"%s%d\":\"%s%s\"}";
|
||||
const char S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE[] PROGMEM = "{\"%s%d\":{\"%d\":{\"" D_JSON_ACTIVE "\":\"%d\"}}}";
|
||||
|
||||
const char S_JSON_SENSOR_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":%d}";
|
||||
const char S_JSON_SENSOR_INDEX_SVALUE[] PROGMEM = "{\"" D_CMND_SENSOR "%d\":\"%s\"}";
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Параметри на лога"
|
||||
#define D_SERIAL_LOG_LEVEL "Степен на серийния лог"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Степен на уеб лога"
|
||||
#define D_SYS_LOG_LEVEL "Степен на системния лог"
|
||||
#define D_MORE_DEBUG "Още дебъгване"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Датчикът DS18x20 е зает"
|
||||
#define D_SENSOR_CRC_ERROR "Датчик DS18x20 - грешка CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Volba logování"
|
||||
#define D_SERIAL_LOG_LEVEL "Seriová úroveň logu"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Webová úroveň logu"
|
||||
#define D_SYS_LOG_LEVEL "Systemová úroveň logu"
|
||||
#define D_MORE_DEBUG "Více debug informací"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor DS18x20 obsazen"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor DS18x20 chyba CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
|
||||
* Use online command Prefix to translate cmnd, stat and tele.
|
||||
*
|
||||
* Updated until v6.6.0.4
|
||||
* Updated until v6.6.0.14
|
||||
\*********************************************************************/
|
||||
|
||||
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
|
@ -284,9 +284,10 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Logging-Einstellungen"
|
||||
#define D_SERIAL_LOG_LEVEL "Seriell-Log Level"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt-Log Level"
|
||||
#define D_WEB_LOG_LEVEL "Web-Log Level"
|
||||
#define D_SYS_LOG_LEVEL "Sys-Log Level"
|
||||
#define D_MORE_DEBUG "More debug"
|
||||
#define D_MORE_DEBUG "Mehr Details"
|
||||
#define D_SYSLOG_HOST "Sys-Log Host"
|
||||
#define D_SYSLOG_PORT "Sys-Log Port"
|
||||
#define D_TELEMETRY_PERIOD "Telemetrieperiode"
|
||||
|
@ -443,9 +444,17 @@
|
|||
#define D_ENERGY_TOTAL "Energie insgesamt"
|
||||
|
||||
// xdrv_27_shutter.ino
|
||||
#define D_OPEN "Open"
|
||||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
#define D_OPEN "Öffnen"
|
||||
#define D_CLOSE "Schliessen"
|
||||
#define D_DOMOTICZ_SHUTTER "Rollo"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Konfiguriere PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 Parameter"
|
||||
#define D_INVERT_PORTS "Invertiere Ports"
|
||||
#define D_DEVICE "Gerät"
|
||||
#define D_DEVICE_INPUT "Eingang"
|
||||
#define D_DEVICE_OUTPUT "Ausgang"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor beschäftigt"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Παράμετροι καταγραφής"
|
||||
#define D_SERIAL_LOG_LEVEL "Επίπεδο Σειριακής"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Επίπεδο Web"
|
||||
#define D_SYS_LOG_LEVEL "Επίπεδο Syslog"
|
||||
#define D_MORE_DEBUG "More debug"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Ο αισθητήρας είναι απασχολημένος"
|
||||
#define D_SENSOR_CRC_ERROR "Σφάλμα CRC αισθητήρα"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Logging parameters"
|
||||
#define D_SERIAL_LOG_LEVEL "Serial log level"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web log level"
|
||||
#define D_SYS_LOG_LEVEL "Syslog level"
|
||||
#define D_MORE_DEBUG "More debug"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor busy"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor CRC error"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
|
||||
* Use online command Prefix to translate cmnd, stat and tele.
|
||||
*
|
||||
* Updated until v6.6.0.4
|
||||
* Updated until v6.6.0.14
|
||||
\*********************************************************************/
|
||||
|
||||
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Parámetros Logging"
|
||||
#define D_SERIAL_LOG_LEVEL "Nivel de log Serial"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Nivel de log Web"
|
||||
#define D_SYS_LOG_LEVEL "Nivel de Syslog"
|
||||
#define D_MORE_DEBUG "Más Debug"
|
||||
|
@ -443,9 +444,17 @@
|
|||
#define D_ENERGY_TOTAL "Energía Total"
|
||||
|
||||
// xdrv_27_shutter.ino
|
||||
#define D_OPEN "Open"
|
||||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
#define D_OPEN "Abrir"
|
||||
#define D_CLOSE "Cerrar"
|
||||
#define D_DOMOTICZ_SHUTTER "Cortina"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configurar PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "Parámetros de PCF8574"
|
||||
#define D_INVERT_PORTS "Invertir Puertos"
|
||||
#define D_DEVICE "Dispositivo"
|
||||
#define D_DEVICE_INPUT "Entrada"
|
||||
#define D_DEVICE_OUTPUT "Salida"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor ocupado"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Paramètres du journal"
|
||||
#define D_SERIAL_LOG_LEVEL "Niveau de journalisation série"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Niveau de journalisation web"
|
||||
#define D_SYS_LOG_LEVEL "Niveau SysLog"
|
||||
#define D_MORE_DEBUG "Plus de debug"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Capteur occupé"
|
||||
#define D_SENSOR_CRC_ERROR "Erreur CRC capteur"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "פרמטרי לוגים"
|
||||
#define D_SERIAL_LOG_LEVEL "רמת לוג עבור סריאל"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "רמת לוג עבור אתר"
|
||||
#define D_SYS_LOG_LEVEL "Syslog רמת לוג עבור שרת"
|
||||
#define D_MORE_DEBUG "מיפוי נוסף"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "שרת עסוק"
|
||||
#define D_SENSOR_CRC_ERROR "בחיישן CRC שגיאת"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Naplózási paraméterek"
|
||||
#define D_SERIAL_LOG_LEVEL "Soros naplózási szint"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web naplózási szint"
|
||||
#define D_SYS_LOG_LEVEL "Syslog szint"
|
||||
#define D_MORE_DEBUG "Részletes hibakeresés"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Szenzor foglalt"
|
||||
#define D_SENSOR_CRC_ERROR "Szenzor CRC hiba"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Parametri Logging"
|
||||
#define D_SERIAL_LOG_LEVEL "Livello di log Seriale"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "livello di log Web"
|
||||
#define D_SYS_LOG_LEVEL "livello di log Sys"
|
||||
#define D_MORE_DEBUG "Debug aggiuntivo"
|
||||
|
@ -443,9 +444,17 @@
|
|||
#define D_ENERGY_TOTAL "Energia Totale"
|
||||
|
||||
// xdrv_27_shutter.ino
|
||||
#define D_OPEN "Open"
|
||||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
#define D_OPEN "Aperta"
|
||||
#define D_CLOSE "Chiusa"
|
||||
#define D_DOMOTICZ_SHUTTER "Serranda"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configura PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "Parametri PCF8574"
|
||||
#define D_INVERT_PORTS "Porte Invertite"
|
||||
#define D_DEVICE "Dispositivo"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensore occupato"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "로그 상세"
|
||||
#define D_SERIAL_LOG_LEVEL "시리얼 로그 레벨"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web 로그 레벨"
|
||||
#define D_SYS_LOG_LEVEL "Syslog 로그 레벨"
|
||||
#define D_MORE_DEBUG "More debug"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "센서가 사용 중"
|
||||
#define D_SENSOR_CRC_ERROR "센서 CRC 에러"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Logging parameters"
|
||||
#define D_SERIAL_LOG_LEVEL "Serieel log niveau"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web log niveau"
|
||||
#define D_SYS_LOG_LEVEL "Syslog niveau"
|
||||
#define D_MORE_DEBUG "Meer debug"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor bezet"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor CRC fout"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Opcje dziennika"
|
||||
#define D_SERIAL_LOG_LEVEL "Serial poziom dziennika"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web poziom dziennika"
|
||||
#define D_SYS_LOG_LEVEL "System poziom dziennika"
|
||||
#define D_MORE_DEBUG "Więcej informacji debug"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Czujnik DS18x20 zajęty"
|
||||
#define D_SENSOR_CRC_ERROR "Czujnik DS18x20 błąd CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Parâmetros Logging"
|
||||
#define D_SERIAL_LOG_LEVEL "Nível de registro serial"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Nível de registro WEB"
|
||||
#define D_SYS_LOG_LEVEL "Nível de registro Syslog"
|
||||
#define D_MORE_DEBUG "Depurar mais"
|
||||
|
@ -443,9 +444,17 @@
|
|||
#define D_ENERGY_TOTAL "Consumo total de energia"
|
||||
|
||||
// xdrv_27_shutter.ino
|
||||
#define D_OPEN "Open"
|
||||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
#define D_OPEN "Aberta"
|
||||
#define D_CLOSE "Fechada"
|
||||
#define D_DOMOTICZ_SHUTTER "Persiana"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configura PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "Parâmetros PCF8574"
|
||||
#define D_INVERT_PORTS "Portas Invertidas"
|
||||
#define D_DEVICE "Dispositivo"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor ocupado"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Parametros Logging"
|
||||
#define D_SERIAL_LOG_LEVEL "Nível de registro serial"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Nível de registro WEB"
|
||||
#define D_SYS_LOG_LEVEL "Nível de registro Syslog"
|
||||
#define D_MORE_DEBUG "Depurar mais"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor ocupado"
|
||||
#define D_SENSOR_CRC_ERROR "Erro Sensor CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Параметры Logging"
|
||||
#define D_SERIAL_LOG_LEVEL "Serial лог уровень"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web лог уровень"
|
||||
#define D_SYS_LOG_LEVEL "System лог уровень"
|
||||
#define D_MORE_DEBUG "Дополнительная информация для отладки"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Датчик DS18x20 занят"
|
||||
#define D_SENSOR_CRC_ERROR "Датчик DS18x20 - ошибка CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "А"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Voľba logovania"
|
||||
#define D_SERIAL_LOG_LEVEL "Sériová úroveň logu"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Webová úroveň logu"
|
||||
#define D_SYS_LOG_LEVEL "Systemová úroveň logu"
|
||||
#define D_MORE_DEBUG "Viac debug informácí"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor DS18x20 obsadený"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor DS18x20 chyba CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Loggningsparametrar"
|
||||
#define D_SERIAL_LOG_LEVEL "Seriell loggnivå"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Webb loggnivå"
|
||||
#define D_SYS_LOG_LEVEL "Syslog-nivå"
|
||||
#define D_MORE_DEBUG "Mer debugging"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor upptagen"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor CRC-fel"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Loglama parametreleri"
|
||||
#define D_SERIAL_LOG_LEVEL "Serial log seviyesi"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web log seviyesi"
|
||||
#define D_SYS_LOG_LEVEL "Syslog seviyesi"
|
||||
#define D_MORE_DEBUG "Hata ayıklama devamı"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensör başgül"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor CRC hatası"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "Параметри журналу"
|
||||
#define D_SERIAL_LOG_LEVEL "Serial рівень"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web рівень"
|
||||
#define D_SYS_LOG_LEVEL "System рівень"
|
||||
#define D_MORE_DEBUG "Додаткова інформація для налагодження"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Датчик DS18x20 зайнятий"
|
||||
#define D_SENSOR_CRC_ERROR "Датчик DS18x20 - помилка CRC"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "А"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "日志设置"
|
||||
#define D_SERIAL_LOG_LEVEL "串口日志级别"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web 日志级别"
|
||||
#define D_SYS_LOG_LEVEL "Syslog 日志级别"
|
||||
#define D_MORE_DEBUG "全部调试"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "传感器正忙"
|
||||
#define D_SENSOR_CRC_ERROR "传感器 CRC 校验错误"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "安"
|
||||
|
|
|
@ -284,6 +284,7 @@
|
|||
|
||||
#define D_LOGGING_PARAMETERS "日志設置"
|
||||
#define D_SERIAL_LOG_LEVEL "串口日志級別"
|
||||
#define D_MQTT_LOG_LEVEL "Mqtt log level"
|
||||
#define D_WEB_LOG_LEVEL "Web 日志級別"
|
||||
#define D_SYS_LOG_LEVEL "Syslog 日志級別"
|
||||
#define D_MORE_DEBUG "全部調試"
|
||||
|
@ -447,6 +448,14 @@
|
|||
#define D_CLOSE "Close"
|
||||
#define D_DOMOTICZ_SHUTTER "Shutter"
|
||||
|
||||
// xdrv_28_pcf8574.ino
|
||||
#define D_CONFIGURE_PCF8574 "Configure PCF8574"
|
||||
#define D_PCF8574_PARAMETERS "PCF8574 parameters"
|
||||
#define D_INVERT_PORTS "Invert Ports"
|
||||
#define D_DEVICE "Device"
|
||||
#define D_DEVICE_INPUT "Input"
|
||||
#define D_DEVICE_OUTPUT "Output"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "傳感器正忙"
|
||||
#define D_SENSOR_CRC_ERROR "傳感器 CRC 校驗錯誤"
|
||||
|
@ -609,6 +618,10 @@
|
|||
#define D_SENSOR_A4988_MS3 "A4988 MS3"
|
||||
#define D_SENSOR_DDS2382_TX "DDS238-2 Tx"
|
||||
#define D_SENSOR_DDS2382_RX "DDS238-2 Rx"
|
||||
#define D_SENSOR_DDSU666_TX "DDSU666 Tx"
|
||||
#define D_SENSOR_DDSU666_RX "DDSU666 Rx"
|
||||
#define D_SENSOR_SM2135_CLK "SM2135 Clk"
|
||||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "安"
|
||||
|
|
|
@ -66,8 +66,9 @@
|
|||
#define STA_PASS1 "" // [Password1] Wifi password
|
||||
#define STA_SSID2 "" // [Ssid2] Optional alternate AP Wifi SSID
|
||||
#define STA_PASS2 "" // [Password2] Optional alternate AP Wifi password
|
||||
#define WIFI_CONFIG_TOOL WIFI_RETRY // [WifiConfig] Default tool if wifi fails to connect
|
||||
// (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL)
|
||||
#define WIFI_CONFIG_TOOL WIFI_RETRY // [WifiConfig] Default tool if wifi fails to connect (default option: 4 - WIFI_RETRY)
|
||||
// (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, WIFI_MANAGER_RESET_ONLY)
|
||||
// The configuration can be changed after first setup using WifiConfig 0, 1, 2, 3, 4, 5, 6 and 7.
|
||||
#define WIFI_CONFIG_NO_SSID WIFI_WPSCONFIG // Default tool if wifi fails to connect and no SSID is configured
|
||||
// (WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_SERIAL)
|
||||
// *** NOTE: When WPS is disabled by USE_WPS below, WIFI_WPSCONFIG will execute WIFI_MANAGER ***
|
||||
|
@ -80,6 +81,7 @@
|
|||
#define SYS_LOG_LEVEL LOG_LEVEL_NONE // [SysLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE)
|
||||
#define SERIAL_LOG_LEVEL LOG_LEVEL_INFO // [SerialLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE)
|
||||
#define WEB_LOG_LEVEL LOG_LEVEL_INFO // [WebLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE)
|
||||
#define MQTT_LOG_LEVEL LOG_LEVEL_NONE // [MqttLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE)
|
||||
|
||||
// -- Ota -----------------------------------------
|
||||
#define OTA_URL "http://thehackbox.org/tasmota/release/sonoff.bin" // [OtaUrl]
|
||||
|
@ -315,6 +317,15 @@
|
|||
//#define ROTARY_V1 // Add support for MI Desk Lamp
|
||||
//#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code)
|
||||
|
||||
// -- Optional light modules ----------------------
|
||||
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
|
||||
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
|
||||
#define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106)
|
||||
#define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
|
||||
#define USE_MY92X1 // Add support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas
|
||||
#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
|
||||
#define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code)
|
||||
|
||||
// -- Counter input -------------------------------
|
||||
#define USE_COUNTER // Enable inputs as counter (+0k8 code)
|
||||
|
||||
|
@ -372,6 +383,7 @@
|
|||
// #define USE_MLX90614 // Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code)
|
||||
// #define USE_CHIRP // Enable CHIRP soil moisture sensor (variable I2C address, default 0x20)
|
||||
// #define USE_PAJ7620 // Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code)
|
||||
// #define USE_PCF8574 // Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x27 and 0x38 - 0x3F) (+1k9 code)
|
||||
|
||||
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
||||
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
||||
|
@ -436,6 +448,8 @@
|
|||
#define SDM630_SPEED 9600 // SDM630-Modbus RS485 serial speed (default: 9600 baud)
|
||||
//#define USE_DDS2382 // Add support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#define DDS2382_SPEED 9600 // Hiking DDS2382 Modbus RS485 serial speed (default: 9600 baud)
|
||||
//#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
#define DDSU666_SPEED 9600 // Chint DDSU666 Modbus RS485 serial speed (default: 9600 baud)
|
||||
|
||||
//#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy meter (+2k4 code)
|
||||
// #define SDM120_SPEED 2400 // SDM120-Modbus RS485 serial speed (default: 2400 baud)
|
||||
|
@ -507,11 +521,6 @@
|
|||
|
||||
// ------------------------------------------------
|
||||
|
||||
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
|
||||
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
|
||||
#define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106)
|
||||
#define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
|
||||
|
||||
#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code, 252 iram (non 2.3.0))
|
||||
|
||||
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
|
||||
|
@ -530,8 +539,6 @@
|
|||
// #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code)
|
||||
// #define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 weather stations using 868MHz RF sensor receiver (+1k7 code)
|
||||
|
||||
#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
|
||||
|
||||
//#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code)
|
||||
//#define USE_A4988_Stepper // Add support for A4988 stepper-motor-driver-circuit (+10k5 code)
|
||||
|
||||
|
|
|
@ -84,8 +84,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
|
|||
uint32_t pwm_multi_channels : 1; // bit 18 (v6.6.0.3) - SetOption68 - Enable multi-channels PWM instead of Color PWM
|
||||
uint32_t tuya_dimmer_min_limit : 1; // bit 19 (v6.6.0.5) - SetOption69 - Limits Tuya dimmers to minimum of 10% (25) when enabled.
|
||||
uint32_t energy_weekend : 1; // bit 20 (v6.6.0.8) - CMND_TARIFF
|
||||
uint32_t spare21 : 1;
|
||||
uint32_t spare22 : 1;
|
||||
uint32_t dds2382_model : 1; // bit 21 (v6.6.0.14) - SetOption71 - Select different Modbus registers for Active Energy (#6531)
|
||||
uint32_t hardware_energy_total : 1; // bit 22 (v6.6.0.15) - SetOption72 - Enable / Disable hardware energy total counter as reference (#6561)
|
||||
uint32_t spare23 : 1;
|
||||
uint32_t spare24 : 1;
|
||||
uint32_t spare25 : 1;
|
||||
|
@ -93,8 +93,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
|
|||
uint32_t spare27 : 1;
|
||||
uint32_t spare28 : 1;
|
||||
uint32_t spare29 : 1;
|
||||
uint32_t shutter_mode : 1; // bit 30 (v6.6.0.15) - SetOption80 - Enable shutter support
|
||||
uint32_t spare31 : 1;
|
||||
uint32_t shutter_mode : 1; // bit 30 (v6.6.0.14) - SetOption80 - Enable shutter support
|
||||
uint32_t pcf8574_ports_inverted : 1; // bit 31 (v6.6.0.14) - SetOption81 - Invert all ports on PCF8574 devices
|
||||
};
|
||||
} SysBitfield3;
|
||||
|
||||
|
@ -376,7 +376,6 @@ struct SYSCFG {
|
|||
uint16_t ina226_r_shunt[4]; // E20
|
||||
uint16_t ina226_i_fs[4]; // E28
|
||||
uint16_t tariff[4][2]; // E30
|
||||
|
||||
uint16_t shutter_opentime[MAX_SHUTTERS]; // E40
|
||||
uint16_t shutter_closetime[MAX_SHUTTERS]; // E48
|
||||
int16_t shuttercoeff[5][MAX_SHUTTERS]; // E50
|
||||
|
@ -384,8 +383,9 @@ struct SYSCFG {
|
|||
uint8_t shutter_set50percent[MAX_SHUTTERS]; // E7C
|
||||
uint8_t shutter_position[MAX_SHUTTERS]; // E80
|
||||
uint8_t shutter_startrelay[MAX_SHUTTERS]; // E84
|
||||
uint8_t pcf8574_config[MAX_PCF8574]; // E88
|
||||
|
||||
uint8_t free_e88[368]; // E88
|
||||
uint8_t free_e90[360]; // E90
|
||||
|
||||
uint32_t cfg_timestamp; // FF8
|
||||
uint32_t cfg_crc32; // FFC
|
||||
|
|
|
@ -125,8 +125,8 @@
|
|||
#ifndef ENERGY_OVERTEMP
|
||||
#define ENERGY_OVERTEMP 90 // Overtemp in Celsius
|
||||
#endif
|
||||
#ifndef TUYA_DIMMER_MAX
|
||||
#define TUYA_DIMMER_MAX 100
|
||||
#ifndef DEFAULT_DIMMER_MAX
|
||||
#define DEFAULT_DIMMER_MAX 100
|
||||
#endif
|
||||
|
||||
enum WebColors {
|
||||
|
@ -678,6 +678,7 @@ void SettingsDefaultSet2(void)
|
|||
Settings.mqtt_fingerprint[1][i] = strtol(p, &p, 16);
|
||||
}
|
||||
Settings.tele_period = TELE_PERIOD;
|
||||
Settings.mqttlog_level = MQTT_LOG_LEVEL;
|
||||
|
||||
// Energy
|
||||
Settings.flag2.current_resolution = 3;
|
||||
|
@ -774,7 +775,7 @@ void SettingsDefaultSet2(void)
|
|||
// Settings.light_rotation = 0;
|
||||
SettingsDefaultSet_5_8_1(); // Clock color
|
||||
|
||||
Settings.param[P_TUYA_DIMMER_MAX] = TUYA_DIMMER_MAX;
|
||||
Settings.param[P_DIMMER_MAX] = DEFAULT_DIMMER_MAX;
|
||||
|
||||
// Display
|
||||
SettingsDefaultSet_5_10_1(); // Display settings
|
||||
|
@ -1084,9 +1085,9 @@ void SettingsDelta(void)
|
|||
if (Settings.version < 0x06060008) {
|
||||
// Move current tuya dimmer range to the new param.
|
||||
if (Settings.flag3.tuya_dimmer_range_255) {
|
||||
Settings.param[P_TUYA_DIMMER_MAX] = 100;
|
||||
Settings.param[P_DIMMER_MAX] = 100;
|
||||
} else {
|
||||
Settings.param[P_TUYA_DIMMER_MAX] = 255;
|
||||
Settings.param[P_DIMMER_MAX] = 255;
|
||||
}
|
||||
}
|
||||
if (Settings.version < 0x06060009) {
|
||||
|
|
|
@ -68,6 +68,7 @@ const uint8_t MAX_XDSP_DRIVERS = 32; // Max number of allowed display dri
|
|||
const uint8_t MAX_XDRV_DRIVERS = 96; // Max number of allowed driver drivers
|
||||
const uint8_t MAX_XSNS_DRIVERS = 96; // Max number of allowed sensor drivers
|
||||
const uint8_t MAX_SHUTTERS = 4; // Max number of shutters
|
||||
const uint8_t MAX_PCF8574 = 8; // Max number of PCF8574 devices
|
||||
const uint8_t MAX_RULE_MEMS = 5; // Max number of saved vars
|
||||
const uint8_t MAX_RULE_SETS = 3; // Max number of rule sets of size 512 characters
|
||||
const uint16_t MAX_RULE_SIZE = 512; // Max number of characters in rules
|
||||
|
@ -248,7 +249,7 @@ enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER };
|
|||
|
||||
enum SettingsParamIndex { P_HOLD_TIME, P_MAX_POWER_RETRY, P_ex_TUYA_DIMMER_ID, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38
|
||||
P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_ex_TUYA_RELAYS, P_OVER_TEMP, // SetOption39 .. SetOption42
|
||||
P_TUYA_DIMMER_MAX,
|
||||
P_DIMMER_MAX,
|
||||
P_ex_TUYA_VOLTAGE_ID, P_ex_TUYA_CURRENT_ID, P_ex_TUYA_POWER_ID, // SetOption43 .. SetOption46
|
||||
P_ex_ENERGY_TARIFF1, P_ex_ENERGY_TARIFF2, // SetOption47 .. SetOption48
|
||||
P_MAX_PARAM8 }; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
|
||||
|
|
|
@ -130,6 +130,7 @@ uint8_t led_power = 0; // LED power state
|
|||
uint8_t ledlnk_inverted = 0; // Link LED inverted flag (1 = (0 = On, 1 = Off))
|
||||
uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted)
|
||||
uint8_t energy_flg = 0; // Energy monitor configured
|
||||
uint8_t light_flg = 0; // Light module configured
|
||||
uint8_t light_type = 0; // Light types
|
||||
uint8_t serial_in_byte; // Received byte
|
||||
uint8_t ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter
|
||||
|
@ -315,6 +316,7 @@ void SetLatchingRelay(power_t lpower, uint32_t state)
|
|||
void SetDevicePower(power_t rpower, uint32_t source)
|
||||
{
|
||||
ShowSource(source);
|
||||
last_source = source;
|
||||
|
||||
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) { // All on and stay on
|
||||
power = (1 << devices_present) -1;
|
||||
|
@ -1390,14 +1392,6 @@ void GpioInit(void)
|
|||
devices_present = 1;
|
||||
|
||||
light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
|
||||
#ifdef USE_LIGHT
|
||||
if (Settings.flag.pwm_control) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (pin[GPIO_PWM1 +i] < 99) { light_type++; } // Use Dimmer/Color control for all PWM as SetOption15 = 1
|
||||
}
|
||||
}
|
||||
#endif // USE_LIGHT
|
||||
|
||||
if (XdrvCall(FUNC_MODULE_INIT)) {
|
||||
// Serviced
|
||||
}
|
||||
|
@ -1419,30 +1413,24 @@ void GpioInit(void)
|
|||
devices_present = 0;
|
||||
baudrate = 19200;
|
||||
}
|
||||
#ifdef USE_LIGHT
|
||||
else if (SONOFF_BN == my_module_type) { // PWM Single color led (White)
|
||||
light_type = LT_PWM1;
|
||||
|
||||
if (!light_type) {
|
||||
devices_present = 0;
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (pin[GPIO_PWM1 +i] < 99) {
|
||||
pwm_present = true;
|
||||
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
|
||||
analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (SONOFF_LED == my_module_type) { // PWM Dual color led (White warm and cold)
|
||||
light_type = LT_PWM2;
|
||||
}
|
||||
else if (AILIGHT == my_module_type) { // RGBW led
|
||||
light_type = LT_RGBW;
|
||||
}
|
||||
else if (SONOFF_B1 == my_module_type) { // RGBWC led
|
||||
light_type = LT_RGBWC;
|
||||
}
|
||||
#endif // USE_LIGHT
|
||||
else {
|
||||
if (!light_type) { devices_present = 0; }
|
||||
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
||||
if (pin[GPIO_REL1 +i] < 99) {
|
||||
pinMode(pin[GPIO_REL1 +i], OUTPUT);
|
||||
devices_present++;
|
||||
if (EXS_RELAY == my_module_type) {
|
||||
digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0);
|
||||
if (i &1) { devices_present--; }
|
||||
}
|
||||
for (uint32_t i = 0; i < MAX_RELAYS; i++) {
|
||||
if (pin[GPIO_REL1 +i] < 99) {
|
||||
pinMode(pin[GPIO_REL1 +i], OUTPUT);
|
||||
devices_present++;
|
||||
if (EXS_RELAY == my_module_type) {
|
||||
digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0);
|
||||
if (i &1) { devices_present--; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1474,37 +1462,6 @@ void GpioInit(void)
|
|||
RotaryInit();
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
#ifdef USE_WS2812
|
||||
if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led
|
||||
devices_present++;
|
||||
light_type = LT_WS2812;
|
||||
}
|
||||
#endif // USE_WS2812
|
||||
#ifdef USE_SM16716
|
||||
if (SM16716_ModuleSelected()) {
|
||||
light_type += 3;
|
||||
light_type |= LT_SM16716;
|
||||
}
|
||||
#endif // USE_SM16716
|
||||
|
||||
// post-process for lights
|
||||
if (Settings.flag3.pwm_multi_channels) {
|
||||
uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7);
|
||||
if (0 == pwm_channels) { pwm_channels = 1; }
|
||||
devices_present += pwm_channels - 1; // add the pwm channels controls at the end
|
||||
}
|
||||
#endif // USE_LIGHT
|
||||
if (!light_type) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
|
||||
if (pin[GPIO_PWM1 +i] < 99) {
|
||||
pwm_present = true;
|
||||
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
|
||||
analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetLedPower(Settings.ledstate &8);
|
||||
SetLedLink(Settings.ledstate &8);
|
||||
|
||||
|
|
|
@ -165,6 +165,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
|||
#define USE_SDM120_2 // Add support for Eastron SDM120-Modbus energy monitor (+1k1 code)
|
||||
#define USE_SDM630_2 // Add support for Eastron SDM630-Modbus energy monitor (+0k6 code)
|
||||
#define USE_DDS2382 // Add support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
|
||||
#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
|
||||
#define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI
|
||||
|
@ -251,6 +252,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
|||
#undef USE_SDM120_2 // Disable support for Eastron SDM120-Modbus energy meter
|
||||
#undef USE_SDM630_2 // Disable support for Eastron SDM630-Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDS2382 // Disable support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
|
||||
#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
|
||||
#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI
|
||||
|
@ -305,6 +307,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
|||
#undef USE_SDM120_2 // Disable support for Eastron SDM120-Modbus energy meter
|
||||
#undef USE_SDM630_2 // Disable support for Eastron SDM630-Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDS2382 // Disable support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
#undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem)
|
||||
#undef USE_DOMOTICZ // Disable Domoticz
|
||||
#undef USE_HOME_ASSISTANT // Disable Home Assistant
|
||||
|
@ -388,6 +391,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
|||
#undef USE_SDM120_2 // Disable support for Eastron SDM120-Modbus energy meter
|
||||
#undef USE_SDM630_2 // Disable support for Eastron SDM630-Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDS2382 // Disable support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
|
||||
//#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
|
||||
#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI
|
||||
|
@ -484,6 +488,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
|||
#undef USE_SDM120_2 // Disable support for Eastron SDM120-Modbus energy meter
|
||||
#undef USE_SDM630_2 // Disable support for Eastron SDM630-Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDS2382 // Disable support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
|
||||
#undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
|
||||
#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI
|
||||
|
@ -568,6 +573,7 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
|
|||
#undef USE_SDM120_2 // Disable support for Eastron SDM120-Modbus energy meter
|
||||
#undef USE_SDM630_2 // Disable support for Eastron SDM630-Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDS2382 // Disable support for Hiking DDS2382 Modbus energy monitor (+0k6 code)
|
||||
#undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code)
|
||||
|
||||
#undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
|
||||
#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI
|
||||
|
|
|
@ -202,6 +202,10 @@ enum UserSelectablePins {
|
|||
GPIO_A4988_MS3, // A4988 microstep pin3
|
||||
GPIO_DDS2382_TX, // DDS2382 Serial interface
|
||||
GPIO_DDS2382_RX, // DDS2382 Serial interface
|
||||
GPIO_DDSU666_TX, // DDSU666 Serial interface
|
||||
GPIO_DDSU666_RX, // DDSU666 Serial interface
|
||||
GPIO_SM2135_CLK, // SM2135 Clk
|
||||
GPIO_SM2135_DAT, // SM2135 Dat
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Programmer selectable GPIO functionality
|
||||
|
@ -277,6 +281,8 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_IBEACON_TX "|" D_SENSOR_IBEACON_RX "|"
|
||||
D_SENSOR_A4988_DIR "|" D_SENSOR_A4988_STP "|" D_SENSOR_A4988_ENA "|" D_SENSOR_A4988_MS1 "|" D_SENSOR_A4988_MS2 "|" D_SENSOR_A4988_MS3 "|"
|
||||
D_SENSOR_DDS2382_TX "|" D_SENSOR_DDS2382_RX "|"
|
||||
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
|
||||
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
|
||||
;
|
||||
|
||||
// User selectable ADC0 functionality
|
||||
|
@ -544,13 +550,19 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
|||
GPIO_ARIRFRCV, // AriLux RF Receive input
|
||||
GPIO_ARIRFSEL, // Arilux RF Receive input selected
|
||||
#endif
|
||||
#ifdef USE_MY92X1
|
||||
GPIO_DI, // my92x1 PWM input
|
||||
GPIO_DCKI, // my92x1 CLK input
|
||||
#endif // USE_MY92X1
|
||||
#ifdef USE_SM16716
|
||||
GPIO_SM16716_CLK, // SM16716 CLOCK
|
||||
GPIO_SM16716_DAT, // SM16716 DATA
|
||||
GPIO_SM16716_SEL, // SM16716 SELECT
|
||||
#endif // USE_SM16716
|
||||
#ifdef USE_SM2135
|
||||
GPIO_SM2135_CLK, // SM2135 CLOCK
|
||||
GPIO_SM2135_DAT, // SM2135 DATA
|
||||
#endif // USE_SM2135
|
||||
#ifdef USE_TUYA_MCU
|
||||
GPIO_TUYA_TX, // Tuya Serial interface
|
||||
GPIO_TUYA_RX, // Tuya Serial interface
|
||||
|
@ -645,6 +657,10 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
|||
GPIO_SOLAXX1_TX, // Solax Inverter tx pin
|
||||
GPIO_SOLAXX1_RX, // Solax Inverter rx pin
|
||||
#endif
|
||||
#ifdef USE_DDSU666
|
||||
GPIO_DDSU666_TX, // DDSU666 Serial interface
|
||||
GPIO_DDSU666_RX, // DDSU666 Serial interface
|
||||
#endif // USE_DDSU666
|
||||
|
||||
#ifdef USE_SERIAL_BRIDGE
|
||||
GPIO_SBR_TX, // Serial Bridge Serial interface
|
||||
|
|
|
@ -20,6 +20,6 @@
|
|||
#ifndef _SONOFF_VERSION_H_
|
||||
#define _SONOFF_VERSION_H_
|
||||
|
||||
const uint32_t VERSION = 0x0606000E;
|
||||
const uint32_t VERSION = 0x0606000F;
|
||||
|
||||
#endif // _SONOFF_VERSION_H_
|
||||
|
|
|
@ -1460,8 +1460,8 @@ void I2cScan(char *devs, unsigned int devs_len)
|
|||
|
||||
void I2cSetActive(uint32_t addr, uint32_t count = 1)
|
||||
{
|
||||
addr &= 0x7F;
|
||||
count &= 0x7F;
|
||||
addr &= 0x7F; // Max I2C address is 127
|
||||
count &= 0x7F; // Max 4 x 32 bits available
|
||||
while (count-- && (addr < 128)) {
|
||||
i2c_active[addr / 32] |= (1 << (addr % 32));
|
||||
addr++;
|
||||
|
@ -1471,7 +1471,7 @@ void I2cSetActive(uint32_t addr, uint32_t count = 1)
|
|||
|
||||
bool I2cActive(uint32_t addr)
|
||||
{
|
||||
addr &= 0x7F;
|
||||
addr &= 0x7F; // Max I2C address is 127
|
||||
if (i2c_active[addr / 32] & (1 << (addr % 32))) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1480,16 +1480,12 @@ bool I2cActive(uint32_t addr)
|
|||
|
||||
bool I2cDevice(uint8_t addr)
|
||||
{
|
||||
addr &= 0x7F; // Max I2C address is 127
|
||||
if (I2cActive(addr)) {
|
||||
return false; // If already active report as not present;
|
||||
}
|
||||
for (uint8_t address = 1; address <= 127; address++) {
|
||||
Wire.beginTransmission(address);
|
||||
if (!Wire.endTransmission() && (address == addr)) {
|
||||
return true; // Report as present;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
Wire.beginTransmission(addr);
|
||||
return (0 == Wire.endTransmission());
|
||||
}
|
||||
#endif // USE_I2C
|
||||
|
||||
|
|
|
@ -81,55 +81,61 @@ void ResponseCmndIdxChar(const char* value)
|
|||
|
||||
/********************************************************************************************/
|
||||
|
||||
void ExecuteCommand(char *cmnd, uint32_t source)
|
||||
void ExecuteCommand(const char *cmnd, uint32_t source)
|
||||
{
|
||||
char *start;
|
||||
char *token;
|
||||
|
||||
// cmnd: "status 0" = stopic "status" and svalue " 0"
|
||||
// cmnd: "var1 =1" = stopic "var1" and svalue " =1"
|
||||
// cmnd: "var1=1" = stopic "var1" and svalue "=1"
|
||||
#ifdef USE_DEBUG_DRIVER
|
||||
ShowFreeMem(PSTR("ExecuteCommand"));
|
||||
#endif
|
||||
ShowSource(source);
|
||||
|
||||
token = strtok(cmnd, " ");
|
||||
if (token != nullptr) {
|
||||
start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble
|
||||
if (start) { token = start +1; }
|
||||
const char *pos = cmnd;
|
||||
while (*pos && isspace(*pos)) {
|
||||
pos++; // Skip all spaces
|
||||
}
|
||||
uint32_t size = (token != nullptr) ? strlen(token) : 0;
|
||||
char stopic[size +2]; // / + \0
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == nullptr) ? "" : token);
|
||||
|
||||
token = strtok(nullptr, "");
|
||||
size = (token != nullptr) ? strlen(token) : 0;
|
||||
char svalue[size +1];
|
||||
strlcpy(svalue, (token == nullptr) ? "" : token, sizeof(svalue)); // Fixed 5.8.0b
|
||||
CommandHandler(stopic, (uint8_t*)svalue, strlen(svalue));
|
||||
const char *start = pos;
|
||||
// Get a command. Commands can only use letters, digits and underscores
|
||||
while (*pos && (isalpha(*pos) || isdigit(*pos) || '_' == *pos || '/' == *pos)) {
|
||||
if ('/' == *pos) { // Skip possible cmnd/sonoff/ preamble
|
||||
start = pos + 1;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if ('\0' == *start || pos <= start) {
|
||||
return; // Did not find any command to execute
|
||||
}
|
||||
|
||||
uint32_t size = pos - start;
|
||||
char stopic[size + 2]; // with leader '/' and end '\0'
|
||||
stopic[0] = '/';
|
||||
memcpy(stopic+1, start, size);
|
||||
stopic[size+1] = '\0';
|
||||
|
||||
char svalue[strlen(pos) +1]; // pos point to the start of parameters
|
||||
strlcpy(svalue, pos, sizeof(svalue));
|
||||
CommandHandler(stopic, svalue, strlen(svalue));
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
// topic: /power1 data: toggle = Console command
|
||||
// topic: cmnd/sonoff/power1 data: toggle = Mqtt command using topic
|
||||
// topic: cmnd/sonoffs/power1 data: toggle = Mqtt command using a group topic
|
||||
// topic: cmnd/DVES_83BB10_fb/power1 data: toggle = Mqtt command using fallback topic
|
||||
// topicBuf: /power1 dataBuf: toggle = Console command
|
||||
// topicBuf: cmnd/sonoff/power1 dataBuf: toggle = Mqtt command using topic
|
||||
// topicBuf: cmnd/sonoffs/power1 dataBuf: toggle = Mqtt command using a group topic
|
||||
// topicBuf: cmnd/DVES_83BB10_fb/power1 dataBuf: toggle = Mqtt command using fallback topic
|
||||
|
||||
void CommandHandler(char* topic, uint8_t* data, uint32_t data_len)
|
||||
void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len)
|
||||
{
|
||||
#ifdef USE_DEBUG_DRIVER
|
||||
ShowFreeMem(PSTR("CommandHandler"));
|
||||
#endif
|
||||
|
||||
char topicBuf[TOPSZ];
|
||||
strlcpy(topicBuf, topic, sizeof(topicBuf));
|
||||
|
||||
uint32_t i = 0;
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if (!isspace(data[i])) { break; } // Skip leading spaces in data
|
||||
while (*dataBuf && isspace(*dataBuf)) {
|
||||
dataBuf++; // Skip leading spaces in data
|
||||
data_len--;
|
||||
}
|
||||
data_len -= i;
|
||||
char dataBuf[data_len+1];
|
||||
memcpy(dataBuf, data +i, sizeof(dataBuf));
|
||||
|
||||
bool grpflg = (strstr(topicBuf, Settings.mqtt_grptopic) != nullptr);
|
||||
|
||||
|
@ -137,8 +143,9 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len)
|
|||
GetFallbackTopic_P(stemp1, CMND, ""); // Full Fallback topic = cmnd/DVES_xxxxxxxx_fb/
|
||||
fallback_topic_flag = (!strncmp(topicBuf, stemp1, strlen(stemp1)));
|
||||
|
||||
char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type)
|
||||
char *type = strrchr(topicBuf, '/'); // Last part of received topic is always the command (type)
|
||||
|
||||
uint32_t i = 0;
|
||||
uint32_t index = 1;
|
||||
bool user_index = false;
|
||||
if (type != nullptr) {
|
||||
|
@ -156,7 +163,7 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len)
|
|||
type[i] = '\0';
|
||||
}
|
||||
|
||||
DEBUG_CORE_LOG(PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CMD: " D_GROUP " %d, " D_INDEX " %d, " D_COMMAND " \"%s\", " D_DATA " \"%s\""), grpflg, index, type, dataBuf);
|
||||
|
||||
if (type != nullptr) {
|
||||
Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}"));
|
||||
|
@ -361,10 +368,10 @@ void CmndStatus(void)
|
|||
}
|
||||
|
||||
if ((0 == payload) || (3 == payload)) {
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\""
|
||||
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_MQTTLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\""
|
||||
D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\""
|
||||
D_JSON_RESOLUTION "\":\"%08X\",\"" D_CMND_SETOPTION "\":[\"%08X\",\"%s\",\"%08X\"]}}"),
|
||||
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level,
|
||||
Settings.seriallog_level, Settings.weblog_level, Settings.mqttlog_level, Settings.syslog_level,
|
||||
Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period,
|
||||
Settings.flag2.data, Settings.flag.data, ToHex_P((unsigned char*)Settings.param, PARAM8_SIZE, stemp2, sizeof(stemp2)), Settings.flag3.data);
|
||||
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3"));
|
||||
|
@ -558,11 +565,24 @@ void CmndPowerOnState(void)
|
|||
void CmndPulsetime(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_PULSETIMERS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 65536)) {
|
||||
Settings.pulse_timer[XdrvMailbox.index -1] = XdrvMailbox.payload; // 0 - 65535
|
||||
SetPulseTimer(XdrvMailbox.index -1, XdrvMailbox.payload);
|
||||
uint32_t items = 1;
|
||||
if (!XdrvMailbox.usridx && !XdrvMailbox.data_len) {
|
||||
items = MAX_PULSETIMERS;
|
||||
} else {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 65536)) {
|
||||
Settings.pulse_timer[XdrvMailbox.index -1] = XdrvMailbox.payload; // 0 - 65535
|
||||
SetPulseTimer(XdrvMailbox.index -1, XdrvMailbox.payload);
|
||||
}
|
||||
}
|
||||
Response_P(S_JSON_COMMAND_INDEX_NVALUE_ACTIVE_NVALUE, XdrvMailbox.command, XdrvMailbox.index, Settings.pulse_timer[XdrvMailbox.index -1], GetPulseTimer(XdrvMailbox.index -1));
|
||||
mqtt_data[0] = '\0';
|
||||
for (uint32_t i = 0; i < items; i++) {
|
||||
uint32_t index = (1 == items) ? XdrvMailbox.index : i +1;
|
||||
ResponseAppend_P(PSTR("%c\"%s%d\":{\"" D_JSON_SET "\":%d,\"" D_JSON_REMAINING "\":%d}"),
|
||||
(i) ? ',' : '{',
|
||||
XdrvMailbox.command, index,
|
||||
Settings.pulse_timer[index -1], GetPulseTimer(index -1));
|
||||
}
|
||||
ResponseJsonEnd();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -686,11 +706,9 @@ void CmndSetoption(void)
|
|||
IrReceiveUpdateThreshold();
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_TUYA_MCU
|
||||
case P_TUYA_DIMMER_MAX:
|
||||
case P_DIMMER_MAX:
|
||||
restart_flag = 2; // Need a restart to update GUI
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -450,11 +450,18 @@ void GetFeatures(void)
|
|||
#ifdef USE_DDS2382
|
||||
feature5 |= 0x00000040; // Xnrg_09_dds2382.ino
|
||||
#endif
|
||||
// feature5 |= 0x00000080;
|
||||
|
||||
// feature5 |= 0x00000100;
|
||||
// feature5 |= 0x00000200;
|
||||
// feature5 |= 0x00000400;
|
||||
#ifdef USE_SM2135
|
||||
feature5 |= 0x00000080; // Xdrv_026_sm2135.ino
|
||||
#endif
|
||||
#ifdef USE_SHUTTER
|
||||
feature5 |= 0x00000100; // Xdrv_027_shutter.ino
|
||||
#endif
|
||||
#ifdef USE_PCF8574
|
||||
feature5 |= 0x00000200; // Xdrv_028_pcf8574.ino
|
||||
#endif
|
||||
#ifdef USE_DDSU666
|
||||
feature5 |= 0x00000400; // Xnrg_11_ddsu666.ino
|
||||
#endif
|
||||
// feature5 |= 0x00000800;
|
||||
|
||||
// feature5 |= 0x00001000;
|
||||
|
|
|
@ -85,7 +85,11 @@ void PollUdp(void)
|
|||
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer);
|
||||
|
||||
// Simple Service Discovery Protocol (SSDP)
|
||||
#ifdef USE_SCRIPT_HUE
|
||||
if (!udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
||||
#else
|
||||
if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) {
|
||||
#endif
|
||||
udp_response_mutex = true;
|
||||
|
||||
udp_remote_ip = PortUdp.remoteIP();
|
||||
|
|
|
@ -527,7 +527,7 @@ const char kButtonConfirm[] PROGMEM = D_CONFIRM_RESTART "|" D_CONFIRM_RESET_CONF
|
|||
enum CTypes { CT_HTML, CT_PLAIN, CT_XML, CT_JSON, CT_STREAM };
|
||||
const char kContentTypes[] PROGMEM = "text/html|text/plain|text/xml|application/json|application/octet-stream";
|
||||
|
||||
const char kLoggingOptions[] PROGMEM = D_SERIAL_LOG_LEVEL "|" D_WEB_LOG_LEVEL "|" D_SYS_LOG_LEVEL;
|
||||
const char kLoggingOptions[] PROGMEM = D_SERIAL_LOG_LEVEL "|" D_WEB_LOG_LEVEL "|" D_MQTT_LOG_LEVEL "|" D_SYS_LOG_LEVEL;
|
||||
const char kLoggingLevels[] PROGMEM = D_NONE "|" D_ERROR "|" D_INFO "|" D_DEBUG "|" D_MORE_DEBUG;
|
||||
|
||||
const char kEmulationOptions[] PROGMEM = D_NONE "|" D_BELKIN_WEMO "|" D_HUE_BRIDGE;
|
||||
|
@ -1128,7 +1128,7 @@ bool HandleRootStatusRefresh(void)
|
|||
}
|
||||
#ifdef USE_SHUTTER
|
||||
char webindex[5]; // WebGetArg name
|
||||
for (uint32_t j = 1; j < 5; j++) {
|
||||
for (uint32_t j = 1; j <= shutters_present; j++) {
|
||||
snprintf_P(webindex, sizeof(webindex), PSTR("u%d"), j);
|
||||
WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent
|
||||
if (strlen(tmp)) {
|
||||
|
@ -1618,9 +1618,10 @@ void HandleLoggingConfiguration(void)
|
|||
WSContentSend_P(HTTP_FORM_LOG1);
|
||||
char stemp1[45];
|
||||
char stemp2[32];
|
||||
uint8_t dlevel[3] = { LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_NONE };
|
||||
for (uint32_t idx = 0; idx < 3; idx++) {
|
||||
uint32_t llevel = (0==idx)?Settings.seriallog_level:(1==idx)?Settings.weblog_level:Settings.syslog_level;
|
||||
uint8_t dlevel[4] = { LOG_LEVEL_INFO, LOG_LEVEL_INFO, LOG_LEVEL_NONE, LOG_LEVEL_NONE };
|
||||
for (uint32_t idx = 0; idx < 4; idx++) {
|
||||
if ((2==idx) && !Settings.flag.mqtt_enabled) { continue; }
|
||||
uint32_t llevel = (0==idx)?Settings.seriallog_level:(1==idx)?Settings.weblog_level:(2==idx)?Settings.mqttlog_level:Settings.syslog_level;
|
||||
WSContentSend_P(PSTR("<p><b>%s</b> (%s)<br><select id='l%d'>"),
|
||||
GetTextIndexed(stemp1, sizeof(stemp1), idx, kLoggingOptions),
|
||||
GetTextIndexed(stemp2, sizeof(stemp2), dlevel[idx], kLoggingLevels),
|
||||
|
@ -1647,6 +1648,8 @@ void LoggingSaveSettings(void)
|
|||
WebGetArg("l1", tmp, sizeof(tmp));
|
||||
Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp);
|
||||
WebGetArg("l2", tmp, sizeof(tmp));
|
||||
Settings.mqttlog_level = (!strlen(tmp)) ? MQTT_LOG_LEVEL : atoi(tmp);
|
||||
WebGetArg("l3", tmp, sizeof(tmp));
|
||||
SetSyslog((!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp));
|
||||
WebGetArg("lh", tmp, sizeof(tmp));
|
||||
strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host));
|
||||
|
@ -1657,8 +1660,8 @@ void LoggingSaveSettings(void)
|
|||
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) {
|
||||
Settings.tele_period = 10; // Do not allow periods < 10 seconds
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"),
|
||||
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period);
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_MQTTLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"),
|
||||
Settings.seriallog_level, Settings.weblog_level, Settings.mqttlog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*/
|
||||
|
|
|
@ -251,7 +251,7 @@ bool MqttPublishLib(const char* topic, bool retained)
|
|||
return result;
|
||||
}
|
||||
|
||||
void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
|
||||
void MqttDataHandler(char* mqtt_topic, uint8_t* mqtt_data, unsigned int data_len)
|
||||
{
|
||||
#ifdef USE_DEBUG_DRIVER
|
||||
ShowFreeMem(PSTR("MqttDataHandler"));
|
||||
|
@ -262,8 +262,8 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
|
|||
|
||||
// Do not execute multiple times if Prefix1 equals Prefix2
|
||||
if (!strcmp(Settings.mqtt_prefix[0], Settings.mqtt_prefix[1])) {
|
||||
char *str = strstr(topic, Settings.mqtt_prefix[0]);
|
||||
if ((str == topic) && mqtt_cmnd_publish) {
|
||||
char *str = strstr(mqtt_topic, Settings.mqtt_prefix[0]);
|
||||
if ((str == mqtt_topic) && mqtt_cmnd_publish) {
|
||||
if (mqtt_cmnd_publish > 3) {
|
||||
mqtt_cmnd_publish -= 3;
|
||||
} else {
|
||||
|
@ -273,13 +273,22 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len)
|
|||
}
|
||||
}
|
||||
|
||||
data[data_len] = 0;
|
||||
// Save MQTT data ASAP as it's data is discarded by PubSubClient with next publish as used in MQTTlog
|
||||
char topic[TOPSZ];
|
||||
strlcpy(topic, mqtt_topic, sizeof(topic));
|
||||
mqtt_data[data_len] = 0;
|
||||
char data[data_len +1];
|
||||
memcpy(data, mqtt_data, sizeof(data));
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " %s, " D_DATA_SIZE " %d, " D_DATA " %s"), topic, data_len, data);
|
||||
// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(dataBuf); }
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_MQTT D_RECEIVED_TOPIC " \"%s\", " D_DATA_SIZE " %d, " D_DATA " \"%s\""), topic, data_len, data);
|
||||
// if (LOG_LEVEL_DEBUG_MORE <= seriallog_level) { Serial.println(data); }
|
||||
|
||||
// MQTT pre-processing
|
||||
if (XdrvMqttData(topic, strlen(topic), (char*)data, data_len)) { return; }
|
||||
XdrvMailbox.index = strlen(topic);
|
||||
XdrvMailbox.data_len = data_len;
|
||||
XdrvMailbox.topic = topic;
|
||||
XdrvMailbox.data = (char*)data;
|
||||
if (XdrvCall(FUNC_MQTT_DATA)) { return; }
|
||||
|
||||
ShowSource(SRC_MQTT);
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ void EnergyUpdateTotal(float value, bool kwh)
|
|||
Energy.kWhtoday = (unsigned long)((value - Energy.start_energy) * multiplier);
|
||||
}
|
||||
|
||||
if (Energy.total < (value - 0.01)){ // We subtract a little offset to avoid continuous updates
|
||||
if ((Energy.total < (value - 0.01)) && Settings.flag3.hardware_energy_total) { // We subtract a little offset to avoid continuous updates
|
||||
RtcSettings.energy_kWhtotal = (unsigned long)((value * multiplier) - Energy.kWhtoday_offset - Energy.kWhtoday);
|
||||
Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal;
|
||||
Energy.total = (float)(RtcSettings.energy_kWhtotal + Energy.kWhtoday_offset + Energy.kWhtoday) / 100000;
|
||||
|
@ -331,11 +331,11 @@ void EnergyMarginCheck(void)
|
|||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(false, Settings.energy_min_current, energy_current_u, flag, Energy.min_current_flag)) {
|
||||
ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (EnergyMargin(true, Settings.energy_max_current, energy_current_u, flag, Energy.max_current_flag)) {
|
||||
ResponseAppend_P(PSTR("%s%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag));
|
||||
jsonflg = true;
|
||||
}
|
||||
if (jsonflg) {
|
||||
|
|
|
@ -257,6 +257,7 @@ struct LIGHT {
|
|||
uint8_t wakeup_active = 0;
|
||||
uint8_t wakeup_dimmer = 0;
|
||||
uint8_t fixed_color_index = 1;
|
||||
uint8_t pwm_offset = 0; // Offset in color buffer
|
||||
|
||||
bool update = true;
|
||||
bool pwm_multi_channels = false; // SetOption68, treat each PWM channel as an independant dimmer
|
||||
|
@ -1184,187 +1185,60 @@ void AriluxRfDisable(void)
|
|||
}
|
||||
#endif // USE_ARILUX_RF
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Sonoff B1 and AiLight inspired by OpenLight https://github.com/icamgo/noduino-sdk
|
||||
\*********************************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
void os_delay_us(unsigned int);
|
||||
}
|
||||
|
||||
uint8_t light_pdi_pin;
|
||||
uint8_t light_pdcki_pin;
|
||||
|
||||
void LightDiPulse(uint8_t times)
|
||||
{
|
||||
for (uint32_t i = 0; i < times; i++) {
|
||||
digitalWrite(light_pdi_pin, HIGH);
|
||||
digitalWrite(light_pdi_pin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void LightDckiPulse(uint8_t times)
|
||||
{
|
||||
for (uint32_t i = 0; i < times; i++) {
|
||||
digitalWrite(light_pdcki_pin, HIGH);
|
||||
digitalWrite(light_pdcki_pin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void LightMy92x1Write(uint8_t data)
|
||||
{
|
||||
for (uint32_t i = 0; i < 4; i++) { // Send 8bit Data
|
||||
digitalWrite(light_pdcki_pin, LOW);
|
||||
digitalWrite(light_pdi_pin, (data & 0x80));
|
||||
digitalWrite(light_pdcki_pin, HIGH);
|
||||
data = data << 1;
|
||||
digitalWrite(light_pdi_pin, (data & 0x80));
|
||||
digitalWrite(light_pdcki_pin, LOW);
|
||||
digitalWrite(light_pdi_pin, LOW);
|
||||
data = data << 1;
|
||||
}
|
||||
}
|
||||
|
||||
void LightMy92x1Init(void)
|
||||
{
|
||||
uint8_t chips = 1; // 1 (AiLight)
|
||||
if (LT_RGBWC == light_type) {
|
||||
chips = 2; // 2 (Sonoff B1)
|
||||
}
|
||||
|
||||
LightDckiPulse(chips * 32); // Clear all duty register
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
// Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12
|
||||
// pulse's rising edge convert to command mode.
|
||||
LightDiPulse(12);
|
||||
os_delay_us(12); // Delay >12us, begin send CMD data
|
||||
for (uint32_t n = 0; n < chips; n++) { // Send CMD data
|
||||
LightMy92x1Write(0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM
|
||||
}
|
||||
os_delay_us(12); // TStart > 12us. Delay 12 us.
|
||||
// Send 16 DI pulse, at 14 pulse's falling edge store CMD data, and
|
||||
// at 16 pulse's falling edge convert to duty mode.
|
||||
LightDiPulse(16);
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
}
|
||||
|
||||
void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c)
|
||||
{
|
||||
uint8_t channels[2] = { 4, 6 };
|
||||
|
||||
uint8_t didx = 0; // 0 (AiLight)
|
||||
if (LT_RGBWC == light_type) {
|
||||
didx = 1; // 1 (Sonoff B1)
|
||||
}
|
||||
|
||||
uint8_t duty[2][6] = {{ duty_r, duty_g, duty_b, duty_w, 0, 0 }, // Definition for RGBW channels
|
||||
{ duty_w, duty_c, 0, duty_g, duty_r, duty_b }}; // Definition for RGBWC channels
|
||||
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
for (uint32_t channel = 0; channel < channels[didx]; channel++) {
|
||||
LightMy92x1Write(duty[didx][channel]); // Send 8bit Data
|
||||
}
|
||||
os_delay_us(12); // TStart > 12us. Ready for send DI pulse.
|
||||
LightDiPulse(8); // Send 8 DI pulse. After 8 pulse falling edge, store old data.
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
}
|
||||
|
||||
#ifdef USE_SM16716
|
||||
/*********************************************************************************************\
|
||||
* SM16716 - Controlling RGB over a synchronous serial line
|
||||
* Copyright (C) 2019 Gabor Simon
|
||||
*
|
||||
* Source: https://community.home-assistant.io/t/cheap-uk-wifi-bulbs-with-tasmota-teardown-help-tywe3s/40508/27
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define D_LOG_SM16716 "SM16716: "
|
||||
|
||||
uint8_t sm16716_pin_clk = 100;
|
||||
uint8_t sm16716_pin_dat = 100;
|
||||
uint8_t sm16716_pin_sel = 100;
|
||||
uint8_t sm16716_enabled = 0;
|
||||
|
||||
void SM16716_SendBit(uint8_t v)
|
||||
{
|
||||
/* NOTE:
|
||||
* According to the spec sheet, max freq is 30 MHz, that is 16.6 ns per high/low half of the
|
||||
* clk square wave. That is less than the overhead of 'digitalWrite' at this clock rate,
|
||||
* so no additional delays are needed yet. */
|
||||
|
||||
digitalWrite(sm16716_pin_dat, (v != 0) ? HIGH : LOW);
|
||||
//delayMicroseconds(1);
|
||||
digitalWrite(sm16716_pin_clk, HIGH);
|
||||
//delayMicroseconds(1);
|
||||
digitalWrite(sm16716_pin_clk, LOW);
|
||||
}
|
||||
|
||||
void SM16716_SendByte(uint8_t v)
|
||||
{
|
||||
uint8_t mask;
|
||||
|
||||
for (mask = 0x80; mask; mask >>= 1) {
|
||||
SM16716_SendBit(v & mask);
|
||||
}
|
||||
}
|
||||
|
||||
void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b)
|
||||
{
|
||||
if (sm16716_pin_sel < 99) {
|
||||
uint8_t sm16716_should_enable = (duty_r | duty_g | duty_b);
|
||||
if (!sm16716_enabled && sm16716_should_enable) {
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color on"));
|
||||
sm16716_enabled = 1;
|
||||
digitalWrite(sm16716_pin_sel, HIGH);
|
||||
// in testing I found it takes a minimum of ~380us to wake up the chip
|
||||
// tested on a Merkury RGBW with an SM726EB
|
||||
delayMicroseconds(1000);
|
||||
SM16716_Init();
|
||||
}
|
||||
else if (sm16716_enabled && !sm16716_should_enable) {
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color off"));
|
||||
sm16716_enabled = 0;
|
||||
digitalWrite(sm16716_pin_sel, LOW);
|
||||
}
|
||||
}
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "Update; rgb=%02x%02x%02x"), duty_r, duty_g, duty_b);
|
||||
|
||||
// send start bit
|
||||
SM16716_SendBit(1);
|
||||
SM16716_SendByte(duty_r);
|
||||
SM16716_SendByte(duty_g);
|
||||
SM16716_SendByte(duty_b);
|
||||
|
||||
// send a 'do it' pulse
|
||||
// (if multiple chips are chained, each one processes the 1st '1rgb' 25-bit block and
|
||||
// passes on the rest, right until the one starting with 0)
|
||||
//SM16716_Init();
|
||||
SM16716_SendBit(0);
|
||||
SM16716_SendByte(0);
|
||||
SM16716_SendByte(0);
|
||||
SM16716_SendByte(0);
|
||||
}
|
||||
|
||||
bool SM16716_ModuleSelected(void)
|
||||
{
|
||||
sm16716_pin_clk = pin[GPIO_SM16716_CLK];
|
||||
sm16716_pin_dat = pin[GPIO_SM16716_DAT];
|
||||
sm16716_pin_sel = pin[GPIO_SM16716_SEL];
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "ModuleSelected; clk_pin=%d, dat_pin=%d)"), sm16716_pin_clk, sm16716_pin_dat);
|
||||
return (sm16716_pin_clk < 99) && (sm16716_pin_dat < 99);
|
||||
}
|
||||
|
||||
void SM16716_Init(void)
|
||||
{
|
||||
for (uint32_t t_init = 0; t_init < 50; ++t_init) {
|
||||
SM16716_SendBit(0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifdef USE_SM16716
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void LightPwmOffset(uint32_t offset)
|
||||
{
|
||||
Light.pwm_offset = offset;
|
||||
}
|
||||
|
||||
bool LightModuleInit(void)
|
||||
{
|
||||
light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
|
||||
|
||||
if (Settings.flag.pwm_control) {
|
||||
for (uint32_t i = 0; i < MAX_PWMS; i++) {
|
||||
if (pin[GPIO_PWM1 +i] < 99) { light_type++; } // Use Dimmer/Color control for all PWM as SetOption15 = 1
|
||||
}
|
||||
}
|
||||
|
||||
light_flg = 0;
|
||||
if (XlgtCall(FUNC_MODULE_INIT)) {
|
||||
// serviced
|
||||
}
|
||||
else if (SONOFF_BN == my_module_type) { // PWM Single color led (White)
|
||||
light_type = LT_PWM1;
|
||||
}
|
||||
else if (SONOFF_LED == my_module_type) { // PWM Dual color led (White warm and cold)
|
||||
if (!my_module.io[4]) { // Fix Sonoff Led instabilities
|
||||
pinMode(4, OUTPUT); // Stop floating outputs
|
||||
digitalWrite(4, LOW);
|
||||
}
|
||||
if (!my_module.io[5]) {
|
||||
pinMode(5, OUTPUT); // Stop floating outputs
|
||||
digitalWrite(5, LOW);
|
||||
}
|
||||
if (!my_module.io[14]) {
|
||||
pinMode(14, OUTPUT); // Stop floating outputs
|
||||
digitalWrite(14, LOW);
|
||||
}
|
||||
light_type = LT_PWM2;
|
||||
}
|
||||
#ifdef USE_WS2812
|
||||
if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led
|
||||
light_type = LT_WS2812;
|
||||
}
|
||||
#endif // USE_WS2812
|
||||
// post-process for lights
|
||||
if (Settings.flag3.pwm_multi_channels) {
|
||||
uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7);
|
||||
if (0 == pwm_channels) { pwm_channels = 1; }
|
||||
devices_present += pwm_channels - 1; // add the pwm channels controls at the end
|
||||
}
|
||||
|
||||
return (light_type > 0);
|
||||
}
|
||||
|
||||
void LightInit(void)
|
||||
{
|
||||
uint8_t max_scheme = LS_MAX -1;
|
||||
|
@ -1402,20 +1276,6 @@ void LightInit(void)
|
|||
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
|
||||
}
|
||||
}
|
||||
if (SONOFF_LED == my_module_type) { // Fix Sonoff Led instabilities
|
||||
if (!my_module.io[4]) {
|
||||
pinMode(4, OUTPUT); // Stop floating outputs
|
||||
digitalWrite(4, LOW);
|
||||
}
|
||||
if (!my_module.io[5]) {
|
||||
pinMode(5, OUTPUT); // Stop floating outputs
|
||||
digitalWrite(5, LOW);
|
||||
}
|
||||
if (!my_module.io[14]) {
|
||||
pinMode(14, OUTPUT); // Stop floating outputs
|
||||
digitalWrite(14, LOW);
|
||||
}
|
||||
}
|
||||
if (pin[GPIO_ARIRFRCV] < 99) {
|
||||
if (pin[GPIO_ARIRFSEL] < 99) {
|
||||
pinMode(pin[GPIO_ARIRFSEL], OUTPUT);
|
||||
|
@ -1429,32 +1289,7 @@ void LightInit(void)
|
|||
max_scheme = LS_MAX + WS2812_SCHEMES;
|
||||
}
|
||||
#endif // USE_WS2812 ************************************************************************
|
||||
#ifdef USE_SM16716
|
||||
else if (LT_SM16716 == light_type - Light.subtype) {
|
||||
// init PWM
|
||||
for (uint32_t i = 0; i < Light.subtype; i++) {
|
||||
Settings.pwm_value[i] = 0; // Disable direct PWM control
|
||||
if (pin[GPIO_PWM1 +i] < 99) {
|
||||
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
|
||||
}
|
||||
}
|
||||
// init sm16716
|
||||
pinMode(sm16716_pin_clk, OUTPUT);
|
||||
digitalWrite(sm16716_pin_clk, LOW);
|
||||
|
||||
pinMode(sm16716_pin_dat, OUTPUT);
|
||||
digitalWrite(sm16716_pin_dat, LOW);
|
||||
|
||||
if (sm16716_pin_sel < 99) {
|
||||
pinMode(sm16716_pin_sel, OUTPUT);
|
||||
digitalWrite(sm16716_pin_sel, LOW);
|
||||
// no need to call SM16716_Init here, it will be called after sel goes HIGH
|
||||
} else {
|
||||
// no sel pin means you have an 'always on' chip, so init right away
|
||||
SM16716_Init();
|
||||
}
|
||||
}
|
||||
#endif // ifdef USE_SM16716
|
||||
/*
|
||||
else {
|
||||
light_pdi_pin = pin[GPIO_DI];
|
||||
light_pdcki_pin = pin[GPIO_DCKI];
|
||||
|
@ -1466,7 +1301,7 @@ void LightInit(void)
|
|||
|
||||
LightMy92x1Init();
|
||||
}
|
||||
|
||||
*/
|
||||
if (Light.subtype < LST_RGB) {
|
||||
max_scheme = LS_POWER;
|
||||
}
|
||||
|
@ -2001,10 +1836,10 @@ void LightAnimate(void)
|
|||
|
||||
// now apply the actual PWM values, adjusted and remapped 10-bits range
|
||||
if (light_type < LT_PWM6) { // only for direct PWM lights, not for Tuya, Armtronix...
|
||||
for (uint32_t i = 0; i < Light.subtype; i++) {
|
||||
for (uint32_t i = 0; i < (Light.subtype - Light.pwm_offset); i++) {
|
||||
if (pin[GPIO_PWM1 +i] < 99) {
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d, Pwm%d %d"), i, cur_col_10bits[i], i+1, cur_col[i]);
|
||||
analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col_10bits[i] : cur_col_10bits[i]);
|
||||
analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col_10bits[(i + Light.pwm_offset)] : cur_col_10bits[(i + Light.pwm_offset)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2014,7 +1849,14 @@ void LightAnimate(void)
|
|||
|
||||
XdrvMailbox.data = (char*)cur_col;
|
||||
XdrvMailbox.data_len = sizeof(cur_col);
|
||||
if (XdrvCall(FUNC_SET_CHANNELS)) {
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "R%d G%d B%d, C%d W%d"),
|
||||
cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
|
||||
|
||||
if (XlgtCall(FUNC_SET_CHANNELS)) {
|
||||
// Serviced
|
||||
}
|
||||
else if (XdrvCall(FUNC_SET_CHANNELS)) {
|
||||
// Serviced
|
||||
}
|
||||
#ifdef USE_WS2812 // ************************************************************************
|
||||
|
@ -2022,23 +1864,6 @@ void LightAnimate(void)
|
|||
Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]);
|
||||
}
|
||||
#endif // USE_ES2812 ************************************************************************
|
||||
#ifdef USE_SM16716
|
||||
else if (LT_SM16716 == light_type - Light.subtype) {
|
||||
// handle any PWM pins, skipping the first 3 values for sm16716
|
||||
for (uint32_t i = 3; i < Light.subtype; i++) {
|
||||
if (pin[GPIO_PWM1 +i-3] < 99) {
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d, Pwm%d %d"), i, cur_col[i], i+1, curcol);
|
||||
analogWrite(pin[GPIO_PWM1 +i-3], bitRead(pwm_inverted, i-3) ? Settings.pwm_range - cur_col_10bits[i] : cur_col_10bits[i]);
|
||||
}
|
||||
}
|
||||
// handle sm16716 update
|
||||
SM16716_Update(cur_col[0], cur_col[1], cur_col[2]);
|
||||
}
|
||||
#endif // ifdef USE_SM16716
|
||||
else if (light_type > LT_WS2812) {
|
||||
//AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "Cur_Col %d,%d,%d,%d,%d"), cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
|
||||
LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
|
||||
}
|
||||
XdrvMailbox.data = tmp_data;
|
||||
XdrvMailbox.data_len = tmp_data_len;
|
||||
}
|
||||
|
@ -2584,11 +2409,11 @@ bool Xdrv04(uint8_t function)
|
|||
{
|
||||
bool result = false;
|
||||
|
||||
if (light_type) {
|
||||
if (FUNC_MODULE_INIT == function) {
|
||||
return LightModuleInit();
|
||||
}
|
||||
else if (light_type) {
|
||||
switch (function) {
|
||||
case FUNC_PRE_INIT:
|
||||
LightInit();
|
||||
break;
|
||||
case FUNC_EVERY_50_MSECOND:
|
||||
LightAnimate();
|
||||
#ifdef USE_ARILUX_RF
|
||||
|
@ -2606,6 +2431,9 @@ bool Xdrv04(uint8_t function)
|
|||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kLightCommands, LightCommand);
|
||||
break;
|
||||
case FUNC_PRE_INIT:
|
||||
LightInit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -45,7 +45,6 @@ const char kDomoticzSensors[] PROGMEM =
|
|||
D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT "|" D_DOMOTICZ_AIRQUALITY "|" D_DOMOTICZ_P1_SMART_METER "|" D_DOMOTICZ_SHUTTER ;
|
||||
|
||||
char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC;
|
||||
char domoticz_out_topic[] = DOMOTICZ_OUT_TOPIC;
|
||||
|
||||
int domoticz_update_timer = 0;
|
||||
uint32_t domoticz_fan_debounce = 0; // iFan02 state debounce timer
|
||||
|
@ -166,7 +165,7 @@ void DomoticzMqttSubscribe(void)
|
|||
}
|
||||
if (domoticz_subscribe) {
|
||||
char stopic[TOPSZ];
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR("%s/#"), domoticz_out_topic); // domoticz topic
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR(DOMOTICZ_OUT_TOPIC "/#")); // domoticz topic
|
||||
MqttSubscribe(stopic);
|
||||
}
|
||||
}
|
||||
|
@ -199,102 +198,104 @@ void DomoticzMqttSubscribe(void)
|
|||
|
||||
bool DomoticzMqttData(void)
|
||||
{
|
||||
char stemp1[10];
|
||||
unsigned long idx = 0;
|
||||
int16_t nvalue = -1;
|
||||
bool found = false;
|
||||
|
||||
domoticz_update_flag = true;
|
||||
if (!strncmp(XdrvMailbox.topic, domoticz_out_topic, strlen(domoticz_out_topic))) {
|
||||
if (XdrvMailbox.data_len < 20) {
|
||||
return true; // No valid data
|
||||
}
|
||||
StaticJsonBuffer<400> jsonBuf;
|
||||
JsonObject& domoticz = jsonBuf.parseObject(XdrvMailbox.data);
|
||||
if (!domoticz.success()) {
|
||||
return true; // To much or invalid data
|
||||
}
|
||||
|
||||
if (strncasecmp_P(XdrvMailbox.topic, PSTR(DOMOTICZ_OUT_TOPIC), strlen(DOMOTICZ_OUT_TOPIC)) != 0) {
|
||||
return false; // Process unchanged data
|
||||
}
|
||||
|
||||
// topic is domoticz/out so try to analyse
|
||||
if (XdrvMailbox.data_len < 20) {
|
||||
return true; // No valid data
|
||||
}
|
||||
StaticJsonBuffer<400> jsonBuf;
|
||||
JsonObject& domoticz = jsonBuf.parseObject(XdrvMailbox.data);
|
||||
if (!domoticz.success()) {
|
||||
return true; // To much or invalid data
|
||||
}
|
||||
// if (strcmp_P(domoticz["dtype"],PSTR("Light/Switch"))) {
|
||||
// return true;
|
||||
// }
|
||||
idx = domoticz["idx"];
|
||||
if (domoticz.containsKey("nvalue")) {
|
||||
nvalue = domoticz["nvalue"];
|
||||
}
|
||||
uint32_t idx = domoticz["idx"];
|
||||
int16_t nvalue = -1;
|
||||
if (domoticz.containsKey("nvalue")) {
|
||||
nvalue = domoticz["nvalue"];
|
||||
}
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue);
|
||||
|
||||
if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) {
|
||||
uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present;
|
||||
for (uint32_t i = 0; i < maxdev; i++) {
|
||||
if (idx == Settings.domoticz_relay_idx[i]) {
|
||||
bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0;
|
||||
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1);
|
||||
bool found = false;
|
||||
if ((idx > 0) && (nvalue >= 0) && (nvalue <= 15)) {
|
||||
uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present;
|
||||
for (uint32_t i = 0; i < maxdev; i++) {
|
||||
if (idx == Settings.domoticz_relay_idx[i]) {
|
||||
bool iscolordimmer = strcmp_P(domoticz["dtype"],PSTR("Color Switch")) == 0;
|
||||
char stemp1[10];
|
||||
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1);
|
||||
#ifdef USE_SONOFF_IFAN
|
||||
if (IsModuleIfan() && (1 == i)) { // Idx 2 is fanspeed
|
||||
uint8_t svalue = 0;
|
||||
if (domoticz.containsKey("svalue1")) {
|
||||
svalue = domoticz["svalue1"];
|
||||
} else {
|
||||
return true; // Invalid data
|
||||
}
|
||||
svalue = (nvalue == 2) ? svalue / 10 : 0;
|
||||
if (GetFanspeed() == svalue) {
|
||||
return true; // Stop loop as already set
|
||||
}
|
||||
if (TimePassedSince(domoticz_fan_debounce) < 1000) {
|
||||
return true; // Stop loop if device in limbo
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue);
|
||||
found = true;
|
||||
} else
|
||||
if (IsModuleIfan() && (1 == i)) { // Idx 2 is fanspeed
|
||||
uint8_t svalue = 0;
|
||||
if (domoticz.containsKey("svalue1")) {
|
||||
svalue = domoticz["svalue1"];
|
||||
} else {
|
||||
return true; // Invalid data
|
||||
}
|
||||
svalue = (nvalue == 2) ? svalue / 10 : 0;
|
||||
if (GetFanspeed() == svalue) {
|
||||
return true; // Stop loop as already set
|
||||
}
|
||||
if (TimePassedSince(domoticz_fan_debounce) < 1000) {
|
||||
return true; // Stop loop if device in limbo
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_FANSPEED));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), svalue);
|
||||
found = true;
|
||||
} else
|
||||
#endif // USE_SONOFF_IFAN
|
||||
if (iscolordimmer && 10 == nvalue) { // Color_SetColor
|
||||
JsonObject& color = domoticz["Color"];
|
||||
uint16_t level = nvalue = domoticz["svalue1"];
|
||||
uint16_t r = color["r"]; r = r * level / 100;
|
||||
uint16_t g = color["g"]; g = g * level / 100;
|
||||
uint16_t b = color["b"]; b = b * level / 100;
|
||||
uint16_t cw = color["cw"]; cw = cw * level / 100;
|
||||
uint16_t ww = color["ww"]; ww = ww * level / 100;
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_COLOR));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%02x%02x%02x%02x%02x"), r, g, b, cw, ww);
|
||||
found = true;
|
||||
}
|
||||
else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel
|
||||
(iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel
|
||||
if (domoticz.containsKey("svalue1")) {
|
||||
nvalue = domoticz["svalue1"];
|
||||
} else {
|
||||
return true; // Invalid data
|
||||
}
|
||||
if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &1)) {
|
||||
return true; // State already set
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_DIMMER));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
|
||||
found = true;
|
||||
}
|
||||
else if (1 == nvalue || 0 == nvalue) {
|
||||
if (((power >> i) &1) == (power_t)nvalue) {
|
||||
return true; // Stop loop
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : "");
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
if (iscolordimmer && 10 == nvalue) { // Color_SetColor
|
||||
JsonObject& color = domoticz["Color"];
|
||||
uint16_t level = nvalue = domoticz["svalue1"];
|
||||
uint16_t r = color["r"]; r = r * level / 100;
|
||||
uint16_t g = color["g"]; g = g * level / 100;
|
||||
uint16_t b = color["b"]; b = b * level / 100;
|
||||
uint16_t cw = color["cw"]; cw = cw * level / 100;
|
||||
uint16_t ww = color["ww"]; ww = ww * level / 100;
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_COLOR));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%02x%02x%02x%02x%02x"), r, g, b, cw, ww);
|
||||
found = true;
|
||||
}
|
||||
else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel
|
||||
(iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel
|
||||
if (domoticz.containsKey("svalue1")) {
|
||||
nvalue = domoticz["svalue1"];
|
||||
} else {
|
||||
return true; // Invalid data
|
||||
}
|
||||
if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &1)) {
|
||||
return true; // State already set
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_DIMMER));
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
|
||||
found = true;
|
||||
}
|
||||
else if (1 == nvalue || 0 == nvalue) {
|
||||
if (((power >> i) &1) == (power_t)nvalue) {
|
||||
return true; // Stop loop
|
||||
}
|
||||
snprintf_P(XdrvMailbox.topic, XdrvMailbox.index, PSTR("/" D_CMND_POWER "%s"), (devices_present > 1) ? stemp1 : "");
|
||||
snprintf_P(XdrvMailbox.data, XdrvMailbox.data_len, PSTR("%d"), nvalue);
|
||||
found = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) { return true; } // No command received
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data);
|
||||
|
||||
domoticz_update_flag = false;
|
||||
}
|
||||
return false; // Process unchanged or new data
|
||||
if (!found) { return true; } // No command received
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_DOMOTICZ D_RECEIVED_TOPIC " %s, " D_DATA " %s"), XdrvMailbox.topic, XdrvMailbox.data);
|
||||
|
||||
domoticz_update_flag = false;
|
||||
return false; // Process new data
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
|
|
@ -698,10 +698,10 @@ void RulesTeleperiod(void)
|
|||
*/
|
||||
bool RulesMqttData(void)
|
||||
{
|
||||
bool serviced = false;
|
||||
if (XdrvMailbox.data_len < 1 || XdrvMailbox.data_len > 256) {
|
||||
return false;
|
||||
}
|
||||
bool serviced = false;
|
||||
String sTopic = XdrvMailbox.topic;
|
||||
String sData = XdrvMailbox.data;
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("RUL: MQTT Topic %s, Event %s"), XdrvMailbox.topic, XdrvMailbox.data);
|
||||
|
|
|
@ -3366,30 +3366,8 @@ void ScriptSaveSettings(void) {
|
|||
#endif
|
||||
|
||||
|
||||
#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT)
|
||||
#if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT)
|
||||
|
||||
/*
|
||||
"state": {
|
||||
"temperature": 2674,
|
||||
"lastupdated": "2017-08-04T12:13:04"
|
||||
},
|
||||
"config": {
|
||||
"on": true,
|
||||
"battery": 100,
|
||||
"reachable": true,
|
||||
"alert": "none",
|
||||
"ledindication": false,
|
||||
"usertest": false,
|
||||
"pending": []
|
||||
},
|
||||
"name": "Hue temperature sensor 1",
|
||||
"type": "ZLLTemperature",
|
||||
"modelid": "SML001",
|
||||
"manufacturername": "Philips",
|
||||
"swversion": "6.1.0.18912",
|
||||
"uniqueid": "xxx"
|
||||
}
|
||||
*/
|
||||
|
||||
#define HUE_DEV_MVNUM 5
|
||||
#define HUE_DEV_NSIZE 16
|
||||
|
@ -3414,8 +3392,76 @@ const char SCRIPT_HUE_LIGHTS_STATUS_JSON1[] PROGMEM =
|
|||
"\"uniqueid\":\"{j2\","
|
||||
"\"swversion\":\"5.50.1.19085\"}";
|
||||
|
||||
/*
|
||||
const char SCRIPT_HUE_LIGHTS_STATUS_JSON2[] PROGMEM =
|
||||
"{\"state\":"
|
||||
"{\"temperature\": 2674,"
|
||||
"\"lastupdated\": \"2019-08-04T12:13:04\"},"
|
||||
"\"config\": {"
|
||||
"\"on\": true,"
|
||||
"\"battery\": 100,"
|
||||
"\"reachable\": true,"
|
||||
"\"alert\": \"none\","
|
||||
"\"ledindication\": false,"
|
||||
"\"usertest\": false,"
|
||||
"\"pending\": []"
|
||||
"},"
|
||||
"\"name\": \"{j1\","
|
||||
"\"type\": \"ZLLTemperature\","
|
||||
"\"modelid\": \"SML001\","
|
||||
"\"manufacturername\": \"Philips\","
|
||||
"\"swversion\": \"6.1.0.18912\","
|
||||
"\"uniqueid\": \"{j2\"}";
|
||||
*/
|
||||
|
||||
|
||||
const char SCRIPT_HUE_LIGHTS_STATUS_JSON2[] PROGMEM =
|
||||
"{\"state\":{"
|
||||
"\"presence\":{state},"
|
||||
"\"lastupdated\":\"2017-10-01T12:37:30\""
|
||||
"},"
|
||||
"\"swupdate\":{"
|
||||
"\"state\":\"noupdates\","
|
||||
"\"lastinstall\": null"
|
||||
"},"
|
||||
"\"config\":{"
|
||||
"\"on\":true,"
|
||||
"\"battery\":100,"
|
||||
"\"reachable\":true,"
|
||||
"\"alert\":\"none\","
|
||||
"\"ledindication\":false,"
|
||||
"\"usertest\":false,"
|
||||
"\"sensitivity\":2,"
|
||||
"\"sensitivitymax\":2,"
|
||||
"\"pending\":[]"
|
||||
"},"
|
||||
"\"name\":\"{j1\","
|
||||
"\"type\":\"ZLLPresence\","
|
||||
"\"modelid\":\"SML001\","
|
||||
"\"manufacturername\":\"Philips\","
|
||||
"\"swversion\":\"6.1.0.18912\","
|
||||
"\"uniqueid\":\"{j2\""
|
||||
"}";
|
||||
|
||||
/*
|
||||
temperature ZLLTemperature
|
||||
lightlevel ZLLLightLevel
|
||||
presence ZLLPresence
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void Script_HueStatus(String *response, uint16_t hue_devs) {
|
||||
|
||||
if (hue_script[hue_devs].type=='P') {
|
||||
*response+=FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON2);
|
||||
response->replace("{j1",hue_script[hue_devs].name);
|
||||
response->replace("{j2", GetHueDeviceId(hue_devs));
|
||||
uint8_t pwr=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1];
|
||||
response->replace("{state}", (pwr ? "true" : "false"));
|
||||
return;
|
||||
}
|
||||
|
||||
*response+=FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON1);
|
||||
uint8_t pwr=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1];
|
||||
response->replace("{state}", (pwr ? "true" : "false"));
|
||||
|
@ -3454,16 +3500,44 @@ void Script_HueStatus(String *response, uint16_t hue_devs) {
|
|||
light_status += ",";
|
||||
}
|
||||
|
||||
response->replace("{light_status}", light_status);
|
||||
response->replace("{j1",hue_script[hue_devs].name);
|
||||
response->replace("{j2", GetHueDeviceId(hue_devs<<8));
|
||||
|
||||
if (hue_script[hue_devs].type=='E') {
|
||||
response->replace("{type}","Extended color light");
|
||||
} else {
|
||||
response->replace("{type}","color light");
|
||||
float temp;
|
||||
switch (hue_script[hue_devs].type) {
|
||||
case 'E':
|
||||
response->replace("{type}","Extended color light");
|
||||
break;
|
||||
case 'S':
|
||||
response->replace("{type}","color light");
|
||||
break;
|
||||
case 'T':
|
||||
response->replace("{type}","ZLLTemperature");
|
||||
temp=glob_script_mem.fvars[hue_script[hue_devs].index[2]-1];
|
||||
light_status += "\"temperature\":";
|
||||
light_status += String(temp*100);
|
||||
light_status += ",";
|
||||
break;
|
||||
case 'L':
|
||||
response->replace("{type}","ZLLLightLevel");
|
||||
temp=glob_script_mem.fvars[hue_script[hue_devs].index[2]-1];
|
||||
light_status += "\"lightlevel\":";
|
||||
light_status += String(temp);
|
||||
light_status += ",";
|
||||
break;
|
||||
case 'P':
|
||||
response->replace("{type}","ZLLPresence");
|
||||
temp=glob_script_mem.fvars[hue_script[hue_devs].index[0]-1];
|
||||
light_status += "\"presence\":";
|
||||
if (temp==0)light_status += "false";
|
||||
else light_status += "true";
|
||||
light_status += ",";
|
||||
break;
|
||||
default:
|
||||
response->replace("{type}","color light");
|
||||
break;
|
||||
}
|
||||
|
||||
response->replace("{light_status}", light_status);
|
||||
response->replace("{j1",hue_script[hue_devs].name);
|
||||
response->replace("{j2", GetHueDeviceId(hue_devs));
|
||||
|
||||
}
|
||||
|
||||
|
@ -3570,7 +3644,13 @@ void Script_Check_Hue(String *response) {
|
|||
}
|
||||
// append response
|
||||
if (response) {
|
||||
*response+=",\""+String(EncodeLightId(hue_devs+devices_present+1))+"\":";
|
||||
if (devices_present) {
|
||||
*response+=",\"";
|
||||
}
|
||||
else {
|
||||
if (hue_devs>0) *response+=",\"";
|
||||
}
|
||||
*response+=String(EncodeLightId(hue_devs+devices_present+1))+"\":";
|
||||
Script_HueStatus(response,hue_devs);
|
||||
}
|
||||
|
||||
|
@ -3584,16 +3664,22 @@ void Script_Check_Hue(String *response) {
|
|||
lp++;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Hue: %d"), hue_devs);
|
||||
toLog(">>>>");
|
||||
toLog(response->c_str());
|
||||
toLog(response->c_str()+LOGSZ);
|
||||
#if 1
|
||||
if (response) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Hue: %d"), hue_devs);
|
||||
toLog(">>>>");
|
||||
toLog(response->c_str());
|
||||
toLog(response->c_str()+LOGSZ);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const char sHUE_LIGHT_RESPONSE_JSON[] PROGMEM =
|
||||
"{\"success\":{\"/lights/{id/state/{cm\":{re}}";
|
||||
|
||||
const char sHUE_SENSOR_RESPONSE_JSON[] PROGMEM =
|
||||
"{\"success\":{\"/lights/{id/state/{cm\":{re}}";
|
||||
|
||||
const char sHUE_ERROR_JSON[] PROGMEM =
|
||||
"[{\"error\":{\"type\":901,\"address\":\"/\",\"description\":\"Internal Error\"}}]";
|
||||
|
||||
|
@ -3649,6 +3735,27 @@ void Script_Handle_Hue(String *path) {
|
|||
glob_script_mem.type[hue_script[index].vindex[1]].bits.changed=1;
|
||||
resp = true;
|
||||
}
|
||||
if (hue_json.containsKey("xy")) { // Saturation of the light. 254 is the most saturated (colored) and 0 is the least saturated (white).
|
||||
float x, y;
|
||||
x = hue_json["xy"][0];
|
||||
y = hue_json["xy"][1];
|
||||
const String &x_str = hue_json["xy"][0];
|
||||
const String &y_str = hue_json["xy"][1];
|
||||
uint8_t rr,gg,bb;
|
||||
LightStateClass::XyToRgb(x, y, &rr, &gg, &bb);
|
||||
LightStateClass::RgbToHsb(rr, gg, bb, &hue, &sat, nullptr);
|
||||
if (resp) { response += ","; }
|
||||
response += FPSTR(sHUE_LIGHT_RESPONSE_JSON);
|
||||
response.replace("{id", String(device));
|
||||
response.replace("{cm", "xy");
|
||||
response.replace("{re", "[" + x_str + "," + y_str + "]");
|
||||
glob_script_mem.fvars[hue_script[index].index[2]-1]=hue;
|
||||
glob_script_mem.type[hue_script[index].vindex[2]].bits.changed=1;
|
||||
glob_script_mem.fvars[hue_script[index].index[3]-1]=sat;
|
||||
glob_script_mem.type[hue_script[index].vindex[3]].bits.changed=1;
|
||||
resp = true;
|
||||
}
|
||||
|
||||
if (hue_json.containsKey("hue")) { // The hue value is a wrapping value between 0 and 65535. Both 0 and 65535 are red, 25500 is green and 46920 is blue.
|
||||
tmp = hue_json["hue"];
|
||||
//hue = changeUIntScale(tmp, 0, 65535, 0, 359);
|
||||
|
@ -4067,7 +4174,7 @@ const char SCRIPT_MSG_BUTTONa_TBL[] PROGMEM =
|
|||
"<td style=\"width:%d%%\"><button type='submit' onclick='seva(%d,\"%s\")'>%s</button></td>";
|
||||
|
||||
const char SCRIPT_MSG_BUTTONb[] PROGMEM =
|
||||
"<img width=\"%d%%\"><\img>";
|
||||
"<img width=\"%d%%\"></img>";
|
||||
|
||||
const char SCRIPT_MSG_BUT_START[] PROGMEM =
|
||||
"<div>";
|
||||
|
@ -4437,7 +4544,9 @@ bool Xdrv10(uint8_t function)
|
|||
if (bitRead(Settings.rule_enabled, 0)) {
|
||||
Run_Scripter(">B",2,0);
|
||||
fast_script=Run_Scripter(">F",-2,0);
|
||||
#if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT)
|
||||
Script_Check_Hue(0);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case FUNC_EVERY_100_MSECOND:
|
||||
|
|
|
@ -347,7 +347,7 @@ void HAssAnnounceSwitches(void)
|
|||
// Send info about buttons
|
||||
char *tmp = Settings.switch_topic;
|
||||
Format(sw_topic, tmp, sizeof(sw_topic));
|
||||
if ((strlen(sw_topic) != 0) && strcmp(sw_topic, "0")) {
|
||||
if (strlen(sw_topic) != 0) {
|
||||
for (uint32_t switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) {
|
||||
uint8_t switch_present = 0;
|
||||
uint8_t toggle = 1;
|
||||
|
@ -376,7 +376,7 @@ void HAssAnnounceButtons(void)
|
|||
// Send info about buttons
|
||||
char *tmp = Settings.button_topic;
|
||||
Format(key_topic, tmp, sizeof(key_topic));
|
||||
if ((strlen(key_topic) != 0) && strcmp(key_topic, "0")) {
|
||||
if (strlen(key_topic) != 0) {
|
||||
for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) {
|
||||
uint8_t button_present = 0;
|
||||
uint8_t toggle = 1;
|
||||
|
|
|
@ -297,14 +297,14 @@ void LightSerialDuty(uint8_t duty)
|
|||
if (Settings.flag3.tuya_dimmer_min_limit) { // Enable dimming limit SetOption69: Enabled by default
|
||||
if (duty < 25) { duty = 25; } // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
|
||||
}
|
||||
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]);
|
||||
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_DIMMER_MAX]);
|
||||
if (Tuya.new_dim != duty) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim value=%d (id=%d)"), duty, dpid);
|
||||
TuyaSendValue(dpid, duty);
|
||||
}
|
||||
} else if (dpid > 0) {
|
||||
Tuya.ignore_dim = false; // reset flag
|
||||
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_TUYA_DIMMER_MAX]);
|
||||
duty = changeUIntScale(duty, 0, 255, 0, Settings.param[P_DIMMER_MAX]);
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Send dim skipped value=%d"), duty); // due to 0 or already set
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Cannot set dimmer. Dimmer Id unknown")); //
|
||||
|
@ -375,7 +375,7 @@ void TuyaPacketProcess(void)
|
|||
bool tuya_energy_enabled = (XNRG_16 == energy_flg);
|
||||
if (fnId == TUYA_MCU_FUNC_DIMMER) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), Tuya.buffer[13]);
|
||||
Tuya.new_dim = changeUIntScale((uint8_t) Tuya.buffer[13], 0, Settings.param[P_TUYA_DIMMER_MAX], 0, 100);
|
||||
Tuya.new_dim = changeUIntScale((uint8_t) Tuya.buffer[13], 0, Settings.param[P_DIMMER_MAX], 0, 100);
|
||||
if ((power || Settings.flag3.tuya_apply_o20) && (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) {
|
||||
Tuya.ignore_dim = true;
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ void PS16DZSerialSendUpdateCommand(void)
|
|||
uint8_t light_state_dimmer = light_state.getDimmer();
|
||||
// Dimming acts odd below 10% - this mirrors the threshold set on the faceplate itself
|
||||
light_state_dimmer = (light_state_dimmer < 10) ? 10 : light_state_dimmer;
|
||||
light_state_dimmer = (light_state_dimmer > Settings.param[P_DIMMER_MAX]) ? Settings.param[P_DIMMER_MAX] : light_state_dimmer;
|
||||
|
||||
snprintf_P(Ps16dz.tx_buffer, PS16DZ_BUFFER_SIZE, PSTR("AT+UPDATE=\"sequence\":\"%d%03d\",\"switch\":\"%s\",\"bright\":%d"),
|
||||
LocalTime(), millis()%1000, power?"on":"off", light_state_dimmer);
|
||||
|
|
|
@ -36,7 +36,7 @@ const char HUE_RESPONSE[] PROGMEM =
|
|||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://%s:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.17.0\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.24.0\r\n" // was 1.17
|
||||
"hue-bridgeid: %s\r\n";
|
||||
const char HUE_ST1[] PROGMEM =
|
||||
"ST: upnp:rootdevice\r\n"
|
||||
|
@ -503,7 +503,7 @@ void HueLights(String *path)
|
|||
response += ",\"";
|
||||
}
|
||||
}
|
||||
#ifdef USE_SCRIPT
|
||||
#ifdef USE_SCRIPT_HUE
|
||||
Script_Check_Hue(&response);
|
||||
#endif
|
||||
response += "}";
|
||||
|
@ -513,7 +513,7 @@ void HueLights(String *path)
|
|||
path->remove(path->indexOf("/state")); // Remove /state
|
||||
device = DecodeLightId(atoi(path->c_str()));
|
||||
|
||||
#ifdef USE_SCRIPT
|
||||
#ifdef USE_SCRIPT_HUE
|
||||
if (device>devices_present) {
|
||||
return Script_Handle_Hue(path);
|
||||
}
|
||||
|
@ -706,7 +706,7 @@ void HueLights(String *path)
|
|||
path->remove(0,8); // Remove /lights/
|
||||
device = DecodeLightId(atoi(path->c_str()));
|
||||
|
||||
#ifdef USE_SCRIPT
|
||||
#ifdef USE_SCRIPT_HUE
|
||||
if (device>devices_present) {
|
||||
Script_HueStatus(&response,device-devices_present-1);
|
||||
goto exit;
|
||||
|
@ -799,7 +799,11 @@ bool Xdrv20(uint8_t function)
|
|||
{
|
||||
bool result = false;
|
||||
|
||||
#ifdef USE_SCRIPT_HUE
|
||||
if ((EMUL_HUE == Settings.flag2.emulation)) {
|
||||
#else
|
||||
if (devices_present && (EMUL_HUE == Settings.flag2.emulation)) {
|
||||
#endif
|
||||
switch (function) {
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer->on("/description.xml", HandleUpnpSetupHue);
|
||||
|
|
|
@ -422,7 +422,7 @@ enum ZCL_Global_Commands {
|
|||
|
||||
};
|
||||
|
||||
enum class ZclGlobalCommandId : uint8_t {
|
||||
};
|
||||
const uint16_t Z_ProfileIds[] PROGMEM = { 0x0104, 0x0109, 0xA10E, 0xC05E };
|
||||
const char Z_ProfileNames[] PROGMEM = "ZigBee Home Automation|ZigBee Smart Energy|ZigBee Green Power|ZigBee Light Link";
|
||||
|
||||
#endif // USE_ZIGBEE
|
||||
|
|
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
xdrv_23_zigbee.ino - zigbee support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends and Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_ZIGBEE
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
typedef struct Z_Device {
|
||||
uint16_t shortaddr; // unique key if not null, or unspecified if null
|
||||
uint64_t longaddr; // 0x00 means unspecified
|
||||
String manufacturerId;
|
||||
String modelId;
|
||||
String friendlyName;
|
||||
std::vector<uint32_t> endpoints; // encoded as high 16 bits is endpoint, low 16 bits is ProfileId
|
||||
std::vector<uint32_t> clusters_in; // encoded as high 16 bits is endpoint, low 16 bits is cluster number
|
||||
std::vector<uint32_t> clusters_out; // encoded as high 16 bits is endpoint, low 16 bits is cluster number
|
||||
} Z_Device;
|
||||
|
||||
// All devices are stored in a Vector
|
||||
// Invariants:
|
||||
// - shortaddr is unique if not null
|
||||
// - longaddr is unique if not null
|
||||
// - shortaddr and longaddr cannot be both null
|
||||
// - clusters_in and clusters_out containt only endpoints listed in endpoints
|
||||
class Z_Devices {
|
||||
public:
|
||||
Z_Devices() {};
|
||||
|
||||
// Add new device, provide ShortAddr and optional longAddr
|
||||
// If it is already registered, update information, otherwise create the entry
|
||||
void updateDevice(uint16_t shortaddr, uint64_t longaddr = 0);
|
||||
|
||||
// Add an endpoint to a device
|
||||
void addEndoint(uint16_t shortaddr, uint8_t endpoint);
|
||||
|
||||
// Add endpoint profile
|
||||
void addEndointProfile(uint16_t shortaddr, uint8_t endpoint, uint16_t profileId);
|
||||
|
||||
// Add cluster
|
||||
void addCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluster, bool out);
|
||||
|
||||
uint8_t findClusterEndpointIn(uint16_t shortaddr, uint16_t cluster);
|
||||
|
||||
void setManufId(uint16_t shortaddr, const char * str);
|
||||
void setModelId(uint16_t shortaddr, const char * str);
|
||||
void setFriendlyNameId(uint16_t shortaddr, const char * str);
|
||||
|
||||
// Dump json
|
||||
String dump(uint8_t dump_mode) const;
|
||||
|
||||
private:
|
||||
std::vector<Z_Device> _devices = {};
|
||||
|
||||
template < typename T>
|
||||
static bool findInVector(const std::vector<T> & vecOfElements, const T & element);
|
||||
|
||||
template < typename T>
|
||||
static int32_t findEndpointInVector(const std::vector<T> & vecOfElements, const T & element);
|
||||
|
||||
// find the first endpoint match for a cluster
|
||||
static int32_t findClusterEndpoint(const std::vector<uint32_t> & vecOfElements, uint16_t element);
|
||||
|
||||
Z_Device & getShortAddr(uint16_t shortaddr); // find Device from shortAddr, creates it if does not exist
|
||||
Z_Device & getLongAddr(uint64_t longaddr); // find Device from shortAddr, creates it if does not exist
|
||||
|
||||
int32_t findShortAddr(uint16_t shortaddr);
|
||||
int32_t findLongAddr(uint64_t longaddr);
|
||||
|
||||
// Create a new entry in the devices list - must be called if it is sure it does not already exist
|
||||
Z_Device & createDeviceEntry(uint16_t shortaddr, uint64_t longaddr = 0);
|
||||
};
|
||||
|
||||
Z_Devices zigbee_devices = Z_Devices();
|
||||
|
||||
// https://thispointer.com/c-how-to-find-an-element-in-vector-and-get-its-index/
|
||||
template < typename T>
|
||||
bool Z_Devices::findInVector(const std::vector<T> & vecOfElements, const T & element) {
|
||||
// Find given element in vector
|
||||
auto it = std::find(vecOfElements.begin(), vecOfElements.end(), element);
|
||||
|
||||
if (it != vecOfElements.end()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template < typename T>
|
||||
int32_t Z_Devices::findEndpointInVector(const std::vector<T> & vecOfElements, const T & element) {
|
||||
// Find given element in vector
|
||||
|
||||
int32_t found = 0;
|
||||
for (auto &elem : vecOfElements) {
|
||||
if ((elem >> 16) & 0xFF == element) { return found; }
|
||||
found++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Find the first endpoint match for a cluster, whether in or out
|
||||
// Clusters are stored in the format 0x00EECCCC (EE=endpoint, CCCC=cluster number)
|
||||
// In:
|
||||
// _devices.clusters_in or _devices.clusters_out
|
||||
// cluster number looked for
|
||||
// Out:
|
||||
// Index of found Endpoint_Cluster number, or -1 if not found
|
||||
//
|
||||
int32_t Z_Devices::findClusterEndpoint(const std::vector<uint32_t> & vecOfElements, uint16_t cluster) {
|
||||
int32_t found = 0;
|
||||
for (auto &elem : vecOfElements) {
|
||||
if ((elem & 0xFFFF) == cluster) { return found; }
|
||||
found++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a new Z_Device entry in _devices. Only to be called if you are sure that no
|
||||
// entry with same shortaddr or longaddr exists.
|
||||
//
|
||||
Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) {
|
||||
if (!shortaddr && !longaddr) { return *(Z_Device*) nullptr; } // it is not legal to create an enrty with both short/long addr null
|
||||
Z_Device device = { shortaddr, longaddr,
|
||||
String(), // ManufId
|
||||
String(), // DeviceId
|
||||
String(), // FriendlyName
|
||||
std::vector<uint32_t>(),
|
||||
std::vector<uint32_t>(),
|
||||
std::vector<uint32_t>() };
|
||||
_devices.push_back(device);
|
||||
return _devices.back();
|
||||
}
|
||||
|
||||
//
|
||||
// Scan all devices to find a corresponding shortaddr
|
||||
// Looks info device.shortaddr entry
|
||||
// In:
|
||||
// shortaddr (non null)
|
||||
// Out:
|
||||
// index in _devices of entry, -1 if not found
|
||||
//
|
||||
int32_t Z_Devices::findShortAddr(uint16_t shortaddr) {
|
||||
if (!shortaddr) { return -1; } // does not make sense to look for 0x0000 shortaddr (localhost)
|
||||
int32_t found = 0;
|
||||
if (shortaddr) {
|
||||
for (auto &elem : _devices) {
|
||||
if (elem.shortaddr == shortaddr) { return found; }
|
||||
found++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
// Scan all devices to find a corresponding longaddr
|
||||
// Looks info device.longaddr entry
|
||||
// In:
|
||||
// longaddr (non null)
|
||||
// Out:
|
||||
// index in _devices of entry, -1 if not found
|
||||
//
|
||||
int32_t Z_Devices::findLongAddr(uint64_t longaddr) {
|
||||
if (!longaddr) { return -1; }
|
||||
int32_t found = 0;
|
||||
if (longaddr) {
|
||||
for (auto &elem : _devices) {
|
||||
if (elem.longaddr == longaddr) { return found; }
|
||||
found++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// We have a seen a shortaddr on the network, get the corresponding
|
||||
//
|
||||
Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) {
|
||||
if (!shortaddr) { return *(Z_Device*) nullptr; } // this is not legal
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
if (found >= 0) {
|
||||
return _devices[found];
|
||||
}
|
||||
//Serial.printf("Device entry created for shortaddr = 0x%02X, found = %d\n", shortaddr, found);
|
||||
return createDeviceEntry(shortaddr, 0);
|
||||
}
|
||||
|
||||
// find the Device object by its longaddr (unique key if not null)
|
||||
Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) {
|
||||
if (!longaddr) { return *(Z_Device*) nullptr; }
|
||||
int32_t found = findLongAddr(longaddr);
|
||||
if (found > 0) {
|
||||
return _devices[found];
|
||||
}
|
||||
return createDeviceEntry(0, longaddr);
|
||||
}
|
||||
|
||||
//
|
||||
// We have just seen a device on the network, update the info based on short/long addr
|
||||
// In:
|
||||
// shortaddr
|
||||
// longaddr (both can't be null at the same time)
|
||||
void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) {
|
||||
int32_t s_found = findShortAddr(shortaddr); // is there already a shortaddr entry
|
||||
int32_t l_found = findLongAddr(longaddr); // is there already a longaddr entry
|
||||
|
||||
if ((s_found >= 0) && (l_found >= 0)) { // both shortaddr and longaddr are already registered
|
||||
if (s_found == l_found) {
|
||||
; // short/long addr match, all good
|
||||
} else { // they don't match
|
||||
// the device with longaddr got a new shortaddr
|
||||
_devices[l_found].shortaddr = shortaddr; // update the shortaddr corresponding to the longaddr
|
||||
// erase the previous shortaddr
|
||||
_devices.erase(_devices.begin() + s_found);
|
||||
}
|
||||
} else if (s_found >= 0) {
|
||||
// shortaddr already exists but longaddr not
|
||||
// add the longaddr to the entry
|
||||
_devices[s_found].longaddr = longaddr;
|
||||
} else if (l_found >= 0) {
|
||||
// longaddr entry exists, update shortaddr
|
||||
_devices[l_found].shortaddr = shortaddr;
|
||||
} else {
|
||||
// neither short/lonf addr are found.
|
||||
if (shortaddr || longaddr) {
|
||||
createDeviceEntry(shortaddr, longaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Add an endpoint to a shortaddr
|
||||
//
|
||||
void Z_Devices::addEndoint(uint16_t shortaddr, uint8_t endpoint) {
|
||||
if (!shortaddr) { return; }
|
||||
uint32_t ep_profile = (endpoint << 16);
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
if (findEndpointInVector(device.endpoints, ep_profile) < 0) { // TODO search only on enpoint
|
||||
device.endpoints.push_back(ep_profile);
|
||||
}
|
||||
}
|
||||
|
||||
void Z_Devices::addEndointProfile(uint16_t shortaddr, uint8_t endpoint, uint16_t profileId) {
|
||||
if (!shortaddr) { return; }
|
||||
uint32_t ep_profile = (endpoint << 16) | profileId;
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
int32_t found = findEndpointInVector(device.endpoints, ep_profile);
|
||||
if (found < 0) { // TODO search only on enpoint
|
||||
device.endpoints.push_back(ep_profile);
|
||||
} else {
|
||||
device.endpoints[found] = ep_profile;
|
||||
}
|
||||
}
|
||||
|
||||
void Z_Devices::addCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluster, bool out) {
|
||||
if (!shortaddr) { return; }
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
uint32_t ep_cluster = (endpoint << 16) | cluster;
|
||||
if (!out) {
|
||||
if (!findInVector(device.clusters_in, ep_cluster)) {
|
||||
device.clusters_in.push_back(ep_cluster);
|
||||
}
|
||||
} else { // out
|
||||
if (!findInVector(device.clusters_out, ep_cluster)) {
|
||||
device.clusters_out.push_back(ep_cluster);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the best endpoint match to send a command for a specific Cluster ID
|
||||
// return 0x00 if none found
|
||||
uint8_t Z_Devices::findClusterEndpointIn(uint16_t shortaddr, uint16_t cluster){
|
||||
Z_Device &device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return 0; } // don't crash if not found
|
||||
int32_t found = findClusterEndpoint(device.clusters_in, cluster);
|
||||
if (found >= 0) {
|
||||
return (device.clusters_in[found] >> 16) & 0xFF;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Z_Devices::setManufId(uint16_t shortaddr, const char * str) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
device.manufacturerId = str;
|
||||
}
|
||||
void Z_Devices::setModelId(uint16_t shortaddr, const char * str) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
device.modelId = str;
|
||||
}
|
||||
void Z_Devices::setFriendlyNameId(uint16_t shortaddr, const char * str) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
device.friendlyName = str;
|
||||
}
|
||||
|
||||
// Dump the internal memory of Zigbee devices
|
||||
// Mode = 1: simple dump of devices addresses and names
|
||||
// Mode = 2: Mode 1 + also dump the endpoints, profiles and clusters
|
||||
String Z_Devices::dump(uint8_t dump_mode) const {
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonArray& json = jsonBuffer.createArray();
|
||||
JsonArray& devices = json;
|
||||
//JsonArray& devices = json.createNestedArray(F("ZigbeeDevices"));
|
||||
|
||||
for (std::vector<Z_Device>::const_iterator it = _devices.begin(); it != _devices.end(); ++it) {
|
||||
const Z_Device& device = *it;
|
||||
uint16_t shortaddr = device.shortaddr;
|
||||
char hex[20];
|
||||
|
||||
JsonObject& dev = devices.createNestedObject();
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
|
||||
dev[F("ShortAddr")] = hex;
|
||||
|
||||
if (device.friendlyName.length() > 0) {
|
||||
dev[F("FriendlyName")] = device.friendlyName;
|
||||
}
|
||||
|
||||
if (1 == dump_mode) {
|
||||
Uint64toHex(device.longaddr, hex, 64);
|
||||
dev[F("IEEEAddr")] = hex;
|
||||
if (device.modelId.length() > 0) {
|
||||
dev[F(D_JSON_MODEL D_JSON_ID)] = device.modelId;
|
||||
}
|
||||
if (device.manufacturerId.length() > 0) {
|
||||
dev[F("Manufacturer")] = device.manufacturerId;
|
||||
}
|
||||
}
|
||||
|
||||
// If dump_mode == 2, dump a lot more details
|
||||
if (2 == dump_mode) {
|
||||
JsonObject& dev_endpoints = dev.createNestedObject(F("Endpoints"));
|
||||
for (std::vector<uint32_t>::const_iterator ite = device.endpoints.begin() ; ite != device.endpoints.end(); ++ite) {
|
||||
uint32_t ep_profile = *ite;
|
||||
uint8_t endpoint = (ep_profile >> 16) & 0xFF;
|
||||
uint16_t profileId = ep_profile & 0xFFFF;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
|
||||
JsonObject& ep = dev_endpoints.createNestedObject(hex);
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), profileId);
|
||||
ep[F("ProfileId")] = hex;
|
||||
|
||||
int32_t found = -1;
|
||||
for (uint32_t i = 0; i < sizeof(Z_ProfileIds) / sizeof(Z_ProfileIds[0]); i++) {
|
||||
if (pgm_read_word(&Z_ProfileIds[i]) == profileId) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found > 0) {
|
||||
GetTextIndexed(hex, sizeof(hex), found, Z_ProfileNames);
|
||||
ep[F("ProfileIdName")] = hex;
|
||||
}
|
||||
|
||||
ep.createNestedArray(F("ClustersIn"));
|
||||
ep.createNestedArray(F("ClustersOut"));
|
||||
}
|
||||
|
||||
for (std::vector<uint32_t>::const_iterator itc = device.clusters_in.begin() ; itc != device.clusters_in.end(); ++itc) {
|
||||
uint16_t cluster = *itc & 0xFFFF;
|
||||
uint8_t endpoint = (*itc >> 16) & 0xFF;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
|
||||
JsonArray &cluster_arr = dev_endpoints[hex][F("ClustersIn")];
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), cluster);
|
||||
cluster_arr.add(hex);
|
||||
}
|
||||
|
||||
for (std::vector<uint32_t>::const_iterator itc = device.clusters_out.begin() ; itc != device.clusters_out.end(); ++itc) {
|
||||
uint16_t cluster = *itc & 0xFFFF;
|
||||
uint8_t endpoint = (*itc >> 16) & 0xFF;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
|
||||
JsonArray &cluster_arr = dev_endpoints[hex][F("ClustersOut")];
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), cluster);
|
||||
cluster_arr.add(hex);
|
||||
}
|
||||
}
|
||||
}
|
||||
String payload = "";
|
||||
payload.reserve(200);
|
||||
json.printTo(payload);
|
||||
return payload;
|
||||
}
|
||||
|
||||
#endif // USE_ZIGBEE
|
|
@ -55,7 +55,7 @@ public:
|
|||
uint32_t timestamp) {
|
||||
char hex_char[_payload.len()*2+2];
|
||||
ToHex_P((unsigned char*)_payload.getBuffer(), _payload.len(), hex_char, sizeof(hex_char));
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEEZCLRECEIVED "\":{"
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEEZCL_RECEIVED "\":{"
|
||||
"\"groupid\":%d," "\"clusterid\":%d," "\"srcaddr\":\"0x%04X\","
|
||||
"\"srcendpoint\":%d," "\"dstendpoint\":%d," "\"wasbroadcast\":%d,"
|
||||
"\"linkquality\":%d," "\"securityuse\":%d," "\"seqnumber\":%d,"
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
|
||||
ResponseJsonEnd(); // append '}'
|
||||
ResponseJsonEnd(); // append '}'
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLSENT));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,9 @@ public:
|
|||
}
|
||||
|
||||
void parseRawAttributes(JsonObject& json, uint8_t offset = 0);
|
||||
void parseReadAttributes(JsonObject& json, uint8_t offset = 0);
|
||||
void parseClusterSpecificCommand(JsonObject& json, uint8_t offset = 0);
|
||||
void postProcessAttributes(JsonObject& json);
|
||||
void postProcessAttributes(uint16_t shortaddr, JsonObject& json);
|
||||
|
||||
inline void setGroupId(uint16_t groupid) {
|
||||
_group_id = groupid;
|
||||
|
@ -208,7 +209,7 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 0x23: // uint16
|
||||
case 0x23: // uint32
|
||||
{
|
||||
uint32_t uint32_val = buf.get32(i);
|
||||
i += 4;
|
||||
|
@ -403,6 +404,27 @@ void ZCLFrame::parseRawAttributes(JsonObject& json, uint8_t offset) {
|
|||
}
|
||||
}
|
||||
|
||||
// ZCL_READ_ATTRIBUTES_RESPONSE
|
||||
void ZCLFrame::parseReadAttributes(JsonObject& json, uint8_t offset) {
|
||||
uint32_t i = offset;
|
||||
uint32_t len = _payload.len();
|
||||
|
||||
while (len - i >= 4) {
|
||||
uint16_t attrid = _payload.get16(i);
|
||||
i += 2;
|
||||
uint8_t status = _payload.get8(i++);
|
||||
|
||||
if (0 == status) {
|
||||
char shortaddr[16];
|
||||
snprintf_P(shortaddr, sizeof(shortaddr), PSTR("%c_%04X_%04X"),
|
||||
Hex36Char(_cmd_id), _cluster_id, attrid);
|
||||
|
||||
i += parseSingleAttribute(json, shortaddr, _payload, i, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse non-normalized attributes
|
||||
// The key is "s_" followed by 16 bits clusterId, "_" followed by 8 bits command id
|
||||
void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) {
|
||||
|
@ -421,7 +443,7 @@ void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) {
|
|||
// return value:
|
||||
// 0 = keep initial value
|
||||
// 1 = remove initial value
|
||||
typedef int32_t (*Z_AttrConverter)(JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param);
|
||||
typedef int32_t (*Z_AttrConverter)(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param);
|
||||
typedef struct Z_AttributeConverter {
|
||||
const char * filter;
|
||||
const char * name;
|
||||
|
@ -434,7 +456,19 @@ const float Z_10 PROGMEM = 10.0f;
|
|||
|
||||
// list of post-processing directives
|
||||
const Z_AttributeConverter Z_PostProcess[] = {
|
||||
{ "A_0000_0005", D_JSON_MODEL D_JSON_ID, &Z_Copy, nullptr }, // ModelID
|
||||
{ "?_0000_0004", nullptr, &Z_ManufKeep, nullptr }, // record Manufacturer
|
||||
{ "?_0000_0005", nullptr, &Z_ModelKeep, nullptr }, // record Model
|
||||
|
||||
{ "?_0000_0000", "ZCLVersion", &Z_Copy, nullptr },
|
||||
{ "?_0000_0001", "AppVersion", &Z_Copy, nullptr },
|
||||
{ "?_0000_0002", "StackVersion", &Z_Copy, nullptr },
|
||||
{ "?_0000_0003", "HWVersion", &Z_Copy, nullptr },
|
||||
{ "?_0000_0004", "Manufacturer", &Z_Copy, nullptr },
|
||||
{ "?_0000_0005", D_JSON_MODEL D_JSON_ID, &Z_Copy, nullptr },
|
||||
{ "?_0000_0006", "DateCode", &Z_Copy, nullptr },
|
||||
{ "?_0000_0007", "PowerSource", &Z_Copy, nullptr },
|
||||
{ "?_0000_4000", "SWBuildID", &Z_Copy, nullptr },
|
||||
{ "A_0000_????", nullptr, &Z_Remove, nullptr }, // Remove all other values
|
||||
|
||||
{ "A_0400_0000", D_JSON_ILLUMINANCE, &Z_Copy, nullptr }, // Illuminance (in Lux)
|
||||
{ "A_0400_0004", "LightSensorType", &Z_Copy, nullptr }, // LightSensorType
|
||||
|
@ -469,38 +503,50 @@ const Z_AttributeConverter Z_PostProcess[] = {
|
|||
// { "A_0B04_????", "", &Z_Remove, nullptr }, // Remove all other values
|
||||
};
|
||||
|
||||
|
||||
// ======================================================================
|
||||
// Record Manuf
|
||||
int32_t Z_ManufKeep(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
zigbee_devices.setManufId(shortaddr, value.as<const char*>());
|
||||
return 0; // keep original key
|
||||
}
|
||||
//
|
||||
int32_t Z_ModelKeep(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
zigbee_devices.setModelId(shortaddr, value.as<const char*>());
|
||||
return 0; // keep original key
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// Remove attribute
|
||||
int32_t Z_Remove(JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
int32_t Z_Remove(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
return 1; // remove original key
|
||||
}
|
||||
|
||||
// Copy value as-is
|
||||
int32_t Z_Copy(JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
int32_t Z_Copy(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
json[new_name] = value;
|
||||
return 1; // remove original key
|
||||
}
|
||||
|
||||
// Copy value as-is
|
||||
int32_t Z_Const_Keep(JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
int32_t Z_Const_Keep(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
json[new_name] = (char*)param;
|
||||
return 0; // keep original key
|
||||
}
|
||||
|
||||
// Convert int to float with divider
|
||||
int32_t Z_ConvFloatDivider(JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
int32_t Z_ConvFloatDivider(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
float f_value = value;
|
||||
float *divider = (float*) param;
|
||||
json[new_name] = f_value / *divider;
|
||||
return 1; // remove original key
|
||||
}
|
||||
|
||||
int32_t Z_AqaraSensor(JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
int32_t Z_AqaraSensor(uint16_t shortaddr, JsonObject& json, const char *name, JsonVariant& value, const char *new_name, void * param) {
|
||||
String hex = value;
|
||||
SBuffer buf2 = SBuffer::SBufferFromHex(hex.c_str(), hex.length());
|
||||
uint32_t i = 0;
|
||||
uint32_t len = buf2.len();
|
||||
char shortaddr[8];
|
||||
char tmp[] = "tmp"; // for obscure reasons, it must be converted from const char* to char*, otherwise ArduinoJson gets confused
|
||||
|
||||
JsonVariant sub_value;
|
||||
|
@ -573,7 +619,7 @@ bool mini_glob_match(char const *pat, char const *str) {
|
|||
}
|
||||
}
|
||||
|
||||
void ZCLFrame::postProcessAttributes(JsonObject& json) {
|
||||
void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) {
|
||||
// iterate on json elements
|
||||
for (auto kv : json) {
|
||||
String key = kv.key;
|
||||
|
@ -584,7 +630,7 @@ void ZCLFrame::postProcessAttributes(JsonObject& json) {
|
|||
const Z_AttributeConverter *converter = &Z_PostProcess[i];
|
||||
|
||||
if (mini_glob_match(converter->filter, key.c_str())) {
|
||||
int32_t drop = (*converter->func)(json, key.c_str(), value, converter->name, converter->param);
|
||||
int32_t drop = (*converter->func)(shortaddr, json, key.c_str(), value, converter->name, converter->param);
|
||||
if (drop) {
|
||||
json.remove(key);
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
/*
|
||||
xdrv_23_zigbee.ino - zigbee support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends and Stephan Hadinger
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_ZIGBEE
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
typedef struct Z_Device {
|
||||
uint16_t shortaddr;
|
||||
uint64_t longaddr; // 0x00 means unspecified
|
||||
std::vector<uint8_t> endpoints;
|
||||
std::vector<uint32_t> clusters_in; // encoded as high 16 bits is endpoint, low 16 bits is cluster number
|
||||
std::vector<uint32_t> clusters_out; // encoded as high 16 bits is endpoint, low 16 bits is cluster number
|
||||
} Z_Device;
|
||||
|
||||
std::map<uint16_t, Z_Device> zigbee_devices = {};
|
||||
|
||||
|
||||
template < typename T>
|
||||
bool findInVector(const std::vector<T> & vecOfElements, const T & element) {
|
||||
// Find given element in vector
|
||||
auto it = std::find(vecOfElements.begin(), vecOfElements.end(), element);
|
||||
|
||||
if (it != vecOfElements.end()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// insert an entry when it is known it is missing
|
||||
void Z_InsertShortAddrEntry(uint16_t shortaddr, uint64_t longaddr) {
|
||||
Z_Device device = { shortaddr, longaddr,
|
||||
std::vector<uint8_t>(),
|
||||
std::vector<uint32_t>(),
|
||||
std::vector<uint32_t>() };
|
||||
zigbee_devices[shortaddr] = device;
|
||||
}
|
||||
|
||||
void Z_AddDeviceLongAddr(uint16_t shortaddr, uint64_t longaddr) {
|
||||
// is the short address already recorded?
|
||||
if (0 == zigbee_devices.count(shortaddr)) {
|
||||
// No, add an entry
|
||||
Z_InsertShortAddrEntry(shortaddr, longaddr);
|
||||
} else {
|
||||
// Yes, update the longaddr if necessary
|
||||
Z_Device &device = zigbee_devices[shortaddr];
|
||||
uint64_t prev_longaddr = device.longaddr;
|
||||
if (prev_longaddr != longaddr) {
|
||||
// new device, i.e. collision
|
||||
device.longaddr = longaddr;
|
||||
device.endpoints.clear();
|
||||
device.clusters_in.clear();
|
||||
device.clusters_out.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Z_AddDeviceEndpoint(uint16_t shortaddr, uint8_t endpoint) {
|
||||
if (0 == zigbee_devices.count(shortaddr)) {
|
||||
// No entry
|
||||
Z_InsertShortAddrEntry(shortaddr, 0);
|
||||
}
|
||||
Z_Device &device = zigbee_devices[shortaddr];
|
||||
if (!findInVector(device.endpoints, endpoint)) {
|
||||
device.endpoints.push_back(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
void Z_AddDeviceCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluster, bool out) {
|
||||
if (0 == zigbee_devices.count(shortaddr)) {
|
||||
// No entry
|
||||
Z_InsertShortAddrEntry(shortaddr, 0);
|
||||
}
|
||||
Z_Device &device = zigbee_devices[shortaddr];
|
||||
if (!findInVector(device.endpoints, endpoint)) {
|
||||
device.endpoints.push_back(endpoint);
|
||||
}
|
||||
uint32_t ep_cluster = (endpoint << 16) | cluster;
|
||||
if (!out) {
|
||||
if (!findInVector(device.clusters_in, ep_cluster)) {
|
||||
device.clusters_in.push_back(ep_cluster);
|
||||
}
|
||||
} else { // out
|
||||
if (!findInVector(device.clusters_out, ep_cluster)) {
|
||||
device.clusters_out.push_back(ep_cluster);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String Z_DumpDevices(void) {
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonObject& json = jsonBuffer.createObject();
|
||||
JsonObject& devices = json.createNestedObject(F("ZigbeeDevices"));
|
||||
|
||||
for (std::map<uint16_t, Z_Device>::iterator it = zigbee_devices.begin(); it != zigbee_devices.end(); ++it) {
|
||||
uint16_t shortaddr = it->first;
|
||||
Z_Device& device = it->second;
|
||||
char hex[20];
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), shortaddr);
|
||||
JsonObject& dev = devices.createNestedObject(hex);
|
||||
dev[F("ShortAddr")] = hex;
|
||||
|
||||
Uint64toHex(device.longaddr, hex, 64);
|
||||
dev[F("IEEEAddr")] = hex;
|
||||
|
||||
JsonArray& dev_endpoints = dev.createNestedArray(F("Endpoints"));
|
||||
for (std::vector<uint8_t>::iterator ite = device.endpoints.begin() ; ite != device.endpoints.end(); ++ite) {
|
||||
uint8_t endpoint = *ite;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
|
||||
dev_endpoints.add(hex);
|
||||
}
|
||||
|
||||
JsonObject& dev_clusters_in = dev.createNestedObject(F("Clusters_in"));
|
||||
for (std::vector<uint32_t>::iterator itc = device.clusters_in.begin() ; itc != device.clusters_in.end(); ++itc) {
|
||||
uint16_t cluster = *itc & 0xFFFF;
|
||||
uint8_t endpoint = (*itc >> 16) & 0xFF;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
|
||||
if (!dev_clusters_in.containsKey(hex)) {
|
||||
dev_clusters_in.createNestedArray(hex);
|
||||
}
|
||||
JsonArray &cluster_arr = dev_clusters_in[hex];
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), cluster);
|
||||
cluster_arr.add(hex);
|
||||
}
|
||||
|
||||
JsonObject& dev_clusters_out = dev.createNestedObject(F("Clusters_out"));
|
||||
for (std::vector<uint32_t>::iterator itc = device.clusters_out.begin() ; itc != device.clusters_out.end(); ++itc) {
|
||||
uint16_t cluster = *itc & 0xFFFF;
|
||||
uint8_t endpoint = (*itc >> 16) & 0xFF;
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%02X"), endpoint);
|
||||
if (!dev_clusters_out.containsKey(hex)) {
|
||||
dev_clusters_out.createNestedArray(hex);
|
||||
}
|
||||
JsonArray &cluster_arr = dev_clusters_out[hex];
|
||||
|
||||
snprintf_P(hex, sizeof(hex), PSTR("0x%04X"), cluster);
|
||||
cluster_arr.add(hex);
|
||||
}
|
||||
}
|
||||
String payload = "";
|
||||
payload.reserve(200);
|
||||
json.printTo(payload);
|
||||
return payload;
|
||||
}
|
||||
|
||||
#endif // USE_ZIGBEE
|
|
@ -38,7 +38,7 @@ const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP versi
|
|||
const uint8_t ZIGBEE_STATUS_ABORT = 99; // Fatal error, Zigbee not working
|
||||
|
||||
typedef int32_t (*ZB_Func)(uint8_t value);
|
||||
typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, class SBuffer &buf);
|
||||
typedef int32_t (*ZB_RecvMsgFunc)(int32_t res, const class SBuffer &buf);
|
||||
|
||||
typedef union Zigbee_Instruction {
|
||||
struct {
|
||||
|
@ -283,8 +283,6 @@ ZBM(AREQ_ZDO_NODEDESCRSP, Z_AREQ | Z_ZDO, ZDO_NODE_DESC_RSP) // 4582
|
|||
// ServerMask (2 bytes) - 0100 - Primary Trust Center
|
||||
// MaxOutTransferSize (2 bytes) - A000 = 160
|
||||
// DescriptorCapabilities (1 byte) - 00
|
||||
ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584
|
||||
ZBM(AREQ_ZDO_ACTIVEEPRSP, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP) // 4585
|
||||
|
||||
// Z_ZDO:activeEpReq
|
||||
ZBM(ZBS_ZDO_ACTIVEEPREQ, Z_SREQ | Z_ZDO, ZDO_ACTIVE_EP_REQ, 0x00, 0x00, 0x00, 0x00) // 250500000000
|
||||
|
@ -313,20 +311,15 @@ ZBM(ZBR_PERMITJOINREQ, Z_SRSP | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_REQ, Z_Success) /
|
|||
ZBM(ZBR_PERMITJOIN_AREQ_CLOSE, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND, 0x00 /* Duration */) // 45CB00
|
||||
ZBM(ZBR_PERMITJOIN_AREQ_OPEN_60, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND, 60 /* Duration */) // 45CB3C
|
||||
ZBM(ZBR_PERMITJOIN_AREQ_OPEN_FF, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND, 0xFF /* Duration */) // 45CBFF
|
||||
ZBM(ZBR_PERMITJOIN_AREQ_OPEN_XX, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND ) // 45CB
|
||||
ZBM(ZBR_PERMITJOIN_AREQ_RSP, Z_AREQ | Z_ZDO, ZDO_MGMT_PERMIT_JOIN_RSP, 0x00, 0x00 /* srcAddr*/, Z_Success ) // 45B6000000
|
||||
|
||||
// Filters for ZCL frames
|
||||
ZBM(ZBR_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
|
||||
ZBM(ZBR_END_DEVICE_ANNCE_IND, Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND) // 45C1
|
||||
|
||||
static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
||||
ZI_LABEL(0)
|
||||
ZI_NOOP()
|
||||
ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT)
|
||||
ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT)
|
||||
ZI_ON_RECV_UNEXPECTED(&Z_Recv_Default)
|
||||
ZI_WAIT(15000) // wait for 15 seconds for Tasmota to stabilize
|
||||
ZI_WAIT(10000) // wait for 10 seconds for Tasmota to stabilize
|
||||
ZI_ON_ERROR_GOTO(50)
|
||||
|
||||
ZI_MQTT_STATUS(ZIGBEE_STATUS_BOOT, "Booting")
|
||||
|
@ -337,7 +330,6 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
|
|||
ZI_LOG(LOG_LEVEL_INFO, "ZIG: checking device configuration")
|
||||
ZI_SEND(ZBS_ZNPHC) // check value of ZNP Has Configured
|
||||
ZI_WAIT_RECV(2000, ZBR_ZNPHC)
|
||||
ZI_WAIT(100)
|
||||
ZI_SEND(ZBS_VERSION) // check ZNP software version
|
||||
ZI_WAIT_RECV_FUNC(2000, ZBR_VERSION, &Z_ReceiveCheckVersion) // Check version
|
||||
ZI_SEND(ZBS_PAN) // check PAN ID
|
||||
|
|
|
@ -188,7 +188,7 @@ int32_t Z_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) {
|
|||
complexDescriptorAvailable ? "true" : "false"
|
||||
);
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) {
|
|||
|
||||
|
||||
for (uint32_t i = 0; i < activeEpCount; i++) {
|
||||
Z_AddDeviceEndpoint(nwkAddr, activeEpList[i]);
|
||||
zigbee_devices.addEndoint(nwkAddr, activeEpList[i]);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < activeEpCount; i++) {
|
||||
|
@ -220,11 +220,33 @@ int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) {
|
|||
ResponseAppend_P(PSTR("\"0x%02X\""), activeEpList[i]);
|
||||
}
|
||||
ResponseAppend_P(PSTR("]}}"));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Z_SendAFInfoRequest(uint16_t shortaddr, uint8_t endpoint, uint16_t clusterid, uint8_t transacid) {
|
||||
SBuffer buf(100);
|
||||
buf.add8(Z_SREQ | Z_AF); // 24
|
||||
buf.add8(AF_DATA_REQUEST); // 01
|
||||
buf.add16(shortaddr);
|
||||
buf.add8(endpoint); // dest endpoint
|
||||
buf.add8(0x01); // source endpoint
|
||||
buf.add16(clusterid);
|
||||
buf.add8(transacid);
|
||||
buf.add8(0x30); // 30 options
|
||||
buf.add8(0x1E); // 1E radius
|
||||
|
||||
buf.add8(3 + 2*sizeof(uint16_t)); // Len = 0x07
|
||||
buf.add8(0x00); // Frame Control Field
|
||||
buf.add8(transacid); // Transaction Sequance Number
|
||||
buf.add8(ZCL_READ_ATTRIBUTES); // 00 Command
|
||||
buf.add16(0x0004); // 0400 ManufacturerName
|
||||
buf.add16(0x0005); // 0500 ModelIdentifier
|
||||
|
||||
ZigbeeZNPSend(buf.getBuffer(), buf.len());
|
||||
}
|
||||
|
||||
|
||||
int32_t Z_ReceiveSimpleDesc(int32_t res, const class SBuffer &buf) {
|
||||
// Received ZDO_SIMPLE_DESC_RSP
|
||||
|
@ -240,18 +262,17 @@ int32_t Z_ReceiveSimpleDesc(int32_t res, const class SBuffer &buf) {
|
|||
uint8_t numOutCluster = buf.get8(15 + numInCluster*2);
|
||||
|
||||
if (0 == status) {
|
||||
zigbee_devices.addEndointProfile(nwkAddr, endpoint, profileId);
|
||||
for (uint32_t i = 0; i < numInCluster; i++) {
|
||||
Z_AddDeviceCluster(nwkAddr, endpoint, buf.get16(15 + i*2), false);
|
||||
zigbee_devices.addCluster(nwkAddr, endpoint, buf.get16(15 + i*2), false);
|
||||
}
|
||||
for (uint32_t i = 0; i < numOutCluster; i++) {
|
||||
Z_AddDeviceCluster(nwkAddr, endpoint, buf.get16(16 + numInCluster*2 + i*2), true);
|
||||
zigbee_devices.addCluster(nwkAddr, endpoint, buf.get16(16 + numInCluster*2 + i*2), true);
|
||||
}
|
||||
// String dump = Z_DumpDevices();
|
||||
// Serial.printf(">>> Devices dump = %s\n", dump.c_str());
|
||||
|
||||
Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATUS "\":{"
|
||||
"\"Status\":%d,\"Endpoint\":\"0x%02X\""
|
||||
",\"ProfileId\":\"0x%04X\",\"DeviceId\":\"0x%04X\",\"DeviceVerion\":%d"
|
||||
",\"ProfileId\":\"0x%04X\",\"DeviceId\":\"0x%04X\",\"DeviceVersion\":%d"
|
||||
"\"InClusters\":["),
|
||||
ZIGBEE_STATUS_SIMPLE_DESC, endpoint,
|
||||
profileId, deviceId, deviceVersion);
|
||||
|
@ -265,8 +286,14 @@ int32_t Z_ReceiveSimpleDesc(int32_t res, const class SBuffer &buf) {
|
|||
ResponseAppend_P(PSTR("\"0x%04X\""), buf.get16(16 + numInCluster*2 + i*2));
|
||||
}
|
||||
ResponseAppend_P(PSTR("]}}"));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
|
||||
uint8_t cluster = zigbee_devices.findClusterEndpointIn(nwkAddr, 0x0000);
|
||||
Serial.printf(">>> Endpoint is 0x%02X for cluster 0x%04X\n", cluster, 0x0000);
|
||||
if (cluster) {
|
||||
Z_SendAFInfoRequest(nwkAddr, cluster, 0x0000, 0x01); // TODO
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -277,9 +304,7 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
|||
Z_IEEEAddress ieeeAddr = buf.get64(6);
|
||||
uint8_t capabilities = buf.get8(14);
|
||||
|
||||
Z_AddDeviceLongAddr(nwkAddr, ieeeAddr);
|
||||
// String dump = Z_DumpDevices();
|
||||
// Serial.printf(">>> Devices dump = %s\n", dump.c_str());
|
||||
zigbee_devices.updateDevice(nwkAddr, ieeeAddr);
|
||||
|
||||
char hex[20];
|
||||
Uint64toHex(ieeeAddr, hex, 64);
|
||||
|
@ -292,7 +317,7 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) {
|
|||
(capabilities & 0x40) ? "true" : "false"
|
||||
);
|
||||
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
Z_SendActiveEpReq(nwkAddr);
|
||||
return -1;
|
||||
|
@ -325,21 +350,47 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) {
|
|||
JsonObject& json = json_root.createNestedObject(shortaddr);
|
||||
if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) {
|
||||
zcl_received.parseRawAttributes(json);
|
||||
} else if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_READ_ATTRIBUTES_RESPONSE == zcl_received.getCmdId())) {
|
||||
zcl_received.parseReadAttributes(json);
|
||||
} else if (zcl_received.isClusterSpecificCommand()) {
|
||||
zcl_received.parseClusterSpecificCommand(json);
|
||||
}
|
||||
zcl_received.postProcessAttributes(json);
|
||||
|
||||
String msg("");
|
||||
msg.reserve(100);
|
||||
json_root.printTo(msg);
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeZCLRawReceived: %s"), msg.c_str());
|
||||
|
||||
zcl_received.postProcessAttributes(srcaddr, json);
|
||||
|
||||
msg = "";
|
||||
json_root.printTo(msg);
|
||||
Response_P(PSTR("%s"), msg.c_str());
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCLRECEIVED));
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED));
|
||||
XdrvRulesProcess();
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef struct Z_Dispatcher {
|
||||
const uint8_t* match;
|
||||
ZB_RecvMsgFunc func;
|
||||
} Z_Dispatcher;
|
||||
|
||||
// Filters for ZCL frames
|
||||
ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
|
||||
ZBM(AREQ_END_DEVICE_ANNCE_IND, Z_AREQ | Z_ZDO, ZDO_END_DEVICE_ANNCE_IND) // 45C1
|
||||
ZBM(AREQ_PERMITJOIN_OPEN_XX, Z_AREQ | Z_ZDO, ZDO_PERMIT_JOIN_IND ) // 45CB
|
||||
ZBM(AREQ_ZDO_ACTIVEEPRSP, Z_AREQ | Z_ZDO, ZDO_ACTIVE_EP_RSP) // 4585
|
||||
ZBM(AREQ_ZDO_SIMPLEDESCRSP, Z_AREQ | Z_ZDO, ZDO_SIMPLE_DESC_RSP) // 4584
|
||||
|
||||
const Z_Dispatcher Z_DispatchTable[] PROGMEM = {
|
||||
{ AREQ_AF_INCOMING_MESSAGE, &Z_ReceiveAfIncomingMessage },
|
||||
{ AREQ_END_DEVICE_ANNCE_IND, &Z_ReceiveEndDeviceAnnonce },
|
||||
{ AREQ_PERMITJOIN_OPEN_XX, &Z_ReceivePermitJoinStatus },
|
||||
{ AREQ_ZDO_NODEDESCRSP, &Z_ReceiveNodeDesc },
|
||||
{ AREQ_ZDO_ACTIVEEPRSP, &Z_ReceiveActiveEp },
|
||||
{ AREQ_ZDO_SIMPLEDESCRSP, &Z_ReceiveSimpleDesc },
|
||||
};
|
||||
|
||||
int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
|
||||
// Default message handler for new messages
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Z_Recv_Default"));
|
||||
|
@ -347,18 +398,10 @@ int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
|
|||
// if still during initialization phase, ignore any unexpected message
|
||||
return -1; // ignore message
|
||||
} else {
|
||||
if (Z_ReceiveMatchPrefix(buf, ZBR_AF_INCOMING_MESSAGE)) {
|
||||
return Z_ReceiveAfIncomingMessage(res, buf);
|
||||
} else if (Z_ReceiveMatchPrefix(buf, ZBR_END_DEVICE_ANNCE_IND)) {
|
||||
return Z_ReceiveEndDeviceAnnonce(res, buf);
|
||||
} else if (Z_ReceiveMatchPrefix(buf, ZBR_PERMITJOIN_AREQ_OPEN_XX)) {
|
||||
return Z_ReceivePermitJoinStatus(res, buf);
|
||||
} else if (Z_ReceiveMatchPrefix(buf, AREQ_ZDO_NODEDESCRSP)) {
|
||||
return Z_ReceiveNodeDesc(res, buf);
|
||||
} else if (Z_ReceiveMatchPrefix(buf, AREQ_ZDO_ACTIVEEPRSP)) {
|
||||
return Z_ReceiveActiveEp(res, buf);
|
||||
} else if (Z_ReceiveMatchPrefix(buf, AREQ_ZDO_SIMPLEDESCRSP)) {
|
||||
return Z_ReceiveSimpleDesc(res, buf);
|
||||
for (uint32_t i = 0; i < sizeof(Z_DispatchTable)/sizeof(Z_Dispatcher); i++) {
|
||||
if (Z_ReceiveMatchPrefix(buf, Z_DispatchTable[i].match)) {
|
||||
(*Z_DispatchTable[i].func)(res, buf);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ TasmotaSerial *ZigbeeSerial = nullptr;
|
|||
|
||||
|
||||
const char kZigbeeCommands[] PROGMEM = "|" D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN
|
||||
"|" D_CMND_ZIGBEE_DUMP;
|
||||
"|" D_CMND_ZIGBEE_STATUS;
|
||||
|
||||
void (* const ZigbeeCommand[])(void) PROGMEM = { &CmndZigbeeZNPSend, &CmndZigbeePermitJoin,
|
||||
&CmndZigbeeDump };
|
||||
&CmndZigbeeStatus };
|
||||
|
||||
int32_t ZigbeeProcessInput(class SBuffer &buf) {
|
||||
if (!zigbee.state_machine) { return -1; } // if state machine is stopped, send 'ignore' message
|
||||
|
@ -234,10 +234,10 @@ void ZigbeeInit(void)
|
|||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
||||
void CmndZigbeeDump(void) {
|
||||
void CmndZigbeeStatus(void) {
|
||||
if (ZigbeeSerial) {
|
||||
String dump = Z_DumpDevices();
|
||||
Response_P(S_JSON_COMMAND_XVALUE, XdrvMailbox.command, dump.c_str());
|
||||
String dump = zigbee_devices.dump(XdrvMailbox.payload);
|
||||
Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.payload, dump.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
xdrv_26_sm2135.ino - sm2135 I2C five channel led support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
#ifdef USE_SM2135
|
||||
/*********************************************************************************************\
|
||||
* SM2135 I2C RGBCW Led bulbs like Action LSC SmartLed
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_26 26
|
||||
|
||||
#define SM2135_ADDR 0x40 // 0x40 .. 0x46
|
||||
|
||||
//#define SM2135_CURRENT 0x24 // Defaults: 20mA for RGB, 30mA for CW
|
||||
#define SM2135_CURRENT 0x16 // 3 x 15mA for RGB, 2 x 40mA/2 for CW
|
||||
|
||||
#define SM2135_RGB 0x00
|
||||
#define SM2135_CW 0x80
|
||||
|
||||
struct SM2135 {
|
||||
bool found = true;
|
||||
} Sm2135;
|
||||
|
||||
bool Sm2135SetChannels(void)
|
||||
{
|
||||
char *buffer = XdrvMailbox.data;
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SM1: R %d G %d B %d, C %d W %d"), buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
|
||||
|
||||
if (('\0' == buffer[0]) && ('\0' == buffer[1]) && ('\0' == buffer[2])) {
|
||||
// No color so must be Cold/Warm
|
||||
if ((buffer[3] + buffer[4]) >= (1 * 256)) {
|
||||
// Scale down to 255 total to fix max power usage of 9W (=40mA)
|
||||
// Currently not needed with setting 2 x 40mA/2 = 40mA = 9W = 255 (handled by lights.ino)
|
||||
|
||||
buffer[3] >>= 1; // Divide by 2
|
||||
buffer[4] >>= 1; // Divide by 2
|
||||
}
|
||||
Wire.beginTransmission(SM2135_ADDR);
|
||||
Wire.write(SM2135_CURRENT); // Set current to 40mA
|
||||
Wire.write(SM2135_CW); // Select CW - Shutdown RGB?
|
||||
Wire.endTransmission();
|
||||
delay(1);
|
||||
Wire.beginTransmission(SM2135_ADDR +5);
|
||||
Wire.write(buffer[3]); // Cold
|
||||
Wire.write(buffer[4]); // Warm
|
||||
Wire.endTransmission();
|
||||
} else {
|
||||
// Color
|
||||
if ((buffer[0] + buffer[1] + buffer[2]) >= (3 * 256)) {
|
||||
// Scale down to 765 total to fix max power usage of 9W
|
||||
// Currently not needed with setting 3 x 15mA = 45mA = 11W = 765
|
||||
}
|
||||
Wire.beginTransmission(SM2135_ADDR);
|
||||
Wire.write(SM2135_CURRENT); // Set current to 15mA
|
||||
Wire.write(SM2135_RGB); // Select RGB - Shutdown CW?
|
||||
Wire.write(buffer[0]); // Red
|
||||
Wire.write(buffer[1]); // Green
|
||||
Wire.write(buffer[2]); // Blue
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sm2135ModuleSelected(void)
|
||||
{
|
||||
if (I2cDevice(SM2135_ADDR)) {
|
||||
|
||||
// Make sure it is the SM2135 chip as it's address is also used by HTU21, INA219, INA226
|
||||
// EXPERIMENTAL: Need further testing
|
||||
|
||||
light_type = LT_RGBWC;
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "SM2135", SM2135_ADDR);
|
||||
} else {
|
||||
Sm2135.found = false;
|
||||
}
|
||||
return Sm2135.found;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv26(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (i2c_flg && Sm2135.found) {
|
||||
switch (function) {
|
||||
case FUNC_SET_CHANNELS:
|
||||
result = Sm2135SetChannels();
|
||||
break;
|
||||
case FUNC_MODULE_INIT:
|
||||
result = Sm2135ModuleSelected();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_SM2135
|
||||
#endif // USE_LIGHT
|
|
@ -107,8 +107,6 @@ void ShutterInit(void)
|
|||
Shutter.mask = 0;
|
||||
//Initialize to get relay that changed
|
||||
Shutter.old_power = power;
|
||||
char shutter_open_chr[10];
|
||||
char shutter_close_chr[10];
|
||||
bool relay_in_interlock = false;
|
||||
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Accuracy digits: %d"), Settings.shutter_accuracy);
|
||||
|
@ -164,9 +162,11 @@ void ShutterInit(void)
|
|||
Shutter.real_position[i] = ShutterPercentToRealPosition(Settings.shutter_position[i], i);
|
||||
//Shutter.real_position[i] = Settings.shutter_position[i] <= 5 ? Settings.shuttercoeff[2][i] * Settings.shutter_position[i] : Settings.shuttercoeff[1][i] * Settings.shutter_position[i] + Settings.shuttercoeff[0,i];
|
||||
Shutter.start_position[i] = Shutter.real_position[i];
|
||||
dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr);
|
||||
dtostrfd((float)Shutter.close_time[i] / 10, 1, shutter_close_chr);
|
||||
|
||||
char shutter_open_chr[10];
|
||||
dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr);
|
||||
char shutter_close_chr[10];
|
||||
dtostrfd((float)Shutter.close_time[i] / 10, 1, shutter_close_chr);
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100 Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoedffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, shuttermode %d"),
|
||||
i, Settings.shutter_startrelay[i], Shutter.real_position[i], Settings.shutter_position[i], Shutter.close_velocity[i], Shutter.open_max[i], shutter_open_chr, shutter_close_chr,
|
||||
Settings.shuttercoeff[0][i], Settings.shuttercoeff[1][i], Settings.shuttercoeff[2][i], Settings.shuttercoeff[3][i], Settings.shuttercoeff[4][i],
|
||||
|
@ -435,13 +435,13 @@ void CmndShutterPosition(void)
|
|||
ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]);
|
||||
Shutter.operations[index]++;
|
||||
if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE) {
|
||||
ExecuteCommandPower(Settings.shutter_startrelay[index] , 0, SRC_SHUTTER);
|
||||
ExecuteCommandPower(Settings.shutter_startrelay[index], 0, SRC_SHUTTER);
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay5 5s, xdrv %d"), XdrvMailbox.payload);
|
||||
ShutterDelayForMotorStop();
|
||||
// Code for shutters with circuit safe configuration, switch the direction Relay
|
||||
ExecuteCommandPower(Settings.shutter_startrelay[index] +1, new_shutterdirection == 1 ? 0 : 1, SRC_SHUTTER);
|
||||
// power on
|
||||
ExecuteCommandPower(Settings.shutter_startrelay[index] , 1, SRC_SHUTTER);
|
||||
ExecuteCommandPower(Settings.shutter_startrelay[index], 1, SRC_SHUTTER);
|
||||
} else {
|
||||
// now start the motor for the right direction, work for momentary and normal shutters.
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start shutter in direction %d"), Shutter.direction[index]);
|
||||
|
@ -453,7 +453,8 @@ void CmndShutterPosition(void)
|
|||
} else {
|
||||
target_pos_percent = ShutterRealToPercentPosition(Shutter.real_position[index], index);
|
||||
}
|
||||
ResponseCmndIdxNumber(Settings.shutter_invert[index] ? 100 - target_pos_percent : target_pos_percent);
|
||||
XdrvMailbox.index = index +1; // Fix random index for ShutterClose
|
||||
ResponseCmndIdxNumber(Settings.shutter_invert[index] ? 100 - target_pos_percent : target_pos_percent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,11 +462,11 @@ void CmndShutterOpenTime(void)
|
|||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Settings.shutter_opentime[XdrvMailbox.index-1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data));
|
||||
Settings.shutter_opentime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data));
|
||||
ShutterInit();
|
||||
}
|
||||
char time_chr[10];
|
||||
dtostrfd((float)(Settings.shutter_opentime[XdrvMailbox.index-1]) / 10, 1, time_chr);
|
||||
dtostrfd((float)(Settings.shutter_opentime[XdrvMailbox.index -1]) / 10, 1, time_chr);
|
||||
ResponseCmndIdxChar(time_chr);
|
||||
}
|
||||
}
|
||||
|
@ -474,11 +475,11 @@ void CmndShutterCloseTime(void)
|
|||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Settings.shutter_closetime[XdrvMailbox.index-1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data));
|
||||
Settings.shutter_closetime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data));
|
||||
ShutterInit();
|
||||
}
|
||||
char time_chr[10];
|
||||
dtostrfd((float)(Settings.shutter_closetime[XdrvMailbox.index-1]) / 10, 1, time_chr);
|
||||
dtostrfd((float)(Settings.shutter_closetime[XdrvMailbox.index -1]) / 10, 1, time_chr);
|
||||
ResponseCmndIdxChar(time_chr);
|
||||
}
|
||||
}
|
||||
|
@ -487,14 +488,14 @@ void CmndShutterRelay(void)
|
|||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SHUTTERS)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 64)) {
|
||||
Settings.shutter_startrelay[XdrvMailbox.index-1] = XdrvMailbox.payload;
|
||||
Settings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
if (XdrvMailbox.payload > 0) {
|
||||
Shutter.mask |= 3 << (XdrvMailbox.payload - 1);
|
||||
} else {
|
||||
Shutter.mask ^= 3 << (Settings.shutter_startrelay[XdrvMailbox.index-1] - 1);
|
||||
Shutter.mask ^= 3 << (Settings.shutter_startrelay[XdrvMailbox.index -1] - 1);
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Relay %d is %d"), XdrvMailbox.index, XdrvMailbox.payload);
|
||||
Settings.shutter_startrelay[XdrvMailbox.index-1] = XdrvMailbox.payload;
|
||||
Settings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
ShutterInit();
|
||||
// if payload is 0 to disable the relay there must be a reboot. Otherwhise does not work
|
||||
}
|
||||
|
@ -506,11 +507,11 @@ void CmndShutterSetHalfway(void)
|
|||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
|
||||
Settings.shutter_set50percent[XdrvMailbox.index-1] = Settings.shutter_invert[XdrvMailbox.index-1] ? 100 - XdrvMailbox.payload : XdrvMailbox.payload;
|
||||
Settings.shutter_set50percent[XdrvMailbox.index -1] = Settings.shutter_invert[XdrvMailbox.index -1] ? 100 - XdrvMailbox.payload : XdrvMailbox.payload;
|
||||
ShutterInit();
|
||||
ResponseCmndIdxNumber(XdrvMailbox.payload); // ????
|
||||
} else {
|
||||
ResponseCmndIdxNumber(Settings.shutter_set50percent[XdrvMailbox.index-1]);
|
||||
ResponseCmndIdxNumber(Settings.shutter_set50percent[XdrvMailbox.index -1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -518,9 +519,9 @@ void CmndShutterSetHalfway(void)
|
|||
void CmndShutterSetClose(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
|
||||
Shutter.real_position[XdrvMailbox.index-1] = 0;
|
||||
ShutterStartInit(XdrvMailbox.index-1, 0, 0);
|
||||
Settings.shutter_position[XdrvMailbox.index-1] = 0;
|
||||
Shutter.real_position[XdrvMailbox.index -1] = 0;
|
||||
ShutterStartInit(XdrvMailbox.index -1, 0, 0);
|
||||
Settings.shutter_position[XdrvMailbox.index -1] = 0;
|
||||
ResponseCmndChar(D_CONFIGURATION_RESET);
|
||||
}
|
||||
}
|
||||
|
@ -529,9 +530,9 @@ void CmndShutterInvert(void)
|
|||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
|
||||
Settings.shutter_invert[XdrvMailbox.index-1] = XdrvMailbox.payload;
|
||||
Settings.shutter_invert[XdrvMailbox.index -1] = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndIdxNumber(Settings.shutter_invert[XdrvMailbox.index-1]);
|
||||
ResponseCmndIdxNumber(Settings.shutter_invert[XdrvMailbox.index -1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
xdrv_28_pcf8574.ino - PCF8574 I2C support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Stefan Bode
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_PCF8574
|
||||
/*********************************************************************************************\
|
||||
* PCF8574 - I2C IO Expander
|
||||
*
|
||||
* I2C Address: PCF8574 = 0x20 .. 0x27, PCF8574A = 0x38 .. 0x3F
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_28 28
|
||||
|
||||
#define PCF8574_ADDR1 0x20 // PCF8574
|
||||
#define PCF8574_ADDR2 0x38 // PCF8574A
|
||||
|
||||
struct PCF8574 {
|
||||
int error;
|
||||
uint8_t pin[64];
|
||||
uint8_t address[MAX_PCF8574];
|
||||
uint8_t pin_mask[MAX_PCF8574] = { 0 };
|
||||
uint8_t max_connected_ports = 0; // Max numbers of devices comming from PCF8574 modules
|
||||
uint8_t max_devices = 0; // Max numbers of PCF8574 modules
|
||||
char stype[8];
|
||||
bool type = true;
|
||||
} Pcf8574;
|
||||
|
||||
void Pcf8574SwitchRelay(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < devices_present; i++) {
|
||||
uint8_t relay_state = bitRead(XdrvMailbox.index, i);
|
||||
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PCF: Pcf8574.max_devices %d requested pin %d"), Pcf8574.max_devices,Pcf8574.pin[i]);
|
||||
|
||||
if (Pcf8574.max_devices > 0 && Pcf8574.pin[i] < 99) {
|
||||
uint8_t board = Pcf8574.pin[i]>>3;
|
||||
uint8_t oldpinmask = Pcf8574.pin_mask[board];
|
||||
uint8_t _val = bitRead(rel_inverted, i) ? !relay_state : relay_state;
|
||||
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PCF: Pcf8574SwitchRelay %d on pin %d"), i,state);
|
||||
|
||||
if (_val) {
|
||||
Pcf8574.pin_mask[board] |= _val << (Pcf8574.pin[i]&0x7);
|
||||
} else {
|
||||
Pcf8574.pin_mask[board] &= ~(1 << (Pcf8574.pin[i]&0x7));
|
||||
}
|
||||
if (oldpinmask != Pcf8574.pin_mask[board]) {
|
||||
Wire.beginTransmission(Pcf8574.address[board]);
|
||||
Wire.write(Pcf8574.pin_mask[board]);
|
||||
Pcf8574.error = Wire.endTransmission();
|
||||
}
|
||||
//pcf8574.write(Pcf8574.pin[i]&0x7, rel_inverted[i] ? !state : state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pcf8574Init()
|
||||
{
|
||||
Pcf8574.type = false;
|
||||
|
||||
uint8_t pcf8574_address = PCF8574_ADDR1;
|
||||
for (uint32_t i = 0; i < MAX_PCF8574; i++) {
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PCF: Probing addr: 0x%x for PCF8574"), pcf8574_address);
|
||||
|
||||
if (I2cDevice(pcf8574_address)) {
|
||||
I2cSetActive(pcf8574_address);
|
||||
Pcf8574.type = true;
|
||||
|
||||
Pcf8574.address[Pcf8574.max_devices] = pcf8574_address;
|
||||
Pcf8574.max_devices++;
|
||||
|
||||
strcpy(Pcf8574.stype, "PCF8574");
|
||||
if (pcf8574_address >= PCF8574_ADDR2) {
|
||||
strcpy(Pcf8574.stype, "PCF8574A");
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, Pcf8574.stype, pcf8574_address);
|
||||
}
|
||||
pcf8574_address++;
|
||||
if ((PCF8574_ADDR1 + 8) == pcf8574_address) {
|
||||
pcf8574_address = PCF8574_ADDR2;
|
||||
}
|
||||
}
|
||||
if (Pcf8574.max_devices) {
|
||||
for (uint32_t i = 0; i < sizeof(Pcf8574.pin); i++) {
|
||||
Pcf8574.pin[i] = 99;
|
||||
}
|
||||
devices_present = devices_present - Pcf8574.max_connected_ports; // reset no of devices to avoid duplicate ports on duplicate init.
|
||||
Pcf8574.max_connected_ports = 0; // reset no of devices to avoid duplicate ports on duplicate init.
|
||||
for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { // suport up to 8 boards PCF8574
|
||||
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PCF: Device %d config 0x%02x"), idx +1, Settings.pcf8574_config[idx]);
|
||||
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
uint8_t _result = Settings.pcf8574_config[idx] >> i &1;
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("PCF: I2C shift i %d: %d. Powerstate: %d, devices_present: %d"), i,_result, Settings.power>>i&1, devices_present);
|
||||
if (_result > 0) {
|
||||
Pcf8574.pin[devices_present] = i + 8 * idx;
|
||||
bitWrite(rel_inverted, devices_present, Settings.flag3.pcf8574_ports_inverted);
|
||||
devices_present++;
|
||||
Pcf8574.max_connected_ports++;
|
||||
}
|
||||
}
|
||||
}
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("PCF: Total devices %d, PCF8574 output ports %d"), devices_present, Pcf8574.max_connected_ports);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Presentation
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
|
||||
#define WEB_HANDLE_PCF8574 "pcf"
|
||||
|
||||
const char HTTP_BTN_MENU_PCF8574[] PROGMEM =
|
||||
"<p><form action='" WEB_HANDLE_PCF8574 "' method='get'><button>" D_CONFIGURE_PCF8574 "</button></form></p>";
|
||||
|
||||
const char HTTP_FORM_I2C_PCF8574_1[] PROGMEM =
|
||||
"<fieldset><legend><b> " D_PCF8574_PARAMETERS " </b></legend>"
|
||||
"<form method='get' action='" WEB_HANDLE_PCF8574 "'>"
|
||||
"<p><input id='b1' name='b1' type='checkbox'%s><b>" D_INVERT_PORTS "</b></p><hr/>";
|
||||
|
||||
const char HTTP_FORM_I2C_PCF8574_2[] PROGMEM =
|
||||
"<tr><td><b>" D_DEVICE " %d " D_PORT " %d</b></td><td style='width:100px'><select id='i2cs%d' name='i2cs%d'>"
|
||||
"<option%s value='0'>" D_DEVICE_INPUT "</option>"
|
||||
"<option%s value='1'>" D_DEVICE_OUTPUT "</option>"
|
||||
"</select></td></tr>";
|
||||
|
||||
void HandlePcf8574(void)
|
||||
{
|
||||
if (!HttpCheckPriviledgedAccess()) { return; }
|
||||
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_PCF8574));
|
||||
|
||||
if (WebServer->hasArg("save")) {
|
||||
Pcf8574SaveSettings();
|
||||
WebRestart(1);
|
||||
return;
|
||||
}
|
||||
|
||||
WSContentStart_P(D_CONFIGURE_PCF8574);
|
||||
WSContentSendStyle();
|
||||
WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings.flag3.pcf8574_ports_inverted) ? " checked" : "");
|
||||
WSContentSend_P(HTTP_TABLE100);
|
||||
for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) {
|
||||
for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574
|
||||
uint8_t helper = 1 << idx2;
|
||||
WSContentSend_P(HTTP_FORM_I2C_PCF8574_2,
|
||||
idx +1, idx2,
|
||||
idx2 + 8*idx,
|
||||
idx2 + 8*idx,
|
||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 0) ? " selected " : " ",
|
||||
((helper & Settings.pcf8574_config[idx]) >> idx2 == 1) ? " selected " : " "
|
||||
);
|
||||
}
|
||||
}
|
||||
WSContentSend_P(PSTR("</table>"));
|
||||
WSContentSend_P(HTTP_FORM_END);
|
||||
WSContentSpaceButton(BUTTON_CONFIGURATION);
|
||||
WSContentStop();
|
||||
}
|
||||
|
||||
void Pcf8574SaveSettings()
|
||||
{
|
||||
char stemp[7];
|
||||
char tmp[100];
|
||||
|
||||
//AddLog_P(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), WebServer->hasArg("b1");
|
||||
|
||||
Settings.flag3.pcf8574_ports_inverted = WebServer->hasArg("b1");
|
||||
for (byte idx = 0; idx < Pcf8574.max_devices; idx++) {
|
||||
byte count=0;
|
||||
byte n = Settings.pcf8574_config[idx];
|
||||
while(n!=0) {
|
||||
n = n&(n-1);
|
||||
count++;
|
||||
}
|
||||
if (count <= devices_present) {
|
||||
devices_present = devices_present - count;
|
||||
}
|
||||
for (byte i = 0; i < 8; i++) {
|
||||
snprintf_P(stemp, sizeof(stemp), PSTR("i2cs%d"), i+8*idx);
|
||||
WebGetArg(stemp, tmp, sizeof(tmp));
|
||||
byte _value = (!strlen(tmp)) ? 0 : atoi(tmp);
|
||||
if (_value) {
|
||||
Settings.pcf8574_config[idx] = Settings.pcf8574_config[idx] | 1 << i;
|
||||
devices_present++;
|
||||
Pcf8574.max_connected_ports++;
|
||||
} else {
|
||||
Settings.pcf8574_config[idx] = Settings.pcf8574_config[idx] & ~(1 << i );
|
||||
}
|
||||
}
|
||||
//Settings.pcf8574_config[0] = (!strlen(webServer->arg("i2cs0").c_str())) ? 0 : atoi(webServer->arg("i2cs0").c_str());
|
||||
//AddLog_P2(LOG_LEVEL_INFO, PSTR("PCF: I2C Board: %d, Config: %2x")), idx, Settings.pcf8574_config[idx];
|
||||
|
||||
}
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv28(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (i2c_flg && Pcf8574.type) {
|
||||
switch (function) {
|
||||
case FUNC_SET_POWER:
|
||||
Pcf8574SwitchRelay();
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_ADD_BUTTON:
|
||||
WSContentSend_P(HTTP_BTN_MENU_PCF8574);
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
WebServer->on("/" WEB_HANDLE_PCF8574, HandlePcf8574);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
case FUNC_PRE_INIT:
|
||||
Pcf8574Init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_PCF8574
|
||||
#endif // USE_I2C
|
|
@ -57,6 +57,10 @@
|
|||
#define D_CMND_HELP "Help"
|
||||
#define D_CMND_RTCDUMP "RtcDump"
|
||||
#define D_CMND_SETSENSOR "SetSensor"
|
||||
#define D_CMND_I2CWRITE "I2CWrite"
|
||||
#define D_CMND_I2CREAD "I2CRead"
|
||||
#define D_CMND_I2CSTRETCH "I2CStretch"
|
||||
#define D_CMND_I2CCLOCK "I2CClock"
|
||||
|
||||
const char kDebugCommands[] PROGMEM = "|" // No prefix
|
||||
D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|"
|
||||
|
@ -70,7 +74,8 @@ const char kDebugCommands[] PROGMEM = "|" // No prefix
|
|||
#ifdef DEBUG_THEO
|
||||
D_CMND_EXCEPTION "|"
|
||||
#endif
|
||||
D_CMND_FLASHDUMP "|" D_CMND_FLASHMODE "|" D_CMND_FREEMEM"|" D_CMND_HELP "|" D_CMND_RTCDUMP "|" D_CMND_SETSENSOR ;
|
||||
D_CMND_FLASHDUMP "|" D_CMND_FLASHMODE "|" D_CMND_FREEMEM"|" D_CMND_HELP "|" D_CMND_RTCDUMP "|" D_CMND_SETSENSOR "|"
|
||||
D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK ;
|
||||
|
||||
void (* const DebugCommand[])(void) PROGMEM = {
|
||||
&CmndCfgDump, &CmndCfgPeek, &CmndCfgPoke,
|
||||
|
@ -84,7 +89,8 @@ void (* const DebugCommand[])(void) PROGMEM = {
|
|||
#ifdef DEBUG_THEO
|
||||
&CmndException,
|
||||
#endif
|
||||
&CmndFlashDump, &CmndFlashMode, &CmndFreemem, &CmndHelp, &CmndRtcDump, &CmndSetSensor };
|
||||
&CmndFlashDump, &CmndFlashMode, &CmndFreemem, &CmndHelp, &CmndRtcDump, &CmndSetSensor,
|
||||
&CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock };
|
||||
|
||||
uint32_t CPU_loops = 0;
|
||||
uint32_t CPU_last_millis = 0;
|
||||
|
@ -569,6 +575,84 @@ void CmndFlashDump(void)
|
|||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void CmndI2cWrite(void)
|
||||
{
|
||||
// I2cWrite <address>,<data>..
|
||||
if (i2c_flg) {
|
||||
char* parms = XdrvMailbox.data;
|
||||
uint8_t buffer[100];
|
||||
uint32_t index = 0;
|
||||
|
||||
char *p;
|
||||
char *data = strtok_r(parms, " ,", &p);
|
||||
while (data != NULL && index < sizeof(buffer)) {
|
||||
buffer[index++] = strtol(data, nullptr, 16);
|
||||
data = strtok_r(nullptr, " ,", &p);
|
||||
}
|
||||
|
||||
if (index > 1) {
|
||||
AddLogBuffer(LOG_LEVEL_INFO, buffer, index);
|
||||
|
||||
Wire.beginTransmission(buffer[0]);
|
||||
for (uint32_t i = 1; i < index; i++) {
|
||||
Wire.write(buffer[i]);
|
||||
}
|
||||
int result = Wire.endTransmission();
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("I2C: Result %d"), result);
|
||||
}
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void CmndI2cRead(void)
|
||||
{
|
||||
// I2cRead <address>,<size>
|
||||
if (i2c_flg) {
|
||||
char* parms = XdrvMailbox.data;
|
||||
uint8_t buffer[100];
|
||||
uint32_t index = 0;
|
||||
|
||||
char *p;
|
||||
char *data = strtok_r(parms, " ,", &p);
|
||||
while (data != NULL && index < sizeof(buffer)) {
|
||||
buffer[index++] = strtol(data, nullptr, 16);
|
||||
data = strtok_r(nullptr, " ,", &p);
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
uint8_t size = 1;
|
||||
if (index > 1) {
|
||||
size = buffer[1];
|
||||
}
|
||||
Wire.requestFrom(buffer[0], size);
|
||||
index = 0;
|
||||
while (Wire.available() && index < sizeof(buffer)) {
|
||||
buffer[index++] = Wire.read();
|
||||
}
|
||||
if (index > 0) {
|
||||
AddLogBuffer(LOG_LEVEL_INFO, buffer, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void CmndI2cStretch(void)
|
||||
{
|
||||
if (i2c_flg && (XdrvMailbox.payload > 0)) {
|
||||
Wire.setClockStretchLimit(XdrvMailbox.payload);
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void CmndI2cClock(void)
|
||||
{
|
||||
if (i2c_flg && (XdrvMailbox.payload > 0)) {
|
||||
Wire.setClock(XdrvMailbox.payload);
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
|
|
@ -847,16 +847,6 @@ void XsnsDriverState(void)
|
|||
|
||||
/*********************************************************************************************/
|
||||
|
||||
bool XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf)
|
||||
{
|
||||
XdrvMailbox.index = stopicBuf;
|
||||
XdrvMailbox.data_len = sdataBuf;
|
||||
XdrvMailbox.topic = topicBuf;
|
||||
XdrvMailbox.data = dataBuf;
|
||||
|
||||
return XdrvCall(FUNC_MQTT_DATA);
|
||||
}
|
||||
|
||||
bool XdrvRulesProcess(void)
|
||||
{
|
||||
return XdrvCallDriver(10, FUNC_RULES_PROCESS);
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
xlgt_02_my92x1.ino - led support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
#ifdef USE_MY92X1
|
||||
/*********************************************************************************************\
|
||||
* Sonoff B1 and AiLight inspired by OpenLight https://github.com/icamgo/noduino-sdk
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XLGT_02 2
|
||||
|
||||
struct MY92X1 {
|
||||
uint8_t pdi_pin;
|
||||
uint8_t pdcki_pin;
|
||||
} My92x1;
|
||||
|
||||
extern "C" {
|
||||
void os_delay_us(unsigned int);
|
||||
}
|
||||
|
||||
void LightDiPulse(uint8_t times)
|
||||
{
|
||||
for (uint32_t i = 0; i < times; i++) {
|
||||
digitalWrite(My92x1.pdi_pin, HIGH);
|
||||
digitalWrite(My92x1.pdi_pin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void LightDckiPulse(uint8_t times)
|
||||
{
|
||||
for (uint32_t i = 0; i < times; i++) {
|
||||
digitalWrite(My92x1.pdcki_pin, HIGH);
|
||||
digitalWrite(My92x1.pdcki_pin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void LightMy92x1Write(uint8_t data)
|
||||
{
|
||||
for (uint32_t i = 0; i < 4; i++) { // Send 8bit Data
|
||||
digitalWrite(My92x1.pdcki_pin, LOW);
|
||||
digitalWrite(My92x1.pdi_pin, (data & 0x80));
|
||||
digitalWrite(My92x1.pdcki_pin, HIGH);
|
||||
data = data << 1;
|
||||
digitalWrite(My92x1.pdi_pin, (data & 0x80));
|
||||
digitalWrite(My92x1.pdcki_pin, LOW);
|
||||
digitalWrite(My92x1.pdi_pin, LOW);
|
||||
data = data << 1;
|
||||
}
|
||||
}
|
||||
|
||||
void LightMy92x1Init(void)
|
||||
{
|
||||
uint8_t chips = 1; // 1 (AiLight)
|
||||
if (LT_RGBWC == light_type) {
|
||||
chips = 2; // 2 (Sonoff B1)
|
||||
}
|
||||
|
||||
LightDckiPulse(chips * 32); // Clear all duty register
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
// Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12
|
||||
// pulse's rising edge convert to command mode.
|
||||
LightDiPulse(12);
|
||||
os_delay_us(12); // Delay >12us, begin send CMD data
|
||||
for (uint32_t n = 0; n < chips; n++) { // Send CMD data
|
||||
LightMy92x1Write(0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM
|
||||
}
|
||||
os_delay_us(12); // TStart > 12us. Delay 12 us.
|
||||
// Send 16 DI pulse, at 14 pulse's falling edge store CMD data, and
|
||||
// at 16 pulse's falling edge convert to duty mode.
|
||||
LightDiPulse(16);
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
}
|
||||
|
||||
void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c)
|
||||
{
|
||||
uint8_t channels[2] = { 4, 6 };
|
||||
|
||||
uint8_t didx = 0; // 0 (AiLight)
|
||||
if (LT_RGBWC == light_type) {
|
||||
didx = 1; // 1 (Sonoff B1)
|
||||
}
|
||||
|
||||
uint8_t duty[2][6] = {{ duty_r, duty_g, duty_b, duty_w, duty_w, duty_w }, // Definition for RGBW(WW) channels
|
||||
{ duty_w, duty_c, 0, duty_g, duty_r, duty_b }}; // Definition for RGBWC channels
|
||||
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
for (uint32_t channel = 0; channel < channels[didx]; channel++) {
|
||||
LightMy92x1Write(duty[didx][channel]); // Send 8bit Data
|
||||
}
|
||||
os_delay_us(12); // TStart > 12us. Ready for send DI pulse.
|
||||
LightDiPulse(8); // Send 8 DI pulse. After 8 pulse falling edge, store old data.
|
||||
os_delay_us(12); // TStop > 12us.
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
bool My92x1SetChannels(void)
|
||||
{
|
||||
uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
|
||||
|
||||
LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void My92x1ModuleSelected(void)
|
||||
{
|
||||
if ((pin[GPIO_DCKI] < 99) && (pin[GPIO_DI] < 99)) {
|
||||
My92x1.pdi_pin = pin[GPIO_DI];
|
||||
My92x1.pdcki_pin = pin[GPIO_DCKI];
|
||||
|
||||
pinMode(My92x1.pdi_pin, OUTPUT);
|
||||
pinMode(My92x1.pdcki_pin, OUTPUT);
|
||||
digitalWrite(My92x1.pdi_pin, LOW);
|
||||
digitalWrite(My92x1.pdcki_pin, LOW);
|
||||
|
||||
LightMy92x1Init();
|
||||
|
||||
if (AILIGHT == my_module_type) { // RGBW(WW) led
|
||||
light_type = LT_RGBW;
|
||||
}
|
||||
else if (SONOFF_B1 == my_module_type) { // RGBWC led
|
||||
light_type = LT_RGBWC;
|
||||
}
|
||||
light_flg = XLGT_02;
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: MY29x1 Found"));
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xlgt02(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_SET_CHANNELS:
|
||||
result = My92x1SetChannels();
|
||||
break;
|
||||
case FUNC_MODULE_INIT:
|
||||
My92x1ModuleSelected();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_MY92X1
|
||||
#endif // USE_LIGHT
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
xlgt_03_sm16716.ino - sm16716 three channel led support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
#ifdef USE_SM16716
|
||||
/*********************************************************************************************\
|
||||
* SM16716 - Controlling RGB over a synchronous serial line
|
||||
* Copyright (C) 2019 Gabor Simon
|
||||
*
|
||||
* Source: https://community.home-assistant.io/t/cheap-uk-wifi-bulbs-with-tasmota-teardown-help-tywe3s/40508/27
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XLGT_03 3
|
||||
|
||||
#define D_LOG_SM16716 "SM16716: "
|
||||
|
||||
struct SM16716 {
|
||||
uint8_t pin_clk = 0;
|
||||
uint8_t pin_dat = 0;
|
||||
uint8_t pin_sel = 0;
|
||||
bool enabled = false;
|
||||
} Sm16716;
|
||||
|
||||
void SM16716_SendBit(uint8_t v)
|
||||
{
|
||||
/* NOTE:
|
||||
* According to the spec sheet, max freq is 30 MHz, that is 16.6 ns per high/low half of the
|
||||
* clk square wave. That is less than the overhead of 'digitalWrite' at this clock rate,
|
||||
* so no additional delays are needed yet. */
|
||||
|
||||
digitalWrite(Sm16716.pin_dat, (v != 0) ? HIGH : LOW);
|
||||
//delayMicroseconds(1);
|
||||
digitalWrite(Sm16716.pin_clk, HIGH);
|
||||
//delayMicroseconds(1);
|
||||
digitalWrite(Sm16716.pin_clk, LOW);
|
||||
}
|
||||
|
||||
void SM16716_SendByte(uint8_t v)
|
||||
{
|
||||
uint8_t mask;
|
||||
|
||||
for (mask = 0x80; mask; mask >>= 1) {
|
||||
SM16716_SendBit(v & mask);
|
||||
}
|
||||
}
|
||||
|
||||
void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b)
|
||||
{
|
||||
if (Sm16716.pin_sel < 99) {
|
||||
bool should_enable = (duty_r | duty_g | duty_b);
|
||||
if (!Sm16716.enabled && should_enable) {
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color on"));
|
||||
Sm16716.enabled = true;
|
||||
digitalWrite(Sm16716.pin_sel, HIGH);
|
||||
// in testing I found it takes a minimum of ~380us to wake up the chip
|
||||
// tested on a Merkury RGBW with an SM726EB
|
||||
delayMicroseconds(1000);
|
||||
SM16716_Init();
|
||||
}
|
||||
else if (Sm16716.enabled && !should_enable) {
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color off"));
|
||||
Sm16716.enabled = false;
|
||||
digitalWrite(Sm16716.pin_sel, LOW);
|
||||
}
|
||||
}
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "Update; rgb=%02x%02x%02x"), duty_r, duty_g, duty_b);
|
||||
|
||||
// send start bit
|
||||
SM16716_SendBit(1);
|
||||
SM16716_SendByte(duty_r);
|
||||
SM16716_SendByte(duty_g);
|
||||
SM16716_SendByte(duty_b);
|
||||
|
||||
// send a 'do it' pulse
|
||||
// (if multiple chips are chained, each one processes the 1st '1rgb' 25-bit block and
|
||||
// passes on the rest, right until the one starting with 0)
|
||||
//SM16716_Init();
|
||||
SM16716_SendBit(0);
|
||||
SM16716_SendByte(0);
|
||||
SM16716_SendByte(0);
|
||||
SM16716_SendByte(0);
|
||||
}
|
||||
|
||||
/*
|
||||
bool SM16716_ModuleSelected(void)
|
||||
{
|
||||
Sm16716.pin_clk = pin[GPIO_SM16716_CLK];
|
||||
Sm16716.pin_dat = pin[GPIO_SM16716_DAT];
|
||||
Sm16716.pin_sel = pin[GPIO_SM16716_SEL];
|
||||
DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "ModuleSelected; clk_pin=%d, dat_pin=%d)"), Sm16716.pin_clk, Sm16716.pin_dat);
|
||||
return (Sm16716.pin_clk < 99) && (Sm16716.pin_dat < 99);
|
||||
}
|
||||
*/
|
||||
|
||||
void SM16716_Init(void)
|
||||
{
|
||||
for (uint32_t t_init = 0; t_init < 50; ++t_init) {
|
||||
SM16716_SendBit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
bool Sm16716SetChannels(void)
|
||||
{
|
||||
/*
|
||||
// handle any PWM pins, skipping the first 3 values for sm16716
|
||||
for (uint32_t i = 3; i < Light.subtype; i++) {
|
||||
if (pin[GPIO_PWM1 +i-3] < 99) {
|
||||
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d, Pwm%d %d"), i, cur_col[i], i+1, curcol);
|
||||
analogWrite(pin[GPIO_PWM1 +i-3], bitRead(pwm_inverted, i-3) ? Settings.pwm_range - cur_col_10bits[i] : cur_col_10bits[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
// handle sm16716 update
|
||||
uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
|
||||
|
||||
SM16716_Update(cur_col[0], cur_col[1], cur_col[2]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sm16716ModuleSelected(void)
|
||||
{
|
||||
if ((pin[GPIO_SM16716_CLK] < 99) && (pin[GPIO_SM16716_DAT] < 99)) {
|
||||
Sm16716.pin_clk = pin[GPIO_SM16716_CLK];
|
||||
Sm16716.pin_dat = pin[GPIO_SM16716_DAT];
|
||||
Sm16716.pin_sel = pin[GPIO_SM16716_SEL];
|
||||
|
||||
/*
|
||||
// init PWM
|
||||
for (uint32_t i = 0; i < Light.subtype; i++) {
|
||||
Settings.pwm_value[i] = 0; // Disable direct PWM control
|
||||
if (pin[GPIO_PWM1 +i] < 99) {
|
||||
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// init sm16716
|
||||
pinMode(Sm16716.pin_clk, OUTPUT);
|
||||
digitalWrite(Sm16716.pin_clk, LOW);
|
||||
|
||||
pinMode(Sm16716.pin_dat, OUTPUT);
|
||||
digitalWrite(Sm16716.pin_dat, LOW);
|
||||
|
||||
if (Sm16716.pin_sel < 99) {
|
||||
pinMode(Sm16716.pin_sel, OUTPUT);
|
||||
digitalWrite(Sm16716.pin_sel, LOW);
|
||||
// no need to call SM16716_Init here, it will be called after sel goes HIGH
|
||||
} else {
|
||||
// no sel pin means you have an 'always on' chip, so init right away
|
||||
SM16716_Init();
|
||||
}
|
||||
|
||||
LightPwmOffset(LST_RGB); // Handle any PWM pins, skipping the first 3 color values for sm16716
|
||||
light_type += LST_RGB; // Add RGB to be controlled by sm16716
|
||||
light_flg = XLGT_03;
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM16716 Found"));
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xlgt03(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_SET_CHANNELS:
|
||||
result = Sm16716SetChannels();
|
||||
break;
|
||||
case FUNC_MODULE_INIT:
|
||||
Sm16716ModuleSelected();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_SM16716
|
||||
#endif // USE_LIGHT
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
xlgt_04_sm2135.ino - sm2135 five channel led support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
#ifdef USE_SM2135
|
||||
/*********************************************************************************************\
|
||||
* SM2135 RGBCW Led bulbs like some Action LSC SmartLed
|
||||
*
|
||||
* {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18}
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XLGT_04 4
|
||||
|
||||
#define SM2135_ADDR_MC 0xC0 // Max current register
|
||||
#define SM2135_ADDR_CH 0xC1 // RGB or CW channel select register
|
||||
#define SM2135_ADDR_R 0xC2 // Red color
|
||||
#define SM2135_ADDR_G 0xC3 // Green color
|
||||
#define SM2135_ADDR_B 0xC4 // Blue color
|
||||
#define SM2135_ADDR_C 0xC5 // Cold
|
||||
#define SM2135_ADDR_W 0xC6 // Warm
|
||||
|
||||
#define SM2135_RGB 0x00 // RGB channel
|
||||
#define SM2135_CW 0x80 // CW channel (Chip default)
|
||||
|
||||
#define SM2135_10MA 0x00
|
||||
#define SM2135_15MA 0x01
|
||||
#define SM2135_20MA 0x02 // RGB max current (Chip default)
|
||||
#define SM2135_25MA 0x03
|
||||
#define SM2135_30MA 0x04 // CW max current (Chip default)
|
||||
#define SM2135_35MA 0x05
|
||||
#define SM2135_40MA 0x06
|
||||
#define SM2135_45MA 0x07 // Max value for RGB
|
||||
#define SM2135_50MA 0x08
|
||||
#define SM2135_55MA 0x09
|
||||
#define SM2135_60MA 0x0A
|
||||
|
||||
// RGB current CW current
|
||||
const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_10MA;
|
||||
|
||||
struct SM2135 {
|
||||
uint8_t clk = 0;
|
||||
uint8_t data = 0;
|
||||
} Sm2135;
|
||||
|
||||
uint8_t Sm2135Write(uint8_t data)
|
||||
{
|
||||
for (uint32_t i = 0; i < 8; i++) {
|
||||
digitalWrite(Sm2135.clk, LOW);
|
||||
digitalWrite(Sm2135.data, (data & 0x80));
|
||||
digitalWrite(Sm2135.clk, HIGH);
|
||||
data = data << 1;
|
||||
}
|
||||
digitalWrite(Sm2135.clk, LOW);
|
||||
digitalWrite(Sm2135.data, HIGH);
|
||||
pinMode(Sm2135.data, INPUT);
|
||||
digitalWrite(Sm2135.clk, HIGH);
|
||||
uint8_t ack = digitalRead(Sm2135.data);
|
||||
pinMode(Sm2135.data, OUTPUT);
|
||||
return ack;
|
||||
}
|
||||
|
||||
void Sm2135Send(uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
digitalWrite(Sm2135.data, LOW);
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
Sm2135Write(buffer[i]);
|
||||
}
|
||||
digitalWrite(Sm2135.clk, LOW);
|
||||
digitalWrite(Sm2135.clk, HIGH);
|
||||
digitalWrite(Sm2135.data, HIGH);
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
bool Sm2135SetChannels(void)
|
||||
{
|
||||
uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
|
||||
uint8_t data[6];
|
||||
|
||||
if ((0 == cur_col[0]) && (0 == cur_col[1]) && (0 == cur_col[2])) {
|
||||
// No color so must be Cold/Warm
|
||||
/*
|
||||
if ((cur_col[3] + cur_col[4]) >= (1 * 256)) {
|
||||
// Scale down to 255 total to fix max power usage of 9W (=40mA)
|
||||
|
||||
// cur_col[3] >>= 1; // Divide by 2
|
||||
// cur_col[4] >>= 1; // Divide by 2
|
||||
}
|
||||
*/
|
||||
data[0] = SM2135_ADDR_MC;
|
||||
data[1] = SM2135_CURRENT;
|
||||
data[2] = SM2135_CW;
|
||||
Sm2135Send(data, 3);
|
||||
delay(1);
|
||||
data[0] = SM2135_ADDR_C;
|
||||
data[1] = cur_col[4]; // Warm
|
||||
data[2] = cur_col[3]; // Cold
|
||||
Sm2135Send(data, 3);
|
||||
} else {
|
||||
// Color
|
||||
/*
|
||||
if ((cur_col[0] + cur_col[1] + cur_col[2]) >= (3 * 256)) {
|
||||
// Scale down to 765 total to fix max power usage of 9W
|
||||
// Currently not needed with setting 3 x 15mA = 45mA = 11W = 765
|
||||
}
|
||||
*/
|
||||
data[0] = SM2135_ADDR_MC;
|
||||
data[1] = SM2135_CURRENT;
|
||||
data[2] = SM2135_RGB;
|
||||
data[3] = cur_col[1]; // Green
|
||||
data[4] = cur_col[0]; // Red
|
||||
data[5] = cur_col[2]; // Blue
|
||||
Sm2135Send(data, 6);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sm2135ModuleSelected(void)
|
||||
{
|
||||
if ((pin[GPIO_SM2135_CLK] < 99) && (pin[GPIO_SM2135_DAT] < 99)) {
|
||||
Sm2135.clk = pin[GPIO_SM2135_CLK];
|
||||
Sm2135.data = pin[GPIO_SM2135_DAT];
|
||||
|
||||
pinMode(Sm2135.data, OUTPUT);
|
||||
digitalWrite(Sm2135.data, HIGH);
|
||||
pinMode(Sm2135.clk, OUTPUT);
|
||||
digitalWrite(Sm2135.clk, HIGH);
|
||||
|
||||
light_type = LT_RGBWC;
|
||||
light_flg = XLGT_04;
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM2135 Found"));
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xlgt04(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_SET_CHANNELS:
|
||||
result = Sm2135SetChannels();
|
||||
break;
|
||||
case FUNC_MODULE_INIT:
|
||||
Sm2135ModuleSelected();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_SM2135
|
||||
#endif // USE_LIGHT
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
xlgt_interface.ino - Light driver interface support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_LIGHT
|
||||
|
||||
#ifdef XFUNC_PTR_IN_ROM
|
||||
bool (* const xlgt_func_ptr[])(uint8_t) PROGMEM = { // Light driver Function Pointers
|
||||
#else
|
||||
bool (* const xlgt_func_ptr[])(uint8_t) = { // Light driver Function Pointers
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_01
|
||||
&Xlgt01,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_02
|
||||
&Xlgt02,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_03
|
||||
&Xlgt03,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_04
|
||||
&Xlgt04,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_05
|
||||
&Xlgt05,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_06
|
||||
&Xlgt06,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_07
|
||||
&Xlgt07,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_08
|
||||
&Xlgt08,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_09
|
||||
&Xlgt09,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_10
|
||||
&Xlgt10,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_11
|
||||
&Xlgt11,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_12
|
||||
&Xlgt12,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_13
|
||||
&Xlgt13,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_14
|
||||
&Xlgt14,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_15
|
||||
&Xlgt15,
|
||||
#endif
|
||||
|
||||
#ifdef XLGT_16
|
||||
&Xlgt16
|
||||
#endif
|
||||
};
|
||||
|
||||
const uint8_t xlgt_present = sizeof(xlgt_func_ptr) / sizeof(xlgt_func_ptr[0]); // Number of drivers found
|
||||
|
||||
uint8_t xlgt_active = 0;
|
||||
|
||||
bool XlgtCall(uint8_t function)
|
||||
{
|
||||
if (FUNC_MODULE_INIT == function) {
|
||||
for (uint32_t x = 0; x < xlgt_present; x++) {
|
||||
xlgt_func_ptr[x](function);
|
||||
if (light_flg) {
|
||||
xlgt_active = x;
|
||||
return true; // Stop further driver investigation
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (light_flg) {
|
||||
return xlgt_func_ptr[xlgt_active](function);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // USE_LIGHT
|
|
@ -54,8 +54,10 @@ void Dds2382EverySecond(void)
|
|||
} else {
|
||||
Energy.data_valid[0] = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
||||
// SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc--
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 = ModBus register
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 = Buffer index
|
||||
// SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc-- = DDS238-2 ZN/S version 1 (#6384)
|
||||
// SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc-- = DDS238-2 ZN/S version 2 (#6531)
|
||||
|
||||
Energy.voltage[0] = (float)((buffer[27] << 8) + buffer[28]) / 10.0;
|
||||
Energy.current[0] = (float)((buffer[29] << 8) + buffer[30]) / 100.0;
|
||||
|
@ -63,9 +65,12 @@ void Dds2382EverySecond(void)
|
|||
Energy.reactive_power[0] = (float)((buffer[33] << 8) + buffer[34]);
|
||||
Energy.power_factor[0] = (float)((buffer[35] << 8) + buffer[36]) / 1000.0; // 1.00
|
||||
Energy.frequency[0] = (float)((buffer[37] << 8) + buffer[38]) / 100.0; // 50.0 Hz
|
||||
Energy.export_active = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[13] << 8) + buffer[14]) / 100.0; // 429496729.0 W
|
||||
// float energy_total = (float)((buffer[3] << 24) + (buffer[4] << 16) + (buffer[5] << 8) + buffer[6]) / 100.0; // 429496729.0 W
|
||||
float import_active = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[17] << 8) + buffer[18]) / 100.0; // 429496729.0 W
|
||||
uint8_t offset = 11;
|
||||
if (Settings.flag3.dds2382_model) {
|
||||
offset = 19;
|
||||
}
|
||||
Energy.export_active = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0; // 429496729.0 W
|
||||
float import_active = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0; // 429496729.0 W
|
||||
|
||||
EnergyUpdateTotal(import_active, false); // 484.708 kWh
|
||||
}
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
xnrg_11_ddsu666.ino - Chint DDSU666-Modbus energy meter support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2019 Pablo Zerón and Theo Arends
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
#ifdef USE_DDSU666
|
||||
/*********************************************************************************************\
|
||||
* Chint DDSU666 Modbus energy meter
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XNRG_11 11
|
||||
|
||||
// can be user defined in my_user_config.h
|
||||
#ifndef DDSU666_SPEED
|
||||
#define DDSU666_SPEED 9600 // default DDSU66 Modbus address
|
||||
#endif
|
||||
// can be user defined in my_user_config.h
|
||||
#ifndef DDSU666_ADDR
|
||||
#define DDSU666_ADDR 1 // default DDSU66 Modbus address
|
||||
#endif
|
||||
|
||||
#include <TasmotaModbus.h>
|
||||
TasmotaModbus *Ddsu666Modbus;
|
||||
|
||||
const uint16_t Ddsu666_start_addresses[] {
|
||||
0x2000, // DDSU666_VOLTAGE [V]
|
||||
0x2002, // DDSU666_CURRENT [A]
|
||||
0x2004, // DDSU666_POWER [KW]
|
||||
0x2006, // DDSU666_REACTIVE_POWER [KVAR]
|
||||
0x200A, // DDSU666_POWER_FACTOR
|
||||
0x200E, // DDSU666_FREQUENCY [Hz]
|
||||
0X4000, // DDSU666_IMPORT_ACTIVE [kWh]
|
||||
0X400A, // DDSU666_EXPORT_ACTIVE [kWh]
|
||||
};
|
||||
|
||||
struct DDSU666 {
|
||||
float import_active = NAN;
|
||||
uint8_t read_state = 0;
|
||||
uint8_t send_retry = 0;
|
||||
} Ddsu666;
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void DDSU666Every250ms(void)
|
||||
{
|
||||
bool data_ready = Ddsu666Modbus->ReceiveReady();
|
||||
|
||||
if (data_ready) {
|
||||
uint8_t buffer[14]; // At least 5 + (2 * 2) = 9
|
||||
|
||||
uint32_t error = Ddsu666Modbus->ReceiveBuffer(buffer, 2);
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, Ddsu666Modbus->ReceiveCount());
|
||||
|
||||
if (error) {
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SDM: Ddsu666 error %d"), error);
|
||||
} else {
|
||||
Energy.data_valid[0] = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
// SA FC BC Fh Fl Sh Sl Cl Ch
|
||||
// 01 04 04 43 66 33 34 1B 38 = 230.2 Volt
|
||||
float value;
|
||||
((uint8_t*)&value)[3] = buffer[3]; // Get float values
|
||||
((uint8_t*)&value)[2] = buffer[4];
|
||||
((uint8_t*)&value)[1] = buffer[5];
|
||||
((uint8_t*)&value)[0] = buffer[6];
|
||||
|
||||
switch(Ddsu666.read_state) {
|
||||
case 0:
|
||||
Energy.voltage[0] = value; // 230.2 V
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Energy.current[0] = value; // 1.260 A
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Energy.active_power[0] = value * 1000; // -196.3 W
|
||||
break;
|
||||
|
||||
case 3:
|
||||
Energy.reactive_power[0] = value * 1000; // 92.2
|
||||
break;
|
||||
|
||||
case 4:
|
||||
Energy.power_factor[0] = value; // 0.91
|
||||
break;
|
||||
|
||||
case 5:
|
||||
Energy.frequency[0] = value; // 50.0 Hz
|
||||
break;
|
||||
|
||||
case 6:
|
||||
Ddsu666.import_active = value; // 478.492 kWh
|
||||
break;
|
||||
|
||||
case 7:
|
||||
Energy.export_active = value; // 6.216 kWh
|
||||
break;
|
||||
}
|
||||
|
||||
Ddsu666.read_state++;
|
||||
|
||||
if (Ddsu666.read_state == 8) {
|
||||
Ddsu666.read_state = 0;
|
||||
EnergyUpdateTotal(Ddsu666.import_active, true); // 484.708 kWh
|
||||
}
|
||||
}
|
||||
} // end data ready
|
||||
|
||||
if (0 == Ddsu666.send_retry || data_ready) {
|
||||
Ddsu666.send_retry = 5;
|
||||
Ddsu666Modbus->Send(DDSU666_ADDR, 0x04, Ddsu666_start_addresses[Ddsu666.read_state], 2);
|
||||
} else {
|
||||
Ddsu666.send_retry--;
|
||||
}
|
||||
}
|
||||
|
||||
void Ddsu666SnsInit(void)
|
||||
{
|
||||
Ddsu666Modbus = new TasmotaModbus(pin[GPIO_DDSU666_RX], pin[GPIO_DDSU666_TX]);
|
||||
uint8_t result = Ddsu666Modbus->Begin(DDSU666_SPEED);
|
||||
if (result) {
|
||||
if (2 == result) { ClaimSerial(); }
|
||||
} else {
|
||||
energy_flg = ENERGY_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void Ddsu666DrvInit(void)
|
||||
{
|
||||
if ((pin[GPIO_DDSU666_RX] < 99) && (pin[GPIO_DDSU666_TX] < 99)) {
|
||||
energy_flg = XNRG_11;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xnrg11(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_EVERY_250_MSECOND:
|
||||
if (uptime > 4) { DDSU666Every250ms(); }
|
||||
break;
|
||||
case FUNC_INIT:
|
||||
Ddsu666SnsInit();
|
||||
break;
|
||||
case FUNC_PRE_INIT:
|
||||
Ddsu666DrvInit();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_DDSU666
|
||||
#endif // USE_ENERGY_SENSOR
|
|
@ -628,15 +628,15 @@ bool MCP230xx_Command(void) {
|
|||
#ifdef USE_MCP230xx_OUTPUT
|
||||
if (Settings.mcp230xx_config[pin].pinmode >= 5) {
|
||||
uint8_t pincmd = Settings.mcp230xx_config[pin].pinmode - 5;
|
||||
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "ON")) {
|
||||
if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "ON")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "1"))) {
|
||||
MCP230xx_SetOutPin(pin,abs(pincmd-1));
|
||||
return serviced;
|
||||
}
|
||||
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "OFF")) {
|
||||
if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "OFF")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0"))) {
|
||||
MCP230xx_SetOutPin(pin,pincmd);
|
||||
return serviced;
|
||||
}
|
||||
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "T")) {
|
||||
if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "T")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "2"))) {
|
||||
MCP230xx_SetOutPin(pin,2);
|
||||
return serviced;
|
||||
}
|
||||
|
@ -655,9 +655,9 @@ bool MCP230xx_Command(void) {
|
|||
intmode = atoi(subStr(sub_string, XdrvMailbox.data, ",", 4));
|
||||
}
|
||||
#ifdef USE_MCP230xx_OUTPUT
|
||||
if ((pin < mcp230xx_pincount) && (pinmode > 0) && (pinmode < 7) && (pullup < 2)) {
|
||||
if ((pin < mcp230xx_pincount) && (pinmode > 0) && (pinmode < 7) && (pullup < 2) && (paramcount > 2)) {
|
||||
#else // not use OUTPUT
|
||||
if ((pin < mcp230xx_pincount) && (pinmode > 0) && (pinmode < 5) && (pullup < 2)) {
|
||||
if ((pin < mcp230xx_pincount) && (pinmode > 0) && (pinmode < 5) && (pullup < 2) && (paramcount > 2)) {
|
||||
#endif // USE_MCP230xx_OUTPUT
|
||||
Settings.mcp230xx_config[pin].pinmode=pinmode;
|
||||
Settings.mcp230xx_config[pin].pullup=pullup;
|
||||
|
|
|
@ -219,7 +219,7 @@ If you do not want using auto extensions use the <code>--no-extension</code> par
|
|||
[--cmnd-indent <indent>] [--cmnd-groups]
|
||||
[--cmnd-nogroups] [--cmnd-<span class="hljs-keyword">sort</span>] [--cmnd-unsort]
|
||||
[-c <filename>] [-S] [-T json|cmnd|command]
|
||||
[-<span class="hljs-keyword">g</span> {Control,Devices,<span class="hljs-keyword">Display</span>,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,<span class="hljs-keyword">Timer</span>,Wifi} [{Control,Devices,<span class="hljs-keyword">Display</span>,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,<span class="hljs-keyword">Timer</span>,Wifi} ...]]
|
||||
[-g {Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} ...]]
|
||||
[--ignore-warnings] [-<span class="hljs-keyword">h</span>] [-<span class="hljs-keyword">H</span>] [-v] [-V]
|
||||
|
||||
Backup/<span class="hljs-keyword">Restore</span> Sonoff-Tasmota configuration data. <span class="hljs-keyword">Args</span> that start with '--'
|
||||
|
@ -299,7 +299,7 @@ Common:
|
|||
(default <span class="hljs-keyword">do</span> not output <span class="hljs-keyword">on</span> backup or <span class="hljs-keyword">restore</span> usage)
|
||||
-T, --output-<span class="hljs-keyword">format</span> json|cmnd|command
|
||||
<span class="hljs-keyword">display</span> output <span class="hljs-keyword">format</span> (default: 'json')
|
||||
-<span class="hljs-keyword">g</span>, --group {Control,Devices,<span class="hljs-keyword">Display</span>,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,<span class="hljs-keyword">Timer</span>,Wifi}
|
||||
-g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi}
|
||||
limit data processing to command groups (default <span class="hljs-keyword">no</span>
|
||||
filter)
|
||||
--ignore-warnings <span class="hljs-keyword">do</span> not <span class="hljs-keyword">exit</span> <span class="hljs-keyword">on</span> warnings. Not recommended, used <span class="hljs-keyword">by</span> your
|
||||
|
|
|
@ -237,7 +237,7 @@ For advanced help use `-H` or `--full-help`:
|
|||
[--cmnd-indent <indent>] [--cmnd-groups]
|
||||
[--cmnd-nogroups] [--cmnd-sort] [--cmnd-unsort]
|
||||
[-c <filename>] [-S] [-T json|cmnd|command]
|
||||
[-g {Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} ...]]
|
||||
[-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} ...]]
|
||||
[--ignore-warnings] [-h] [-H] [-v] [-V]
|
||||
|
||||
Backup/Restore Sonoff-Tasmota configuration data. Args that start with '--'
|
||||
|
@ -317,7 +317,7 @@ For advanced help use `-H` or `--full-help`:
|
|||
(default do not output on backup or restore usage)
|
||||
-T, --output-format json|cmnd|command
|
||||
display output format (default: 'json')
|
||||
-g, --group {Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi}
|
||||
-g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi}
|
||||
limit data processing to command groups (default no
|
||||
filter)
|
||||
--ignore-warnings do not exit on warnings. Not recommended, used by your
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
VER = '2.3.0034'
|
||||
VER = '2.3.0035'
|
||||
|
||||
"""
|
||||
decode-config.py - Backup/Restore Sonoff-Tasmota configuration data
|
||||
|
@ -43,7 +43,7 @@ Usage: decode-config.py [-f <filename>] [-d <host>] [-P <port>]
|
|||
[--cmnd-indent <indent>] [--cmnd-groups]
|
||||
[--cmnd-nogroups] [--cmnd-sort] [--cmnd-unsort]
|
||||
[-c <filename>] [-S] [-T json|cmnd|command]
|
||||
[-g {Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi} ...]]
|
||||
[-g {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} [{Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi} ...]]
|
||||
[--ignore-warnings] [-h] [-H] [-v] [-V]
|
||||
|
||||
Backup/Restore Sonoff-Tasmota configuration data. Args that start with '--'
|
||||
|
@ -123,7 +123,7 @@ Usage: decode-config.py [-f <filename>] [-d <host>] [-P <port>]
|
|||
(default do not output on backup or restore usage)
|
||||
-T, --output-format json|cmnd|command
|
||||
display output format (default: 'json')
|
||||
-g, --group {Control,Devices,Display,Domoticz,Internal,KNX,Light,MQTT,Management,Power,Rules,Sensor,Serial,SetOption,SonoffRF,System,Timer,Wifi}
|
||||
-g, --group {Control,Devices,Display,Domoticz,Internal,Knx,Light,Management,Mqtt,Power,Rules,Sensor,Serial,Setoption,Shutter,Sonoffrf,System,Timer,Wifi}
|
||||
limit data processing to command groups (default no
|
||||
filter)
|
||||
--ignore-warnings do not exit on warnings. Not recommended, used by your
|
||||
|
@ -832,6 +832,9 @@ Setting_6_4_1_7['flag3'][0].update ({
|
|||
})
|
||||
# ======================================================================
|
||||
Setting_6_4_1_8 = copy.deepcopy(Setting_6_4_1_7)
|
||||
Setting_6_4_1_8.update ({
|
||||
'my_gp': ('B', 0x484, ([17], None, ('Management', '"Gpio{} {}".format(#,$)')) ),
|
||||
})
|
||||
Setting_6_4_1_8['flag3'][0].update ({
|
||||
'split_interlock': ('<L', (0x3A0,1,13), (None, None, ('SetOption', '"SetOption63 {}".format($)')) ),
|
||||
})
|
||||
|
@ -908,7 +911,12 @@ Setting_6_5_0_9['flag3'][0].update ({
|
|||
'no_power_feedback': ('<L', (0x3A0,1,13), (None, None, ('SetOption', '"SetOption63 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_5_0_11 = copy.deepcopy(Setting_6_5_0_9)
|
||||
Setting_6_5_0_10 = copy.deepcopy(Setting_6_5_0_9)
|
||||
Setting_6_5_0_10.update ({
|
||||
'my_adc0': ('B', 0x495, (None, None, ('Sensor', '"Adc {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_5_0_11 = copy.deepcopy(Setting_6_5_0_10)
|
||||
Setting_6_5_0_11['flag3'][0].update ({
|
||||
'use_underscore': ('<L', (0x3A0,1,14), (None, None, ('SetOption', '"SetOption64 {}".format($)')) ),
|
||||
})
|
||||
|
@ -1015,7 +1023,48 @@ Setting_6_6_0_12['flag3'][0].update ({
|
|||
'energy_weekend': ('<L', (0x3A0,1,20), (None, None, ('Power', '"Tariff9 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_6_0_13 = copy.deepcopy(Setting_6_6_0_12)
|
||||
Setting_6_6_0_13['SensorBits1'][0].update ({
|
||||
'hx711_json_weight_change': ('B', (0x717,1, 6), (None, None, ('Sensor', '"Sensor34 8 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_6_0_14 = copy.deepcopy(Setting_6_6_0_13)
|
||||
Setting_6_6_0_14.pop('register8_ENERGY_TARIFF1_ST',None)
|
||||
Setting_6_6_0_14.pop('register8_ENERGY_TARIFF2_ST',None)
|
||||
Setting_6_6_0_14.pop('register8_ENERGY_TARIFF1_DS',None)
|
||||
Setting_6_6_0_14.pop('register8_ENERGY_TARIFF2_DS',None)
|
||||
Setting_6_6_0_14.update ({
|
||||
'register8': ('B', 0x1D6, ([16], None, ('Power', None)) ),
|
||||
'tariff1_0': ('<H', 0xE30, (None, None, ('Power', '"Tariff1 {:02d}:{:02d},{:02d}:{:02d}".format(@["tariff1_0"]/60,@["tariff1_0"]%60,@["tariff1_1"]/60,@["tariff1_1"]%60)')) ),
|
||||
'tariff1_1': ('<H', 0xE32, (None, None, ('Power', None)) ),
|
||||
'tariff2_0': ('<H', 0xE34, (None, None, ('Power', '"Tariff2 {:02d}:{:02d},{:02d}:{:02d}".format(@["tariff2_0"]/60,@["tariff2_0"]%60,@["tariff2_1"]/60,@["tariff2_1"]%60)')) ),
|
||||
'tariff2_1': ('<H', 0xE36, (None, None, ('Power', None)) ),
|
||||
'mqttlog_level': ('B', 0x1E7, (None, None, ('Management', '"MqttLog {}".format($)')) ),
|
||||
'pcf8574_config': ('B', 0xE88, ([8], None, ('Devices', None)) ),
|
||||
'shutter_accuracy': ('B', 0x1E6, (None, None, ('Shutter', None)) ),
|
||||
'shutter_opentime': ('<H', 0xE40, ([4], None, ('Shutter', '"ShutterOpenDuration{} {:.1f}".format(#,$/10)')) ),
|
||||
'shutter_closetime': ('<H', 0xE48, ([4], None, ('Shutter', '"ShutterCloseDuration{} {:.1f}".format(#,$/10)')) ),
|
||||
'shuttercoeff': ('<H', 0xE50, ([5,4],None, ('Shutter', None)) ),
|
||||
'shutter_invert': ('B', 0xE78, ([4], None, ('Shutter', '"ShutterInvert{} {}".format(#,$)')) ),
|
||||
'shutter_set50percent': ('B', 0xE7C, ([4], None, ('Shutter', '"ShutterSetHalfway{} {}".format(#,$)')) ),
|
||||
'shutter_position': ('B', 0xE80, ([4], None, ('Shutter', '"ShutterPosition{} {}".format(#,$)')) ),
|
||||
'shutter_startrelay': ('B', 0xE84, ([4], None, ('Shutter', '"ShutterRelay{} {}".format(#,$)')) ),
|
||||
})
|
||||
Setting_6_6_0_14['flag3'][0].update ({
|
||||
'dds2382_model': ('<L', (0x3A0,1,21), (None, None, ('SetOption', '"SetOption71 {}".format($)')) ),
|
||||
'shutter_mode': ('<L', (0x3A0,1,30), (None, None, ('SetOption', '"SetOption80 {}".format($)')) ),
|
||||
'pcf8574_ports_inverted': ('<L', (0x3A0,1,31), (None, None, ('SetOption', '"SetOption81 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Setting_6_6_0_15 = copy.deepcopy(Setting_6_6_0_14)
|
||||
Setting_6_6_0_15['flag3'][0].update ({
|
||||
'hardware_energy_total': ('<L', (0x3A0,1,22), (None, None, ('SetOption', '"SetOption72 {}".format($)')) ),
|
||||
})
|
||||
# ======================================================================
|
||||
Settings = [
|
||||
(0x606000F,0x1000, Setting_6_6_0_15),
|
||||
(0x606000E,0x1000, Setting_6_6_0_14),
|
||||
(0x606000D,0x1000, Setting_6_6_0_13),
|
||||
(0x606000C,0x1000, Setting_6_6_0_12),
|
||||
(0x606000B,0x1000, Setting_6_6_0_11),
|
||||
(0x606000A,0x1000, Setting_6_6_0_10),
|
||||
|
@ -1030,7 +1079,7 @@ Settings = [
|
|||
(0x605000F, 0xe00, Setting_6_5_0_15),
|
||||
(0x605000C, 0xe00, Setting_6_5_0_12),
|
||||
(0x605000B, 0xe00, Setting_6_5_0_11),
|
||||
(0x605000B, 0xe00, Setting_6_5_0_11),
|
||||
(0x605000A, 0xe00, Setting_6_5_0_10),
|
||||
(0x6050009, 0xe00, Setting_6_5_0_9),
|
||||
(0x6050007, 0xe00, Setting_6_5_0_7),
|
||||
(0x6050006, 0xe00, Setting_6_5_0_6),
|
||||
|
@ -2162,7 +2211,7 @@ def IsFilterGroup(group):
|
|||
if group is None:
|
||||
return False
|
||||
if group == '*':
|
||||
return False
|
||||
return True
|
||||
if group.title() != INTERNAL.title() and group.title() not in (groupname.title() for groupname in args.filter):
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -124,9 +124,12 @@ a_setoption = [[
|
|||
"Enable multi-channels PWM instead of Color PWM",
|
||||
"Limits Tuya MCU dimmers to minimum of 10% (25) when enabled",
|
||||
"Enable Weekend Energy Tariff",
|
||||
"","","",
|
||||
"Select different Modbus registers for Active Energy",
|
||||
"","",
|
||||
"","","","",
|
||||
"","","",""
|
||||
"","",
|
||||
"Enable shutter support",
|
||||
"Invert PCF8574 ports"
|
||||
]]
|
||||
|
||||
a_features = [[
|
||||
|
@ -167,8 +170,8 @@ a_features = [[
|
|||
"USE_MAX31865","USE_CHIRP","USE_SOLAX_X1","USE_PAJ7620"
|
||||
],[
|
||||
"USE_BUZZER","USE_RDM6300","USE_IBEACON","USE_SML_M",
|
||||
"USE_INA226","USE_A4988_Stepper","USE_DDS2382","",
|
||||
"","","","",
|
||||
"USE_INA226","USE_A4988_Stepper","USE_DDS2382","USE_SM2135",
|
||||
"USE_SHUTTER","USE_PCF8574","USE_DDSU666","",
|
||||
"","","","",
|
||||
"","","","",
|
||||
"","","","",
|
||||
|
|
Loading…
Reference in New Issue