ESPHome 2026.8.0b4
Loading...
Searching...
No Matches
mitsubishi_cn105_properties.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <cmath>
5#include <cstdint>
6#include <limits>
7#include <type_traits>
8#include <utility>
9#include "mitsubishi_cn105.h"
10
12
13template<auto Unknown, size_t N> struct LookupMap {
14 using value_type = decltype(Unknown);
15 const std::array<value_type, N> table;
16
17 constexpr value_type lookup(uint8_t raw) const { return (raw < N) ? this->table[raw] : Unknown; }
18
19 constexpr bool reverse_lookup(value_type value, uint8_t &out) const {
20 static_assert(N <= std::numeric_limits<uint8_t>::max());
21 if (value == Unknown) {
22 return false;
23 }
24 for (uint8_t i = 0; i < static_cast<uint8_t>(N); ++i) {
25 if (this->table[i] == value) {
26 out = i;
27 return true;
28 }
29 }
30 return false;
31 }
32};
33
34template<auto Unknown, class T, std::size_t N> static constexpr auto make_map(const T (&values)[N]) {
35 return LookupMap<Unknown, N>{std::to_array(values)};
36}
37
38struct Property {
42
43 struct Power {
44 static constexpr auto ID = PropertyId::POWER;
45
46 static void decode_context(PropertyContext &ctx, const uint8_t *payload) {}
47
48 static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx) {
49 status.power_on = payload[2] != 0;
50 }
51
52 static void encode(uint8_t *payload, const Status &status, const PropertyContext &ctx) {
53 payload[1] |= 0x01;
54 payload[3] = status.power_on ? 0x01 : 0x00;
55 }
56 };
57
58 struct Temperature {
59 struct Target {
60 static constexpr auto ID = PropertyId::TEMPERATURE;
61 static constexpr uint8_t TARGET_TEMPERATURE_ENC_A_OFFSET = 31;
62
63 static void decode_context(PropertyContext &ctx, const uint8_t *payload) {
64 ctx.use_temperature_encoding_b = payload[10] != 0;
65 }
66
67 static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx) {
68 status.target_temperature = Temperature::decode(-payload[4], payload[10], TARGET_TEMPERATURE_ENC_A_OFFSET);
69 }
70
71 static void encode(uint8_t *payload, const Status &status, const PropertyContext &ctx) {
72 payload[1] |= 0x04;
74 payload[14] = static_cast<uint8_t>(std::round(status.target_temperature * 2.0f) + 128);
75 } else {
76 payload[5] = static_cast<uint8_t>(TARGET_TEMPERATURE_ENC_A_OFFSET - std::round(status.target_temperature));
77 }
78 }
79 };
80
81 struct Room {
82 static void decode_context(PropertyContext &ctx, const uint8_t *payload) {}
83
84 static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx) {
85 status.room_temperature = Temperature::decode(payload[2], payload[5], 10);
86 }
87 };
88
89 struct Remote {
90 static constexpr auto ID = PropertyId::REMOTE_TEMPERATURE;
91
92 static void encode(uint8_t *payload, uint8_t remote_temperature_half_deg, const PropertyContext &) {
93 if (remote_temperature_half_deg == MitsubishiCN105::REMOTE_TEMPERATURE_DISABLED) {
94 payload[3] = 0x80;
95 } else {
96 payload[1] = 0x01;
97 payload[2] = static_cast<uint8_t>(remote_temperature_half_deg - 16);
98 payload[3] = static_cast<uint8_t>(remote_temperature_half_deg + 128);
99 }
100 }
101 };
102
103 protected:
104 static constexpr float decode(int temp_a, int temp_b, int delta) {
105 return temp_b != 0 ? (temp_b - 128) / 2.0f : delta + temp_a;
106 }
107 };
108
109 template<typename Derived, auto Field> struct Lookup {
110 using Value = std::remove_cvref_t<decltype(std::declval<Status>().*Field)>;
111
112 static void decode_context(PropertyContext &ctx, const uint8_t *payload) {}
113
114 static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx) {
115 status.*Field = Derived::MAP.lookup(Derived::decode_raw(payload, ctx));
116 }
117
118 static void encode(uint8_t *payload, const Status &status, const PropertyContext &ctx) {
119 uint8_t raw;
120 if (Derived::MAP.reverse_lookup(status.*Field, raw)) {
121 Derived::encode_raw(payload, raw, ctx);
122 }
123 }
124
125 template<typename Mask> static bool validate_and_set(Value value, Status &status, Mask &mask) {
126 uint8_t raw;
127 if (!Derived::MAP.reverse_lookup(value, raw)) {
128 return false;
129 }
130 status.*Field = value;
131 mask.set(Derived::ID);
132 return true;
133 }
134
135 private:
136 friend Derived;
137 constexpr Lookup() = default;
138 };
139
140 struct Mode : Lookup<Mode, &Status::mode> {
141 static constexpr auto ID = PropertyId::MODE;
142 static constexpr auto MAP = make_map<MitsubishiCN105::Mode::UNKNOWN>({
152 });
153
154 static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx) {
155 const bool i_see = payload[3] > 0x08;
156 return payload[3] - (i_see ? 0x08 : 0);
157 }
158
159 static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &) {
160 payload[1] |= 0x02;
161 payload[4] = raw;
162 }
163 };
164
165 struct FanMode : Lookup<FanMode, &Status::fan_mode> {
166 static constexpr auto ID = PropertyId::FAN;
167 static constexpr auto MAP = make_map<MitsubishiCN105::FanMode::UNKNOWN>({
175 });
176
177 static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx) { return payload[5]; }
178
179 static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &) {
180 payload[1] |= 0x08;
181 payload[6] = raw;
182 }
183 };
184
185 struct VaneMode : Lookup<VaneMode, &Status::vane_mode> {
186 static constexpr auto ID = PropertyId::VANE;
187 static constexpr auto MAP = make_map<MitsubishiCN105::VaneMode::UNKNOWN>({
196 });
197
198 static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx) { return payload[6]; }
199
200 static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &) {
201 payload[1] |= 0x10;
202 payload[7] = raw;
203 }
204 };
205
206 struct WideVaneMode : Lookup<WideVaneMode, &Status::wide_vane_mode> {
207 static constexpr auto ID = PropertyId::WIDE_VANE;
208 static constexpr auto MAP = make_map<MitsubishiCN105::WideVaneMode::UNKNOWN>({
222 });
223
224 static void decode_context(PropertyContext &ctx, const uint8_t *payload) {
225 ctx.set_wide_vane_high_bit = (payload[9] & 0xF0) == 0x80;
226 }
227
228 static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx) { return payload[9] & 0x0F; }
229
230 static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &ctx) {
231 payload[2] |= 0x01;
232 payload[13] = ctx.set_wide_vane_high_bit ? raw | 0x80 : raw;
233 }
234 };
235
236 template<typename Mask> struct Decoder {
237 const std::span<const uint8_t> payload;
239 const Mask &pending_writes;
240
241 bool ESPHOME_ALWAYS_INLINE decode_settings(Status &status) {
242 if (this->payload.size() <= 10) {
243 return false;
244 }
246 return true;
247 }
248
249 bool ESPHOME_ALWAYS_INLINE decode_room_temperature(Status &status) {
250 if (this->payload.size() <= 5) {
251 return false;
252 }
253 this->decode_<Temperature::Room>(status);
254 return true;
255 }
256
257 protected:
258 template<typename T, typename Out> ESPHOME_ALWAYS_INLINE void decode_one_(Out &out) {
259 T::decode_context(this->context, this->payload.data());
260 if constexpr (requires { T::ID; }) {
261 if (this->pending_writes.contains(T::ID)) {
262 return;
263 }
264 }
265 T::decode(out, this->payload.data(), this->context);
266 }
267
268 template<typename... T, typename Out> void ESPHOME_ALWAYS_INLINE decode_(Out &out) {
269 (this->decode_one_<T>(out), ...);
270 }
271 };
272
273 template<typename Mask> struct Encoder {
274 uint8_t *payload;
277
278 void ESPHOME_ALWAYS_INLINE encode_settings(const Status &status) {
279 this->payload[0] = 0x01;
281 }
282
283 void ESPHOME_ALWAYS_INLINE encode_remote_temperature(uint8_t remote_temperature_half_deg) {
284 this->payload[0] = 0x07;
285 this->encode_and_clear_<Temperature::Remote>(remote_temperature_half_deg);
286 }
287
288 protected:
289 template<typename... T, typename In> void ESPHOME_ALWAYS_INLINE encode_and_clear_(const In &in) {
290 (this->encode_one_<T>(in), ...);
291 (this->pending_writes.clear(T::ID), ...);
292 }
293
294 template<typename T, typename In> void encode_one_(const In &in) {
295 if (this->pending_writes.contains(T::ID)) {
296 T::encode(this->payload, in, this->context);
297 }
298 }
299 };
300};
301
302} // namespace esphome::mitsubishi_cn105
uint8_t raw[35]
Definition bl0939.h:0
uint8_t status
Definition bl0942.h:8
static constexpr uint8_t REMOTE_TEMPERATURE_DISABLED
constexpr value_type lookup(uint8_t raw) const
constexpr bool reverse_lookup(value_type value, uint8_t &out) const
const std::array< value_type, N > table
bool ESPHOME_ALWAYS_INLINE decode_settings(Status &status)
bool ESPHOME_ALWAYS_INLINE decode_room_temperature(Status &status)
void ESPHOME_ALWAYS_INLINE encode_remote_temperature(uint8_t remote_temperature_half_deg)
void ESPHOME_ALWAYS_INLINE encode_settings(const Status &status)
void ESPHOME_ALWAYS_INLINE encode_and_clear_(const In &in)
static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &)
static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx)
static bool validate_and_set(Value value, Status &status, Mask &mask)
std::remove_cvref_t< decltype(std::declval< Status >().*Field)> Value
static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx)
static void encode(uint8_t *payload, const Status &status, const PropertyContext &ctx)
static void decode_context(PropertyContext &ctx, const uint8_t *payload)
static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx)
static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &)
static void encode(uint8_t *payload, const Status &status, const PropertyContext &ctx)
static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx)
static void decode_context(PropertyContext &ctx, const uint8_t *payload)
static void encode(uint8_t *payload, uint8_t remote_temperature_half_deg, const PropertyContext &)
static void decode_context(PropertyContext &ctx, const uint8_t *payload)
static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx)
static void encode(uint8_t *payload, const Status &status, const PropertyContext &ctx)
static void decode_context(PropertyContext &ctx, const uint8_t *payload)
static void decode(Status &status, const uint8_t *payload, const PropertyContext &ctx)
static constexpr float decode(int temp_a, int temp_b, int delta)
static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx)
static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &)
static void decode_context(PropertyContext &ctx, const uint8_t *payload)
static void encode_raw(uint8_t *payload, uint8_t raw, const PropertyContext &ctx)
static uint8_t decode_raw(const uint8_t *payload, const PropertyContext &ctx)