From 8b2088103a74e616ca82fe043de55cb7ed58e329 Mon Sep 17 00:00:00 2001 From: Evgeny Zinoviev Date: Mon, 29 May 2023 05:44:59 +0300 Subject: platformio: split code into libraries --- platformio/common/libs/mqtt/homekit/mqtt.cpp | 18 --- platformio/common/libs/mqtt/homekit/mqtt.h | 18 --- .../common/libs/mqtt/homekit/mqtt/module.cpp | 26 ++++ platformio/common/libs/mqtt/homekit/mqtt/module.h | 47 ++++++ platformio/common/libs/mqtt/homekit/mqtt/mqtt.cpp | 164 +++++++++++++++++++++ platformio/common/libs/mqtt/homekit/mqtt/mqtt.h | 48 ++++++ platformio/common/libs/mqtt/homekit/mqtt/payload.h | 15 ++ platformio/common/libs/mqtt/library.json | 3 +- 8 files changed, 301 insertions(+), 38 deletions(-) delete mode 100644 platformio/common/libs/mqtt/homekit/mqtt.cpp delete mode 100644 platformio/common/libs/mqtt/homekit/mqtt.h create mode 100644 platformio/common/libs/mqtt/homekit/mqtt/module.cpp create mode 100644 platformio/common/libs/mqtt/homekit/mqtt/module.h create mode 100644 platformio/common/libs/mqtt/homekit/mqtt/mqtt.cpp create mode 100644 platformio/common/libs/mqtt/homekit/mqtt/mqtt.h create mode 100644 platformio/common/libs/mqtt/homekit/mqtt/payload.h (limited to 'platformio/common/libs/mqtt') diff --git a/platformio/common/libs/mqtt/homekit/mqtt.cpp b/platformio/common/libs/mqtt/homekit/mqtt.cpp deleted file mode 100644 index c2ba293..0000000 --- a/platformio/common/libs/mqtt/homekit/mqtt.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "./mqtt.h" - -namespace homekit::mqtt { - - const uint8_t MQTT_CA_FINGERPRINT[] = { \ - 0x0e, 0xb6, 0x3a, 0x02, 0x1f, \ - 0x4e, 0x1e, 0xe1, 0x6a, 0x67, \ - 0x62, 0xec, 0x64, 0xd4, 0x84, \ - 0x8a, 0xb0, 0xc9, 0x9c, 0xbb \ - };; - const char MQTT_SERVER[] = "mqtt.solarmon.ru"; - const uint16_t MQTT_PORT = 8883; - const char MQTT_USERNAME[] = CONFIG_MQTT_USERNAME; - const char MQTT_PASSWORD[] = CONFIG_MQTT_PASSWORD; - const char MQTT_CLIENT_ID[] = CONFIG_MQTT_CLIENT_ID; - const char MQTT_SECRET[CONFIG_NODE_SECRET_SIZE+1] = CONFIG_NODE_SECRET; - -} diff --git a/platformio/common/libs/mqtt/homekit/mqtt.h b/platformio/common/libs/mqtt/homekit/mqtt.h deleted file mode 100644 index 2c86b00..0000000 --- a/platformio/common/libs/mqtt/homekit/mqtt.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef COMMON_HOMEKIT_MQTT_H -#define COMMON_HOMEKIT_MQTT_H - -#include - -namespace homekit::mqtt { - - extern const uint8_t MQTT_CA_FINGERPRINT[]; - extern const char MQTT_SERVER[]; - extern const uint16_t MQTT_PORT; - extern const char MQTT_USERNAME[]; - extern const char MQTT_PASSWORD[]; - extern const char MQTT_CLIENT_ID[]; - extern const char MQTT_SECRET[CONFIG_NODE_SECRET_SIZE+1]; - -} - -#endif //COMMON_HOMEKIT_MQTT_H diff --git a/platformio/common/libs/mqtt/homekit/mqtt/module.cpp b/platformio/common/libs/mqtt/homekit/mqtt/module.cpp new file mode 100644 index 0000000..e78ff12 --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt/module.cpp @@ -0,0 +1,26 @@ +#include "./module.h" +#include + +namespace homekit::mqtt { + +bool MqttModule::tickElapsed() { + if (!tickSw.elapsed(tickInterval*1000)) + return false; + + tickSw.save(); + return true; +} + +void MqttModule::handlePayload(Mqtt& mqtt, String& topic, uint16_t packetId, const uint8_t* payload, size_t length, + size_t index, size_t total) { + if (length != total) + PRINTLN("mqtt: received partial message, not supported"); + + // TODO +} + +void MqttModule::handleOnPublish(uint16_t packetId) {} + +void MqttModule::handleOnDisconnect(espMqttClientTypes::DisconnectReason reason) {} + +} diff --git a/platformio/common/libs/mqtt/homekit/mqtt/module.h b/platformio/common/libs/mqtt/homekit/mqtt/module.h new file mode 100644 index 0000000..7bf2522 --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt/module.h @@ -0,0 +1,47 @@ +#ifndef HOMEKIT_LIB_MQTT_MODULE_H +#define HOMEKIT_LIB_MQTT_MODULE_H + +#include "./mqtt.h" +#include "./payload.h" +#include + + +namespace homekit::mqtt { + +class Mqtt; + +class MqttModule { +protected: + bool initialized; + StopWatch tickSw; + short tickInterval; + + bool receiveOnPublish; + bool receiveOnDisconnect; + + bool tickElapsed(); + +public: + MqttModule(short _tickInterval, bool _receiveOnPublish = false, bool _receiveOnDisconnect = false) + : initialized(false) + , tickInterval(_tickInterval) + , receiveOnPublish(_receiveOnPublish) + , receiveOnDisconnect(_receiveOnDisconnect) {} + + virtual void init(Mqtt& mqtt) = 0; + virtual void tick(Mqtt& mqtt) = 0; + + virtual void handlePayload(Mqtt& mqtt, String& topic, uint16_t packetId, const uint8_t *payload, size_t length, size_t index, size_t total); + virtual void handleOnPublish(uint16_t packetId); + virtual void handleOnDisconnect(espMqttClientTypes::DisconnectReason reason); + + inline void setInitialized() { + initialized = true; + } + + friend class Mqtt; +}; + +} + +#endif //HOMEKIT_LIB_MQTT_MODULE_H \ No newline at end of file diff --git a/platformio/common/libs/mqtt/homekit/mqtt/mqtt.cpp b/platformio/common/libs/mqtt/homekit/mqtt/mqtt.cpp new file mode 100644 index 0000000..9d96f9f --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt/mqtt.cpp @@ -0,0 +1,164 @@ +#include "./mqtt.h" + +#include +#include +#include + +namespace homekit::mqtt { + +const uint8_t MQTT_CA_FINGERPRINT[] = { \ + 0x0e, 0xb6, 0x3a, 0x02, 0x1f, \ + 0x4e, 0x1e, 0xe1, 0x6a, 0x67, \ + 0x62, 0xec, 0x64, 0xd4, 0x84, \ + 0x8a, 0xb0, 0xc9, 0x9c, 0xbb \ +};; +const char MQTT_SERVER[] = "mqtt.solarmon.ru"; +const uint16_t MQTT_PORT = 8883; +const char MQTT_USERNAME[] = CONFIG_MQTT_USERNAME; +const char MQTT_PASSWORD[] = CONFIG_MQTT_PASSWORD; +const char MQTT_CLIENT_ID[] = CONFIG_MQTT_CLIENT_ID; +const char MQTT_SECRET[CONFIG_NODE_SECRET_SIZE+1] = CONFIG_NODE_SECRET; + +static const uint16_t MQTT_KEEPALIVE = 30; + +using namespace espMqttClientTypes; + +Mqtt::Mqtt() { + auto cfg = config::read(); + homeId = String(cfg.flags.node_configured ? cfg.node_id : wifi::NODE_ID); + + randomSeed(micros()); + + client.onConnect([&](bool sessionPresent) { + PRINTLN("mqtt: connected"); + + for (auto* module: modules) { + if (!module->initialized) { + module->init(*this); + module->setInitialized(); + } + } + + connected = true; + }); + + client.onDisconnect([&](DisconnectReason reason) { + PRINTF("mqtt: disconnected, reason=%d\n", static_cast(reason)); +#ifdef DEBUG + if (reason == DisconnectReason::TLS_BAD_FINGERPRINT) + PRINTLN("reason: bad fingerprint"); +#endif + + for (auto* module: modules) { + if (module->receiveOnDisconnect) { + module->handleOnDisconnect(reason); + } + } + +// if (ota.readyToRestart) { +// restartTimer.once(1, restart); +// } else { + reconnectTimer.once(2, [&]() { + reconnect(); + }); +// } + }); + + client.onSubscribe([&](uint16_t packetId, const SubscribeReturncode* returncodes, size_t len) { + PRINTF("mqtt: subscribe ack, packet_id=%d\n", packetId); + for (size_t i = 0; i < len; i++) { + PRINTF(" return code: %u\n", static_cast(*(returncodes+i))); + } + }); + + client.onUnsubscribe([&](uint16_t packetId) { + PRINTF("mqtt: unsubscribe ack, packet_id=%d\n", packetId); + }); + + client.onMessage([&](const MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total) { + PRINTF("mqtt: message received, topic=%s, qos=%d, dup=%d, retain=%d, len=%ul, index=%ul, total=%ul\n", + topic, properties.qos, (int)properties.dup, (int)properties.retain, len, index, total); + + const char *ptr = topic + homeId.length() + 10; + String relevantTopic(ptr); + + auto it = moduleSubscriptions.find(relevantTopic); + if (it != moduleSubscriptions.end()) { + auto module = it->second; + module->handlePayload(*this, relevantTopic, properties.packetId, payload, len, index, total); + } else { + PRINTF("error: module subscription for topic %s not found\n", topic); + } + }); + + client.onPublish([&](uint16_t packetId) { + PRINTF("mqtt: publish ack, packet_id=%d\n", packetId); + + for (auto* module: modules) { + if (module->receiveOnPublish) { + module->handleOnPublish(packetId); + } + } + }); + + client.setServer(MQTT_SERVER, MQTT_PORT); + client.setClientId(MQTT_CLIENT_ID); + client.setCredentials(MQTT_USERNAME, MQTT_PASSWORD); + client.setCleanSession(true); + client.setFingerprint(MQTT_CA_FINGERPRINT); + client.setKeepAlive(MQTT_KEEPALIVE); +} + +void Mqtt::connect() { + reconnect(); +} + +void Mqtt::reconnect() { + if (client.connected()) { + PRINTLN("warning: already connected"); + return; + } + client.connect(); +} + +void Mqtt::disconnect() { + // TODO test how this works??? + reconnectTimer.detach(); + client.disconnect(); +} + +void Mqtt::loop() { + client.loop(); + for (auto& module: modules) { + module->tick(*this); + } +} + +uint16_t Mqtt::publish(const String& topic, uint8_t* payload, size_t length) { + String fullTopic = "hk/" + homeId + "/temphum/" + topic; + return client.publish(fullTopic.c_str(), 1, false, payload, length); +} + +uint16_t Mqtt::subscribe(const String& topic, uint8_t qos) { + String fullTopic = "hk/" + homeId + "/temphum/" + topic; + PRINTF("mqtt: subscribing to %s...\n", fullTopic.c_str()); + + uint16_t packetId = client.subscribe(fullTopic.c_str(), qos); + if (!packetId) + PRINTF("error: failed to subscribe to %s\n", fullTopic.c_str()); + return packetId; +} + +void Mqtt::addModule(MqttModule* module) { + modules.emplace_back(module); + if (connected) { + module->init(*this); + module->setInitialized(); + } +} + +void Mqtt::subscribeModule(String& topic, MqttModule* module) { + moduleSubscriptions[topic] = module; +} + +} diff --git a/platformio/common/libs/mqtt/homekit/mqtt/mqtt.h b/platformio/common/libs/mqtt/homekit/mqtt/mqtt.h new file mode 100644 index 0000000..983cc5a --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt/mqtt.h @@ -0,0 +1,48 @@ +#ifndef HOMEKIT_LIB_MQTT_H +#define HOMEKIT_LIB_MQTT_H + +#include +#include +#include +#include +#include +#include "./module.h" + +namespace homekit::mqtt { + +extern const uint8_t MQTT_CA_FINGERPRINT[]; +extern const char MQTT_SERVER[]; +extern const uint16_t MQTT_PORT; +extern const char MQTT_USERNAME[]; +extern const char MQTT_PASSWORD[]; +extern const char MQTT_CLIENT_ID[]; +extern const char MQTT_SECRET[CONFIG_NODE_SECRET_SIZE+1]; + +class MqttModule; + +class Mqtt { +private: + String homeId; + WiFiClientSecure httpsSecureClient; + espMqttClientSecure client; + Ticker reconnectTimer; + std::vector modules; + std::map moduleSubscriptions; + bool connected; + + uint16_t subscribe(const String& topic, uint8_t qos = 0); + +public: + Mqtt(); + void connect(); + void disconnect(); + void reconnect(); + void loop(); + void addModule(MqttModule* module); + void subscribeModule(String& topic, MqttModule* module); + uint16_t publish(const String& topic, uint8_t* payload, size_t length); +}; + +} + +#endif //HOMEKIT_LIB_MQTT_H \ No newline at end of file diff --git a/platformio/common/libs/mqtt/homekit/mqtt/payload.h b/platformio/common/libs/mqtt/homekit/mqtt/payload.h new file mode 100644 index 0000000..3e0fe0c --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt/payload.h @@ -0,0 +1,15 @@ +#ifndef HOMEKIT_MQTT_PAYLOAD_H +#define HOMEKIT_MQTT_PAYLOAD_H + +#include + +namespace homekit::mqtt { + +struct MqttPayload { + virtual ~MqttPayload() = default; + virtual size_t size() const = 0; +}; + +} + +#endif \ No newline at end of file diff --git a/platformio/common/libs/mqtt/library.json b/platformio/common/libs/mqtt/library.json index 8131494..179b10a 100644 --- a/platformio/common/libs/mqtt/library.json +++ b/platformio/common/libs/mqtt/library.json @@ -1,8 +1,7 @@ { "name": "homekit_mqtt", - "version": "1.0.2", + "version": "1.0.8", "build": { "flags": "-I../../include" } } - -- cgit v1.2.3