Skip to content

Instantly share code, notes, and snippets.

@Wollac
Created May 21, 2026 17:13
Show Gist options
  • Select an option

  • Save Wollac/ce5d23283d7643081f89b92b1ff08f81 to your computer and use it in GitHub Desktop.

Select an option

Save Wollac/ce5d23283d7643081f89b92b1ff08f81 to your computer and use it in GitHub Desktop.
fritz_smart_offset HACS integration build prompt

fritz_smart_offset — HACS Custom Component Build Prompt

Build a proper HACS custom component for Home Assistant called fritz_smart_offset. The goal is to automatically calibrate AVM Fritz!Box DECT radiator thermostats (FRITZ!Smart Thermo 301/302) using any HA-compatible external temperature sensor, replicating what the expensive FRITZ!DECT 440 Taster does natively.


Background & Research (do not re-research, use this directly)

Fritz!Box DECT thermostats have a valve-mounted temperature sensor that reads high due to proximity to the hot radiator pipe. Fritz!Box corrects this via a configurable offset (Temperaturabweichung). When a DECT 440 is paired, Fritz!Box automatically updates this offset using the 440's room temperature reading — confirmed via the Fritz!Box UI label "Automatische Offset-Anpassung". The valve always uses its own sensor + offset for local on/off control; the offset is the only correction mechanism.

The offset is not exposed via:

  • The official AHA HTTP Interface (/webservices/homeautoswitch.lua) — readable only
  • The new Fritz!Box Smart Home REST API (FritzOS 8.20, v0.9.5) — not present at all

The only way to write the offset is via the Fritz!Box internal web UI backend. This has been verified working on FritzOS 8.20 via browser DevTools:

Authentication: POST to /login_sid.lua?version=2 using PBKDF2-HMAC-SHA256 challenge-response.

Write offset: POST to /data.lua with these parameters (all required, verified by testing minimal payloads):

xhr=1
sid={session_id}
device={device_ain}           # e.g. "13979 0387192"
Offset={value}                # float, 0.5°C increments e.g. "-1.5"
WindowOpenTimer={int}         # 1-120, required by backend validation
WindowOpenTrigger={int}       # required
ule_device_name={name}        # required, causes SetName error if missing
apply=
page=home_auto_hkr_edit
lang=de

Response on success: {"data":{"redirect":{...},"apply":"ok"}}

The Fritz!Box SPA (#/ routing) still uses this same backend endpoint — the frontend changed but the API did not.


What the integration should do

  1. Calculate offset: external_sensor_temp - valve_sensor_temp, rounded to nearest 0.5°C
  2. Filter to comfort mode only: Only sample/apply when the Fritz!Box comfort mode sensor equals "comfort" (HA entity: sensor.{device}_aktuelle_geplante_voreinstellung)
  3. Rolling average: Use a configurable time window (default 48h) of comfort-mode-only samples to smooth out the spike when the valve is fully open. Samples return unavailable outside comfort mode, which the statistics sensor skips.
  4. Apply offset: Write to Fritz!Box via the endpoint above
  5. Expose sensors: Current calculated offset, 48h average offset, last applied offset

HACS custom component structure

custom_components/fritz_smart_offset/
  __init__.py
  manifest.json
  config_flow.py        # UI setup: Fritz!Box host/user/pass, device AIN(s), external sensor, window timer/trigger values
  const.py
  coordinator.py        # Handles auth, offset calculation, Fritz!Box write
  sensor.py             # Exposes offset sensors
  services.yaml         # fritz_smart_offset.apply_offset service
  strings.json
  translations/
    en.json
    de.json

Config flow should ask for

  • Fritz!Box hostname (default: fritz.box)
  • Fritz!Box username + password
  • One or more thermostat devices: each needs AIN, display name, WindowOpenTimer, WindowOpenTrigger, and the associated valve temperature sensor entity
  • External room temperature sensor entity (the one mounted away from the radiator)
  • Comfort mode sensor entity (e.g. sensor.heizung_wohnzimmer_aktuelle_geplante_voreinstellung)
  • Rolling average window in hours (default: 48)
  • Update interval in minutes (default: 60)

Key implementation notes

  • Use aiohttp (available in HA) for all HTTP requests
  • Auth should be re-done on each update cycle (SIDs expire after ~20 min inactivity)
  • The offset calculation sensor should return unavailable when not in comfort mode so the statistics average only includes relevant samples
  • Should support multiple thermostats per config entry (e.g. two radiators in one room sharing the same external sensor)
  • Include a fritz_smart_offset.apply_offset service that applies immediately on demand, plus automatic updates on the configured interval
  • Store credentials in HA's encrypted config entry storage, not plaintext YAML
  • This integration is inherently fragile (undocumented endpoint) — include a clear warning in the README and a persistent notification if the Fritz!Box write fails after a firmware update

Test environment

  • Fritz!Box 5530 Fiber, FritzOS 8.20
  • External sensor: IKEA TIMMERFLOTTE (Matter over Thread, temperature + humidity)
  • Thermostats: FRITZ!Smart Thermo 301 (Heizkörper Fenster, AIN 13979 0387192) and FRITZ!Smart Thermo 301 (Heizkörper Wintergarten)
  • HA at 192.168.178.34, Fritz!Box at fritz.box
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment