integrate IRBlaster into climate card

This commit is contained in:
Siwat Sirichai 2024-01-10 19:43:07 +07:00
parent 618f0b51e8
commit 81aa0c64f9
6 changed files with 60 additions and 50 deletions

View File

@ -11,12 +11,15 @@
/** /**
* @brief Construct a new ClimateCard object. * @brief Construct a new ClimateCard object.
* *
* @note RMT channel must be universally unique, this means that you can't use the same channel for multiple cards.
*
* @param ir_pin The GPIO pin number of the IR transmitter. * @param ir_pin The GPIO pin number of the IR transmitter.
* @param ac The AirConditioner object that represents the air conditioner. * @param ac The AirConditioner object that represents the air conditioner.
* @param sensor_type The type of the sensor connected to the card. * @param sensor_type The type of the sensor connected to the card.
* @param sensor_pin The GPIO pin number of the sensor. * @param sensor_pin The GPIO pin number of the sensor.
* @param channel The RMT channel to use for IR transmission.
*/ */
ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin) ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin, rmt_channel_t channel) : ir_blaster(ir_pin, channel)
{ {
this->ir_pin = ir_pin; this->ir_pin = ir_pin;
this->ac = ac; this->ac = ac;
@ -45,10 +48,13 @@ ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type,
* *
* @param ir_pin The GPIO pin number of the IR transmitter. * @param ir_pin The GPIO pin number of the IR transmitter.
* @param ac The AirConditioner object that represents the air conditioner. * @param ac The AirConditioner object that represents the air conditioner.
* @param channel The RMT channel to use for IR transmission.
*
* @note RMT channel must be universally unique, this means that you can't use the same channel for multiple cards.
* *
* @note This constructor can be used when no sensor is connected to the card. * @note This constructor can be used when no sensor is connected to the card.
*/ */
ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac) : ClimateCard(ir_pin, ac, AC_SENSOR_TYPE_NONE, 0) ClimateCard::ClimateCard(uint8_t ir_pin, AirConditioner ac, rmt_channel_t channel) : ClimateCard(ir_pin, ac, AC_SENSOR_TYPE_NONE, 0, channel)
{ {
} }
@ -59,7 +65,6 @@ ClimateCard::~ClimateCard()
{ {
delete dht; delete dht;
delete ds18b20; delete ds18b20;
rmt_driver_uninstall(RMT_TX_CHANNEL);
} }
/** /**
@ -81,17 +86,7 @@ bool ClimateCard::begin()
break; break;
} }
updateAirConditioner(); updateAirConditioner();
// We are returning here because sending IR signals is not working yet
return true; 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);
}
} }
/** /**
@ -351,25 +346,15 @@ void ClimateCard::updateSensor()
void ClimateCard::updateAirConditioner() void ClimateCard::updateAirConditioner()
{ {
// // The IR Transmissions are not working yet so we just return // // The IR Transmissions are not working yet so we just return
// const uint16_t* ir_code_ptr = nullptr; 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); 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) if (ir_code_ptr == nullptr)
// return; return;
// rmt_item32_t items[itemCount]; ir_blaster.send(ir_code_ptr, itemCount);
// // Convert IR timing array to RMT items
// for (size_t i = 0; i < itemCount; i+=2) // Publish state
// {
// 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 (const auto &callback : callbacks) for (const auto &callback : callbacks)
{ {
callback.second(this->state.ac_mode, this->state.ac_fan_speed, this->state.ac_temperature); callback.second(this->state.ac_mode, this->state.ac_fan_speed, this->state.ac_temperature);

View File

@ -1,14 +1,12 @@
#pragma once #pragma once
#include <ExpansionCard.hpp> #include <ExpansionCard.hpp>
#include <driver/rmt.h> #include <IRBlaster.hpp>
#include <FRAM.h> #include <FRAM.h>
#include <OneWire.h> #include <OneWire.h>
#include <DS18B20.h> #include <DS18B20.h>
#include <dhtnew.h> #include <dhtnew.h>
#include <map> #include <map>
#define RMT_TX_CHANNEL RMT_CHANNEL_0
#define CARD_TYPE_CLIMATE 0x03 #define CARD_TYPE_CLIMATE 0x03
#define AC_SENSOR_TYPE_NONE 0x00 #define AC_SENSOR_TYPE_NONE 0x00
@ -65,8 +63,8 @@ struct AirConditioner {
*/ */
class ClimateCard : public ExpansionCard { class ClimateCard : public ExpansionCard {
public: public:
ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin); ClimateCard(uint8_t ir_pin, AirConditioner ac, uint8_t sensor_type, uint8_t sensor_pin, rmt_channel_t channel);
ClimateCard(uint8_t ir_pin, AirConditioner ac); ClimateCard(uint8_t ir_pin, AirConditioner ac, rmt_channel_t channel);
~ClimateCard(); ~ClimateCard();
bool begin(); bool begin();
void loop(); void loop();
@ -107,6 +105,7 @@ class ClimateCard : public ExpansionCard {
void updateAirConditioner(); void updateAirConditioner();
// IR variables // IR variables
uint8_t ir_pin; uint8_t ir_pin;
IRBlaster ir_blaster;
// Air conditioner variables // Air conditioner variables
AirConditioner ac; AirConditioner ac;
ClimateCardData state; ClimateCardData state;

View File

@ -1,11 +1,23 @@
#include <IRBlaster.hpp> #include <IRBlaster.hpp>
#include <Arduino.h>
void IRBlaster::send(uint16_t *data, size_t size) /**
* @brief Destroy the IRBlaster object
*/
IRBlaster::~IRBlaster()
{
ESP_ERROR_CHECK(rmt_driver_uninstall(channel));
}
/**
* @brief Send an IR signal
*
* @param data The microseconds timing array produced by IRReceiver
* @param size The number of elements in the array
*/
void IRBlaster::send(const uint16_t *data, const size_t size)
{ {
// Send a raw IR signal // Send a raw IR signal
rmt_item32_t *items = new rmt_item32_t[size / 2 + size % 2]; rmt_item32_t *items = new rmt_item32_t[size / 2 + size % 2];
Serial.println("Converting IR data");
// data is in microseconds, we need to convert it to ticks // data is in microseconds, we need to convert it to ticks
// If the number of elements is odd, we need to add a 0 at the end // If the number of elements is odd, we need to add a 0 at the end
for (size_t i = 0, j = 0; i < size; i += 2, j++) for (size_t i = 0, j = 0; i < size; i += 2, j++)
@ -20,12 +32,18 @@ void IRBlaster::send(uint16_t *data, size_t size)
items[j].duration1 = 0; items[j].duration1 = 0;
} }
} }
Serial.println("Sending IR data");
ESP_ERROR_CHECK(rmt_write_items(channel, items, size / 2 + size % 2, true)); ESP_ERROR_CHECK(rmt_write_items(channel, items, size / 2 + size % 2, true));
delete[] items; delete[] items;
} }
IRBlaster::IRBlaster(uint8_t pin, rmt_channel_t channel) /**
* @brief Construct a new IRBlaster object
*
* @param pin The pin to use for IR transmission
* @param channel The RMT channel to use
*/
IRBlaster::IRBlaster(const uint8_t pin, rmt_channel_t channel)
{ {
this->channel = channel; this->channel = channel;
gpio_num_t gpio = gpio_num_t(pin); gpio_num_t gpio = gpio_num_t(pin);
@ -37,7 +55,13 @@ IRBlaster::IRBlaster(uint8_t pin, rmt_channel_t channel)
ESP_ERROR_CHECK(rmt_driver_install(channel, 0, 0)); ESP_ERROR_CHECK(rmt_driver_install(channel, 0, 0));
} }
IRBlaster::IRBlaster(uint8_t pin) /**
* @brief Construct a new IRBlaster object
* @note This constructor uses RMT_CHANNEL_0
*
* @param pin The pin to use for IR transmission
*/
IRBlaster::IRBlaster(const uint8_t pin)
{ {
IRBlaster(pin, RMT_CHANNEL_0); IRBlaster(pin, RMT_CHANNEL_0);
} }

View File

@ -1,16 +1,18 @@
#pragma once
#include <driver/rmt.h> #include <driver/rmt.h>
/**
* @brief Class for sending IR signals
*
* @warning This class takes one of the RMT channels, The ESP32 has 8 RMT channels, so you can use 7 IRBlaster objects at the same time (or 6 if you use the IRReceiver class)
*/
class IRBlaster class IRBlaster
{ {
public: public:
IRBlaster(uint8_t pin, rmt_channel_t channel); IRBlaster(const uint8_t pin, rmt_channel_t channel);
IRBlaster(uint8_t pin); IRBlaster(const uint8_t pin);
/*** ~IRBlaster();
* @brief Send an array of IR codes void send(const uint16_t *data, const size_t size);
*
* @param data Array of IR codes, each code is a 16 bit integer representing the number of 10us ticks
* @param size Size of the array
*/
void send(uint16_t *data, size_t size);
private: private:
rmt_channel_t channel; rmt_channel_t channel;
}; };