Merge pull request #2011 from blazoncek/multi-button-update

Added MQTT support for buttons and simplified switch.
This commit is contained in:
Christian Schwinne 2021-07-01 14:57:12 +02:00 committed by GitHub
commit e16a67242e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 14 deletions

View File

@ -6,6 +6,8 @@
#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing) #define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing)
static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage
void shortPressAction(uint8_t b) void shortPressAction(uint8_t b)
{ {
if (!macroButton[b]) if (!macroButton[b])
@ -15,6 +17,13 @@ void shortPressAction(uint8_t b)
} else { } else {
applyPreset(macroButton[b]); applyPreset(macroButton[b]);
} }
// publish MQTT message
if (WLED_MQTT_CONNECTED) {
char subuf[64];
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, "short");
}
} }
bool isButtonPressed(uint8_t i) bool isButtonPressed(uint8_t i)
@ -29,7 +38,7 @@ bool isButtonPressed(uint8_t i)
if (digitalRead(btnPin[i]) == LOW) return true; if (digitalRead(btnPin[i]) == LOW) return true;
break; break;
case BTN_TYPE_PUSH_ACT_HIGH: case BTN_TYPE_PUSH_ACT_HIGH:
case BTN_TYPE_SWITCH_ACT_HIGH: case BTN_TYPE_PIR_SENSOR:
if (digitalRead(btnPin[i]) == HIGH) return true; if (digitalRead(btnPin[i]) == HIGH) return true;
break; break;
case BTN_TYPE_TOUCH: case BTN_TYPE_TOUCH:
@ -43,6 +52,7 @@ bool isButtonPressed(uint8_t i)
void handleSwitch(uint8_t b) void handleSwitch(uint8_t b)
{ {
// isButtonPressed() handles inverted/noninverted logic
if (buttonPressedBefore[b] != isButtonPressed(b)) { if (buttonPressedBefore[b] != isButtonPressed(b)) {
buttonPressedTime[b] = millis(); buttonPressedTime[b] = millis();
buttonPressedBefore[b] = !buttonPressedBefore[b]; buttonPressedBefore[b] = !buttonPressedBefore[b];
@ -51,17 +61,26 @@ void handleSwitch(uint8_t b)
if (buttonLongPressed[b] == buttonPressedBefore[b]) return; if (buttonLongPressed[b] == buttonPressedBefore[b]) return;
if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce) if (millis() - buttonPressedTime[b] > WLED_DEBOUNCE_THRESHOLD) { //fire edge event only after 50ms without change (debounce)
if (buttonPressedBefore[b]) { //LOW, falling edge, switch closed if (!buttonPressedBefore[b]) { // on -> off
if (macroButton[b]) applyPreset(macroButton[b]); if (macroButton[b]) applyPreset(macroButton[b]);
else { //turn on else { //turn on
if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);} if (!bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
} }
} else { //HIGH, rising edge, switch opened } else { // off -> on
if (macroLongPress[b]) applyPreset(macroLongPress[b]); if (macroLongPress[b]) applyPreset(macroLongPress[b]);
else { //turn off else { //turn off
if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);} if (bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);}
} }
} }
// publish MQTT message
if (WLED_MQTT_CONNECTED) {
char subuf[64];
if (buttonType[b] == BTN_TYPE_PIR_SENSOR) sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)b);
else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on");
}
buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state buttonLongPressed[b] = buttonPressedBefore[b]; //save the last "long term" switch state
} }
} }
@ -74,6 +93,9 @@ void handleAnalog(uint8_t b)
#else #else
uint16_t aRead = analogRead(btnPin[b]) >> 4; // convert 12bit read to 8bit uint16_t aRead = analogRead(btnPin[b]) >> 4; // convert 12bit read to 8bit
#endif #endif
if (buttonType[b] == BTN_TYPE_ANALOG_INVERTED) aRead = 255 - aRead;
// remove noise & reduce frequency of UI updates // remove noise & reduce frequency of UI updates
aRead &= 0xFC; aRead &= 0xFC;
@ -132,8 +154,6 @@ void handleAnalog(uint8_t b)
seg.setOption(SEG_OPTION_ON, 1); seg.setOption(SEG_OPTION_ON, 1);
} }
// this will notify clients of update (websockets,mqtt,etc) // this will notify clients of update (websockets,mqtt,etc)
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
updateInterfaces(NOTIFIER_CALL_MODE_BUTTON); updateInterfaces(NOTIFIER_CALL_MODE_BUTTON);
} }
} else { } else {
@ -141,8 +161,6 @@ void handleAnalog(uint8_t b)
// we can either trigger a preset depending on the level (between short and long entries) // we can either trigger a preset depending on the level (between short and long entries)
// or use it for RGBW direct control // or use it for RGBW direct control
} }
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
@ -152,17 +170,18 @@ void handleButton()
for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) { for (uint8_t b=0; b<WLED_MAX_BUTTONS; b++) {
#ifdef ESP8266 #ifdef ESP8266
if ((btnPin[b]<0 && buttonType[b] != BTN_TYPE_ANALOG) || buttonType[b] == BTN_TYPE_NONE) continue; if ((btnPin[b]<0 && !(buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED)) || buttonType[b] == BTN_TYPE_NONE) continue;
#else #else
if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue; if (btnPin[b]<0 || buttonType[b] == BTN_TYPE_NONE) continue;
#endif #endif
if (buttonType[b] == BTN_TYPE_ANALOG && millis() - lastRead > 250) { // button is not a button but a potentiometer if ((buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) && millis() - lastRead > 250) { // button is not a button but a potentiometer
if (b+1 == WLED_MAX_BUTTONS) lastRead = millis(); if (b+1 == WLED_MAX_BUTTONS) lastRead = millis();
handleAnalog(b); continue; handleAnalog(b); continue;
} }
if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_SWITCH_ACT_HIGH) { //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0) //button is not momentary, but switch. This is only suitable on pins whose on-boot state does not matter (NOT gpio0)
if (buttonType[b] == BTN_TYPE_SWITCH || buttonType[b] == BTN_TYPE_PIR_SENSOR) {
handleSwitch(b); continue; handleSwitch(b); continue;
} }
@ -179,6 +198,13 @@ void handleButton()
if (macroLongPress[b]) {applyPreset(macroLongPress[b]);} if (macroLongPress[b]) {applyPreset(macroLongPress[b]);}
else _setRandomColor(false,true); else _setRandomColor(false,true);
// publish MQTT message
if (WLED_MQTT_CONNECTED) {
char subuf[64];
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, "long");
}
buttonLongPressed[b] = true; buttonLongPressed[b] = true;
} }
} }
@ -197,8 +223,16 @@ void handleButton()
else if (!buttonLongPressed[b]) { //short press else if (!buttonLongPressed[b]) { //short press
if (macroDoublePress[b]) if (macroDoublePress[b])
{ {
if (doublePress) applyPreset(macroDoublePress[b]); if (doublePress) {
else buttonWaitTime[b] = millis(); applyPreset(macroDoublePress[b]);
// publish MQTT message
if (WLED_MQTT_CONNECTED) {
char subuf[64];
sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b);
mqtt->publish(subuf, 0, false, "double");
}
} else buttonWaitTime[b] = millis();
} else shortPressAction(b); } else shortPressAction(b);
} }
buttonPressedBefore[b] = false; buttonPressedBefore[b] = false;

