33static constexpr uint8_t TEMP_MIN_NOT_HEAT = 64;
34static constexpr uint8_t TEMP_DEFAULT = 72;
36static constexpr uint8_t STATE_MESSAGE_LENGTH_UTIL = 5;
37static constexpr uint16_t CARRIER_ADDRESS = 0x28C6;
38static constexpr uint32_t CARRIER_FREQUENCY = 38000;
40static constexpr uint8_t BYTE3_POWER_OFF = 0x40;
41static constexpr uint8_t BYTE6_POWER_ON = 0x80;
42static constexpr uint8_t BYTE7_MODE_AUTO = 0x00;
43static constexpr uint8_t BYTE8_FAN_AUTO = 0x00;
44static constexpr uint8_t BYTE8_FAN_SWING = 0x08;
47static constexpr uint8_t STATE_TEMPLATE[STATE_MESSAGE_LENGTH] PROGMEM = {
48 0x00, 0x08, 0x08, 0x7F, 0x90, 0x0C, BYTE6_POWER_ON, BYTE7_MODE_AUTO, BYTE8_FAN_AUTO, 0x00, 0x00, 0x00, 0x04, 0x00};
50static constexpr uint8_t OFF_FRAME[STATE_MESSAGE_LENGTH_UTIL] PROGMEM = {0x00, 0x08, 0x08, BYTE3_POWER_OFF,
51 255 - BYTE3_POWER_OFF};
57static constexpr Code MODES[]
PROGMEM = {
64static constexpr Code FANS[]
PROGMEM = {
71template<
size_t N>
static optional<Code> find_entry(
const Code (&table)[N], uint8_t key,
bool match_code) {
72 for (
const Code &slot : table) {
75 if ((match_code ? entry.code : entry.value) == key)
82static uint8_t reverse_nibble(uint8_t value) {
return reverse_bits(value) >> 4; }
84static bool matches_template(
const uint8_t *data, uint8_t from, uint8_t to) {
85 for (uint8_t i = from; i <= to; i++) {
99static uint8_t checksum_state(
const uint8_t *data) {
101 for (uint8_t i = 6; i < STATE_MESSAGE_LENGTH - 1; ++i) {
107static const LogString *model_to_string(
Model model) {
111 return LOG_STR(
"MW12Y3H");
116 auto traits = ClimateIR::traits();
132 LOG_CLIMATE(
"",
"Friedrich Climate",
this);
134 " Temperature range: %u to %u °F\n"
145 ESP_LOGV(TAG,
"Transmit state");
154 const auto mode = find_entry(MODES, this->
mode,
false);
160 frame[7] =
mode.has_value() ?
mode->code : BYTE7_MODE_AUTO;
161 frame[8] = fan.has_value() ? fan->code : BYTE8_FAN_AUTO;
163 frame[8] |= BYTE8_FAN_SWING;
170 ESP_LOGV(TAG,
"Transmit off");
172 uint8_t frame[STATE_MESSAGE_LENGTH_UTIL];
178 ESP_LOGV(TAG,
"Transmit message");
188 ESP_LOGV(TAG,
"Received message");
190 if (!odata.has_value())
192 const auto &d = odata->data;
194 if (odata->address != CARRIER_ADDRESS || d.size() < STATE_MESSAGE_LENGTH_UTIL || !matches_template(d.data(), 0, 2))
197 if (d.size() == STATE_MESSAGE_LENGTH_UTIL) {
199 if (d[3] != BYTE3_POWER_OFF || d[4] != 255 - d[3])
201 ESP_LOGV(TAG,
"Received off message");
208 !matches_template(d.data(), 3, 5))
212 const auto mode = find_entry(MODES, d[7],
true);
213 if (!
mode.has_value()) {
214 ESP_LOGV(TAG,
"Ignoring unknown mode 0x%02X", d[7]);
221 const uint8_t temp_code = d[6] & ~BYTE6_POWER_ON;
222 const uint8_t temp_index = reverse_nibble(temp_code);
227 const auto fan = find_entry(FANS, d[8] & ~BYTE8_FAN_SWING,
true);
ClimateMode mode
The active mode of the climate device.
optional< ClimateFanMode > fan_mode
The active fan mode of the climate device.
float target_temperature
The target temperature of the climate device.
ClimateSwingMode swing_mode
The active swing mode of the climate device.
void publish_state()
Publish the state of the climate device, to be called from integrations.
void set_temperature_unit(TemperatureUnit unit)
void transmit_state() override
Transmit via IR the state of this climate controller.
static constexpr uint8_t TEMP_STEP
static constexpr uint8_t TEMP_MAX
bool on_receive(remote_base::RemoteReceiveData src) override
Parse incoming message.
climate::ClimateTraits traits() override
void transmit_off_()
Transmit via IR power off command.
static constexpr uint8_t STATE_MESSAGE_LENGTH
void dump_config() override
static constexpr uint8_t TEMP_MIN
void transmit_(const uint8_t *data, uint8_t len)
Transmit message as IR pulses.
optional< AEHAData > decode(RemoteReceiveData src)
void encode(RemoteTransmitData *dst, const AEHAData &data)
void set_carrier_frequency(uint32_t carrier_frequency)
RemoteTransmitterBase * transmitter_
RemoteTransmitData * get_data()
constexpr float BME680_GAS_LOOKUP_TABLE_1[16] PROGMEM
@ CLIMATE_SWING_OFF
The swing mode is set to Off.
@ CLIMATE_SWING_VERTICAL
The fan mode is set to Vertical.
ClimateMode
Enum for all modes a climate device can be in.
@ CLIMATE_MODE_DRY
The climate device is set to dry/humidity mode.
@ CLIMATE_MODE_FAN_ONLY
The climate device only has the fan enabled, no heating or cooling is taking place.
@ CLIMATE_MODE_HEAT
The climate device is set to heat to reach the target temperature.
@ CLIMATE_MODE_COOL
The climate device is set to cool to reach the target temperature.
@ CLIMATE_MODE_HEAT_COOL
The climate device is set to heat/cool to reach the target temperature.
@ CLIMATE_MODE_OFF
The climate device is off.
ClimateFanMode
NOTE: If adding values, update ClimateFanModeMask in climate_traits.h to use the new last value.
@ CLIMATE_FAN_MEDIUM
The fan mode is set to Medium.
@ CLIMATE_FAN_AUTO
The fan mode is set to Auto.
@ CLIMATE_FAN_LOW
The fan mode is set to Low.
@ CLIMATE_FAN_QUIET
The fan mode is set to Quiet.
@ CLIMATE_FAN_HIGH
The fan mode is set to High.
ESPHOME_LOG_TAG(TAG, "friedrich")
void progmem_memcpy(void *dst, const void *src, size_t len)
uint8_t reverse_bits(uint8_t x)
Reverse the order of 8 bits.
uint8_t progmem_read_byte(const uint8_t *addr)