IoT Comment

This commit is contained in:
Siwat Sirichai 2024-01-01 11:14:33 +07:00
parent 9a0f02fcd9
commit d75d098247
2 changed files with 287 additions and 20 deletions

View File

@ -1,6 +1,11 @@
#include <ESPMegaIoT.hpp>
#include <ETH.h>
/**
* @brief Create a new ESPMegaIoT object
*
* @note You shold not create this object directly, Instead, you should use the ESPMegaPRO::iot object
*/
ESPMegaIoT::ESPMegaIoT() : mqtt(tcpClient)
{
tcpClient.setTimeout(TCP_TIMEOUT_SEC);
@ -13,10 +18,24 @@ ESPMegaIoT::ESPMegaIoT() : mqtt(tcpClient)
mqtt_connected = false;
}
/**
* @brief Destroy the ESPMegaIoT object
*/
ESPMegaIoT::~ESPMegaIoT()
{
}
/**
* @brief The mqtt callback function, This function is called when a message is received on a subscribed topic
*
* This function is called when a message is received on a subscribed topic
* The payload is copied to a buffer and a null terminator is added
* The payload is then passed to the respective card's mqtt callback
*
* @param topic The topic of the message
* @param payload The payload of the message in byte form
* @param length The length of the payload
*/
void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length)
{
// Create a null terminated string from the payload
@ -46,17 +65,33 @@ void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length)
components[card_id]->handleMqttMessage(topic_without_base + 3, payload_buffer);
}
/**
* @brief Set the base topic for the IoT
*
* @param base_topic The base topic
*/
void ESPMegaIoT::setBaseTopic(char *base_topic)
{
strcpy(this->mqtt_config.base_topic, base_topic);
base_topic_length = strlen(this->mqtt_config.base_topic);
}
/**
* @brief Begin the ESPMegaIoT object
*
* @param cards The array of ExpansionCard objects
*/
void ESPMegaIoT::intr_begin(ExpansionCard *cards[])
{
this->cards = cards;
active = true;
}
/**
* @brief The main loop for the ESPMegaIoT object
*
* @note Normally you should not call this function, Instead, you should call ESPMegaPRO::loop()
*/
void ESPMegaIoT::loop()
{
if (!active)
@ -73,7 +108,14 @@ void ESPMegaIoT::loop()
sessionKeepAlive();
}
// Register Existing Card for use with IoT
/**
* @brief Register an existing card for use with IoT
*
* This function registers an existing card for use with IoT
* The card should be installed using ESPMegaPRO::installCard() before calling this function
*
* @param card_id The id of the card
*/
void ESPMegaIoT::registerCard(uint8_t card_id)
{
// Check if the card is already registered
@ -127,6 +169,12 @@ void ESPMegaIoT::registerCard(uint8_t card_id)
return;
}
}
/**
* @brief Unregister a card
*
* @param card_id The id of the card
*/
void ESPMegaIoT::unregisterCard(uint8_t card_id)
{
// Check if the card is registered
@ -138,6 +186,10 @@ void ESPMegaIoT::unregisterCard(uint8_t card_id)
delete components[card_id];
components[card_id] = NULL;
}
/**
* @brief Publish all cards's reports
*/
void ESPMegaIoT::publishCard(uint8_t card_id)
{
// Check if the card is registered
@ -148,30 +200,76 @@ void ESPMegaIoT::publishCard(uint8_t card_id)
// Publish the card
components[card_id]->publishReport();
}
void ESPMegaIoT::subscribeToTopic(char *topic)
/**
* @brief Subscribe to a topic
*
* @param topic The topic to subscribe to
*/
void ESPMegaIoT::subscribe(char *topic)
{
mqtt.subscribe(topic);
}
/**
* @brief Unsubscribe from a topic
*
* @param topic The topic to unsubscribe from
*/
void ESPMegaIoT::unsubscribeFromTopic(char *topic)
{
mqtt.unsubscribe(topic);
}
/**
* @brief Connect to a wifi network
*
* @param ssid The SSID of the wifi network
* @param password The password of the wifi network
*/
void ESPMegaIoT::connectToWifi(char *ssid, char *password)
{
WiFi.begin(ssid, password);
}
/**
* @brief Connect to a unsecured wifi network
*
* @param ssid The SSID of the wifi network
*/
void ESPMegaIoT::connectToWifi(char *ssid)
{
WiFi.begin(ssid);
}
/**
* @brief Disconnect from the wifi network
*/
void ESPMegaIoT::disconnectFromWifi()
{
WiFi.disconnect();
}
/**
* @brief Check if the wifi is connected
*
* @return True if the wifi is connected, false otherwise
*/
bool ESPMegaIoT::wifiConnected()
{
return WiFi.status() == WL_CONNECTED;
}
/**
* @brief Connect to a MQTT broker with authentication
*
* @param client_id The client id to use
* @param mqtt_server The MQTT server to connect to
* @param mqtt_port The MQTT port to connect to
* @param mqtt_user The MQTT username to use
* @param mqtt_password The MQTT password to use
* @return True if the connection is successful, false otherwise
*/
bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port, char *mqtt_user, char *mqtt_password)
{
mqtt.setServer(mqtt_server, mqtt_port);
@ -201,6 +299,15 @@ bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt
mqtt_connected = false;
return false;
}
/**
* @brief Connect to a MQTT broker without authentication
*
* @param client_id The client id to use
* @param mqtt_server The MQTT server to connect to
* @param mqtt_port The MQTT port to connect to
* @return True if the connection is successful, false otherwise
*/
bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt_port)
{
ESP_LOGD("ESPMegaIoT", "Setting MQTT server to %s:%d", mqtt_server, mqtt_port);
@ -231,26 +338,51 @@ bool ESPMegaIoT::connectToMqtt(char *client_id, char *mqtt_server, uint16_t mqtt
mqtt_connected = false;
return false;
}
/**
* @brief Disconnect from the MQTT broker
*/
void ESPMegaIoT::disconnectFromMqtt()
{
mqtt.disconnect();
}
/**
* @brief Publish a message to a topic
*
* @param topic The topic to publish to
* @param payload The payload to publish
*/
void ESPMegaIoT::publish(const char *topic, const char *payload)
{
mqtt.publish(topic, payload);
}
/**
* @brief Register a callback for MQTT messages
*
* @param callback The callback function
* @return The handler for the callback
*/
uint8_t ESPMegaIoT::registerMqttCallback(std::function<void(char *, char *)> callback)
{
mqtt_callbacks[mqtt_callbacks_handler_index] = callback;
return mqtt_callbacks_handler_index++;
}
/**
* @brief Unregister a callback
*
* @param handler The handler of the callback
*/
void ESPMegaIoT::unregisterMqttCallback(uint8_t handler)
{
mqtt_callbacks.erase(handler);
}
/**
* @brief Subscribe to all components's topics
*/
void ESPMegaIoT::mqttSubscribe()
{
ESP_LOGD("ESPMegaIoT", "Begin MQTT Subscription");
@ -271,6 +403,9 @@ void ESPMegaIoT::mqttSubscribe()
}
}
/**
* @brief Publish relative to the base topic
*/
void ESPMegaIoT::publishRelative(uint8_t card_id, char *topic, char *payload)
{
char absolute_topic[100];
@ -278,6 +413,9 @@ void ESPMegaIoT::publishRelative(uint8_t card_id, char *topic, char *payload)
mqtt.publish(absolute_topic, payload);
}
/**
* @brief Subscribe relative to the base topic
*/
bool ESPMegaIoT::mqttReconnect()
{
if (this->mqtt_config.mqtt_useauth)
@ -290,6 +428,10 @@ bool ESPMegaIoT::mqttReconnect()
}
}
/**
* @brief Keep the MQTT session alive
* @note This function is called automatically by the ESPMegaIoT object, You should not call this function directly
*/
void ESPMegaIoT::sessionKeepAlive()
{
// This reconnect the MQTT if it disconnect.
@ -316,17 +458,36 @@ void ESPMegaIoT::sessionKeepAlive()
}
}
/**
* @brief Register a callback for MQTT messages relative to the base topic
*
* The message's base topic will be removed before calling the callback
*
* @param callback The callback function
* @return The handler for the callback
*/
uint8_t ESPMegaIoT::registerRelativeMqttCallback(std::function<void(char *, char *)> callback)
{
mqtt_relative_callbacks[mqtt_relative_callbacks_handler_index] = callback;
return mqtt_relative_callbacks_handler_index++;
}
/**
* @brief Unregister a relative MQTT callback
*
* @param handler The handler of the callback
*/
void ESPMegaIoT::unregisterRelativeMqttCallback(uint8_t handler)
{
mqtt_relative_callbacks.erase(handler);
}
/**
* @brief Publish a message relative to the base topic
*
* @param topic The topic to publish to
* @param payload The payload to publish
*/
void ESPMegaIoT::publishRelative(char *topic, char *payload)
{
char absolute_topic[100];
@ -335,6 +496,11 @@ void ESPMegaIoT::publishRelative(char *topic, char *payload)
mqtt.loop();
}
/**
* @brief Subscribe to a topic relative to the base topic
*
* @param topic The topic to subscribe to
*/
void ESPMegaIoT::subscribeRelative(char *topic)
{
char absolute_topic[100];
@ -343,22 +509,41 @@ void ESPMegaIoT::subscribeRelative(char *topic)
mqtt.loop();
}
/**
* @brief Register a function to be called when the ESPMegaIoT object is subscribing to topics
*
* @param callback The callback function
* @return The handler for the callback
*/
uint8_t ESPMegaIoT::registerSubscribeCallback(std::function<void(void)> callback)
{
subscribe_callbacks[subscribe_callbacks_handler_index] = callback;
return subscribe_callbacks_handler_index++;
}
/**
* @brief Unregister a subscribe callback
*
* @param handler The handler of the callback
*/
void ESPMegaIoT::unregisterSubscribeCallback(uint8_t handler)
{
subscribe_callbacks.erase(handler);
}
/**
* @brief Set the network config
*
* @param network_config The network config struct
*/
void ESPMegaIoT::setNetworkConfig(NetworkConfig network_config)
{
this->network_config = network_config;
}
/**
* @brief Load the network config from FRAM
*/
void ESPMegaIoT::loadNetworkConfig()
{
// Load the network config from FRAM
@ -375,6 +560,9 @@ void ESPMegaIoT::loadNetworkConfig()
fram->read(IOT_FRAM_ADDRESS + 87, (uint8_t *)network_config.password, 32);
}
/**
* @brief Save the network config to FRAM
*/
void ESPMegaIoT::saveNetworkConfig()
{
// Save the network config to FRAM
@ -391,11 +579,17 @@ void ESPMegaIoT::saveNetworkConfig()
fram->write(IOT_FRAM_ADDRESS + 87, (uint8_t *)network_config.password, 32);
}
/**
* @brief Begin the ethernet interface
*/
void ESPMegaIoT::ethernetBegin()
{
ethernetIface->setHostname(network_config.hostname);
}
/**
* @brief Load the MQTT config from FRAM
*/
void ESPMegaIoT::loadMqttConfig()
{
// Load the mqtt config from FRAM
@ -409,6 +603,9 @@ void ESPMegaIoT::loadMqttConfig()
this->base_topic_length = strlen(mqtt_config.base_topic);
}
/**
* @brief Save the MQTT config to FRAM
*/
void ESPMegaIoT::saveMqttConfig()
{
fram->write16(IOT_FRAM_ADDRESS + 128, mqtt_config.mqtt_port);
@ -419,6 +616,9 @@ void ESPMegaIoT::saveMqttConfig()
fram->write(IOT_FRAM_ADDRESS + 227, (uint8_t *)mqtt_config.base_topic, 32);
}
/**
* @brief Connect to MQTT with the current config
*/
void ESPMegaIoT::connectToMqtt()
{
if (mqtt_config.mqtt_useauth)
@ -433,6 +633,9 @@ void ESPMegaIoT::connectToMqtt()
}
}
/**
* @brief Connect to the network using the current config
*/
void ESPMegaIoT::connectNetwork()
{
if (network_config.useWifi)
@ -454,38 +657,78 @@ void ESPMegaIoT::connectNetwork()
}
}
/**
* @brief Set the MQTT config
*
* @param mqtt_config The MQTT config struct
*/
void ESPMegaIoT::setMqttConfig(MqttConfig mqtt_config)
{
this->mqtt_config = mqtt_config;
this->base_topic_length = strlen(mqtt_config.base_topic);
}
/**
* @brief Bind an ethernet interface to the ESPMegaIoT object
*
* @param ethernetIface The ethernet interface to bind (ETH for ESPMegaPRO R3)
*/
void ESPMegaIoT::bindEthernetInterface(ETHClass *ethernetIface)
{
this->ethernetIface = ethernetIface;
}
/**
* @brief Get the IoTComponent object for a card
*
* @param card_id The id of the card
* @return The IoTComponent object for the card
*/
IoTComponent *ESPMegaIoT::getComponent(uint8_t card_id)
{
return components[card_id];
}
/**
* @brief Get the network config
*
* @warning You should not modify the returned struct directly
*
* @return The network config struct
*/
NetworkConfig *ESPMegaIoT::getNetworkConfig()
{
return &network_config;
}
/**
* @brief Get the MQTT config
*
* @warning You should not modify the returned struct directly
*
* @return The MQTT config struct
*/
MqttConfig *ESPMegaIoT::getMqttConfig()
{
return &mqtt_config;
}
/**
* @brief Check if the MQTT is connected
*
* @return True if the MQTT is connected, false otherwise
*/
bool ESPMegaIoT::mqttConnected()
{
//return mqtt_connected;
return mqtt.connected();
}
/**
* @brief Check if the network is connected
*
* @return True if the network is connected, false otherwise
*/
bool ESPMegaIoT::networkConnected()
{
if (network_config.useWifi)
@ -494,6 +737,12 @@ bool ESPMegaIoT::networkConnected()
return ethernetIface->linkUp();
}
/**
* @brief Bind a FRAM object to the ESPMegaIoT object
* @note This class is hardcode to use the FRAM address 34-300
*
* @param fram The FRAM object to bind
*/
void ESPMegaIoT::bindFRAM(FRAM *fram)
{
this->fram = fram;

View File

@ -15,6 +15,7 @@
#include <FRAM.h>
#include <map>
// MQTT Connection Parameters
#define TCP_TIMEOUT_SEC 5
#define MQTT_RECONNECT_INTERVAL 30000
@ -24,31 +25,48 @@
// Total of 267 bytes
#define IOT_FRAM_ADDRESS 34
/**
* @brief The network configuration struct
* @note This struct will be saved to FRAM when calling saveNetworkConfig
*/
struct NetworkConfig
{
IPAddress ip;
IPAddress gateway;
IPAddress subnet;
IPAddress dns1;
IPAddress dns2;
char hostname[32];
bool useStaticIp;
bool useWifi;
bool wifiUseAuth;
char ssid[32];
char password[32];
IPAddress ip; ///< The IP address
IPAddress gateway; ///< The gateway address
IPAddress subnet; ///< The subnet mask
IPAddress dns1; ///< The primary DNS server
IPAddress dns2; ///< The secondary DNS server
char hostname[32]; ///< The hostname
bool useStaticIp; ///< Whether to use a static IP, if false, DHCP will be used
bool useWifi; ///< Whether to use WiFi or Ethernet, if false, Ethernet will be used
bool wifiUseAuth; ///< Whether to use WiFi authentication, if false, ssid and password will be ignored
char ssid[32]; ///< The WiFi SSID, even if wifiUseAuth is false, this should be set
char password[32]; ///< The WiFi password, even if wifiUseAuth is false, this should be set
};
/**
* @brief The MQTT configuration struct
* @note This struct will be saved to FRAM when calling saveMqttConfig
*/
struct MqttConfig
{
char mqtt_server[32];
uint16_t mqtt_port;
char mqtt_user[32];
char mqtt_password[32];
bool mqtt_useauth;
char base_topic[32];
char mqtt_server[32]; ///< The MQTT server address
uint16_t mqtt_port; ///< The MQTT server port
char mqtt_user[32]; ///< The MQTT username, even if mqtt_useauth is false, this should be set
char mqtt_password[32]; ///< The MQTT password, even if mqtt_useauth is false, this should be set
bool mqtt_useauth; ///< Whether to use MQTT authentication, if false, mqtt_user and mqtt_password will be ignored
char base_topic[32]; ///< The base topic for the MQTT messages
};
/**
* @brief The ESPMegaIoT class is a class that is used to interface with the ESPMegaPRO IoT module
*
* This class allows you to register IoT components and interface with them through MQTT.
* This class also manages the network and MQTT connections for you.
* Supports both WiFi and Ethernet.
* Also allows you to save and load network and MQTT configurations to and from FRAM.
* Also provides MQTT helpers for publishing and subscribing to topics.
*/
class ESPMegaIoT
{
public:
@ -63,7 +81,7 @@ public:
void publishRelative(char *topic, char *payload);
// Subscribe topic appended with base topic
void subscribeRelative(char *topic);
void subscribeToTopic(char *topic);
void subscribe(char *topic);
void unsubscribeFromTopic(char *topic);
void connectToWifi(char *ssid, char *password);
void connectToWifi(char *ssid);