Add Sonoff B1 features

This commit is contained in:
arendst 2017-08-16 17:05:36 +02:00
parent 99c9b1671c
commit ebee148be8
7 changed files with 141 additions and 118 deletions

View File

@ -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)

View File

@ -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};

View File

@ -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

View File

@ -70,6 +70,9 @@ const char HTTP_HEAD[] PROGMEM =
"function lb(p){"
"la('?d='+p);"
"}"
"function lc(p){"
"la('?t='+p);"
"}"
"</script>"
"<style>"
@ -81,12 +84,13 @@ const char HTTP_HEAD[] PROGMEM =
"td{padding:0px;}"
"button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;-webkit-transition-duration:0.4s;transition-duration:0.4s;}"
"button:hover{background-color:#006cba;}"
".q{float:right;width:200px;text-align:right;}"
".p{float:left;text-align:left;}"
".q{float:right;text-align:right;}"
"</style>"
"</head>"
"<body>"
"<div style='text-align:left;display:inline-block;min-width:320px;'>"
"<div style='text-align:left;display:inline-block;min-width:340px;'>"
"<div style='text-align:center;'><h3>{ha} Module</h3><h2>{h}</h2></div>";
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("<body>"), F("<body onload='la()'>"));
@ -423,7 +427,12 @@ void handleRoot()
page += F("<div id='l1' name='l1'></div>");
if (Maxdevice) {
if (sfl_flg) {
snprintf_P(line, sizeof(line), PSTR("<input type='range' min='1' max='100' value='%d' onchange='lb(value)'>"),
if ((2 == sfl_flg) || (5 == sfl_flg)) {
snprintf_P(line, sizeof(line), PSTR("<div><span class='p'>Cold</span><span class='q'>Warm</span></div><div><input type='range' min='153' max='500' value='%d' onchange='lc(value)'></div>"),
sl_getColorTemp());
page += line;
}
snprintf_P(line, sizeof(line), PSTR("<div><span class='p'>Dark</span><span class='q'>Bright</span></div><div><input type='range' min='1' max='100' value='%d' onchange='lb(value)'></div>"),
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);

View File

@ -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

View File

@ -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;

View File

@ -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);
}