complete iot structure

This commit is contained in:
Siwat Sirichai 2023-12-28 14:52:52 +07:00
parent da277e1e4a
commit 0dfb066a74
10 changed files with 259 additions and 74 deletions

View File

@ -11,6 +11,7 @@ class AnalogIoT : public IoTComponent {
void setADCsPublishInterval(uint32_t interval); void setADCsPublishInterval(uint32_t interval);
void setADCsPublishEnabled(bool enabled); void setADCsPublishEnabled(bool enabled);
void publishReport(); void publishReport();
void subscribe();
uint8_t getType(); uint8_t getType();
private: private:
char *adc_topic; char *adc_topic;

View File

@ -168,4 +168,26 @@ void DigitalOutputIoT::publishReport() {
uint8_t DigitalOutputIoT::getType() { uint8_t DigitalOutputIoT::getType() {
return CARD_TYPE_DIGITAL_OUTPUT; return CARD_TYPE_DIGITAL_OUTPUT;
}
void DigitalOutputIoT::subscribe() {
// Subscribe to all set state topics
for(int i = 1; i <= 16; i++) {
char topic[10];
sprintf(topic, "%02d/set/state", i);
subscribeRelative(topic);
}
// Subscribe to all set value topics
for(int i = 1; i <= 16; i++) {
char topic[10];
sprintf(topic, "%02d/set/value", i);
subscribeRelative(topic);
}
// Subscribe to request state topic
subscribeRelative(REQUEST_STATE_TOPIC);
// Subscribe to publish enable topic
subscribeRelative(PUBLISH_ENABLE_TOPIC);
}
void DigitalOutputIoT::loop() {
} }

View File

@ -18,6 +18,8 @@ class DigitalOutputIoT : public IoTComponent {
void registerValueChangeCallback(void (*callback)(uint8_t, bool, uint16_t)); void registerValueChangeCallback(void (*callback)(uint8_t, bool, uint16_t));
void deregisterValueChangeCallback(); void deregisterValueChangeCallback();
void publishReport(); void publishReport();
void subscribe();
void loop();
uint8_t getType(); uint8_t getType();
private: private:
bool digital_outputs_publish_enabled = false; bool digital_outputs_publish_enabled = false;

View File

@ -1,5 +1,14 @@
#include <ESPMegaIoT.hpp> #include <ESPMegaIoT.hpp>
ESPMegaIoT::ESPMegaIoT() {
// Initialize the components array
for (int i = 0; i < 255; i++) {
components[i] = NULL;
}
active = false;
mqtt_connected = false;
}
void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length) { void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length) {
// Create a null terminated string from the payload // Create a null terminated string from the payload
memcpy(payload_buffer, payload, length); memcpy(payload_buffer, payload, length);
@ -17,6 +26,12 @@ void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length) {
return; return;
} }
components[card_id]->handleMqttMessage(topic_without_base + 3, payload_buffer); components[card_id]->handleMqttMessage(topic_without_base + 3, payload_buffer);
if (user_relative_mqtt_callback != NULL) {
user_relative_mqtt_callback(topic_without_base + 3, payload_buffer);
}
if (user_mqtt_callback != NULL) {
user_mqtt_callback(topic, payload_buffer);
}
} }
void ESPMegaIoT::setBaseTopic(char *base_topic) { void ESPMegaIoT::setBaseTopic(char *base_topic) {
@ -24,10 +39,23 @@ void ESPMegaIoT::setBaseTopic(char *base_topic) {
base_topic_length = strlen(base_topic); base_topic_length = strlen(base_topic);
} }
void ESPMegaIoT::begin(ExpansionCard *cards[]) { void ESPMegaIoT::intr_begin(ExpansionCard *cards[]) {
this->cards = cards; this->cards = cards;
ETH.begin();
active = true;
}
void ESPMegaIoT::loop() {
if(!active)
return;
// Call each component's loop function
for (int i = 0; i < 255; i++) {
if (components[i] != NULL) {
components[i]->loop();
}
}
mqtt.loop();
sessionKeepAlive();
} }
void ESPMegaIoT::loop();
// Register Existing Card for use with IoT // Register Existing Card for use with IoT
void ESPMegaIoT::registerCard(uint8_t card_id) { void ESPMegaIoT::registerCard(uint8_t card_id) {
@ -54,11 +82,6 @@ void ESPMegaIoT::registerCard(uint8_t card_id) {
default: default:
return; return;
} }
// Initialize the IoT component
// Enable publishing for the card
card_publish_enabled[card_id] = true;
} }
void ESPMegaIoT::deregisterCard(uint8_t card_id) { void ESPMegaIoT::deregisterCard(uint8_t card_id) {
// Check if the card is registered // Check if the card is registered
@ -68,8 +91,6 @@ void ESPMegaIoT::deregisterCard(uint8_t card_id) {
// Delete the IoT component // Delete the IoT component
delete components[card_id]; delete components[card_id];
components[card_id] = NULL; components[card_id] = NULL;
// Disable publishing for the card
card_publish_enabled[card_id] = false;
} }
void ESPMegaIoT::publishCard(uint8_t card_id) { void ESPMegaIoT::publishCard(uint8_t card_id) {
// Check if the card is registered // Check if the card is registered
@ -103,13 +124,114 @@ void ESPMegaIoT::disconnectFromWifi() {
bool ESPMegaIoT::wifiConnected() { bool ESPMegaIoT::wifiConnected() {
return WiFi.status() == WL_CONNECTED; return WiFi.status() == WL_CONNECTED;
} }
void ESPMegaIoT::connectToMqtt(char*client_id, char *mqtt_server, uint16_t mqtt_port, char *mqtt_user, char *mqtt_password) { 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); mqtt.setServer(mqtt_server, mqtt_port);
mqtt.setCallback(mqttCallback); auto boundCallback = std::bind(&ESPMegaIoT::mqttCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
mqtt.connect(client_id, mqtt_user, mqtt_password); mqtt.setCallback(boundCallback);
sessionKeepAlive(); if (mqtt.connect(client_id, mqtt_user, mqtt_password)) {
sessionKeepAlive();
mqttSubscribe();
mqtt_connected = true;
return true;
}
mqtt_connected = false;
return false;
} }
void ESPMegaIoT::connectToMqtt(char* client_id, char *mqtt_server, uint16_t mqtt_port); bool ESPMegaIoT::connectToMqtt(char* client_id, char *mqtt_server, uint16_t mqtt_port) {
void ESPMegaIoT::disconnectFromMqtt(); // Store mqtt connection parameters
void ESPMegaIoT::publishToTopic(char *topic, char *payload); this->mqtt_server = mqtt_server;
void ESPMegaIoT::registerMqttCallback(void (*callback)(char *, char *)); this->mqtt_port = mqtt_port;
this->mqtt_useauth = false;
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);
if(mqtt.connect(client_id)) {
sessionKeepAlive();
mqttSubscribe();
mqtt_connected = true;
return true;
}
mqtt_connected = false;
return false;
}
void ESPMegaIoT::disconnectFromMqtt() {
mqtt.disconnect();
}
void ESPMegaIoT::publishToTopic(char *topic, char *payload) {
mqtt.publish(topic, payload);
}
void ESPMegaIoT::registerMqttCallback(void (*callback)(char *, char *)) {
}
void ESPMegaIoT::mqttSubscribe() {
// Subscribe to all topics
for (int i = 0; i < 255; i++) {
if (components[i] != NULL) {
components[i]->subscribe();
}
}
}
void ESPMegaIoT::publishRelative(uint8_t card_id, char *topic, char *payload) {
char absolute_topic[100];
sprintf(absolute_topic, "%s/%d/%s", base_topic, card_id, topic);
mqtt.publish(absolute_topic, payload);
}
void ESPMegaIoT::setETHStaticIp(IPAddress ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) {
ETH.config(ip, gateway, subnet, dns1, dns2);
}
void ESPMegaIoT::setETHStaticIp(IPAddress ip, IPAddress gateway, IPAddress subnet, IPAddress dns1) {
ETH.config(ip, gateway, subnet, dns1);
}
void ESPMegaIoT::setETHStaticIp(IPAddress ip, IPAddress gateway, IPAddress subnet) {
ETH.config(ip, gateway, subnet);
}
IPAddress ESPMegaIoT::getETHIp() {
return ETH.localIP();
}
bool ESPMegaIoT::mqttReconnect() {
if (mqtt_useauth) {
return this->connectToMqtt(client_id, mqtt_server, mqtt_port, mqtt_user, mqtt_password);
} else {
return this->connectToMqtt(client_id, mqtt_server, mqtt_port);
}
}
void ESPMegaIoT::sessionKeepAlive() {
static unsigned long lastSessionKeepAlive = 0;
if (millis() - lastSessionKeepAlive > 30000) {
lastSessionKeepAlive = millis();
// Check if mqtt is connected
if (!mqtt.connected()) {
// Try to reconnect
mqtt_connected = mqttReconnect();
}
}
}
void ESPMegaIoT::registerRelativeMqttCallback(void (*callback)(char *, char *)) {
user_relative_mqtt_callback = callback;
}
void ESPMegaIoT::publishRelative(char *topic, char *payload) {
char absolute_topic[100];
sprintf(absolute_topic, "%s/%s", base_topic, topic);
mqtt.publish(absolute_topic, payload);
}
void ESPMegaIoT::subscribeRelative(char *topic) {
char absolute_topic[100];
sprintf(absolute_topic, "%s/%s", base_topic, topic);
mqtt.subscribe(absolute_topic);
}

View File

@ -11,37 +11,58 @@
class ESPMegaIoT class ESPMegaIoT
{ {
public: public:
void begin(ExpansionCard *cards[]); void intr_begin(ExpansionCard *cards[]);
void loop(); void loop();
void registerCard(uint8_t card_id); void registerCard(uint8_t card_id);
void deregisterCard(uint8_t card_id); void deregisterCard(uint8_t card_id);
void publishCard(uint8_t card_id); void publishCard(uint8_t card_id);
void subscribeToTopic(char *topic); // Publish topic appended with base topic
void unsubscribeFromTopic(char *topic); void publishRelative(char *topic, char *payload);
void connectToEthernet(); // Subscribe topic appended with base topic
bool ethernetConnected(); void subscribeRelative(char *topic);
void connectToWifi(char *ssid, char *password); void subscribeToTopic(char *topic);
void connectToWifi(char *ssid); void unsubscribeFromTopic(char *topic);
void disconnectFromWifi(); void connectToEthernet();
bool wifiConnected(); bool ethernetConnected();
void connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port, char *mqtt_user, char *mqtt_password); void connectToWifi(char *ssid, char *password);
void connectToMqtt(char* client_id, char *mqtt_server, uint16_t mqtt_port); void connectToWifi(char *ssid);
void disconnectFromMqtt(); void disconnectFromWifi();
void publishToTopic(char *topic, char *payload); bool wifiConnected();
void registerMqttCallback(void (*callback)(char *, char *)); bool connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port, char *mqtt_user, char *mqtt_password);
void setBaseTopic(char *base_topic); bool connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port);
private: void disconnectFromMqtt();
void sessionKeepAlive(); void publishToTopic(char *topic, char *payload);
void mqttReconnect(); void registerMqttCallback(void (*callback)(char *, char *));
void wifiReconnect(); void registerRelativeMqttCallback(void (*callback)(char *, char *));
void mqttCallback(char *topic, byte *payload, unsigned int length); void setBaseTopic(char *base_topic);
void publishRelative(uint8_t card_id, char *topic, char *payload); void setETHStaticIp(IPAddress ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2);
PubSubClient mqtt; void setETHStaticIp(IPAddress ip, IPAddress gateway, IPAddress subnet, IPAddress dns1);
IoTComponent *components[255]; void setETHStaticIp(IPAddress ip, IPAddress gateway, IPAddress subnet);
bool card_publish_enabled[255]; IPAddress getETHIp();
char payload_buffer[200];
char base_topic[100]; private:
uint8_t base_topic_length; void sessionKeepAlive();
ExpansionCard **cards; // Points to card array in ESPMegaPRO Core bool mqttReconnect();
void wifiReconnect();
void mqttSubscribe();
void mqttCallback(char *topic, byte *payload, unsigned int length);
void (*user_mqtt_callback)(char *, char *);
void (*user_relative_mqtt_callback)(char *, char *);
void publishRelative(uint8_t card_id, char *topic, char *payload);
bool active;
PubSubClient mqtt;
IoTComponent *components[255];
char payload_buffer[200];
char base_topic[100];
uint8_t base_topic_length;
ExpansionCard **cards; // Points to card array in ESPMegaPRO Core
// MQTT Connection Parameters
char *mqtt_server;
uint16_t mqtt_port;
char *mqtt_user;
char *mqtt_password;
char *client_id;
bool mqtt_useauth;
bool mqtt_connected;
}; };

