Implemented usermod for integration with smartnest.cz (#2800)
Co-authored-by: Christian Schwinne <dev.aircoookie@gmail.com>
This commit is contained in:
parent
b0037c75a3
commit
38e2fc6812
61
usermods/smartnest/readme.md
Normal file
61
usermods/smartnest/readme.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Smartnest
|
||||||
|
|
||||||
|
This usermod-v2 modification allows integration with `smartnest.cz` service which provides MQTT integration with voice assistants.
|
||||||
|
In order to setup Smartnest follow the [documentation](https://www.docu.smartnest.cz/).
|
||||||
|
|
||||||
|
## MQTT API
|
||||||
|
|
||||||
|
The API is described in the Smartnest [Github repo](https://github.com/aososam/Smartnest/blob/master/Devices/lightRgb/lightRgb.ino).
|
||||||
|
|
||||||
|
|
||||||
|
## Usermod installation
|
||||||
|
|
||||||
|
1. Register the usermod by adding `#include "../usermods/smartnest/usermod_smartnest.h"` at the top and `usermods.add(new Smartnest());` at the bottom of `usermods_list.cpp`.
|
||||||
|
or
|
||||||
|
2. Use `#define USERMOD_SMARTNEST` in wled.h or `-D USERMOD_SMARTNEST` in your platformio.ini
|
||||||
|
|
||||||
|
|
||||||
|
Example **usermods_list.cpp**:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "wled.h"
|
||||||
|
/*
|
||||||
|
* Register your v2 usermods here!
|
||||||
|
* (for v1 usermods using just usermod.cpp, you can ignore this file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add/uncomment your usermod filename here (and once more below)
|
||||||
|
* || || ||
|
||||||
|
* \/ \/ \/
|
||||||
|
*/
|
||||||
|
//#include "usermod_v2_example.h"
|
||||||
|
//#include "usermod_temperature.h"
|
||||||
|
#include "../usermods/usermod_smartnest.h"
|
||||||
|
|
||||||
|
void registerUsermods()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Add your usermod class name here
|
||||||
|
* || || ||
|
||||||
|
* \/ \/ \/
|
||||||
|
*/
|
||||||
|
//usermods.add(new MyExampleUsermod());
|
||||||
|
//usermods.add(new UsermodTemperature());
|
||||||
|
usermods.add(new Smartnest());
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Usermod has no configuration but relies on the MQTT configuration.\
|
||||||
|
Under Config > Sync Interfaces > MQTT:
|
||||||
|
* Enable MQTT check box
|
||||||
|
* Set the `Broker` field to: `smartnest.cz`
|
||||||
|
* The `Username` and `Password` fields are the login information from the `smartnest.cz` website.
|
||||||
|
* `Client ID` field is obtained from the device configuration panel in `smartnest.cz`.
|
||||||
|
|
||||||
|
## Change log
|
||||||
|
2022-09
|
||||||
|
* First implementation.
|
167
usermods/smartnest/usermod_smartnest.h
Normal file
167
usermods/smartnest/usermod_smartnest.h
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
|
||||||
|
class Smartnest : public Usermod
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void sendToBroker(const char *const topic, const char *const message)
|
||||||
|
{
|
||||||
|
if (!WLED_MQTT_CONNECTED)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String topic_ = String(mqttClientID) + "/" + String(topic);
|
||||||
|
mqtt->publish(topic_.c_str(), 0, true, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void turnOff()
|
||||||
|
{
|
||||||
|
setBrightness(0);
|
||||||
|
turnOnAtBoot = false;
|
||||||
|
offMode = true;
|
||||||
|
sendToBroker("report/powerState", "OFF");
|
||||||
|
}
|
||||||
|
|
||||||
|
void turnOn()
|
||||||
|
{
|
||||||
|
setBrightness(briLast);
|
||||||
|
turnOnAtBoot = true;
|
||||||
|
offMode = false;
|
||||||
|
sendToBroker("report/powerState", "ON");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBrightness(int value)
|
||||||
|
{
|
||||||
|
if (value == 0 && bri > 0) briLast = bri;
|
||||||
|
bri = value;
|
||||||
|
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setColor(int r, int g, int b)
|
||||||
|
{
|
||||||
|
strip.setColor(0, r, g, b);
|
||||||
|
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||||
|
char msg[18] {};
|
||||||
|
sprintf(msg, "rgb(%d,%d,%d)", r, g, b);
|
||||||
|
sendToBroker("report/color", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int splitColor(const char *const color, int * const rgb)
|
||||||
|
{
|
||||||
|
char *color_ = NULL;
|
||||||
|
const char delim[] = ",";
|
||||||
|
char *cxt = NULL;
|
||||||
|
char *token = NULL;
|
||||||
|
int position = 0;
|
||||||
|
|
||||||
|
// We need to copy the string in order to keep it read only as strtok_r function requires mutable string
|
||||||
|
color_ = (char *)malloc(strlen(color));
|
||||||
|
if (NULL == color_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(color_, color);
|
||||||
|
token = strtok_r(color_, delim, &cxt);
|
||||||
|
|
||||||
|
while (token != NULL)
|
||||||
|
{
|
||||||
|
rgb[position++] = (int)strtoul(token, NULL, 10);
|
||||||
|
token = strtok_r(NULL, delim, &cxt);
|
||||||
|
}
|
||||||
|
free(color_);
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Functions called by WLED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handling of MQTT message
|
||||||
|
* topic should look like: /<mqttClientID>/<Command>/<Message>
|
||||||
|
*/
|
||||||
|
bool onMqttMessage(char *topic, char *message)
|
||||||
|
{
|
||||||
|
String topic_{topic};
|
||||||
|
String topic_prefix{mqttClientID + String("/directive/")};
|
||||||
|
|
||||||
|
if (!topic_.startsWith(topic_prefix))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String subtopic = topic_.substring(topic_prefix.length());
|
||||||
|
String message_(message);
|
||||||
|
|
||||||
|
if (subtopic == "powerState")
|
||||||
|
{
|
||||||
|
if (strcmp(message, "ON") == 0)
|
||||||
|
{
|
||||||
|
turnOn();
|
||||||
|
}
|
||||||
|
else if (strcmp(message, "OFF") == 0)
|
||||||
|
{
|
||||||
|
turnOff();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subtopic == "percentage")
|
||||||
|
{
|
||||||
|
int val = (int)strtoul(message, NULL, 10);
|
||||||
|
if (val >= 0 && val <= 100)
|
||||||
|
{
|
||||||
|
setBrightness(map(val, 0, 100, 0, 255));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subtopic == "color")
|
||||||
|
{
|
||||||
|
// Parse the message which is in the format "rgb(<0-255>,<0-255>,<0-255>)"
|
||||||
|
int rgb[3] = {};
|
||||||
|
String colors = message_.substring(String("rgb(").length(), message_.lastIndexOf(')'));
|
||||||
|
if (3 != splitColor(colors.c_str(), rgb))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setColor(rgb[0], rgb[1], rgb[2]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscribe to MQTT topic and send publish current status.
|
||||||
|
*/
|
||||||
|
void onMqttConnect(bool sessionPresent)
|
||||||
|
{
|
||||||
|
String topic = String(mqttClientID) + "/#";
|
||||||
|
|
||||||
|
mqtt->subscribe(topic.c_str(), 0);
|
||||||
|
sendToBroker("report/online", (bri ? "true" : "false")); // Reports that the device is online
|
||||||
|
delay(100);
|
||||||
|
sendToBroker("report/firmware", versionString); // Reports the firmware version
|
||||||
|
delay(100);
|
||||||
|
sendToBroker("report/ip", (char *)WiFi.localIP().toString().c_str()); // Reports the ip
|
||||||
|
delay(100);
|
||||||
|
sendToBroker("report/network", (char *)WiFi.SSID().c_str()); // Reports the network name
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
String signal(WiFi.RSSI(), 10);
|
||||||
|
sendToBroker("report/signal", signal.c_str()); // Reports the signal strength
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
||||||
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
|
*/
|
||||||
|
uint16_t getId()
|
||||||
|
{
|
||||||
|
return USERMOD_ID_SMARTNEST;
|
||||||
|
}
|
||||||
|
};
|
@ -91,7 +91,8 @@
|
|||||||
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
||||||
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
||||||
#define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h
|
#define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h
|
||||||
#define USERMOD_ID_AUDIOREACTIVE 31 //Usermod "audioreactive.h"
|
#define USERMOD_ID_SMARTNEST 31 //Usermod "usermod_smartnest.h"
|
||||||
|
#define USERMOD_ID_AUDIOREACTIVE 32 //Usermod "audioreactive.h"
|
||||||
|
|
||||||
//Access point behavior
|
//Access point behavior
|
||||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||||
|
@ -117,6 +117,7 @@ void publishMqtt()
|
|||||||
if (!WLED_MQTT_CONNECTED) return;
|
if (!WLED_MQTT_CONNECTED) return;
|
||||||
DEBUG_PRINTLN(F("Publish MQTT"));
|
DEBUG_PRINTLN(F("Publish MQTT"));
|
||||||
|
|
||||||
|
#ifndef USERMOD_SMARTNEST
|
||||||
char s[10];
|
char s[10];
|
||||||
char subuf[38];
|
char subuf[38];
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ void publishMqtt()
|
|||||||
strlcpy(subuf, mqttDeviceTopic, 33);
|
strlcpy(subuf, mqttDeviceTopic, 33);
|
||||||
strcat_P(subuf, PSTR("/v"));
|
strcat_P(subuf, PSTR("/v"));
|
||||||
mqtt->publish(subuf, 0, false, apires); // do not retain message
|
mqtt->publish(subuf, 0, false, apires); // do not retain message
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,9 +168,11 @@ bool initMqtt()
|
|||||||
mqtt->setClientId(mqttClientID);
|
mqtt->setClientId(mqttClientID);
|
||||||
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
||||||
|
|
||||||
|
#ifndef USERMOD_SMARTNEST
|
||||||
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
strlcpy(mqttStatusTopic, mqttDeviceTopic, 33);
|
||||||
strcat_P(mqttStatusTopic, PSTR("/status"));
|
strcat_P(mqttStatusTopic, PSTR("/status"));
|
||||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message
|
||||||
|
#endif
|
||||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||||
mqtt->connect();
|
mqtt->connect();
|
||||||
return true;
|
return true;
|
||||||
|
@ -132,6 +132,10 @@
|
|||||||
#include "../usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h"
|
#include "../usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_SMARTNEST
|
||||||
|
#include "../usermods/smartnest/usermod_smartnest.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_AUDIOREACTIVE
|
#ifdef USERMOD_AUDIOREACTIVE
|
||||||
#include "../usermods/audioreactive/audio_reactive.h"
|
#include "../usermods/audioreactive/audio_reactive.h"
|
||||||
#endif
|
#endif
|
||||||
@ -256,6 +260,10 @@ void registerUsermods()
|
|||||||
usermods.add(new Si7021_MQTT_HA());
|
usermods.add(new Si7021_MQTT_HA());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USERMOD_SMARTNEST
|
||||||
|
usermods.add(new Smartnest());
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_AUDIOREACTIVE
|
#ifdef USERMOD_AUDIOREACTIVE
|
||||||
usermods.add(new AudioReactive());
|
usermods.add(new AudioReactive());
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user