2023-12-30 06:49:37 +00:00
|
|
|
#include <ClimateCard.hpp>
|
|
|
|
|
2023-12-30 17:25:07 +00:00
|
|
|
ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin)
|
2023-12-30 06:49:37 +00:00
|
|
|
{
|
|
|
|
this->ir_pin = ir_pin;
|
2023-12-30 17:25:07 +00:00
|
|
|
this->ac = ac;
|
|
|
|
this->sensor_type = sensor_type;
|
|
|
|
this->sensor_pin = sensor_pin;
|
2023-12-30 06:49:37 +00:00
|
|
|
// Initialize Pointers
|
|
|
|
this->dht = nullptr;
|
|
|
|
this->ds18b20 = nullptr;
|
|
|
|
this->fram = nullptr;
|
|
|
|
// Initialize Variables
|
|
|
|
this->fram_address = 0;
|
|
|
|
this->fram_auto_save = false;
|
|
|
|
this->state.ac_temperature = 0;
|
|
|
|
this->state.ac_mode = 0;
|
|
|
|
this->state.ac_fan_speed = 0;
|
|
|
|
this->humidity = 0;
|
|
|
|
this->room_temperature = 0;
|
|
|
|
// Initialize state
|
|
|
|
this->state.ac_temperature = 25;
|
|
|
|
this->state.ac_mode = 0;
|
|
|
|
this->state.ac_fan_speed = 0;
|
2023-12-30 17:25:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac) : ClimateCard(ir_pin, ac, AC_SENSOR_TYPE_NONE, 0)
|
|
|
|
{
|
|
|
|
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ClimateCard::~ClimateCard()
|
|
|
|
{
|
|
|
|
delete dht;
|
|
|
|
delete ds18b20;
|
2023-12-30 08:39:16 +00:00
|
|
|
rmt_driver_uninstall(RMT_TX_CHANNEL);
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
2023-12-30 17:25:07 +00:00
|
|
|
bool ClimateCard::begin()
|
2023-12-30 06:49:37 +00:00
|
|
|
{
|
|
|
|
switch (sensor_type)
|
|
|
|
{
|
|
|
|
case AC_SENSOR_TYPE_DHT22:
|
|
|
|
dht = new DHTNEW(sensor_pin);
|
|
|
|
break;
|
|
|
|
case AC_SENSOR_TYPE_DS18B20:
|
|
|
|
OneWire oneWire(sensor_pin);
|
|
|
|
ds18b20 = new DS18B20(&oneWire);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
updateAirConditioner();
|
2023-12-30 08:56:05 +00:00
|
|
|
return true;
|
2023-12-30 17:25:07 +00:00
|
|
|
if (sensor_pin != 0)
|
|
|
|
{
|
|
|
|
// Initialize RMT
|
|
|
|
gpio_num_t gpio_num = gpio_num_t(ir_pin);
|
|
|
|
rmt_config_t rmt_tx = RMT_DEFAULT_CONFIG_TX(gpio_num, RMT_TX_CHANNEL);
|
|
|
|
rmt_tx.clk_div = 80; // 1MHz clock
|
|
|
|
rmt_config(&rmt_tx);
|
|
|
|
rmt_driver_install(rmt_tx.channel, 0, 0);
|
|
|
|
}
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::loop()
|
|
|
|
{
|
|
|
|
static uint32_t last_sensor_update = 0;
|
|
|
|
if (millis() - last_sensor_update >= AC_SENSOR_READ_INTERVAL)
|
|
|
|
{
|
|
|
|
last_sensor_update = millis();
|
|
|
|
updateSensor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::bindFRAM(FRAM *fram, uint16_t fram_address)
|
|
|
|
{
|
|
|
|
this->fram = fram;
|
|
|
|
this->fram_address = fram_address;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::setFRAMAutoSave(bool autoSave)
|
|
|
|
{
|
|
|
|
this->fram_auto_save = autoSave;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::saveStateToFRAM()
|
|
|
|
{
|
2023-12-30 19:59:25 +00:00
|
|
|
fram->write8(fram_address, state.ac_temperature);
|
|
|
|
fram->write8(fram_address + 1, state.ac_mode);
|
|
|
|
fram->write8(fram_address + 2, state.ac_fan_speed);
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::loadStateFromFRAM()
|
|
|
|
{
|
2023-12-31 06:29:11 +00:00
|
|
|
if (state.ac_temperature > ac.max_temperature)
|
|
|
|
state.ac_temperature = ac.max_temperature;
|
|
|
|
else if (state.ac_temperature < ac.min_temperature)
|
|
|
|
state.ac_temperature = ac.min_temperature;
|
|
|
|
// If mode is out of range, set to 0
|
|
|
|
if (state.ac_mode > ac.modes)
|
|
|
|
state.ac_mode = 0;
|
|
|
|
// If fan speed is out of range, set to 0
|
|
|
|
if (state.ac_fan_speed > ac.fan_speeds)
|
|
|
|
state.ac_fan_speed = 0;
|
2023-12-30 17:37:50 +00:00
|
|
|
updateAirConditioner();
|
2023-12-31 06:29:11 +00:00
|
|
|
for (const auto& callback : callbacks)
|
2023-12-30 19:18:57 +00:00
|
|
|
{
|
2023-12-31 06:29:11 +00:00
|
|
|
callback.second(this->state.ac_mode, this->state.ac_fan_speed, this->state.ac_temperature);
|
2023-12-30 19:18:57 +00:00
|
|
|
}
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::setTemperature(uint8_t temperature)
|
|
|
|
{
|
2023-12-30 17:25:07 +00:00
|
|
|
// If temperature is out of range, set to its respective maximum or minimum
|
|
|
|
if (temperature > ac.max_temperature)
|
|
|
|
temperature = ac.max_temperature;
|
|
|
|
else if (temperature < ac.min_temperature)
|
|
|
|
temperature = ac.min_temperature;
|
2023-12-30 06:49:37 +00:00
|
|
|
this->state.ac_temperature = temperature;
|
|
|
|
updateAirConditioner();
|
2023-12-30 06:52:32 +00:00
|
|
|
if (fram_auto_save)
|
|
|
|
saveStateToFRAM();
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::setMode(uint8_t mode)
|
|
|
|
{
|
|
|
|
this->state.ac_mode = mode;
|
|
|
|
updateAirConditioner();
|
2023-12-30 06:52:32 +00:00
|
|
|
if (fram_auto_save)
|
|
|
|
saveStateToFRAM();
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
2023-12-31 17:07:11 +00:00
|
|
|
char* ClimateCard::getModeName()
|
|
|
|
{
|
|
|
|
return (char*)ac.mode_names[state.ac_mode];
|
|
|
|
}
|
|
|
|
|
|
|
|
char* ClimateCard::getFanSpeedName()
|
|
|
|
{
|
|
|
|
return (char*)ac.fan_speed_names[state.ac_fan_speed];
|
|
|
|
}
|
|
|
|
|
2023-12-30 06:49:37 +00:00
|
|
|
void ClimateCard::setFanSpeed(uint8_t fan_speed)
|
|
|
|
{
|
|
|
|
this->state.ac_fan_speed = fan_speed;
|
|
|
|
updateAirConditioner();
|
2023-12-30 06:52:32 +00:00
|
|
|
if (fram_auto_save)
|
|
|
|
saveStateToFRAM();
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
2023-12-31 17:07:11 +00:00
|
|
|
void ClimateCard::setFanSpeedByName(const char* fan_speed_name)
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < ac.fan_speeds; i++)
|
|
|
|
{
|
|
|
|
if (strcmp(fan_speed_name, ac.fan_speed_names[i]) == 0)
|
|
|
|
{
|
|
|
|
setFanSpeed(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::setModeByName(const char* mode_name)
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < ac.modes; i++)
|
|
|
|
{
|
|
|
|
if (strcmp(mode_name, ac.mode_names[i]) == 0)
|
|
|
|
{
|
|
|
|
setMode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-31 06:32:38 +00:00
|
|
|
uint8_t ClimateCard::registerChangeCallback(std::function<void(uint8_t, uint8_t, uint8_t)> callback)
|
2023-12-30 06:49:37 +00:00
|
|
|
{
|
2023-12-31 06:32:38 +00:00
|
|
|
callbacks[callbacks_handler_count] = callback;
|
|
|
|
return callbacks_handler_count++;
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t ClimateCard::getType()
|
|
|
|
{
|
|
|
|
return CARD_TYPE_CLIMATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::updateSensor()
|
|
|
|
{
|
2023-12-30 07:32:40 +00:00
|
|
|
if (sensor_type == AC_SENSOR_TYPE_NONE)
|
|
|
|
return;
|
2023-12-30 06:49:37 +00:00
|
|
|
// Read sensor data and update variables
|
|
|
|
switch (sensor_type)
|
|
|
|
{
|
|
|
|
case AC_SENSOR_TYPE_DHT22:
|
|
|
|
if (millis() - dht->lastRead() < AC_SENSOR_READ_INTERVAL)
|
|
|
|
return;
|
|
|
|
dht->read();
|
|
|
|
room_temperature = dht->getTemperature();
|
|
|
|
humidity = dht->getHumidity();
|
|
|
|
break;
|
|
|
|
case AC_SENSOR_TYPE_DS18B20:
|
|
|
|
ds18b20->requestTemperatures();
|
|
|
|
uint32_t start = millis();
|
|
|
|
while (!ds18b20->isConversionComplete())
|
|
|
|
{
|
|
|
|
if (millis() - start >= AC_SENSOR_READ_TIMEOUT)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
room_temperature = ds18b20->getTempC();
|
|
|
|
break;
|
|
|
|
}
|
2023-12-31 06:29:11 +00:00
|
|
|
for (const auto& callback : sensor_callbacks)
|
2023-12-30 07:32:40 +00:00
|
|
|
{
|
2023-12-31 06:29:11 +00:00
|
|
|
callback.second(room_temperature, humidity);
|
2023-12-30 07:32:40 +00:00
|
|
|
}
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::updateAirConditioner()
|
|
|
|
{
|
2023-12-30 17:25:07 +00:00
|
|
|
// const uint16_t* ir_code_ptr = nullptr;
|
|
|
|
// size_t itemCount = (*(this->ac.getInfraredCode))(this->state.ac_mode, this->state.ac_fan_speed, this->state.ac_temperature, &ir_code_ptr);
|
|
|
|
|
|
|
|
// if (ir_code_ptr == nullptr)
|
|
|
|
// return;
|
|
|
|
|
|
|
|
// rmt_item32_t items[itemCount];
|
|
|
|
// // Convert IR timing array to RMT items
|
|
|
|
// for (size_t i = 0; i < itemCount; i+=2)
|
|
|
|
// {
|
|
|
|
// items[i].level0 = 1;
|
|
|
|
// items[i].duration0 = ir_code_ptr[i];
|
|
|
|
// items[i].level1 = 0;
|
|
|
|
// items[i].duration1 = ir_code_ptr[i+1];
|
|
|
|
// }
|
|
|
|
// // Send IR signal
|
|
|
|
// rmt_write_items(RMT_TX_CHANNEL, items, itemCount, true);
|
|
|
|
// rmt_wait_tx_done(RMT_TX_CHANNEL, portMAX_DELAY);
|
|
|
|
// // Publish state
|
2023-12-31 06:29:11 +00:00
|
|
|
for (const auto& callback : callbacks)
|
2023-12-30 19:18:57 +00:00
|
|
|
{
|
2023-12-31 06:29:11 +00:00
|
|
|
callback.second(this->state.ac_mode, this->state.ac_fan_speed, this->state.ac_temperature);
|
2023-12-30 19:18:57 +00:00
|
|
|
}
|
2023-12-30 06:49:37 +00:00
|
|
|
}
|
|
|
|
|
2023-12-30 07:32:40 +00:00
|
|
|
uint8_t ClimateCard::getSensorType()
|
|
|
|
{
|
|
|
|
return sensor_type;
|
|
|
|
}
|
|
|
|
|
2023-12-30 06:49:37 +00:00
|
|
|
float ClimateCard::getRoomTemperature()
|
|
|
|
{
|
|
|
|
return room_temperature;
|
|
|
|
}
|
|
|
|
|
|
|
|
float ClimateCard::getHumidity()
|
|
|
|
{
|
|
|
|
return humidity;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t ClimateCard::getTemperature()
|
|
|
|
{
|
|
|
|
return state.ac_temperature;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t ClimateCard::getMode()
|
|
|
|
{
|
|
|
|
return state.ac_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t ClimateCard::getFanSpeed()
|
|
|
|
{
|
|
|
|
return state.ac_fan_speed;
|
2023-12-30 07:32:40 +00:00
|
|
|
}
|
|
|
|
|
2023-12-31 06:32:38 +00:00
|
|
|
uint8_t ClimateCard::registerSensorCallback(std::function<void(float, float)> callback)
|
2023-12-30 07:32:40 +00:00
|
|
|
{
|
2023-12-31 06:32:38 +00:00
|
|
|
sensor_callbacks[sensor_callbacks_handler_count] = callback;
|
|
|
|
return sensor_callbacks_handler_count++;
|
2023-12-30 17:25:07 +00:00
|
|
|
}
|
|
|
|
|
2023-12-31 06:29:11 +00:00
|
|
|
void ClimateCard::unregisterChangeCallback(uint8_t handler)
|
|
|
|
{
|
|
|
|
callbacks.erase(handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClimateCard::unregisterSensorCallback(uint8_t handler)
|
|
|
|
{
|
|
|
|
sensor_callbacks.erase(handler);
|
|
|
|
}
|