View File

@ -27,7 +27,8 @@ void ESPMegaPRO::loop() {
if (cardInstalled[i]) { if (cardInstalled[i]) {
cards[i]->loop(); cards[i]->loop();
} }
} }
iot.loop();
} }
bool ESPMegaPRO::installCard(uint8_t slot, ExpansionCard* card) { bool ESPMegaPRO::installCard(uint8_t slot, ExpansionCard* card) {
if (slot > 255) return false; if (slot > 255) return false;
@ -88,3 +89,6 @@ void ESPMegaPRO::setTime(int hours, int minutes, int seconds, int day, int month
RTC.write(timeElement); RTC.write(timeElement);
} }
void ESPMegaPRO::enableIotModule() {
iot.intr_begin(cards);
}

View File

@ -32,6 +32,7 @@ class ESPMegaPRO {
void loop(); void loop();
bool installCard(uint8_t slot, ExpansionCard* card); bool installCard(uint8_t slot, ExpansionCard* card);
bool updateTimeFromNTP(); bool updateTimeFromNTP();
void enableIotModule();
rtctime_t getTime(); rtctime_t getTime();
void setTime(int hours, int minutes, int seconds, int day, int month, int year); void setTime(int hours, int minutes, int seconds, int day, int month, int year);
FRAM fram; FRAM fram;

View File

@ -8,4 +8,14 @@ void IoTComponent::publishRelative(char *topic, char *payload) {
char absolute_topic[100]; char absolute_topic[100];
sprintf(absolute_topic, "%s/%d/%s", base_topic, card_id, topic); sprintf(absolute_topic, "%s/%d/%s", base_topic, card_id, topic);
mqtt->publish(absolute_topic, payload); mqtt->publish(absolute_topic, payload);
}
void IoTComponent::subscribeRelative(char *topic) {
char absolute_topic[100];
sprintf(absolute_topic, "%s/%d/%s", base_topic, card_id, topic);
mqtt->subscribe(absolute_topic);
}
void IoTComponent::loop() {
// Placeholder, Do nothing
} }

View File

@ -8,9 +8,12 @@ class IoTComponent {
void setMqttClient(PubSubClient *mqtt); void setMqttClient(PubSubClient *mqtt);
virtual void publishReport(); virtual void publishReport();
virtual uint8_t getType(); virtual uint8_t getType();
virtual void subscribe();
void loop();
protected: protected:
char *base_topic; char *base_topic;
void publishRelative(char *topic, char *payload); void publishRelative(char *topic, char *payload);
void subscribeRelative(char *topic);
PubSubClient *mqtt; PubSubClient *mqtt;
uint8_t card_id; uint8_t card_id;
}; };

