Updates for release 6.3.0

Updates for release 6.3.0
This commit is contained in:
Theo Arends 2018-10-27 13:33:17 +02:00
parent 42cb47de92
commit 0017a6304a
29 changed files with 2061 additions and 608 deletions

View File

@ -152,6 +152,7 @@ People helping to keep the show on the road:
- Raymond Mouthaan for managing Wemos Wiki information - Raymond Mouthaan for managing Wemos Wiki information
- Norbert Richter for his decode-config.py tool - Norbert Richter for his decode-config.py tool
- Andre Thomas for providing [thehackbox](http://thehackbox.org/tasmota/) OTA support and daily development builds - Andre Thomas for providing [thehackbox](http://thehackbox.org/tasmota/) OTA support and daily development builds
- Joel Stein and digiblur for their Tuya research and driver
- Frogmore42 and Jason2866 for providing many issue answers - Frogmore42 and Jason2866 for providing many issue answers
- Many more providing Tips, Pocs or PRs - Many more providing Tips, Pocs or PRs

View File

@ -125,6 +125,7 @@ Version 6.3.0 20181030
* Change energy monitoring using energy sensor driver modules * Change energy monitoring using energy sensor driver modules
* Change Webserver page handler for easier extension (thx to Adrian Scillato) * Change Webserver page handler for easier extension (thx to Adrian Scillato)
* Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896) * Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896)
* Change default OTA Url to http://thehackbox.org/tasmota/release/sonoff.bin (#4170)
* Remove support for MQTT Client esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Remove support for MQTT Client esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO
* Remove commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet * Remove commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet
* Remove restart after ntpserver change and force NTP re-sync (#3890) * Remove restart after ntpserver change and force NTP re-sync (#3890)

View File

@ -7,6 +7,7 @@
* Change energy monitoring using energy sensor driver modules * Change energy monitoring using energy sensor driver modules
* Change Webserver page handler for easier extension (thx to Adrian Scillato) * Change Webserver page handler for easier extension (thx to Adrian Scillato)
* Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896) * Change pinmode for no-pullup defined switches to pullup when configured as switchmode PUSHBUTTON (=3 and up) (#3896)
* Change default OTA Url to http://thehackbox.org/tasmota/release/sonoff.bin (#4170)
* Remove support for MQTT Client esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO * Remove support for MQTT Client esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO
* Remove commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet * Remove commands PowerCal, VoltageCal and CurrentCal as more functionality is provided by commands PowerSet, VoltageSet and CurrentSet
* Remove restart after ntpserver change and force NTP re-sync (#3890) * Remove restart after ntpserver change and force NTP re-sync (#3890)

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "А" #define D_UNIT_AMPERE "А"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "A" #define D_UNIT_AMPERE "A"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "А" #define D_UNIT_AMPERE "А"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "安" #define D_UNIT_AMPERE "安"

View File

@ -527,6 +527,8 @@
#define D_SENSOR_TX20_TX "TX20" #define D_SENSOR_TX20_TX "TX20"
#define D_SENSOR_RFSEND "RFSend" #define D_SENSOR_RFSEND "RFSend"
#define D_SENSOR_RFRECV "RFrecv" #define D_SENSOR_RFRECV "RFrecv"
#define D_SENSOR_TUYA_TX "Tuya Tx"
#define D_SENSOR_TUYA_RX "Tuya Rx"
// Units // Units
#define D_UNIT_AMPERE "安" #define D_UNIT_AMPERE "安"

View File

@ -79,7 +79,7 @@
#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 WEB_LOG_LEVEL LOG_LEVEL_INFO // [WebLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE)
// -- Ota ----------------------------------------- // -- Ota -----------------------------------------
#define OTA_URL "http://sonoff.maddox.co.uk/tasmota/sonoff.bin" // [OtaUrl] #define OTA_URL "http://thehackbox.org/tasmota/release/sonoff.bin" // [OtaUrl]
// -- MQTT ---------------------------------------- // -- MQTT ----------------------------------------
#define MQTT_USE 1 // [SetOption3] Select default MQTT use (0 = Off, 1 = On) #define MQTT_USE 1 // [SetOption3] Select default MQTT use (0 = Off, 1 = On)

View File

@ -131,6 +131,8 @@ enum UserSelectablePins {
GPIO_TX20_TXD_BLACK, // TX20 Transmission Pin GPIO_TX20_TXD_BLACK, // TX20 Transmission Pin
GPIO_RFSEND, // RF transmitter GPIO_RFSEND, // RF transmitter
GPIO_RFRECV, // RF receiver GPIO_RFRECV, // RF receiver
GPIO_TUYA_TX, // Tuya Serial interface
GPIO_TUYA_RX, // Tuya Serial interface
GPIO_SENSOR_END }; GPIO_SENSOR_END };
// Programmer selectable GPIO functionality offset by user selectable GPIOs // Programmer selectable GPIO functionality offset by user selectable GPIOs
@ -187,7 +189,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_DFR562 "|" D_SENSOR_SDS0X1_TX "|" D_SENSOR_DFR562 "|" D_SENSOR_SDS0X1_TX "|"
D_SENSOR_HX711_SCK "|" D_SENSOR_HX711_DAT "|" D_SENSOR_HX711_SCK "|" D_SENSOR_HX711_DAT "|"
D_SENSOR_TX20_TX "|" D_SENSOR_TX20_TX "|"
D_SENSOR_RFSEND "|" D_SENSOR_RFRECV; D_SENSOR_RFSEND "|" D_SENSOR_RFRECV "|"
D_SENSOR_TUYA_TX "|" D_SENSOR_TUYA_RX;
/********************************************************************************************/ /********************************************************************************************/
@ -371,7 +374,9 @@ const uint8_t kGpioNiceList[GPIO_SENSOR_END] PROGMEM = {
GPIO_SDM630_RX, // SDM630 Serial interface GPIO_SDM630_RX, // SDM630 Serial interface
GPIO_PMS5003, // Plantower PMS5003 Serial interface GPIO_PMS5003, // Plantower PMS5003 Serial interface
GPIO_TX20_TXD_BLACK, // TX20 Transmission Pin GPIO_TX20_TXD_BLACK, // TX20 Transmission Pin
GPIO_MP3_DFR562 // RB-DFR-562, DFPlayer Mini MP3 Player Serial interface GPIO_MP3_DFR562, // RB-DFR-562, DFPlayer Mini MP3 Player Serial interface
GPIO_TUYA_TX, // Tuya Serial interface
GPIO_TUYA_RX // Tuya Serial interface
}; };
const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
@ -1150,9 +1155,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
{ "Tuya Dimmer", // Tuya Dimmer (ESP8266 w/ separate MCU dimmer) { "Tuya Dimmer", // Tuya Dimmer (ESP8266 w/ separate MCU dimmer)
// https://www.amazon.com/gp/product/B07CTNSZZ8/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1 // https://www.amazon.com/gp/product/B07CTNSZZ8/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1
GPIO_KEY1, // Virtual Button (controlled by MCU) GPIO_KEY1, // Virtual Button (controlled by MCU)
GPIO_TXD, // GPIO01 MCU serial control GPIO_USER, // GPIO01 MCU serial control
GPIO_USER, GPIO_USER,
GPIO_RXD, // GPIO03 MCU serial control GPIO_USER, // GPIO03 MCU serial control
GPIO_USER, GPIO_USER,
GPIO_USER, GPIO_USER,
0, 0, 0, 0, 0, 0, // Flash connection 0, 0, 0, 0, 0, 0, // Flash connection

View File

@ -22,6 +22,11 @@
#ifndef TUYA_DIMMER_ID #ifndef TUYA_DIMMER_ID
#define TUYA_DIMMER_ID 3 #define TUYA_DIMMER_ID 3
#endif #endif
#define TUYA_BUFFER_SIZE 256
#include <TasmotaSerial.h>
TasmotaSerial *TuyaSerial = nullptr;
uint8_t tuya_new_dim = 0; // Tuya dimmer value temp uint8_t tuya_new_dim = 0; // Tuya dimmer value temp
boolean tuya_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction boolean tuya_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction
@ -29,6 +34,9 @@ uint8_t tuya_cmd_status = 0; // Current status of serial-read
uint8_t tuya_cmd_checksum = 0; // Checksum of tuya command uint8_t tuya_cmd_checksum = 0; // Checksum of tuya command
uint8_t tuya_data_len = 0; // Data lenght of command uint8_t tuya_data_len = 0; // Data lenght of command
char tuya_buffer[TUYA_BUFFER_SIZE]; // Serial receive buffer
int tuya_byte_counter = 0; // Index in serial receive buffer
boolean TuyaSetPower() boolean TuyaSetPower()
{ {
boolean status = false; boolean status = false;
@ -36,24 +44,24 @@ boolean TuyaSetPower()
uint8_t rpower = XdrvMailbox.index; uint8_t rpower = XdrvMailbox.index;
int16_t source = XdrvMailbox.payload; int16_t source = XdrvMailbox.payload;
if (source != SRC_SWITCH ) { // ignore to prevent loop from pushing state from faceplate interaction if (source != SRC_SWITCH && TuyaSerial) { // ignore to prevent loop from pushing state from faceplate interaction
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: SetDevicePower.rpower=%d"), rpower); snprintf_P(log_data, sizeof(log_data), PSTR("TYA: SetDevicePower.rpower=%d"), rpower);
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
Serial.write(0x55); // Tuya header 55AA TuyaSerial->write((uint8_t)0x55); // Tuya header 55AA
Serial.write(0xAA); TuyaSerial->write((uint8_t)0xAA);
Serial.write(0x00); // version 00 TuyaSerial->write((uint8_t)0x00); // version 00
Serial.write(0x06); // Tuya command 06 TuyaSerial->write((uint8_t)0x06); // Tuya command 06
Serial.write(0x00); TuyaSerial->write((uint8_t)0x00);
Serial.write(0x05); // following data length 0x05 TuyaSerial->write((uint8_t)0x05); // following data length 0x05
Serial.write(0x01); // relay number 1,2,3 TuyaSerial->write((uint8_t)0x01); // relay number 1,2,3
Serial.write(0x01); TuyaSerial->write((uint8_t)0x01);
Serial.write(0x00); TuyaSerial->write((uint8_t)0x00);
Serial.write(0x01); TuyaSerial->write((uint8_t)0x01);
Serial.write(rpower); // status TuyaSerial->write((uint8_t)rpower); // status
Serial.write(0x0D + rpower); // checksum sum of all bytes in packet mod 256 TuyaSerial->write((uint8_t)0x0D + rpower); // checksum sum of all bytes in packet mod 256
Serial.flush(); TuyaSerial->flush();
status = true; status = true;
} }
@ -62,26 +70,26 @@ boolean TuyaSetPower()
void LightSerialDuty(uint8_t duty) void LightSerialDuty(uint8_t duty)
{ {
if (duty > 0 && !tuya_ignore_dim ) { if (duty > 0 && !tuya_ignore_dim && TuyaSerial) {
if (duty < 25) { if (duty < 25) {
duty = 25; // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself duty = 25; // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
} }
Serial.write(0x55); // Tuya header 55AA TuyaSerial->write((uint8_t)0x55); // Tuya header 55AA
Serial.write(0xAA); TuyaSerial->write((uint8_t)0xAA);
Serial.write(0x00); // version 00 TuyaSerial->write((uint8_t)0x00); // version 00
Serial.write(0x06); // Tuya command 06 - send order TuyaSerial->write((uint8_t)0x06); // Tuya command 06 - send order
Serial.write(0x00); TuyaSerial->write((uint8_t)0x00);
Serial.write(0x08); // following data length 0x08 TuyaSerial->write((uint8_t)0x08); // following data length 0x08
Serial.write(Settings.param[P_TUYA_DIMMER_ID]); // dimmer id TuyaSerial->write((uint8_t)Settings.param[P_TUYA_DIMMER_ID]); // dimmer id
Serial.write(0x02); // type=value TuyaSerial->write((uint8_t)0x02); // type=value
Serial.write(0x00); // length hi TuyaSerial->write((uint8_t)0x00); // length hi
Serial.write(0x04); // length low TuyaSerial->write((uint8_t)0x04); // length low
Serial.write(0x00); // TuyaSerial->write((uint8_t)0x00); //
Serial.write(0x00); // TuyaSerial->write((uint8_t)0x00); //
Serial.write(0x00); // TuyaSerial->write((uint8_t)0x00); //
Serial.write( duty ); // dim value (0-255) TuyaSerial->write((uint8_t) duty ); // dim value (0-255)
Serial.write( byte(Settings.param[P_TUYA_DIMMER_ID] + 19 + duty) ); // checksum:sum of all bytes in packet mod 256 TuyaSerial->write((uint8_t) byte(Settings.param[P_TUYA_DIMMER_ID] + 19 + duty) ); // checksum:sum of all bytes in packet mod 256
Serial.flush(); TuyaSerial->flush();
snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Serial Packet Dim Value=%d (id=%d)"), duty, Settings.param[P_TUYA_DIMMER_ID]); snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Serial Packet Dim Value=%d (id=%d)"), duty, Settings.param[P_TUYA_DIMMER_ID]);
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
@ -99,27 +107,27 @@ void TuyaPacketProcess()
{ {
char scmnd[20]; char scmnd[20];
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Packet Size=%d"), serial_in_byte_counter); snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Packet Size=%d"), tuya_byte_counter);
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
if (serial_in_byte_counter == 7 && serial_in_buffer[3] == 14 ) { // heartbeat packet if (tuya_byte_counter == 7 && tuya_buffer[3] == 14 ) { // heartbeat packet
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Heartbeat")); AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Heartbeat"));
} }
else if (serial_in_byte_counter == 12 && serial_in_buffer[3] == 7 && serial_in_buffer[5] == 5) { // on/off packet else if (tuya_byte_counter == 12 && tuya_buffer[3] == 7 && tuya_buffer[5] == 5) { // on/off packet
snprintf_P(log_data, sizeof(log_data),PSTR("TYA: Rcvd - %s State"),serial_in_buffer[10]?"On":"Off"); snprintf_P(log_data, sizeof(log_data),PSTR("TYA: Rcvd - %s State"),tuya_buffer[10]?"On":"Off");
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
if((power || Settings.light_dimmer > 0) && (power != serial_in_buffer[10])) { if((power || Settings.light_dimmer > 0) && (power != tuya_buffer[10])) {
ExecuteCommandPower(1, serial_in_buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction ExecuteCommandPower(1, tuya_buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
} }
} }
else if (serial_in_byte_counter == 15 && serial_in_buffer[3] == 7 && serial_in_buffer[5] == 8) { // dim packet else if (tuya_byte_counter == 15 && tuya_buffer[3] == 7 && tuya_buffer[5] == 8) { // dim packet
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Rcvd Dim State=%d"), serial_in_buffer[13]); snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Rcvd Dim State=%d"), tuya_buffer[13]);
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
tuya_new_dim = round(serial_in_buffer[13] * (100. / 255.)); tuya_new_dim = round(tuya_buffer[13] * (100. / 255.));
if((power) && (tuya_new_dim > 0) && (abs(tuya_new_dim - Settings.light_dimmer) > 2)) { if((power) && (tuya_new_dim > 0) && (abs(tuya_new_dim - Settings.light_dimmer) > 2)) {
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send CMND_DIMMER=%d"), tuya_new_dim ); snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send CMND_DIMMER=%d"), tuya_new_dim );
@ -134,7 +142,7 @@ void TuyaPacketProcess()
ExecuteCommand(scmnd, SRC_SWITCH); ExecuteCommand(scmnd, SRC_SWITCH);
} }
} }
else if (serial_in_byte_counter == 8 && serial_in_buffer[3] == 5 && serial_in_buffer[5] == 1 && serial_in_buffer[7] == 5 ) { // reset WiFi settings packet - to do: reset red MCU LED after WiFi is up else if (tuya_byte_counter == 8 && tuya_buffer[3] == 5 && tuya_buffer[5] == 1 && tuya_buffer[7] == 5 ) { // reset WiFi settings packet - to do: reset red MCU LED after WiFi is up
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: WiFi Reset Rcvd")); AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: WiFi Reset Rcvd"));
@ -145,16 +153,16 @@ void TuyaPacketProcess()
void TuyaSerialInput() void TuyaSerialInput()
{ {
while (Serial.available()) { while (TuyaSerial->available()) {
yield(); yield();
serial_in_byte = Serial.read(); byte serial_in_byte = TuyaSerial->read();
//snprintf_P(log_data, sizeof(log_data), PSTR("TYA: serial_in_byte %d, tuya_cmd_status %d, tuya_cmd_checksum %d, tuya_data_len %d, serial_in_byte_counter %d"), serial_in_byte, tuya_cmd_status, tuya_cmd_checksum, tuya_data_len, serial_in_byte_counter); //snprintf_P(log_data, sizeof(log_data), PSTR("TYA: serial_in_byte %d, tuya_cmd_status %d, tuya_cmd_checksum %d, tuya_data_len %d, tuya_byte_counter %d"), serial_in_byte, tuya_cmd_status, tuya_cmd_checksum, tuya_data_len, tuya_byte_counter);
//AddLog(LOG_LEVEL_DEBUG); //AddLog(LOG_LEVEL_DEBUG);
if (serial_in_byte == 0x55) { // Start TUYA Packet if (serial_in_byte == 0x55) { // Start TUYA Packet
tuya_cmd_status = 1; tuya_cmd_status = 1;
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; tuya_buffer[tuya_byte_counter++] = serial_in_byte;
tuya_cmd_checksum += serial_in_byte; tuya_cmd_checksum += serial_in_byte;
} }
else if (tuya_cmd_status == 1 && serial_in_byte == 0xAA){ // Only packtes with header 0x55AA are valid else if (tuya_cmd_status == 1 && serial_in_byte == 0xAA){ // Only packtes with header 0x55AA are valid
@ -162,40 +170,40 @@ void TuyaSerialInput()
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: 0x55AA Packet Start")); AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: 0x55AA Packet Start"));
serial_in_byte_counter = 0; tuya_byte_counter = 0;
serial_in_buffer[serial_in_byte_counter++] = 0x55; tuya_buffer[tuya_byte_counter++] = 0x55;
serial_in_buffer[serial_in_byte_counter++] = 0xAA; tuya_buffer[tuya_byte_counter++] = 0xAA;
tuya_cmd_checksum = 0xFF; tuya_cmd_checksum = 0xFF;
} }
else if (tuya_cmd_status == 2){ else if (tuya_cmd_status == 2){
if(serial_in_byte_counter == 5){ // Get length of data if(tuya_byte_counter == 5){ // Get length of data
tuya_cmd_status = 3; tuya_cmd_status = 3;
tuya_data_len = serial_in_byte; tuya_data_len = serial_in_byte;
} }
tuya_cmd_checksum += serial_in_byte; tuya_cmd_checksum += serial_in_byte;
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; tuya_buffer[tuya_byte_counter++] = serial_in_byte;
} }
else if ((tuya_cmd_status == 3) && (serial_in_byte_counter == (6 + tuya_data_len)) && (tuya_cmd_checksum == serial_in_byte)){ // Compare checksum and process packet else if ((tuya_cmd_status == 3) && (tuya_byte_counter == (6 + tuya_data_len)) && (tuya_cmd_checksum == serial_in_byte)){ // Compare checksum and process packet
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; tuya_buffer[tuya_byte_counter++] = serial_in_byte;
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: 0x55 Packet End: \"")); snprintf_P(log_data, sizeof(log_data), PSTR("TYA: 0x55 Packet End: \""));
for (int i = 0; i < serial_in_byte_counter; i++) { for (int i = 0; i < tuya_byte_counter; i++) {
snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, serial_in_buffer[i]); snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, tuya_buffer[i]);
} }
snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data); snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data);
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
TuyaPacketProcess(); TuyaPacketProcess();
serial_in_byte_counter = 0; tuya_byte_counter = 0;
tuya_cmd_status = 0; tuya_cmd_status = 0;
tuya_cmd_checksum = 0; tuya_cmd_checksum = 0;
tuya_data_len = 0; tuya_data_len = 0;
} // read additional packets from TUYA } // read additional packets from TUYA
else if(serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits else if(tuya_byte_counter < TUYA_BUFFER_SIZE -1) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; tuya_buffer[tuya_byte_counter++] = serial_in_byte;
tuya_cmd_checksum += serial_in_byte; tuya_cmd_checksum += serial_in_byte;
} else { } else {
serial_in_byte_counter = 0; tuya_byte_counter = 0;
tuya_cmd_status = 0; tuya_cmd_status = 0;
tuya_cmd_checksum = 0; tuya_cmd_checksum = 0;
tuya_data_len = 0; tuya_data_len = 0;
@ -205,7 +213,10 @@ void TuyaSerialInput()
boolean TuyaModuleSelected() boolean TuyaModuleSelected()
{ {
baudrate = 9600; if (!(pin[GPIO_TUYA_RX] < 99) || !(pin[GPIO_TUYA_TX] < 99)) { // fallback to hardware-serial if not explicitly selected
pin[GPIO_TUYA_RX] = 1;
pin[GPIO_TUYA_TX] = 3;
}
light_type = LT_SERIAL; light_type = LT_SERIAL;
return true; return true;
} }
@ -215,20 +226,23 @@ void TuyaInit()
if (!Settings.param[P_TUYA_DIMMER_ID]) { if (!Settings.param[P_TUYA_DIMMER_ID]) {
Settings.param[P_TUYA_DIMMER_ID] = TUYA_DIMMER_ID; Settings.param[P_TUYA_DIMMER_ID] = TUYA_DIMMER_ID;
} }
Serial.setDebugOutput(false); TuyaSerial = new TasmotaSerial(pin[GPIO_TUYA_RX], pin[GPIO_TUYA_TX], 1);
ClaimSerial(); if (TuyaSerial->begin(9600)) {
if (TuyaSerial->hardwareSerial()) { ClaimSerial(); }
// Get current status of MCU // Get current status of MCU
snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state"); snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state");
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
Serial.write(0x55); // header 55AA
Serial.write(0xAA); TuyaSerial->write((uint8_t)0x55); // header 55AA
Serial.write(0x00); // version 00 TuyaSerial->write((uint8_t)0xAA);
Serial.write(0x08); // command 08 - get status TuyaSerial->write((uint8_t)0x00); // version 00
Serial.write(0x00); TuyaSerial->write((uint8_t)0x08); // command 08 - get status
Serial.write(0x00); // following data length 0x00 TuyaSerial->write((uint8_t)0x00);
Serial.write(0x07); // checksum:sum of all bytes in packet mod 256 TuyaSerial->write((uint8_t)0x00); // following data length 0x00
Serial.flush(); TuyaSerial->write((uint8_t)0x07); // checksum:sum of all bytes in packet mod 256
TuyaSerial->flush();
}
} }
boolean TuyaButtonPressed() boolean TuyaButtonPressed()
@ -266,7 +280,7 @@ boolean Xdrv16(byte function)
TuyaInit(); TuyaInit();
break; break;
case FUNC_LOOP: case FUNC_LOOP:
TuyaSerialInput(); if (TuyaSerial) { TuyaSerialInput(); }
break; break;
case FUNC_SET_DEVICE_POWER: case FUNC_SET_DEVICE_POWER:
result = TuyaSetPower(); result = TuyaSetPower();

