climate IoT Implementation

This commit is contained in:
Siwat Sirichai 2023-12-30 14:32:40 +07:00
parent b1dd128aa1
commit 4c04a135ac
6 changed files with 198 additions and 3 deletions

View File

@ -106,7 +106,7 @@ void ClimateCard::setFanSpeed(uint8_t fan_speed)
saveStateToFRAM(); saveStateToFRAM();
} }
void ClimateCard::registerCallback(std::function<void(uint8_t, uint8_t, uint8_t)> callback) void ClimateCard::registerChangeCallback(std::function<void(uint8_t, uint8_t, uint8_t)> callback)
{ {
callbacks.push_back(callback); callbacks.push_back(callback);
} }
@ -118,6 +118,8 @@ uint8_t ClimateCard::getType()
void ClimateCard::updateSensor() void ClimateCard::updateSensor()
{ {
if (sensor_type == AC_SENSOR_TYPE_NONE)
return;
// Read sensor data and update variables // Read sensor data and update variables
switch (sensor_type) switch (sensor_type)
{ {
@ -141,6 +143,10 @@ void ClimateCard::updateSensor()
room_temperature = ds18b20->getTempC(); room_temperature = ds18b20->getTempC();
break; break;
} }
for (uint8_t i = 0; i < sensor_callbacks.size(); i++)
{
sensor_callbacks[i](room_temperature, humidity);
}
} }
void ClimateCard::updateAirConditioner() void ClimateCard::updateAirConditioner()
@ -150,11 +156,16 @@ void ClimateCard::updateAirConditioner()
NEC_KHZ); NEC_KHZ);
for (uint8_t i = 0; i < callbacks.size(); i++) 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() float ClimateCard::getRoomTemperature()
{ {
return room_temperature; return room_temperature;
@ -178,4 +189,9 @@ uint8_t ClimateCard::getMode()
uint8_t ClimateCard::getFanSpeed() uint8_t ClimateCard::getFanSpeed()
{ {
return state.ac_fan_speed; return state.ac_fan_speed;
}
void ClimateCard::registerSensorCallback(std::function<void(float, float)> callback)
{
sensor_callbacks.push_back(callback);
} }

View File

@ -52,7 +52,9 @@ class ClimateCard : public ExpansionCard {
uint8_t getFanSpeed(); uint8_t getFanSpeed();
float getRoomTemperature(); float getRoomTemperature();
float getHumidity(); float getHumidity();
void registerCallback(std::function<void(uint8_t, uint8_t, uint8_t)> callback); uint8_t getSensorType();
void registerChangeCallback(std::function<void(uint8_t, uint8_t, uint8_t)> callback);
void registerSensorCallback(std::function<void(float, float)> callback);
uint8_t getType(); uint8_t getType();
private: private:
// Sensor objects // Sensor objects
@ -61,6 +63,7 @@ class ClimateCard : public ExpansionCard {
DS18B20 *ds18b20; DS18B20 *ds18b20;
// Callbacks // Callbacks
std::vector<std::function<void(uint8_t, uint8_t, uint8_t)>> callbacks; std::vector<std::function<void(uint8_t, uint8_t, uint8_t)>> callbacks;
std::vector<std::function<void(float, float)>> sensor_callbacks;
// Update functions // Update functions
void updateSensor(); void updateSensor();
void updateAirConditioner(); void updateAirConditioner();

View File

@ -0,0 +1,131 @@
#include <ClimateIoT.hpp>
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;
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <IoTComponent.hpp>
#include <ExpansionCard.hpp>
#include <ClimateCard.hpp>
#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;
};

View File

@ -14,6 +14,8 @@
#include <MCP4725.h> #include <MCP4725.h>
#endif #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_A_ADDRESS 0x21
#define INPUT_BANK_B_ADDRESS 0x22 #define INPUT_BANK_B_ADDRESS 0x22
#define PWM_BANK_ADDRESS 0x5F #define PWM_BANK_ADDRESS 0x5F

View File

@ -2,6 +2,7 @@
#include <ExpansionCard.hpp> #include <ExpansionCard.hpp>
#include <DigitalInputCard.hpp> #include <DigitalInputCard.hpp>
#include <DigitalOutputCard.hpp> #include <DigitalOutputCard.hpp>
#include <ClimateCard.hpp>
#include <ESPMegaIoT.hpp> #include <ESPMegaIoT.hpp>
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h> #include <Wire.h>