mirror of https://github.com/arendst/Tasmota.git
Merge pull request #6652 from RoadRunnr/fix/pwm-multichannel
fix pwm multichannel
This commit is contained in:
commit
2128513c08
|
@ -7,6 +7,8 @@
|
||||||
* Add define USE_SONOFF_RF to enable/disable Sonoff Rf support (#6648)
|
* Add define USE_SONOFF_RF to enable/disable Sonoff Rf support (#6648)
|
||||||
* Add incremental beeps to Ifan03 remote control fan speed buttons (#6636)
|
* Add incremental beeps to Ifan03 remote control fan speed buttons (#6636)
|
||||||
* Add rule support after every command execution like Fanspeed#Data=2 (#6636)
|
* Add rule support after every command execution like Fanspeed#Data=2 (#6636)
|
||||||
|
* Fix handling of ligth channels when pwm_multichannel (Option68) is enabled
|
||||||
|
* Add WebUI for multiple, independent PWM channels
|
||||||
*
|
*
|
||||||
* 6.6.0.17 20191009
|
* 6.6.0.17 20191009
|
||||||
* Add command SetOption34 0..255 to set backlog delay. Default value is 200 (mSeconds) (#6562)
|
* Add command SetOption34 0..255 to set backlog delay. Default value is 200 (mSeconds) (#6562)
|
||||||
|
|
|
@ -153,39 +153,17 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM =
|
||||||
#endif // USE_SCRIPT_WEB_DISPLAY
|
#endif // USE_SCRIPT_WEB_DISPLAY
|
||||||
|
|
||||||
#ifdef USE_JAVASCRIPT_ES6
|
#ifdef USE_JAVASCRIPT_ES6
|
||||||
"lb=p=>la('&d='+p);" // Dark - Bright &d related to lb(value) and WebGetArg("d", tmp, sizeof(tmp));
|
"lb=(v,p)=>la(`&${v}=${p}`);"
|
||||||
"lc=p=>la('&t='+p);" // Cold - Warm &t related to lc(value) and WebGetArg("t", tmp, sizeof(tmp));
|
"lc=(v,i,p)=>la(`&${v}${i}=${p}`);"
|
||||||
#else
|
#else
|
||||||
"function lb(p){"
|
"function lb(v,p){"
|
||||||
"la('&d='+p);" // &d related to WebGetArg("d", tmp, sizeof(tmp));
|
"la('&'+v+'='+p);"
|
||||||
"}"
|
"}"
|
||||||
"function lc(p){"
|
"function lc(v,i,p){"
|
||||||
"la('&t='+p);" // &t related to WebGetArg("t", tmp, sizeof(tmp));
|
"la('&'+v+i+'='+p);"
|
||||||
"}"
|
"}"
|
||||||
#endif // USE_JAVASCRIPT_ES6
|
#endif // USE_JAVASCRIPT_ES6
|
||||||
|
|
||||||
#ifdef USE_SHUTTER
|
|
||||||
#ifdef USE_JAVASCRIPT_ES6
|
|
||||||
"ld1=p=>la('&u1='+p);"
|
|
||||||
"ld2=p=>la('&u2='+p);"
|
|
||||||
"ld3=p=>la('&u3='+p);"
|
|
||||||
"ld4=p=>la('&u4='+p);"
|
|
||||||
#else
|
|
||||||
"function ld1(p){"
|
|
||||||
"la('&u1='+p);"
|
|
||||||
"}"
|
|
||||||
"function ld2(p){"
|
|
||||||
"la('&u2='+p);"
|
|
||||||
"}"
|
|
||||||
"function ld3(p){"
|
|
||||||
"la('&u3='+p);"
|
|
||||||
"}"
|
|
||||||
"function ld4(p){"
|
|
||||||
"la('&u4='+p);"
|
|
||||||
"}"
|
|
||||||
#endif // USE_JAVASCRIPT_ES6
|
|
||||||
#endif // USE_SHUTTER
|
|
||||||
|
|
||||||
"wl(la);";
|
"wl(la);";
|
||||||
|
|
||||||
const char HTTP_SCRIPT_WIFI[] PROGMEM =
|
const char HTTP_SCRIPT_WIFI[] PROGMEM =
|
||||||
|
@ -395,16 +373,11 @@ const char HTTP_HEAD_STYLE3[] PROGMEM =
|
||||||
"<h2>%s</h2>";
|
"<h2>%s</h2>";
|
||||||
|
|
||||||
const char HTTP_MSG_SLIDER1[] PROGMEM =
|
const char HTTP_MSG_SLIDER1[] PROGMEM =
|
||||||
"<div><span class='p'>" D_COLDLIGHT "</span><span class='q'>" D_WARMLIGHT "</span></div>"
|
"<div><span class='p'>%s</span><span class='q'>%s</span></div>"
|
||||||
"<div><input type='range' min='153' max='500' value='%d' onchange='lc(value)'></div>";
|
"<div><input type='range' min='%d' max='%d' value='%d' onchange='lb(\"%c\", value)'></div>";
|
||||||
const char HTTP_MSG_SLIDER2[] PROGMEM =
|
const char HTTP_MSG_SLIDER2[] PROGMEM =
|
||||||
"<div><span class='p'>" D_DARKLIGHT "</span><span class='q'>" D_BRIGHTLIGHT "</span></div>"
|
"<div><span class='p'>%s</span><span class='q'>%s</span></div>"
|
||||||
"<div><input type='range' min='1' max='100' value='%d' onchange='lb(value)'></div>";
|
"<div><input type='range' min='%d' max='%d' value='%d' onchange='lc(\"%c\", %d, value)'></div>";
|
||||||
#ifdef USE_SHUTTER
|
|
||||||
const char HTTP_MSG_SLIDER3[] PROGMEM =
|
|
||||||
"<div><span class='p'>" D_CLOSE "</span><span class='q'>" D_OPEN "</span></div>"
|
|
||||||
"<div><input type='range' min='0' max='100' value='%d' onchange='ld%d(value)'></div>";
|
|
||||||
#endif // USE_SHUTTER
|
|
||||||
const char HTTP_MSG_RSTRT[] PROGMEM =
|
const char HTTP_MSG_RSTRT[] PROGMEM =
|
||||||
"<br><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br>";
|
"<br><div style='text-align:center;'>" D_DEVICE_WILL_RESTART "</div><br>";
|
||||||
|
|
||||||
|
@ -1012,16 +985,31 @@ void HandleRoot(void)
|
||||||
if (devices_present) {
|
if (devices_present) {
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
if (light_type) {
|
if (light_type) {
|
||||||
if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) {
|
if (!Settings.flag3.pwm_multi_channels) {
|
||||||
WSContentSend_P(HTTP_MSG_SLIDER1, LightGetColorTemp());
|
if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) {
|
||||||
}
|
// Cold - Warm &t related to lb("t", value) and WebGetArg("t", tmp, sizeof(tmp));
|
||||||
WSContentSend_P(HTTP_MSG_SLIDER2, Settings.light_dimmer);
|
WSContentSend_P(HTTP_MSG_SLIDER1, F(D_COLDLIGHT), F(D_WARMLIGHT),
|
||||||
|
153, 500, LightGetColorTemp(), 't');
|
||||||
|
}
|
||||||
|
// Dark - Bright &d related to lb("d", value) and WebGetArg("d", tmp, sizeof(tmp));
|
||||||
|
WSContentSend_P(HTTP_MSG_SLIDER1, F(D_DARKLIGHT), F(D_BRIGHTLIGHT),
|
||||||
|
1, 100, Settings.light_dimmer, 'd');
|
||||||
|
} else { // Settings.flag3.pwm_multi_channels
|
||||||
|
uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7);
|
||||||
|
for (uint32_t i = 0; i < pwm_channels; i++) {
|
||||||
|
snprintf_P(stemp, sizeof(stemp), PSTR("c%d"), i);
|
||||||
|
WSContentSend_P(HTTP_MSG_SLIDER2, stemp, FPSTR("100%"),
|
||||||
|
1, 100,
|
||||||
|
changeUIntScale(Settings.light_color[i], 0, 255, 0, 100), 'd', i+1);
|
||||||
|
}
|
||||||
|
} // Settings.flag3.pwm_multi_channels
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_SHUTTER
|
#ifdef USE_SHUTTER
|
||||||
if (Settings.flag3.shutter_mode) {
|
if (Settings.flag3.shutter_mode) {
|
||||||
for (uint32_t i = 0; i < shutters_present; i++) {
|
for (uint32_t i = 0; i < shutters_present; i++) {
|
||||||
WSContentSend_P(HTTP_MSG_SLIDER3, Settings.shutter_position[i], i+1);
|
WSContentSend_P(HTTP_MSG_SLIDER2, F(D_CLOSE), F(D_OPEN),
|
||||||
|
0, 100, Settings.shutter_position[i], 'u', i+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_SHUTTER
|
#endif // USE_SHUTTER
|
||||||
|
@ -1097,6 +1085,7 @@ bool HandleRootStatusRefresh(void)
|
||||||
|
|
||||||
char tmp[8]; // WebGetArg numbers only
|
char tmp[8]; // WebGetArg numbers only
|
||||||
char svalue[32]; // Command and number parameter
|
char svalue[32]; // Command and number parameter
|
||||||
|
char webindex[5]; // WebGetArg name
|
||||||
|
|
||||||
WebGetArg("o", tmp, sizeof(tmp)); // 1 - 16 Device number for button Toggle or Fanspeed
|
WebGetArg("o", tmp, sizeof(tmp)); // 1 - 16 Device number for button Toggle or Fanspeed
|
||||||
if (strlen(tmp)) {
|
if (strlen(tmp)) {
|
||||||
|
@ -1122,13 +1111,21 @@ bool HandleRootStatusRefresh(void)
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp);
|
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp);
|
||||||
ExecuteWebCommand(svalue, SRC_WEBGUI);
|
ExecuteWebCommand(svalue, SRC_WEBGUI);
|
||||||
}
|
}
|
||||||
|
uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7);
|
||||||
|
for (uint32_t j = 1; j <= pwm_channels; j++) {
|
||||||
|
snprintf_P(webindex, sizeof(webindex), PSTR("d%d"), j);
|
||||||
|
WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent
|
||||||
|
if (strlen(tmp)) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_CHANNEL "%d %s"), j, tmp);
|
||||||
|
ExecuteWebCommand(svalue, SRC_WEBGUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
WebGetArg("t", tmp, sizeof(tmp)); // 153 - 500 Color temperature
|
WebGetArg("t", tmp, sizeof(tmp)); // 153 - 500 Color temperature
|
||||||
if (strlen(tmp)) {
|
if (strlen(tmp)) {
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp);
|
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp);
|
||||||
ExecuteWebCommand(svalue, SRC_WEBGUI);
|
ExecuteWebCommand(svalue, SRC_WEBGUI);
|
||||||
}
|
}
|
||||||
#ifdef USE_SHUTTER
|
#ifdef USE_SHUTTER
|
||||||
char webindex[5]; // WebGetArg name
|
|
||||||
for (uint32_t j = 1; j <= shutters_present; j++) {
|
for (uint32_t j = 1; j <= shutters_present; j++) {
|
||||||
snprintf_P(webindex, sizeof(webindex), PSTR("u%d"), j);
|
snprintf_P(webindex, sizeof(webindex), PSTR("u%d"), j);
|
||||||
WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent
|
WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent
|
||||||
|
|
|
@ -420,6 +420,14 @@ class LightStateClass {
|
||||||
getActualRGBCW(&channels[0], &channels[1], &channels[2], &channels[3], &channels[4]);
|
getActualRGBCW(&channels[0], &channels[1], &channels[2], &channels[3], &channels[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getChannelsRaw(uint8_t *channels) {
|
||||||
|
channels[0] = _r;
|
||||||
|
channels[1] = _g;
|
||||||
|
channels[2] = _b;
|
||||||
|
channels[3] = _wc;
|
||||||
|
channels[4] = _ww;
|
||||||
|
}
|
||||||
|
|
||||||
void getHSB(uint16_t *hue, uint8_t *sat, uint8_t *bri) {
|
void getHSB(uint16_t *hue, uint8_t *sat, uint8_t *bri) {
|
||||||
if (hue) { *hue = _hue; }
|
if (hue) { *hue = _hue; }
|
||||||
if (sat) { *sat = _sat; }
|
if (sat) { *sat = _sat; }
|
||||||
|
@ -602,6 +610,16 @@ class LightStateClass {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set all 5 channels at once, don't modify the values in ANY way
|
||||||
|
// Channels are: R G B CW WW
|
||||||
|
void setChannelsRaw(uint8_t *channels) {
|
||||||
|
_r = channels[0];
|
||||||
|
_g = channels[1];
|
||||||
|
_b = channels[2];
|
||||||
|
_wc = channels[3];
|
||||||
|
_ww = channels[4];
|
||||||
|
}
|
||||||
|
|
||||||
// set all 5 channels at once.
|
// set all 5 channels at once.
|
||||||
// Channels are: R G B CW WW
|
// Channels are: R G B CW WW
|
||||||
// Brightness is automatically recalculated to adjust channels to the desired values
|
// Brightness is automatically recalculated to adjust channels to the desired values
|
||||||
|
@ -838,10 +856,13 @@ public:
|
||||||
AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::loadSettings light_type/sub (%d %d)",
|
AddLog_P2(LOG_LEVEL_DEBUG_MORE, "LightControllerClass::loadSettings light_type/sub (%d %d)",
|
||||||
light_type, Light.subtype);
|
light_type, Light.subtype);
|
||||||
#endif
|
#endif
|
||||||
// first try setting CW, if zero, it select RGB mode
|
if (_pwm_multi_channels) {
|
||||||
_state->setCW(Settings.light_color[3], Settings.light_color[4], true);
|
_state->setChannelsRaw(Settings.light_color);
|
||||||
_state->setRGB(Settings.light_color[0], Settings.light_color[1], Settings.light_color[2]);
|
} else {
|
||||||
if (!_pwm_multi_channels) {
|
// first try setting CW, if zero, it select RGB mode
|
||||||
|
_state->setCW(Settings.light_color[3], Settings.light_color[4], true);
|
||||||
|
_state->setRGB(Settings.light_color[0], Settings.light_color[1], Settings.light_color[2]);
|
||||||
|
|
||||||
// only if non-multi channel
|
// only if non-multi channel
|
||||||
// We apply dimmer in priority to RGB
|
// We apply dimmer in priority to RGB
|
||||||
uint8_t bri = _state->DimmerToBri(Settings.light_dimmer);
|
uint8_t bri = _state->DimmerToBri(Settings.light_dimmer);
|
||||||
|
@ -893,16 +914,13 @@ public:
|
||||||
// calculate the levels for each channel
|
// calculate the levels for each channel
|
||||||
void calcLevels() {
|
void calcLevels() {
|
||||||
uint8_t r,g,b,c,w,briRGB,briCT;
|
uint8_t r,g,b,c,w,briRGB,briCT;
|
||||||
_state->getActualRGBCW(&r,&g,&b,&c,&w);
|
|
||||||
|
|
||||||
if (_pwm_multi_channels) { // if PWM multi channel, no more transformation required
|
if (_pwm_multi_channels) { // if PWM multi channel, no more transformation required
|
||||||
Light.current_color[0] = r;
|
_state->getChannelsRaw(Light.current_color);
|
||||||
Light.current_color[1] = g;
|
|
||||||
Light.current_color[2] = b;
|
|
||||||
Light.current_color[3] = c;
|
|
||||||
Light.current_color[4] = w;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_state->getActualRGBCW(&r,&g,&b,&c,&w);
|
||||||
briRGB = _state->getBriRGB();
|
briRGB = _state->getBriRGB();
|
||||||
briCT = _state->getBriCT();
|
briCT = _state->getBriCT();
|
||||||
|
|
||||||
|
@ -948,9 +966,7 @@ public:
|
||||||
void saveSettings() {
|
void saveSettings() {
|
||||||
if (Light.pwm_multi_channels) {
|
if (Light.pwm_multi_channels) {
|
||||||
// simply save each channel
|
// simply save each channel
|
||||||
_state->getActualRGBCW(&Settings.light_color[0], &Settings.light_color[1],
|
_state->getChannelsRaw(Settings.light_color);
|
||||||
&Settings.light_color[2], &Settings.light_color[3],
|
|
||||||
&Settings.light_color[4]);
|
|
||||||
Settings.light_dimmer = 100; // arbitrary value, unused in this mode
|
Settings.light_dimmer = 100; // arbitrary value, unused in this mode
|
||||||
} else {
|
} else {
|
||||||
uint8_t cm = _state->getColorMode();
|
uint8_t cm = _state->getColorMode();
|
||||||
|
@ -980,13 +996,16 @@ public:
|
||||||
// Channels are: R G B CW WW
|
// Channels are: R G B CW WW
|
||||||
// Brightness is automatically recalculated to adjust channels to the desired values
|
// Brightness is automatically recalculated to adjust channels to the desired values
|
||||||
void changeChannels(uint8_t *channels) {
|
void changeChannels(uint8_t *channels) {
|
||||||
if (LST_COLDWARM == Light.subtype) {
|
if (Light.pwm_multi_channels) {
|
||||||
|
_state->setChannelsRaw(channels);
|
||||||
|
} else if (LST_COLDWARM == Light.subtype) {
|
||||||
// remap channels 0-1 to 3-4 if cold/warm
|
// remap channels 0-1 to 3-4 if cold/warm
|
||||||
uint8_t remapped_channels[5] = {0,0,0,channels[0],channels[1]};
|
uint8_t remapped_channels[5] = {0,0,0,channels[0],channels[1]};
|
||||||
_state->setChannels(remapped_channels);
|
_state->setChannels(remapped_channels);
|
||||||
} else {
|
} else {
|
||||||
_state->setChannels(channels);
|
_state->setChannels(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSettings();
|
saveSettings();
|
||||||
calcLevels();
|
calcLevels();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue