completed InputCard

This commit is contained in:
Siwat Sirichai 2023-12-28 23:28:21 +07:00
parent 9f6512bf71
commit 75aa6f490b
8 changed files with 77 additions and 84 deletions

View File

@ -1,11 +1,12 @@
#include <DigitalInputIoT.hpp>
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);
}

View File

@ -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<void(uint8_t, uint8_t)> change_callback;
bool digital_inputs_publish_enabled = false;
DigitalInputCard *card;

View File

@ -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 <pin>/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() {

View File

@ -1,5 +1,5 @@
#include <ESPMegaIoT.hpp>
#include <ETH.h>
#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];
}

View File

@ -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;
};

View File

@ -1,12 +1,5 @@
#include <IoTComponent.hpp>
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);

View File

@ -3,7 +3,7 @@
#include <PubSubClient.h>
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();

View File

@ -1,10 +1,20 @@
#include <ESPMegaPRO_OOP.hpp>
#include <ETH.h>
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(&ETH);
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() {