New usermod: MQTT switches.
This user mod adds a function to toggle output pins via MQTT.
This commit is contained in:
parent
b694bcf62a
commit
fe3fb622ee
46
usermods/mqtt_switch_v2/README.md
Normal file
46
usermods/mqtt_switch_v2/README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# 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, 0 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, 0, 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.
|
||||||
|
|
140
usermods/mqtt_switch_v2/usermod_mqtt_switch.h
Normal file
140
usermods/mqtt_switch_v2/usermod_mqtt_switch.h
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
#ifndef WLED_ENABLE_MQTT
|
||||||
|
#error "This user mod requires MQTT to be enabled."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MQTTSWITCHPINS
|
||||||
|
#define MQTTSWITCHPINS 12, 0, 2
|
||||||
|
//#error "Please define MQTTSWITCHPINS in platformio_override.ini. e.g. -D MQTTSWITCHPINS="12, 0, 2" "
|
||||||
|
#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))
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
pinMode(switchPins[pinNr], OUTPUT);
|
||||||
|
setState(pinNr, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) 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