ESPMegaPRO-v3-SDK/Template Project/lib/ESPMegaPRO/DigitalOutputIoT.cpp

231 lines
8.2 KiB
C++
Raw Normal View History

2023-12-28 05:46:39 +00:00
#include <DigitalOutputIoT.hpp>
2023-12-28 06:14:18 +00:00
DigitalOutputIoT::DigitalOutputIoT() {
this->state_report_topic = new char[10];
this->value_report_topic = new char[10];
this->digital_outputs_publish_enabled = true;
2023-12-28 06:14:18 +00:00
}
DigitalOutputIoT::~DigitalOutputIoT() {
delete[] this->state_report_topic;
delete[] this->value_report_topic;
}
2023-12-28 07:08:10 +00:00
bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) {
2023-12-28 08:52:08 +00:00
Serial.print("Initializing digital output IoT component for card ");
Serial.println(card_id);
2023-12-28 06:34:51 +00:00
this->mqtt = mqtt;
this->base_topic = base_topic;
2023-12-28 05:46:39 +00:00
this->card = (DigitalOutputCard *) card;
2023-12-28 07:08:10 +00:00
if(!card->begin()) return false;
this-> card_id = card_id;
2023-12-28 05:46:39 +00:00
this->set_state_length = strlen(SET_STATE_TOPIC);
this->set_value_length = strlen(SET_VALUE_TOPIC);
this->state_length = strlen(STATE_TOPIC);
this->value_length = strlen(VALUE_TOPIC);
this->request_state_length = strlen(REQUEST_STATE_TOPIC);
this->publish_enable_length = strlen(PUBLISH_ENABLE_TOPIC);
2023-12-28 06:14:18 +00:00
strcpy(this->state_report_topic, "00/state");
strcpy(this->value_report_topic, "00/value");
2023-12-28 12:01:37 +00:00
// Register callbacks
auto bindedCallback = std::bind(&DigitalOutputIoT::handleValueChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
this->card->registerChangeCallback(bindedCallback);
2023-12-28 05:46:39 +00:00
return true;
}
// Protocol for digital output card
// Note that pin is always 2 characters long and padded with 0 if necessary
// Set pin state topic: <pin>/set/state payload: 0/1
// Set pin pwm topic: <pin>/set/value payload: 0-4095
// Publish pin state topic: <pin>/state payload: 0/1
// Publish pin pwm topic: <pin>/value payload: 0-4095
// 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);
2023-12-28 05:46:39 +00:00
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");
2023-12-28 05:46:39 +00:00
}
bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_t topic_length) {
// Check if the topic is a set state topic
// The correct format is <pin>/set/state
// This mean that the topic must end with /set/state
// Check if the 3rd character is /
if(topic[2] != '/') {
return false;
}
Serial.println("Set state first check passed");
2023-12-28 05:46:39 +00:00
// 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");
2023-12-28 05:46:39 +00:00
// 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");
2023-12-28 05:46:39 +00:00
// Get the pin number
uint8_t pin = (topic[0] - '0')*10 + (topic[1] - '0');
Serial.print("Pin: ");
Serial.println(pin);
2023-12-28 05:46:39 +00:00
// Get the state
bool state = false;
Serial.println(payload);
2023-12-28 05:46:39 +00:00
char state_char = payload[0];
if (state_char == '0') {
state = false;
2023-12-28 05:46:39 +00:00
} else if (state_char == '1') {
state = true;
2023-12-28 05:46:39 +00:00
} else {
return false;
}
Serial.print("State: ");
Serial.println(state);
2023-12-28 05:46:39 +00:00
// Set the state
card->setState(pin, state);
2023-12-28 05:46:39 +00:00
return true;
}
return false;
}
bool DigitalOutputIoT::processSetValueMessage(char *topic, char *payload, uint8_t topic_length) {
// Check if the topic is a set value topic
// 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");
2023-12-28 05:46:39 +00:00
if(topic[2] != '/') {
return false;
}
Serial.println("Set value first check passed");
2023-12-28 05:46:39 +00:00
// 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");
2023-12-28 05:46:39 +00:00
// 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");
2023-12-28 05:46:39 +00:00
// Get the pin number
uint8_t pin = (topic[0] - '0')*10 + (topic[1] - '0');
// Get the value
uint16_t value = atoi(payload);
// Set the value
card->setValue(pin, value);
2023-12-28 05:46:39 +00:00
return true;
}
return false;
}
bool DigitalOutputIoT::processRequestStateMessage(char *topic, char *payload, uint8_t topic_length) {
// Check if the topic is a request state topic
// 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);
2023-12-28 05:46:39 +00:00
if(topic_length != request_state_length) {
return false;
}
Serial.println("Request state first check passed");
2023-12-28 05:46:39 +00:00
// Check if the topic is requeststate
if (!strncmp(topic, REQUEST_STATE_TOPIC, request_state_length)) {
Serial.println("Request state second check passed");
2023-12-28 05:46:39 +00:00
// Publish the state of all pins
publishDigitalOutputs();
return true;
}
return false;
}
void DigitalOutputIoT::publishDigitalOutputs() {
2023-12-28 06:14:18 +00:00
if(!digital_outputs_publish_enabled) return;
Serial.println("Publishing digital outputs");
for(int i = 0; i < 16; i++) {
2023-12-28 06:14:18 +00:00
publishDigitalOutput(i);
}
2023-12-28 05:46:39 +00:00
}
void DigitalOutputIoT::publishDigitalOutput(uint8_t pin) {
2023-12-28 06:14:18 +00:00
publishDigitalOutputState(pin);
publishDigitalOutputValue(pin);
}
void DigitalOutputIoT::publishDigitalOutputState(uint8_t pin) {
if(!digital_outputs_publish_enabled) return;
state_report_topic[0] = pin / 10 + '0';
state_report_topic[1] = pin % 10 + '0';
publishRelative(state_report_topic, card->getState(pin) ? "1" : "0");
2023-12-28 06:14:18 +00:00
}
void DigitalOutputIoT::publishDigitalOutputValue(uint8_t pin) {
if(!digital_outputs_publish_enabled) return;
value_report_topic[0] = pin / 10 + '0';
value_report_topic[1] = pin % 10 + '0';
char payload[5];
sprintf(payload, "%d", card->getValue(pin));
publishRelative(value_report_topic, payload);
2023-12-28 05:46:39 +00:00
}
void DigitalOutputIoT::setDigitalOutputsPublishEnabled(bool enabled) {
digital_outputs_publish_enabled = enabled;
}
2023-12-28 06:14:18 +00:00
void DigitalOutputIoT::handleValueChange(uint8_t pin, bool state, uint16_t value) {
publishDigitalOutput(pin);
if(value_change_callback != NULL) {
value_change_callback(pin, state, value);
2023-12-28 05:46:39 +00:00
}
}
2023-12-28 12:01:37 +00:00
void DigitalOutputIoT::registerChangeCallback(std::function<void(uint8_t, bool, uint16_t)> callback) {
2023-12-28 06:14:18 +00:00
value_change_callback = callback;
}
2023-12-28 12:01:37 +00:00
void DigitalOutputIoT::deregisterChangeCallback() {
2023-12-28 06:14:18 +00:00
value_change_callback = NULL;
2023-12-28 05:46:39 +00:00
}
2023-12-28 06:14:18 +00:00
void DigitalOutputIoT::publishReport() {
publishDigitalOutputs();
}
uint8_t DigitalOutputIoT::getType() {
return CARD_TYPE_DIGITAL_OUTPUT;
2023-12-28 07:52:52 +00:00
}
void DigitalOutputIoT::subscribe() {
2023-12-28 08:52:08 +00:00
Serial.println("Subscribing to digital output topics");
char topic[20];
2023-12-28 08:52:08 +00:00
Serial.println("Subscribe to all set state topics");
2023-12-28 07:52:52 +00:00
// Subscribe to all set state topics
for(int i = 0; i < 16; i++) {
2023-12-28 07:52:52 +00:00
sprintf(topic, "%02d/set/state", i);
subscribeRelative(topic);
}
2023-12-28 08:52:08 +00:00
Serial.println("Subscribe to all set value topics");
2023-12-28 07:52:52 +00:00
// Subscribe to all set value topics
for(int i = 0; i < 16; i++) {
2023-12-28 07:52:52 +00:00
sprintf(topic, "%02d/set/value", i);
subscribeRelative(topic);
}
2023-12-28 08:52:08 +00:00
Serial.println("Subscribe to request state topic");
2023-12-28 07:52:52 +00:00
// Subscribe to request state topic
subscribeRelative(REQUEST_STATE_TOPIC);
2023-12-28 08:52:08 +00:00
Serial.println("Subscribe to publish enable topic");
2023-12-28 07:52:52 +00:00
// Subscribe to publish enable topic
subscribeRelative(PUBLISH_ENABLE_TOPIC);
2023-12-28 08:52:08 +00:00
Serial.println("Subscriptions complete");
2023-12-28 07:52:52 +00:00
}
void DigitalOutputIoT::loop() {
2023-12-28 06:14:18 +00:00
}