diff --git a/data/homie/ui_bundle.gz b/data/homie/ui_bundle.gz new file mode 100644 index 0000000..13983d4 Binary files /dev/null and b/data/homie/ui_bundle.gz differ 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)