Skip to content

Commit fe3fb62

Browse files
committed
New usermod: MQTT switches.
This user mod adds a function to toggle output pins via MQTT.
1 parent b694bcf commit fe3fb62

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

usermods/mqtt_switch_v2/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# MQTT controllable switches
2+
This usermod allows controlling switches (e.g. relays) via MQTT.
3+
4+
## Usermod installation
5+
6+
1. Copy the file `usermod_mqtt_switch.h` to the `wled00` directory.
7+
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`.
8+
9+
10+
Example `usermods_list.cpp`:
11+
12+
```
13+
#include "wled.h"
14+
#include "usermod_mqtt_switch.h"
15+
16+
void registerUsermods()
17+
{
18+
usermods.add(new UsermodMqttSwitch());
19+
}
20+
```
21+
22+
## Define pins
23+
Add a define for MQTTSWITCHPINS to platformio_override.ini.
24+
The following example defines 3 switches connected to the GPIO pins 13, 0 and 2:
25+
26+
```
27+
[env:livingroom]
28+
board = esp12e
29+
platform = ${common.platform_wled_default}
30+
board_build.ldscript = ${common.ldscript_4m1m}
31+
build_flags = ${common.build_flags_esp8266}
32+
-D LEDPIN=3
33+
-D BTNPIN=4
34+
-D RLYPIN=12
35+
-D RLYMDE=1
36+
-D STATUSPIN=15
37+
-D MQTTSWITCHPINS="13, 0, 2"
38+
```
39+
40+
## MQTT topics
41+
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.
42+
Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`.
43+
44+
### Home Assistant auto-discovery
45+
Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant.
46+
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#pragma once
2+
3+
#include "wled.h"
4+
#ifndef WLED_ENABLE_MQTT
5+
#error "This user mod requires MQTT to be enabled."
6+
#endif
7+
8+
#ifndef MQTTSWITCHPINS
9+
#define MQTTSWITCHPINS 12, 0, 2
10+
//#error "Please define MQTTSWITCHPINS in platformio_override.ini. e.g. -D MQTTSWITCHPINS="12, 0, 2" "
11+
#endif
12+
13+
14+
static const uint8_t switchPins[] = {MQTTSWITCHPINS};
15+
//This is a hack to get the number of pins defined by the user
16+
#define NUM_SWITCH_PINS (sizeof(switchPins))
17+
18+
class UsermodMqttSwitch: public Usermod
19+
{
20+
private:
21+
bool mqttInitialized;
22+
bool switchState[NUM_SWITCH_PINS];
23+
24+
public:
25+
UsermodMqttSwitch() :
26+
mqttInitialized(false)
27+
{
28+
}
29+
30+
void setup()
31+
{
32+
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
33+
pinMode(switchPins[pinNr], OUTPUT);
34+
setState(pinNr, false);
35+
}
36+
}
37+
38+
void loop()
39+
{
40+
if (!mqttInitialized) {
41+
mqttInit();
42+
return; // Try again in next loop iteration
43+
}
44+
}
45+
46+
void mqttInit()
47+
{
48+
if (!mqtt)
49+
return;
50+
mqtt->onMessage(
51+
std::bind(&UsermodMqttSwitch::onMqttMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
52+
std::placeholders::_5, std::placeholders::_6));
53+
mqtt->onConnect(std::bind(&UsermodMqttSwitch::onMqttConnect, this, std::placeholders::_1));
54+
mqttInitialized = true;
55+
}
56+
57+
void onMqttConnect(bool sessionPresent);
58+
59+
void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
60+
void updateState(uint8_t pinNr);
61+
62+
void setState(uint8_t pinNr, bool active)
63+
{
64+
if (pinNr > NUM_SWITCH_PINS)
65+
return;
66+
switchState[pinNr] = active;
67+
digitalWrite((char) switchPins[pinNr], (char) active);
68+
updateState(pinNr);
69+
}
70+
};
71+
72+
inline void UsermodMqttSwitch::onMqttConnect(bool sessionPresent)
73+
{
74+
if (mqttDeviceTopic[0] == 0)
75+
return;
76+
77+
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
78+
char buf[128];
79+
StaticJsonDocument<1024> json;
80+
sprintf(buf, "%s Switch %d", serverDescription, pinNr + 1);
81+
json[F("name")] = buf;
82+
83+
sprintf(buf, "%s/switch/%d", mqttDeviceTopic, pinNr);
84+
json["~"] = buf;
85+
strcat(buf, "/set");
86+
mqtt->subscribe(buf, 0);
87+
88+
json[F("stat_t")] = "~/state";
89+
json[F("cmd_t")] = "~/set";
90+
json[F("pl_off")] = F("OFF");
91+
json[F("pl_on")] = F("ON");
92+
93+
char uid[16];
94+
sprintf(uid, "%s_sw%d", escapedMac.c_str(), pinNr);
95+
json[F("unique_id")] = uid;
96+
97+
strcpy(buf, mqttDeviceTopic);
98+
strcat(buf, "/status");
99+
json[F("avty_t")] = buf;
100+
json[F("pl_avail")] = F("online");
101+
json[F("pl_not_avail")] = F("offline");
102+
//TODO: dev
103+
sprintf(buf, "homeassistant/switch/%s/config", uid);
104+
char json_str[1024];
105+
size_t payload_size = serializeJson(json, json_str);
106+
mqtt->publish(buf, 0, true, json_str, payload_size);
107+
updateState(pinNr);
108+
}
109+
}
110+
111+
inline void UsermodMqttSwitch::onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
112+
{
113+
//Note: Payload is not necessarily null terminated. Check "len" instead.
114+
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
115+
char buf[64];
116+
sprintf(buf, "%s/switch/%d/set", mqttDeviceTopic, pinNr);
117+
if (strcmp(topic, buf) == 0) {
118+
//Any string starting with "ON" is interpreted as ON, everything else as OFF
119+
setState(pinNr, len >= 2 && payload[0] == 'O' && payload[1] == 'N');
120+
break;
121+
}
122+
}
123+
}
124+
125+
inline void UsermodMqttSwitch::updateState(uint8_t pinNr)
126+
{
127+
if (!mqttInitialized)
128+
return;
129+
130+
if (pinNr > NUM_SWITCH_PINS)
131+
return;
132+
133+
char buf[64];
134+
sprintf(buf, "%s/switch/%d/state", mqttDeviceTopic, pinNr);
135+
if (switchState[pinNr]) {
136+
mqtt->publish(buf, 0, false, "ON");
137+
} else {
138+
mqtt->publish(buf, 0, false, "OFF");
139+
}
140+
}

0 commit comments

Comments
 (0)