Rewrite Tuya Dimmer code

Rewrite Tuya Dimmer code
This commit is contained in:
Theo Arends 2018-10-18 13:01:31 +02:00
parent f8ab8ef552
commit d1c807998f
7 changed files with 330 additions and 186 deletions

View File

@ -3,6 +3,7 @@
* Update TasmotaModbus and TasmotaSerial libraries for support of serial 8N2 communication
* Add support for Pzem-003/017 DC Energy monitoring module (#3694)
* Change support for Pzem-014/016 AC Energy monitoring module (#3694)
* Rewrite Tuya Dimmer code
*
* 6.2.1.16 20181015
* Add TasmotaModbus library for very basic modbus wrapper for TasmotaSerial

View File

@ -202,7 +202,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED };
enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER };
enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8};
enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_TUYA_DIMMER_ID, P_MAX_PARAM8};
enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_AIRQUALITY, DZ_MAX_SENSORS};
@ -212,7 +212,7 @@ enum LightTypes {LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6,
enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC};
enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD,
enum XsnsFunctions {FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD,
FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR,
FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, FUNC_WEB_ADD_HANDLER};

View File

@ -200,8 +200,6 @@ char mqtt_data[MESSZ]; // MQTT publish buffer and web page
char log_data[LOGSZ]; // Logging
char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
String backlog[MAX_BACKLOG]; // Command backlog
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
/********************************************************************************************/
@ -342,9 +340,11 @@ void SetDevicePower(power_t rpower, int source)
}
XdrvMailbox.index = rpower;
XdrvCall(FUNC_SET_POWER);
XdrvMailbox.payload = source;
if (XdrvCall(FUNC_SET_POWER)) {
if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
}
else if ((SONOFF_DUAL == Settings.module) || (CH4 == Settings.module)) {
Serial.write(0xA0);
Serial.write(0x04);
Serial.write(rpower &0xFF);
@ -352,23 +352,6 @@ void SetDevicePower(power_t rpower, int source)
Serial.write('\n');
Serial.flush();
}
else if (TUYA_DIMMER == Settings.module && source != SRC_SWITCH ) { // ignore to prevent loop from pushing state from faceplate interaction
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: SetDevicePower.rpower=%d"), rpower);
AddLog(LOG_LEVEL_DEBUG);
Serial.write(0x55); // Tuya header 55AA
Serial.write(0xAA);
Serial.write(0x00); // version 00
Serial.write(0x06); // Tuya command 06
Serial.write(0x00);
Serial.write(0x05); // following data length 0x05
Serial.write(0x01); // relay number 1,2,3
Serial.write(0x01);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(rpower); // status
Serial.write(0x0D + rpower); // checksum sum of all bytes in packet mod 256
Serial.flush();
}
else if (EXS_RELAY == Settings.module) {
SetLatchingRelay(rpower, 1);
}
@ -770,19 +753,16 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
}
else { // SetOption32 .. 49
/*
uint8_t param_low = 0;
uint8_t param_high = 255;
switch (pindex) {
case P_HOLD_TIME:
case P_MAX_POWER_RETRY:
if ((payload >= 1) && (payload <= 250)) {
Settings.param[pindex] = payload;
}
param_low = 1;
param_high = 250;
break;
default:
ptype = 99; // Command Error
}
*/
if ((payload >= 1) && (payload <= 250)) {
if ((payload >= param_low) && (payload <= param_high)) {
Settings.param[pindex] = payload;
}
}
@ -2234,48 +2214,6 @@ void ArduinoOTAInit()
/********************************************************************************************/
void TuyaPacketProcess()
{
char scmnd[20];
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Packet Size=%d"), serial_in_byte_counter);
AddLog(LOG_LEVEL_DEBUG);
if (serial_in_byte_counter == 7 && serial_in_buffer[3] == 14 ) { // heartbeat packet
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Heartbeat"));
}
if (serial_in_byte_counter == 12 && serial_in_buffer[3] == 7 && serial_in_buffer[5] == 5) { // on/off packet
if (serial_in_buffer[10] == 0) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Rcvd - Off State"));
ExecuteCommandPower(1, 0, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
} else
{
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: Rcvd - On State"));
ExecuteCommandPower(1, 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
}
serial_in_byte_counter = 0;
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
}
if (serial_in_byte_counter == 15 && serial_in_buffer[3] == 7 && serial_in_buffer[5] == 8) { // dim packet
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Rcvd Dim State=%d"), serial_in_buffer[13]);
AddLog(LOG_LEVEL_DEBUG);
tuya_new_dim = round(serial_in_buffer[13] * (100. / 255.));
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send CMND_DIMMER=%d"), tuya_new_dim );
AddLog(LOG_LEVEL_DEBUG);
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), tuya_new_dim );
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send CMND_DIMMER_STR=%s"), scmnd );
AddLog(LOG_LEVEL_DEBUG);
tuya_ignore_dim = true;
ExecuteCommand(scmnd, SRC_SWITCH);
serial_in_byte_counter = 0;
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
}
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
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: WiFi Reset Rcvd"));
serial_in_byte_counter = 0;
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
snprintf_P(scmnd, sizeof(scmnd), D_CMND_WIFICONFIG " 2");
ExecuteCommand(scmnd, SRC_BUTTON);
}
}
void SerialInput()
{
while (Serial.available()) {
@ -2304,29 +2242,6 @@ void SerialInput()
}
}
/*-------------------------------------------------------------------------------------------*\
* Tuya based Dimmer with Serial Communications to MCU dimmer at 9600 baud
\*-------------------------------------------------------------------------------------------*/
if (TUYA_DIMMER == Settings.module) {
if (serial_in_byte == '\x55') { // Start TUYA Packet
if (serial_in_byte_counter > 0 && serial_in_byte_counter < 11) {
TuyaPacketProcess();
}
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: 0x55 Packet Start"));
serial_in_byte_counter = 0;
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
// return; // test to see if we need this
} else { // read additional packets from TUYA
if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
serial_polling_window = millis();
// return; // test to see if we need this
} else {
serial_in_byte_counter = 0;
}
}
}
/*-------------------------------------------------------------------------------------------*/
if (XdrvCall(FUNC_SERIAL)) {
@ -2336,33 +2251,33 @@ void SerialInput()
}
/*-------------------------------------------------------------------------------------------*/
if (TUYA_DIMMER != Settings.module) {
if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data...
serial_in_byte_counter = 0;
Serial.flush();
return;
}
if (!Settings.flag.mqtt_serial) {
if (isprint(serial_in_byte)) {
if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
} else {
serial_in_byte_counter = 0;
}
if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data...
serial_in_byte_counter = 0;
Serial.flush();
return;
}
if (!Settings.flag.mqtt_serial) {
if (isprint(serial_in_byte)) {
if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
} else {
serial_in_byte_counter = 0;
}
} else {
if (serial_in_byte || Settings.flag.mqtt_serial_raw) {
if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) &&
((serial_in_byte != Settings.serial_delimiter) || Settings.flag.mqtt_serial_raw)) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
serial_polling_window = millis();
} else {
serial_polling_window = 0;
break;
}
}
} else {
if (serial_in_byte || Settings.flag.mqtt_serial_raw) {
if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) &&
((serial_in_byte != Settings.serial_delimiter) || Settings.flag.mqtt_serial_raw)) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
serial_polling_window = millis();
} else {
serial_polling_window = 0;
break;
}
}
}
/*-------------------------------------------------------------------------------------------*\
* Sonoff SC 19200 baud serial interface
\*-------------------------------------------------------------------------------------------*/
@ -2391,32 +2306,20 @@ void SerialInput()
}
}
if (TUYA_DIMMER == Settings.module && serial_in_byte_counter > 6 && (millis() > (serial_polling_window + SERIAL_POLLING))) {
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: 0x55 Packet End: \""));
for (int i = 0; i < serial_in_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\""), log_data);
AddLog(LOG_LEVEL_DEBUG);
TuyaPacketProcess();
if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) {
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
serial_in_byte_counter = 0;
} else {
if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) {
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
if (!Settings.flag.mqtt_serial_raw) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\""));
for (int i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%02x"), mqtt_data, serial_in_buffer[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}"), mqtt_data);
if (!Settings.flag.mqtt_serial_raw) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer);
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\""));
for (int i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%02x"), mqtt_data, serial_in_buffer[i]);
}
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
// XdrvRulesProcess();
serial_in_byte_counter = 0;
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"}"), mqtt_data);
}
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
// XdrvRulesProcess();
serial_in_byte_counter = 0;
}
}
/********************************************************************************************/
@ -2545,7 +2448,9 @@ void GpioInit()
baudrate = 19200;
}
if (SONOFF_DUAL == Settings.module) {
if (XdrvCall(FUNC_MODULE_INIT)) {
}
else if (SONOFF_DUAL == Settings.module) {
Settings.flag.mqtt_serial = 0;
devices_present = 2;
baudrate = 19200;
@ -2560,11 +2465,6 @@ void GpioInit()
devices_present = 0;
baudrate = 19200;
}
else if (TUYA_DIMMER == Settings.module) {
Settings.flag.mqtt_serial = 0;
baudrate = 9600;
light_type = LT_SERIAL;
}
else if (SONOFF_BN == Settings.module) { // PWM Single color led (White)
light_type = LT_PWM1;
}

View File

@ -1138,13 +1138,19 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
},
{ "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
0,
GPIO_TXD, // TX to dimmer MCU
0,
GPIO_RXD, // RX from dimmer MCU
0, 0,
GPIO_KEY1, // Virtual Button (controlled by MCU)
GPIO_TXD, // GPIO01 MCU serial control
GPIO_USER,
GPIO_RXD, // GPIO03 MCU serial control
GPIO_USER,
GPIO_USER,
0, 0, 0, 0, 0, 0, // Flash connection
0, 0, 0, 0, 0, 0
GPIO_USER,
GPIO_USER,
GPIO_LED1, // GPIO14 Green Led
GPIO_USER,
GPIO_USER,
0
}
};

