Merge pull request #10 from arendst/development

Update
This commit is contained in:
Jason2866 2019-10-06 18:58:12 +02:00 committed by GitHub
commit 13b505d427
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 2690 additions and 977 deletions

View File

@ -1,6 +1,6 @@
{
"name": "TasmotaSerial",
"version": "2.4.0",
"version": "2.4.1",
"keywords": [
"serial", "io", "TasmotaSerial"
],

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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\"}";

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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 "А"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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 "А"

View File

@ -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 "安"

View File

@ -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 "安"

View File

@ -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)

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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);
}
/*-------------------------------------------------------------------------------------------*/

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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
}
/*********************************************************************************************/

View File

@ -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);

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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

View File

@ -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]);
}
}

248
sonoff/xdrv_28_pcf8574.ino Normal file
View File

@ -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>&nbsp;" D_PCF8574_PARAMETERS "&nbsp;</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

View File

@ -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
\*********************************************************************************************/

View File

@ -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);

166
sonoff/xlgt_02_my92x1.ino Normal file
View File

@ -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

200
sonoff/xlgt_03_sm16716.ino Normal file
View File

@ -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

172
sonoff/xlgt_04_sm2135.ino Normal file
View File

@ -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

114
sonoff/xlgt_interface.ino Normal file
View File

@ -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

View File

@ -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
}

175
sonoff/xnrg_11_ddsu666.ino Normal file
View File

@ -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

View File

@ -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;

View File

@ -219,7 +219,7 @@ If you do not want using auto extensions use the <code>--no-extension</code> par
[--cmnd-indent &lt;indent&gt;] [--cmnd-groups]
[--cmnd-nogroups] [--cmnd-<span class="hljs-keyword">sort</span>] [--cmnd-unsort]
[-c &lt;filename&gt;] [-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

View File

@ -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

View File

@ -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

View File

@ -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","",
"","","","",
"","","","",
"","","","",