Merge pull request #1309 from herm/usermod_mqtt_switch
Usermod mqtt switch
This commit is contained in:
commit
afe75f8a89
50
usermods/mqtt_switch_v2/README.md
Normal file
50
usermods/mqtt_switch_v2/README.md
Normal file
@ -0,0 +1,50 @@
|
||||
# MQTT controllable switches
|
||||
This usermod allows controlling switches (e.g. relays) via MQTT.
|
||||
|
||||
## Usermod installation
|
||||
|
||||
1. Copy the file `usermod_mqtt_switch.h` to the `wled00` directory.
|
||||
2. Register the usermod by adding `#include "usermod_mqtt_switch.h"` in the top and `registerUsermod(new UsermodMqttSwitch());` in the bottom of `usermods_list.cpp`.
|
||||
|
||||
|
||||
Example `usermods_list.cpp`:
|
||||
|
||||
```
|
||||
#include "wled.h"
|
||||
#include "usermod_mqtt_switch.h"
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
usermods.add(new UsermodMqttSwitch());
|
||||
}
|
||||
```
|
||||
|
||||
## Define pins
|
||||
Add a define for MQTTSWITCHPINS to platformio_override.ini.
|
||||
The following example defines 3 switches connected to the GPIO pins 13, 5 and 2:
|
||||
|
||||
```
|
||||
[env:livingroom]
|
||||
board = esp12e
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
-D LEDPIN=3
|
||||
-D BTNPIN=4
|
||||
-D RLYPIN=12
|
||||
-D RLYMDE=1
|
||||
-D STATUSPIN=15
|
||||
-D MQTTSWITCHPINS="13, 5, 2"
|
||||
```
|
||||
|
||||
Pins can be inverted by setting `MQTTSWITCHINVERT`. For example `-D MQTTSWITCHINVERT="false, false, true"` would invert the switch on pin 2 in the previous example.
|
||||
|
||||
The default state after booting before any MQTT message can be set by `MQTTSWITCHDEFAULTS`. For example `-D MQTTSWITCHDEFAULTS="ON, OFF, OFF"` would power on the switch on pin 13 and power off switches on pins 5 and 2.
|
||||
|
||||
## MQTT topics
|
||||
This usermod listens on `[mqttDeviceTopic]/switch/0/set` (where 0 is replaced with the index of the switch) for commands. Anything starting with `ON` turns on the switch, everything else turns it off.
|
||||
Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`.
|
||||
|
||||
### Home Assistant auto-discovery
|
||||
Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant.
|
||||
|
157
usermods/mqtt_switch_v2/usermod_mqtt_switch.h
Normal file
157
usermods/mqtt_switch_v2/usermod_mqtt_switch.h
Normal file
@ -0,0 +1,157 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
#ifndef WLED_ENABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
#ifndef MQTTSWITCHPINS
|
||||
#error "Please define MQTTSWITCHPINS in platformio_override.ini. e.g. -D MQTTSWITCHPINS="12, 0, 2" "
|
||||
// The following define helps Eclipse's C++ parser but is never used in production due to the #error statement on the line before
|
||||
#define MQTTSWITCHPINS 12, 0, 2
|
||||
#endif
|
||||
|
||||
// Default behavior: All outputs active high
|
||||
#ifndef MQTTSWITCHINVERT
|
||||
#define MQTTSWITCHINVERT
|
||||
#endif
|
||||
|
||||
// Default behavior: All outputs off
|
||||
#ifndef MQTTSWITCHDEFAULTS
|
||||
#define MQTTSWITCHDEFAULTS
|
||||
#endif
|
||||
|
||||
static const uint8_t switchPins[] = { MQTTSWITCHPINS };
|
||||
//This is a hack to get the number of pins defined by the user
|
||||
#define NUM_SWITCH_PINS (sizeof(switchPins))
|
||||
static const bool switchInvert[NUM_SWITCH_PINS] = { MQTTSWITCHINVERT};
|
||||
//Make settings in config file more readable
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
static const bool switchDefaults[NUM_SWITCH_PINS] = { MQTTSWITCHDEFAULTS};
|
||||
#undef ON
|
||||
#undef OFF
|
||||
|
||||
class UsermodMqttSwitch: public Usermod
|
||||
{
|
||||
private:
|
||||
bool mqttInitialized;
|
||||
bool switchState[NUM_SWITCH_PINS];
|
||||
|
||||
public:
|
||||
UsermodMqttSwitch() :
|
||||
mqttInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
|
||||
setState(pinNr, switchDefaults[pinNr]);
|
||||
pinMode(switchPins[pinNr], OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!mqttInitialized) {
|
||||
mqttInit();
|
||||
return; // Try again in next loop iteration
|
||||
}
|
||||
}
|
||||
|
||||
void mqttInit()
|
||||
{
|
||||
if (!mqtt)
|
||||
return;
|
||||
mqtt->onMessage(
|
||||
std::bind(&UsermodMqttSwitch::onMqttMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
|
||||
std::placeholders::_5, std::placeholders::_6));
|
||||
mqtt->onConnect(std::bind(&UsermodMqttSwitch::onMqttConnect, this, std::placeholders::_1));
|
||||
mqttInitialized = true;
|
||||
}
|
||||
|
||||
void onMqttConnect(bool sessionPresent);
|
||||
|
||||
void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
|
||||
void updateState(uint8_t pinNr);
|
||||
|
||||
void setState(uint8_t pinNr, bool active)
|
||||
{
|
||||
if (pinNr > NUM_SWITCH_PINS)
|
||||
return;
|
||||
switchState[pinNr] = active;
|
||||
digitalWrite((char) switchPins[pinNr], (char) (switchInvert[pinNr] ? !active : active));
|
||||
updateState(pinNr);
|
||||
}
|
||||
};
|
||||
|
||||
inline void UsermodMqttSwitch::onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
if (mqttDeviceTopic[0] == 0)
|
||||
return;
|
||||
|
||||
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
|
||||
char buf[128];
|
||||
StaticJsonDocument<1024> json;
|
||||
sprintf(buf, "%s Switch %d", serverDescription, pinNr + 1);
|
||||
json[F("name")] = buf;
|
||||
|
||||
sprintf(buf, "%s/switch/%d", mqttDeviceTopic, pinNr);
|
||||
json["~"] = buf;
|
||||
strcat(buf, "/set");
|
||||
mqtt->subscribe(buf, 0);
|
||||
|
||||
json[F("stat_t")] = "~/state";
|
||||
json[F("cmd_t")] = "~/set";
|
||||
json[F("pl_off")] = F("OFF");
|
||||
json[F("pl_on")] = F("ON");
|
||||
|
||||
char uid[16];
|
||||
sprintf(uid, "%s_sw%d", escapedMac.c_str(), pinNr);
|
||||
json[F("unique_id")] = uid;
|
||||
|
||||
strcpy(buf, mqttDeviceTopic);
|
||||
strcat(buf, "/status");
|
||||
json[F("avty_t")] = buf;
|
||||
json[F("pl_avail")] = F("online");
|
||||
json[F("pl_not_avail")] = F("offline");
|
||||
//TODO: dev
|
||||
sprintf(buf, "homeassistant/switch/%s/config", uid);
|
||||
char json_str[1024];
|
||||
size_t payload_size = serializeJson(json, json_str);
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size);
|
||||
updateState(pinNr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void UsermodMqttSwitch::onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
|
||||
{
|
||||
//Note: Payload is not necessarily null terminated. Check "len" instead.
|
||||
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
|
||||
char buf[64];
|
||||
sprintf(buf, "%s/switch/%d/set", mqttDeviceTopic, pinNr);
|
||||
if (strcmp(topic, buf) == 0) {
|
||||
//Any string starting with "ON" is interpreted as ON, everything else as OFF
|
||||
setState(pinNr, len >= 2 && payload[0] == 'O' && payload[1] == 'N');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UsermodMqttSwitch::updateState(uint8_t pinNr)
|
||||
{
|
||||
if (!mqttInitialized)
|
||||
return;
|
||||
|
||||
if (pinNr > NUM_SWITCH_PINS)
|
||||
return;
|
||||
|
||||
char buf[64];
|
||||
sprintf(buf, "%s/switch/%d/state", mqttDeviceTopic, pinNr);
|
||||
if (switchState[pinNr]) {
|
||||
mqtt->publish(buf, 0, false, "ON");
|
||||
} else {
|
||||
mqtt->publish(buf, 0, false, "OFF");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user