diff --git a/src/config.h b/include/config.h similarity index 100% rename from src/config.h rename to include/config.h diff --git a/lib/ETH/WS_ETH.cpp b/lib/ETH/WS_ETH.cpp deleted file mode 100644 index 794ce5f..0000000 --- a/lib/ETH/WS_ETH.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "WS_ETH.h" - -#include -#include - -static bool eth_connected = false; -static bool eth_connected_Old = false; -IPAddress ETH_ip; -// NTP setup -WiFiUDP udp; -NTPClient timeClient(udp, "pool.ntp.org", TZ*3600, 60000); // NTP server, time offset in seconds, update interval - -void onEvent(arduino_event_id_t event, arduino_event_info_t info) { - switch (event) { - case ARDUINO_EVENT_ETH_START: - printf("ETH Started\r\n"); - //set eth hostname here - ETH.setHostname("esp32-eth0"); - break; - case ARDUINO_EVENT_ETH_CONNECTED: printf("ETH Connected\r\n"); break; - case ARDUINO_EVENT_ETH_GOT_IP: printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); //printf("%s\r\n",ETH); - ETH_ip = ETH.localIP(); - printf("ETH Got IP: %d.%d.%d.%d\n", ETH_ip[0], ETH_ip[1], ETH_ip[2], ETH_ip[3]); -#if USE_TWO_ETH_PORTS - // printf("%d\r\n",ETH1); -#endif - eth_connected = true; - break; - case ARDUINO_EVENT_ETH_LOST_IP: - printf("ETH Lost IP\r\n"); - eth_connected = false; - break; - case ARDUINO_EVENT_ETH_DISCONNECTED: - printf("ETH Disconnected\r\n"); - eth_connected = false; - break; - case ARDUINO_EVENT_ETH_STOP: - printf("ETH Stopped\r\n"); - eth_connected = false; - break; - default: break; - } -} - -void testClient(const char *host, uint16_t port) { - printf("\nconnecting to \r\n");; - printf("%s\r\n",host); - - NetworkClient client; - if (!client.connect(host, port)) { - printf("connection failed\r\n"); - return; - } - client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); - while (client.connected() && !client.available()); - while (client.available()) { - printf("%c",(char)client.read()); - } - - printf("closing connection\n"); - client.stop(); -} - -void ETH_Init(void) { - printf("Ethernet Start\r\n"); - Network.onEvent(onEvent); - - SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI); - ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI); -#if USE_TWO_ETH_PORTS - ETH1.begin(ETH1_PHY_TYPE, ETH1_PHY_ADDR, ETH1_PHY_CS, ETH1_PHY_IRQ, ETH1_PHY_RST, SPI); -#endif - xTaskCreatePinnedToCore( - EthernetTask, - "EthernetTask", - 4096, - NULL, - 2, - NULL, - 0 - ); -} -void EthernetTask(void *parameter) { - while(1){ - if (eth_connected && !eth_connected_Old) { - eth_connected_Old = eth_connected; - //RGB_Open_Time(0, 60, 0,1000, 0); - printf("Network port connected!\r\n"); - Acquisition_time(); - } - else if(!eth_connected && eth_connected_Old){ - eth_connected_Old = eth_connected; - printf("Network port disconnected!\r\n"); - } - vTaskDelay(pdMS_TO_TICKS(100)); - } - vTaskDelete(NULL); -} -void Acquisition_time(void) { // Get the network time and set to DS3231 to be called after the WIFI connection is successful - timeClient.begin(); - timeClient.update(); - - time_t currentTime = timeClient.getEpochTime(); - while(currentTime < 1609459200) // Using the current timestamp to compare with a known larger value,1609459200 is a known larger timestamp value that corresponds to January 1, 2021 - { - timeClient.update(); - currentTime = timeClient.getEpochTime(); - printf("ETH - Online clock error!!!\r\n"); - } - struct tm *localTime = localtime(¤tTime); - //static datetime_t PCF85063_Time = {0}; - //PCF85063_Time.year = localTime->tm_year + 1900; - //PCF85063_Time.month = localTime->tm_mon + 1; - //PCF85063_Time.day = localTime->tm_mday; - //PCF85063_Time.dotw = localTime->tm_wday; - //PCF85063_Time.hour = localTime->tm_hour; - //PCF85063_Time.minute = localTime->tm_min; - //PCF85063_Time.second = localTime->tm_sec; - //PCF85063_Set_All(PCF85063_Time); -} diff --git a/lib/ETH/WS_ETH.h b/lib/ETH/WS_ETH.h deleted file mode 100644 index f0d0f5b..0000000 --- a/lib/ETH/WS_ETH.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include -#include -#include - -// Set this to 1 to enable dual Ethernet support -#define USE_TWO_ETH_PORTS 0 - -#ifndef ETH_PHY_TYPE - #define ETH_PHY_TYPE ETH_PHY_W5500 - #define ETH_PHY_ADDR 1 - #define ETH_PHY_CS 16 - #define ETH_PHY_IRQ 12 - #define ETH_PHY_RST 39 -#endif - -// SPI pins -#define ETH_SPI_SCK 15 -#define ETH_SPI_MISO 14 -#define ETH_SPI_MOSI 13 - -#if USE_TWO_ETH_PORTS - // Second port on shared SPI bus - #ifndef ETH1_PHY_TYPE - #define ETH1_PHY_TYPE ETH_PHY_W5500 - #define ETH1_PHY_ADDR 1 - #define ETH1_PHY_CS 32 - #define ETH1_PHY_IRQ 33 - #define ETH1_PHY_RST 18 - #endif - ETHClass ETH1(1); -#endif - -#define TZ 1 // rome - -void ETH_Init(void); -void ETH_Loop(void); -void EthernetTask(void *parameter); - -void Acquisition_time(void); \ No newline at end of file diff --git a/lib/GPIO/BUZZER_Driver.cpp b/lib/GPIO/BUZZER_Driver.cpp index b9a8f7d..4cd7642 100644 --- a/lib/GPIO/BUZZER_Driver.cpp +++ b/lib/GPIO/BUZZER_Driver.cpp @@ -14,7 +14,7 @@ namespace drivers ledcAttach(buzzerPin, 1000, 8); m_bp.pin = buzzerPin; m_bp.beeperTask = NULL; - beep(50, NOTE_G); + //beep(50, NOTE_G); } Buzzer::~Buzzer() diff --git a/src/main.cpp b/src/main.cpp index 7c05d02..b8e03f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -16,32 +15,21 @@ #include +#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG +#include #include "utils.h" /////////////// GLOBALS /////////////// -Config& conf = Config::getInstance(); +Config &conf = Config::getInstance(); /////////////// GLOBALS /////////////// -void callback(char *topic, uint8_t *payload, unsigned int length) +void testAction(const ArduinoJson::JsonDocument &doc) { - std::string pl; - pl.resize(length); - std::snprintf(pl.data(), length, "%s", payload); - LOG_INFO("Message: Topic [", topic, "], Payload [", pl.c_str(), "]"); + std::string message; + ArduinoJson::serializeJsonPretty(doc, message); + LOG_INFO("Received on testAction\n", message.c_str()); } -void myTask(void *mqtt) -{ - auto client = (PubSubClient *)(mqtt); - while (client->connected()) - { - client->loop(); - vTaskDelay(pdMS_TO_TICKS(100)); - } - LOG_ERROR("Mqtt Loop Ended, client disconnected"); - vTaskDelete(NULL); // delete the current task -}; - void setup() { Serial.begin(9600); @@ -75,15 +63,11 @@ void loop() LOG_INFO("Temperature sensors connected ->", sensors); //////////////// NETWORK //////////////// - // MQTT Test // - NetworkClient tcp; - PubSubClient mqtt(tcp); - mqtt.setServer(conf.m_mqttHost.c_str(), conf.m_mqttPort); - mqtt.setCallback(callback); + auto mqtt = MQTTwrapper(); //////////////// NETWORK //////////////// - - //////////////// NETWORK //////////////// - /////////////// CALLBACK //////////////// + + //////////////// NETWORK //////////////// + /////////////// CALLBACK //////////////// Network.onEvent( [ð, &rtc, &mqtt, &buzzer, &led](arduino_event_id_t event, arduino_event_info_t info) -> void { @@ -98,7 +82,7 @@ void loop() { if (eth.getNtpTime(ntpTime) && rtc.setDatetime(drivers::PCF85063::fromEpoch(ntpTime))) { - buzzer.beep(250, NOTE_F); + //buzzer.beep(250, NOTE_F); led.setColor({255, 255, 0}); const drivers::PCF85063::datetime_t dt(drivers::PCF85063::fromEpoch(ntpTime)); LOG_INFO("NTP Time: ", drivers::PCF85063::datetime2str(dt).c_str()); @@ -108,10 +92,9 @@ void loop() } while (mqttRetries++ < conf.m_mqttRetries) { - if (!mqtt.connected() && mqtt.connect(conf.m_mqttClientName.c_str())) + if (mqtt.connect()) { - mqtt.subscribe("test/esp32-in"); - xTaskCreatePinnedToCore(myTask, "mqttLoop", 4096, &mqtt, 2, NULL, 1); + mqtt.subscribe("test/esp32-in", testAction); break; } delay(100); @@ -128,7 +111,10 @@ void loop() const std::string timeStr(rtc.getTimeStr()); LOG_INFO("Current Datetime", timeStr.c_str()); - mqtt.publish("test/esp32-out", ("[" + std::to_string(k) + "] -> " + timeStr).c_str()); + ArduinoJson::JsonDocument ts; + ts["loopIterator"] = k; + ts["currentTime"] = timeStr; + mqtt.publish("test/esp32-out", ts); uint8_t i(0); for (auto v : tmp.getTempAll()) @@ -172,11 +158,13 @@ void loop() LOG_INFO("Buzzing -> ", buzzing ? "True" : "False"); } - if(io.digitalIORead(9)) { // verde + if (io.digitalIORead(9)) + { // verde conf.resetConfig(); } - if(io.digitalIORead(10)) { // giallo + if (io.digitalIORead(10)) + { // giallo esp_restart(); } diff --git a/src/mqtt.cpp b/src/mqtt.cpp new file mode 100644 index 0000000..38f9de1 --- /dev/null +++ b/src/mqtt.cpp @@ -0,0 +1,136 @@ +#include + +#define STACK_DEPTH 4096 +#define PRIOTITY 1 + +MQTTwrapper::MQTTwrapper() : m_config(Config::getInstance()), m_tcp(NetworkClient()), m_client(PubSubClient(m_tcp)), m_loopHandle(NULL) +{ + m_client.setServer(m_config.m_mqttHost.c_str(), m_config.m_mqttPort); + m_client.setKeepAlive(15); + getInstance(this); +} + +MQTTwrapper::~MQTTwrapper() +{ + disconnect(); +} + +const bool MQTTwrapper::connect() +{ + if (!m_client.connect(m_config.m_mqttClientName.c_str())) + { + LOG_ERROR("Unable to connect to MQTT Host", m_config.m_mqttHost.c_str()); + return false; + } + LOG_INFO("MQTT client connected to", m_config.m_mqttHost.c_str()); + if (m_loopHandle == NULL) + { + xTaskCreate(clientLoop, "mqttLoop", STACK_DEPTH, this, PRIOTITY, &m_loopHandle); + m_client.setCallback(MQTTwrapper::callback); + } + return true; +} + +const bool MQTTwrapper::disconnect() +{ + m_client.disconnect(); + if (m_loopHandle) + { + vTaskDelete(m_loopHandle); // immediate terminate loop + } + return true; +} + +const bool MQTTwrapper::subscribe(topic_t topic, action_t action) +{ + if (m_actionMap.contains(topic)) + { + LOG_WARN("MQTT was already subscribed to", topic.c_str()); + return true; + } + if (m_client.subscribe(topic.c_str())) + { + m_actionMap[topic] = action; + LOG_INFO("MQTT subscribed to", topic.c_str()); + return true; + } + LOG_ERROR("MQTT unable to subscribe to", topic.c_str()); + return false; +} + +const bool MQTTwrapper::unsubscribe(topic_t topic) +{ + if (!m_actionMap.contains(topic)) + { + LOG_WARN("MQTT was NOT subscribed to", topic.c_str()); + return false; + } + if (m_client.unsubscribe(topic.c_str())) + { + LOG_INFO("MQTT unsubscribed to", topic.c_str()); + m_actionMap.erase(topic); + return true; + } + LOG_ERROR("MQTT unable to unsubscribe to", topic.c_str()); + return false; +} + +const bool MQTTwrapper::publish(topic_t topic, const ArduinoJson::JsonDocument obj) +{ + std::string message; + if (!ArduinoJson::serializeJson(obj, message)) + { + LOG_ERROR("MQTT failed to serialize object"); + return false; + } + if (m_client.publish(topic.c_str(), message.c_str())) + { + LOG_DEBUG("MQTT published topic [", topic.c_str(), "] - message [", message.c_str(), "]"); + return true; + } + LOG_ERROR("MQTT failed to publish topic [", topic.c_str(), "] - message [", message.c_str(), "]"); + return false; +} + +void MQTTwrapper::callback(char *topic, uint8_t *payload, unsigned int length) +{ + std::string pl; + pl.resize(length+1); + std::snprintf(pl.data(), length+1, "%s", payload); + auto inst = getInstance(); + if (inst) + { + inst->onMessage(std::string(topic), pl); + return; + } + LOG_ERROR("MQTT no client instance set"); + return; +} + +void MQTTwrapper::onMessage(const std::string topic, const std::string message) +{ + ArduinoJson::JsonDocument obj; + LOG_DEBUG("MQTT received topic [", topic.c_str(), "] - message [", message.c_str(), "]"); + if (ArduinoJson::deserializeJson(obj, message) == ArduinoJson::DeserializationError::Ok) + { + m_actionMap[topic](obj); + return; + } + LOG_ERROR("MQTT failed to deserialize message\n", message.c_str()); + return; +} + +void MQTTwrapper::clientLoop(void *params) +{ + auto client = (MQTTwrapper *)(params); + auto loopTime = client->m_config.m_mqttLoopTime; + LOG_INFO("Starting MQTT client loop"); + while (client->m_client.connected()) + { + client->m_client.loop(); + vTaskDelay(pdMS_TO_TICKS(loopTime)); + } + LOG_ERROR("MQTT client loop terminated, disconnected"); + client->m_loopHandle = NULL; + vTaskDelete(NULL); // delete the current task +} diff --git a/src/mqtt.h b/src/mqtt.h new file mode 100644 index 0000000..793333c --- /dev/null +++ b/src/mqtt.h @@ -0,0 +1,58 @@ +#pragma once + +#define DEBUGLOG_DEFAULT_LOG_LEVEL_DEBUG + +#include +#include +#include +#include +#include + +#include + +#include + +typedef std::string topic_t; +typedef std::function action_t; // the actions receive a JsonObject containing the received message +typedef std::map action_map_t; + +class MQTTwrapper +{ + +private: + static MQTTwrapper *getInstance(MQTTwrapper *inst = nullptr) + { + static std::unique_ptr m_instance; + if (inst) + m_instance.reset(inst); + if (m_instance) + return m_instance.get(); + return nullptr; + } + +public: + MQTTwrapper(); + ~MQTTwrapper(); + + const bool connect(); + const bool disconnect(); + + const bool subscribe(topic_t topic, action_t action); + const bool unsubscribe(topic_t topic); + + const bool publish(topic_t topic, const ArduinoJson::JsonDocument obj); + +private: + static void callback(char *topic, uint8_t *payload, unsigned int length); // C-style callback only to invoke onMessage + void onMessage(const std::string topic, const std::string message); + + // infinite loop to call the client loop method in a taskHandle + static void clientLoop(void *params); + +private: + const Config &m_config; + action_map_t m_actionMap; + NetworkClient m_tcp; + PubSubClient m_client; + TaskHandle_t m_loopHandle; +};