View File

@ -378,6 +378,9 @@
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code)
#define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer
#define TUYA_DIMMER_ID 3 // Default dimmer Id
/*********************************************************************************************\
* Debug features are only supported in development branch
\*********************************************************************************************/

View File

@ -343,37 +343,6 @@ void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t dut
os_delay_us(12); // TStop > 12us.
}
// *************** Tuya Dimmer Serial Comms
void LightSerialDuty(uint8_t duty)
{
if (duty > 0 && !tuya_ignore_dim ) {
if (duty < 25) {
duty = 25; // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
}
Serial.write(0x55); // Tuya header 55AA
Serial.write(0xAA);
Serial.write(0x00); // version 00
Serial.write(0x06); // Tuya command 06 - send order
Serial.write(0x00);
Serial.write(0x08); // following data length 0x08
Serial.write(0x03); // dimmer id
Serial.write(0x02); // type=value
Serial.write(0x00); // length hi
Serial.write(0x04); // length low
Serial.write(0x00); //
Serial.write(0x00); //
Serial.write(0x00); //
Serial.write( duty ); // dim value (0-255)
Serial.write( byte(22 + duty) ); // checksum:sum of all bytes in packet mod 256
Serial.flush();
snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Serial Packet Dim Value=%d"), duty);
AddLog(LOG_LEVEL_DEBUG);
} else {
tuya_ignore_dim = false; // reset flag
snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Dim Level skipped due to 0 or already set. Value=%d"), duty);
AddLog(LOG_LEVEL_DEBUG);
}
}
/********************************************************************************************/
void LightInit()
@ -424,7 +393,7 @@ void LightInit()
#endif // USE_WS2812 ************************************************************************
else if (LT_SERIAL == light_type) {
light_subtype = LST_SINGLE;
}
}
else {
light_pdi_pin = pin[GPIO_DI];
light_pdcki_pin = pin[GPIO_DCKI];
@ -855,9 +824,11 @@ void LightAnimate()
if (light_type > LT_WS2812) {
LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
}
#ifdef USE_TUYA_DIMMER
if (light_type == LT_SERIAL) {
LightSerialDuty(cur_col[0]);
}
#endif // USE_TUYA_DIMMER
}
}
}

