Updated boolean write to MQTT

This commit is contained in:
Ard Kuijpers
2020-02-29 18:35:46 +01:00
parent 458f48493c
commit 3820300460
4 changed files with 62 additions and 282 deletions

BIN
data/homie/ui_bundle.gz Normal file

Binary file not shown.

View File

@@ -1,132 +0,0 @@
#include <PubSubClient.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
class MQTTHelper {
private:
String _group = "homedevice";
String _identifier = "garagesensor";
const char* _user = "homedevice";
const char* _password = "WNzAb4VazNFUPlpkn0ED";
WiFiClient _espClient;
PubSubClient _mqttClient;
String _will_topic;
String _command_topic;
String _announce_topic;
void reconnect(int delayMillis = 5000);
bool connect();
void announce();
void callback(char* topic, byte* payload, unsigned int length);
public:
MQTTHelper() : _espClient(), _mqttClient(_espClient) {
auto deviceMac = WiFi.macAddress();
deviceMac.replace(":","");
_identifier = "etxean-"+deviceMac.substring(6);
_will_topic = getTopic("online");
_command_topic = _group + "/command";
_announce_topic = _group+"/announce";
_mqttClient.setCallback([this] (char* topic, byte* payload, unsigned int length) { this->callback(topic, payload, length); });
}
String getIdentifier() { return _identifier; }
String getTopic(String node) {
return _group + "/" + _identifier + "/" + node;
}
void Configure(IPAddress server, uint16 port) {
Serial.println("MQTT: configuring connection to "+server.toString()+":"+String(port));
_mqttClient.setServer(server, port);
if (_mqttClient.connected()) {
connect();
}
}
void loop() {
static unsigned long lastWillTopicSent;
if (!_mqttClient.connected()) {
reconnect();
}
_mqttClient.loop();
auto now = millis();
if ((now - lastWillTopicSent) > 1000)
{
lastWillTopicSent = now;
_mqttClient.publish(_will_topic.c_str(), "true");
}
}
template<class T>
void publish(String node, T payload, bool retained = false, bool debug = true) {
auto topic = getTopic(node);
auto payload_s = String(payload);
if (debug)
Serial.println("MQTT: publish: "+topic+" = "+payload_s);
_mqttClient.publish(topic.c_str(), payload_s.c_str(), retained);
}
};
void MQTTHelper::callback(char* topic_chars, byte* payload_bytes, unsigned int length) {
String topic(topic_chars);
payload_bytes[length] = '\0';
String payload = (char*)payload_bytes;
Serial.print("MQTT: callback on: ");
Serial.println(topic+" = "+payload);
String commandTopic = getTopic("command");
if (topic == _command_topic && payload == "announce") {
Serial.println("Announcing");
announce();
}
}
void MQTTHelper::reconnect(int delayMillis) {
// Loop until we're reconnected
while (!_mqttClient.connected()) {
Serial.print("MQTT: attempting connection...");
if (connect()) {
Serial.println("connected");
} else {
auto reconnectSeconds = (int)round(delayMillis/1000.0);
Serial.print("failed, rc=");
Serial.print(_mqttClient.state());
Serial.println(" try again in "+String(reconnectSeconds)+" seconds");
// Wait 5 seconds before retrying
delay(delayMillis);
}
}
}
void MQTTHelper::announce() {
DynamicJsonDocument doc(1024);
doc["ip"] = WiFi.localIP().toString();
doc["mac"] = WiFi.macAddress();
String payloadSettings;
serializeJson(doc,payloadSettings);
// publish to settings topic
publish("settings", payloadSettings);
doc["id"] = _identifier;
String payloadAnnounce;
serializeJson(doc,payloadAnnounce);
// publish to genneral announce topic
Serial.println("MQTT: "+_announce_topic+" = "+payloadAnnounce);
_mqttClient.publish(_announce_topic.c_str(),payloadAnnounce.c_str());
}
bool MQTTHelper::connect() {
// If you do not want to use a username and password, change next line to
// if (_mqttClient.connect(_identifier.c_str()) {
if (_mqttClient.connect(_identifier.c_str(), _user, _password, _will_topic.c_str(), 2, false, "false")) {
_mqttClient.subscribe((_command_topic).c_str());
announce();
return true;
} else {
return false;
}
}

View File

@@ -15,8 +15,6 @@ framework = arduino
upload_speed = 921600
monitor_speed = 115200
lib_deps =
PubSubClient
ArduinoJson
NewPing
WiFiManager
Homie

View File

