Merge pull request #2497 from herm/usermod_multirelay
Add Home Assisant MQTT autodiscovery for usermod multi_relay.
This commit is contained in:
commit
ea15c2245e
@ -36,7 +36,7 @@ wled/deviceMAC/relay/0 on|off
|
||||
|
||||
1. Register the usermod by adding `#include "../usermods/multi_relay/usermod_multi_relay.h"` at the top and `usermods.add(new MultiRelay());` at the bottom of `usermods_list.cpp`.
|
||||
or
|
||||
2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY`in your platformio.ini
|
||||
2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY` in your platformio.ini
|
||||
|
||||
You can override the default maximum number (4) of relays by defining MULTI_RELAY_MAX_RELAYS.
|
||||
|
||||
|
@ -45,6 +45,11 @@ class MultiRelay : public Usermod {
|
||||
// status of initialisation
|
||||
bool initDone = false;
|
||||
|
||||
bool HAautodiscovery = false;
|
||||
|
||||
uint16_t periodicBroadcastSec = 60;
|
||||
unsigned long lastBroadcast = 0;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
@ -53,14 +58,15 @@ class MultiRelay : public Usermod {
|
||||
static const char _activeHigh[];
|
||||
static const char _external[];
|
||||
static const char _button[];
|
||||
static const char _broadcast[];
|
||||
static const char _HAautodiscovery[];
|
||||
|
||||
|
||||
void publishMqtt(const char* state, int relay) {
|
||||
void publishMqtt(int relay) {
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED){
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay);
|
||||
mqtt->publish(subuf, 0, false, state);
|
||||
mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,15 +74,19 @@ class MultiRelay : public Usermod {
|
||||
* switch off the strip if the delay has elapsed
|
||||
*/
|
||||
void handleOffTimer() {
|
||||
unsigned long now = millis();
|
||||
bool activeRelays = false;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].active && _switchTimerStart > 0 && millis() - _switchTimerStart > (_relay[i].delay*1000)) {
|
||||
if (_relay[i].active && _switchTimerStart > 0 && now - _switchTimerStart > (_relay[i].delay*1000)) {
|
||||
if (!_relay[i].external) toggleRelay(i);
|
||||
_relay[i].active = false;
|
||||
} else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
|
||||
if (_relay[i].pin>=0) publishMqtt(i);
|
||||
}
|
||||
activeRelays = activeRelays || _relay[i].active;
|
||||
}
|
||||
if (!activeRelays) _switchTimerStart = 0;
|
||||
if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) lastBroadcast = now;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,7 +115,7 @@ class MultiRelay : public Usermod {
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
int value = getValue(p->value(), ',', i);
|
||||
if (value==-1) {
|
||||
error = F("There must be as much arugments as relays");
|
||||
error = F("There must be as many arguments as relays");
|
||||
} else {
|
||||
// Switch
|
||||
if (_relay[i].external) switchRelay(i, (bool)value);
|
||||
@ -118,7 +128,7 @@ class MultiRelay : public Usermod {
|
||||
for (int i=0;i<MULTI_RELAY_MAX_RELAYS;i++) {
|
||||
int value = getValue(p->value(), ',', i);
|
||||
if (value==-1) {
|
||||
error = F("There must be as mutch arugments as relays");
|
||||
error = F("There must be as many arguments as relays");
|
||||
} else {
|
||||
// Toggle
|
||||
if (value && _relay[i].external) toggleRelay(i);
|
||||
@ -199,7 +209,7 @@ class MultiRelay : public Usermod {
|
||||
_relay[relay].state = mode;
|
||||
pinMode(_relay[relay].pin, OUTPUT);
|
||||
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
|
||||
publishMqtt(mode ? "on" : "off", relay);
|
||||
publishMqtt(relay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -252,6 +262,50 @@ class MultiRelay : public Usermod {
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat_P(subuf, PSTR("/relay/#"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
if (HAautodiscovery) publishHomeAssistantAutodiscovery();
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin<0) continue;
|
||||
publishMqtt(i); //publish current state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void publishHomeAssistantAutodiscovery() {
|
||||
for (uint8_t i = 0; i < MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
char uid[16], json_str[1024], buf[128];
|
||||
size_t payload_size;
|
||||
sprintf_P(uid, PSTR("%s_sw%d"), escapedMac.c_str(), i);
|
||||
|
||||
if (_relay[i].pin >= 0 && _relay[i].external) {
|
||||
StaticJsonDocument<1024> json;
|
||||
sprintf_P(buf, PSTR("%s Switch %d"), serverDescription, i); //max length: 33 + 8 + 3 = 44
|
||||
json[F("name")] = buf;
|
||||
|
||||
sprintf_P(buf, PSTR("%s/relay/%d"), mqttDeviceTopic, i); //max length: 33 + 7 + 3 = 43
|
||||
json["~"] = buf;
|
||||
strcat_P(buf, PSTR("/command"));
|
||||
mqtt->subscribe(buf, 0);
|
||||
|
||||
json[F("stat_t")] = "~";
|
||||
json[F("cmd_t")] = F("~/command");
|
||||
json[F("pl_off")] = F("off");
|
||||
json[F("pl_on")] = F("on");
|
||||
json[F("uniq_id")] = uid;
|
||||
|
||||
strcpy(buf, mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||
strcat_P(buf, PSTR("/status"));
|
||||
json[F("avty_t")] = buf;
|
||||
json[F("pl_avail")] = F("online");
|
||||
json[F("pl_not_avail")] = F("offline");
|
||||
//TODO: dev
|
||||
payload_size = serializeJson(json, json_str);
|
||||
} else {
|
||||
//Unpublish disabled or internal relays
|
||||
json_str[0] = 0;
|
||||
payload_size = 0;
|
||||
}
|
||||
sprintf_P(buf, PSTR("homeassistant/switch/%s/config"), uid);
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +320,7 @@ class MultiRelay : public Usermod {
|
||||
if (!pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) {
|
||||
_relay[i].pin = -1; // allocation failed
|
||||
} else {
|
||||
if (!_relay[i].external) _relay[i].state = offMode;
|
||||
if (!_relay[i].external) _relay[i].state = !offMode;
|
||||
switchRelay(i, _relay[i].state);
|
||||
_relay[i].active = false;
|
||||
}
|
||||
@ -313,13 +367,18 @@ class MultiRelay : public Usermod {
|
||||
*/
|
||||
bool handleButton(uint8_t b) {
|
||||
yield();
|
||||
if (buttonType[b] == BTN_TYPE_NONE || buttonType[b] == BTN_TYPE_RESERVED || buttonType[b] == BTN_TYPE_PIR_SENSOR || buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
if (!enabled
|
||||
|| buttonType[b] == BTN_TYPE_NONE
|
||||
|| buttonType[b] == BTN_TYPE_RESERVED
|
||||
|| buttonType[b] == BTN_TYPE_PIR_SENSOR
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].button == b) {
|
||||
if (_relay[i].button == b && _relay[i].external) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -355,6 +414,8 @@ class MultiRelay : public Usermod {
|
||||
buttonPressedBefore[b] = true;
|
||||
|
||||
if (now - buttonPressedTime[b] > 600) { //long press
|
||||
//longPressAction(b); //not exposed
|
||||
//handled = false; //use if you want to pass to default behaviour
|
||||
buttonLongPressed[b] = true;
|
||||
}
|
||||
|
||||
@ -371,7 +432,8 @@ class MultiRelay : public Usermod {
|
||||
if (!buttonLongPressed[b]) { //short press
|
||||
// if this is second release within 350ms it is a double press (buttonWaitTime!=0)
|
||||
if (doublePress) {
|
||||
//doublePressAction(b);
|
||||
//doublePressAction(b); //not exposed
|
||||
//handled = false; //use if you want to pass to default behaviour
|
||||
} else {
|
||||
buttonWaitTime[b] = now;
|
||||
}
|
||||
@ -379,9 +441,10 @@ class MultiRelay : public Usermod {
|
||||
buttonPressedBefore[b] = false;
|
||||
buttonLongPressed[b] = false;
|
||||
}
|
||||
// if 450ms elapsed since last press/release it is a short press
|
||||
// if 350ms elapsed since last press/release it is a short press
|
||||
if (buttonWaitTime[b] && now - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
|
||||
buttonWaitTime[b] = 0;
|
||||
//shortPressAction(b); //not exposed
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin>=0 && _relay[i].button == b) {
|
||||
toggleRelay(i);
|
||||
@ -477,6 +540,7 @@ class MultiRelay : public Usermod {
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
top[FPSTR(_broadcast)] = periodicBroadcastSec;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
JsonObject relay = top.createNestedObject(parName);
|
||||
@ -486,6 +550,7 @@ class MultiRelay : public Usermod {
|
||||
relay[FPSTR(_external)] = _relay[i].external;
|
||||
relay[FPSTR(_button)] = _relay[i].button;
|
||||
}
|
||||
top[FPSTR(_HAautodiscovery)] = HAautodiscovery;
|
||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||
}
|
||||
|
||||
@ -506,6 +571,9 @@ class MultiRelay : public Usermod {
|
||||
}
|
||||
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
||||
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
||||
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
||||
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
@ -539,7 +607,9 @@ class MultiRelay : public Usermod {
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin>=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) {
|
||||
if (!_relay[i].external) {
|
||||
switchRelay(i, offMode);
|
||||
_relay[i].state = !offMode;
|
||||
switchRelay(i, _relay[i].state);
|
||||
_oldMode = offMode;
|
||||
}
|
||||
} else {
|
||||
_relay[i].pin = -1;
|
||||
@ -549,7 +619,7 @@ class MultiRelay : public Usermod {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[F("relay-0")][FPSTR(_button)].isNull();
|
||||
return !top[FPSTR(_broadcast)].isNull();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -570,3 +640,5 @@ const char MultiRelay::_delay_str[] PROGMEM = "delay-s";
|
||||
const char MultiRelay::_activeHigh[] PROGMEM = "active-high";
|
||||
const char MultiRelay::_external[] PROGMEM = "external";
|
||||
const char MultiRelay::_button[] PROGMEM = "button";
|
||||
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
|
||||
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
|
||||
|
Loading…
Reference in New Issue
Block a user