View File

@ -0,0 +1,263 @@
/*
xdrv_16_tuyadimmer.ino - Tuya dimmer support for Sonoff-Tasmota
Copyright (C) 2018 digiblur, Joel Stein 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_TUYA_DIMMER
#ifndef TUYA_DIMMER_ID
#define TUYA_DIMMER_ID 3
#endif
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
uint8_t tuya_cmd_status = 0; // Current status of serial-read
uint8_t tuya_cmd_checksum = 0; // Checksum of tuya command
uint8_t tuya_data_len = 0; // Data lenght of command
boolean TuyaSetPower()
{
boolean status = false;
uint8_t rpower = XdrvMailbox.index;
int16_t source = XdrvMailbox.payload;
if (source != SRC_SWITCH ) { // ignore to prevent loop from pushing state from faceplate interaction
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: SetDevicePower.rpower=%d"), rpower);
AddLog(LOG_LEVEL_DEBUG);
Serial.write(0x55); // Tuya header 55AA
Serial.write(0xAA);
Serial.write(0x00); // version 00
Serial.write(0x06); // Tuya command 06
Serial.write(0x00);
Serial.write(0x05); // following data length 0x05
Serial.write(0x01); // relay number 1,2,3
Serial.write(0x01);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(rpower); // status
Serial.write(0x0D + rpower); // checksum sum of all bytes in packet mod 256
Serial.flush();
status = true;
}
return status;
}
void LightSerialDuty(uint8_t duty)
{
if (duty > 0 && !tuya_ignore_dim ) {
if (duty < 25) {
duty = 25; // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
}
Serial.write(0x55); // Tuya header 55AA
Serial.write(0xAA);
Serial.write(0x00); // version 00
Serial.write(0x06); // Tuya command 06 - send order
Serial.write(0x00);
Serial.write(0x08); // following data length 0x08
Serial.write(Settings.param[P_TUYA_DIMMER_ID]); // dimmer id
Serial.write(0x02); // type=value
Serial.write(0x00); // length hi
Serial.write(0x04); // length low
Serial.write(0x00); //
Serial.write(0x00); //
Serial.write(0x00); //
Serial.write( 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
Serial.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]);
AddLog(LOG_LEVEL_DEBUG);
} else {
tuya_ignore_dim = false; // reset flag
snprintf_P(log_data, sizeof(log_data), PSTR( "TYA: Send Dim Level skipped due to 0 or already set. Value=%d"), duty);
AddLog(LOG_LEVEL_DEBUG);
}
}
void TuyaPacketProcess()
{
char scmnd[20];
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Packet Size=%d"), serial_in_byte_counter);
AddLog(LOG_LEVEL_DEBUG);
if (serial_in_byte_counter == 7 && serial_in_buffer[3] == 14 ) { // heartbeat packet
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
snprintf_P(log_data, sizeof(log_data),PSTR("TYA: Rcvd - %s State"),serial_in_buffer[10]?"On":"Off");
AddLog(LOG_LEVEL_DEBUG);
if((power || Settings.light_dimmer > 0) && (power != serial_in_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
}
}
else if (serial_in_byte_counter == 15 && serial_in_buffer[3] == 7 && serial_in_buffer[5] == 8) { // dim packet
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Rcvd Dim State=%d"), serial_in_buffer[13]);
AddLog(LOG_LEVEL_DEBUG);
tuya_new_dim = round(serial_in_buffer[13] * (100. / 255.));
if((power || !Settings.light_dimmer ) && (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 );
AddLog(LOG_LEVEL_DEBUG);
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), tuya_new_dim );
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: Send CMND_DIMMER_STR=%s"), scmnd );
AddLog(LOG_LEVEL_DEBUG);
tuya_ignore_dim = true;
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
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: WiFi Reset Rcvd"));
snprintf_P(scmnd, sizeof(scmnd), D_CMND_WIFICONFIG " 2");
ExecuteCommand(scmnd, SRC_BUTTON);
}
}
void TuyaSerialInput()
{
while (Serial.available()) {
yield();
serial_in_byte = Serial.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);
//AddLog(LOG_LEVEL_DEBUG);
if (serial_in_byte == 0x55) { // Start TUYA Packet
tuya_cmd_status = 1;
serial_in_buffer[serial_in_byte_counter++] = 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
tuya_cmd_status = 2;
AddLog_P(LOG_LEVEL_DEBUG, PSTR("TYA: 0x55AA Packet Start"));
serial_in_byte_counter = 0;
serial_in_buffer[serial_in_byte_counter++] = 0x55;
serial_in_buffer[serial_in_byte_counter++] = 0xAA;
tuya_cmd_checksum = 0xFF;
}
else if (tuya_cmd_status == 2){
if(serial_in_byte_counter == 5){ // Get length of data
tuya_cmd_status = 3;
tuya_data_len = serial_in_byte;
}
tuya_cmd_checksum += serial_in_byte;
serial_in_buffer[serial_in_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
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
snprintf_P(log_data, sizeof(log_data), PSTR("TYA: 0x55 Packet End: \""));
for (int i = 0; i < serial_in_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\""), log_data);
AddLog(LOG_LEVEL_DEBUG);
TuyaPacketProcess();
serial_in_byte_counter = 0;
tuya_cmd_status = 0;
tuya_cmd_checksum = 0;
tuya_data_len = 0;
} // read additional packets from TUYA
else if(serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
tuya_cmd_checksum += serial_in_byte;
} else {
serial_in_byte_counter = 0;
tuya_cmd_status = 0;
tuya_cmd_checksum = 0;
tuya_data_len = 0;
}
}
}
boolean TuyaModuleSelected()
{
baudrate = 9600;
light_type = LT_SERIAL;
return true;
}
void TuyaInit()
{
if (!Settings.param[P_TUYA_DIMMER_ID]) {
Settings.param[P_TUYA_DIMMER_ID] = TUYA_DIMMER_ID;
}
Serial.setDebugOutput(false);
ClaimSerial();
// Get current status of MCU
snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state");
AddLog(LOG_LEVEL_DEBUG);
Serial.write(0x55); // header 55AA
Serial.write(0xAA);
Serial.write(0x00); // version 00
Serial.write(0x08); // command 08 - get status
Serial.write(0x00);
Serial.write(0x00); // following data length 0x00
Serial.write(0x07); // checksum:sum of all bytes in packet mod 256
Serial.flush();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XDRV_16
boolean Xdrv16(byte function)
{
boolean result = false;
if (TUYA_DIMMER == Settings.module) {
switch (function) {
case FUNC_MODULE_INIT:
result = TuyaModuleSelected();
break;
case FUNC_INIT:
TuyaInit();
break;
case FUNC_LOOP:
TuyaSerialInput();
break;
case FUNC_SET_POWER:
result = TuyaSetPower();
break;
}
}
return result;
}
#endif // USE_TUYA_DIMMER