Mqtt with HA configuration
This commit is contained in:
parent
156d92b7f8
commit
fc3416f12c
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -10,3 +10,6 @@
|
||||
[submodule "lib/EasyButton"]
|
||||
path = lib/EasyButton
|
||||
url = https://github.com/evert-arias/EasyButton.git
|
||||
[submodule "lib/pubsubclient"]
|
||||
path = lib/pubsubclient
|
||||
url = https://github.com/knolleary/pubsubclient.git
|
||||
|
34
README.md
34
README.md
@ -10,9 +10,39 @@ Before sending press the on board button "flash" or connect a button to D0. You
|
||||
{
|
||||
"hostname": "your_hostname",
|
||||
"ssid": "your_ssid",
|
||||
"pass": "[48..."
|
||||
"wifipass": "[48...",
|
||||
"mqttserver": "mqtt.mydomain.com",
|
||||
"mqttuser": "mymqtt_user",
|
||||
"mqttpass": "7j%!fs#",
|
||||
"mqttport": "1883",
|
||||
}
|
||||
```
|
||||
|
||||
## OTA Updates
|
||||
Configured in vscode, inside of *platformio.ini* change the board name to what you've set in the configuration. Then upload sketch updates via WiFi by clicking the *Upload* button in *platformIO* under the *evn:esp8266 OTA* configuration
|
||||
Configured in vscode, inside of *platformio.ini* change the board name to what you've set in the configuration. Then upload sketch updates via WiFi by clicking the *Upload* button in *platformIO* under the *evn:esp8266 OTA* configuration
|
||||
|
||||
## MQTT
|
||||
Topics....
|
||||
Example payload:
|
||||
```
|
||||
{
|
||||
"brightness": 255,
|
||||
"color": {
|
||||
"r": 255,
|
||||
"g": 180,
|
||||
"b": 200
|
||||
},
|
||||
"state": "ON"
|
||||
}
|
||||
```
|
||||
## Home Assistant
|
||||
Adjust the name and topics to suite your configuration
|
||||
```
|
||||
- name: Bedside Lamp
|
||||
platform: mqtt
|
||||
schema: json
|
||||
state_topic: light/bedlamp/relay/0
|
||||
command_topic: light/bedlamp/relay/0/set
|
||||
brightness: true
|
||||
rgb: true
|
||||
```
|
@ -9,6 +9,10 @@ public:
|
||||
char hostname[20];
|
||||
char ssid[20];
|
||||
char pass[20];
|
||||
char mqttServer[20];
|
||||
char mqttUser[10];
|
||||
char mqttPass[20];
|
||||
int mqttPort;
|
||||
uint8_t brightness;
|
||||
std::array<uint8_t, 3> color;
|
||||
} Data;
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
class MyLed {
|
||||
@ -12,18 +14,32 @@ public:
|
||||
|
||||
void toggle();
|
||||
|
||||
//! @param state Json package
|
||||
//! {
|
||||
//! "brightness": 255,
|
||||
//! "color": {
|
||||
//! "r": 255,
|
||||
//! "g": 180,
|
||||
//! "b": 200,
|
||||
//! },
|
||||
//! "state": "ON"
|
||||
//! }
|
||||
void set(String jsonState);
|
||||
|
||||
String get();
|
||||
|
||||
//! @param brightness in [0, 1]
|
||||
void setBrightness(float brightness);
|
||||
|
||||
//! @param diff in [-1, 1]
|
||||
void adjustBrightness(float diff);
|
||||
|
||||
void setColor(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
//! Called by public setBrightness. This function
|
||||
//! will not store the brightness
|
||||
void _setBrightness(float brightness);
|
||||
void _apply();
|
||||
|
||||
bool _useEffects;
|
||||
|
||||
@ -35,5 +51,5 @@ private:
|
||||
|
||||
const std::array<float, 3> _defColor;
|
||||
|
||||
const std::array<float, 3> _color;
|
||||
std::array<float, 3> _color;
|
||||
};
|
1
lib/pubsubclient
Submodule
1
lib/pubsubclient
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 2d228f2f862a95846c65a8518c79f48dfc8f188c
|
@ -9,7 +9,11 @@ void printConfig(Config::Data data)
|
||||
{
|
||||
Serial.printf("hostname: %s\n", data.hostname);
|
||||
Serial.printf("ssid: %s\n", data.ssid);
|
||||
Serial.printf("pass: %s\n", data.pass);
|
||||
Serial.printf("wifi pass: %s\n", data.pass);
|
||||
Serial.printf("mqtt server: %s\n", data.mqttServer);
|
||||
Serial.printf("mqtt user: %s\n", data.mqttUser);
|
||||
Serial.printf("mqtt pass: %s\n", data.mqttPass);
|
||||
Serial.printf("mqtt port: %d\n", data.mqttPort);
|
||||
Serial.printf("brightness: %d\n", data.brightness);
|
||||
Serial.printf("color: %d, %d, %d\n",
|
||||
data.color.at(0),
|
||||
|
103
src/main.cpp
103
src/main.cpp
@ -3,6 +3,8 @@
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <EasyButton.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <Ticker.h>
|
||||
|
||||
// My own includes
|
||||
#include "config.h"
|
||||
@ -25,6 +27,11 @@ Config& config = Config::Instance();
|
||||
|
||||
MyLed myLed(ledPin, ledCount);
|
||||
|
||||
WiFiClient wifiClient;
|
||||
PubSubClient mqttClient(wifiClient);
|
||||
|
||||
Ticker tickerLedStatus, tickerMqttCyclic, tickerMqttReconnect;
|
||||
|
||||
typedef struct {
|
||||
float distance; // Distance in mm
|
||||
float distanceNormalized;
|
||||
@ -37,23 +44,34 @@ void checkSerial()
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
Serial.println(s.c_str());
|
||||
DynamicJsonDocument doc(200);
|
||||
DynamicJsonDocument doc(512);
|
||||
deserializeJson(doc, s);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
String hostname = obj["hostname"];
|
||||
String ssid = obj["ssid"];
|
||||
String pass = obj["pass"];
|
||||
String wifiPass = obj["pass"];
|
||||
String mqttServer = obj["mqttserver"];
|
||||
String mqttUser = obj["mqttuser"];
|
||||
String mqttPass = obj["mqttpass"];
|
||||
int mqttPort = obj["mqttport"];
|
||||
Serial.printf("Parsed hostname: %s, ssid: %s, pass: %s\n",
|
||||
hostname.c_str(),
|
||||
ssid.c_str(),
|
||||
String(pass).c_str());
|
||||
String(wifiPass).c_str());
|
||||
|
||||
if (hostname != "null" && ssid != "null" && pass != "null")
|
||||
if (hostname != "null" && ssid != "null" && wifiPass != "null")
|
||||
{
|
||||
hostname.toCharArray(config.data.hostname,
|
||||
sizeof(config.data.hostname));
|
||||
ssid.toCharArray(config.data.ssid, sizeof(config.data.ssid));
|
||||
pass.toCharArray(config.data.pass, sizeof(config.data.pass));
|
||||
wifiPass.toCharArray(config.data.pass, sizeof(config.data.pass));
|
||||
mqttServer.toCharArray(config.data.mqttServer,
|
||||
sizeof(config.data.mqttServer));
|
||||
mqttUser.toCharArray(config.data.mqttUser,
|
||||
sizeof(config.data.mqttUser));
|
||||
mqttPass.toCharArray(config.data.mqttPass,
|
||||
sizeof(config.data.mqttPass));
|
||||
config.data.mqttPort = mqttPort;
|
||||
|
||||
config.write();
|
||||
}
|
||||
@ -63,6 +81,7 @@ void checkSerial()
|
||||
void onPressed()
|
||||
{
|
||||
digitalWrite(boardLedPin, LOW);
|
||||
Serial.println("Button pressed. Waiting 10s for config...");
|
||||
|
||||
unsigned long t = millis();
|
||||
static unsigned long lastT = t;
|
||||
@ -71,12 +90,60 @@ void onPressed()
|
||||
{
|
||||
lastT = t;
|
||||
checkSerial();
|
||||
delay(1000);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
digitalWrite(boardLedPin, HIGH);
|
||||
}
|
||||
|
||||
void mqttPublishState()
|
||||
{
|
||||
const String outTopic =
|
||||
"light/" + String(config.data.hostname) + "/relay/0";
|
||||
if (mqttClient.connected())
|
||||
mqttClient.publish(outTopic.c_str(), myLed.get().c_str());
|
||||
}
|
||||
|
||||
void mqttReconnect()
|
||||
{
|
||||
if (!mqttClient.connected())
|
||||
{
|
||||
Serial.print("Attempting MQTT connection...");
|
||||
if (mqttClient.connect(config.data.hostname,
|
||||
config.data.mqttUser,
|
||||
config.data.mqttPass))
|
||||
{
|
||||
Serial.println("connected");
|
||||
mqttPublishState();
|
||||
const String inTopic =
|
||||
"light/" + String(config.data.hostname) + "/relay/0/set";
|
||||
mqttClient.subscribe(inTopic.c_str());
|
||||
} else
|
||||
{
|
||||
Serial.print("failed, rc=");
|
||||
Serial.print(mqttClient.state());
|
||||
Serial.println(" try again in 5 seconds");
|
||||
|
||||
tickerMqttReconnect.once(5, mqttReconnect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mqttCallback(char* topic, byte* payload, unsigned int length)
|
||||
{
|
||||
Serial.print("Message arrived [");
|
||||
Serial.print(topic);
|
||||
Serial.print("] ");
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
Serial.print((char)payload[i]);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
myLed.set(String(reinterpret_cast<char const*>(payload)));
|
||||
mqttPublishState();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(boardLedPin, OUTPUT);
|
||||
@ -100,8 +167,21 @@ void setup()
|
||||
Serial.println();
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
config.load();
|
||||
|
||||
mqttClient.setServer(config.data.mqttServer, config.data.mqttPort);
|
||||
mqttClient.setCallback(mqttCallback);
|
||||
|
||||
ArduinoOTA.setHostname(config.data.hostname);
|
||||
ArduinoOTA.begin();
|
||||
|
||||
tickerLedStatus.attach(120, mqttPublishState);
|
||||
tickerMqttCyclic.attach(60 * 5, mqttReconnect);
|
||||
mqttReconnect();
|
||||
|
||||
// TEST
|
||||
// myLed.set("{\"brightness\": 233, \"color\": { \"r\": 211, \"g\": 200, "
|
||||
// "\"b\": 199 }, \"state\": \"OFF\"}");
|
||||
}
|
||||
|
||||
float filter(float input)
|
||||
@ -172,6 +252,7 @@ void evalDist(SensorData data)
|
||||
{
|
||||
lastToggleTime = t;
|
||||
myLed.toggle();
|
||||
mqttPublishState();
|
||||
stillCounter = 0;
|
||||
}
|
||||
} else
|
||||
@ -192,8 +273,11 @@ void evalDist(SensorData data)
|
||||
|
||||
if (distDeltaAbs < releaseThreshold &&
|
||||
distDeltaAbs > stillThreshold * 2)
|
||||
{
|
||||
myLed.adjustBrightness((data.distance - lastDist) *
|
||||
dimFactor);
|
||||
mqttPublishState();
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
@ -207,7 +291,7 @@ void evalDist(SensorData data)
|
||||
lastDist = data.distance;
|
||||
}
|
||||
|
||||
void run()
|
||||
void slowLoop()
|
||||
{
|
||||
SensorData data = getDist();
|
||||
|
||||
@ -215,7 +299,7 @@ void run()
|
||||
|
||||
myLed.run();
|
||||
|
||||
button.read();
|
||||
mqttClient.loop();
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -223,10 +307,11 @@ void loop()
|
||||
unsigned long t = millis();
|
||||
static unsigned long lastT = t;
|
||||
|
||||
button.read();
|
||||
if (t - lastT > 50)
|
||||
{
|
||||
lastT = t;
|
||||
run();
|
||||
slowLoop();
|
||||
}
|
||||
ArduinoOTA.handle();
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#include "myled.h"
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
namespace {
|
||||
const float minBrightness = 0.2;
|
||||
}
|
||||
@ -25,9 +27,16 @@ void MyLed::initialize()
|
||||
|
||||
void MyLed::setOnState(bool on)
|
||||
{
|
||||
_setBrightness(on ? _brightness : 0.0f);
|
||||
_isOn = on;
|
||||
Serial.println(on ? "Turning on" : "Turning off");
|
||||
if (on)
|
||||
{
|
||||
_apply();
|
||||
} else
|
||||
{
|
||||
_strip.fill({});
|
||||
_strip.show();
|
||||
};
|
||||
}
|
||||
|
||||
bool MyLed::getOnState()
|
||||
@ -41,6 +50,45 @@ void MyLed::toggle()
|
||||
setOnState(!_isOn);
|
||||
}
|
||||
|
||||
void MyLed::set(String jsonState)
|
||||
{
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, jsonState);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
Serial.println(jsonState.c_str());
|
||||
|
||||
if (obj.containsKey("brightness"))
|
||||
{
|
||||
uint8_t brightness = obj["brightness"];
|
||||
setBrightness(static_cast<float>(brightness) / 255.0f);
|
||||
Serial.printf("Brightness: %d\n", brightness);
|
||||
}
|
||||
if (obj.containsKey("color"))
|
||||
{
|
||||
uint8_t r = obj["color"]["r"];
|
||||
uint8_t g = obj["color"]["g"];
|
||||
uint8_t b = obj["color"]["b"];
|
||||
setColor(r, g, b);
|
||||
Serial.printf("Color: r: %d, g: %d, b: %d\n", r, g, b);
|
||||
}
|
||||
if (obj.containsKey("state"))
|
||||
{
|
||||
bool state = obj["state"] == "ON";
|
||||
if (state != getOnState())
|
||||
setOnState(state);
|
||||
Serial.printf("State: %s\n", state ? "ON" : "OFF");
|
||||
}
|
||||
}
|
||||
|
||||
String MyLed::get()
|
||||
{
|
||||
return "{\"brightness\": " + String(_brightness * 255.0f) +
|
||||
", \"color\": { \"r\": " + String(_color.at(0)) +
|
||||
", \"g\": " + String(_color.at(1)) +
|
||||
", \"b\": " + String(_color.at(2)) + " }, \"state\": \"" +
|
||||
String(_isOn ? "ON" : "OFF") + "\"}";
|
||||
}
|
||||
|
||||
void MyLed::setBrightness(float brightness)
|
||||
{
|
||||
brightness = max(minBrightness, brightness);
|
||||
@ -50,8 +98,8 @@ void MyLed::setBrightness(float brightness)
|
||||
_targetBrightness = brightness;
|
||||
} else
|
||||
{
|
||||
_setBrightness(brightness);
|
||||
_brightness = brightness;
|
||||
_apply();
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +109,12 @@ void MyLed::adjustBrightness(float diff)
|
||||
setBrightness(brightness);
|
||||
}
|
||||
|
||||
void MyLed::setColor(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
_color = {r, g, b};
|
||||
_apply();
|
||||
}
|
||||
|
||||
void MyLed::run()
|
||||
{
|
||||
if (!_useEffects)
|
||||
@ -70,15 +124,14 @@ void MyLed::run()
|
||||
const float mixFactor = 0.2;
|
||||
_brightness =
|
||||
_brightness * (1 - mixFactor) + _targetBrightness * mixFactor;
|
||||
_setBrightness(_brightness);
|
||||
_apply();
|
||||
}
|
||||
}
|
||||
|
||||
void MyLed::_setBrightness(float brightness)
|
||||
void MyLed::_apply()
|
||||
{
|
||||
_strip.fill(
|
||||
_strip.Color(static_cast<uint8_t>(_defColor.at(0) * brightness),
|
||||
static_cast<uint8_t>(_defColor.at(1) * brightness),
|
||||
static_cast<uint8_t>(_defColor.at(2) * brightness)));
|
||||
_strip.fill(_strip.Color(static_cast<uint8_t>(_color.at(0) * _brightness),
|
||||
static_cast<uint8_t>(_color.at(1) * _brightness),
|
||||
static_cast<uint8_t>(_color.at(2) * _brightness)));
|
||||
_strip.show();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user