View File

@ -3,36 +3,35 @@
// Instantiate ESPMega // Instantiate ESPMega
ESPMegaPRO espmega = ESPMegaPRO(); ESPMegaPRO espmega = ESPMegaPRO();
void mqtt_callback(char *topic, char *payload)
{
Serial.print("MQTT Callback: ");
Serial.print(topic);
Serial.print(" ");
Serial.println(payload);
}
void setup() void setup()
{ {
// Initialize ESPMega // Initialize ESPMega
espmega.begin(); espmega.begin();
Serial.println("ESPMega initialized"); Serial.println("ESPMega initialized");
espmega.enableIotModule();
espmega.iot.connectToEthernet();
IPAddress ip(192, 168, 0, 11);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
espmega.iot.setETHStaticIp(ip, gateway, subnet);
espmega.iot.setBaseTopic("/testmegaoop");
espmega.iot.connectToMqtt("espmega", "192.168.0.26", 1883);
espmega.iot.publishRelative("test", "test");
espmega.iot.subscribeRelative("test");
espmega.iot.registerMqttCallback(mqtt_callback);
Serial.println("ESPMega IoT initialized");
} }
void loop() void loop()
{ {
// Read all the inputs and print them // Call ESPMega loop
for (int i = 0; i < 16; i++) espmega.loop();
{
Serial.print("Input ");
Serial.print(i);
Serial.print(": ");
Serial.print(espmega.inputs.digitalRead(i));
Serial.println();
}
// Turn on all the outputs
for (int i = 0; i < 16; i++)
{
espmega.outputs.digitalWrite(i, true);
}
// Wait 1 second
delay(1000);
// Turn off all the outputs
for (int i = 0; i < 16; i++)
{
espmega.outputs.digitalWrite(i, false);
}
// Wait 1 second
delay(1000);
} }