Initial TuyaDimmer Support

This commit is contained in:
digiblur 2018-10-15 18:32:14 -05:00
parent f5eb2919bd
commit 5894cd97fc
4 changed files with 187 additions and 39 deletions

View File

@ -208,7 +208,7 @@ enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, D
enum Ws2812ClockIndex { WS_SECOND, WS_MINUTE, WS_HOUR, WS_MARKER }; enum Ws2812ClockIndex { WS_SECOND, WS_MINUTE, WS_HOUR, WS_MARKER };
enum Ws2812Color { WS_RED, WS_GREEN, WS_BLUE }; enum Ws2812Color { WS_RED, WS_GREEN, WS_BLUE };
enum LightTypes {LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7, LT_NU8, LT_NU9, LT_NU10, LT_WS2812, LT_RGBW, LT_RGBWC}; enum LightTypes {LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7, LT_SERIAL, LT_NU9, LT_NU10, LT_WS2812, LT_RGBW, LT_RGBWC};
enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC}; 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 LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};

View File

@ -200,6 +200,8 @@ char mqtt_data[MESSZ]; // MQTT publish buffer and web page
char log_data[LOGSZ]; // Logging char log_data[LOGSZ]; // Logging
char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
String backlog[MAX_BACKLOG]; // Command backlog 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
/********************************************************************************************/ /********************************************************************************************/
@ -350,6 +352,23 @@ void SetDevicePower(power_t rpower, int source)
Serial.write('\n'); Serial.write('\n');
Serial.flush(); 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) { else if (EXS_RELAY == Settings.module) {
SetLatchingRelay(rpower, 1); SetLatchingRelay(rpower, 1);
} }
@ -2214,6 +2233,48 @@ 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() void SerialInput()
{ {
while (Serial.available()) { while (Serial.available()) {
@ -2242,6 +2303,29 @@ void SerialInput()
} }
} }
/*-------------------------------------------------------------------------------------------*\
* Tuya based Dimmer with Serial Communications to MCU dimmer
\*-------------------------------------------------------------------------------------------*/
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)) { if (XdrvCall(FUNC_SERIAL)) {
@ -2251,33 +2335,33 @@ void SerialInput()
} }
/*-------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------*/
if (TUYA_DIMMER != Settings.module) {
if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data... if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data...
serial_in_byte_counter = 0; serial_in_byte_counter = 0;
Serial.flush(); Serial.flush();
return; 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 (!Settings.flag.mqtt_serial) {
if (serial_in_byte || Settings.flag.mqtt_serial_raw) { if (isprint(serial_in_byte)) {
if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
((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_in_buffer[serial_in_byte_counter++] = serial_in_byte; } else {
serial_polling_window = millis(); serial_in_byte_counter = 0;
} 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 * Sonoff SC 19200 baud serial interface
\*-------------------------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------------------------*/
@ -2306,23 +2390,34 @@ void SerialInput()
} }
} }
if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) { if (TUYA_DIMMER == Settings.module && serial_in_byte_counter > 6 && (millis() > (serial_polling_window + SERIAL_POLLING))) {
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed snprintf_P(log_data, sizeof(log_data), PSTR("TYA: 0x55 Packet End: \""));
if (!Settings.flag.mqtt_serial_raw) { for (int i = 0; i < serial_in_byte_counter; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer); snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, serial_in_buffer[i]);
} 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);
} }
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED)); snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data);
// XdrvRulesProcess(); AddLog(LOG_LEVEL_DEBUG);
TuyaPacketProcess();
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
serial_in_byte_counter = 0; 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);
}
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
// XdrvRulesProcess();
serial_in_byte_counter = 0;
}
} }
} }
/********************************************************************************************/ /********************************************************************************************/
void GpioSwitchPinMode(uint8_t index) void GpioSwitchPinMode(uint8_t index)
@ -2464,6 +2559,11 @@ void GpioInit()
devices_present = 0; devices_present = 0;
baudrate = 19200; 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) else if (SONOFF_BN == Settings.module) { // PWM Single color led (White)
light_type = LT_PWM1; light_type = LT_PWM1;
} }

View File

@ -241,6 +241,7 @@ enum SupportedModules {
OBI, OBI,
TECKIN, TECKIN,
APLIC_WDP303075, APLIC_WDP303075,
TUYA_DIMMER,
MAXMODULE }; MAXMODULE };
/********************************************************************************************/ /********************************************************************************************/
@ -418,7 +419,8 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
AILIGHT, // Light Bulbs AILIGHT, // Light Bulbs
PHILIPS, PHILIPS,
WITTY, // Development Devices WITTY, // Development Devices
WEMOS WEMOS,
TUYA_DIMMER
}; };
// Default module settings // Default module settings
@ -1133,6 +1135,15 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off) GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off)
GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On ) GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On )
0, 0, 0 0, 0, 0
},
{ "Tuya Dimmer", // Tuya Dimmer (ESP8266 w/ separate MCU dimmer)
0,
GPIO_TXD, // TX to dimmer MCU
0,
GPIO_RXD, // RX from dimmer MCU
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0
} }
}; };

View File

@ -343,6 +343,37 @@ void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t dut
os_delay_us(12); // TStop > 12us. 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() void LightInit()
@ -359,7 +390,7 @@ void LightInit()
pinMode(pin[GPIO_PWM1 +i], OUTPUT); pinMode(pin[GPIO_PWM1 +i], OUTPUT);
} }
} }
if (LT_PWM1 == light_type) { if (LT_PWM1 == light_type || LT_SERIAL == light_type) {
Settings.light_color[0] = 255; // One PWM channel only supports Dimmer but needs max color Settings.light_color[0] = 255; // One PWM channel only supports Dimmer but needs max color
} }
if (SONOFF_LED == Settings.module) { // Fix Sonoff Led instabilities if (SONOFF_LED == Settings.module) { // Fix Sonoff Led instabilities
@ -391,6 +422,9 @@ void LightInit()
max_scheme = LS_MAX + WS2812_SCHEMES; max_scheme = LS_MAX + WS2812_SCHEMES;
} }
#endif // USE_WS2812 ************************************************************************ #endif // USE_WS2812 ************************************************************************
else if (LT_SERIAL == light_type) {
light_subtype = LST_SINGLE;
}
else { else {
light_pdi_pin = pin[GPIO_DI]; light_pdi_pin = pin[GPIO_DI];
light_pdcki_pin = pin[GPIO_DCKI]; light_pdcki_pin = pin[GPIO_DCKI];
@ -821,6 +855,9 @@ void LightAnimate()
if (light_type > LT_WS2812) { if (light_type > LT_WS2812) {
LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
} }
if (light_type == LT_SERIAL) {
LightSerialDuty(cur_col[0]);
}
} }
} }
} }