diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 612fb4f96..03a265ba0 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,6 +1,14 @@ -/* 5.5.2b +/* 5.5.2h * Fix Sonoff Pow intermittent exception 0 * Change Sonoff Pow sending Domoticz telemetry data only + * Add Sonoff B1 RGBCW led support with command Color RRGGBBCCWW (#676) + * Add command CT 152..500 to Sonoff Led and Sonoff B1 to control Color Temperature + * Add Cold-Warm slider to web page for Sonoff Led and Sonoff B1 + * Add CT parameter to Hue + * Add Ai-Thinker RGBW led (AiLight) (experimental) + * Add NeoPixelBus library to Sonoff Led for Hue support (saves 1k code space) + * Add user configurable GPIO4 and GPIO5 to module Sonoff Bridge + * Fix Mitsubishi HVAC IR power controll (#740) * * 5.5.2 20170808 * Extent max number of WS2812 pixels from 256 to 512 (#667) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index ad7708866..f4be6a1d7 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05050202 // 5.5.2b +#define VERSION 0x05050208 // 5.5.2h enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum week_t {Last, First, Second, Third, Fourth}; @@ -172,6 +172,7 @@ enum opt_t {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8}; // Index in sysCf #include // Ota #include // Webserver, Updater #include // WemoHue, IRremote, Domoticz +#include // Ws2812, Sonoff Led hue support #ifdef USE_WEBSERVER #include // WifiManager, Webserver #include // WifiManager @@ -303,7 +304,7 @@ uint8_t hlw_flg = 0; // Power monitor configured uint8_t i2c_flg = 0; // I2C configured uint8_t spi_flg = 0; // SPI configured uint8_t pwm_flg = 0; // PWM configured -uint8_t sfl_flg = 0; // Sonoff Led flag (0 = No led, 1 = BN-SZ01, 2 = Sonoff Led) +uint8_t sfl_flg = 0; // Sonoff Led flag (0 = No led, 1 = BN-SZ01, 2 = Sonoff Led, 5 = Sonoff B1) uint8_t pwm_idxoffset = 0; // Allowed PWM command offset (change for Sonoff Led) boolean mDNSbegun = false; @@ -2318,7 +2319,7 @@ void stateloop() button_handler(); switch_handler(); - if (sfl_flg) { // Sonoff BN-SZ01 or Sonoff Led + if (sfl_flg) { // Sonoff B1, AiLight, Sonoff led or BN-SZ01 sl_animate(); } @@ -2627,12 +2628,18 @@ void GPIO_init() Maxdevice = 0; Baudrate = 19200; } - else if (SONOFF_BN == sysCfg.module) { + else if (SONOFF_BN == sysCfg.module) { // Single color led (White) sfl_flg = 1; } - else if (SONOFF_LED == sysCfg.module) { + else if (SONOFF_LED == sysCfg.module) { // Dual color led (White warm and cold) sfl_flg = 2; } + else if (AILIGHT == sysCfg.module) { // RGBW led + sfl_flg = 4; + } + else if (SONOFF_B1 == sysCfg.module) { // RGBWC led + sfl_flg = 5; + } else { Maxdevice = 0; for (byte i = 0; i < 4; i++) { @@ -2660,20 +2667,9 @@ void GPIO_init() } } - if (sfl_flg) { // Sonoff Led or BN-SZ01 - pwm_idxoffset = sfl_flg; // 1 for BN-SZ01, 2 for Sonoff Led - pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led - if (!my_module.gp.io[4]) { - pinMode(4, OUTPUT); // Stop floating outputs - digitalWrite(4, LOW); - } - if (!my_module.gp.io[5]) { - pinMode(5, OUTPUT); // Stop floating outputs - digitalWrite(5, LOW); - } - if (!my_module.gp.io[14]) { - pinMode(14, OUTPUT); // Stop floating outputs - digitalWrite(14, LOW); + if (sfl_flg) { // Sonoff B1, AiLight, Sonoff Led or BN-SZ01 + if (sfl_flg < 4) { + pwm_idxoffset = sfl_flg; // 1 for BN-SZ01, 2 for Sonoff Led } sl_init(); } diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 1d4400bc3..409621322 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -117,6 +117,8 @@ enum fpins_t { GPIO_HLW_CF1, // HLW8012 CF1 voltage / current (Sonoff Pow) GPIO_HLW_CF, // HLW8012 CF power (Sonoff Pow) GPIO_ADC0, // ADC + GPIO_DI, // my92x1 PWM input + GPIO_DCKI, // my92x1 CLK input GPIO_USER, // User configurable GPIO_MAX }; @@ -149,6 +151,8 @@ enum module_t { SONOFF_4CHPRO, HUAFAN_SS, SONOFF_BRIDGE, + SONOFF_B1, + AILIGHT, MAXMODULE }; /********************************************************************************************/ @@ -482,13 +486,44 @@ const mytmplt modules[MAXMODULE] PROGMEM = { GPIO_TXD, // GPIO01 RF bridge control GPIO_USER, // GPIO02 Optional sensor GPIO_RXD, // GPIO03 RF bridge control - 0, 0, + GPIO_USER, // GPIO04 Optional sensor + GPIO_USER, // GPIO05 Optional sensor 0, 0, 0, // Flash connection 0, 0, 0, // Flash connection 0, GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) 0, 0, 0, 0 + }, + { "Sonoff B1", // Sonoff B1 (ESP8285 - my9231) + GPIO_KEY1, // GPIO00 Pad + GPIO_USER, // GPIO01 Serial RXD and Optional sensor pad + GPIO_USER, // GPIO02 Optional sensor SDA pad + GPIO_USER, // GPIO03 Serial TXD and Optional sensor pad + 0, 0, + 0, 0, 0, // Flash connection + 0, 0, + 0, // Flash connection + GPIO_DI, // GPIO12 my9231 DI + 0, + GPIO_DCKI, // GPIO14 my9231 DCKI + 0, 0, 0 + }, + { "AiLight", // Ai-Thinker RGBW led (ESP8266 - my9291) + GPIO_KEY1, // GPIO00 Pad + GPIO_USER, // GPIO01 Serial RXD and Optional sensor pad + GPIO_USER, // GPIO02 Optional sensor SDA pad + GPIO_USER, // GPIO03 Serial TXD and Optional sensor pad + 0, 0, + 0, 0, 0, // Flash connection + 0, 0, + 0, // Flash connection + 0, + GPIO_DI, // GPIO13 my9291 DI + 0, + GPIO_DCKI, // GPIO15 my9291 DCKI + 0, 0 } + }; diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 249fd51e5..a8bf0bba2 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -70,6 +70,9 @@ const char HTTP_HEAD[] PROGMEM = "function lb(p){" "la('?d='+p);" "}" + "function lc(p){" + "la('?t='+p);" + "}" "" "" "" "" - "
" + "
" "

{ha} Module

{h}

"; const char HTTP_SCRIPT_CONSOL[] PROGMEM = "var sn=0;" // Scroll position @@ -415,7 +419,7 @@ void handleRoot() if (HTTP_MANAGER == _httpflag) { handleWifi0(); } else { - char stemp[10], line[100]; + char stemp[10], line[160]; String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), F("Main menu")); page.replace(F(""), F("")); @@ -423,7 +427,12 @@ void handleRoot() page += F("
"); if (Maxdevice) { if (sfl_flg) { - snprintf_P(line, sizeof(line), PSTR(""), + if ((2 == sfl_flg) || (5 == sfl_flg)) { + snprintf_P(line, sizeof(line), PSTR("
ColdWarm
"), + sl_getColorTemp()); + page += line; + } + snprintf_P(line, sizeof(line), PSTR("
DarkBright
"), sysCfg.led_dimmer[0]); page += line; } @@ -474,6 +483,10 @@ void handleAjax2() snprintf_P(svalue, sizeof(svalue), PSTR("dimmer %s"), webServer->arg("d").c_str()); do_cmnd(svalue); } + if (strlen(webServer->arg("t").c_str())) { + snprintf_P(svalue, sizeof(svalue), PSTR("ct %s"), webServer->arg("t").c_str()); + do_cmnd(svalue); + } if (strlen(webServer->arg("k").c_str())) { snprintf_P(svalue, sizeof(svalue), PSTR("rfkey%s"), webServer->arg("k").c_str()); do_cmnd(svalue); diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino index a1998f605..e25b44176 100644 --- a/sonoff/xdrv_ir_send.ino +++ b/sonoff/xdrv_ir_send.ino @@ -261,7 +261,7 @@ boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boole mode = (p - HVACMODE +1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20 mitsubir->setMode(mode); - mitsubir->setPower(~HVAC_Power); + mitsubir->setPower(HVAC_Power); if (HVAC_FanMode == NULL) { p = (char*)FANSPEED; // default FAN_SPEED_AUTO diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino index 9f5acdf0c..dba0e6167 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -18,7 +18,14 @@ */ /*********************************************************************************************\ - * Sonoff Led and BN-SZ01 + * Sonoff B1, AiLight, Sonoff Led and BN-SZ01 + * + * sfl_flg Module Color ColorTemp + * 1 Sonoff BN-SZ W no + * 2 Sonoff Led CW yes + * 3 not used + * 4 AiLight RGBW no + * 5 Sonoff B1 RGBCW yes \*********************************************************************************************/ uint8_t ledTable[] = { @@ -39,9 +46,9 @@ uint8_t ledTable[] = { 184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217, 219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 }; -uint8_t sl_dcolor[2]; -uint8_t sl_tcolor[2]; -uint8_t sl_lcolor[2]; +uint8_t sl_dcolor[5]; +uint8_t sl_tcolor[5]; +uint8_t sl_lcolor[5]; uint8_t sl_power; uint8_t sl_any; @@ -49,54 +56,211 @@ uint8_t sl_wakeupActive = 0; uint8_t sl_wakeupDimmer = 0; uint16_t sl_wakeupCntr = 0; -/********************************************************************************************/ +/*********************************************************************************************\ + * Sonoff B1 and AiLight inspired by OpenLight https://github.com/icamgo/noduino-sdk +\*********************************************************************************************/ -void sl_setDim(uint8_t myDimmer) -{ - if ((1 == sfl_flg) && (100 == myDimmer)) { - myDimmer = 99; // BN-SZ01 starts flickering at dimmer = 100 - } - float newDim = 100 / (float)myDimmer; - float fmyCld = (float)sysCfg.led_color[0] / newDim; - sl_dcolor[0] = (uint8_t)fmyCld; - float fmyWrm = (float)sysCfg.led_color[1] / newDim; - sl_dcolor[1] = (uint8_t)fmyWrm; +extern "C" { + void os_delay_us(unsigned int); } +uint8_t sl_pdi; +uint8_t sl_pdcki; + +void sl_di_pulse(uint8_t times) +{ + for (uint8_t i = 0; i < times; i++) { + digitalWrite(sl_pdi, HIGH); + digitalWrite(sl_pdi, LOW); + } +} + +void sl_dcki_pulse(uint8_t times) +{ + for (uint8_t i = 0; i < times; i++) { + digitalWrite(sl_pdcki, HIGH); + digitalWrite(sl_pdcki, LOW); + } +} + +void sl_my92x1_write(uint8_t data) +{ + for (uint8_t i = 0; i < 4; i++) { // Send 8bit Data + digitalWrite(sl_pdcki, LOW); + digitalWrite(sl_pdi, (data & 0x80)); + digitalWrite(sl_pdcki, HIGH); + data = data << 1; + digitalWrite(sl_pdi, (data & 0x80)); + digitalWrite(sl_pdcki, LOW); + digitalWrite(sl_pdi, LOW); + data = data << 1; + } +} + +void sl_my92x1_init() +{ + uint8_t chips = sfl_flg -3; // 1 (AiLight) or 2 (Sonoff B1) + + sl_dcki_pulse(chips * 32); // Clear all duty register + os_delay_us(12); // TStop > 12us. + // Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12 + // pulse's rising edge convert to command mode. + sl_di_pulse(12); + os_delay_us(12); // Delay >12us, begin send CMD data + for (uint8_t n = 0; n < chips; n++) { // Send CMD data + sl_my92x1_write(0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM + } + os_delay_us(12); // TStart > 12us. Delay 12 us. + // Send 16 DI pulse, at 14 pulse's falling edge store CMD data, and + // at 16 pulse's falling edge convert to duty mode. + sl_di_pulse(16); + os_delay_us(12); // TStop > 12us. +} + +void sl_my92x1_duty(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 = sfl_flg -4; // 0 or 1 + + 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 + + os_delay_us(12); // TStop > 12us. + for (uint8_t channel = 0; channel < channels[didx]; channel++) { + sl_my92x1_write(duty[didx][channel]); // Send 8bit Data + } + os_delay_us(12); // TStart > 12us. Ready for send DI pulse. + sl_di_pulse(8); // Send 8 DI pulse. After 8 pulse falling edge, store old data. + os_delay_us(12); // TStop > 12us. +} + +/********************************************************************************************/ + void sl_init(void) { - sysCfg.pwmvalue[0] = 0; // We use dimmer / led_color - if (2 == sfl_flg) { - sysCfg.pwmvalue[1] = 0; // We use led_color + pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led + if (sfl_flg < 4) { + if (!my_module.gp.io[4]) { + pinMode(4, OUTPUT); // Stop floating outputs + digitalWrite(4, LOW); + } + if (!my_module.gp.io[5]) { + pinMode(5, OUTPUT); // Stop floating outputs + digitalWrite(5, LOW); + } + if (!my_module.gp.io[14]) { + pinMode(14, OUTPUT); // Stop floating outputs + digitalWrite(14, LOW); + } + sysCfg.pwmvalue[0] = 0; // We use dimmer / led_color + if (2 == sfl_flg) { + sysCfg.pwmvalue[1] = 0; // We use led_color + } + } else { + sl_pdi = pin[GPIO_DI]; + sl_pdcki = pin[GPIO_DCKI]; + + pinMode(sl_pdi, OUTPUT); + pinMode(sl_pdcki, OUTPUT); + digitalWrite(sl_pdi, LOW); + digitalWrite(sl_pdcki, LOW); + + sl_my92x1_init(); } + sl_power = 0; sl_any = 0; sl_wakeupActive = 0; } -void sl_setColor(char* colstr) +void sl_setColorTemp(uint16_t ct) { - uint8_t my_color[2]; - char *p; - - uint16_t temp = strtol(colstr, &p, 16); - my_color[1] = temp & 0xFF; // Warm - temp >>= 8; - my_color[0] = temp & 0xFF; // Cold - if (temp < my_color[1]) { - temp = my_color[1]; +/* Color Temperature (https://developers.meethue.com/documentation/core-concepts) + * + * ct = 153 = 2000K = Warm = CCWW = 00FF + * ct = 500 = 6500K = Cold = CCWW = FF00 + */ + uint16_t my_ct = ct - 153; + if (my_ct > 347) { + my_ct = 347; } - float mDim = (float)temp / 2.55; + uint16_t icold = (100 * (347 - my_ct)) / 136; + uint16_t iwarm = (100 * my_ct) / 136; + if (5 == sfl_flg) { + sysCfg.led_color[0] = 0; + sysCfg.led_color[1] = 0; + sysCfg.led_color[2] = 0; + sysCfg.led_color[3] = (uint8_t)icold; + sysCfg.led_color[4] = (uint8_t)iwarm; + } else { + sysCfg.led_color[0] = (uint8_t)icold; + sysCfg.led_color[1] = (uint8_t)iwarm; + } +} + +uint16_t sl_getColorTemp() +{ + uint8_t ct_idx = 0; + if (5 == sfl_flg) { + ct_idx = 3; + } + uint16_t my_ct = sysCfg.led_color[ct_idx +1]; + if (my_ct > 0) { + return ((my_ct * 136) / 100) + 154; + } else { + my_ct = sysCfg.led_color[ct_idx]; + return 499 - ((my_ct * 136) / 100); + } +} + +void sl_setDim(uint8_t myDimmer) +{ + float temp; + + if ((1 == sfl_flg) && (100 == myDimmer)) { + myDimmer = 99; // BN-SZ01 starts flickering at dimmer = 100 + } + float newDim = 100 / (float)myDimmer; + for (byte i = 0; i < sfl_flg; i++) { + temp = (float)sysCfg.led_color[i] / newDim; + sl_dcolor[i] = (uint8_t)temp; + } +} + +void sl_setColor() +{ + uint8_t highest = 0; + float temp; + + for (byte i = 0; i < sfl_flg; i++) { + if (highest < sl_dcolor[i]) { + highest = sl_dcolor[i]; + } + } + float mDim = (float)highest / 2.55; sysCfg.led_dimmer[0] = (uint8_t)mDim; float newDim = 100 / mDim; - float fmyCold = (float)my_color[0] * newDim; - float fmyWarm = (float)my_color[1] * newDim; - sysCfg.led_color[0] = (uint8_t)fmyCold; - sysCfg.led_color[1] = (uint8_t)fmyWarm; + for (byte i = 0; i < sfl_flg; i++) { + temp = (float)sl_dcolor[i] * newDim; + sysCfg.led_color[i] = (uint8_t)temp; + } +} + +char* sl_getColor(char* scolor) +{ + sl_setDim(sysCfg.led_dimmer[0]); + scolor[0] = '\0'; + for (byte i = 0; i < sfl_flg; i++) { + snprintf_P(scolor, 11, PSTR("%s%02X"), scolor, sl_dcolor[i]); + } + return scolor; } void sl_prepPower(char *svalue, uint16_t ssvalue) { + char scolor[11]; + // do_cmnd_power(index, (sysCfg.led_dimmer[0]>0)); if (sysCfg.led_dimmer[0] && !(power&1)) { do_cmnd_power(1, 7); // No publishPowerState @@ -107,12 +271,9 @@ void sl_prepPower(char *svalue, uint16_t ssvalue) #ifdef USE_DOMOTICZ mqtt_publishDomoticzPowerState(1); #endif // USE_DOMOTICZ - sl_setDim(sysCfg.led_dimmer[0]); - if (2 == sfl_flg) { - uint16_t color = (uint16_t)sl_dcolor[0] << 8; - color += (uint16_t)sl_dcolor[1]; - snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d, \"Color\":\"%04X\"}"), - getStateText(power &1), sysCfg.led_dimmer[0], color); + if (sfl_flg > 1) { + snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d, \"Color\":\"%s\"}"), + getStateText(power &1), sysCfg.led_dimmer[0], sl_getColor(scolor)); } else { snprintf_P(svalue, ssvalue, PSTR("{\"POWER\":\"%s\", \"Dimmer\":%d}"), getStateText(power &1), sysCfg.led_dimmer[0]); @@ -133,40 +294,38 @@ void sl_animate() // {"Wakeup":"Done"} char svalue[32]; // was MESSZ uint8_t fadeValue; + uint8_t cur_col[5]; if (0 == sl_power) { // Power Off - sl_tcolor[0] = 0; - sl_tcolor[1] = 0; + for (byte i = 0; i < sfl_flg; i++) { + sl_tcolor[i] = 0; + } } else { if (!sl_wakeupActive) { // Power On sl_setDim(sysCfg.led_dimmer[0]); if (0 == sysCfg.led_fade) { - sl_tcolor[0] = sl_dcolor[0]; - sl_tcolor[1] = sl_dcolor[1]; - } else { - if (sl_tcolor[0] != sl_dcolor[0]) { - if (sl_tcolor[0] < sl_dcolor[0]) { - sl_tcolor[0] += ((sl_dcolor[0] - sl_tcolor[0]) >> sysCfg.led_speed) +1; - } - if (sl_tcolor[0] > sl_dcolor[0]) { - sl_tcolor[0] -= ((sl_tcolor[0] - sl_dcolor[0]) >> sysCfg.led_speed) +1; - } + for (byte i = 0; i < sfl_flg; i++) { + sl_tcolor[i] = sl_dcolor[i]; } - if ((2 == sfl_flg) && (sl_tcolor[1] != sl_dcolor[1])) { - if (sl_tcolor[1] < sl_dcolor[1]) { - sl_tcolor[1] += ((sl_dcolor[1] - sl_tcolor[1]) >> sysCfg.led_speed) +1; - } - if (sl_tcolor[1] > sl_dcolor[1]) { - sl_tcolor[1] -= ((sl_tcolor[1] - sl_dcolor[1]) >> sysCfg.led_speed) +1; + } else { + for (byte i = 0; i < sfl_flg; i++) { + if (sl_tcolor[i] != sl_dcolor[i]) { + if (sl_tcolor[i] < sl_dcolor[i]) { + sl_tcolor[i] += ((sl_dcolor[i] - sl_tcolor[i]) >> sysCfg.led_speed) +1; + } + if (sl_tcolor[i] > sl_dcolor[i]) { + sl_tcolor[i] -= ((sl_tcolor[i] - sl_dcolor[i]) >> sysCfg.led_speed) +1; + } } } } } else { // Power On using wake up duration if (2 == sl_wakeupActive) { sl_wakeupActive = 1; - sl_tcolor[0] = 0; - sl_tcolor[1] = 0; + for (byte i = 0; i < sfl_flg; i++) { + sl_tcolor[i] = 0; + } sl_wakeupCntr = 0; sl_wakeupDimmer = 0; } @@ -176,8 +335,9 @@ void sl_animate() sl_wakeupDimmer++; if (sl_wakeupDimmer <= sysCfg.led_dimmer[0]) { sl_setDim(sl_wakeupDimmer); - sl_tcolor[0] = sl_dcolor[0]; - sl_tcolor[1] = sl_dcolor[1]; + for (byte i = 0; i < sfl_flg; i++) { + sl_tcolor[i] = sl_dcolor[i]; + } } else { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Wakeup\":\"Done\"}")); mqtt_publish_topic_P(2, PSTR("WAKEUP"), svalue); @@ -186,15 +346,25 @@ void sl_animate() } } } - if ((sl_lcolor[0] != sl_tcolor[0]) || (sl_lcolor[1] != sl_tcolor[1]) || sl_any) { + for (byte i = 0; i < sfl_flg; i++) { + if (sl_lcolor[i] != sl_tcolor[i]) { + sl_any = 1; + } + } + if (sl_any) { sl_any = 0; - sl_lcolor[0] = sl_tcolor[0]; - sl_lcolor[1] = sl_tcolor[1]; for (byte i = 0; i < sfl_flg; i++) { - if (pin[GPIO_PWM1 +i] < 99) { - analogWrite(pin[GPIO_PWM1 +i], ((sysCfg.led_table) ? ledTable[sl_lcolor[i]] : sl_lcolor[i]) * (PWM_RANGE / 255)); + sl_lcolor[i] = sl_tcolor[i]; + cur_col[i] = (sysCfg.led_table) ? ledTable[sl_lcolor[i]] : sl_lcolor[i]; + if (sfl_flg < 4) { + if (pin[GPIO_PWM1 +i] < 99) { + analogWrite(pin[GPIO_PWM1 +i], cur_col[i] * (PWM_RANGE / 255)); + } } } + if (sfl_flg > 3) { + sl_my92x1_duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); + } } } @@ -202,28 +372,99 @@ void sl_animate() * Hue support \*********************************************************************************************/ +void sl_rgb2hsb(float *hue, float *sat, float *bri) +{ + RgbColor dcolor; + + sl_setDim(sysCfg.led_dimmer[0]); + dcolor.R = sl_dcolor[0]; + dcolor.G = sl_dcolor[1]; + dcolor.B = sl_dcolor[2]; + HsbColor hsb = HsbColor(dcolor); + *hue = hsb.H; + *sat = hsb.S; + *bri = hsb.B; +} + +/********************************************************************************************/ + void sl_replaceHSB(String *response) { - response->replace("{h}", "0"); - response->replace("{s}", "0"); - response->replace("{b}", String((uint8_t)(2.54f * (float)sysCfg.led_dimmer[0]))); + float hue; + float sat; + float bri; + + if (sfl_flg > 2) { + sl_rgb2hsb(&hue, &sat, &bri); + response->replace("{h}", String((uint16_t)(65535.0f * hue))); + response->replace("{s}", String((uint8_t)(254.0f * sat))); + response->replace("{b}", String((uint8_t)(254.0f * bri))); + } else { + response->replace("{h}", "0"); + response->replace("{s}", "0"); +// response->replace("{b}", String((uint8_t)(2.54f * (float)sysCfg.led_dimmer[0]))); + response->replace("{b}", String((uint8_t)(0.01f * (float)sysCfg.led_dimmer[0]))); + } } void sl_getHSB(float *hue, float *sat, float *bri) { - *hue = 0; - *sat = 0; - *bri = (2.54f * (float)sysCfg.led_dimmer[0]); + if (sfl_flg > 2) { + sl_rgb2hsb(hue, sat, bri); + } else { + *hue = 0; + *sat = 0; +// *bri = (2.54f * (float)sysCfg.led_dimmer[0]); + *bri = (0.01f * (float)sysCfg.led_dimmer[0]); + } } -void sl_setHSB(float hue, float sat, float bri) +void sl_setHSB(float hue, float sat, float bri, uint16_t ct) { char svalue[MESSZ]; + HsbColor hsb; - uint8_t tmp = (uint8_t)(bri * 100); - sysCfg.led_dimmer[0] = tmp; - sl_prepPower(svalue, sizeof(svalue)); - mqtt_publish_topic_P(5, "DIMMER", svalue); +/* + char log[LOGSZ]; + char stemp1[10]; + char stemp2[10]; + char stemp3[10]; + dtostrf(hue, 1, 3, stemp1); + dtostrf(sat, 1, 3, stemp2); + dtostrf(bri, 1, 3, stemp3); + snprintf_P(log, sizeof(log), PSTR("HUE: Set Hue %s, Sat %s, Bri %s, Ct %d"), stemp1, stemp2, stemp3, ct); + addLog(LOG_LEVEL_DEBUG, log); +*/ + + if (sfl_flg > 2) { + if ((5 == sfl_flg) && (ct > 0)) { + sl_setColorTemp(ct); + } else { + hsb.H = hue; + hsb.S = sat; + hsb.B = bri; + RgbColor tmp = RgbColor(hsb); + sl_dcolor[0] = tmp.R; + sl_dcolor[1] = tmp.G; + sl_dcolor[2] = tmp.B; + sl_setColor(); + } + sl_prepPower(svalue, sizeof(svalue)); + mqtt_publish_topic_P(5, "COLOR", svalue); + } else { + uint8_t tmp = (uint8_t)(bri * 100); + sysCfg.led_dimmer[0] = tmp; + if (2 == sfl_flg) { + if (ct > 0) { + sl_setColorTemp(ct); + } + sl_prepPower(svalue, sizeof(svalue)); + mqtt_publish_topic_P(5, "COLOR", svalue); + } else { + sl_prepPower(svalue, sizeof(svalue)); + mqtt_publish_topic_P(5, "DIMMER", svalue); + } + } } /*********************************************************************************************\ @@ -234,18 +475,27 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le { boolean serviced = true; boolean coldim = false; + char scolor[11]; + char *p; - if ((2 == sfl_flg) && !strcmp_P(type,PSTR("COLOR"))) { - uint8_t my_color[2]; - char *p; - if (4 == data_len) { - sl_setColor(dataBufUc); + if ((sfl_flg > 1) && !strcmp_P(type,PSTR("COLOR"))) { + if ((2 * sfl_flg) == data_len) { + for (byte i = 0; i < sfl_flg; i++) { + strlcpy(scolor, dataBufUc + (i *2), 3); + sl_dcolor[i] = (uint8_t)strtol(scolor, &p, 16); + } + sl_setColor(); coldim = true; } else { - sl_setDim(sysCfg.led_dimmer[0]); - uint16_t color = (uint16_t)sl_dcolor[0] << 8; - color += (uint16_t)sl_dcolor[1]; - snprintf_P(svalue, ssvalue, PSTR("{\"Color\":\"%04X\"}"), color); + snprintf_P(svalue, ssvalue, PSTR("{\"Color\":\"%s\"}"), sl_getColor(scolor)); + } + } + else if (!strcmp_P(type,PSTR("CT")) && ((2 == sfl_flg) || (5 == sfl_flg))) { // ColorTemp + if ((payload >= 153) && (payload <= 500)) { // https://developers.meethue.com/documentation/core-concepts + sl_setColorTemp(payload); + coldim = true; + } else { + snprintf_P(svalue, ssvalue, PSTR("{\"CT\":%d}"), sl_getColorTemp()); } } else if (!strcmp_P(type,PSTR("DIMMER"))) { diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino index 08bcba878..ac522167d 100644 --- a/sonoff/xdrv_wemohue.ino +++ b/sonoff/xdrv_wemohue.ino @@ -533,6 +533,7 @@ void hue_lights(String *path) float bri = 0; float hue = 0; float sat = 0; + uint16_t ct = 0; bool resp = false; bool on = false; bool change = false; @@ -636,9 +637,20 @@ void hue_lights(String *path) response.replace("{res}", String(tmp)); change = true; } + if (hue_json.containsKey("ct")) { // Color temperature 153 (Cold) to 500 (Warm) + ct = hue_json["ct"]; + if (resp) { + response += ","; + } + response += FPSTR(HUE_LIGHT_RESPONSE_JSON); + response.replace("{id}", String(device)); + response.replace("{cmd}", "ct"); + response.replace("{res}", String(ct)); + change = true; + } if (change) { if (sfl_flg) { - sl_setHSB(hue, sat, bri); + sl_setHSB(hue, sat, bri, ct); #ifdef USE_WS2812 } else if (pin[GPIO_WS2812] < 99) { @@ -655,6 +667,9 @@ void hue_lights(String *path) else { response = FPSTR(HUE_ERROR_JSON); } + +//addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); + webServer->send(200, FPSTR(HDR_CTYPE_JSON), response); } else if(path->indexOf("/lights/") >= 0) { // Got /lights/ID @@ -678,6 +693,9 @@ void hue_lights(String *path) void hue_groups(String *path) { +/* + * http://sonoff/api/username/groups?1={"name":"Woonkamer","lights":[],"type":"Room","class":"Living room"}) + */ String response = "{}"; if (path->endsWith("/0")) { @@ -721,7 +739,7 @@ void handle_hue_api(String *path) else if (path->endsWith("/")) hue_auth(path); // New HUE App setup else if (path->endsWith("/config")) hue_config(path); else if (path->indexOf("/lights") >= 0) hue_lights(path); - else if (path->indexOf("/groups") >= 0) hue_groups(path); + else if (path->indexOf("/groups") >= 0) hue_groups(path); else if (path->endsWith("/schedules")) hue_todo(path); else if (path->endsWith("/sensors")) hue_todo(path); else if (path->endsWith("/scenes")) hue_todo(path); diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index 93a6e5fe4..92fe3e349 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -22,7 +22,7 @@ * WS2812 Leds using NeopixelBus library \*********************************************************************************************/ -#include +//#include // Global defined as also used by Sonoff Led #ifdef USE_WS2812_DMA #if (USE_WS2812_CTYPE == 1) @@ -145,37 +145,6 @@ void ws2812_setColor(uint16_t led, char* colstr) } } -void ws2812_replaceHSB(String *response) -{ - ws2812_setDim(sysCfg.ws_dimmer); - HsbColor hsb = HsbColor(dcolor); - response->replace("{h}", String((uint16_t)(65535.0f * hsb.H))); - response->replace("{s}", String((uint8_t)(254.0f * hsb.S))); - response->replace("{b}", String((uint8_t)(254.0f * hsb.B))); -} - -void ws2812_getHSB(float *hue, float *sat, float *bri) -{ - ws2812_setDim(sysCfg.ws_dimmer); - HsbColor hsb = HsbColor(dcolor); - *hue = hsb.H; - *sat = hsb.S; - *bri = hsb.B; -} - -void ws2812_setHSB(float hue, float sat, float bri) -{ - char rgb[7]; - - HsbColor hsb; - hsb.H = hue; - hsb.S = sat; - hsb.B = bri; - RgbColor tmp = RgbColor(hsb); - sprintf(rgb,"%02X%02X%02X", tmp.R, tmp.G, tmp.B); - ws2812_setColor(0,rgb); -} - void ws2812_getColor(uint16_t led, char* svalue, uint16_t ssvalue) { RgbColor mcolor; @@ -504,6 +473,41 @@ void ws2812_init(uint8_t powerbit) ws2812_pixels(); } +/*********************************************************************************************\ + * Hue support +\*********************************************************************************************/ + +void ws2812_replaceHSB(String *response) +{ + ws2812_setDim(sysCfg.ws_dimmer); + HsbColor hsb = HsbColor(dcolor); + response->replace("{h}", String((uint16_t)(65535.0f * hsb.H))); + response->replace("{s}", String((uint8_t)(254.0f * hsb.S))); + response->replace("{b}", String((uint8_t)(254.0f * hsb.B))); +} + +void ws2812_getHSB(float *hue, float *sat, float *bri) +{ + ws2812_setDim(sysCfg.ws_dimmer); + HsbColor hsb = HsbColor(dcolor); + *hue = hsb.H; + *sat = hsb.S; + *bri = hsb.B; +} + +void ws2812_setHSB(float hue, float sat, float bri) +{ + char rgb[7]; + + HsbColor hsb; + hsb.H = hue; + hsb.S = sat; + hsb.B = bri; + RgbColor tmp = RgbColor(hsb); + sprintf(rgb,"%02X%02X%02X", tmp.R, tmp.G, tmp.B); + ws2812_setColor(0,rgb); +} + /*********************************************************************************************\ * Commands \*********************************************************************************************/