#include ClimateCard::ClimateCard(uint8_t ir_pin) { this->ir_pin = ir_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 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); } ClimateCard::~ClimateCard() { delete dht; delete ds18b20; rmt_driver_uninstall(RMT_TX_CHANNEL); } bool ClimateCard::begin(AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin) { this->ac = ac; this->sensor_type = sensor_type; this->sensor_pin = sensor_pin; 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(); } bool ClimateCard::begin(AirConditioner ac) { this->begin(ac, AC_SENSOR_TYPE_NONE, 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); } void ClimateCard::setTemperature(uint8_t 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() { size_t itemCount = sizeof(ac.infraredCodes[this->state.ac_mode][this->state.ac_fan_speed][this->state.ac_temperature]) / sizeof(ac.infraredCodes[this->state.ac_mode][this->state.ac_fan_speed][this->state.ac_temperature][0]); rmt_item32_t items[itemCount]; // Convert IR timing array to RMT items for (size_t i = 0; i < itemCount; i++) { items[i].level0 = 1; items[i].duration0 = ac.infraredCodes[this->state.ac_mode][this->state.ac_fan_speed][this->state.ac_temperature][i]; items[i].level1 = 0; items[i].duration1 = ac.infraredCodes[this->state.ac_mode][this->state.ac_fan_speed][this->state.ac_temperature][i]; } // 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); }