diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index cc9d81c0b..03a265ba0 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,9 +1,14 @@ -/* 5.5.2g +/* 5.5.2h * Fix Sonoff Pow intermittent exception 0 * Change Sonoff Pow sending Domoticz telemetry data only - * Add Sonoff B1 support + * 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 1k1 code space) + * 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 97a0c15bc..f4be6a1d7 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05050207 // 5.5.2g +#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}; diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 333ed89e9..409621322 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -486,7 +486,8 @@ 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 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 525c245f4..dba0e6167 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -19,6 +19,13 @@ /*********************************************************************************************\ * 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[] = { @@ -50,7 +57,7 @@ uint8_t sl_wakeupDimmer = 0; uint16_t sl_wakeupCntr = 0; /*********************************************************************************************\ - * Sonoff B1 (my9231) and AiLight (my9291) based on OpenLight https://github.com/icamgo/noduino-sdk + * Sonoff B1 and AiLight inspired by OpenLight https://github.com/icamgo/noduino-sdk \*********************************************************************************************/ extern "C" { @@ -76,83 +83,56 @@ void sl_dcki_pulse(uint8_t times) } } -void sl_my92x1_command(uint8_t chips, uint8_t command) +void sl_my92x1_write(uint8_t data) { - uint8_t command_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; + } +} - os_delay_us(12); // TStop > 12us. +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 + os_delay_us(12); // Delay >12us, begin send CMD data for (uint8_t n = 0; n < chips; n++) { // Send CMD data - command_data = command; - for (uint8_t i = 0; i < 4; i++) { // Send byte - digitalWrite(sl_pdcki, LOW); - digitalWrite(sl_pdi, (command_data & 0x80)); - digitalWrite(sl_pdcki, HIGH); - command_data = command_data << 1; - digitalWrite(sl_pdi, (command_data & 0x80)); - digitalWrite(sl_pdcki, LOW); - digitalWrite(sl_pdi, LOW); - command_data = command_data << 1; - } + 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. + 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. + os_delay_us(12); // TStop > 12us. } -void sl_my9231_duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c) +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 duty_current = 0; + uint8_t channels[2] = { 4, 6 }; - uint8_t duty[6] = { duty_w, duty_c, 0, duty_g, duty_r, duty_b }; // Definition for RGBWC channels + uint8_t didx = sfl_flg -4; // 0 or 1 - os_delay_us(12); // TStop > 12us. - for (uint8_t channel = 0; channel < 6; channel++) { // WC0GRB 6CH - duty_current = duty[channel]; - for (uint8_t i = 0; i < 4; i++) { // Send 8bit Data - digitalWrite(sl_pdcki, LOW); - digitalWrite(sl_pdi, (duty_current & 0x80)); - digitalWrite(sl_pdcki, HIGH); - duty_current = duty_current << 1; - digitalWrite(sl_pdi, (duty_current & 0x80)); - digitalWrite(sl_pdcki, LOW); - digitalWrite(sl_pdi, LOW); - duty_current = duty_current << 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_my9291_duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w) -{ - uint8_t duty_current = 0; - - uint8_t duty[4] = { duty_r, duty_g, duty_b, duty_w }; // Definition for RGBW channels - - os_delay_us(12); // TStop > 12us. - for (uint8_t channel = 0; channel < 4; channel++) { // RGBW 4CH - duty_current = duty[channel]; // RGBW Channel - for (uint8_t i = 0; i < 4; i++) { // Send 8bit Data - digitalWrite(sl_pdcki, LOW); - digitalWrite(sl_pdi, (duty_current & 0x80)); - digitalWrite(sl_pdcki, HIGH); - duty_current = duty_current << 1; - digitalWrite(sl_pdi, (duty_current & 0x80)); - digitalWrite(sl_pdcki, LOW); - digitalWrite(sl_pdi, LOW); - duty_current = duty_current << 1; - } - } - 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. + 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. } /********************************************************************************************/ @@ -186,15 +166,7 @@ void sl_init(void) digitalWrite(sl_pdi, LOW); digitalWrite(sl_pdcki, LOW); - if (4 == sfl_flg) { - // Clear all duty register - sl_dcki_pulse(32); // 1 * 32 bits - sl_my92x1_command(1, 0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM - } else if (5 == sfl_flg) { - // Clear all duty register - sl_dcki_pulse(64); // 2 * 32 bits - sl_my92x1_command(2, 0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM - } + sl_my92x1_init(); } sl_power = 0; @@ -202,6 +174,46 @@ void sl_init(void) sl_wakeupActive = 0; } +void sl_setColorTemp(uint16_t ct) +{ +/* 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; + } + 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; @@ -350,11 +362,8 @@ void sl_animate() } } } - if (4 == sfl_flg) { - sl_my9291_duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3]); - } - else if (5 == sfl_flg) { - sl_my9231_duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); + if (sfl_flg > 3) { + sl_my92x1_duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); } } } @@ -410,35 +419,36 @@ void sl_getHSB(float *hue, float *sat, float *bri) } } -void sl_setHSB(float hue, float sat, float bri, float ct) +void sl_setHSB(float hue, float sat, float bri, uint16_t ct) { char svalue[MESSZ]; HsbColor hsb; - float my_ct; /* char log[LOGSZ]; char stemp1[10]; char stemp2[10]; char stemp3[10]; - char stemp4[10]; dtostrf(hue, 1, 3, stemp1); dtostrf(sat, 1, 3, stemp2); dtostrf(bri, 1, 3, stemp3); - dtostrf(ct, 1, 3, stemp4); - snprintf_P(log, sizeof(log), PSTR("HUE: Set Hue %s, Sat %s, Bri %s, Ct %s"), stemp1, stemp2, stemp3, stemp4); + 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) { - 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(); + 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 { @@ -446,20 +456,7 @@ void sl_setHSB(float hue, float sat, float bri, float ct) sysCfg.led_dimmer[0] = tmp; if (2 == sfl_flg) { if (ct > 0) { - my_ct = ct - 0.306; - if (my_ct > 0.694) { // >500 (Warm) - my_ct = 0.694; - } - float fcold = 367 * (0.694 - my_ct); // 0 - 255 - float fwarm = 367 * my_ct; // 0 - 255 - float fmax = (fwarm > fcold) ? fwarm : fcold; - float fbri = 100 / (fmax / 2.55); // Scale to 255 - if (bri < 1) { - bri = bri + 0.01; // Adjust for sl_setColor - } - sl_dcolor[0] = (uint8_t)(fcold * fbri * bri); // Cold - sl_dcolor[1] = (uint8_t)(fwarm * fbri * bri); // Warm - sl_setColor(); + sl_setColorTemp(ct); } sl_prepPower(svalue, sizeof(svalue)); mqtt_publish_topic_P(5, "COLOR", svalue); @@ -493,6 +490,14 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le 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"))) { if ((payload >= 0) && (payload <= 100)) { sysCfg.led_dimmer[0] = payload; diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino index 3d0aa30fc..ac522167d 100644 --- a/sonoff/xdrv_wemohue.ino +++ b/sonoff/xdrv_wemohue.ino @@ -533,7 +533,7 @@ void hue_lights(String *path) float bri = 0; float hue = 0; float sat = 0; - float ct = 0; + uint16_t ct = 0; bool resp = false; bool on = false; bool change = false; @@ -638,15 +638,14 @@ void hue_lights(String *path) change = true; } if (hue_json.containsKey("ct")) { // Color temperature 153 (Cold) to 500 (Warm) - tmp = hue_json["ct"]; - ct = (float)tmp / 500.0f; + 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(tmp)); + response.replace("{res}", String(ct)); change = true; } if (change) { @@ -669,7 +668,7 @@ void hue_lights(String *path) response = FPSTR(HUE_ERROR_JSON); } -addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); +//addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); webServer->send(200, FPSTR(HDR_CTYPE_JSON), response); }