diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c671236 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,62 @@ +{ + "files.associations": { + "*.module": "php", + "*.html": "html", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "complex": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "list": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "set": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp" + } +} \ No newline at end of file diff --git a/include/MQTTHelper.h b/include/MQTTHelper.h new file mode 100644 index 0000000..98f18b9 --- /dev/null +++ b/include/MQTTHelper.h @@ -0,0 +1,113 @@ +#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; + + 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"); + _mqttClient.setCallback([this] (char* topic, byte* payload, unsigned int length) { this->callback(topic, payload, length); }); + } + + String getIdentifier() { return _identifier; } + + String getTopic(String sensor) { + return _group + "/" + _identifier + "/" + sensor; + } + + void Configure(IPAddress server, uint16 port) { + Serial.println("Configuring MQTT connection to: "+server.toString()+":"+String(port)); + _mqttClient.setServer(server, port); + if (_mqttClient.connected()) { + connect(); + } + } + + void loop() { + static unsigned long lastWill; + if (!_mqttClient.connected()) { + reconnect(); + } + _mqttClient.loop(); + + auto now = millis(); + if ((now - lastWill) > 1000) + { + lastWill = now; + _mqttClient.publish(_will_topic.c_str(), "true"); + } + } + + template + void publish(String sensor, T payload, bool retained = false) { + _mqttClient.publish(getTopic(sensor).c_str(), String(payload).c_str(), retained); + } +}; + +void MQTTHelper::callback(char* topic, byte* payload, unsigned int length) { + Serial.print("Message arrived:"); + Serial.print(topic); + Serial.print(" = "); + for (unsigned int i=0; i +#include //this needs to be first, or it all crashes and burns... + +#include "MQTTHelper.h" + #include -#include #include #include #include +#include #define TURN_ON LOW #define TURN_OFF HIGH -#define mqtt_server "192.168.249.5" -#define mqtt_port 1883 -#define mqtt_user "homedevice" -#define mqtt_password "WNzAb4VazNFUPlpkn0ED" -#define mqtt_client_id "home_DistanceSensor" +struct Config { + IPAddress mqtt_server = {192, 168, 249, 5}; + uint16 mqtt_port = 1883; +} config; + +MQTTHelper mqtt; -#define distance_topic "garagesensor/distance" #define heartbeatMillis 10000 #define messageMillis 1000 -#define will_topic "garagesensor/online" -#define will_message "false" -WiFiClient espClient; -PubSubClient mpttClient(espClient); +//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 heartbeat(); +void heartbeat(int times = 3); void longbeat(); void setup_wifi(String ssid, String password); void reconnect(); +void readConfig(); +void saveConfig(); void setup() { Serial.begin(115200); + Serial.println(); randomSeed(analogRead(0)); pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, TURN_OFF); - - //WiFiManager - WiFiManager wifiManager; - //wifiManager.resetSettings(); //reset saved settings - wifiManager.autoConnect(); - - //if you get here you have connected to the WiFi - Serial.print("WiFi connected to: "); - Serial.println(WiFi.SSID()); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - mpttClient.setServer(mqtt_server, mqtt_port); + //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; @@ -59,12 +79,8 @@ bool checkBound(float newValue, float prevValue, float maxDiff) { } void loop() { - if (!mpttClient.connected()) { - reconnect(); - } - mpttClient.loop(); - mpttClient.publish(will_topic, "true"); - + mqtt.loop(); + long now = millis(); if (now - lastHeartbeat > heartbeatMillis) { lastHeartbeat = now; @@ -75,66 +91,81 @@ void loop() { lastMessage = now; float newDistance = random(5,400)/100.0; - Serial.print("New distance:"); - Serial.println(String(newDistance).c_str()); + // Serial.print("New distance:"); + // Serial.println(String(newDistance).c_str()); if (checkBound(newDistance, distance, diff)) { distance = newDistance; - Serial.print(distance_topic); - Serial.print(" = "); - Serial.println(String(distance).c_str()); - mpttClient.publish(distance_topic, String(distance).c_str()); + auto sensorName = "distance"; + Serial.print(mqtt.getTopic(sensorName)); + Serial.println(" = "+String(distance)); + mqtt.publish("distance", distance); } } } -void setup_wifi(String ssid, String password) { - delay(10); - // We start by connecting to a WiFi network - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - - Serial.println(""); - Serial.println("WiFi connected"); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); -} - -void reconnect() { - // Loop until we're reconnected - while (!mpttClient.connected()) { - Serial.print("Attempting MQTT connection..."); - // Attempt to connect - // If you do not want to use a username and password, change next line to - // if (mpttClient.connect(mqtt_client_id)) { - if (mpttClient.connect(mqtt_client_id, mqtt_user, mqtt_password, will_topic, 2, false, will_message)) { - Serial.println("connected"); - } else { - Serial.print("failed, rc="); - Serial.print(mpttClient.state()); - Serial.println(" try again in 5 seconds"); - // Wait 5 seconds before retrying - delay(5000); +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); + Serial.println(); + 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 heartbeat() +void heartbeat(int times) { - for (int i=0; i<2; i++) + for (int blink=0; blink