IoT Comment
This commit is contained in:
parent
9a0f02fcd9
commit
d75d098247
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue