mirror of https://github.com/arendst/Tasmota.git
BLM certify part 2
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT - Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
This commit is contained in:
parent
4e3b547657
commit
c533eb1186
|
@ -59,6 +59,8 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
|
|||
- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]``
|
||||
- Change Energy JSON ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]``
|
||||
- Change ESP32 USER GPIO template representation decreasing template message size
|
||||
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
|
||||
- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
|
||||
- Fix escape of non-JSON received serial data (#8329)
|
||||
- Add command ``Rule0`` to change global rule parameters
|
||||
- Add command ``Time 4`` to display timestamp using milliseconds (#8537)
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
- Add library to be used for decoding Teleinfo (French Metering Smart Meter)
|
||||
- Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
|
||||
- Change ESP32 USER GPIO template representation decreasing template message size
|
||||
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
|
||||
- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
|
||||
|
||||
### 8.3.1.5 20200616
|
||||
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "Hibernation"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Esclave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Esclave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Esclave Rst"
|
||||
#define D_SENSOR_CLIENT_TX "Esclave TX"
|
||||
#define D_SENSOR_CLIENT_RX "Esclave RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Esclave Rst"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 - DATI"
|
||||
#define D_SENSOR_DEEPSLEEP "Deep sleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS - Abilita"
|
||||
#define D_SENSOR_SLAVE_TX "Slave - TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave - RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave - RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client - TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client - RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client - RST"
|
||||
#define D_SENSOR_GPS_RX "GPS - RX"
|
||||
#define D_SENSOR_GPS_TX "GPS - TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 - RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "Głęboko uśpiony"
|
||||
#define D_SENSOR_EXS_ENABLE "Załącz EXS"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -663,9 +663,9 @@
|
|||
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
|
||||
#define D_SENSOR_DEEPSLEEP "DeepSleep"
|
||||
#define D_SENSOR_EXS_ENABLE "EXS Enable"
|
||||
#define D_SENSOR_SLAVE_TX "Slave TX"
|
||||
#define D_SENSOR_SLAVE_RX "Slave RX"
|
||||
#define D_SENSOR_SLAVE_RESET "Slave RST"
|
||||
#define D_SENSOR_CLIENT_TX "Client TX"
|
||||
#define D_SENSOR_CLIENT_RX "Client RX"
|
||||
#define D_SENSOR_CLIENT_RESET "Client RST"
|
||||
#define D_SENSOR_GPS_RX "GPS RX"
|
||||
#define D_SENSOR_GPS_TX "GPS TX"
|
||||
#define D_SENSOR_HM10_RX "HM10 RX"
|
||||
|
|
|
@ -596,9 +596,9 @@
|
|||
// #define USE_FLOG // Add support for GPS logging in OTA's Flash (Experimental) (+2k9 code, +8 bytes RAM)
|
||||
//#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge (+9k3 code)
|
||||
//#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
|
||||
//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
|
||||
#define USE_TASMOTA_SLAVE_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
|
||||
#define USE_TASMOTA_SLAVE_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
|
||||
//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
|
||||
#define USE_TASMOTA_CLIENT_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
|
||||
#define USE_TASMOTA_CLIENT_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
|
||||
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
|
||||
|
||||
// -- Power monitoring sensors --------------------
|
||||
|
|
|
@ -1620,8 +1620,8 @@ void I2cScan(char *devs, unsigned int devs_len)
|
|||
// Return error codes defined in twi.h and core_esp8266_si2c.c
|
||||
// I2C_OK 0
|
||||
// I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover
|
||||
// I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time
|
||||
// I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits
|
||||
// I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond client clock stretch time
|
||||
// I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by client/another_master after n bits
|
||||
// I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master?
|
||||
|
||||
uint8_t error = 0;
|
||||
|
|
|
@ -477,8 +477,8 @@ void GetFeatures(void)
|
|||
#ifdef USE_EXS_DIMMER
|
||||
feature5 |= 0x00008000; // xdrv_30_exs_dimmer.ino
|
||||
#endif
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
feature5 |= 0x00010000; // xdrv_31_arduino_slave.ino
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
feature5 |= 0x00010000; // xdrv_31_tasmota_client.ino
|
||||
#endif
|
||||
#ifdef USE_HIH6
|
||||
feature5 |= 0x00020000; // xsns_55_hih_series.ino
|
||||
|
|
|
@ -152,7 +152,7 @@
|
|||
#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
|
||||
//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
|
||||
#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
|
||||
//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
|
||||
//#define USE_MCP9808 // Add support for MCP9808 temperature sensor (+0k9 code)
|
||||
//#define USE_HP303B // Add support for HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
|
||||
|
@ -383,7 +383,7 @@
|
|||
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
|
||||
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
|
||||
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
|
||||
#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
|
||||
|
||||
//#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
|
||||
|
@ -488,7 +488,7 @@
|
|||
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
|
||||
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
|
||||
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
|
||||
#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
|
||||
|
||||
//#undef USE_ENERGY_SENSOR // Disable energy sensors
|
||||
|
@ -615,7 +615,7 @@
|
|||
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
|
||||
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
|
||||
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
|
||||
#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
|
||||
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
|
||||
|
||||
#undef USE_ENERGY_SENSOR // Disable energy sensors
|
||||
|
|
|
@ -69,6 +69,18 @@ String EthernetMacAddress(void);
|
|||
#ifdef USE_EMULATION_WEMO
|
||||
#define USE_EMULATION
|
||||
#endif
|
||||
|
||||
// Convert legacy slave to client
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
#define USE_TASMOTA_CLIENT
|
||||
#endif
|
||||
#ifdef USE_TASMOTA_SLAVE_FLASH_SPEED
|
||||
#define USE_TASMOTA_CLIENT_FLASH_SPEED USE_TASMOTA_SLAVE_FLASH_SPEED
|
||||
#endif
|
||||
#ifdef USE_TASMOTA_SLAVE_SERIAL_SPEED
|
||||
#define USE_TASMOTA_CLIENT_SERIAL_SPEED USE_TASMOTA_SLAVE_SERIAL_SPEED
|
||||
#endif
|
||||
|
||||
// See https://github.com/esp8266/Arduino/pull/4889
|
||||
#undef NO_EXTRA_4K_HEAP // Allocate 4k heap for WPS in ESP8166/Arduino core v2.4.2 (was always allocated in previous versions)
|
||||
|
||||
|
|
|
@ -137,8 +137,8 @@ enum UserSelectablePins {
|
|||
GPIO_TUYA_RX, // Tuya Serial interface
|
||||
GPIO_MGC3130_XFER, // MGC3130 Transfer
|
||||
GPIO_MGC3130_RESET, // MGC3130 Reset
|
||||
GPIO_SSPI_MISO, // Software SPI Master Input Slave Output
|
||||
GPIO_SSPI_MOSI, // Software SPI Master Output Slave Input
|
||||
GPIO_SSPI_MISO, // Software SPI Master Input Client Output
|
||||
GPIO_SSPI_MOSI, // Software SPI Master Output Client Input
|
||||
GPIO_SSPI_SCLK, // Software SPI Serial Clock
|
||||
GPIO_SSPI_CS, // Software SPI Chip Select
|
||||
GPIO_SSPI_DC, // Software SPI Data or Command
|
||||
|
@ -210,10 +210,10 @@ enum UserSelectablePins {
|
|||
GPIO_SM2135_DAT, // SM2135 Dat
|
||||
GPIO_DEEPSLEEP, // Kill switch for deepsleep
|
||||
GPIO_EXS_ENABLE, // EXS MCU Enable
|
||||
GPIO_TASMOTASLAVE_TXD, // Slave TX
|
||||
GPIO_TASMOTASLAVE_RXD, // Slave RX
|
||||
GPIO_TASMOTASLAVE_RST, // Slave Reset Pin
|
||||
GPIO_TASMOTASLAVE_RST_INV, // Slave Reset Inverted
|
||||
GPIO_TASMOTACLIENT_TXD, // Client TX
|
||||
GPIO_TASMOTACLIENT_RXD, // Client RX
|
||||
GPIO_TASMOTACLIENT_RST, // Client Reset Pin
|
||||
GPIO_TASMOTACLIENT_RST_INV, // Client Reset Inverted
|
||||
GPIO_HPMA_RX, // Honeywell HPMA115S0 Serial interface
|
||||
GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface
|
||||
GPIO_GPS_RX, // GPS serial interface
|
||||
|
@ -317,7 +317,7 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
|
||||
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
|
||||
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
|
||||
D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "i|"
|
||||
D_SENSOR_CLIENT_TX "|" D_SENSOR_CLIENT_RX "|" D_SENSOR_CLIENT_RESET "|" D_SENSOR_CLIENT_RESET "i|"
|
||||
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
|
||||
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX "|"
|
||||
D_SENSOR_DS18X20 "o|" D_SENSOR_DHT11 "o|"
|
||||
|
@ -432,8 +432,8 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
|||
#ifdef USE_SPI
|
||||
GPIO_SPI_CS, // SPI Chip Select
|
||||
GPIO_SPI_DC, // SPI Data Direction
|
||||
GPIO_SSPI_MISO, // Software SPI Master Input Slave Output
|
||||
GPIO_SSPI_MOSI, // Software SPI Master Output Slave Input
|
||||
GPIO_SSPI_MISO, // Software SPI Master Input Client Output
|
||||
GPIO_SSPI_MOSI, // Software SPI Master Output Client Input
|
||||
GPIO_SSPI_SCLK, // Software SPI Serial Clock
|
||||
GPIO_SSPI_CS, // Software SPI Chip Select
|
||||
GPIO_SSPI_DC, // Software SPI Data or Command
|
||||
|
@ -630,11 +630,11 @@ const uint8_t kGpioNiceList[] PROGMEM = {
|
|||
GPIO_PN532_TXD, // PN532 HSU Tx
|
||||
GPIO_PN532_RXD, // PN532 HSU Rx
|
||||
#endif
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
GPIO_TASMOTASLAVE_TXD, // Tasmota Slave TX
|
||||
GPIO_TASMOTASLAVE_RXD, // Tasmota Slave RX
|
||||
GPIO_TASMOTASLAVE_RST, // Tasmota Slave Reset
|
||||
GPIO_TASMOTASLAVE_RST_INV, // Tasmota Slave Reset Inverted
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
GPIO_TASMOTACLIENT_TXD, // Tasmota Client TX
|
||||
GPIO_TASMOTACLIENT_RXD, // Tasmota Client RX
|
||||
GPIO_TASMOTACLIENT_RST, // Tasmota Client Reset
|
||||
GPIO_TASMOTACLIENT_RST_INV, // Tasmota Client Reset Inverted
|
||||
#endif
|
||||
#ifdef USE_RDM6300
|
||||
GPIO_RDM6300_RX,
|
||||
|
|
|
@ -102,8 +102,8 @@ enum UserSelectablePins {
|
|||
GPIO_SM2135_CLK, GPIO_SM2135_DAT, // SM2135 PWM controller
|
||||
GPIO_DEEPSLEEP, // Kill switch for deepsleep
|
||||
GPIO_EXS_ENABLE, // EXS MCU Enable
|
||||
GPIO_TASMOTASLAVE_TXD, GPIO_TASMOTASLAVE_RXD, // Slave Serial interface
|
||||
GPIO_TASMOTASLAVE_RST, GPIO_TASMOTASLAVE_RST_INV, // Slave Reset
|
||||
GPIO_TASMOTACLIENT_TXD, GPIO_TASMOTACLIENT_RXD, // Client Serial interface
|
||||
GPIO_TASMOTACLIENT_RST, GPIO_TASMOTACLIENT_RST_INV, // Client Reset
|
||||
GPIO_HPMA_RX, GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface
|
||||
GPIO_GPS_RX, GPIO_GPS_TX, // GPS Serial interface
|
||||
GPIO_HM10_RX, GPIO_HM10_TX, // HM10-BLE-Mijia-bridge Serial interface
|
||||
|
@ -200,7 +200,7 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
|
||||
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
|
||||
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
|
||||
D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "_i|"
|
||||
D_SENSOR_CLIENT_TX "|" D_SENSOR_CLIENT_RX "|" D_SENSOR_CLIENT_RESET "|" D_SENSOR_CLIENT_RESET "_i|"
|
||||
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
|
||||
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX "|"
|
||||
D_SENSOR_HM10_RX "|" D_SENSOR_HM10_TX "|"
|
||||
|
@ -271,8 +271,8 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
AGPIO(GPIO_SPI_CLK), // SPI Clk
|
||||
AGPIO(GPIO_SPI_CS), // SPI Chip Select
|
||||
AGPIO(GPIO_SPI_DC), // SPI Data Direction
|
||||
AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Slave Output
|
||||
AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Slave Input
|
||||
AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Client Output
|
||||
AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Client Input
|
||||
AGPIO(GPIO_SSPI_SCLK), // Software SPI Serial Clock
|
||||
AGPIO(GPIO_SSPI_CS), // Software SPI Chip Select
|
||||
AGPIO(GPIO_SSPI_DC), // Software SPI Data or Command
|
||||
|
@ -473,11 +473,11 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
AGPIO(GPIO_PN532_TXD), // PN532 HSU Tx
|
||||
AGPIO(GPIO_PN532_RXD), // PN532 HSU Rx
|
||||
#endif
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
AGPIO(GPIO_TASMOTASLAVE_TXD), // Tasmota Slave TX
|
||||
AGPIO(GPIO_TASMOTASLAVE_RXD), // Tasmota Slave RX
|
||||
AGPIO(GPIO_TASMOTASLAVE_RST), // Tasmota Slave Reset
|
||||
AGPIO(GPIO_TASMOTASLAVE_RST_INV), // Tasmota Slave Reset Inverted
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
AGPIO(GPIO_TASMOTACLIENT_TXD), // Tasmota Client TX
|
||||
AGPIO(GPIO_TASMOTACLIENT_RXD), // Tasmota Client RX
|
||||
AGPIO(GPIO_TASMOTACLIENT_RST), // Tasmota Client Reset
|
||||
AGPIO(GPIO_TASMOTACLIENT_RST_INV), // Tasmota Client Reset Inverted
|
||||
#endif
|
||||
#ifdef USE_RDM6300
|
||||
AGPIO(GPIO_RDM6300_RX),
|
||||
|
|
|
@ -44,7 +44,7 @@ const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 28000; // milliseconds - Allow
|
|||
uint8_t *efm8bb1_update = nullptr;
|
||||
#endif // USE_RF_FLASH
|
||||
|
||||
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTASLAVE };
|
||||
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT };
|
||||
|
||||
static const char * HEADER_KEYS[] = { "User-Agent", };
|
||||
|
||||
|
@ -2651,8 +2651,8 @@ void HandleUploadDone(void)
|
|||
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br>"), WebColor(COL_TEXT_SUCCESS));
|
||||
WSContentSend_P(HTTP_MSG_RSTRT);
|
||||
ShowWebSource(SRC_WEBGUI);
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
if (TasmotaSlave_GetFlagFlashing()) {
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
if (TasmotaClient_GetFlagFlashing()) {
|
||||
restart_flag = 0;
|
||||
} else { // It was a normal firmware file, or we are ready to restart device
|
||||
restart_flag = 2;
|
||||
|
@ -2665,9 +2665,9 @@ void HandleUploadDone(void)
|
|||
WSContentSend_P(PSTR("</div><br>"));
|
||||
WSContentSpaceButton(BUTTON_MAIN);
|
||||
WSContentStop();
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
if (TasmotaSlave_GetFlagFlashing()) {
|
||||
TasmotaSlave_Flash();
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
if (TasmotaClient_GetFlagFlashing()) {
|
||||
TasmotaClient_Flash();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -2737,11 +2737,11 @@ void HandleUploadLoop(void)
|
|||
if (Web.upload_error != 0) { return; }
|
||||
} else
|
||||
#endif // USE_RF_FLASH
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO SLAVE hex file
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO CLIENT hex file
|
||||
Update.end(); // End esp8266 update session
|
||||
Web.upload_file_type = UPL_TASMOTASLAVE;
|
||||
Web.upload_error = TasmotaSlave_UpdateInit(); // 0
|
||||
Web.upload_file_type = UPL_TASMOTACLIENT;
|
||||
Web.upload_error = TasmotaClient_UpdateInit(); // 0
|
||||
if (Web.upload_error != 0) { return; }
|
||||
} else
|
||||
#endif
|
||||
|
@ -2805,9 +2805,9 @@ void HandleUploadLoop(void)
|
|||
}
|
||||
}
|
||||
#endif // USE_RF_FLASH
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
else if (UPL_TASMOTASLAVE == Web.upload_file_type) {
|
||||
TasmotaSlave_WriteBuffer(upload.buf, upload.currentSize);
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
else if (UPL_TASMOTACLIENT == Web.upload_file_type) {
|
||||
TasmotaClient_WriteBuffer(upload.buf, upload.currentSize);
|
||||
}
|
||||
#endif
|
||||
else { // firmware
|
||||
|
@ -2871,10 +2871,10 @@ void HandleUploadLoop(void)
|
|||
Web.upload_file_type = UPL_TASMOTA;
|
||||
}
|
||||
#endif // USE_RF_FLASH
|
||||
#ifdef USE_TASMOTA_SLAVE
|
||||
else if (UPL_TASMOTASLAVE == Web.upload_file_type) {
|
||||
#ifdef USE_TASMOTA_CLIENT
|
||||
else if (UPL_TASMOTACLIENT == Web.upload_file_type) {
|
||||
// Done writing the hex to SPI flash
|
||||
TasmotaSlave_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart
|
||||
TasmotaClient_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart
|
||||
Web.upload_file_type = UPL_TASMOTA;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
xdrv_31_tasmota_client.ino - Support for external microcontroller on serial
|
||||
|
||||
Copyright (C) 2020 Andre Thomas 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_TASMOTA_CLIENT
|
||||
/*********************************************************************************************\
|
||||
* Tasmota to microcontroller
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_31 31
|
||||
|
||||
#define CONST_STK_CRC_EOP 0x20
|
||||
|
||||
#define CMND_STK_GET_SYNC 0x30
|
||||
#define CMND_STK_SET_DEVICE 0x42
|
||||
#define CMND_STK_SET_DEVICE_EXT 0x45
|
||||
#define CMND_STK_ENTER_PROGMODE 0x50
|
||||
#define CMND_STK_LEAVE_PROGMODE 0x51
|
||||
#define CMND_STK_LOAD_ADDRESS 0x55
|
||||
#define CMND_STK_PROG_PAGE 0x64
|
||||
|
||||
/*************************************************\
|
||||
* Tasmota Client Specific Commands
|
||||
\*************************************************/
|
||||
|
||||
#define CMND_START 0xFC
|
||||
#define CMND_END 0xFD
|
||||
|
||||
#define CMND_FEATURES 0x01
|
||||
#define CMND_JSON 0x02
|
||||
#define CMND_FUNC_EVERY_SECOND 0x03
|
||||
#define CMND_FUNC_EVERY_100_MSECOND 0x04
|
||||
#define CMND_CLIENT_SEND 0x05
|
||||
#define CMND_PUBLISH_TELE 0x06
|
||||
#define CMND_EXECUTE_CMND 0x07
|
||||
|
||||
#define PARAM_DATA_START 0xFE
|
||||
#define PARAM_DATA_END 0xFF
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
/*
|
||||
* Embedding class in here since its rather specific to Arduino bootloader
|
||||
*/
|
||||
|
||||
class SimpleHexParse {
|
||||
public:
|
||||
SimpleHexParse(void);
|
||||
uint8_t parseLine(char *hexline);
|
||||
uint8_t ptr_l = 0;
|
||||
uint8_t ptr_h = 0;
|
||||
bool PageIsReady = false;
|
||||
bool firstrun = true;
|
||||
bool EndOfFile = false;
|
||||
uint8_t FlashPage[128];
|
||||
uint8_t FlashPageIdx = 0;
|
||||
uint8_t layoverBuffer[16];
|
||||
uint8_t layoverIdx = 0;
|
||||
uint8_t getByte(char *hexline, uint8_t idx);
|
||||
};
|
||||
|
||||
SimpleHexParse::SimpleHexParse(void) {
|
||||
|
||||
}
|
||||
|
||||
uint8_t SimpleHexParse::parseLine(char *hexline) {
|
||||
if (layoverIdx) {
|
||||
memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx);
|
||||
FlashPageIdx = layoverIdx;
|
||||
layoverIdx = 0;
|
||||
}
|
||||
uint8_t len = getByte(hexline, 1);
|
||||
uint8_t addr_h = getByte(hexline, 2);
|
||||
uint8_t addr_l = getByte(hexline, 3);
|
||||
uint8_t rectype = getByte(hexline, 4);
|
||||
for (uint8_t idx = 0; idx < len; idx++) {
|
||||
if (FlashPageIdx < 128) {
|
||||
FlashPage[FlashPageIdx] = getByte(hexline, idx+5);
|
||||
FlashPageIdx++;
|
||||
} else { // We have layover bytes
|
||||
layoverBuffer[layoverIdx] = getByte(hexline, idx+5);
|
||||
layoverIdx++;
|
||||
}
|
||||
}
|
||||
if (1 == rectype) {
|
||||
EndOfFile = true;
|
||||
while (FlashPageIdx < 128) {
|
||||
FlashPage[FlashPageIdx] = 0xFF;
|
||||
FlashPageIdx++;
|
||||
}
|
||||
}
|
||||
if (FlashPageIdx == 128) {
|
||||
if (firstrun) {
|
||||
firstrun = false;
|
||||
} else {
|
||||
ptr_l += 0x40;
|
||||
if (ptr_l == 0) {
|
||||
ptr_l = 0;
|
||||
ptr_h++;
|
||||
}
|
||||
}
|
||||
firstrun = false;
|
||||
PageIsReady = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx) {
|
||||
char buff[3];
|
||||
buff[3] = '\0';
|
||||
memcpy(&buff, &hexline[(idx*2)-1], 2);
|
||||
return strtol(buff, 0, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* End of embedded class SimpleHexParse
|
||||
*/
|
||||
|
||||
struct TCLIENT {
|
||||
uint32_t spi_hex_size = 0;
|
||||
uint32_t spi_sector_counter = 0;
|
||||
uint8_t spi_sector_cursor = 0;
|
||||
uint8_t inverted = LOW;
|
||||
bool type = false;
|
||||
bool flashing = false;
|
||||
bool SerialEnabled = false;
|
||||
uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup
|
||||
bool unsupported = false;
|
||||
} TClient;
|
||||
|
||||
typedef union {
|
||||
uint32_t data;
|
||||
struct {
|
||||
uint32_t func_json_append : 1; // Client supports providing a JSON for TELEPERIOD
|
||||
uint32_t func_every_second : 1; // Client supports receiving a FUNC_EVERY_SECOND callback with no response
|
||||
uint32_t func_every_100_msecond : 1; // Client supports receiving a FUNC_EVERY_100_MSECOND callback with no response
|
||||
uint32_t func_client_send : 1; // Client supports receiving commands with "client send xxx"
|
||||
uint32_t spare4 : 1;
|
||||
uint32_t spare5 : 1;
|
||||
uint32_t spare6 : 1;
|
||||
uint32_t spare7 : 1;
|
||||
uint32_t spare8 : 1;
|
||||
uint32_t spare9 : 1;
|
||||
uint32_t spare10 : 1;
|
||||
uint32_t spare11 : 1;
|
||||
uint32_t spare12 : 1;
|
||||
uint32_t spare13 : 1;
|
||||
uint32_t spare14 : 1;
|
||||
uint32_t spare15 : 1;
|
||||
uint32_t spare16 : 1;
|
||||
uint32_t spare17 : 1;
|
||||
uint32_t spare18 : 1;
|
||||
uint32_t spare19 : 1;
|
||||
uint32_t spare20 : 1;
|
||||
uint32_t spare21 : 1;
|
||||
uint32_t spare22 : 1;
|
||||
uint32_t spare23 : 1;
|
||||
uint32_t spare24 : 1;
|
||||
uint32_t spare25 : 1;
|
||||
uint32_t spare26 : 1;
|
||||
uint32_t spare27 : 1;
|
||||
uint32_t spare28 : 1;
|
||||
uint32_t spare29 : 1;
|
||||
uint32_t spare30 : 1;
|
||||
uint32_t spare31 : 1;
|
||||
};
|
||||
} TClientFeatureCfg;
|
||||
|
||||
/*
|
||||
* The structure below must remain 4 byte aligned to be compatible with
|
||||
* Tasmota as master
|
||||
*/
|
||||
|
||||
struct TCLIENT_FEATURES {
|
||||
uint32_t features_version;
|
||||
TClientFeatureCfg features;
|
||||
} TClientSettings;
|
||||
|
||||
struct TCLIENT_COMMAND {
|
||||
uint8_t command;
|
||||
uint8_t parameter;
|
||||
uint8_t unused2;
|
||||
uint8_t unused3;
|
||||
} TClientCommand;
|
||||
|
||||
TasmotaSerial *TasmotaClient_Serial;
|
||||
|
||||
uint32_t TasmotaClient_FlashStart(void) {
|
||||
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_UpdateInit(void) {
|
||||
TClient.spi_hex_size = 0;
|
||||
TClient.spi_sector_counter = TasmotaClient_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored
|
||||
TClient.spi_sector_cursor = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TasmotaClient_Reset(void) {
|
||||
if (TClient.SerialEnabled) {
|
||||
digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), !TClient.inverted);
|
||||
delay(1);
|
||||
digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), TClient.inverted);
|
||||
delay(1);
|
||||
digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), !TClient.inverted);
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_waitForSerialData(int dataCount, int timeout) {
|
||||
int timer = 0;
|
||||
while (timer < timeout) {
|
||||
if (TasmotaClient_Serial->available() >= dataCount) {
|
||||
return 1;
|
||||
}
|
||||
delay(1);
|
||||
timer++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_sendBytes(uint8_t* bytes, int count) {
|
||||
TasmotaClient_Serial->write(bytes, count);
|
||||
TasmotaClient_waitForSerialData(2, 250);
|
||||
uint8_t sync = TasmotaClient_Serial->read();
|
||||
uint8_t ok = TasmotaClient_Serial->read();
|
||||
if ((sync == 0x14) && (ok == 0x10)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_execCmd(uint8_t cmd) {
|
||||
uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP };
|
||||
return TasmotaClient_sendBytes(bytes, 2);
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_execParam(uint8_t cmd, uint8_t* params, int count) {
|
||||
uint8_t bytes[32];
|
||||
bytes[0] = cmd;
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
bytes[i + 1] = params[i];
|
||||
i++;
|
||||
}
|
||||
bytes[i + 1] = CONST_STK_CRC_EOP;
|
||||
return TasmotaClient_sendBytes(bytes, i + 2);
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_exitProgMode(void) {
|
||||
return TasmotaClient_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_SetupFlash(void) {
|
||||
uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00};
|
||||
uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00};
|
||||
TasmotaClient_Serial->begin(USE_TASMOTA_CLIENT_FLASH_SPEED);
|
||||
if (TasmotaClient_Serial->hardwareSerial()) {
|
||||
ClaimSerial();
|
||||
}
|
||||
|
||||
TasmotaClient_Reset();
|
||||
|
||||
uint8_t timeout = 0;
|
||||
uint8_t no_error = 0;
|
||||
while (50 > timeout) {
|
||||
if (TasmotaClient_execCmd(CMND_STK_GET_SYNC)) {
|
||||
timeout = 200;
|
||||
no_error = 1;
|
||||
}
|
||||
timeout++;
|
||||
delay(1);
|
||||
}
|
||||
if (no_error) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Found bootloader"));
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Bootloader could not be found"));
|
||||
}
|
||||
if (no_error) {
|
||||
if (TasmotaClient_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) {
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Could not configure device for programming (1)"));
|
||||
}
|
||||
}
|
||||
if (no_error) {
|
||||
if (TasmotaClient_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) {
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Could not configure device for programming (2)"));
|
||||
}
|
||||
}
|
||||
if (no_error) {
|
||||
if (TasmotaClient_execCmd(CMND_STK_ENTER_PROGMODE)) {
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Failed to put bootloader into programming mode"));
|
||||
}
|
||||
}
|
||||
return no_error;
|
||||
}
|
||||
|
||||
uint8_t TasmotaClient_loadAddress(uint8_t adrHi, uint8_t adrLo) {
|
||||
uint8_t params[] = { adrLo, adrHi };
|
||||
return TasmotaClient_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params));
|
||||
}
|
||||
|
||||
void TasmotaClient_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data) {
|
||||
uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46};
|
||||
TasmotaClient_loadAddress(addr_h, addr_l);
|
||||
TasmotaClient_Serial->write(Header, 4);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
TasmotaClient_Serial->write(data[i]);
|
||||
}
|
||||
TasmotaClient_Serial->write(CONST_STK_CRC_EOP);
|
||||
TasmotaClient_waitForSerialData(2, 250);
|
||||
TasmotaClient_Serial->read();
|
||||
TasmotaClient_Serial->read();
|
||||
}
|
||||
|
||||
void TasmotaClient_Flash(void) {
|
||||
bool reading = true;
|
||||
uint32_t read = 0;
|
||||
uint32_t processed = 0;
|
||||
char thishexline[50];
|
||||
uint8_t position = 0;
|
||||
char* flash_buffer;
|
||||
|
||||
SimpleHexParse hexParse = SimpleHexParse();
|
||||
|
||||
if (!TasmotaClient_SetupFlash()) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Flashing aborted!"));
|
||||
TClient.flashing = false;
|
||||
restart_flag = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
flash_buffer = new char[SPI_FLASH_SEC_SIZE];
|
||||
uint32_t flash_start = TasmotaClient_FlashStart() * SPI_FLASH_SEC_SIZE;
|
||||
while (reading) {
|
||||
ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE);
|
||||
read = read + SPI_FLASH_SEC_SIZE;
|
||||
if (read >= TClient.spi_hex_size) {
|
||||
reading = false;
|
||||
}
|
||||
for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) {
|
||||
processed++;
|
||||
if ((processed <= TClient.spi_hex_size) && (!hexParse.EndOfFile)) {
|
||||
if (':' == flash_buffer[ca]) {
|
||||
position = 0;
|
||||
}
|
||||
if (0x0D == flash_buffer[ca]) {
|
||||
thishexline[position] = 0;
|
||||
hexParse.parseLine(thishexline);
|
||||
if (hexParse.PageIsReady) {
|
||||
TasmotaClient_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage);
|
||||
hexParse.PageIsReady = false;
|
||||
hexParse.FlashPageIdx = 0;
|
||||
}
|
||||
} else {
|
||||
if (0x0A != flash_buffer[ca]) {
|
||||
thishexline[position] = flash_buffer[ca];
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TasmotaClient_exitProgMode();
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Flash done!"));
|
||||
TClient.flashing = false;
|
||||
restart_flag = 2;
|
||||
}
|
||||
|
||||
void TasmotaClient_SetFlagFlashing(bool value) {
|
||||
TClient.flashing = value;
|
||||
}
|
||||
|
||||
bool TasmotaClient_GetFlagFlashing(void) {
|
||||
return TClient.flashing;
|
||||
}
|
||||
|
||||
void TasmotaClient_WriteBuffer(uint8_t *buf, size_t size) {
|
||||
if (0 == TClient.spi_sector_cursor) { // Starting a new sector write so we need to erase it first
|
||||
ESP.flashEraseSector(TClient.spi_sector_counter);
|
||||
}
|
||||
TClient.spi_sector_cursor++;
|
||||
ESP.flashWrite((TClient.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TClient.spi_sector_cursor-1)*2048), (uint32_t*)buf, size);
|
||||
TClient.spi_hex_size = TClient.spi_hex_size + size;
|
||||
if (2 == TClient.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
|
||||
TClient.spi_sector_cursor = 0;
|
||||
TClient.spi_sector_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaClient_Init(void) {
|
||||
if (TClient.type) {
|
||||
return;
|
||||
}
|
||||
if (10 > TClient.waitstate) {
|
||||
TClient.waitstate++;
|
||||
return;
|
||||
}
|
||||
if (!TClient.SerialEnabled) {
|
||||
if (PinUsed(GPIO_TASMOTACLIENT_RXD) && PinUsed(GPIO_TASMOTACLIENT_TXD) &&
|
||||
(PinUsed(GPIO_TASMOTACLIENT_RST) || PinUsed(GPIO_TASMOTACLIENT_RST_INV))) {
|
||||
TasmotaClient_Serial = new TasmotaSerial(Pin(GPIO_TASMOTACLIENT_RXD), Pin(GPIO_TASMOTACLIENT_TXD), 1, 0, 200);
|
||||
if (TasmotaClient_Serial->begin(USE_TASMOTA_CLIENT_SERIAL_SPEED)) {
|
||||
if (TasmotaClient_Serial->hardwareSerial()) {
|
||||
ClaimSerial();
|
||||
}
|
||||
TasmotaClient_Serial->setTimeout(100); // Theo 20200502 - increase from 50
|
||||
if (PinUsed(GPIO_TASMOTACLIENT_RST_INV)) {
|
||||
SetPin(Pin(GPIO_TASMOTACLIENT_RST_INV), GPIO_TASMOTACLIENT_RST);
|
||||
TClient.inverted = HIGH;
|
||||
}
|
||||
pinMode(Pin(GPIO_TASMOTACLIENT_RST), OUTPUT);
|
||||
TClient.SerialEnabled = true;
|
||||
TasmotaClient_Reset();
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TClient.SerialEnabled) { // All go for hardware now we need to detect features if there are any
|
||||
TasmotaClient_sendCmnd(CMND_FEATURES, 0);
|
||||
char buffer[32] = { 0 };
|
||||
TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer));
|
||||
uint8_t len = TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer));
|
||||
|
||||
if (len) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)buffer, len); } // Theo 20200502 - DMP: 99 17 34 01 02 00 00 00
|
||||
|
||||
memcpy(&TClientSettings, &buffer, sizeof(TClientSettings));
|
||||
if (20191129 == TClientSettings.features_version) {
|
||||
TClient.type = true;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Version %u"), TClientSettings.features_version);
|
||||
} else {
|
||||
if ((!TClient.unsupported) && (TClientSettings.features_version > 0)) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Version %u not supported!"), TClientSettings.features_version);
|
||||
TClient.unsupported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaClient_Show(void) {
|
||||
if ((TClient.type) && (TClientSettings.features.func_json_append)) {
|
||||
char buffer[100];
|
||||
TasmotaClient_sendCmnd(CMND_JSON, 0);
|
||||
TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1);
|
||||
uint8_t len = TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1);
|
||||
buffer[len] = '\0';
|
||||
ResponseAppend_P(PSTR(",\"TasmotaClient\":%s"), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaClient_sendCmnd(uint8_t cmnd, uint8_t param) {
|
||||
TClientCommand.command = cmnd;
|
||||
TClientCommand.parameter = param;
|
||||
char buffer[sizeof(TClientCommand)+2];
|
||||
buffer[0] = CMND_START;
|
||||
memcpy(&buffer[1], &TClientCommand, sizeof(TClientCommand));
|
||||
buffer[sizeof(TClientCommand)+1] = CMND_END;
|
||||
|
||||
TasmotaClient_Serial->flush(); // Theo 20200502
|
||||
|
||||
for (uint8_t ca = 0; ca < sizeof(buffer); ca++) {
|
||||
TasmotaClient_Serial->write(buffer[ca]);
|
||||
}
|
||||
}
|
||||
|
||||
#define D_PRFX_CLIENT "Client"
|
||||
#define D_CMND_CLIENT_RESET "Reset"
|
||||
#define D_CMND_CLIENT_SEND "Send"
|
||||
|
||||
const char kTasmotaClientCommands[] PROGMEM = D_PRFX_CLIENT "|"
|
||||
D_CMND_CLIENT_RESET "|" D_CMND_CLIENT_SEND;
|
||||
|
||||
void (* const TasmotaClientCommand[])(void) PROGMEM = {
|
||||
&CmndClientReset, &CmndClientSend };
|
||||
|
||||
void CmndClientReset(void) {
|
||||
TasmotaClient_Reset();
|
||||
TClient.type = false; // Force redetection
|
||||
TClient.waitstate = 7; // give it at least 3 seconds to restart from bootloader
|
||||
TClient.unsupported = false; // Reset unsupported flag
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void CmndClientSend(void) {
|
||||
if (0 < XdrvMailbox.data_len) {
|
||||
TasmotaClient_sendCmnd(CMND_CLIENT_SEND, XdrvMailbox.data_len);
|
||||
TasmotaClient_Serial->write(char(PARAM_DATA_START));
|
||||
for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) {
|
||||
TasmotaClient_Serial->write(XdrvMailbox.data[idx]);
|
||||
}
|
||||
TasmotaClient_Serial->write(char(PARAM_DATA_END));
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void TasmotaClient_ProcessIn(void) {
|
||||
uint8_t cmnd = TasmotaClient_Serial->read();
|
||||
if (CMND_START == cmnd) {
|
||||
TasmotaClient_waitForSerialData(sizeof(TClientCommand),50);
|
||||
uint8_t buffer[sizeof(TClientCommand)];
|
||||
for (uint8_t idx = 0; idx < sizeof(TClientCommand); idx++) {
|
||||
buffer[idx] = TasmotaClient_Serial->read();
|
||||
}
|
||||
TasmotaClient_Serial->read(); // read trailing byte of command
|
||||
memcpy(&TClientCommand, &buffer, sizeof(TClientCommand));
|
||||
char inbuf[TClientCommand.parameter+1];
|
||||
TasmotaClient_waitForSerialData(TClientCommand.parameter, 50);
|
||||
TasmotaClient_Serial->read(); // Read leading byte
|
||||
for (uint8_t idx = 0; idx < TClientCommand.parameter; idx++) {
|
||||
inbuf[idx] = TasmotaClient_Serial->read();
|
||||
}
|
||||
TasmotaClient_Serial->read(); // Read trailing byte
|
||||
inbuf[TClientCommand.parameter] = '\0';
|
||||
|
||||
if (CMND_PUBLISH_TELE == TClientCommand.command) { // We need to publish stat/ with incoming stream as content
|
||||
Response_P(PSTR("{\"TasmotaClient\":"));
|
||||
ResponseAppend_P("%s", inbuf);
|
||||
ResponseJsonEnd();
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
|
||||
XdrvRulesProcess();
|
||||
}
|
||||
if (CMND_EXECUTE_CMND == TClientCommand.command) { // We need to execute the incoming command
|
||||
ExecuteCommand(inbuf, SRC_IGNORE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv31(uint8_t function) {
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_EVERY_100_MSECOND:
|
||||
if (TClient.type) {
|
||||
if (TasmotaClient_Serial->available()) {
|
||||
TasmotaClient_ProcessIn();
|
||||
}
|
||||
if (TClientSettings.features.func_every_100_msecond) {
|
||||
TasmotaClient_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
if ((TClient.type) && (TClientSettings.features.func_every_second)) {
|
||||
TasmotaClient_sendCmnd(CMND_FUNC_EVERY_SECOND, 0);
|
||||
}
|
||||
TasmotaClient_Init();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
if ((TClient.type) && (TClientSettings.features.func_json_append)) {
|
||||
TasmotaClient_Show();
|
||||
}
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kTasmotaClientCommands, TasmotaClientCommand);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_TASMOTA_CLIENT
|
|
@ -1,615 +0,0 @@
|
|||
/*
|
||||
xdrv_31_tasmota_slave.ino - Support for external microcontroller slave on serial
|
||||
|
||||
Copyright (C) 2020 Andre Thomas 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_TASMOTA_SLAVE
|
||||
/*********************************************************************************************\
|
||||
* Tasmota slave
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_31 31
|
||||
|
||||
#define CONST_STK_CRC_EOP 0x20
|
||||
|
||||
#define CMND_STK_GET_SYNC 0x30
|
||||
#define CMND_STK_SET_DEVICE 0x42
|
||||
#define CMND_STK_SET_DEVICE_EXT 0x45
|
||||
#define CMND_STK_ENTER_PROGMODE 0x50
|
||||
#define CMND_STK_LEAVE_PROGMODE 0x51
|
||||
#define CMND_STK_LOAD_ADDRESS 0x55
|
||||
#define CMND_STK_PROG_PAGE 0x64
|
||||
|
||||
/*************************************************\
|
||||
* Tasmota Slave Specific Commands
|
||||
\*************************************************/
|
||||
|
||||
#define CMND_START 0xFC
|
||||
#define CMND_END 0xFD
|
||||
|
||||
#define CMND_FEATURES 0x01
|
||||
#define CMND_JSON 0x02
|
||||
#define CMND_FUNC_EVERY_SECOND 0x03
|
||||
#define CMND_FUNC_EVERY_100_MSECOND 0x04
|
||||
#define CMND_SLAVE_SEND 0x05
|
||||
#define CMND_PUBLISH_TELE 0x06
|
||||
#define CMND_EXECUTE_CMND 0x07
|
||||
|
||||
#define PARAM_DATA_START 0xFE
|
||||
#define PARAM_DATA_END 0xFF
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
/*
|
||||
* Embedding class in here since its rather specific to Arduino bootloader
|
||||
*/
|
||||
|
||||
class SimpleHexParse {
|
||||
public:
|
||||
SimpleHexParse(void);
|
||||
uint8_t parseLine(char *hexline);
|
||||
uint8_t ptr_l = 0;
|
||||
uint8_t ptr_h = 0;
|
||||
bool PageIsReady = false;
|
||||
bool firstrun = true;
|
||||
bool EndOfFile = false;
|
||||
uint8_t FlashPage[128];
|
||||
uint8_t FlashPageIdx = 0;
|
||||
uint8_t layoverBuffer[16];
|
||||
uint8_t layoverIdx = 0;
|
||||
uint8_t getByte(char *hexline, uint8_t idx);
|
||||
};
|
||||
|
||||
SimpleHexParse::SimpleHexParse(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint8_t SimpleHexParse::parseLine(char *hexline)
|
||||
{
|
||||
if (layoverIdx) {
|
||||
memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx);
|
||||
FlashPageIdx = layoverIdx;
|
||||
layoverIdx = 0;
|
||||
}
|
||||
uint8_t len = getByte(hexline, 1);
|
||||
uint8_t addr_h = getByte(hexline, 2);
|
||||
uint8_t addr_l = getByte(hexline, 3);
|
||||
uint8_t rectype = getByte(hexline, 4);
|
||||
for (uint8_t idx = 0; idx < len; idx++) {
|
||||
if (FlashPageIdx < 128) {
|
||||
FlashPage[FlashPageIdx] = getByte(hexline, idx+5);
|
||||
FlashPageIdx++;
|
||||
} else { // We have layover bytes
|
||||
layoverBuffer[layoverIdx] = getByte(hexline, idx+5);
|
||||
layoverIdx++;
|
||||
}
|
||||
}
|
||||
if (1 == rectype) {
|
||||
EndOfFile = true;
|
||||
while (FlashPageIdx < 128) {
|
||||
FlashPage[FlashPageIdx] = 0xFF;
|
||||
FlashPageIdx++;
|
||||
}
|
||||
}
|
||||
if (FlashPageIdx == 128) {
|
||||
if (firstrun) {
|
||||
firstrun = false;
|
||||
} else {
|
||||
ptr_l += 0x40;
|
||||
if (ptr_l == 0) {
|
||||
ptr_l = 0;
|
||||
ptr_h++;
|
||||
}
|
||||
}
|
||||
firstrun = false;
|
||||
PageIsReady = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx)
|
||||
{
|
||||
char buff[3];
|
||||
buff[3] = '\0';
|
||||
memcpy(&buff, &hexline[(idx*2)-1], 2);
|
||||
return strtol(buff, 0, 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* End of embedded class SimpleHexParse
|
||||
*/
|
||||
|
||||
struct TSLAVE {
|
||||
uint32_t spi_hex_size = 0;
|
||||
uint32_t spi_sector_counter = 0;
|
||||
uint8_t spi_sector_cursor = 0;
|
||||
uint8_t inverted = LOW;
|
||||
bool type = false;
|
||||
bool flashing = false;
|
||||
bool SerialEnabled = false;
|
||||
uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup
|
||||
bool unsupported = false;
|
||||
} TSlave;
|
||||
|
||||
typedef union {
|
||||
uint32_t data;
|
||||
struct {
|
||||
uint32_t func_json_append : 1; // Slave supports providing a JSON for TELEPERIOD
|
||||
uint32_t func_every_second : 1; // Slave supports receiving a FUNC_EVERY_SECOND callback with no response
|
||||
uint32_t func_every_100_msecond : 1; // Slave supports receiving a FUNC_EVERY_100_MSECOND callback with no response
|
||||
uint32_t func_slave_send : 1; // Slave supports receiving commands with "slave send xxx"
|
||||
uint32_t spare4 : 1;
|
||||
uint32_t spare5 : 1;
|
||||
uint32_t spare6 : 1;
|
||||
uint32_t spare7 : 1;
|
||||
uint32_t spare8 : 1;
|
||||
uint32_t spare9 : 1;
|
||||
uint32_t spare10 : 1;
|
||||
uint32_t spare11 : 1;
|
||||
uint32_t spare12 : 1;
|
||||
uint32_t spare13 : 1;
|
||||
uint32_t spare14 : 1;
|
||||
uint32_t spare15 : 1;
|
||||
uint32_t spare16 : 1;
|
||||
uint32_t spare17 : 1;
|
||||
uint32_t spare18 : 1;
|
||||
uint32_t spare19 : 1;
|
||||
uint32_t spare20 : 1;
|
||||
uint32_t spare21 : 1;
|
||||
uint32_t spare22 : 1;
|
||||
uint32_t spare23 : 1;
|
||||
uint32_t spare24 : 1;
|
||||
uint32_t spare25 : 1;
|
||||
uint32_t spare26 : 1;
|
||||
uint32_t spare27 : 1;
|
||||
uint32_t spare28 : 1;
|
||||
uint32_t spare29 : 1;
|
||||
uint32_t spare30 : 1;
|
||||
uint32_t spare31 : 1;
|
||||
};
|
||||
} TSlaveFeatureCfg;
|
||||
|
||||
/*
|
||||
* The structure below must remain 4 byte aligned to be compatible with
|
||||
* Tasmota as master
|
||||
*/
|
||||
|
||||
struct TSLAVE_FEATURES {
|
||||
uint32_t features_version;
|
||||
TSlaveFeatureCfg features;
|
||||
} TSlaveSettings;
|
||||
|
||||
struct TSLAVE_COMMAND {
|
||||
uint8_t command;
|
||||
uint8_t parameter;
|
||||
uint8_t unused2;
|
||||
uint8_t unused3;
|
||||
} TSlaveCommand;
|
||||
|
||||
TasmotaSerial *TasmotaSlave_Serial;
|
||||
|
||||
uint32_t TasmotaSlave_FlashStart(void)
|
||||
{
|
||||
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_UpdateInit(void)
|
||||
{
|
||||
TSlave.spi_hex_size = 0;
|
||||
TSlave.spi_sector_counter = TasmotaSlave_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored
|
||||
TSlave.spi_sector_cursor = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TasmotaSlave_Reset(void)
|
||||
{
|
||||
if (TSlave.SerialEnabled) {
|
||||
digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), !TSlave.inverted);
|
||||
delay(1);
|
||||
digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), TSlave.inverted);
|
||||
delay(1);
|
||||
digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), !TSlave.inverted);
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_waitForSerialData(int dataCount, int timeout)
|
||||
{
|
||||
int timer = 0;
|
||||
while (timer < timeout) {
|
||||
if (TasmotaSlave_Serial->available() >= dataCount) {
|
||||
return 1;
|
||||
}
|
||||
delay(1);
|
||||
timer++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_sendBytes(uint8_t* bytes, int count)
|
||||
{
|
||||
TasmotaSlave_Serial->write(bytes, count);
|
||||
TasmotaSlave_waitForSerialData(2, 250);
|
||||
uint8_t sync = TasmotaSlave_Serial->read();
|
||||
uint8_t ok = TasmotaSlave_Serial->read();
|
||||
if ((sync == 0x14) && (ok == 0x10)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_execCmd(uint8_t cmd)
|
||||
{
|
||||
uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP };
|
||||
return TasmotaSlave_sendBytes(bytes, 2);
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_execParam(uint8_t cmd, uint8_t* params, int count)
|
||||
{
|
||||
uint8_t bytes[32];
|
||||
bytes[0] = cmd;
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
bytes[i + 1] = params[i];
|
||||
i++;
|
||||
}
|
||||
bytes[i + 1] = CONST_STK_CRC_EOP;
|
||||
return TasmotaSlave_sendBytes(bytes, i + 2);
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_exitProgMode(void)
|
||||
{
|
||||
return TasmotaSlave_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_SetupFlash(void)
|
||||
{
|
||||
uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00};
|
||||
uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00};
|
||||
TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_FLASH_SPEED);
|
||||
if (TasmotaSlave_Serial->hardwareSerial()) {
|
||||
ClaimSerial();
|
||||
}
|
||||
|
||||
TasmotaSlave_Reset();
|
||||
|
||||
uint8_t timeout = 0;
|
||||
uint8_t no_error = 0;
|
||||
while (50 > timeout) {
|
||||
if (TasmotaSlave_execCmd(CMND_STK_GET_SYNC)) {
|
||||
timeout = 200;
|
||||
no_error = 1;
|
||||
}
|
||||
timeout++;
|
||||
delay(1);
|
||||
}
|
||||
if (no_error) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Found bootloader"));
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Bootloader could not be found"));
|
||||
}
|
||||
if (no_error) {
|
||||
if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) {
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (1)"));
|
||||
}
|
||||
}
|
||||
if (no_error) {
|
||||
if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) {
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (2)"));
|
||||
}
|
||||
}
|
||||
if (no_error) {
|
||||
if (TasmotaSlave_execCmd(CMND_STK_ENTER_PROGMODE)) {
|
||||
} else {
|
||||
no_error = 0;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Failed to put bootloader into programming mode"));
|
||||
}
|
||||
}
|
||||
return no_error;
|
||||
}
|
||||
|
||||
uint8_t TasmotaSlave_loadAddress(uint8_t adrHi, uint8_t adrLo)
|
||||
{
|
||||
uint8_t params[] = { adrLo, adrHi };
|
||||
return TasmotaSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params));
|
||||
}
|
||||
|
||||
void TasmotaSlave_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data)
|
||||
{
|
||||
uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46};
|
||||
TasmotaSlave_loadAddress(addr_h, addr_l);
|
||||
TasmotaSlave_Serial->write(Header, 4);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
TasmotaSlave_Serial->write(data[i]);
|
||||
}
|
||||
TasmotaSlave_Serial->write(CONST_STK_CRC_EOP);
|
||||
TasmotaSlave_waitForSerialData(2, 250);
|
||||
TasmotaSlave_Serial->read();
|
||||
TasmotaSlave_Serial->read();
|
||||
}
|
||||
|
||||
void TasmotaSlave_Flash(void)
|
||||
{
|
||||
bool reading = true;
|
||||
uint32_t read = 0;
|
||||
uint32_t processed = 0;
|
||||
char thishexline[50];
|
||||
uint8_t position = 0;
|
||||
char* flash_buffer;
|
||||
|
||||
SimpleHexParse hexParse = SimpleHexParse();
|
||||
|
||||
if (!TasmotaSlave_SetupFlash()) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flashing aborted!"));
|
||||
TSlave.flashing = false;
|
||||
restart_flag = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
flash_buffer = new char[SPI_FLASH_SEC_SIZE];
|
||||
uint32_t flash_start = TasmotaSlave_FlashStart() * SPI_FLASH_SEC_SIZE;
|
||||
while (reading) {
|
||||
ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE);
|
||||
read = read + SPI_FLASH_SEC_SIZE;
|
||||
if (read >= TSlave.spi_hex_size) {
|
||||
reading = false;
|
||||
}
|
||||
for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) {
|
||||
processed++;
|
||||
if ((processed <= TSlave.spi_hex_size) && (!hexParse.EndOfFile)) {
|
||||
if (':' == flash_buffer[ca]) {
|
||||
position = 0;
|
||||
}
|
||||
if (0x0D == flash_buffer[ca]) {
|
||||
thishexline[position] = 0;
|
||||
hexParse.parseLine(thishexline);
|
||||
if (hexParse.PageIsReady) {
|
||||
TasmotaSlave_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage);
|
||||
hexParse.PageIsReady = false;
|
||||
hexParse.FlashPageIdx = 0;
|
||||
}
|
||||
} else {
|
||||
if (0x0A != flash_buffer[ca]) {
|
||||
thishexline[position] = flash_buffer[ca];
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TasmotaSlave_exitProgMode();
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flash done!"));
|
||||
TSlave.flashing = false;
|
||||
restart_flag = 2;
|
||||
}
|
||||
|
||||
void TasmotaSlave_SetFlagFlashing(bool value)
|
||||
{
|
||||
TSlave.flashing = value;
|
||||
}
|
||||
|
||||
bool TasmotaSlave_GetFlagFlashing(void)
|
||||
{
|
||||
return TSlave.flashing;
|
||||
}
|
||||
|
||||
void TasmotaSlave_WriteBuffer(uint8_t *buf, size_t size)
|
||||
{
|
||||
if (0 == TSlave.spi_sector_cursor) { // Starting a new sector write so we need to erase it first
|
||||
ESP.flashEraseSector(TSlave.spi_sector_counter);
|
||||
}
|
||||
TSlave.spi_sector_cursor++;
|
||||
ESP.flashWrite((TSlave.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TSlave.spi_sector_cursor-1)*2048), (uint32_t*)buf, size);
|
||||
TSlave.spi_hex_size = TSlave.spi_hex_size + size;
|
||||
if (2 == TSlave.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
|
||||
TSlave.spi_sector_cursor = 0;
|
||||
TSlave.spi_sector_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaSlave_Init(void)
|
||||
{
|
||||
if (TSlave.type) {
|
||||
return;
|
||||
}
|
||||
if (10 > TSlave.waitstate) {
|
||||
TSlave.waitstate++;
|
||||
return;
|
||||
}
|
||||
if (!TSlave.SerialEnabled) {
|
||||
if (PinUsed(GPIO_TASMOTASLAVE_RXD) && PinUsed(GPIO_TASMOTASLAVE_TXD) &&
|
||||
(PinUsed(GPIO_TASMOTASLAVE_RST) || PinUsed(GPIO_TASMOTASLAVE_RST_INV))) {
|
||||
TasmotaSlave_Serial = new TasmotaSerial(Pin(GPIO_TASMOTASLAVE_RXD), Pin(GPIO_TASMOTASLAVE_TXD), 1, 0, 200);
|
||||
if (TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_SERIAL_SPEED)) {
|
||||
if (TasmotaSlave_Serial->hardwareSerial()) {
|
||||
ClaimSerial();
|
||||
}
|
||||
TasmotaSlave_Serial->setTimeout(100); // Theo 20200502 - increase from 50
|
||||
if (PinUsed(GPIO_TASMOTASLAVE_RST_INV)) {
|
||||
SetPin(Pin(GPIO_TASMOTASLAVE_RST_INV), GPIO_TASMOTASLAVE_RST);
|
||||
TSlave.inverted = HIGH;
|
||||
}
|
||||
pinMode(Pin(GPIO_TASMOTASLAVE_RST), OUTPUT);
|
||||
TSlave.SerialEnabled = true;
|
||||
TasmotaSlave_Reset();
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TSlave.SerialEnabled) { // All go for hardware now we need to detect features if there are any
|
||||
TasmotaSlave_sendCmnd(CMND_FEATURES, 0);
|
||||
char buffer[32] = { 0 };
|
||||
TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer));
|
||||
uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer));
|
||||
|
||||
if (len) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)buffer, len); } // Theo 20200502 - DMP: 99 17 34 01 02 00 00 00
|
||||
|
||||
memcpy(&TSlaveSettings, &buffer, sizeof(TSlaveSettings));
|
||||
if (20191129 == TSlaveSettings.features_version) {
|
||||
TSlave.type = true;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u"), TSlaveSettings.features_version);
|
||||
} else {
|
||||
if ((!TSlave.unsupported) && (TSlaveSettings.features_version > 0)) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u not supported!"), TSlaveSettings.features_version);
|
||||
TSlave.unsupported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaSlave_Show(void)
|
||||
{
|
||||
if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) {
|
||||
char buffer[100];
|
||||
TasmotaSlave_sendCmnd(CMND_JSON, 0);
|
||||
TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1);
|
||||
uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1);
|
||||
buffer[len] = '\0';
|
||||
ResponseAppend_P(PSTR(",\"TasmotaSlave\":%s"), buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void TasmotaSlave_sendCmnd(uint8_t cmnd, uint8_t param)
|
||||
{
|
||||
TSlaveCommand.command = cmnd;
|
||||
TSlaveCommand.parameter = param;
|
||||
char buffer[sizeof(TSlaveCommand)+2];
|
||||
buffer[0] = CMND_START;
|
||||
memcpy(&buffer[1], &TSlaveCommand, sizeof(TSlaveCommand));
|
||||
buffer[sizeof(TSlaveCommand)+1] = CMND_END;
|
||||
|
||||
TasmotaSlave_Serial->flush(); // Theo 20200502
|
||||
|
||||
for (uint8_t ca = 0; ca < sizeof(buffer); ca++) {
|
||||
TasmotaSlave_Serial->write(buffer[ca]);
|
||||
}
|
||||
}
|
||||
|
||||
#define D_PRFX_SLAVE "Slave"
|
||||
#define D_CMND_SLAVE_RESET "Reset"
|
||||
#define D_CMND_SLAVE_SEND "Send"
|
||||
|
||||
const char kTasmotaSlaveCommands[] PROGMEM = D_PRFX_SLAVE "|"
|
||||
D_CMND_SLAVE_RESET "|" D_CMND_SLAVE_SEND;
|
||||
|
||||
void (* const TasmotaSlaveCommand[])(void) PROGMEM = {
|
||||
&CmndTasmotaSlaveReset, &CmndTasmotaSlaveSend };
|
||||
|
||||
void CmndTasmotaSlaveReset(void)
|
||||
{
|
||||
TasmotaSlave_Reset();
|
||||
TSlave.type = false; // Force redetection
|
||||
TSlave.waitstate = 7; // give it at least 3 seconds to restart from bootloader
|
||||
TSlave.unsupported = false; // Reset unsupported flag
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void CmndTasmotaSlaveSend(void)
|
||||
{
|
||||
if (0 < XdrvMailbox.data_len) {
|
||||
TasmotaSlave_sendCmnd(CMND_SLAVE_SEND, XdrvMailbox.data_len);
|
||||
TasmotaSlave_Serial->write(char(PARAM_DATA_START));
|
||||
for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) {
|
||||
TasmotaSlave_Serial->write(XdrvMailbox.data[idx]);
|
||||
}
|
||||
TasmotaSlave_Serial->write(char(PARAM_DATA_END));
|
||||
}
|
||||
ResponseCmndDone();
|
||||
}
|
||||
|
||||
void TasmotaSlave_ProcessIn(void)
|
||||
{
|
||||
uint8_t cmnd = TasmotaSlave_Serial->read();
|
||||
switch (cmnd) {
|
||||
case CMND_START:
|
||||
TasmotaSlave_waitForSerialData(sizeof(TSlaveCommand),50);
|
||||
uint8_t buffer[sizeof(TSlaveCommand)];
|
||||
for (uint8_t idx = 0; idx < sizeof(TSlaveCommand); idx++) {
|
||||
buffer[idx] = TasmotaSlave_Serial->read();
|
||||
}
|
||||
TasmotaSlave_Serial->read(); // read trailing byte of command
|
||||
memcpy(&TSlaveCommand, &buffer, sizeof(TSlaveCommand));
|
||||
char inbuf[TSlaveCommand.parameter+1];
|
||||
TasmotaSlave_waitForSerialData(TSlaveCommand.parameter, 50);
|
||||
TasmotaSlave_Serial->read(); // Read leading byte
|
||||
for (uint8_t idx = 0; idx < TSlaveCommand.parameter; idx++) {
|
||||
inbuf[idx] = TasmotaSlave_Serial->read();
|
||||
}
|
||||
TasmotaSlave_Serial->read(); // Read trailing byte
|
||||
inbuf[TSlaveCommand.parameter] = '\0';
|
||||
|
||||
if (CMND_PUBLISH_TELE == TSlaveCommand.command) { // We need to publish stat/ with incoming stream as content
|
||||
Response_P(PSTR("{\"TasmotaSlave\":"));
|
||||
ResponseAppend_P("%s", inbuf);
|
||||
ResponseJsonEnd();
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
|
||||
XdrvRulesProcess();
|
||||
}
|
||||
if (CMND_EXECUTE_CMND == TSlaveCommand.command) { // We need to execute the incoming command
|
||||
ExecuteCommand(inbuf, SRC_IGNORE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv31(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_EVERY_100_MSECOND:
|
||||
if (TSlave.type) {
|
||||
if (TasmotaSlave_Serial->available()) {
|
||||
TasmotaSlave_ProcessIn();
|
||||
}
|
||||
if (TSlaveSettings.features.func_every_100_msecond) {
|
||||
TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
if ((TSlave.type) && (TSlaveSettings.features.func_every_second)) {
|
||||
TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_SECOND, 0);
|
||||
}
|
||||
TasmotaSlave_Init();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) {
|
||||
TasmotaSlave_Show();
|
||||
}
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kTasmotaSlaveCommands, TasmotaSlaveCommand);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_TASMOTA_SLAVE
|
|
@ -127,15 +127,15 @@ void FifLEEvery250ms(void)
|
|||
} else {
|
||||
Energy.data_valid[0] = 0;
|
||||
|
||||
// SA=Slave Address, FC=Function Code, BC=Byte Count, B3..B0=Data byte, Ch Cl = crc16 checksum
|
||||
// CA=Client Address, FC=Function Code, BC=Byte Count, B3..B0=Data byte, Ch Cl = crc16 checksum
|
||||
// U32 registers:
|
||||
// 00 01 02 03 04 05 06 07 08
|
||||
// SA FC BC B3 B2 B1 B0 Cl Ch
|
||||
// CA FC BC B3 B2 B1 B0 Cl Ch
|
||||
// 01 03 04 00 00 00 72 7A 16 = REG[B3..B2=0x0139,B1..B0=0x013A] 114 = 0.114 A
|
||||
// 01 03 04 00 00 00 B0 FB 87 = REG[B3..B2=0xA01E,B1..B0=0xA01F] 176 = 1.76 kvarh
|
||||
// U16/S16 registers:
|
||||
// 00 01 02 03 04 05 06
|
||||
// SA FC BC B1 B0 Cl Ch
|
||||
// CA FC BC B1 B0 Cl Ch
|
||||
// 01 03 02 5B 02 02 B5 = REG[B1..B0=0x0131] 23298 = 232.98 V
|
||||
// 01 03 02 03 E8 B8 FA = REG[B1..B0=0x0158] 1000 = 1.000 (power factor)
|
||||
// there are 3 data types used:
|
||||
|
|
Loading…
Reference in New Issue