* MIELHVAC New features and bug fixes
## Changelog
### Bug Fixes
**Memory leak in `miel_hvac_pre_init()`** — `goto del` jumped past the `free(sc)` label, leaking the allocated struct on serial init failure. Replaced with explicit `delete`/`free`/`return`.
**`remotetemp_clear` semantics inverted** — variable was `true` on boot causing a CLR frame to be sent before any sensor registered. Renamed to `remotetemp_active`, initialised `false`.
**`HVACSetPurify` used wrong map** — `airdirection_map` was passed instead of `purifier_map`.
**`0x08` Set Run State flags wrong byte order** — flags are little-endian on the wire (ref: muart-group/muart-group.github.io#17). Removed `htons()` from all `0x08` flag assignments.
**`widevane_isee` false positives** — values like `0x84`/`0x85`/`0x8c` (ISEE bit + position nibble) incorrectly reported `AirDirection:"even"`. Reverted to exact-match for `0x80`, `0x28`, `0xaa`.
---
### New Features
**`0x42` HVAC Options polling** — added `miel_hvac_data_hvac_options` struct and `MIEL_HVAC_REQUEST_HVAC_OPTIONS` request. The unit is polled for Purifier, NightMode and EconoCool state. Requires short request form (len=1). Results stored in `sc_hvac_options` and published in SENSOR and HVACSETTINGS when `cap_run_state=true`.
**Run State commands (`0x41 0x08`)** — new commands `HVACSetPurify`, `HVACSetNightMode`, `HVACSetEconoCool` and `HVACSetAirDirection` sent via `0x08` on units that report `cap_run_state=true`. Optimistic update to `sc_hvac_options` applied before confirmation.
**EconoCool** — `0x08` byte 14, flag `0x10`, COOL mode only. Command `HVACSetEconoCool on|off`.
**Base Capabilities (`0x5B 0xC9`)** — queried once after connecting. Parsed into `miel_hvac_capabilities`. Results published flat inside `MiElHVAC` as `*Supported` fields. Temperature ranges published as °C. Raw packet in `CapabilitiesHex`.
**Capabilities-aware command validation** — commands blocked when unit reports feature unavailable: modes (heat/dry/fan), temperature range from capabilities, fan speeds, run state commands return `NotSupported` or `ControlNotSupported`.
**`0x42` polling skip** — skipped on units with `cap_run_state=false`, eliminating recurring timeouts.
**`miel_hvac_append_settings_json()`** — shared helper replacing ~80 lines of duplicated JSON code between SENSOR and HVACSETTINGS topics.
---
### JSON Changes
- `Power` (W) and `Energy` (kWh) published inside `MiElHVAC` and also in a separate `ENERGY{}` object outside `MiElHVAC` for Home Assistant auto-discovery
- `Purifier`, `NightMode`, `EconoCool` shown in SENSOR and HVACSETTINGS when `cap_run_state=true`; otherwise omitted
- `AirDirection` always shows current state from `0x62 0x02` regardless of control support
- `*Supported` capability fields published flat inside `MiElHVAC`: `HeatSupported`, `DrySupported`, `FanSupported`, `VaneVSupported`, `SwingSupported`, `AutoFanSupported`, `OutdoorTempSupported`, `AirDirectionSupported`, `PurifierSupported`, `NightModeSupported`, `EconoCoolSupported`
---
### Tested on
MSZ-LN25VG2W — `cap_run_state=false`, temp ranges 16–31 °C cool/auto, 10–31 °C heat, 5 fan speeds.
* Extend AirDirection capability, added web ui energy sensor, cleanup
### AirDirection — respect i-See sensor presence
`AirDirection` now requires three conditions instead of just the vertical vane capability:
- `cap_vane_v` — unit has a vertical vane
- `sc_has_isee` — i-See sensor observed at runtime (widevane ever seen with bit `0x80`, or value `0x28`/`0xaa`)
- `cap_run_state` — unit supports `0x08` for control
Resulting behaviour:
| `cap_vane_v` | `sc_has_isee` | `cap_run_state` | `AirDirection` visible | `AirDirectionSupported` |
|:-:|:-:|:-:|:-:|:-:|
| ❌ | — | — | hidden | `not_supported` |
| ✅ | ❌ | — | hidden | `not_supported` |
| ✅ | ✅ | ❌ | shown | `control_not_supported` |
| ✅ | ✅ | ✅ | shown | `on` |
Units with vertical + horizontal vanes but no i-See sensor now correctly report `AirDirectionSupported:"not_supported"` and omit `AirDirection` from both `MiElHVAC` and `HVACSettings` JSON.
### Capability field renames
For naming consistency across the `*Supported` fields:
- `cap_heat` → `cap_mode_heat`, `HeatSupported` → `ModeHeatSupported`
- `cap_dry` → `cap_mode_dry`, `DrySupported` → `ModeDrySupported`
- `cap_fan_mode` → `cap_mode_fan`, `FanSupported` → `ModeFanSupported`
- `cap_auto_fan` → `cap_fan_auto`, `AutoFanSupported` → `FanAutoSupported`
- `OutdoorTempSupported` → `OutdoorTemperatureSupported`
- `TempCool` / `TempHeat` / `TempAuto` → `SetTemperatureCoolMinMax` / `SetTemperatureHeatMinMax` / `SetTemperatureAutoMinMax`
### Energy values
- `Power` (W) and `Energy` (kWh) published both inside `MiElHVAC` and in a standard Tasmota `ENERGY{}` sub-object (`Power`/`Total`) for Home Assistant auto-discovery.
- Added Web UI rows via `FUNC_WEB_SENSOR` showing instantaneous power (W) and cumulative total (kWh) on the Tasmota main page.
### Runtime i-See detection
New `sc_has_isee` flag in `miel_hvac_softc`, set in `miel_hvac_input_settings` on the first widevane value indicating i-See state. Once set, stays set for the session.
**Practical note:** after boot, the flag starts `false`. Units with i-See that has never been activated since Tasmota started will show `AirDirection` as hidden until i-See is first used (via IR remote or `HVACSetAirDirection`). Safe default — prevents showing misleading values on units without i-See.
* MiElHVAC Full support of AirDirection control
* MiELHVAC fix globals, VLA, duplicate JSON fields and float formatting
## Summary
- **Remove file-scope globals** (`temp_type`, `remotetemp_active`,
`remotetemp_auto_clear_time`, `remotetemp_last_call_time`,
`remotetemp_half`): moved into `miel_hvac_softc` as `sc_temp_type`
and `sc_remotetemp_*`. All references updated. Eliminates potential
conflict with other drivers sharing the same translation unit.
- **Fix VLA in `miel_hvac_send`**: `char hex_d[(len + 1) * 2]` replaced
with fixed-size `(MIEL_HVAC_DATABUFLEN + 1) * 2`. Variable-length
arrays on the stack are disallowed by `-Wvla` and unreliable on
embedded targets.
- **Make `temp_type` explicit**: helper functions `miel_hvac_deg2temp`,
`miel_hvac_temp2deg`, `miel_hvac_roomtemp2deg` now take `bool
temp_type` as a parameter. Detection of the extended encoding moved
from render functions to `miel_hvac_input_data()`, removing a hidden
side effect inside JSON serialisation code.
- **Remove duplicate JSON fields**: `Purifier`, `NightMode`, `EconoCool`
were emitted twice (from both the settings block and the options
block). Options block now only emits `OptionsHex`.
- **Fix `RemoteTemperatureSensorAutoClearTime` JSON type**: was
serialised as a string (`"10000"`), now a proper JSON number (`10000`).
- **Bool consistency**: assignments `= 1` / `= 0` on `bool` fields
replaced with `= true` / `= false`.
* MiEl HVAC: sync SENSOR, HVACSettings and discovery on state change
When settings (power, mode, temp, fan, vane, etc.) are confirmed by
the unit, publish both tele/+/HVACSettings and tele/+/SENSOR so the
two topics stay consistent. Also call TasRediscover() to refresh the
retained tasmota/discovery/+/sensors snapshot used by HA on reconnect.
Apply the same treatment to Options (Purifier, NightMode, EconoCool):
when they change, update both tele/+/SENSOR and tele/+/HVACSettings
in addition to refreshing the discovery snapshot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This helps configuring input devices as they need frames of three bytes
length and need the command twice. Just calling DaliSend twice is not
enough for this due to the delay.
* Matter Zigbee bridge: route per-endpoint friendly names to correct endpoint
The Matter to Zigbee bridge mapped each Matter endpoint to a Zigbee
shortaddr only, losing endpoint information. For multi-endpoint
devices (e.g. 2-channel on/off relays), every Matter command routed
to Zigbee endpoint 1 and incoming reports updated all Matter plugins
targeting that device.
Changes in Matter_z_Zigbee.be:
* New "<device>:<N>" explicit syntax for per-endpoint targeting,
e.g. zigbee_device:"my_device:2" routes Matter to Zigbee endpoint 2.
* Per-endpoint friendly name auto-resolution as a fallback: when no
explicit ":N" is given and the config string is a non-hex name,
the mapper queries ZbName once at first resolve and walks the
response to find the source endpoint. Preserves the existing
Tasmota convention of per-endpoint friendly names set via
ZbName <dev>,<name>,<ep>.
* Outgoing: pass the original config string verbatim in the ZbSend
Device field. ZbSend's parseDeviceFromName resolves per-endpoint
friendly names natively. Adds explicit Endpoint field when known.
* Incoming: filter Matter_Zigbee.attributes_final by attr_list._src_ep
when the mapper has a known endpoint. The frame parameter is
always nil at this call site (caller passes nullptr), so the
filter relies on the attribute list's source endpoint instead.
* Boot probe (probe_zb_values) is now endpoint-aware: triggers a
ZbRead per attribute the plugin tracks for the specific endpoint.
Avoids the previous merged-state pollution where probe pushed the
same device.info() to all plugins targeting the same shortaddr.
Single-endpoint configs keep the cheap cached probe (no extra
Zigbee traffic).
Backwards compatibility preserved for shortaddr / integer / device-
level friendly name configs - default endpoint behavior is unchanged.
Tested on a 2-channel Zigbee on/off device paired to a Tasmota
Zigbee gateway, verified bidirectional in Apple Home.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Delet solidify file
---------
Co-authored-by: Paul de Monchy <paul.de.monchy@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: s-hadinger <49731213+s-hadinger@users.noreply.github.com>
On platforms without exceptions (-fno-exceptions, e.g. ESP8266),
new[] returns nullptr on allocation failure instead of throwing.
The missing NULL check caused a hard crash (load/store to address
derived from nullptr+offset) whenever the token buffer could not
be allocated.
Fix all four paths that dereference _tokens without a NULL guard,
and implement the existing TODO in parse() to ensure _token_len=0
invariant holds after OOM, consistent with the zero-error design.
* MIELHVAC New features and bug fixes
## Changelog
### Bug Fixes
**Memory leak in `miel_hvac_pre_init()`** — `goto del` jumped past the `free(sc)` label, leaking the allocated struct on serial init failure. Replaced with explicit `delete`/`free`/`return`.
**`remotetemp_clear` semantics inverted** — variable was `true` on boot causing a CLR frame to be sent before any sensor registered. Renamed to `remotetemp_active`, initialised `false`.
**`HVACSetPurify` used wrong map** — `airdirection_map` was passed instead of `purifier_map`.
**`0x08` Set Run State flags wrong byte order** — flags are little-endian on the wire (ref: muart-group/muart-group.github.io#17). Removed `htons()` from all `0x08` flag assignments.
**`widevane_isee` false positives** — values like `0x84`/`0x85`/`0x8c` (ISEE bit + position nibble) incorrectly reported `AirDirection:"even"`. Reverted to exact-match for `0x80`, `0x28`, `0xaa`.
---
### New Features
**`0x42` HVAC Options polling** — added `miel_hvac_data_hvac_options` struct and `MIEL_HVAC_REQUEST_HVAC_OPTIONS` request. The unit is polled for Purifier, NightMode and EconoCool state. Requires short request form (len=1). Results stored in `sc_hvac_options` and published in SENSOR and HVACSETTINGS when `cap_run_state=true`.
**Run State commands (`0x41 0x08`)** — new commands `HVACSetPurify`, `HVACSetNightMode`, `HVACSetEconoCool` and `HVACSetAirDirection` sent via `0x08` on units that report `cap_run_state=true`. Optimistic update to `sc_hvac_options` applied before confirmation.
**EconoCool** — `0x08` byte 14, flag `0x10`, COOL mode only. Command `HVACSetEconoCool on|off`.
**Base Capabilities (`0x5B 0xC9`)** — queried once after connecting. Parsed into `miel_hvac_capabilities`. Results published flat inside `MiElHVAC` as `*Supported` fields. Temperature ranges published as °C. Raw packet in `CapabilitiesHex`.
**Capabilities-aware command validation** — commands blocked when unit reports feature unavailable: modes (heat/dry/fan), temperature range from capabilities, fan speeds, run state commands return `NotSupported` or `ControlNotSupported`.
**`0x42` polling skip** — skipped on units with `cap_run_state=false`, eliminating recurring timeouts.
**`miel_hvac_append_settings_json()`** — shared helper replacing ~80 lines of duplicated JSON code between SENSOR and HVACSETTINGS topics.
---
### JSON Changes
- `Power` (W) and `Energy` (kWh) published inside `MiElHVAC` and also in a separate `ENERGY{}` object outside `MiElHVAC` for Home Assistant auto-discovery
- `Purifier`, `NightMode`, `EconoCool` shown in SENSOR and HVACSETTINGS when `cap_run_state=true`; otherwise omitted
- `AirDirection` always shows current state from `0x62 0x02` regardless of control support
- `*Supported` capability fields published flat inside `MiElHVAC`: `HeatSupported`, `DrySupported`, `FanSupported`, `VaneVSupported`, `SwingSupported`, `AutoFanSupported`, `OutdoorTempSupported`, `AirDirectionSupported`, `PurifierSupported`, `NightModeSupported`, `EconoCoolSupported`
---
### Tested on
MSZ-LN25VG2W — `cap_run_state=false`, temp ranges 16–31 °C cool/auto, 10–31 °C heat, 5 fan speeds.
* Extend AirDirection capability, added web ui energy sensor, cleanup
### AirDirection — respect i-See sensor presence
`AirDirection` now requires three conditions instead of just the vertical vane capability:
- `cap_vane_v` — unit has a vertical vane
- `sc_has_isee` — i-See sensor observed at runtime (widevane ever seen with bit `0x80`, or value `0x28`/`0xaa`)
- `cap_run_state` — unit supports `0x08` for control
Resulting behaviour:
| `cap_vane_v` | `sc_has_isee` | `cap_run_state` | `AirDirection` visible | `AirDirectionSupported` |
|:-:|:-:|:-:|:-:|:-:|
| ❌ | — | — | hidden | `not_supported` |
| ✅ | ❌ | — | hidden | `not_supported` |
| ✅ | ✅ | ❌ | shown | `control_not_supported` |
| ✅ | ✅ | ✅ | shown | `on` |
Units with vertical + horizontal vanes but no i-See sensor now correctly report `AirDirectionSupported:"not_supported"` and omit `AirDirection` from both `MiElHVAC` and `HVACSettings` JSON.
### Capability field renames
For naming consistency across the `*Supported` fields:
- `cap_heat` → `cap_mode_heat`, `HeatSupported` → `ModeHeatSupported`
- `cap_dry` → `cap_mode_dry`, `DrySupported` → `ModeDrySupported`
- `cap_fan_mode` → `cap_mode_fan`, `FanSupported` → `ModeFanSupported`
- `cap_auto_fan` → `cap_fan_auto`, `AutoFanSupported` → `FanAutoSupported`
- `OutdoorTempSupported` → `OutdoorTemperatureSupported`
- `TempCool` / `TempHeat` / `TempAuto` → `SetTemperatureCoolMinMax` / `SetTemperatureHeatMinMax` / `SetTemperatureAutoMinMax`
### Energy values
- `Power` (W) and `Energy` (kWh) published both inside `MiElHVAC` and in a standard Tasmota `ENERGY{}` sub-object (`Power`/`Total`) for Home Assistant auto-discovery.
- Added Web UI rows via `FUNC_WEB_SENSOR` showing instantaneous power (W) and cumulative total (kWh) on the Tasmota main page.
### Runtime i-See detection
New `sc_has_isee` flag in `miel_hvac_softc`, set in `miel_hvac_input_settings` on the first widevane value indicating i-See state. Once set, stays set for the session.
**Practical note:** after boot, the flag starts `false`. Units with i-See that has never been activated since Tasmota started will show `AirDirection` as hidden until i-See is first used (via IR remote or `HVACSetAirDirection`). Safe default — prevents showing misleading values on units without i-See.
* MiElHVAC Full support of AirDirection control
* MiELHVAC fix globals, VLA, duplicate JSON fields and float formatting
## Summary
- **Remove file-scope globals** (`temp_type`, `remotetemp_active`,
`remotetemp_auto_clear_time`, `remotetemp_last_call_time`,
`remotetemp_half`): moved into `miel_hvac_softc` as `sc_temp_type`
and `sc_remotetemp_*`. All references updated. Eliminates potential
conflict with other drivers sharing the same translation unit.
- **Fix VLA in `miel_hvac_send`**: `char hex_d[(len + 1) * 2]` replaced
with fixed-size `(MIEL_HVAC_DATABUFLEN + 1) * 2`. Variable-length
arrays on the stack are disallowed by `-Wvla` and unreliable on
embedded targets.
- **Make `temp_type` explicit**: helper functions `miel_hvac_deg2temp`,
`miel_hvac_temp2deg`, `miel_hvac_roomtemp2deg` now take `bool
temp_type` as a parameter. Detection of the extended encoding moved
from render functions to `miel_hvac_input_data()`, removing a hidden
side effect inside JSON serialisation code.
- **Remove duplicate JSON fields**: `Purifier`, `NightMode`, `EconoCool`
were emitted twice (from both the settings block and the options
block). Options block now only emits `OptionsHex`.
- **Fix `RemoteTemperatureSensorAutoClearTime` JSON type**: was
serialised as a string (`"10000"`), now a proper JSON number (`10000`).
- **Bool consistency**: assignments `= 1` / `= 0` on `bool` fields
replaced with `= true` / `= false`.
* ESP8266: fix ESP_getMaxAllocHeap() and ESP_getHeapFragmentation()
Both functions returned wrong values: ESP_getMaxAllocHeap() returned
ESP.getFreeHeap() (total free, not largest contiguous block);
ESP_getHeapFragmentation() read ummHeapInfo.maxFreeContiguousBlocks,
which is only valid immediately after a umm_info() heap walk.
Fix: cache the result of umm_max_block_size() in ESP_UpdateHeapMetrics().
The cache is refreshed once per second when SetOption130 is active, and
on demand in CmndStatus() before Status 4 is output. Both getter functions
read the cached value; the call site overhead is a single integer read.
umm_max_block_size() is unconditionally available (UMM_INFO is hardcoded
in the Arduino ESP8266 umm_malloc_cfg.h), so no build flags are required.
Status 4 (StatusMEM) gains two ESP8266-specific fields: MaxFreeBlock (KB)
and Frag (%).
* ESP8266: add heap OOM diagnostics, Status 4 fields, Status 44 dump
OOM event monitoring (requires UMM_INLINE_METRICS or UMM_STATS_FULL):
- ESP_HeapOomCheck(): called once per second; logs the OOM counter delta
when the counter changes ("OOM: count N (+M)")
- ESP_HeapOomTest(): logs current OOM count on demand
Status 4 (StatusMEM) gains additional ESP8266-specific fields when the
corresponding build flags are active:
- OomCount: cumulative out-of-memory events (UMM_INLINE_METRICS or
UMM_STATS_FULL)
- HeapLwm (KB): heap low-watermark since boot (UMM_STATS_FULL)
- MaxAllocSz (bytes): peak single allocation size (UMM_STATS_FULL)
Status 44 (ESP8266-only diagnostic command):
- Triggers umm_info(nullptr, true) to print a full heap block map to
the serial console
- Calls ESP_HeapOomTest() to log the current OOM count
- Returns {"Status44":{"HeapDump":"serial"}}
- Status 44 is accepted regardless of MAX_STATUS
Build flags UMM_STATS_FULL and UMM_INLINE_METRICS can be enabled via
platformio_override.ini build_flags; documented in
platformio_override_sample.ini.
* Replace old software-defined library arduino-vid6608 with hw-defined esp-32-vid6608
* VID6608: Rework integration to allow select RMT/SW method by using the `VID6608_RMT` option
* VID6608: Tune library inclusion for RMT version
* The RMT version is not supported on ESP32-C2, library excluded
* Add more clear error message, if RMT is requested, but not supported