Merge pull request #4075 from digiblur/development

Initial Tuya Dimmer Support
This commit is contained in:
Theo Arends 2018-10-16 09:46:16 +02:00 committed by GitHub
commit cd9987111e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 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 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 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
/********************************************************************************************/
@ -350,6 +352,23 @@ 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);
}
@ -2215,6 +2234,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()
{
while (Serial.available()) {
@ -2243,6 +2304,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)) {
@ -2252,33 +2336,33 @@ void SerialInput()
}
/*-------------------------------------------------------------------------------------------*/
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 (TUYA_DIMMER != Settings.module) {
if (serial_in_byte > 127 && !Settings.flag.mqtt_serial_raw) { // binary data...
serial_in_byte_counter = 0;
Serial.flush();
return;
}
} 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;
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;
}
}
}
}
/*-------------------------------------------------------------------------------------------*\
* Sonoff SC 19200 baud serial interface
\*-------------------------------------------------------------------------------------------*/
@ -2307,23 +2391,34 @@ void SerialInput()
}
}
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 (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]);
}
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
// XdrvRulesProcess();
snprintf_P(log_data, sizeof(log_data), PSTR("%s\""), log_data);
AddLog(LOG_LEVEL_DEBUG);
TuyaPacketProcess();
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);
}
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
// XdrvRulesProcess();
serial_in_byte_counter = 0;
}
}
}
/********************************************************************************************/
void GpioSwitchPinMode(uint8_t index)
@ -2465,6 +2560,11 @@ 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

@ -241,6 +241,7 @@ enum SupportedModules {
OBI,
TECKIN,
APLIC_WDP303075,
TUYA_DIMMER,
MAXMODULE };
/********************************************************************************************/
@ -418,7 +419,8 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
AILIGHT, // Light Bulbs
PHILIPS,
WITTY, // Development Devices
WEMOS
WEMOS,
TUYA_DIMMER
};
// Default module settings
@ -1133,6 +1135,15 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off)
GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On )
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.
}
// *************** 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()
@ -359,7 +390,7 @@ void LightInit()
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
}
if (SONOFF_LED == Settings.module) { // Fix Sonoff Led instabilities
@ -391,6 +422,9 @@ void LightInit()
max_scheme = LS_MAX + WS2812_SCHEMES;
}
#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];
@ -821,6 +855,9 @@ void LightAnimate()
if (light_type > LT_WS2812) {
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]);
}
}
}
}