Commit Graph
10257 Commits
Author SHA1 Message Date
Jacek ZiółkowskiandGitHub 4690b4b2ed add_support_for_modbus_relays (#24812) 2026-06-01 17:23:20 +02:00
s-hadingerandGitHub 7a2fbbe7ba Tasmesh safety fixes (#24809) 2026-05-30 18:33:30 +02:00
s-hadingerandGitHub a35e045863 Ethernet strcat safety (#24808) 2026-05-30 17:19:29 +02:00
s-hadingerandGitHub 4eac8298d5 Berry mapping minor fixes (#24807) 2026-05-30 17:18:55 +02:00
s-hadingerandGitHub 944ad6de4b Zigbee multiple fixes (#24806) 2026-05-30 16:50:50 +02:00
Theo Arends 7edbc4b3d8 Add comments to dali 2026-05-30 16:42:40 +02:00
s-hadingerandGitHub 580b952dfd Artnet check datalen does not exceed payload length (#24805) 2026-05-30 16:41:20 +02:00
l-jonasandGitHub 6a142725c9 dali: allow using TM_DALI_SEND_TWICE for 3 byte frames (#24803)
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.
2026-05-30 16:30:33 +02:00
Theo Arends 46d0bd3425 Fix sensirion SEN6X intermittend detection 2026-05-30 15:59:02 +02:00
s-hadingerandGitHub eda9102237 Fix various bugs (#24802)
* Fix various bugs

* More fixes
2026-05-30 08:22:15 +02:00
s-hadingerandGitHub 44b5c49f86 Berry write(value:int | s:string) -> nil internal argument parsing (#24800) 2026-05-29 23:19:34 +02:00
s-hadingerandGitHub bd890c0ade Add missing break (#24801) 2026-05-29 16:06:37 +02:00
Theo Arends 5bb17bd275 Pre-populate decompressed rule cach (#24799) 2026-05-29 14:12:31 +02:00
s-hadingerandGitHub d3d33b452f Trigger events to Berry when 'USE_RULES' is not enabled (#24796)
* Trigger events to Berry when 'USE_RULES' is not enabled

* replace long with int32_t

* Fix SystemEventsSetNewPower signature
2026-05-29 13:41:31 +02:00
s-hadingerandGitHub a2032b7ec1 Fix Crash when MQTT-TLS when tcp connection failed (#24798) 2026-05-28 22:37:35 +02:00
Jacek ZiółkowskiandGitHub 38e2ce4884 add PowerTotal and ExportActiveTotal to JSON for multi-phase devices (#24790)
* add PowerTotal and ExportActiveTotal to JSON for multi-phase devices

* don't add the fields if SO129=1
2026-05-27 14:46:00 +02:00
GrzegorzandGitHub 07154d430a MiELHVAC fix globals, VLA, duplicate JSON fields and float formatting (#24784)
* 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`.
2026-05-26 10:23:30 +02:00
Theo Arends 6300b542ee Add define USE_ESP8266_DEBUG_HEAP to control (#24777) 2026-05-25 17:27:32 +02:00
joluxerandGitHub ba88358ed6 ESP8266: fix heap metric functions and add OOM diagnostics (#24777)
* 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.
2026-05-25 17:25:04 +02:00
Christian BaarsandGitHub 68635b9668 MI32: unify connection task (#24769) 2026-05-20 12:27:50 +02:00
Theo Arends fb424dca50 Add support for hosted MCU different from esp32c6 2026-05-19 15:35:34 +02:00
Frederick BlaisandGitHub e6d471f25f Add descriptor-driven ST7305 uDisplay packing (#24738) 2026-05-19 12:24:18 +02:00
Theo Arends bbd10227af Fix setting DISABLE_REFERER_CHK 2026-05-19 11:38:16 +02:00
Petr GolovachevandGitHub 0a5311c3ee VID6608: add hardware RMT support for Automotive gauge driver (#24759)
* 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
2026-05-18 17:40:13 +02:00
Theo Arends f4aa8ed67f Increase security by inverting state of define DISABLE_REFERER_CHK, command SetOption128 controlling HTTP access which is now default off 2026-05-17 15:46:32 +02:00
Theo Arends 2c2a28cae1 Fix HTTP invalid file type upload 2026-05-17 11:59:20 +02:00
s-hadingerandGitHub cfe25959cd Berry Matter improve async HTTP error handling (#24756) 2026-05-16 23:40:37 +02:00
Theo Arends 5009bea30b Fix scripter buffer overflow 2026-05-16 22:54:45 +02:00
91a33aa39f Add support for multi-byte chars like emojis (💡) in light device toggle buttons (#24482)
* Add support for multi-byte characters like emojis (💡) in WebButton labels for light device toggle buttons

- Remove the 3-character buffer truncation of light device toggle button labels allowing multi-byte characters like emojis
- Rely on CSS to handle truncation and add `max-width:0` to the td so it respects the provided percentage width instead of expanding to fit content
- Wrap button content in a span with overflow handling to prevent layout breakage

* Use localized `D_BUTTON_TOGGLE` for light device button default text

* Improve UTF-8 support in light device WebButton text

- Add `Utf8Truncate` function in `support.ino` to truncate UTF-8 strings to a max chars limit or max visual width limit
- Truncate light device button text to max 4 chars or max width of 4 before passing to button HTML template
- cache calls to GetWebButton so only called once and update bool var from `set_button` to `has_web_button`.

* Small tweaks to improve clarity in Utf8Truncate on codepoint limits and visual width handling

* Correctness fixes

---------

Co-authored-by: s-hadinger <49731213+s-hadinger@users.noreply.github.com>
2026-05-16 14:28:22 +02:00
Allen SchoberandGitHub 47d53f1761 Add RGBW white blend and 10-bit gamma support to Berry LED pixel rendering so Berry animations render with the same color output as the standard Tasmota NeoPixel light driver. (#24750)
- Replace 8-bit per-channel math with 10-bit intermediates to preserve color ratios at low brightness.
- When SetOption105 (white blend mode) is enabled on a 4-byte RGBW strip, extract the minimum RGB component as a white channel (scaled by rgbwwTable[3]) rather than zeroing it, mirroring the logic in xdrv_04_light.ino.
- Gamma correction is applied via ledGamma10_10 throughout, including the extracted white channel.
2026-05-16 12:31:36 +02:00
s-hadingerandGitHub e18035a6de Support for M5Stack Atom S3R drivers (#24747) 2026-05-15 22:37:48 +02:00
s-hadingerandGitHub 7a21f72f70 rename GPIO_DISPLAY_RESET and update GPIOs (#24742) 2026-05-13 22:42:25 +02:00
bovirusandGitHub 5e8019dc8c Italian language update (#24736) 2026-05-12 12:53:46 +02:00
Allen SchoberandGitHub b05c3004dd Fix default hostname generation to support single-specifier Format() patterns (#24731)
- Route single-specifier hostnames through Format() so patterns like %NX (last N MAC hex chars) work correctly, while preserving the existing two-specifier %s-%04d behavior via snprintf
- Update comment in my_user_config.h to accurately describe chip ID rather than MAC
2026-05-11 11:03:27 +02:00
Allen SchoberandGitHub c7042c767c Fix seesaw encoder position tracking in light control mode and add relative position (#24730)
- Position tracking (abs_position, rel_position) was previously skipped when SEESAW_ENCODER_LIKE_ROTARY light control mode was active due to an early return. Moved position updates before the light control block so Show() and Telemetry always reflect current position.
- Also adds Pos (global relative position) alongside Pos1/Pos2 in JSON telemetry responses, rule triggers, and the web UI display.
2026-05-11 10:55:48 +02:00
Norbert RichterandGitHub 528a306c0f Neopool fix hydrolysis module detection and potential rare crash issues (#24724)
* NeoPool fix possible overflow/div-zero errors

* NeoPool fix Hydrolysis module detection
2026-05-11 10:53:55 +02:00
Jacek ZiółkowskiandGitHub 0c85dbc039 Add RX Enable GPIO support for Modbus (#24726)
* Add RX Enable GPIO support for Modbus

* fix typo

* fix typo in language files
2026-05-11 10:53:07 +02:00
Theo Arends fd68ef7daa Add webcam assert wrt framesize change 2026-05-09 16:01:23 +02:00
Theo Arends 1287868780 Fix webcam buffer overflow 2026-05-07 15:31:21 +02:00
Theo Arends b484ece702 Update change logs and version v15.4.0.2 bump 2026-05-07 14:57:58 +02:00
gemuandGitHub f290dd99c9 sml updates (#24716)
# SML driver: catch-up of accumulated fork changes

This PR rolls up the SML driver work that's accumulated on a downstream fork
over the last ~2 years. **One file** (`tasmota/tasmota_xsns_sensor/xsns_53_sml.ino`,
+288 / −27), squashed for review. Three logical groups, each with its own
opt-out path so existing builds get bit-for-bit-identical behaviour where
nothing actually changed.

## TL;DR

| Group | What | Gating | Default |
|---|---|---|---|
| **A** — bug fixes | 10 narrow correctness fixes | always-on | enabled |
| **B** — scripter-free operation | drive descriptor from `/sml_meter.def` without the Tasmota Scripter | existing `#ifdef USE_SCRIPT` / `USE_UFILESYS` guards | inherits build config |
| **C** — `USE_BAT_CTRL` (Modbus write queue, TCP-reset cleanup, dynamic MBAP SIZE) | new feature for Modbus-write-heavy descriptors | new `#ifdef USE_BAT_CTRL` | ESP32 ON, ESP8266 OFF |

If you want to merge only Group A, the gate-out for B and C is a 2-line
revert (drop the `USE_BAT_CTRL` auto-define and the missing-`USE_SCRIPT`
fallbacks). Happy to split into 3 separate PRs if that's preferred.

## Group A — bug fixes (always-on)

Each is a documented repro on a real or emulated meter; failure modes
listed are observed not theoretical.

### A1. FC-aware Modbus RTU response framing
`mlen = sbuff[2] + 5` was used for ALL RTU responses. Correct for FC01-04
reads but wrong for FC05/06/15/16 write echoes (fixed 8 B with `reg_hi`
in `sbuff[2]`) and exception replies (`FC|0x80`, fixed 5 B). Mixing reads
with writes corrupted receive-buffer alignment for one cycle after each
write. Now switches on the FC byte. Inline comment block documents all
four framing cases.

### A2. `@bN:iM:` bit-extract dropped when combined with mbus index filter
The `b` block updated `ebus_dval` only; the `@i` path immediately below
took `dval = mbus_dval`, so the bit was thrown away. Visible on FC01
coil descriptors that fan one response byte across 8 per-coil JSON
fields — all read 17 (raw byte) instead of 1/0/0/1. One added line:
`mbus_dval = ebus_dval;` inside the `b` block.

### A3. Heap corruption when loading descriptor from `/sml_meter.def`
Without scripter, `lp1` points into `file_md` whose lines end with
`SCRIPT_EOL`, not `'\0'`. The descriptor copy loop only checked `'\0'`,
so it ran past line end and clobbered adjacent heap (observed reliably
with 30+-row meter defs on SD card). Added `*lp1 == SCRIPT_EOL` to the
loop terminator.

### A4. `SML_SRCBSIZE` 256 → 512
With 30+ register requests per meter, the `+1` line easily exceeds
256 chars. Pre-fix, line-buffer overran → parser saw mid-line content
as new line → `maxvars=0` → "sml memory error".

### A5. Reverted PR #24587's early-bail in `SML_Immediate_MQTT`
PR #24587 added `if (!sml_globs.dvalid[index]) return;` at the top of
`SML_Immediate_MQTT`. Three reasons it was wrong:
- the math `@`-chain branch sets `dvalid` AFTER calling
  `SML_Immediate_MQTT` → first emission lost on every meter
- the Modbus/eBus/PZEM/VBus/raw value branch never sets `dvalid` in
  this code path at all → those meters lost ALL immediate-MQTT
  emissions
- encrypted SML decoders feed `SML_Decode` → match fires →
  `SML_Immediate_MQTT`, but encrypted descriptors don't hit the
  same `dvalid`-set sites that PR #24587 assumed

`SML_Immediate_MQTT` is by definition called immediately after a fresh
value has been parsed, so the gate adds no safety and breaks legitimate
use. The gate in `SML_Show` (TelePeriod JSON path) is correct and is
**preserved** — that one needs to suppress slots that haven't seen
data yet because it fires regardless of whether new data arrived.

### A6. OBIS literal-pattern `/n` and `/r` escape support
OBIS descriptors that match line terminators (CR/LF) had no way to
express them. Now `/n` → `\n` and `/r` → `\r` in the literal-byte
match block (only for type `o`/`c`).

### A7. ESP32 hardware-serial validation
Reject configurations where `rx_pin == trx_pin`, fall back to software
serial when `srcpin < 0`, and log which path was taken. Pre-fix, an
accidental same-pin config would silently fail at `Serial.begin()` and
the meter would just stay quiet.

### A8. Sanitised log messages
Several `AddLog` lines didn't have an `SML:` prefix → meter errors got
lost in the general log stream. Now consistent.

### A9. Math evaluation moved to its own 1-second timer
Pre-fix used `if (*mp == 'm' && !sb_counter)` — relied on a global byte
counter being zero, which it usually isn't. Math expressions in
descriptors fired sporadically. Now `lastmath` global + `math_run` flag
set once per second at top of `SML_Decode`. Math runs exactly once per
second per pattern, deterministically.

### A10. `sb_counter` overflow protection
Reset to 0 when > 10. Was used by the old math gate (#A9); could grow
unbounded across long runtime. Harmless but cleaner with a cap.

## Group B — scripter-free operation

The driver historically required the Tasmota Scripter for descriptor
parsing. With `USE_UFILESYS`, a standalone `/sml_meter.def` file can
now drive the whole pipeline — useful for builds that ship without
scripter.

Changes are guarded so existing `USE_SCRIPT` builds get identical
behaviour:
- `SML_REPLACE_VARS` now requires `USE_SCRIPT` (var substitution only
  makes sense with scripter)
- `SML_Init`: file-md path is the fallback when `meter_script != 99`,
  OR the only path when `USE_SCRIPT` is undefined
- `SML_getlinelen` moved out of `#ifdef SML_REPLACE_VARS` so the
  non-scripter path can use it
- Removed `#ifdef USE_SCRIPT` wrapper around `SML_Send_Seq` and
  `SML_Check_Send` (TX dispatch is universal)
- Provide `SCRIPT_EOL` fallback (= `'\n'`) when scripter isn't
  compiled (was an exported symbol from `xdrv_10_scripter.ino`)
- `SML_Init` robustness: filesystem availability check before `open()`,
  `special_malloc` return check with clear log instead of crash,
  null-terminate file content after read, close file handle on error
  paths, prefix all error messages with `SML:`

## Group C — `USE_BAT_CTRL` (ESP32 only)

Originally added for an SMA SunnyBoy battery-control descriptor where
the coexistence of FC03 reads, FC16 writes, and a tight TCP-session
policy stressed the driver. The underlying fixes are useful for any
Modbus-write-heavy descriptor, so I'm exposing them as a feature flag
rather than burying them. Auto-defined for ESP32 (off for ESP8266
where there's no TCP meter use case worth supporting); a one-line
override in `user_config_override.h` opts out.

### C1. Two-slot write queue
`SML_Write()` for type `m`/`M`/`k` now queues into `sml_write_buf[0..1]`
instead of calling `SML_Send_Seq` directly. `SML_Check_Send()` picks up
queued writes between read requests. Prevents read/write collision when
an MQTT command arrives mid-cycle. OBIS (`o`) and other timing-critical
types bypass the queue — IEC 62056-21 mode-A handshake needs deterministic
timing that a 100-ms queue hop would break.

### C2. Meter-switch cooldown (500 ms)
When `sml_desc_cnt` advances to a different meter, hold off transmission
for 5 × 100 ms. Several Modbus slaves (notably SMA-class inverters) need
~200-500 ms between session-end and next-session-start; without it,
back-to-back requests land on a slave still tearing down the previous
response and return CRC errors.

### C3. Modbus-TCP MBAP `SIZE` field made dynamic
Pre-fix, `tcph.SIZE = sml_swap(6)` was hardcoded for FC03 reads (PDU =
6 bytes: `addr + fc + reg_hi + reg_lo + cnt_hi + cnt_lo`). FC16 multi-
register write has a longer PDU (7 + 2*N bytes, up to 26+), and TCP
servers reject frames whose MBAP header `SIZE` doesn't match the actual
PDU length. Now: `sml_swap(slen - 2)`. Also bumped
`MODBUS_TCP_HEADER.payload[8]` → `[48]` for the larger PDU.

### C4. `SML_Clean_Meters()` — force TCP RST before restart
Wired into `FUNC_SAVE_BEFORE_RESTART`. Necessary for slaves that allow
only one TCP session (notably SMA Tripower 10.0SE): without forcing RST,
the slave's session table holds the dead connection in `ESTABLISHED`
state for several minutes after our reboot, rejecting reconnects from
the rebooted ESP. Uses `SO_LINGER {1, 0}` to send RST instead of FIN.
ESP32 only — ESP8266's `WiFiClient` has no `setSocketOption()`; plain
`stop()` is the best it can do there.

### C5. `reset_sml_vars()` forces TCP cleanup on script reload
Same `SO_LINGER` trick as C4 — pre-fix, a script reload would leak the
active TCP connection until natural keepalive timeout (often >30 s).

### C6. Cleanup of write-queue state on script reload
`head`/`tail`/`buf` reset so a re-init can't pick up stale queued writes.

## Footprint

```
diff --stat:
  tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 315 ++++++++++++++++++++++---
  1 file changed, 288 insertions(+), 27 deletions(-)
```

No new files, no new headers, no new dependencies, no other files touched.

## Validation

- ESP32-S3 devkit + emulated Modbus slave covering FC01/FC02/FC03/FC04/
  FC05/FC15. Every fix in Group A has a documented repro that passes
  after the change.
- Group C has been in production on the fork's SMA installations for
  ~18 months across ~50 devices.

## For the maintainer

If you'd prefer 3 PRs (one per group), I can split this without further
work — the commits are already organised that way locally. Let me know.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-07 09:01:22 +02:00
Theo Arends 14864934ab Remove camera feature settings for non OV2640 2026-05-06 12:37:52 +02:00
Theo Arends ba17364d28 Add webcam support for resolutions 16 to 24
- Changes disable camera (resolution) from option 15 to -1
2026-05-05 16:30:20 +02:00
SteWersandGitHub e8a7a209b5 Fix PulseTime Remaining (#24690)
`PulseTime` `Remaining` sometimes returns a non zero value, when no pulsetime remains. It is caused by a rollover of `millis()`.
2026-04-30 16:21:49 +02:00
Theo Arends aa4037051d Add command SetOption [0..2] to display SetOption values 2026-04-29 12:27:51 +02:00
Theo Arends dd58b80d53 Add Commands SetOption, SetOption 1 and SetOption 2 for display all SetOption values
Finally!
2026-04-28 15:31:17 +02:00
Theo Arends 518f839694 Revert "Add Commands SetOption, SetOption 1 and SetOption 2 for display all SetOption values"
This reverts commit 06b5042e17.
2026-04-28 15:10:30 +02:00
Theo Arends 06b5042e17 Add Commands SetOption, SetOption 1 and SetOption 2 for display all SetOption values
Better late than never.
2026-04-28 15:04:33 +02:00
GrzegorzandGitHub 13b7c7d26e MiElHVAC extend support of AirDirection control (#24675)
* 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
2026-04-27 11:13:16 +02:00
Theo Arends 1904f5a89e Oops. Forgot the version change 2026-04-22 22:03:50 +02:00