#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; } }