From 473892d5c925a0aef9975f299915d8f01b18391e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 1 Mar 2020 15:31:08 +0100 Subject: [PATCH] Add updated experimental Sonoff D1 support Add updated experimental Sonoff D1 support (#7598) --- tasmota/my_user_config.h | 2 +- tasmota/support_features.ino | 4 +- tasmota/tasmota_post.h | 10 ++ tasmota/tasmota_template.h | 4 +- tasmota/xdrv_37_sonoff_d1.ino | 225 ++++++++++++++++++++++++++++++++++ tools/decode-status.py | 2 +- 6 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 tasmota/xdrv_37_sonoff_d1.ino diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index b6300c9a4..77c0771ee 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -419,7 +419,7 @@ #define USE_PWM_DIMMER // Add support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) #define USE_PWM_DIMMER_REMOTE // Add support for remote switches to PWM Dimmer, also adds device groups support (+0k7 code, also includes device groups) //#define USE_KEELOQ // Add support for Jarolift rollers by Keeloq algorithm (+4k5 code) -//#define USE_SONOFF_D1 // Add support for Sonoff D1 +#define USE_SONOFF_D1 // Add support for Sonoff D1 Dimmer (+0k7 code) // -- Optional light modules ---------------------- #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index c37216c14..4049d9cfe 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -536,7 +536,9 @@ void GetFeatures(void) #ifdef USE_HRXL feature6 |= 0x00000002; // xsns_64_hrxl.ino #endif -// feature6 |= 0x00000004; +#ifdef USE_SONOFF_D1 + feature6 |= 0x00000004; +#endif // feature6 |= 0x00000008; // feature6 |= 0x00000010; diff --git a/tasmota/tasmota_post.h b/tasmota/tasmota_post.h index fd0183dc9..7cf0fff75 100644 --- a/tasmota/tasmota_post.h +++ b/tasmota/tasmota_post.h @@ -117,6 +117,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack #define USE_HOTPLUG // Add support for sensor HotPlug #undef USE_DEVICE_GROUPS // Disable support for device groups (+5k6 code) #undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +#define USE_SONOFF_D1 // Add support for Sonoff D1 Dimmer (+0k7 code) // -- Optional light modules ---------------------- #define USE_LIGHT // Add Dimmer/Light support @@ -305,6 +307,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack #undef USE_DEVICE_GROUPS // Disable support for device groups (+3k5 code) #undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) #undef USE_PWM_DIMMER_REMOTE // Disbale support for remote switches to PWM Dimmer +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) #undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code) #undef USE_PZEM004T // Disable PZEM004T energy sensor @@ -384,6 +388,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack #undef USE_DEVICE_GROUPS // Disable support for device groups (+3k5 code) #undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) #undef USE_PWM_DIMMER_REMOTE // Disbale support for remote switches to PWM Dimmer +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) // -- Optional light modules ---------------------- //#undef USE_LIGHT // Also disable all Dimmer/Light support @@ -495,6 +501,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack #undef USE_DEVICE_GROUPS // Disable support for device groups (+3k5 code) #undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) #undef USE_PWM_DIMMER_REMOTE // Disbale support for remote switches to PWM Dimmer +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +//#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) // -- Optional light modules ---------------------- //#undef USE_LIGHT // Also disable all Dimmer/Light support @@ -613,6 +621,8 @@ extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack #undef USE_DEVICE_GROUPS // Disable support for device groups (+3k5 code) #undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) #undef USE_PWM_DIMMER_REMOTE // Disbale support for remote switches to PWM Dimmer +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) // -- Optional light modules ---------------------- #undef USE_LIGHT // Disable support for lights diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index cdc976bb0..a45c456f8 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -2264,7 +2264,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO09 0, // GPIO10 // GPIO11 (SD_CMD Flash) - 0, 0, 0, 0, 0, 0 + 0, // GPIO12 + GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status + 0, 0, 0, 0 } }; diff --git a/tasmota/xdrv_37_sonoff_d1.ino b/tasmota/xdrv_37_sonoff_d1.ino new file mode 100644 index 000000000..b7f98c352 --- /dev/null +++ b/tasmota/xdrv_37_sonoff_d1.ino @@ -0,0 +1,225 @@ +/* + xdrv_37_sonoff_d1.ino - sonoff D1 dimmer support for Tasmota + + Copyright (C) 2020 Theo Arends and robbz23 (protocol analysis) + + 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_SONOFF_D1 +/*********************************************************************************************\ + * Sonoff D1 dimmer 433 + * + * 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 + * AA 55 - Header + * 01 04 - Version? + * 00 0A - Following data length (10 bytes) + * 01 - Power state (00 = off, 01 = on, FF = ignore) + * 64 - Dimmer percentage (01 to 64 = 1 to 100%) + * FF FF FF FF FF FF FF FF - Not used + * 6C - CRC over bytes 2 to F (Addition) + * + * Based on Gravitate1: + * When I switch the light ON via the app, I get: + * AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C + * + * When I switch it OFF, I get: + * AA 55 01 04 00 0A 00 64 FF FF FF FF FF FF FF FF 6B + * + * When I set it to 1%, I get: + * AA 55 01 04 00 0A FF 01 FF FF FF FF FF FF FF FF 07 + * AB 55 FD F7 FF FF F5 01 FF FF FF FF FF FF FF FF 09 + * + * When I set it to 6%, I get: + * AA 55 01 04 00 0A FF 06 FF FF FF FF FF FF FF FF 0C + * AB 55 FD F7 FF FF F5 06 FF FF FF FF FF FF FF FF 0E + * + * When I set it to 100%, I get: + * AA 55 01 04 00 0A FF 64 FF FF FF FF FF FF FF FF 6A + * AB 55 FD F7 FF FF F5 64 FF FF FF FF FF FF FF FF 6C + * + * Based on robbz23: + * 00:17:59 CMD: Baudrate 9600 + * 00:17:59 SER: Set to 8N1 9600 bit/s + * 00:17:59 RSL: stat/tasmota_D9E56D/RESULT = {"Baudrate":9600} + * + * 00:25:32 CMD: SerialSend5 aa 55 01 04 00 0a 01 22 ffffffffffffffff 29 + * 00:25:32 RSL: stat/tasmota_D9E56D/RESULT = {"SerialSend":"Done"} + * + * 00:26:35 CMD: SerialSend5 aa 55 01 04 00 0a 01 22 ffffffffffffffff 2a + * 00:26:35 RSL: stat/tasmota_D9E56D/RESULT = {"SerialSend":"Done"} + * 00:26:35 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 00 05} + * + * 00:28:58 CMD: SerialSend5 aa 55 01 04 00 0a 01 01 ffffffffffffffff 09 + * 00:28:58 RSL: stat/tasmota_D9E56D/RESULT = {"SerialSend":"Done"} + * 00:28:58 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 00 05} + * + * 00:29:12 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A 01 3C FF FF FF FF FF FF FF FF 44} + * 00:29:43 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A 01 01 FF FF FF FF FF FF FF FF 09} + * 00:29:53 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C} + * + * 00:30:02 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A FF 1E FF FF FF FF FF FF FF FF 24} +\*********************************************************************************************/ + +#define XDRV_37 37 + +struct SONOFFD1 { + uint8_t receive_flag = 0; + uint8_t dimmer; +} SnfD1; + +/********************************************************************************************/ + +void SonoffD1Received(void) +{ + char svalue[32]; + + uint8_t action = serial_in_buffer[6]; + uint8_t dimmer = serial_in_buffer[7]; + + if (action < 2) { + // AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C - Power On, Dimmer 100% + // AA 55 01 04 00 0A 00 64 FF FF FF FF FF FF FF FF 6B - Power Off, Dimmer 100% + bool is_switch_change = (action != power); + if (is_switch_change) { + ExecuteCommandPower(1, action, SRC_SWITCH); + } + } + else if (0xFF == action) { + SnfD1.dimmer = dimmer; + bool is_brightness_change = SnfD1.dimmer != Settings.light_dimmer; + if (power && (SnfD1.dimmer > 0) && is_brightness_change) { + char scmnd[20]; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), SnfD1.dimmer); + ExecuteCommand(scmnd, SRC_SWITCH); + } + } + + // Send Acknowledge - Copy first 5 bytes, reset byte 6 and store crc in byte 7 + // AA 55 01 04 00 00 05 + serial_in_buffer[5] = 0; // Ack + serial_in_buffer[6] = 0; // Crc + for (uint32_t i = 0; i < 7; i++) { + if ((i > 1) && (i < 6)) { serial_in_buffer[6] += serial_in_buffer[i]; } + Serial.write(serial_in_buffer[i]); + } +} + +bool SonoffD1SerialInput(void) +{ + uint8_t packet_length = 0; + + if (0xAA == serial_in_byte) { // 0xAA - Start of text + serial_in_byte_counter = 0; + SnfD1.receive_flag = true; + } + if (SnfD1.receive_flag) { + serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; + if (serial_in_byte_counter == 6) { + packet_length = 7 + serial_in_byte; // 8 or 17 + } + if (serial_in_byte_counter == packet_length) { + + // Sonoff D1 codes + // AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C - Power On, Dimmer 100% + // AA 55 01 04 00 0A 00 64 FF FF FF FF FF FF FF FF 6B - Power Off, Dimmer 100% + // AA 55 01 04 00 0A FF 01 FF FF FF FF FF FF FF FF 07 - Power ignore, Dimmer 1% + // AB 55 FD F7 FF FF F5 01 FF FF FF FF FF FF FF FF 09 - Response 2 + // AA 55 01 04 00 0A FF 06 FF FF FF FF FF FF FF FF 0C - Power ignore, Dimmer 6% + // AB 55 FD F7 FF FF F5 06 FF FF FF FF FF FF FF FF 0E - Response 2 + // AA 55 01 04 00 0A FF 64 FF FF FF FF FF FF FF FF 6A - Power ignore, Dimmer 100% + // AB 55 FD F7 FF FF F5 64 FF FF FF FF FF FF FF FF 6C - Response 2 + + AddLogSerial(LOG_LEVEL_DEBUG); + uint8_t crc = 0; + for (uint32_t i = 2; i < packet_length -1; i++) { + crc += serial_in_buffer[i]; + } + if (crc == serial_in_buffer[packet_length -1]) { + SonoffD1Received(); + SnfD1.receive_flag = false; + return true; + } + } + serial_in_byte = 0; + } + return false; +} + +/********************************************************************************************/ + +bool SonoffD1SendPower(void) +{ + uint8_t buffer[17] = { 0xAA,0x55,0x01,0x04,0x00,0x0A,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00 }; + + buffer[6] = XdrvMailbox.index; + + for (uint32_t i = 0; i < sizeof(buffer); i++) { + if ((i > 1) && (i < sizeof(buffer) -1)) { buffer[16] += buffer[i]; } + Serial.write(buffer[i]); + } + return true; +} + +bool SonoffD1SendDimmer(void) +{ + uint8_t buffer[17] = { 0xAA,0x55,0x01,0x04,0x00,0x0A,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00 }; + + buffer[7] = changeUIntScale(((uint16_t *)XdrvMailbox.data)[0], 0, 255, 0, 100); + + for (uint32_t i = 0; i < sizeof(buffer); i++) { + if ((i > 1) && (i < sizeof(buffer) -1)) { buffer[16] += buffer[i]; } + Serial.write(buffer[i]); + } + return true; +} + +bool SonoffD1ModuleSelected(void) +{ + SetSerial(9600, TS_SERIAL_8N1); + + devices_present++; + light_type = LT_SERIAL1; + + return true; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv37(uint8_t function) +{ + bool result = false; + + if (SONOFF_D1 == my_module_type) { + switch (function) { + case FUNC_SERIAL: + result = SonoffD1SerialInput(); + break; + case FUNC_SET_DEVICE_POWER: + result = SonoffD1SendPower(); + break; + case FUNC_SET_CHANNELS: + result = SonoffD1SendDimmer(); + break; + case FUNC_MODULE_INIT: + result = SonoffD1ModuleSelected(); + break; + } + } + return result; +} + +#endif // USE_SONOFF_D1 diff --git a/tools/decode-status.py b/tools/decode-status.py index 756f27dff..6c5dd6a5b 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -198,7 +198,7 @@ a_features = [[ "USE_NRF24","USE_MIBLE","USE_HM10","USE_LE01MR", "USE_AHT1x","USE_WEMOS_MOTOR_V1","USE_DEVICE_GROUPS","USE_PWM_DIMMER" ],[ - "USE_KEELOQ","USE_HRXL","","", + "USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","", "","","","", "","","","", "","","","",