#include ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin) { this->ir_pin = ir_pin; this->ac = ac; this->sensor_type = sensor_type; this->sensor_pin = sensor_pin; // 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; // Initialize callbacks this->callbacks = std::vector>(); } ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac) : ClimateCard(ir_pin, ac, AC_SENSOR_TYPE_NONE, 0) { } ClimateCard::~ClimateCard() { delete dht; delete ds18b20; rmt_driver_uninstall(RMT_TX_CHANNEL); } bool ClimateCard::begin() { 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(); return true; 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); } } 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() { fram->writeObject(fram_address, this->state); } void ClimateCard::loadStateFromFRAM() { fram->readObject(fram_address, this->state); // If temperature is out of range, set to its respective maximum or minimum 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; updateAirConditioner(); } void ClimateCard::setTemperature(uint8_t temperature) { // 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; this->state.ac_temperature = temperature; updateAirConditioner(); if (fram_auto_save) saveStateToFRAM(); } void ClimateCard::setMode(uint8_t mode) { this->state.ac_mode = mode; updateAirConditioner(); if (fram_auto_save) saveStateToFRAM(); } void ClimateCard::setFanSpeed(uint8_t fan_speed) { this->state.ac_fan_speed = fan_speed; updateAirConditioner(); if (fram_auto_save) saveStateToFRAM(); } void ClimateCard::registerChangeCallback(std::function callback) { callbacks.push_back(callback); } uint8_t ClimateCard::getType() { return CARD_TYPE_CLIMATE; } void ClimateCard::updateSensor() { if (sensor_type == AC_SENSOR_TYPE_NONE) return; // 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; } for (uint8_t i = 0; i < sensor_callbacks.size(); i++) { sensor_callbacks[i](room_temperature, humidity); } } void ClimateCard::updateAirConditioner() { // 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 // for (uint8_t i = 0; i < callbacks.size(); i++) // { // 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; } 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; } void ClimateCard::registerSensorCallback(std::function callback) { sensor_callbacks.push_back(callback); }