View File

@ -161,9 +161,10 @@
#define BTN_TYPE_PUSH 2 #define BTN_TYPE_PUSH 2
#define BTN_TYPE_PUSH_ACT_HIGH 3 #define BTN_TYPE_PUSH_ACT_HIGH 3
#define BTN_TYPE_SWITCH 4 #define BTN_TYPE_SWITCH 4
#define BTN_TYPE_SWITCH_ACT_HIGH 5 #define BTN_TYPE_PIR_SENSOR 5
#define BTN_TYPE_TOUCH 6 #define BTN_TYPE_TOUCH 6
#define BTN_TYPE_ANALOG 7 #define BTN_TYPE_ANALOG 7
#define BTN_TYPE_ANALOG_INVERTED 8
//Ethernet board types //Ethernet board types
#define WLED_NUM_ETH_TYPES 7 #define WLED_NUM_ETH_TYPES 7

View File

@ -286,9 +286,10 @@ Reverse (rotated 180°): <input type="checkbox" name="CV${i}">
c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`; c += `<option value="2" ${t==2?"selected":""}>Pushbutton</option>`;
c += `<option value="3" ${t==3?"selected":""}>Push inverted</option>`; c += `<option value="3" ${t==3?"selected":""}>Push inverted</option>`;
c += `<option value="4" ${t==4?"selected":""}>Switch</option>`; c += `<option value="4" ${t==4?"selected":""}>Switch</option>`;
c += `<option value="5" ${t==4?"selected":""}>Switch inverted</option>`; c += `<option value="5" ${t==5?"selected":""}>PIR sensor</option>`;
c += `<option value="6" ${t==6?"selected":""}>Touch</option>`; c += `<option value="6" ${t==6?"selected":""}>Touch</option>`;
c += `<option value="7" ${t==7?"selected":""}>Analog</option>`; c += `<option value="7" ${t==7?"selected":""}>Analog</option>`;
c += `<option value="8" ${t==8?"selected":""}>Analog inverted</option>`;
c += `</select>`; c += `</select>`;
c += `<span style="cursor: pointer;" onclick="off('${bt}')">&nbsp;&#215;</span><br>`; c += `<span style="cursor: pointer;" onclick="off('${bt}')">&nbsp;&#215;</span><br>`;
gId("btns").innerHTML = c; gId("btns").innerHTML = c;