diff --git a/Template Project/lib/ESPMegaPRO/DigitalInputIoT.cpp b/Template Project/lib/ESPMegaPRO/DigitalInputIoT.cpp index e03a204..ea5666a 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalInputIoT.cpp +++ b/Template Project/lib/ESPMegaPRO/DigitalInputIoT.cpp @@ -1,11 +1,12 @@ #include -bool DigitalInputIoT::begin(uint8_t card_id, DigitalInputCard *card, PubSubClient *mqtt, char *base_topic) { - this->card = card; +bool DigitalInputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) { + this->card = (DigitalInputCard *)card; this->card_id = card_id; this->mqtt = mqtt; this->base_topic = base_topic; + this->setDigitalInputsPublishEnabled(true); this->card->registerCallback(std::bind(&DigitalInputIoT::handleValueChange, this, std::placeholders::_1, std::placeholders::_2)); return true; @@ -63,9 +64,12 @@ uint8_t DigitalInputIoT::getType() { void DigitalInputIoT::publishDigitalInput(uint8_t pin) { - char topic[64]; - char payload[2]; - sprintf(topic, "%s/%d/%d", this->base_topic, this->card_id, pin); - sprintf(payload, "%d", this->card->digitalRead(pin, false)); + char topic[20] = {0}; + char payload[20] = {0}; + topic[0] = pin-pin%10 + '0'; + topic[1] = pin%10 + '0'; + topic[2] = '\0'; + payload[0] = this->card->digitalRead(pin, false) + '0'; + payload[1] = '\0'; this->publishRelative(topic, payload); } \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/DigitalInputIoT.hpp b/Template Project/lib/ESPMegaPRO/DigitalInputIoT.hpp index 574058c..f2bf4ce 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalInputIoT.hpp +++ b/Template Project/lib/ESPMegaPRO/DigitalInputIoT.hpp @@ -8,7 +8,7 @@ class DigitalInputIoT : public IoTComponent { public: - bool begin(uint8_t card_id, DigitalInputCard *card, PubSubClient *mqtt, char *base_topic); + bool begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic); void handleMqttMessage(char *topic, char *payload); void publishDigitalInputs(); void publishDigitalInput(uint8_t pin); @@ -19,9 +19,6 @@ class DigitalInputIoT : public IoTComponent { void subscribe(); uint8_t getType(); private: - uint8_t card_id; - PubSubClient *mqtt; - char *base_topic; std::function change_callback; bool digital_inputs_publish_enabled = false; DigitalInputCard *card; diff --git a/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp b/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp index a7065e9..0b120fa 100644 --- a/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp +++ b/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp @@ -12,8 +12,6 @@ DigitalOutputIoT::~DigitalOutputIoT() { } bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) { - Serial.print("Initializing digital output IoT component for card "); - Serial.println(card_id); this->mqtt = mqtt; this->base_topic = base_topic; this->card = (DigitalOutputCard *) card; @@ -42,15 +40,10 @@ bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient // Publish all topic: requeststate payload: N/A // Enable/disable publish topic: publish_enable payload: 0/1 void DigitalOutputIoT::handleMqttMessage(char *topic, char *payload) { - Serial.print("Handling mqtt message for digital output IoT component for card "); - Serial.println(card_id); - Serial.print("Topic: "); - Serial.println(topic); uint8_t topic_length = strlen(topic); if(this-> processSetStateMessage(topic, payload, topic_length)) return; if(this-> processSetValueMessage(topic, payload, topic_length)) return; if(this-> processRequestStateMessage(topic, payload, topic_length)) return; - Serial.println("No handler found"); } bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_t topic_length) { @@ -61,22 +54,16 @@ bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_ if(topic[2] != '/') { return false; } - Serial.println("Set state first check passed"); // The topic must be set_state_length + 2 characters long if(topic_length != set_state_length + 2) { return false; } - Serial.println("Set state second check passed"); // Check if the topic ends with /set/state if (!strncmp(topic+2, SET_STATE_TOPIC, set_state_length)) { - Serial.println("Set state third check passed"); // Get the pin number uint8_t pin = (topic[0] - '0')*10 + (topic[1] - '0'); - Serial.print("Pin: "); - Serial.println(pin); // Get the state bool state = false; - Serial.println(payload); char state_char = payload[0]; if (state_char == '0') { state = false; @@ -85,8 +72,6 @@ bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_ } else { return false; } - Serial.print("State: "); - Serial.println(state); // Set the state card->setState(pin, state); return true; @@ -99,19 +84,15 @@ bool DigitalOutputIoT::processSetValueMessage(char *topic, char *payload, uint8_ // The correct format is /set/value // This mean that the topic must end with /set/value // Check if the 3rd character is / - Serial.println("Set value first check"); if(topic[2] != '/') { return false; } - Serial.println("Set value first check passed"); // The topic must be set_value_length + 2 characters long if(topic_length != set_value_length + 2) { return false; } - Serial.println("Set value second check passed"); // Check if the topic ends with /set/value if (!strncmp(topic+2, SET_VALUE_TOPIC, set_value_length)) { - Serial.println("Set value third check passed"); // Get the pin number uint8_t pin = (topic[0] - '0')*10 + (topic[1] - '0'); // Get the value @@ -128,18 +109,11 @@ bool DigitalOutputIoT::processRequestStateMessage(char *topic, char *payload, ui // The correct format is requeststate // This mean that the topic must be request_state_length characters long // The topic must be request_state_length characters long - Serial.println("Request state first check"); - Serial.print("Topic length: "); - Serial.println(topic_length); - Serial.print("Request state length: "); - Serial.println(request_state_length); if(topic_length != request_state_length) { return false; } - Serial.println("Request state first check passed"); // Check if the topic is requeststate if (!strncmp(topic, REQUEST_STATE_TOPIC, request_state_length)) { - Serial.println("Request state second check passed"); // Publish the state of all pins publishDigitalOutputs(); return true; @@ -149,7 +123,6 @@ bool DigitalOutputIoT::processRequestStateMessage(char *topic, char *payload, ui void DigitalOutputIoT::publishDigitalOutputs() { if(!digital_outputs_publish_enabled) return; - Serial.println("Publishing digital outputs"); for(int i = 0; i < 16; i++) { publishDigitalOutput(i); } @@ -204,27 +177,21 @@ uint8_t DigitalOutputIoT::getType() { } void DigitalOutputIoT::subscribe() { - Serial.println("Subscribing to digital output topics"); char topic[20]; - Serial.println("Subscribe to all set state topics"); // Subscribe to all set state topics for(int i = 0; i < 16; i++) { sprintf(topic, "%02d/set/state", i); subscribeRelative(topic); } - Serial.println("Subscribe to all set value topics"); // Subscribe to all set value topics for(int i = 0; i < 16; i++) { sprintf(topic, "%02d/set/value", i); subscribeRelative(topic); } - Serial.println("Subscribe to request state topic"); // Subscribe to request state topic subscribeRelative(REQUEST_STATE_TOPIC); - Serial.println("Subscribe to publish enable topic"); // Subscribe to publish enable topic subscribeRelative(PUBLISH_ENABLE_TOPIC); - Serial.println("Subscriptions complete"); } void DigitalOutputIoT::loop() { diff --git a/Template Project/lib/ESPMegaPRO/ESPMegaIoT.cpp b/Template Project/lib/ESPMegaPRO/ESPMegaIoT.cpp index 7bf11ea..6fa7507 100644 --- a/Template Project/lib/ESPMegaPRO/ESPMegaIoT.cpp +++ b/Template Project/lib/ESPMegaPRO/ESPMegaIoT.cpp @@ -1,5 +1,5 @@ #include - +#include #define NETWORK_CONFIG_ADDRESS 34 #define MQTT_CONFIG_ADDRESS 34 + sizeof(NetworkConfig) @@ -15,6 +15,12 @@ ESPMegaIoT::ESPMegaIoT() : mqtt(tcpClient) mqtt_connected = false; } +ESPMegaIoT::~ESPMegaIoT() +{ + // Delete the mqtt server + delete[] mqtt_server; +} + void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length) { // Create a null terminated string from the payload @@ -34,11 +40,7 @@ void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length) // Note that after the base topic, there should be the card id // /base_topic/card_id/... // First, get the card id in integer form - Serial.print("Topic: "); - Serial.println(topic_without_base); char *card_id_str = strtok(topic_without_base, "/"); - Serial.print("Card ID: "); - Serial.println(card_id_str); uint8_t card_id = atoi(card_id_str); // Check if the card is registered if (components[card_id] == NULL) @@ -95,6 +97,11 @@ void ESPMegaIoT::registerCard(uint8_t card_id) case CARD_TYPE_DIGITAL_INPUT: components[card_id] = new DigitalInputIoT(); components[card_id]->begin(card_id, cards[card_id], &mqtt, base_topic); + if (mqtt_connected) + { + components[card_id]->subscribe(); + components[card_id]->publishReport(); + } break; case CARD_TYPE_DIGITAL_OUTPUT: components[card_id] = new DigitalOutputIoT(); @@ -106,10 +113,9 @@ void ESPMegaIoT::registerCard(uint8_t card_id) } break; default: - Serial.println("Invalid card type"); + Serial.println("Unsupported card type"); return; } - Serial.println("Card registered"); } void ESPMegaIoT::deregisterCard(uint8_t card_id) { @@ -158,13 +164,6 @@ bool ESPMegaIoT::wifiConnected() } bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port, char *mqtt_user, char *mqtt_password) { - // Store mqtt connection parameters - this->mqtt_server = mqtt_server; - this->mqtt_port = mqtt_port; - this->mqtt_user = mqtt_user; - this->mqtt_password = mqtt_password; - this->mqtt_useauth = true; - this->client_id = client_id; mqtt.setServer(mqtt_server, mqtt_port); auto boundCallback = std::bind(&ESPMegaIoT::mqttCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); mqtt.setCallback(boundCallback); @@ -188,26 +187,13 @@ bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt } bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port) { - // Store mqtt connection parameters - Serial.println("Storing mqtt connection parameters"); - this->mqtt_server = mqtt_server; - this->mqtt_port = mqtt_port; - this->mqtt_useauth = false; - this->client_id = client_id; - Serial.println("Setting mqtt server"); mqtt.setServer(mqtt_server, mqtt_port); - Serial.println("Setting mqtt callback"); auto boundCallback = std::bind(&ESPMegaIoT::mqttCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); mqtt.setCallback(boundCallback); - Serial.println("Connecting to mqtt"); if (mqtt.connect(client_id)) { - Serial.println("Connected to mqtt"); - Serial.println("Calling session keep alive"); sessionKeepAlive(); - Serial.println("Subscribing to topics"); mqttSubscribe(); - Serial.println("Publishing all cards"); // Publish all cards for (int i = 0; i < 255; i++) { @@ -237,7 +223,6 @@ void ESPMegaIoT::registerMqttCallback(void (*callback)(char *, char *)) } void ESPMegaIoT::mqttSubscribe() { - Serial.println("MQTT Subscribe Activated"); if (user_subscribe_callback != NULL) { user_subscribe_callback(); @@ -313,7 +298,7 @@ void ESPMegaIoT::registerSubscribeCallback(void (*callback)(void)) void ESPMegaIoT::setNetworkConfig(NetworkConfig network_config) { this->network_config = network_config; - this->connectNetwork(); + client_id = network_config.hostname; } void ESPMegaIoT::loadNetworkConfig() @@ -330,8 +315,7 @@ void ESPMegaIoT::saveNetworkConfig() void ESPMegaIoT::ethernetBegin() { - ETH.begin(); - ETH.setHostname(network_config.hostname); + ethernetIface->setHostname(network_config.hostname); } void ESPMegaIoT::loadMqttConfig() @@ -388,15 +372,38 @@ void ESPMegaIoT::connectNetwork() { this->ethernetBegin(); if (network_config.useStaticIp) - ETH.config(network_config.ip, network_config.gateway, network_config.subnet, network_config.dns1, network_config.dns2); + ethernetIface->config(network_config.ip, network_config.gateway, network_config.subnet, network_config.dns1, network_config.dns2); } } void ESPMegaIoT::setMqttConfig(MqttConfig mqtt_config) { + if (mqtt_server != nullptr) { + delete[] mqtt_server; + } + this->mqtt_server = new char[32]; strcpy(mqtt_server, mqtt_config.mqtt_server); mqtt_port = mqtt_config.mqtt_port; + if (mqtt_user != nullptr) { + delete[] mqtt_user; + } + this->mqtt_user = new char[32]; strcpy(mqtt_user, mqtt_config.mqtt_user); + if (mqtt_password != nullptr) { + delete[] mqtt_password; + } + this->mqtt_password = new char[32]; strcpy(mqtt_password, mqtt_config.mqtt_password); mqtt_useauth = mqtt_config.mqtt_useauth; + strcpy(base_topic, mqtt_config.base_topic); +} + +void ESPMegaIoT::bindEthernetInterface(ETHClass *ethernetIface) +{ + this->ethernetIface = ethernetIface; +} + +IoTComponent* ESPMegaIoT::getComponent(uint8_t card_id) +{ + return components[card_id]; } \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/ESPMegaIoT.hpp b/Template Project/lib/ESPMegaPRO/ESPMegaIoT.hpp index f64190a..7fb6dbc 100644 --- a/Template Project/lib/ESPMegaPRO/ESPMegaIoT.hpp +++ b/Template Project/lib/ESPMegaPRO/ESPMegaIoT.hpp @@ -33,12 +33,14 @@ struct MqttConfig char mqtt_user[32]; char mqtt_password[32]; bool mqtt_useauth; + char base_topic[32]; }; class ESPMegaIoT { public: ESPMegaIoT(); + ~ESPMegaIoT(); void intr_begin(ExpansionCard *cards[]); void loop(); void registerCard(uint8_t card_id); @@ -71,6 +73,8 @@ public: void registerRelativeMqttCallback(void (*callback)(char *, char *)); void registerSubscribeCallback(void (*callback)(void)); void setBaseTopic(char *base_topic); + void bindEthernetInterface(ETHClass *ethernetIface); + IoTComponent* getComponent(uint8_t card_id); IPAddress getETHIp(); private: @@ -105,4 +109,5 @@ private: bool mqtt_useauth; bool mqtt_connected; NetworkConfig network_config; + ETHClass *ethernetIface; }; \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/IoTComponent.cpp b/Template Project/lib/ESPMegaPRO/IoTComponent.cpp index 59d19f9..38479e7 100644 --- a/Template Project/lib/ESPMegaPRO/IoTComponent.cpp +++ b/Template Project/lib/ESPMegaPRO/IoTComponent.cpp @@ -1,12 +1,5 @@ #include -bool IoTComponent::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) { - this->card_id = card_id; - this->mqtt = mqtt; - this->base_topic = base_topic; - return true; -} - void IoTComponent::setMqttClient(PubSubClient *mqtt) { this->mqtt = mqtt; } @@ -18,7 +11,6 @@ void IoTComponent::publishRelative(const char *topic, const char *payload) { } void IoTComponent::subscribeRelative(const char *topic) { - Serial.println("Subscribe relative"); char absolute_topic[50]; sprintf(absolute_topic, "%s/%02d/%s", base_topic, card_id, topic); mqtt->subscribe(absolute_topic); diff --git a/Template Project/lib/ESPMegaPRO/IoTComponent.hpp b/Template Project/lib/ESPMegaPRO/IoTComponent.hpp index 5d81647..947bc79 100644 --- a/Template Project/lib/ESPMegaPRO/IoTComponent.hpp +++ b/Template Project/lib/ESPMegaPRO/IoTComponent.hpp @@ -3,7 +3,7 @@ #include class IoTComponent { public: - bool begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic); + virtual bool begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic); virtual void handleMqttMessage(char *topic, char *payload); void setMqttClient(PubSubClient *mqtt); virtual void publishReport(); diff --git a/Template Project/src/iot_framdemo.cpp b/Template Project/src/iot_framdemo.cpp index f0ff3d6..74e334e 100644 --- a/Template Project/src/iot_framdemo.cpp +++ b/Template Project/src/iot_framdemo.cpp @@ -1,10 +1,20 @@ #include +#include ESPMegaPRO espmega = ESPMegaPRO(); +void input_change_callback(uint8_t pin, uint8_t value) { + Serial.print("Input change callback: "); + Serial.print(pin); + Serial.print(" "); + Serial.println(value); +} + void setup() { espmega.begin(); espmega.enableIotModule(); + ETH.begin(); + espmega.iot.bindEthernetInterface(Ð); NetworkConfig config = { .ip = {192, 168, 0, 11}, .gateway = {192, 168, 0, 1}, @@ -18,17 +28,28 @@ void setup() { strcpy(config.ssid, "ssid"); strcpy(config.password, "password"); strcpy(config.hostname, "espmega"); + Serial.println("Setting network config"); espmega.iot.setNetworkConfig(config); + Serial.println("Connecting to network"); espmega.iot.connectNetwork(); + Serial.println("Begin MQTT Modules"); MqttConfig mqtt_config = { .mqtt_port = 1883, .mqtt_useauth = false }; + Serial.println("Setting MQTT Server"); strcpy(mqtt_config.mqtt_server, "192.168.0.26"); + strcpy(mqtt_config.base_topic, "/espmegaoop"); + Serial.println("Loading MQTT Config Struct to IoT Module"); espmega.iot.setMqttConfig(mqtt_config); + Serial.println("Connecting to MQTT"); espmega.iot.connectToMqtt(); + Serial.println("Registering cards"); espmega.iot.registerCard(0); espmega.iot.registerCard(1); + Serial.println("Initialization Routine Complete"); + ((DigitalInputIoT*)espmega.iot.getComponent(0)) -> registerChangeCallback(input_change_callback); + } void loop() {