From 4c04a135accd535aca3baeb49eda547c0dfe91fb Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Sat, 30 Dec 2023 14:32:40 +0700 Subject: [PATCH] climate IoT Implementation --- .../lib/ESPMegaPRO/ClimateCard.cpp | 20 ++- .../lib/ESPMegaPRO/ClimateCard.hpp | 5 +- .../lib/ESPMegaPRO/ClimateIoT.cpp | 131 ++++++++++++++++++ .../lib/ESPMegaPRO/ClimateIoT.hpp | 42 ++++++ Template Project/lib/ESPMegaPRO/ESPMegaPRO.h | 2 + .../lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp | 1 + 6 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 Template Project/lib/ESPMegaPRO/ClimateIoT.cpp create mode 100644 Template Project/lib/ESPMegaPRO/ClimateIoT.hpp diff --git a/Template Project/lib/ESPMegaPRO/ClimateCard.cpp b/Template Project/lib/ESPMegaPRO/ClimateCard.cpp index 1c816d9..e7108fc 100644 --- a/Template Project/lib/ESPMegaPRO/ClimateCard.cpp +++ b/Template Project/lib/ESPMegaPRO/ClimateCard.cpp @@ -106,7 +106,7 @@ void ClimateCard::setFanSpeed(uint8_t fan_speed) saveStateToFRAM(); } -void ClimateCard::registerCallback(std::function callback) +void ClimateCard::registerChangeCallback(std::function callback) { callbacks.push_back(callback); } @@ -118,6 +118,8 @@ uint8_t ClimateCard::getType() void ClimateCard::updateSensor() { + if (sensor_type == AC_SENSOR_TYPE_NONE) + return; // Read sensor data and update variables switch (sensor_type) { @@ -141,6 +143,10 @@ void ClimateCard::updateSensor() room_temperature = ds18b20->getTempC(); break; } + for (uint8_t i = 0; i < sensor_callbacks.size(); i++) + { + sensor_callbacks[i](room_temperature, humidity); + } } void ClimateCard::updateAirConditioner() @@ -150,11 +156,16 @@ void ClimateCard::updateAirConditioner() NEC_KHZ); for (uint8_t i = 0; i < callbacks.size(); i++) { - callbacks[i](this->state.ac_temperature, this->state.ac_mode, this->state.ac_fan_speed); + callbacks[i](this->state.ac_mode, this->state.ac_fan_speed, this->state.ac_temperature); } } +uint8_t ClimateCard::getSensorType() +{ + return sensor_type; +} + float ClimateCard::getRoomTemperature() { return room_temperature; @@ -178,4 +189,9 @@ uint8_t ClimateCard::getMode() uint8_t ClimateCard::getFanSpeed() { return state.ac_fan_speed; +} + +void ClimateCard::registerSensorCallback(std::function callback) +{ + sensor_callbacks.push_back(callback); } \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/ClimateCard.hpp b/Template Project/lib/ESPMegaPRO/ClimateCard.hpp index 5d2e286..639d343 100644 --- a/Template Project/lib/ESPMegaPRO/ClimateCard.hpp +++ b/Template Project/lib/ESPMegaPRO/ClimateCard.hpp @@ -52,7 +52,9 @@ class ClimateCard : public ExpansionCard { uint8_t getFanSpeed(); float getRoomTemperature(); float getHumidity(); - void registerCallback(std::function callback); + uint8_t getSensorType(); + void registerChangeCallback(std::function callback); + void registerSensorCallback(std::function callback); uint8_t getType(); private: // Sensor objects @@ -61,6 +63,7 @@ class ClimateCard : public ExpansionCard { DS18B20 *ds18b20; // Callbacks std::vector> callbacks; + std::vector> sensor_callbacks; // Update functions void updateSensor(); void updateAirConditioner(); diff --git a/Template Project/lib/ESPMegaPRO/ClimateIoT.cpp b/Template Project/lib/ESPMegaPRO/ClimateIoT.cpp new file mode 100644 index 0000000..2484f9a --- /dev/null +++ b/Template Project/lib/ESPMegaPRO/ClimateIoT.cpp @@ -0,0 +1,131 @@ +#include + +ClimateIoT::ClimateIoT() { + +} + +ClimateIoT::~ClimateIoT() { + // Destructor implementation +} + +bool ClimateIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) { + this->card = (ClimateCard *)card; + // Reister Callbacks + auto bindedSensorCallback = std::bind(&ClimateIoT::handleSensorUpdate, this, std::placeholders::_1, std::placeholders::_2); + this->card->registerSensorCallback(bindedSensorCallback); + auto bindedAirConditionerCallback = std::bind(&ClimateIoT::handleAirConditionerUpdate, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + this->card->registerChangeCallback(bindedAirConditionerCallback); +} + +void ClimateIoT::handleMqttMessage(char *topic, char *payload) { + uint8_t topic_length = strlen(topic); + if (this->processSetTemperatureMessage(topic, payload, topic_length)) + return; + if (this->processSetModeMessage(topic, payload, topic_length)) + return; + if (this->processSetFanSpeedMessage(topic, payload, topic_length)) + return; + if (this->processRequestStateMessage(topic, payload, topic_length)) + return; +} + +void ClimateIoT::publishClimateTemperature() { + char payload[5]; + itoa(this->card->getTemperature(), payload, 10); + this->publishRelative(AC_TEMPERATURE_REPORT_TOPIC, payload); +} + +void ClimateIoT::publishClimateMode() { + char payload[2]; + itoa(this->card->getMode(), payload, 10); + this->publishRelative(AC_MODE_REPORT_TOPIC, payload); +} + +void ClimateIoT::publishClimateFanSpeed() { + char payload[2]; + itoa(this->card->getFanSpeed(), payload, 10); + this->publishRelative(AC_FAN_SPEED_REPORT_TOPIC, payload); +} + +void ClimateIoT::publishSensor() { + this->publishRoomTemperature(); + this->publishHumidity(); +} + +void ClimateIoT::publishClimate() { + this->publishClimateTemperature(); + this->publishClimateMode(); + this->publishClimateFanSpeed(); +} + +void ClimateIoT::publishRoomTemperature() { + char payload[5]; + itoa(this->card->getRoomTemperature(), payload, 10); + this->publishRelative(AC_ROOM_TEMPERATURE_REPORT_TOPIC, payload); +} + +void ClimateIoT::publishHumidity() { + if (this->card->getSensorType() == AC_SENSOR_TYPE_DHT22) { + char payload[5]; + itoa(this->card->getHumidity(), payload, 10); + this->publishRelative(AC_HUMIDITY_REPORT_TOPIC, payload); + } +} + +void ClimateIoT::handleStateChange(uint8_t temperature, uint8_t mode, uint8_t fan_speed) { + this->publishClimate(); +} + +void ClimateIoT::publishReport() { + this->publishClimate(); + this->publishSensor(); +} + +void ClimateIoT::subscribe() { + this->subscribeRelative(AC_TEMPERATURE_SET_TOPIC); + this->subscribeRelative(AC_MODE_SET_TOPIC); + this->subscribeRelative(AC_FAN_SPEED_SET_TOPIC); +} + +void ClimateIoT::loop() { + +} + +uint8_t ClimateIoT::getType() { + return CARD_TYPE_CLIMATE; +} + +bool ClimateIoT::processSetTemperatureMessage(char *topic, char *payload, uint8_t topic_length) { + if (!strcmp(topic, AC_TEMPERATURE_SET_TOPIC)) { + uint8_t temperature = atoi(payload); + this->card->setTemperature(temperature); + return true; + } + return false; +} + +bool ClimateIoT::processSetModeMessage(char *topic, char *payload, uint8_t topic_length) { + if (!strcmp(topic, AC_MODE_SET_TOPIC)) { + uint8_t mode = atoi(payload); + this->card->setMode(mode); + return true; + } + return false; +} + +bool ClimateIoT::processSetFanSpeedMessage(char *topic, char *payload, uint8_t topic_length) { + if (!strcmp(topic, AC_FAN_SPEED_SET_TOPIC)) { + uint8_t fan_speed = atoi(payload); + this->card->setFanSpeed(fan_speed); + return true; + } + return false; +} + +bool ClimateIoT::processRequestStateMessage(char *topic, char *payload, uint8_t topic_length) { + if (!strcmp(topic, AC_REQUEST_STATE_TOPIC)) { + this->publishReport(); + return true; + } + return false; +} \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/ClimateIoT.hpp b/Template Project/lib/ESPMegaPRO/ClimateIoT.hpp new file mode 100644 index 0000000..1e80c1c --- /dev/null +++ b/Template Project/lib/ESPMegaPRO/ClimateIoT.hpp @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include + +#define AC_MODE_REPORT_TOPIC "mode" +#define AC_MODE_SET_TOPIC "set/mode" +#define AC_TEMPERATURE_REPORT_TOPIC "temperature" +#define AC_TEMPERATURE_SET_TOPIC "set/temperature" +#define AC_FAN_SPEED_REPORT_TOPIC "fan_speed" +#define AC_FAN_SPEED_SET_TOPIC "set/fan_speed" +#define AC_ROOM_TEMPERATURE_REPORT_TOPIC "room_temperature" +#define AC_HUMIDITY_REPORT_TOPIC "humidity" +#define AC_REQUEST_STATE_TOPIC "request_state" + +class ClimateIoT : public IoTComponent { + public: + ClimateIoT(); + ~ClimateIoT(); + bool begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic); + void handleMqttMessage(char *topic, char *payload); + void publishClimate(); + void publishClimateTemperature(); + void publishClimateMode(); + void publishClimateFanSpeed(); + void publishSensor(); + void publishRoomTemperature(); + void publishHumidity(); + void handleStateChange(uint8_t temperature, uint8_t mode, uint8_t fan_speed); + void handleSensorUpdate(float temperature, float humidity); + void handleAirConditionerUpdate(uint8_t mode, uint8_t fan_speed, uint8_t temperature); + void publishReport(); + void subscribe(); + void loop(); + uint8_t getType(); + private: + bool processSetTemperatureMessage(char *topic, char *payload, uint8_t topic_length); + bool processSetModeMessage(char *topic, char *payload, uint8_t topic_length); + bool processSetFanSpeedMessage(char *topic, char *payload, uint8_t topic_length); + bool processRequestStateMessage(char *topic, char *payload, uint8_t topic_length); + ClimateCard *card; +}; \ No newline at end of file diff --git a/Template Project/lib/ESPMegaPRO/ESPMegaPRO.h b/Template Project/lib/ESPMegaPRO/ESPMegaPRO.h index c11688e..d5324fc 100644 --- a/Template Project/lib/ESPMegaPRO/ESPMegaPRO.h +++ b/Template Project/lib/ESPMegaPRO/ESPMegaPRO.h @@ -14,6 +14,8 @@ #include #endif +#warning "The procedural ESPMega library does not support installing card. If you want to use the card system, please use the OOP version of the library." + #define INPUT_BANK_A_ADDRESS 0x21 #define INPUT_BANK_B_ADDRESS 0x22 #define PWM_BANK_ADDRESS 0x5F diff --git a/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp b/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp index 99b0c7d..fe21abd 100644 --- a/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp +++ b/Template Project/lib/ESPMegaPRO/ESPMegaPRO_OOP.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include