From 0d11fa61931e6ec8089b9b9963fd9ccd78bbcd73 Mon Sep 17 00:00:00 2001 From: edennelson Date: Tue, 30 Jun 2026 08:53:49 -0700 Subject: [PATCH] Fix Core room size round trip --- LEVOIT_UART.md | 2 +- components/levoit/core_commands.cpp | 4 ++-- components/levoit/core_status.cpp | 4 ++-- components/levoit/decoder_helpers.h | 16 ++++++++++++++++ components/levoit/levoit.cpp | 5 ++--- components/levoit/levoit.h | 2 +- 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/LEVOIT_UART.md b/LEVOIT_UART.md index 70c7c91..a8bb7fb 100644 --- a/LEVOIT_UART.md +++ b/LEVOIT_UART.md @@ -361,7 +361,7 @@ Room sizes are transmitted as raw integer values derived from square feet. | Vital (tag `0x10`) | `raw = round(m² × 10.764 × 1.3)` | ESP→MCU | | Core / Core600S | `raw = round(m² × 10.764 × 3.15)` | ESP→MCU | -Decode (MCU→ESP): `m² = raw / (10.764 × factor)` where factor = 1.3 (Vital) or 3.15 (Core). +Decode (MCU→ESP): `m² = raw / (10.764 × factor)` where factor = 1.3 (Vital) or 3.15 (Core). Core status values are rounded to the nearest whole m² before publishing so values encoded with `round(m² × 10.764 × 3.15)` round-trip at range edges. --- diff --git a/components/levoit/core_commands.cpp b/components/levoit/core_commands.cpp index b07ecd5..b454ccd 100644 --- a/components/levoit/core_commands.cpp +++ b/components/levoit/core_commands.cpp @@ -2,6 +2,7 @@ #include "levoit_message.h" #include "levoit.h" #include "number/levoit_number.h" +#include "decoder_helpers.h" #include "esphome/core/log.h" namespace esphome @@ -122,9 +123,8 @@ namespace esphome auto *num = self->get_number(NumberType::EFFICIENCY_ROOM_SIZE); if (num != nullptr) { - // Convert m² → raw MCU value: 1 m² = 10.764 sq ft, MCU uses sq_ft × 3.15 float m2 = num->state; - uint32_t raw = static_cast(m2 * 10.764f * 3.15f + 0.5f); + uint32_t raw = encode_core_room_size_raw(m2); uint8_t size_low = raw & 0xFF; uint8_t size_high = (raw >> 8) & 0xFF; diff --git a/components/levoit/core_status.cpp b/components/levoit/core_status.cpp index 7b9a2bc..3fcba41 100644 --- a/components/levoit/core_status.cpp +++ b/components/levoit/core_status.cpp @@ -110,7 +110,7 @@ namespace esphome bool child_lock = payload[14] != 0; uint8_t fan_auto_mode = payload[15]; uint16_t efficency_area = (uint16_t)((payload[17] << 8) | payload[16]); - float efficency_area_m2 = static_cast(efficency_area) / (10.764f * 3.15f); + float efficency_area_m2 = decode_core_room_size_m2(efficency_area); bool light_detect = payload[21] != 0; self->publish_text_sensor(TextSensorType::ERROR_MESSAGE, "Ok"); @@ -144,7 +144,7 @@ namespace esphome bool child_lock = payload[13] != 0; uint8_t fan_auto_mode = payload[14]; uint16_t efficency_area = (payload[16] << 8) | payload[15]; - float efficency_area_m2 = static_cast(efficency_area) / (10.764f * 3.15f); + float efficency_area_m2 = decode_core_room_size_m2(efficency_area); bool display_on = false; uint8_t fan_speed = 0; if (model == ModelType::CORE300S) diff --git a/components/levoit/decoder_helpers.h b/components/levoit/decoder_helpers.h index 9d85734..1e26dcb 100644 --- a/components/levoit/decoder_helpers.h +++ b/components/levoit/decoder_helpers.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace esphome { @@ -36,5 +37,20 @@ namespace esphome return std::to_string(secs) + "s"; } + static inline float core_room_size_factor() + { + return 10.764f * 3.15f; + } + + static inline uint32_t encode_core_room_size_raw(float m2) + { + return static_cast(std::round(m2 * core_room_size_factor())); + } + + static inline float decode_core_room_size_m2(uint16_t raw) + { + return std::round(static_cast(raw) / core_room_size_factor()); + } + } // namespace levoit } // namespace esphome diff --git a/components/levoit/levoit.cpp b/components/levoit/levoit.cpp index 5751c3a..7c5b000 100644 --- a/components/levoit/levoit.cpp +++ b/components/levoit/levoit.cpp @@ -126,14 +126,13 @@ namespace esphome #endif } - void Levoit::publish_number(NumberType type, uint32_t value) + void Levoit::publish_number(NumberType type, float value) { #ifdef USE_NUMBER auto *nm = numbers_[nt_idx_(type)]; if (!nm) return; - float fvalue = static_cast(value); - if (nm->has_state() && nm->state == fvalue) + if (nm->has_state() && nm->state == value) return; nm->publish_state(value); #endif diff --git a/components/levoit/levoit.h b/components/levoit/levoit.h index 8686aad..d9cd187 100644 --- a/components/levoit/levoit.h +++ b/components/levoit/levoit.h @@ -44,7 +44,7 @@ class Levoit : public Component, public uart::UARTDevice { // called by decoder when device reports status void publish_switch(SwitchType type, bool state); - void publish_number(NumberType type, uint32_t value); + void publish_number(NumberType type, float value); void publish_sensor(SensorType type, uint32_t value); void publish_select(SelectType type, uint32_t value); void publish_text_sensor(TextSensorType type, const std::string &value);