Commit Graph
21611 Commits
Author SHA1 Message Date
Theo Arends 50d9e8a13c Add support for M5Stack Unit6CL display 2026-09-11 09:50:05 +02:00
SteWers 5ef80a538e [MI32BLE] Add LYWSD02MMC unit/battery support (#25022) 2026-09-11 08:47:55 +02:00
SteWers 130d5342b1 [MI32BLE] Improve logging and command responses (#25021) 2026-09-10 13:33:46 +02:00
SteWers 9068fd7313 Store BLE security bonds in UfsJsonSettings (#25015)
* Store BLE security bonds in UfsJsonSettings

Store BLE security bonds in `UfsJsonSettings`, as promised in PR #25008

* Optimize LTK storage
2026-09-10 13:24:41 +02:00
Theo Arends d96c10dbad Fix Config Backup for Shutters on ESP32 (#25016) 2026-09-09 12:11:13 +02:00
Theo Arends bf5d60e3dc Use Tasmota seperator function 2026-09-09 11:25:36 +02:00
SteWers 211691d5fb [MI32BLE] Change RSSI to general format (#25014)
* [MI32BLE] Change RSSI to general format

Change RSSI to general format `xx% (-yy dBm)`

* Separate type
2026-09-08 09:12:36 +02:00
Grzegorz cb836456a4 MiEL HVAC: add a web config page for the Modbus RTU slave (#25018)
Configure the Modbus RTU slave from the web UI instead of the console, the
same way MQTT is set up.

- a "Modbus RTU" button on the Configuration menu, next to "MQTT", built
  only with USE_MIEL_HVAC_MODBUS_SLAVE on ESP32
- the page has an "Enable Modbus RTU" checkbox plus address, baudrate and
  serial config, laid out like the MQTT and Logging pages. Save runs the
  HVACModbus* commands, which apply live, and returns to the Configuration
  menu. No reboot. A wrapped note appears when the MB Rx/Tx GPIOs are
  unassigned, without widening the page.
- a "Modbus" sticker on the main-page status line while the slave is running

No core files touched. The console commands are unchanged.
2026-09-08 09:10:00 +02:00
Grzegorz 213d4e43b6 MiEL HVAC: publish HVACSettings after an optimistic settings apply (#25017)
Follow-up to #25004. Since that PR copies an outgoing 0x41 set-settings
request into sc_settings immediately, the confirming 0x62 0x02 normally
equals sc_settings, so the memcmp() in miel_hvac_input_settings() no
longer fires and HVACSettings / SENSOR were not published after an
HVACSet* command until the next TelePeriod (reported by @mamrai1).

Publish HVACSettings + SENSOR right after the optimistic apply. If the
unit rejects or modifies the request its 0x62 0x02 still differs from
sc_settings and the existing comparison republishes the corrected state.
2026-09-08 09:09:38 +02:00
Theo Arends 7e51b9e87d Add SSD1306 SPI support 2026-09-07 16:05:14 +02:00
Grzegorz 76eafebb51 MiEL HVAC: add 0x62 0x04 Get Error State to SENSOR and the Modbus slave (#25011)
Poll and parse the 0x04 Get Error State response so a faulted indoor unit is
visible from SENSOR / MQTT and over the Modbus slave.

- MIEL_HVAC_REQUEST_ERROR / MIEL_HVAC_DATA_T_ERROR 0x04, struct
  miel_hvac_data_error (code bytes 4-5, packed two-char code byte 6), sc_error
  slot, parser case and one poll-rotation slot after room temp. Units that do
  not implement 0x04 time out via the existing p_tmo path.
- SENSOR: ErrorState (on unless code 8000), ErrorCode (packed BCD, 8000 = no
  error, 6999 = bad indoor-unit comms per spec), ErrorShort (decoded two-char
  code) and ErrorHex. miel_hvac_error_shortcode() decodes frame byte 6.
- Modbus: input regs 0x0054/0x0055 (PLC 30085/30086) and their FC03 mirror
  0x0018/0x0019 (PLC 40025/40026). miel_hvac_mb_bcd16() converts the packed-BCD
  wire value so a PLC reads 8000, not 0x8000.
- The register-map comment block now gives every Modbus address in both the raw
  0-based offset and the 5-digit Modicon / PLC form.
2026-09-07 13:50:51 +02:00
GrzegorzandTheo Arends 633895a282 MiEL HVAC: hide the redundant power toggle from the web UI (#25005)
The web control panel's Mode segment has its own Off button, so the
generic power toggle button and the ON/OFF state row are duplicates.
Hide them with a scoped stylesheet from FUNC_WEB_ADD_MAIN_BUTTON; the
POWER command and its MQTT/HA state sync are unchanged.

Co-authored-by: Theo Arends <11044339+arendst@users.noreply.github.com>
2026-09-07 11:01:24 +02:00
Grzegorz af0aa1eb99 MiEL HVAC: fix HVACSetProhibit, add it to the web panel, apply sent changes optimistically (#25004)
- HVACSetProhibit (and the Modbus prohibit register) never reached the
  unit: the 0x41 set-settings update flag was 1<<13 (0x0020 on the wire)
  but must be 1<<14 (0x0040), and the lock byte belongs at payload
  offset 11, not 8.
- add a Prohibit select to the web control panel; give
  miel_hvac_web_optlabel() a '_'->space fallback.
- after sending a 0x41 settings update, reflect the sent fields in
  sc_settings right away so the web panel sync, the Modbus registers and
  SENSOR show the intent instead of the pre-change state for the ~1s
  until the unit confirms - fixes a control (or a PLC reading back over
  Modbus) snapping to its previous value. The unit's next 0x62 wins if
  it rejects the change.
2026-09-07 11:00:27 +02:00
SteWers da3bbf3658 Add BLE pairing to support newer EQ3 TRV firmware (#25008)
* Add BLE pairing to support newer EQ3 TRV firmware

* Verify fwrite result when saving BLE data
2026-09-07 11:00:02 +02:00
Theo Arends a245189808 Fix BLE MI32 unwanted dot/comma replacement (#25009) 2026-09-07 10:46:31 +02:00
s-hadinger 9fac74bac5 Berry rare register allocation bug (#25010) 2026-09-06 13:04:54 +02:00
Theo Arends 143409151c Update change logs 2026-09-05 14:22:44 +02:00
CT Tsai 6ec914b198 Fix Zigbee deferred timer use after free, and the truncated backtrace that hid it (#24979)
* Keep the backtrace going when the crash pc is not code

An instruction fetch exception leaves pc pointing at the bad address the CPU
jumped to, so the executable check on the first frame declares the backtrace
corrupted and Status 12 reports a single call chain entry that only repeats EPC.
a0 and a1 are still valid there, so the walk can recover the callers, which is
exactly what identifies the code that used the bad pointer.

esp_backtrace_print_from_frame() skips the same check for EXCCAUSE_INSTR_PROHIBITED;
do the same here and include EXCCAUSE_INSTR_ERROR, seen on a device that jumped
into DRAM.

* Fix use after free in the Zigbee deferred timer list

Z_Devices::runTimer() runs the timer callbacks while iterating _deferred.
Publishing attributes from Z_PublishAttributes() runs the Rules and the Berry
handlers, which can send a Zigbee command; zigbeeZCLSendCmd() then re-arms the
read-back and reachability timers of the target device, and setTimer() clears
the previous ones of the same category. Freeing an element leaves the next
pointer cached by the LList iterator dangling, so the next turn of the loop
reads a freed node and calls whatever the allocator left in func.

On a ZBBridge Pro with 55 devices and rules that send a command on ZbReceived
this crashed about once a day, always as an instruction fetch to an address that
is nowhere in the image:

  Exception 20 InstrFetchProhibited EPC 0xc88f8924
  CallChain 488f8921 4012271e 400df4b8 400da20a 40157d20
            bad ptr, XdrvCall, XdrvXsnsCall, Scheduler, loopTask

Detach the due timers into a local list first and run them afterwards, so no
iterator is held across a callback. The removal in the first loop only touches
the current element, which the iterator already handles.
2026-09-05 14:09:00 +02:00
gudinis e17a83c510 Matter: fix autoconfiguration after configuration reset (#24997) 2026-09-05 13:56:40 +02:00
Theo Arends 40c24e193e Update change logs 2026-09-04 11:16:25 +02:00
Grzegorz 141c0ad6f4 MiEL HVAC Modbus: length-based framing, queue writes, FC03 sensor mirror (#24993)
* 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`.

* MiElHVAC auto-enable i-See widevane when setting AirDirection

### Problem
`HVACSetAirDirection` (`indirect` / `direct` / `even`) sets the i-See airflow
direction via a `0x41 0x08` runstate packet (flag `0x2000`). The unit only
honors that value once i-See airflow control is enabled, which requires
`widevane=0x80` sent in a `0x01` settings packet.

Until now the user had to manually run `HVACSetWideVane isee` **before**
`HVACSetAirDirection`, otherwise the direction change was silently ignored.

### Change
`HVACSetAirDirection` now sets the widevane to
`MIEL_HVAC_SETTINGS_WIDEVANE_ISEE` (`0x80`) in the same call.

The dispatcher always sends the settings (`0x01`) packet before the runstate
(`0x41`) packet, so the unit receives the i-See enable first and the direction
value on the following tick — no manual ordering required.

### Notes
- `off` is unchanged (still expressed as `widevane=0x8c` via `0x01`).
- The existing capability guard (`cap_vane_v` + `sc_has_isee`) is unchanged.

* Fix GPIO name table offset from duplicate MODBUSRELAY entry

kSensorNames had the four D_MODBUSRELAY_* tokens twice while the
UserSelectablePins enum lists GPIO_MODBUSRELAY_* once, shifting every
following name by four - the GPIO dropdown showed MiEl HVAC MB Tx/Rx/DE
and CC1101 CS as 'MbsRelay ...'. Drop the duplicate row.

* MiEL HVAC accept fan_only as alias for fan mode

Home Assistant's climate integration uses 'fan_only'; map it to the same
value as 'fan' so HVACSetMode/HVACSetHAMode accept it. Reporting is
unchanged (miel_hvac_map_byval still returns 'fan').

* MiEL HVAC Modbus: mirror sensor values on FC03 holding registers

Add holding registers 0x0010..0x0017 as read-only mirrors of room
temperature, compressor, instantaneous power, stage operation/fan/mode
and the requests/CRC-error diagnostic counters, so a master that only
speaks FC03 can read them. Writes to these addresses still return
exception 0x02.

* MiEL HVAC Modbus: start FC03 mirror block at 0x000f, no gap after control block

* MiEL HVAC Modbus: queue writes when HVAC link is not up yet

Return to the master with a normal response and queue the update
(same as the HVACSet* console commands) instead of Modbus exception
0x04, so a PLC can pre-load settings and bench testing works without
the AC connected.

* MiEL HVAC Modbus: frame incoming requests by length, not the T3.5 gap

A FUNC_LOOP poll cannot measure the 3.5-char inter-frame gap reliably
above 9600 baud, so a frame split across two polls was processed as two
truncated frames (CRC error count exceeded the request count on a busy
19200 8E1 bus). Compute the expected request length from the function
code and dispatch as soon as it is buffered; keep the idle gap only to
flush a stuck partial frame or retry an unknown function code. Also skip
requests addressed to other slaves without a CRC check.

* MiEL HVAC Modbus: byte-level resync, larger RX buffer, no flush on auto-direction

CrcErrors was still ~1:1 with Requests on a busy 19200 8E1 multi-drop bus.
- resync one byte at a time on a framing/CRC mismatch instead of dropping
  the whole assumed frame and waiting for bus idle
- only count a CRC error when the frame claims our own address
- 1 kB RX buffer so a late FUNC_LOOP poll does not lose bytes to a UART
  FIFO overflow (TasmotaSerial cannot report the overflow on ESP32)
- bulk serial read instead of byte-at-a-time
- skip flush() when no DE pin is configured - on ESP32 flush() also
  discards the RX buffer, dropping the next request on a shared bus

* MiEL HVAC Modbus: add link status to the FC03 sensor mirror

Holding register 0x0017 (PLC 40024) mirrors input 0x0001 - connected to
the HVAC unit (0/1).

* MiEL HVAC Modbus: wait the RTU turnaround silence before answering

Intermittent corrupted responses (master saw e.g. 80 C8 ...) on an
auto-direction transceiver at 19200: the slave started transmitting
before the master's line had turned around. Hold quiet for up to 3.5
char times after the last received byte before sending the response.
Track the last-byte time per read so the wait is accurate.

* MiEL HVAC Modbus: do not send a late reply once the master has re-polled

When a FUNC_LOOP stall makes the response miss the master's timeout
(Siemens S7 MB_MASTER STATUS 0x80C8), a newer request is already
buffered behind the stale one. Apply the stale request but skip its
response so it cannot land on the master's next transaction and make
that one time out too.

* MiEL HVAC Modbus: strip the i-See bit from the swingH register

Input 0x0015 / holding 0x0005 (40006) returned the raw wide-vane byte,
so a unit with an i-See sensor reported e.g. 131 (0x83 = 0x80 | center).
Report the position only (1..8, 12), or 0x80 when the byte encodes
i-See direction mode - matching the SwingH field in the SENSOR JSON.

* MiEL HVAC: document the driver and Modbus slave in the file header

Move the Modbus RTU slave detail out of the changelog into a doc block
at the head of xdrv_44_miel_hvac.ino, per the PR #24993 review.
2026-09-04 11:09:46 +02:00
Theo Arends a9d4c34255 Update version, disable debug 2026-09-04 10:42:44 +02:00
Theo Arends f5b34a26be BTHome (re)set button when updated state is received (#25002) 2026-09-04 10:03:50 +02:00
Norbert RichterandTheo Arends 4b95302553 NeoPool add AuxMode (#24998)
Co-authored-by: Theo Arends <11044339+arendst@users.noreply.github.com>
2026-09-03 17:45:01 +02:00
Theo Arends a0656a911e Update change logs 2026-09-03 15:15:01 +02:00
s-hadinger a3c97ad00a Berry sortedmap support for json.dump (#24999) 2026-09-02 23:07:06 +02:00
Theo Arends e37f4c0170 refactor add virtual button 2026-09-02 18:15:29 +02:00
Theo Arends da3e0d12cb Simplify berry virtual buttons 2026-09-02 17:49:22 +02:00
Theo Arends d5f33ec1b6 Update pi4ioe5v6408_M5Stack_UnitC6L.be 2026-09-02 15:47:14 +02:00
Theo Arends d6bc8bf105 Missed addition 2026-09-02 15:21:01 +02:00
Theo Arends 079718527b Add Berry virtual button support 2026-09-02 15:18:49 +02:00
Theo Arends 5f80f3a196 Prep buttons for late addition of virtual buttons 2026-09-02 12:39:24 +02:00
Theo Arends 559a9e0275 Fix berry I2C driver message 2026-09-01 15:36:51 +02:00
Theo Arends 4b92474794 Update change log 2026-09-01 14:31:10 +02:00
Grzegorz 2b0f5fd650 MiEL HVAC: fix duplicate GPIO name entry, accept fan_only alias (#24992)
* 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`.

* MiElHVAC auto-enable i-See widevane when setting AirDirection

### Problem
`HVACSetAirDirection` (`indirect` / `direct` / `even`) sets the i-See airflow
direction via a `0x41 0x08` runstate packet (flag `0x2000`). The unit only
honors that value once i-See airflow control is enabled, which requires
`widevane=0x80` sent in a `0x01` settings packet.

Until now the user had to manually run `HVACSetWideVane isee` **before**
`HVACSetAirDirection`, otherwise the direction change was silently ignored.

### Change
`HVACSetAirDirection` now sets the widevane to
`MIEL_HVAC_SETTINGS_WIDEVANE_ISEE` (`0x80`) in the same call.

The dispatcher always sends the settings (`0x01`) packet before the runstate
(`0x41`) packet, so the unit receives the i-See enable first and the direction
value on the following tick — no manual ordering required.

### Notes
- `off` is unchanged (still expressed as `widevane=0x8c` via `0x01`).
- The existing capability guard (`cap_vane_v` + `sc_has_isee`) is unchanged.

* Fix GPIO name table offset from duplicate MODBUSRELAY entry

kSensorNames had the four D_MODBUSRELAY_* tokens twice while the
UserSelectablePins enum lists GPIO_MODBUSRELAY_* once, shifting every
following name by four - the GPIO dropdown showed MiEl HVAC MB Tx/Rx/DE
and CC1101 CS as 'MbsRelay ...'. Drop the duplicate row.

* MiEL HVAC accept fan_only as alias for fan mode

Home Assistant's climate integration uses 'fan_only'; map it to the same
value as 'fan' so HVACSetMode/HVACSetHAMode accept it. Reporting is
unchanged (miel_hvac_map_byval still returns 'fan').
2026-09-01 14:26:19 +02:00
bovirus d29d3a65c7 Update Italian language (#24988) 2026-08-31 16:58:13 +02:00
Theo Arends b4e24df39c BLE MI32 display icons instead of data lines. disable by removing #define USE_SENSOR_ICON 2026-08-31 13:55:16 +02:00
Theo Arends 98868dea15 Fix BLE MI32 rssi graph 2026-08-30 22:48:26 +02:00
Theo Arends 89ef175a3c Update change logs 2026-08-30 22:19:45 +02:00
GrzegorzandTheo Arends 2faea5078a Add HVAC control panel to the MiEL HVAC web UI (xdrv_44) (#24984)
Replace the on/off-only main-page presence with a full climate panel and
a live read-only state table, styled to a fixed dark palette scoped
under #hvacp so it is independent of the Tasmota theme.

- FUNC_WEB_ADD_MAIN_BUTTON renders the panel once: mode segment
  (Auto/Heat/Cool/Dry/Fan/Off), target-temperature stepper + slider, and
  Fan speed / Vane vertical / Vane horizontal / Air direction selects;
  which controls appear is gated by the 0x7B 0xC9 Base Capabilities
  (cap_mode_*, cap_vane_v, cap_vane_swing, cap_fan_auto, cap_run_state)
  and miel_hvac_get_fan_count()
- controls call la('&<key>=<value>'); FUNC_WEB_GET_ARG turns each key
  into the matching HVACSet* command (mode via HVACSetHAMode so a mode
  button also powers the unit), reusing the existing validated setters
- FUNC_WEB_SENSOR refreshes the panel in place every web_refresh via the
  <img onerror> exec trick: state-table cells, mode-button highlight and
  every select value, skipped while a change is still in flight
  (update_settings/runstate_pending) or the control is focused
- state table: Room/Set temp, Mode, Fan, Vane V/H, Air Direction,
  Operation, Compressor, Power/Energy; locale decimal separator applied

(cherry picked from commit 6e013484f168f3748f6d388f18ef69f8313fab97)

Co-authored-by: Theo Arends <11044339+arendst@users.noreply.github.com>
2026-08-30 22:17:06 +02:00
Theo Arends 41964bb72d Update change logs 2026-08-30 22:09:59 +02:00
Philipp SchröerandTheo Arends 2f08cd2fc8 Add support for TFA Marbella pool thermometer (#24959)
* Fix GPIO name list falling out of sync without USE_MODBUS_RELAY

The enum in kGpioNiceList guards the four MODBUSRELAY entries with
#ifdef USE_MODBUS_RELAY, the matching name list does not. In any build
without that define - which is the default - the two run four entries
apart, and every GPIO role added after that point inherits a name that
belongs to something else.

Nothing visible went wrong so far because no role after the Modbus block
is currently offered in the selection list. The next one added would have
shown up as "MbsRelay TX".

* Add support for TFA Marbella pool thermometer

Receives the TFA Dostmann Marbella (30.3066.01) floating pool thermometer
on 868 MHz with a CC1101 and reports water temperature, sensor id, rolling
counter and battery state as sensor telemetry.

Packet layout, checksum algorithm and temperature formula are taken from
the rtl_433 project (src/devices/tfa_marbella.c and the reflected reverse
Galois digest in src/bit_util.c), Copyright (C) 2021 Benjamin Larsson,
GPL-2.0-or-later.

Wiring is the shared SPI bus plus two pins that belong to the module:

  SCK / MISO / MOSI -> SPI CLK / SPI MISO / SPI MOSI
  CSN               -> CC1101 CS
  GDO0              -> CC1101 GDO0

CC1101 CS is added as a role of its own, like every other SPI device has
one (LORA_CS, RC522_CS, MCP2515_CS and so on). The three bus lines stay
generic because they are shared - a display and this receiver hang on the
same wires, and only chip select tells them apart. The name string for it
already existed in the language files, unused.

Built on RadioLib, which already ships with Tasmota and drives the CC1101
on both ESP8266 and ESP32. The older lib/lib_rf/cc1101 declares
"platforms": "espressif8266" for a reason: on ESP32 it collides with the
CC1101 class RadioLib itself declares.

Three settings are not obvious and were established against hardware:

  - The bit rate is 9.5238 kBit/s, not 9.6. rtl_433 documents a symbol
    width of 105 us, and the 0.8 percent difference accumulates to about
    0.7 bit over an 88 bit frame - enough that the first bytes arrive
    intact and the last ones come out shifted.
  - The sync word is 0xAAD2, although the frame itself begins with
    AA 2D D4. The radio matches in hardware and strips what it matched,
    so the two values describe the same transition from different sides.
  - disableAddressFiltering() is required. RadioLib leaves address
    checking on, and the chip then discards every frame whose first byte
    does not match the node address - which for this sensor is always
    0xAA. Without it reception runs and nothing ever arrives.

SPI is set up by the driver rather than left to RadioLib, whose ArduinoHal
calls SPI.begin() without arguments - on ESP32 that picks the default bus
pins and ignores the GPIO template, the same reason the LoRa drivers do it
themselves.

Reception follows the split the LoRa drivers use: the interrupt handler
sets a flag and nothing else, the packet is read in the main loop. The
flag is cleared after reception is restarted, not before, because
startReceive() puts GDO0 back to its idle level and that is an edge in
itself - clearing first makes the driver re-trigger on its own restart and
read the same stale buffer thousands of times per second. Both edges are
used: the pin does not reliably return to idle after a packet.

The driver binds to the first sensor with a valid checksum and ignores
every other one afterwards, so a neighbour's identical sensor cannot feed
readings into the same value. Marbella <id> rebinds, Marbella 0 relearns;
anything that is not a valid 24 bit id is refused rather than silently
turned into 0, which would look like a successful bind while clearing the
binding.

After TFA_MARBELLA_TIMEOUT seconds without a packet the reading disappears
from both the JSON payload and the web interface. A stale value looks
exactly like a measurement that simply does not change, which is the one
failure mode this driver must not produce.

No plausibility range is applied to the temperature. A range check of
0..50 degrees, as sometimes used in place of a checksum, would wrongly
discard a real reading of 51 degrees.

Verified against the sensor: frames decode with matching checksums, a
disturbed frame is rejected by the checksum, and the rolling counter
advances without gaps over consecutive receptions.

* Add SetOption166 to publish TFA Marbella readings on reception

Off by default, so readings go out with the regular TelePeriod telemetry
like those of every other sensor - a driver should not quietly behave
differently from the rest.

Worth turning on for this sensor: it transmits about once a minute, so
with the default TelePeriod of 300 seconds four out of five readings never
leave the device, and the one that does can be almost five minutes old.
With the option set, every reading becomes an MQTT message - useful for
rules, and more traffic on a busy broker, which is why it is a choice
rather than the default.

The bit is taken from the spare range of the SetOption146..177 block. If
the number collides with something merged in the meantime, it can be moved
without touching the driver.

* Add TFA Marbella build configuration

USE_TFA_MARBELLA is off by default and adds 12k6 of code on ESP8266 and
5k7 on ESP32, most of it RadioLib where it is not already in the build.
It sits with the other SPI peripherals because it needs USE_SPI: without
that, the CC1101 CS role cannot be assigned at all and the driver would be
silently dead.

USE_TFA_MARBELLA and USE_KEELOQ cannot be combined: both drive the same
CC1101, one transmitting on 433 MHz and one receiving on 868 MHz.
Whichever configured the chip last would win silently, so the combination
fails at compile time instead.

* Show the age of the last TFA Marbella reading in the web UI

The reading is still dropped from JSON after TFA_MARBELLA_TIMEOUT, so a
stale value never reaches MQTT. The web interface, however, showed nothing
at all in that case - and an empty page cannot be told apart from a driver
that is not running, a radio that never starts, or a sensor whose battery
died. Those need different answers.

The web interface now always shows a line: the age of the last packet
("12 sec ago"), or "no signal, last 4 Min ago" once the reading expired,
or "no signal yet" when nothing was ever received.

The age is shown rather than a timestamp: the sensor sends once a minute,
so what matters is whether the last packet is seconds or hours old - and a
clock time would be wrong anyway while the device has no NTP yet.

* Use SetOption147 for TFA Marbella and correct the radio parameters

Review feedback: drop the newly added SetOption166 and share the existing
SetOption147 instead. Readings are now published as they arrive, which is
what the sensor needs - it transmits once a minute while TelePeriod defaults
to 300 seconds - and SetOption147 suppresses that, the same handle the serial
bridge, IR, LoRaWAN and WizMote drivers already use. flag6 bit 20 goes back
to being spare.

Two radio parameters were wrong. Both came from the rtl_433 device
description and were never verified against a real sensor:

- Bit rate 9.4 kBit/s, not the 9523.8 Bd that rtl_433's 105 us per symbol
  implies. Measured from three SDR recordings by decoding each at every
  sampling phase and letting the sensor's own checksum decide: all three
  peak at 9400 Bd, and none yields a single valid frame at 9523.8 Bd. Over
  the 112 bits of a transmission a 1.3 % rate error drifts past a full bit,
  so the tail of every frame arrives shifted - which is why 9.6 kBit/s
  delivered nothing at all and 9.5238 only worked occasionally.
- Deviation 34.5 kHz, not 30, from the same recordings.

New setting: "Marbella <MHz>" tunes the receiver and is stored in
Settings->marbella_frequency (int16, 100 Hz steps, taken from the filler
after marbella_serial). The CC1101 derives its frequency from a 26 MHz
crystal, and one module measured here sat 27 kHz below what it was told.
That fits inside the 135 kHz receive filter but spends the margin the signal
needs, and it is a property of the board rather than of the driver - so it
is a setting instead of a constant, and nobody needs a private build for it.
A decimal point tells a frequency from a sensor id; ids now have to be the
full six hex digits, so "Marbella 868" is refused rather than silently
binding to sensor 000868.

Also documented at the sync word why 0xAAD2 is the right value: the sensor
sends an alternating preamble, then a single 0xD2, then the frame - so the
16 bits before AA 2D D4 read AA D2, which is exactly what the radio matches.
That was previously noted as unexplained.

Claude-Session: https://claude.ai/code/session_01EmAyStmKbyqFx9X7eTH7Qg

* Update tasmota_types.h

Use union

---------

Co-authored-by: Theo Arends <11044339+arendst@users.noreply.github.com>
2026-08-30 21:56:29 +02:00
Theo Arends 9aa935c231 Update change logs 2026-08-30 21:41:19 +02:00
GrzegorzandTheo Arends 46794883aa Add Modbus RTU slave to MiEL HVAC driver (xdrv_44) (#24982)
* 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`.

* MiElHVAC auto-enable i-See widevane when setting AirDirection

### Problem
`HVACSetAirDirection` (`indirect` / `direct` / `even`) sets the i-See airflow
direction via a `0x41 0x08` runstate packet (flag `0x2000`). The unit only
honors that value once i-See airflow control is enabled, which requires
`widevane=0x80` sent in a `0x01` settings packet.

Until now the user had to manually run `HVACSetWideVane isee` **before**
`HVACSetAirDirection`, otherwise the direction change was silently ignored.

### Change
`HVACSetAirDirection` now sets the widevane to
`MIEL_HVAC_SETTINGS_WIDEVANE_ISEE` (`0x80`) in the same call.

The dispatcher always sends the settings (`0x01`) packet before the runstate
(`0x41`) packet, so the unit receives the i-See enable first and the direction
value on the following tick — no manual ordering required.

### Notes
- `off` is unchanged (still expressed as `widevane=0x8c` via `0x01`).
- The existing capability guard (`cap_vane_v` + `sc_has_isee`) is unchanged.

* Add Modbus RTU slave to MiEL HVAC driver (xdrv_44)

Optional second RS485 serial port that exposes every MiEL HVAC state as
Modbus read registers and maps every driver function to write
registers/coils, so the unit can be driven directly from a PLC.

- ESP32 only, opt-in via USE_MIEL_HVAC_MODBUS_SLAVE
- new GPIOs: MiEl HVAC MB Tx / Rx / DE (RS485 direction, optional)
- persisted config (address, baudrate, serial config) reclaimed from
  Settings free_eb0 + SBitfield1 spare bit; no settings version bump
- function codes 0x01-0x06, 0x0F, 0x10 with CRC-16, RTU inter-frame
  gap framing in FUNC_LOOP, and Modbus exception replies
- input registers (FC04) mirror settings, room/outdoor temp, timers,
  status/energy, stage, capabilities; holding registers/coils drive
  power, mode, temp, fan, vane, widevane, airdirection, prohibit,
  purifier, night mode, econocool, remote temp and clear time
- writes reuse new miel_hvac_apply_* typed setters (same capability
  gating as the console commands, which are unchanged)
- commands HVACModbus / HVACModbusAddress / HVACModbusBaudrate /
  HVACModbusConfig (all live), plus a "Modbus" block in SENSOR JSON

* Update tasmota_template.h

Fix duplicate GPIOs

* Update tasmota_types.h

Use union for parameters

---------

Co-authored-by: Theo Arends <11044339+arendst@users.noreply.github.com>
2026-08-30 21:31:05 +02:00
Theo Arends a95a6f99ab Fix zigbee compilation 2026-08-30 21:11:38 +02:00
Theo Arends cfb0f171a6 Add optional icon display of sensors (WIP) 2026-08-30 15:58:27 +02:00
Theo Arends fc2bdd40a0 Add support for tooltips on touch media 2026-08-30 15:34:05 +02:00
bovirus d220daf373 Update it_IT.h (#24980) 2026-08-28 12:04:27 +02:00
Theo Arends 44a6526523 Update change logs 2026-08-28 11:09:31 +02:00
SteWers 0422f8d618 [EQ3-TRV] Next part of code refactoring (#24978)
* [EQ3-TRV] Next part of code refactoring

- Update command description
- Correct and optimize filter and identification logic (Alias, Name, MAC address)
- Optimize logic for mode in result
- Correct and optimize logic for hassmode in result
- Add `Mode` to UI incl. enhancement of language files
- Tighten types (use bool/uint8_t)
- Harden some input validations
- Many other simplifications and improvements

* ValvePos, device identification

- Rename DutyCycle to ValvePos
- Simplify identification logic
- Make BLE remark smaller
2026-08-28 11:02:38 +02:00