@@ -1,128 +1,95 @@
#include <FS.h> //this needs to be first, or it all crashes and burns...
#include "MQTTHelper.h"
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include <NewPing.h>
#include <Homie.h>
#define TURN_ON LOW
#define TURN_OFF HIGH
const int trigPin = D1; //D6
const int echoPin = D2; //D5
const int ledPin = LED_BUILTIN; //D1
const int trigPin = D1; //D1
const int echoPin = D2; //D2
const int ledPin = LED_BUILTIN;
const float minDistance = 0.01;
const float maxDistance = 4.0;
const float minimumChange = 0.2;
const int updateInterval_ms = 1; // s
const int ledInterval_ms = 5; // s
struct Config {
IPAddress mqtt_server = {192, 168, 249, 5};
uint16 mqtt_port = 1883;
} config;
MQTTHelper mqtt;
#define DISTANCE_INTERVAL 5 // s
#define LED_INTERVAL 5 // s
NewPing sonar(trigPin,echoPin,maxDistance*100.0);
HomieNode obstacleNode("obstacle", "Obstacle", "object");
#define heartbeatMillis 5000
#define messageMillis 5000
//flag for saving data
bool shouldSaveConfig = false;
//callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void signal_led(bool ons = true);
void heartbeat_led(int times = 2);
void longbeat_led();
void setup_wifi(String ssid, String password);
void reconnect();
void readConfig();
void saveConfig();
void loopHandler();
void setupHandler();
float readDistance();
void setup() {
Serial.begin(115200);
Serial.println();
Serial << endl << endl;
randomSeed(analogRead(0));
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, TURN_OFF);
//clean FS, for testing
//SPIFFS.format();
readConfig();
//WiFiManager
WiFiManager wifiManager;
//wifiManager.resetSettings(); //reset saved settings
WiFiManagerParameter custom_mqtt_server("MQTT server", "mqtt server", config.mqtt_server.toString().c_str(), 40);
WiFiManagerParameter custom_mqtt_port("MQTT port", "mqtt port", String(config.mqtt_port).c_str(), 6);
wifiManager.setSaveConfigCallback(saveConfigCallback);
wifiManager.addParameter(&custom_mqtt_server);
wifiManager.addParameter(&custom_mqtt_port);
wifiManager.autoConnect(mqtt.getIdentifier().c_str());
//if you get here you have connected to the WiFi
Serial.println("WiFi connected to: "+WiFi.SSID()+", IP address: "+WiFi.localIP().toString());
//read updated parameters
config.mqtt_server.fromString(custom_mqtt_server.getValue());
config.mqtt_port = String(custom_mqtt_port.getValue()).toInt();
saveConfig();
mqtt.Configure(config.mqtt_server,config.mqtt_port);
}
long lastMessage = 0;
long lastHeartbeat = 0;
float oldDistance = 0.0;
float diff = 4.0;
bool checkBounds(float value, float min, float max) {
return !isnan(value) &&
(value >= min && value <= max);
}
bool signalChange(float distance, float oldDistance) {
return fabs(distance - oldDistance) > minimumChange;
Homie_setBrand("EtxeanIoT");
Homie_setFirmware("etxean-distancesensor", "1.0.0");
Homie.setLoopFunction(loopHandler);
obstacleNode
.advertise("distance").setName("Distance").setDatatype("float").setUnit("m");
obstacleNode
.advertise("valid").setName("Valid measurement").setDatatype("boolean");
obstacleNode
.advertise("changed").setName("Obstacle changed").setDatatype("boolean");
Homie.setup();
}
void loop() {
mqtt.loop();
long now = millis();
if (now - lastHeartbeat > heartbeatMillis) {
lastHeartbeat = now;
heartbeat_led();
Homie.loop();
}
if (now - lastMessage > messageMillis) {
lastMessage = now;
long lastHeartbeat = 0;
long lastDistanceSent = 0;
float lastDistance = 0.0;
bool checkBounds(float value, float min, float max) {
return !isnan(value) && value >= min && value <= max;
}
bool signalChange(float distance, float lastDistance) {
return fabs(distance - lastDistance) > minimumChange;
}
String toPayload(bool value)
{
return value ? "true" : "false";
}
void loopHandler() {
if (millis() - lastDistanceSent >= DISTANCE_INTERVAL * 1000UL || lastDistanceSent == 0) {
heartbeat_led();
float distance = readDistance();
//float distance = random(5,400)/100.0;
// Serial.print("Distance read:");
// Serial.print(int(distance*1000));
// Serial.println(" mm");
Homie.getLogger() << "Distance: " << distance << " m";
obstacleNode.setProperty("distance").send(String(distance));
if (checkBounds(distance, 0, maxDistance)) {
mqtt.publish("distance", distance);
bool signal = signalChange(distance, oldDistance);
mqtt.publish("signal", signal);
if (signal)
bool valid = checkBounds(distance,minDistance,maxDistance);
Serial << ", valid = " << toPayload(valid);
obstacleNode.setProperty("valid").send(toPayload(valid));
if (valid)
{
bool changed = signalChange(distance, lastDistance);
obstacleNode.setProperty("changed").send(toPayload(changed));
if (changed)
{
signal_led();
Serial << ", changed";
}
oldDistance = distance;
lastDistance = distance;
}
Serial << endl;
lastDistanceSent = millis();
}
}
@@ -148,59 +115,6 @@ float readDistance() {
return computedDistance;
}
void readConfig() {
//read configuration from FS json
Serial.println("mounting FS...");
if (SPIFFS.begin()) {
Serial.println("mounted file system");
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config.json");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config.json");
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc,configFile);
serializeJsonPretty(doc,Serial);
if (error) {
Serial.print("failed to load config.json: ");
Serial.println(error.c_str());
return;
}
Serial.println("\nparsed config.json");
IPAddress addr;
if (addr.fromString(doc["mqtt_server"].as<char*>())) {
config.mqtt_server = addr;
}
config.mqtt_port = doc["mqtt_port"];
}
}
} else {
Serial.println("failed to mount FS");
}
//end read
}
void saveConfig() {
//save the custom parameters to FS
if (shouldSaveConfig) {
Serial.println("saving config.json");
DynamicJsonDocument doc(1024);
doc["mqtt_server"] = config.mqtt_server.toString();
doc["mqtt_port"] = String(config.mqtt_port);
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config.json for writing");
}
serializeJsonPretty(doc,Serial);
serializeJson(doc,configFile);
configFile.close();
}
}
void signal_led(bool on)
{
if (on)