View File

@ -664,7 +664,7 @@ void HueLights(String *path)
response = "["; response = "[";
StaticJsonBuffer<400> jsonBuffer; StaticJsonBuffer<400> jsonBuffer;
JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg((WebServer->args())-1)); JsonObject &hue_json = jsonBuffer.parseObject(WebServer->arg("1"));
if (hue_json.containsKey("on")) { if (hue_json.containsKey("on")) {
response += FPSTR(HUE_LIGHT_RESPONSE_JSON); response += FPSTR(HUE_LIGHT_RESPONSE_JSON);

230
tools/decode-config.html Normal file
View File

@ -0,0 +1,230 @@
<h1 id="decode-config-py">decode-config.py</h1>
<p><em>decode-config.py</em> backup and restore Sonoff-Tasmota configuration.</p>
<p>Comparing backup files created by <em>decode-config.py</em> and *.dmp files created by Tasmota &quot;Backup/Restore Configuration&quot;: </p>
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th style="text-align:center">decode-config.py<br />*.json file</th>
<th style="text-align:center">Sonoff-Tasmota<br />*.dmp file</th>
</tr>
</thead>
<tbody>
<tr>
<td>Encrypted</td>
<td style="text-align:center">No</td>
<td style="text-align:center">Yes</td>
</tr>
<tr>
<td>Readable</td>
<td style="text-align:center">Yes</td>
<td style="text-align:center">No</td>
</tr>
<tr>
<td>Simply editable</td>
<td style="text-align:center">Yes</td>
<td style="text-align:center">No</td>
</tr>
<tr>
<td>Simply batch processing</td>
<td style="text-align:center">Yes</td>
<td style="text-align:center">No</td>
</tr>
</tbody>
</table>
<p><em>decode-config.py</em> handles Tasmota configurations for release version since 5.10.0 up to now.</p>
<h1 id="content">Content</h1>
<ul>
<li><a href="decode-config.html#prerequisite">Prerequisite</a></li>
<li><a href="decode-config.html#file-types">File Types</a><ul>
<li><a href="decode-config.html#-dmp-file-format">.dmp File Format</a></li>
<li><a href="decode-config.html#-json-file-format">.json File Format</a></li>
<li><a href="decode-config.html#-bin-file-format">.bin File Format</a><ul>
<li><a href="decode-config.html#file-extensions">File extensions</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="decode-config.html#usage">Usage</a><ul>
<li><a href="decode-config.html#basics">Basics</a></li>
<li><a href="decode-config.html#save-backup-file">Save backup file</a></li>
<li><a href="decode-config.html#restore-backup-file">Restore backup file</a></li>
<li><a href="decode-config.html#configuration-file">Configuration file</a></li>
<li><a href="decode-config.html#more-program-arguments">More program arguments</a></li>
<li><a href="decode-config.html#examples">Examples</a><ul>
<li><a href="decode-config.html#config-file">Config file</a></li>
<li><a href="decode-config.html#using-tasmota-binary-configuration-files">Using Tasmota binary configuration files</a></li>
<li><a href="decode-config.html#use-batch-processing">Use batch processing</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="prerequisite">Prerequisite</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Python_(programming_language">Python</a>)<br>This program is written in <a href="https://en.wikipedia.org/wiki/Python_(programming_language">Python</a>) so you need to install a python environment (for details see <a href="https://docs.python.org/2.7/using/index.html">Python Setup and Usage</a>)</li>
<li><a href="https://github.com/arendst/Sonoff-Tasmota">Sonoff-Tasmota</a> <a href="https://github.com/arendst/Sonoff-Tasmota/releases">Firmware</a> with enabled Web-Server<br>To backup or restore configurations from/to a Sonoff-Tasmota device you need a firmare with enabled web-server in admin mode (command <a href="https://github.com/arendst/Sonoff-Tasmota/wiki/Commands#wifi">WebServer 2</a>).
<br />Only self compiled firmware may do not have a web-server sod if you use your own compiled firmware be aware to enable the web-server, otherwise you can only use the <code>--file</code> parameter as source.</li>
</ul>
<h2 id="file-types">File Types</h2>
<p><em>decode-config.py</em> can handle the following backup file types: </p>
<h3 id="-dmp-format">.dmp Format</h3>
<p>Configuration data as used by Tasmota &quot;Backup/Restore Configuration&quot; web interface.<br>This format is binary and encrypted.</p>
<h3 id="-json-format">.json Format</h3>
<p>Configuration data in <a href="http://www.json.org/">JSON</a>-format.<br>This format is decrypted, human readable and editable and can also be used for the <code>--restore-file</code> command.<br>This file will becreated by <em>decode-config.py</em> using <code>--backup-file</code> with <code>--backup-type json</code> parameter (default).</p>
<h3 id="-bin-format">.bin Format</h3>
<p>Configuration data in binary format.<br>This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for <code>--restore-file</code> command.<br>It will be created by <em>decode-config.py</em> using <code>--backup-file</code> with <code>--backup-type bin</code>.<br>Note:<br>This file is 4 byte longer than an original .dmp file due to an prefix header at the beginning. The file data starting at address position 4 are containing the same as the <strong>struct SYSCFG</strong> from Tasmota <a href="https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/settings.h">settings.h</a> in decrypted format.</p>
<h4 id="file-extensions">File extensions</h4>
<p><em>decode-config.py</em> uses auto extension as default for backup filenames; you don&#39;t need to append extensions to your backup file, it will be selected based on <code>--backup-type</code> argument.<br>If you want using your own extension use the <code>--no-extension</code> argument.</p>
<h2 id="usage">Usage</h2>
<p>After download don&#39;t forget to set exec flag under linux with <code>chmod +x decode-config.py</code> or call the program using <code>python decode-config.py...</code>.</p>
<h3 id="basics">Basics</h3>
<p>At least pass a source where you want to read the configuration data from using <code>-f &lt;filename&gt;</code> or <code>-d &lt;host&gt;</code>:</p>
<p>The source can be either </p>
<ul>
<li>a Tasmota device hostname or IP by passing it using the <code>-d &lt;host&gt;</code> arg</li>
<li>or a previously stored Tasmota *.dmp<code>configuration file by passing the filename using</code>-f <filename>` arg</li>
</ul>
<p>Example: </p>
<pre><code>decode-config<span class="hljs-selector-class">.py</span> -d sonoff-<span class="hljs-number">4281</span>
</code></pre><p>will output a human readable configuration in <a href="http://www.json.org/">JSON</a>-format:</p>
<pre><code>{
<span class="hljs-string">"altitude"</span>: <span class="hljs-number">112</span>,
<span class="hljs-string">"baudrate"</span>: <span class="hljs-number">115200</span>,
<span class="hljs-string">"blinkcount"</span>: <span class="hljs-number">10</span>,
<span class="hljs-string">"blinktime"</span>: <span class="hljs-number">10</span>,
...
<span class="hljs-string">"ws_width"</span>: [
<span class="hljs-number">1</span>,
<span class="hljs-number">3</span>,
<span class="hljs-number">5</span>
]
}
</code></pre><h3 id="save-backup-file">Save backup file</h3>
<p>To save the output as backup file <code>--backup-file &lt;filename&gt;</code>, you can use placeholder for Version, Friendlyname and Hostname: </p>
<pre><code><span class="hljs-selector-tag">decode-config</span><span class="hljs-selector-class">.py</span> <span class="hljs-selector-tag">-d</span> <span class="hljs-selector-tag">sonoff-4281</span> <span class="hljs-selector-tag">--backup-file</span> <span class="hljs-selector-tag">Config_</span>@<span class="hljs-keyword">f_</span>@<span class="hljs-keyword">v</span>
</code></pre><p>If you have setup a WebPassword within Tasmota, use</p>
<pre><code>decode-config<span class="hljs-selector-class">.py</span> -d sonoff-<span class="hljs-number">4281</span> -<span class="hljs-selector-tag">p</span> &lt;yourpassword&gt; --backup-file Config_@f_@v
</code></pre><p>will create a file like <code>Config_Sonoff_x.x.x.json</code>. Because it is in JSON format, you can read and edit the file with any raw text editor.</p>
<h3 id="restore-backup-file">Restore backup file</h3>
<p>Reading back a saved (and possible changed) backup file use the <code>--restore-file &lt;filename&gt;</code> arg. This will read the (changed) configuration data from this file and send it back to the source device or filename.</p>
<p>To restore the previously save backup file <code>Config_Sonoff_6.2.1.json</code> to device <code>sonoff-4281</code> use: </p>
<pre><code><span class="hljs-selector-tag">decode-config</span><span class="hljs-selector-class">.py</span> <span class="hljs-selector-tag">-d</span> <span class="hljs-selector-tag">sonoff-4281</span> <span class="hljs-selector-tag">--restore-file</span> <span class="hljs-selector-tag">Config_Sonoff_6</span><span class="hljs-selector-class">.2</span><span class="hljs-selector-class">.1</span><span class="hljs-selector-class">.json</span>
</code></pre><p>with password set by WebPassword:</p>
<pre><code><span class="hljs-selector-tag">decode-config</span><span class="hljs-selector-class">.py</span> <span class="hljs-selector-tag">-d</span> <span class="hljs-selector-tag">sonoff-4281</span> <span class="hljs-selector-tag">-p</span> &lt;<span class="hljs-selector-tag">yourpassword</span>&gt; <span class="hljs-selector-tag">--restore-file</span> <span class="hljs-selector-tag">Config_Sonoff_6</span><span class="hljs-selector-class">.2</span><span class="hljs-selector-class">.1</span><span class="hljs-selector-class">.json</span>
</code></pre><h3 id="configuration-file">Configuration file</h3>
<p>Each argument that start with <code>--</code> (eg. <code>--file</code>) can also be set in a config file (specified via -c). Config file syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at <a href="https://pypi.org/project/ConfigArgParse/">https://pypi.org/project/ConfigArgParse</a>).</p>
<p>If an argument is specified in more than one place, then commandline values override config file values which override defaults. This is usefull if you always use the same argument or a basic set of arguments.</p>
<p>The http authentication credentials <code>--username</code> and <code>--password</code> is predestinated to store it in a file instead using it on your command line as argument:</p>
<p>e.g. my.conf:</p>
<pre><code><span class="hljs-section">[source]</span>
<span class="hljs-attr">username</span> = admin
<span class="hljs-attr">password</span> = myPaszxwo!z
</code></pre><p>To make a backup file from example above you can now pass the config file instead using the password on command line:</p>
<pre><code><span class="hljs-selector-tag">decode-config</span><span class="hljs-selector-class">.py</span> <span class="hljs-selector-tag">-d</span> <span class="hljs-selector-tag">sonoff-4281</span> <span class="hljs-selector-tag">-c</span> <span class="hljs-selector-tag">my</span><span class="hljs-selector-class">.conf</span> <span class="hljs-selector-tag">--backup-file</span> <span class="hljs-selector-tag">Config_</span>@<span class="hljs-keyword">f_</span>@<span class="hljs-keyword">v</span>
</code></pre><h3 id="more-program-arguments">More program arguments</h3>
<p>For better reading your porgram arguments each short written arg (minus sign <code>-</code>) has a corresponding readable long version (two minus signs <code>--</code>), eg. <code>--device</code> for <code>-d</code> or <code>--file</code> for <code>-f</code> (note: not even all <code>--</code> arg has a corresponding <code>-</code> one).</p>
<p>A short list of possible program args is displayed using <code>-h</code> or <code>--help</code>.</p>
<p>For advanced help use <code>-H</code> or <code>--full-help</code>:</p>
<pre><code>usage: decode-config.py [-f &lt;filename&gt;] [-d &lt;host&gt;] [-P &lt;<span class="hljs-keyword">port</span>&gt;]
[-u &lt;username&gt;] [-p &lt;password&gt;] [-i &lt;filename&gt;]
[-o &lt;filename&gt;] [-F json|bin|dmp] [-E] [-e]
[<span class="hljs-comment">--json-indent &lt;indent&gt;] [--json-compact]</span>
[<span class="hljs-comment">--json-hide-pw] [--json-unhide-pw] [-h] [-H] [-v]</span>
[-V] [-c &lt;filename&gt;] [<span class="hljs-comment">--ignore-warnings]</span>
Backup/Restore Sonoff-Tasmota <span class="hljs-keyword">configuration</span> data. Args that start <span class="hljs-keyword">with</span> '<span class="hljs-comment">--'</span>
(eg. -f) can also be set <span class="hljs-keyword">in</span> a config <span class="hljs-keyword">file</span> (specified via -c). Config <span class="hljs-keyword">file</span>
syntax allows: key=value, flag=<span class="hljs-literal">true</span>, stuff=[a,b,c] (<span class="hljs-keyword">for</span> details, see syntax at
https://goo.gl/R74nmi). <span class="hljs-keyword">If</span> an arg <span class="hljs-keyword">is</span> specified <span class="hljs-keyword">in</span> more than one place, <span class="hljs-keyword">then</span>
commandline values override config <span class="hljs-keyword">file</span> values which override defaults.
optional arguments:
-c, <span class="hljs-comment">--config &lt;filename&gt;</span>
program config <span class="hljs-keyword">file</span> - can be used <span class="hljs-keyword">to</span> set <span class="hljs-keyword">default</span>
command args (<span class="hljs-keyword">default</span>: None)
<span class="hljs-comment">--ignore-warnings do not exit on warnings. Not recommended, used by your</span>
own responsibility!
Source:
Read/Write Tasmota <span class="hljs-keyword">configuration</span> from/<span class="hljs-keyword">to</span>
-f, <span class="hljs-comment">--file, --tasmota-file &lt;filename&gt;</span>
<span class="hljs-keyword">file</span> <span class="hljs-keyword">to</span> retrieve/write Tasmota <span class="hljs-keyword">configuration</span> from/<span class="hljs-keyword">to</span>
(<span class="hljs-keyword">default</span>: None)'
-d, <span class="hljs-comment">--device, --host &lt;host&gt;</span>
hostname <span class="hljs-keyword">or</span> IP address <span class="hljs-keyword">to</span> retrieve/send Tasmota
<span class="hljs-keyword">configuration</span> from/<span class="hljs-keyword">to</span> (<span class="hljs-keyword">default</span>: None)
-P, <span class="hljs-comment">--port &lt;port&gt; TCP/IP port number to use for the host connection</span>
(<span class="hljs-keyword">default</span>: <span class="hljs-number">80</span>)
-u, <span class="hljs-comment">--username &lt;username&gt;</span>
host HTTP <span class="hljs-keyword">access</span> username (<span class="hljs-keyword">default</span>: admin)
-p, <span class="hljs-comment">--password &lt;password&gt;</span>
host HTTP <span class="hljs-keyword">access</span> password (<span class="hljs-keyword">default</span>: None)
Backup/Restore:
Backup/Restore <span class="hljs-keyword">configuration</span> <span class="hljs-keyword">file</span> specification
-i, <span class="hljs-comment">--restore-file &lt;filename&gt;</span>
<span class="hljs-keyword">file</span> <span class="hljs-keyword">to</span> restore <span class="hljs-keyword">configuration</span> from (<span class="hljs-keyword">default</span>: None).
Replacements: @v=firmware version, @f=device friendly
name, @h=device hostname
-o, <span class="hljs-comment">--backup-file &lt;filename&gt;</span>
<span class="hljs-keyword">file</span> <span class="hljs-keyword">to</span> backup <span class="hljs-keyword">configuration</span> <span class="hljs-keyword">to</span> (<span class="hljs-keyword">default</span>: None).
Replacements: @v=firmware version, @f=device friendly
name, @h=device hostname
-F, <span class="hljs-comment">--backup-type json|bin|dmp</span>
backup filetype (<span class="hljs-keyword">default</span>: <span class="hljs-symbol">'json</span>')
-E, <span class="hljs-comment">--extension append filetype extension for -i and -o filename</span>
(<span class="hljs-keyword">default</span>)
-e, <span class="hljs-comment">--no-extension do not append filetype extension, use -i and -o</span>
filename as passed
JSON:
JSON backup format specification
<span class="hljs-comment">--json-indent &lt;indent&gt;</span>
pretty-printed JSON output using indent level
(<span class="hljs-keyword">default</span>: <span class="hljs-symbol">'None</span>'). -<span class="hljs-number">1</span> disables indent.
<span class="hljs-comment">--json-compact compact JSON output by eliminate whitespace</span>
<span class="hljs-comment">--json-hide-pw hide passwords (default)</span>
<span class="hljs-comment">--json-unhide-pw unhide passwords</span>
Info:
additional information
-h, <span class="hljs-comment">--help show usage help message and exit</span>
-H, <span class="hljs-comment">--full-help show full help message and exit</span>
-v, <span class="hljs-comment">--verbose produce more output about what the program does</span>
-V, <span class="hljs-comment">--version show program's version number and exit</span>
Either argument -d &lt;host&gt; <span class="hljs-keyword">or</span> -f &lt;filename&gt; must be given.
</code></pre><h3 id="examples">Examples</h3>
<p>The most of the examples are for linux command line. Under Windows call the program using <code>python decode-config.py ...</code>.</p>
<h4 id="config-file">Config file</h4>
<p>Note: The example contains .ini style sections <code>[...]</code>. Sections are always treated as comment and serves as clarity only.
For further details of config file syntax see <a href="https://pypi.org/project/ConfigArgParse/">https://pypi.org/project/ConfigArgParse</a>.</p>
<p><em>my.conf</em></p>
<pre><code><span class="hljs-string">[Source]</span>
username = admin
password = myPaszxwo!z
<span class="hljs-string">[JSON]</span>
json-indent <span class="hljs-number">2</span>
</code></pre><h4 id="using-tasmota-binary-configuration-files">Using Tasmota binary configuration files</h4>
<ol>
<li><p>Restore a Tasmota configuration file</p>
<p> <code>decode-config.py -c my.conf -d sonoff --restore-file Config_Sonoff_6.2.1.dmp</code></p>
</li>
<li><p>Backup device using Tasmota configuration compatible format</p>
<p>a) use file extension to choice the file format</p>
<p> <code>decode-config.py -c my.conf -d sonoff --backup-file Config_@f_@v.dmp</code></p>
<p>b) use args to choice the file format</p>
<p> <code>decode-config.py -c my.conf -d sonoff --backup-type dmp --backup-file Config_@f_@v</code></p>
</li>
</ol>
<h4 id="use-batch-processing">Use batch processing</h4>
<pre><code><span class="hljs-keyword">for</span> device <span class="hljs-keyword">in</span> sonoff1 sonoff2 sonoff3; <span class="hljs-keyword">do</span> ./decode-config.py -c my.conf -d <span class="hljs-variable">$device</span> -o Config<span class="hljs-number">_</span><span class="hljs-variable">@f_</span><span class="hljs-variable">@v</span>
</code></pre><p>or under windows</p>
<pre><code><span class="hljs-keyword">for</span> device <span class="hljs-keyword">in</span> (sonoff1 sonoff2 sonoff3) <span class="hljs-keyword">do</span> <span class="hljs-keyword">python</span> decode-config.py -c my.conf -d %device -o Config_@f_@v
</code></pre><p>will produce JSON configuration files for host sonoff1, sonoff2 and sonoff3 using friendly name and Tasmota firmware version for backup filenames.</p>

253
tools/decode-config.md Normal file
View File

@ -0,0 +1,253 @@
# decode-config.py
_decode-config.py_ backup and restore Sonoff-Tasmota configuration.
Comparing backup files created by *decode-config.py* and *.dmp files created by Tasmota "Backup/Restore Configuration":
| &nbsp; | decode-config.py<br />*.json file | Sonoff-Tasmota<br />*.dmp file |
|-------------------------|:-------------------------------:|:-----------------------------------:|
| Encrypted | No | Yes |
| Readable | Yes | No |
| Simply editable | Yes | No |
| Simply batch processing | Yes | No |
_decode-config.py_ handles Tasmota configurations for release version since 5.10.0 up to now.
# Content
* [Prerequisite](decode-config.md#prerequisite)
* [File Types](decode-config.md#file-types)
* [.dmp File Format](decode-config.md#-dmp-file-format)
* [.json File Format](decode-config.md#-json-file-format)
* [.bin File Format](decode-config.md#-bin-file-format)
* [File extensions](decode-config.md#file-extensions)
* [Usage](decode-config.md#usage)
* [Basics](decode-config.md#basics)
* [Save backup file](decode-config.md#save-backup-file)
* [Restore backup file](decode-config.md#restore-backup-file)
* [Configuration file](decode-config.md#configuration-file)
* [More program arguments](decode-config.md#more-program-arguments)
* [Examples](decode-config.md#examples)
* [Config file](decode-config.md#config-file)
* [Using Tasmota binary configuration files](decode-config.md#using-tasmota-binary-configuration-files)
* [Use batch processing](decode-config.md#use-batch-processing)
## Prerequisite
* [Python](https://en.wikipedia.org/wiki/Python_(programming_language))
This program is written in [Python](https://en.wikipedia.org/wiki/Python_(programming_language)) so you need to install a python environment (for details see [Python Setup and Usage](https://docs.python.org/2.7/using/index.html))
* [Sonoff-Tasmota](https://github.com/arendst/Sonoff-Tasmota) [Firmware](https://github.com/arendst/Sonoff-Tasmota/releases) with enabled Web-Server
To backup or restore configurations from/to a Sonoff-Tasmota device you need a firmare with enabled web-server in admin mode (command [WebServer 2](https://github.com/arendst/Sonoff-Tasmota/wiki/Commands#wifi)).
<br />Only self compiled firmware may do not have a web-server sod if you use your own compiled firmware be aware to enable the web-server, otherwise you can only use the `--file` parameter as source.
## File Types
_decode-config.py_ can handle the following backup file types:
### .dmp Format
Configuration data as used by Tasmota "Backup/Restore Configuration" web interface.
This format is binary and encrypted.
### .json Format
Configuration data in [JSON](http://www.json.org/)-format.
This format is decrypted, human readable and editable and can also be used for the `--restore-file` command.
This file will becreated by _decode-config.py_ using `--backup-file` with `--backup-type json` parameter (default).
### .bin Format
Configuration data in binary format.
This format is binary decryptet, editable (e.g. using a hex editor) and can also be used for `--restore-file` command.
It will be created by _decode-config.py_ using `--backup-file` with `--backup-type bin`.
Note:
This file is 4 byte longer than an original .dmp file due to an prefix header at the beginning. The file data starting at address position 4 are containing the same as the **struct SYSCFG** from Tasmota [settings.h](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/settings.h) in decrypted format.
#### File extensions
_decode-config.py_ uses auto extension as default for backup filenames; you don't need to append extensions to your backup file, it will be selected based on `--backup-type` argument.
If you want using your own extension use the `--no-extension` argument.
## Usage
After download don't forget to set exec flag under linux with `chmod +x decode-config.py` or call the program using `python decode-config.py...`.
### Basics
At least pass a source where you want to read the configuration data from using `-f <filename>` or `-d <host>`:
The source can be either
* a Tasmota device hostname or IP by passing it using the `-d <host>` arg
* or a previously stored Tasmota *.dmp` configuration file by passing the filename using `-f <filename>` arg
Example:
decode-config.py -d sonoff-4281
will output a human readable configuration in [JSON](http://www.json.org/)-format:
{
"altitude": 112,
"baudrate": 115200,
"blinkcount": 10,
"blinktime": 10,
...
"ws_width": [
1,
3,
5
]
}
### Save backup file
To save the output as backup file `--backup-file <filename>`, you can use placeholder for Version, Friendlyname and Hostname:
decode-config.py -d sonoff-4281 --backup-file Config_@f_@v
If you have setup a WebPassword within Tasmota, use
decode-config.py -d sonoff-4281 -p <yourpassword> --backup-file Config_@f_@v
will create a file like `Config_Sonoff_x.x.x.json`. Because it is in JSON format, you can read and edit the file with any raw text editor.
### Restore backup file
Reading back a saved (and possible changed) backup file use the `--restore-file <filename>` arg. This will read the (changed) configuration data from this file and send it back to the source device or filename.
To restore the previously save backup file `Config_Sonoff_6.2.1.json` to device `sonoff-4281` use:
decode-config.py -d sonoff-4281 --restore-file Config_Sonoff_6.2.1.json
with password set by WebPassword:
decode-config.py -d sonoff-4281 -p <yourpassword> --restore-file Config_Sonoff_6.2.1.json
### Configuration file
Each argument that start with `--` (eg. `--file`) can also be set in a config file (specified via -c). Config file syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at [https://pypi.org/project/ConfigArgParse](https://pypi.org/project/ConfigArgParse/)).
If an argument is specified in more than one place, then commandline values override config file values which override defaults. This is usefull if you always use the same argument or a basic set of arguments.
The http authentication credentials `--username` and `--password` is predestinated to store it in a file instead using it on your command line as argument:
e.g. my.conf:
[source]
username = admin
password = myPaszxwo!z
To make a backup file from example above you can now pass the config file instead using the password on command line:
decode-config.py -d sonoff-4281 -c my.conf --backup-file Config_@f_@v
### More program arguments
For better reading your porgram arguments each short written arg (minus sign `-`) has a corresponding readable long version (two minus signs `--`), eg. `--device` for `-d` or `--file` for `-f` (note: not even all `--` arg has a corresponding `-` one).
A short list of possible program args is displayed using `-h` or `--help`.
For advanced help use `-H` or `--full-help`:
usage: decode-config.py [-f <filename>] [-d <host>] [-P <port>]
[-u <username>] [-p <password>] [-i <filename>]
[-o <filename>] [-F json|bin|dmp] [-E] [-e]
[--json-indent <indent>] [--json-compact]
[--json-hide-pw] [--json-unhide-pw] [-h] [-H] [-v]
[-V] [-c <filename>] [--ignore-warnings]
Backup/Restore Sonoff-Tasmota configuration data. Args that start with '--'
(eg. -f) can also be set in a config file (specified via -c). Config file
syntax allows: key=value, flag=true, stuff=[a,b,c] (for details, see syntax at
https://goo.gl/R74nmi). If an arg is specified in more than one place, then
commandline values override config file values which override defaults.
optional arguments:
-c, --config <filename>
program config file - can be used to set default
command args (default: None)
--ignore-warnings do not exit on warnings. Not recommended, used by your
own responsibility!
Source:
Read/Write Tasmota configuration from/to
-f, --file, --tasmota-file <filename>
file to retrieve/write Tasmota configuration from/to
(default: None)'
-d, --device, --host <host>
hostname or IP address to retrieve/send Tasmota
configuration from/to (default: None)
-P, --port <port> TCP/IP port number to use for the host connection
(default: 80)
-u, --username <username>
host HTTP access username (default: admin)
-p, --password <password>
host HTTP access password (default: None)
Backup/Restore:
Backup/Restore configuration file specification
-i, --restore-file <filename>
file to restore configuration from (default: None).
Replacements: @v=firmware version, @f=device friendly
name, @h=device hostname
-o, --backup-file <filename>
file to backup configuration to (default: None).
Replacements: @v=firmware version, @f=device friendly
name, @h=device hostname
-F, --backup-type json|bin|dmp
backup filetype (default: 'json')
-E, --extension append filetype extension for -i and -o filename
(default)
-e, --no-extension do not append filetype extension, use -i and -o
filename as passed
JSON:
JSON backup format specification
--json-indent <indent>
pretty-printed JSON output using indent level
(default: 'None'). -1 disables indent.
--json-compact compact JSON output by eliminate whitespace
--json-hide-pw hide passwords (default)
--json-unhide-pw unhide passwords
Info:
additional information
-h, --help show usage help message and exit
-H, --full-help show full help message and exit
-v, --verbose produce more output about what the program does
-V, --version show program's version number and exit
Either argument -d <host> or -f <filename> must be given.
### Examples
The most of the examples are for linux command line. Under Windows call the program using `python decode-config.py ...`.
#### Config file
Note: The example contains .ini style sections `[...]`. Sections are always treated as comment and serves as clarity only.
For further details of config file syntax see [https://pypi.org/project/ConfigArgParse](https://pypi.org/project/ConfigArgParse/).
*my.conf*
[Source]
username = admin
password = myPaszxwo!z
[JSON]
json-indent 2
#### Using Tasmota binary configuration files
1. Restore a Tasmota configuration file
`decode-config.py -c my.conf -d sonoff --restore-file Config_Sonoff_6.2.1.dmp`
2. Backup device using Tasmota configuration compatible format
a) use file extension to choice the file format
`decode-config.py -c my.conf -d sonoff --backup-file Config_@f_@v.dmp`
b) use args to choice the file format
`decode-config.py -c my.conf -d sonoff --backup-type dmp --backup-file Config_@f_@v`
#### Use batch processing
for device in sonoff1 sonoff2 sonoff3; do ./decode-config.py -c my.conf -d $device -o Config_@f_@v
or under windows
for device in (sonoff1 sonoff2 sonoff3) do python decode-config.py -c my.conf -d %device -o Config_@f_@v
will produce JSON configuration files for host sonoff1, sonoff2 and sonoff3 using friendly name and Tasmota firmware version for backup filenames.

File diff suppressed because it is too large Load Diff