From e284e78b4d526459a3279f9373313b9afec4c1bb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Nov 2018 12:22:15 +0100 Subject: [PATCH] Add support for Armtronix dimmers Add support for Armtronix dimmers. See wiki for info (#4321) --- sonoff/_changelog.ino | 1 + sonoff/my_user_config.h | 2 +- sonoff/sonoff.h | 7 +- sonoff/xdrv_04_light.ino | 28 +++-- sonoff/xdrv_16_tuyadimmer.ino | 2 +- ...mers.ino => xdrv_18_armtronix_dimmers.ino} | 116 +++++++++--------- 6 files changed, 81 insertions(+), 75 deletions(-) rename sonoff/{xdrv_18_armtronixDimmers.ino => xdrv_18_armtronix_dimmers.ino} (67%) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 226fdcec1..3914c426b 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.3.0.8 20181115 * Stop enforcing flashmode dout but it is still mandatory * Moved bootcount update (being first) flash write to 10 seconds after restart + * Add support for Armtronix dimmers. See wiki for info (#4321) * * 6.3.0.7 20181111 * Fix wifi connection errors using wifi disconnect and ESP.reset instead of ESP.restart diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 8e3050a4e..3e0efdef4 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -356,7 +356,7 @@ #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max) #define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer #define TUYA_DIMMER_ID 0 // Default dimmer Id -//#define USE_ARMTRONIX_DIMMERS //Add support for Armtronix Dimmers +#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index fb59eac68..5a43e147f 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -227,8 +227,11 @@ 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_SERIAL, LT_SERIAL2, LT_NU10, LT_WS2812, LT_RGBW, LT_RGBWC}; -enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC}; + +enum LightSubtypes { LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC }; // Do not insert new fields +enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7, + LT_NU8, LT_SERIAL1, LT_SERIAL2, LT_WS2812, LT_RGBW, LT_RGBWC, LT_NU14, LT_NU15 }; // Do not insert new fields + enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX}; enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index 35cda4f97..92e19fb57 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -311,7 +311,10 @@ void LightMy92x1Write(uint8_t data) void LightMy92x1Init(void) { - uint8_t chips = light_type -11; // 1 (AiLight) or 2 (Sonoff B1) + uint8_t chips = 1; // 1 (AiLight) + if (LT_RGBWC == light_type) { + chips = 2; // 2 (Sonoff B1) + } LightDckiPulse(chips * 32); // Clear all duty register os_delay_us(12); // TStop > 12us. @@ -332,7 +335,12 @@ void LightMy92x1Init(void) void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c) { uint8_t channels[2] = { 4, 6 }; - uint8_t didx = light_type -12; // 0 or 1 + + uint8_t didx = 0; // 0 (AiLight) + if (LT_RGBWC == light_type) { + didx = 1; // 1 (Sonoff B1) + } + uint8_t duty[2][6] = {{ duty_r, duty_g, duty_b, duty_w, 0, 0 }, // Definition for RGBW channels { duty_w, duty_c, 0, duty_g, duty_r, duty_b }}; // Definition for RGBWC channels @@ -352,8 +360,11 @@ void LightInit(void) uint8_t max_scheme = LS_MAX -1; light_device = devices_present; - light_subtype = light_type &7; + light_subtype = light_type &7; // Always 0 - 7 + if (LST_SINGLE == light_subtype) { + Settings.light_color[0] = 255; // One channel only supports Dimmer but needs max color + } if (light_type < LT_PWM6) { // PWM for (byte i = 0; i < light_type; i++) { Settings.pwm_value[i] = 0; // Disable direct PWM control @@ -361,9 +372,6 @@ void LightInit(void) pinMode(pin[GPIO_PWM1 +i], OUTPUT); } } - 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 if (!my_module.gp.io[4]) { pinMode(4, OUTPUT); // Stop floating outputs @@ -393,12 +401,6 @@ void LightInit(void) max_scheme = LS_MAX + WS2812_SCHEMES; } #endif // USE_WS2812 ************************************************************************ - else if (LT_SERIAL == light_type) { - light_subtype = LST_SINGLE; - } - else if (LT_SERIAL2 == light_type) { - light_subtype = LST_COLDWARM; - } else { light_pdi_pin = pin[GPIO_DI]; light_pdcki_pin = pin[GPIO_DCKI]; @@ -830,7 +832,7 @@ void LightAnimate(void) 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) { + if (light_type == LT_SERIAL1) { LightSerialDuty(cur_col[0]); } #endif // USE_TUYA_DIMMER diff --git a/sonoff/xdrv_16_tuyadimmer.ino b/sonoff/xdrv_16_tuyadimmer.ino index 278ef6941..1322da33a 100644 --- a/sonoff/xdrv_16_tuyadimmer.ino +++ b/sonoff/xdrv_16_tuyadimmer.ino @@ -276,7 +276,7 @@ boolean TuyaModuleSelected(void) Settings.my_gp.io[3] = GPIO_TUYA_RX; restart_flag = 2; } - light_type = LT_SERIAL; + light_type = LT_SERIAL1; return true; } diff --git a/sonoff/xdrv_18_armtronixDimmers.ino b/sonoff/xdrv_18_armtronix_dimmers.ino similarity index 67% rename from sonoff/xdrv_18_armtronixDimmers.ino rename to sonoff/xdrv_18_armtronix_dimmers.ino index 9fae00ff0..0cab44e1d 100644 --- a/sonoff/xdrv_18_armtronixDimmers.ino +++ b/sonoff/xdrv_18_armtronix_dimmers.ino @@ -1,7 +1,7 @@ /* - xdrv_18_armtronixdimmer.ino - Armtronix dimmers support for Sonoff-Tasmota + xdrv_18_armtronix_dimmers.ino - Armtronix dimmers support for Sonoff-Tasmota - Copyright (C) 2018 digiblur, Joel Stein and Theo Arends + Copyright (C) 2018 wvdv2002 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 @@ -17,11 +17,13 @@ along with this program. If not, see . */ -/*This code can be used for Armtronix dimmers. The dimmers contain a Atmega328 to do the actual dimming. - Checkout the Tasmota Wiki for information on how to flash this Atmega328 with the firmware to work together with this driver. -*/ - #ifdef USE_ARMTRONIX_DIMMERS +/*********************************************************************************************\ + * This code can be used for Armtronix dimmers. + * The dimmers contain a Atmega328 to do the actual dimming. + * Checkout the Tasmota Wiki for information on how to flash this Atmega328 with the firmware + * to work together with this driver. +\*********************************************************************************************/ #define XDRV_18 18 @@ -31,27 +33,24 @@ TasmotaSerial *ArmtronixSerial = nullptr; boolean armtronix_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction int8_t armtronix_wifi_state = -2; // Keep MCU wifi-status in sync with WifiState() -int8_t armtronix_dimState[2]; //Dimmer state values. -int8_t armtronix_knobState[2]; //Dimmer state values. - +int8_t armtronix_dimState[2]; // Dimmer state values. +int8_t armtronix_knobState[2]; // Dimmer state values. /*********************************************************************************************\ * Internal Functions \*********************************************************************************************/ - - void LightSerial2Duty(uint8_t duty1, uint8_t duty2) { if (ArmtronixSerial && !armtronix_ignore_dim) { - duty1 = ((float)duty1)/2.575757; //max 99 - duty2 = ((float)duty2)/2.575757; //max 99 - armtronix_dimState[0] = duty1; - armtronix_dimState[1] = duty2; - ArmtronixSerial->print("Dimmer1:"); - ArmtronixSerial->print(duty1); - ArmtronixSerial->print("\nDimmer2:"); - ArmtronixSerial->println(duty2); + duty1 = ((float)duty1)/2.575757; //max 99 + duty2 = ((float)duty2)/2.575757; //max 99 + armtronix_dimState[0] = duty1; + armtronix_dimState[1] = duty2; + ArmtronixSerial->print("Dimmer1:"); + ArmtronixSerial->print(duty1); + ArmtronixSerial->print("\nDimmer2:"); + ArmtronixSerial->println(duty2); snprintf_P(log_data, sizeof(log_data), PSTR( "ARM: Send Serial Packet Dim Values=%d,%d"), armtronix_dimState[0],armtronix_dimState[1]); AddLog(LOG_LEVEL_DEBUG); @@ -64,13 +63,14 @@ void LightSerial2Duty(uint8_t duty1, uint8_t duty2) } } -void ArmtronixRequestState(){ - if(ArmtronixSerial) { +void ArmtronixRequestState(void) +{ + if (ArmtronixSerial) { // Get current status of MCU snprintf_P(log_data, sizeof(log_data), "TYA: Request MCU state"); AddLog(LOG_LEVEL_DEBUG); ArmtronixSerial->println("Status"); - + } } @@ -78,13 +78,13 @@ void ArmtronixRequestState(){ * API Functions \*********************************************************************************************/ -boolean ArmtronixModuleSelected() +boolean ArmtronixModuleSelected(void) { light_type = LT_SERIAL2; return true; } -void ArmtronixInit() +void ArmtronixInit(void) { armtronix_dimState[0] = -1; armtronix_dimState[1] = -1; @@ -97,21 +97,21 @@ void ArmtronixInit() } } -void ArmtronixSerialInput() +void ArmtronixSerialInput(void) { String answer; int8_t newDimState[2]; uint8_t temp; int commaIndex; - char scmnd[20]; + char scmnd[20]; if (ArmtronixSerial->available()) { yield(); answer = ArmtronixSerial->readStringUntil('\n'); - if(answer.substring(0,7) == "Status:"){ + if (answer.substring(0,7) == "Status:") { commaIndex = 6; - for(int i =0;i<2;i++){ + for (int i =0; i<2; i++) { newDimState[i] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt(); - if(newDimState[i] != armtronix_dimState[i]){ + if (newDimState[i] != armtronix_dimState[i]) { temp = ((float)newDimState[i])*1.01010101010101; //max 255 armtronix_dimState[i] = newDimState[i]; armtronix_ignore_dim = true; @@ -120,7 +120,7 @@ void ArmtronixSerialInput() snprintf_P(log_data, sizeof(log_data), PSTR("ARM: Send CMND_CHANNEL=%s"), scmnd ); AddLog(LOG_LEVEL_DEBUG); } - commaIndex = answer.indexOf(',',commaIndex+1); + commaIndex = answer.indexOf(',',commaIndex+1); } armtronix_knobState[0] = answer.substring(commaIndex+1,answer.indexOf(',',commaIndex+1)).toInt(); commaIndex = answer.indexOf(',',commaIndex+1); @@ -129,40 +129,40 @@ void ArmtronixSerialInput() } } -void ArmtronixSetWifiLed(){ - uint8_t wifi_state = 0x02; - switch(WifiState()){ - case WIFI_SMARTCONFIG: - wifi_state = 0x00; - break; - case WIFI_MANAGER: - case WIFI_WPSCONFIG: - wifi_state = 0x01; - break; - case WIFI_RESTART: - wifi_state = 0x03; - break; - } +void ArmtronixSetWifiLed(void) +{ + uint8_t wifi_state = 0x02; - snprintf_P(log_data, sizeof(log_data), "ARM: Set WiFi LED to state %d (%d)", wifi_state, WifiState()); - AddLog(LOG_LEVEL_DEBUG); - - char state = '0' + (wifi_state & 1 > 0); - ArmtronixSerial->print("Setled:"); - ArmtronixSerial->write(state); - ArmtronixSerial->write(','); - state = '0' + (wifi_state & 2 > 0); - ArmtronixSerial->write(state); - ArmtronixSerial->write(10); - armtronix_wifi_state = WifiState(); + switch (WifiState()) { + case WIFI_SMARTCONFIG: + wifi_state = 0x00; + break; + case WIFI_MANAGER: + case WIFI_WPSCONFIG: + wifi_state = 0x01; + break; + case WIFI_RESTART: + wifi_state = 0x03; + break; + } + snprintf_P(log_data, sizeof(log_data), "ARM: Set WiFi LED to state %d (%d)", wifi_state, WifiState()); + AddLog(LOG_LEVEL_DEBUG); + char state = '0' + (wifi_state & 1 > 0); + ArmtronixSerial->print("Setled:"); + ArmtronixSerial->write(state); + ArmtronixSerial->write(','); + state = '0' + (wifi_state & 2 > 0); + ArmtronixSerial->write(state); + ArmtronixSerial->write(10); + armtronix_wifi_state = WifiState(); } - /*********************************************************************************************\ * Interface \*********************************************************************************************/ + boolean Xdrv18(byte function) { boolean result = false; @@ -179,9 +179,9 @@ boolean Xdrv18(byte function) if (ArmtronixSerial) { ArmtronixSerialInput(); } break; case FUNC_EVERY_SECOND: - if(ArmtronixSerial){ + if (ArmtronixSerial) { if (armtronix_wifi_state!=WifiState()) { ArmtronixSetWifiLed(); } - if(uptime&1){ + if (uptime &1) { ArmtronixSerial->println("Status"); } }