12static constexpr uint32_t RESPONSE_TIMEOUT_MS = 2000;
14static constexpr size_t REQUEST_PAYLOAD_LEN = 0x10;
15static constexpr size_t HEADER_LEN = 5;
16static constexpr uint8_t PREAMBLE = 0xFC;
17static constexpr uint8_t HEADER_BYTE_1 = 0x01;
18static constexpr uint8_t HEADER_BYTE_2 = 0x30;
20static constexpr uint8_t PACKET_TYPE_CONNECT_REQUEST = 0x5A;
21static constexpr uint8_t PACKET_TYPE_CONNECT_RESPONSE = 0x7A;
22static constexpr std::array<uint8_t, 2> CONNECT_REQUEST_PAYLOAD = {0xCA, 0x01};
24static constexpr uint8_t PACKET_TYPE_STATUS_REQUEST = 0x42;
25static constexpr uint8_t PACKET_TYPE_STATUS_RESPONSE = 0x62;
26static constexpr uint8_t STATUS_MSG_SETTINGS = 0x02;
27static constexpr uint8_t STATUS_MSG_TELEMETRY = 0x03;
29static constexpr uint8_t PACKET_TYPE_WRITE_SETTINGS_REQUEST = 0x41;
30static constexpr uint8_t PACKET_TYPE_WRITE_SETTINGS_RESPONSE = 0x61;
32static constexpr uint8_t
checksum(
const uint8_t *bytes,
size_t length) {
36template<std::
size_t PayloadSize>
37static constexpr auto make_packet(uint8_t
type,
const std::array<uint8_t, PayloadSize> &payload) {
38 const size_t full_len = PayloadSize + HEADER_LEN + 1;
39 std::array<uint8_t, full_len> packet{PREAMBLE,
type, HEADER_BYTE_1, HEADER_BYTE_2,
static_cast<uint8_t
>(PayloadSize)};
40 std::copy_n(payload.begin(), PayloadSize, packet.begin() + HEADER_LEN);
41 packet.back() =
checksum(packet.data(), packet.size() - 1);
45static constexpr auto CONNECT_PACKET = make_packet(PACKET_TYPE_CONNECT_REQUEST, CONNECT_REQUEST_PAYLOAD);
217 this->
send_packet_(make_packet(PACKET_TYPE_STATUS_REQUEST, payload));
222 case PACKET_TYPE_CONNECT_RESPONSE:
226 case PACKET_TYPE_STATUS_RESPONSE:
229 case PACKET_TYPE_WRITE_SETTINGS_RESPONSE:
234 ESP_LOGVV(TAG,
"RX unknown packet type 0x%02X",
type);
241 ESP_LOGVV(TAG,
"RX status packet too short");
245 const auto previous = this->
status_;
246 const auto msg_type = payload[0];
270 case STATUS_MSG_SETTINGS:
271 if (!decoder.decode_settings(this->status_)) {
272 ESP_LOGVV(TAG,
"RX settings payload too short");
277 case STATUS_MSG_TELEMETRY:
278 if (!decoder.decode_room_temperature(this->status_)) {
279 ESP_LOGVV(TAG,
"RX telemetry payload too short");
286 ESP_LOGVV(TAG,
"RX unsupported status msg type 0x%02X", msg_type);
293 ESP_LOGD(TAG,
"Ignoring NaN remote temperature");
297 ESP_LOGD(TAG,
"Ignoring out-of-range remote temperature: %.1f",
temperature);
328 ESP_LOGD(TAG,
"Ignoring invalid mode: %u",
static_cast<uint8_t
>(
mode));
334 ESP_LOGD(TAG,
"Ignoring invalid fan mode: %u",
static_cast<uint8_t
>(
fan_mode));
340 ESP_LOGD(TAG,
"Ignoring invalid vane mode: %u",
static_cast<uint8_t
>(vane_mode));
346 ESP_LOGD(TAG,
"Ignoring invalid wide vane mode: %u",
static_cast<uint8_t
>(wide_vane_mode));
351 std::array<uint8_t, REQUEST_PAYLOAD_LEN> payload{};
358 encoder.encode_settings(this->
status_);
361 this->
send_packet_(make_packet(PACKET_TYPE_WRITE_SETTINGS_REQUEST, payload));
367 return LOG_STR(
"Not connected");
369 return LOG_STR(
"Connecting");
371 return LOG_STR(
"Connected");
373 return LOG_STR(
"UpdatingStatus");
375 return LOG_STR(
"StatusUpdated");
377 return LOG_STR(
"DeferredStatusRequest");
379 return LOG_STR(
"ScheduleNextStatusUpdate");
381 return LOG_STR(
"WaitingForScheduledStatusUpdate");
383 return LOG_STR(
"ApplyingSettings");
385 return LOG_STR(
"SettingsApplied");
387 return LOG_STR(
"ReadTimeout");
389 return LOG_STR(
"Unknown");
392template<
typename Callback>
394 uint8_t watchdog = 64;
395 while (device.
available() > 0 && watchdog-- > 0) {
396 uint8_t &value = this->read_buffer_[this->read_pos_];
398 ESP_LOGW(TAG,
"UART read failed while data available");
402 switch (++this->read_pos_) {
404 if (value != PREAMBLE) {
413 if (value != HEADER_BYTE_1) {
419 if (value != HEADER_BYTE_2) {
425 static_assert(READ_BUFFER_SIZE > HEADER_LEN);
426 if (this->read_buffer_[HEADER_LEN - 1] >= READ_BUFFER_SIZE - HEADER_LEN) {
435 const size_t len_without_checksum = HEADER_LEN +
static_cast<size_t>(this->read_buffer_[HEADER_LEN - 1]);
436 if (this->read_pos_ <= len_without_checksum) {
440 if (
checksum(this->read_buffer_, len_without_checksum) != value) {
446 const bool processed =
447 callback(this->read_buffer_[1], this->read_buffer_ + HEADER_LEN, len_without_checksum - HEADER_LEN);
456 dump_buffer_vv(prefix, this->read_buffer_, this->read_pos_);
461#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
BedjetMode mode
BedJet operating mode.
void reset_and_dump_buffer_(const char *prefix)
bool read_and_parse(uart::UARTDevice &device, Callback &&callback)
static void dump_buffer_vv(const char *prefix, const uint8_t *data, size_t len)
bool should_request_telemetry_() const
bool process_status_packet_(const uint8_t *payload, size_t len)
uint32_t operation_start_ms_
static bool should_transition(State from, State to)
uint8_t current_status_msg_type_
void set_state_(State new_state)
PropertyContext property_context_
void set_remote_temperature_half_deg_(uint8_t temperature_half_deg)
bool process_rx_packet_(uint8_t type, const uint8_t *payload, size_t len)
uint32_t status_update_wait_credit_ms_
bool is_status_initialized() const
bool is_telemetry_polling_enabled() const
void clear_remote_temperature()
uart::UARTDevice & device_
void did_transition_(State to)
void set_remote_temperature(float temperature)
bool has_timed_out_(uint32_t timeout) const
static constexpr uint8_t REMOTE_TEMPERATURE_DISABLED
uint32_t telemetry_request_min_interval_ms_
std::optional< uint32_t > last_telemetry_update_ms_
UpdateFlags pending_updates_
@ WAITING_FOR_SCHEDULED_STATUS_UPDATE
@ DEFERRED_STATUS_REQUEST
@ SCHEDULE_NEXT_STATUS_UPDATE
void send_packet_(std::span< const uint8_t > packet)
void set_power(bool power_on)
static const LogString * state_to_string(State state)
void set_wide_vane_mode(WideVaneMode mode)
void set_target_temperature(float target_temperature)
uint32_t update_interval_ms_
void set_fan_mode(FanMode fan_mode)
bool parse_status_payload_(uint8_t msg_type, const uint8_t *payload, size_t len)
uint8_t remote_temperature_half_deg_
FrameParser frame_parser_
void set_vane_mode(VaneMode vane_mode)
bool read_byte(uint8_t *data)
void write_array(const uint8_t *data, size_t len)
ESPHOME_LOG_TAG(TAG, "mitsubishi_cn105.driver")
uint32_t get_loop_time_ms()
constexpr uint8_t sum_bytes(const uint8_t *data, size_t len, uint8_t sum=0)
Add up the bytes of data with size len, truncated to 8 bits: the checksum many serial and IR protocol...
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Lightweight type-erased callback (8 bytes on 32-bit) that avoids std::function overhead.
WideVaneMode wide_vane_mode
bool contains_only(PropertyId id) const
static bool validate_and_set(Value value, Status &status, Mask &mask)