diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 36de9f29c..c54e2199d 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -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 diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index eb99cc2a1..8acbc8db5 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -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}; diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index a5dbcef4e..edb9253fb 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -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; } diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index b7d591801..ad2a44e6b 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -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 } }; diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 1d66a92c4..32fbaa8ca 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -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 \*********************************************************************************************/ diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index a4f58ae67..c5ba2acc7 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -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 } } } diff --git a/sonoff/xdrv_16_tuyadimmer.ino b/sonoff/xdrv_16_tuyadimmer.ino new file mode 100644 index 000000000..cb5c31038 --- /dev/null +++ b/sonoff/xdrv_16_tuyadimmer.ino @@ -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 . +*/ + +#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 \ No newline at end of file