From 38203004605cb9b1f226463370a0d2db3101d7cc Mon Sep 17 00:00:00 2001 From: Ard Kuijpers Date: Sat, 29 Feb 2020 18:35:46 +0100 Subject: [PATCH] Updated boolean write to MQTT --- data/homie/ui_bundle.gz | Bin 0 -> 59532 bytes include/MQTTHelper.h | 132 ------------------------- platformio.ini | 6 +- src/main.cpp | 206 ++++++++++++---------------------------- 4 files changed, 62 insertions(+), 282 deletions(-) create mode 100644 data/homie/ui_bundle.gz delete mode 100644 include/MQTTHelper.h diff --git a/data/homie/ui_bundle.gz b/data/homie/ui_bundle.gz new file mode 100644 index 0000000000000000000000000000000000000000..13983d499881b63c9027a044e856d758894eda9c GIT binary patch literal 59532 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
  • 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 Ra{liB{TFnm9UVJ^0|0f1Kdb-% literal 0 HcmV?d00001 diff --git a/include/MQTTHelper.h b/include/MQTTHelper.h deleted file mode 100644 index 15eac6c..0000000 --- a/include/MQTTHelper.h +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include -#include -#include - -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 - 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; - } -} - diff --git a/platformio.ini b/platformio.ini index f877531..b487207 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,8 +15,6 @@ framework = arduino upload_speed = 921600 monitor_speed = 115200 lib_deps = - PubSubClient - ArduinoJson NewPing - WiFiManager - + Homie + diff --git a/src/main.cpp b/src/main.cpp index fba697e..37541bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,128 +1,95 @@ -#include //this needs to be first, or it all crashes and burns... - -#include "MQTTHelper.h" - -#include -#include -#include -#include -#include #include +#include #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; + Homie.loop(); +} + +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(); - } - - if (now - lastMessage > messageMillis) { - lastMessage = now; - 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) - signal_led(); + 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"; + } + lastDistance = distance; } - - oldDistance = 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())) { - 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)