Skip to main content

AVM FRITZ!Box Smart Home

Control and monitor FRITZ!DECT devices paired to an AVM FRITZ!Box router — the router is the DECT ULE base station, and this driver talks the on-router /webservices/homeautoswitch.lua (AHA-HTTP) endpoint to enumerate, poll, and command each paired device.

Supported device families:

  • FRITZ!DECT 200 / 210 — smart plug with energy metering (indoor / outdoor).
  • FRITZ!DECT 301 / 302 — radiator thermostats.
  • FRITZ!DECT 500 — dimmable colour bulb (basic on/off + brightness in this driver; colour temperature and hue follow-ups are noted as follow-up work).
  • FRITZ!DECT Repeater 100 with paired sensors — sensor readings surface as read-only attributes.
  • Paired HAN-FUN endpoints — third-party DECT ULE devices announce their capabilities via the same functionbitmask bitfield and are exposed as far as their AHA schema supports.

FRITZ!Box is one of the most common residential broadband routers in the DACH region (Germany / Austria / Switzerland) and often the only smart-home hub on a residential LAN in that market. This driver lets a GEM install piggy-back on the existing FRITZ!Box hub instead of adding a second DECT bridge.

Prerequisites

  • FRITZ!OS 7.0 or later on the FRITZ!Box. Older firmware speaks a different challenge format that this driver does not implement.
  • A FRITZ!Box user account with the Smart Home permission enabled. On FRITZ!OS 7.24+ the default admin account works out of the box. On older firmware you may only have the shared-password login flow — in that case leave username blank.
  • At least one DECT / HAN-FUN device paired to the box (in the FRITZ!Box UI: Home Network → Smart Home → Register new device). The base station itself is not a controllable zone.
  • LAN reachability from the GEM host to fritz.box (or the router's LAN IP). If the FRITZ!Box is behind another edge router that hijacks port 443, use the AHA-native 49443 port or plain HTTP on 49000 from an isolated LAN.

Setup

  1. Add the device. In the admin, create a new device with driver fritz_box:
    • ipfritz.box on a Fritz-managed LAN, otherwise the router LAN IP.
    • password — the account password. Stored encrypted; sent hashed on the wire.
    • username — the account username. Leave blank for the legacy shared-password login.
    • port — leave on 443 unless the box is on a non-default port. 49443 is the direct AHA HTTPS port if 443 is intercepted upstream.
    • protocolhttps strongly recommended; only downgrade to http on an isolated LAN.
  2. Confirm the connection state flips to Connected. If it does not, jump to Troubleshooting — it is almost always the Smart Home permission on the user account.
  3. Enumerate paired devices. From the device detail page, run get_devices. The response is an array of records like:
    {
    "ain": "116300123456",
    "id": 16,
    "productname": "FRITZ!DECT 200",
    "name": "Espresso Machine",
    "functionbitmask": 35712,
    "present": true,
    "on": true,
    "power_w": 42.5,
    "energy_kwh": 1832.45,
    "voltage_v": 229.4
    }
    Copy the ain — it is what you will use as the zone address.
  4. Create one zone per AIN. Zone address = AIN (12 digits, no dashes, no spaces). The zone can live under any subsystem — lights for plugs, climate for thermostats, power if you only care about metering.
  5. Adjust status_interval (optional). Defaults to 15000 ms. The FRITZ!Box AHA endpoint is cheap; you can safely run at 5 s if you need fast state feedback on a switch flip.

Attributes

Device attributes

NameRequiredTypeDefaultDescription
ipyesstringfritz.boxLAN host of the FRITZ!Box.
passwordyesstring (secure)Account password. Stored encrypted; hashed on the wire.
usernamenostringAccount username. Leave blank for legacy shared-password login.
portnoint443443, 49443, 80, or 49000 (see setup).
protocolnostringhttpshttp or https.
status_intervalnoint15000Poll cadence in milliseconds.

Zone attributes (read-only, populated by the polling loop)

NameTypeDescription
device_namestringName of the paired device as entered in the FRITZ!Box UI.
productstringProduct code (e.g. FRITZ!DECT 200).
power_wfloatInstantaneous line power in watts (plugs / meters only).
energy_kwhfloatLifetime energy in kWh.
voltage_vfloatLine voltage in volts.
temperature_cfloatAmbient temperature in °C (thermostats and repeaters with paired sensors).
setpoint_cfloatThermostat target temperature in °C (16.0–28.0 in 0.5 °C steps).
battery_lowboolBattery low warning (thermostats).
statestringZone rollup — on, off, or offline (device unresponsive).

Zone address format

Zone address is a 12-digit AIN (Actor Identification Number) with no dashes and no spaces — e.g. 116300123456. Get the AIN from get_devices or from the FRITZ!Box UI (Home Network → Smart Home → the gear icon on any device).

HAN-FUN endpoints on paired third-party devices use a longer identifier of the form AIN-N where N is the sub-endpoint index. Pass it exactly as reported.

Commands

CommandArgsWhat it does
get_devicesEnumerate every paired DECT / HAN-FUN device. Use during setup.
onaddressSwitch on a FRITZ!DECT plug / relay by AIN.
offaddressSwitch off a FRITZ!DECT plug / relay by AIN.
toggleaddressToggle a FRITZ!DECT plug / relay by AIN.
set_temperatureaddress, levelSet thermostat setpoint in °C. Clamped to 8–28 °C, rounded to the nearest 0.5 °C step.
set_leveladdress, levelSet dimmable-bulb level 0–100.
get_stateaddressRead on/off / setpoint / power for one AIN, on demand.
poll_nowForce a status poll of every wired-up zone right now. Cadence is unchanged.

Known limitations

  • Colour bulb hue / colour-temperature commands are not yet wired. set_level handles brightness on the FRITZ!DECT 500; hue and colour temperature use separate AHA sub-commands (setcolor, setcolortemperature) that this driver does not implement in this pass. Roadmap item.
  • Thermostat OFF and BOOST modes are intentionally not exposed via set_temperature. AVM encodes OFF as the sentinel value 253 and always-ON as 254; the driver refuses those to avoid a set_temperature: 253 typo shutting off heat unexpectedly. Use the FRITZ!Box UI for OFF/BOOST or a dedicated command in a follow-up driver revision.
  • Read-only surface for FRITZ!DECT sensors (temperature-only devices, motion sensors, door/window contacts). The driver reads the values; there is no command to write on a sensor-only device.
  • PBKDF2 login is used automatically when the box advertises it. On FRITZ!OS 7.24+ the driver detects the 2$ challenge prefix and uses PBKDF2 (per AVM's recommended flow); older firmware falls back to MD5-over-UTF-16LE.
  • Multiple FRITZ!Box devices on one GEM install — supported. Each FRITZ!Box is its own device row with its own zone set; there is no cross-box coordination.

Troubleshooting

Login always returns SID 0000000000000000. Wrong username / password, or the account lacks the Smart Home permission. In the FRITZ!Box UI go to System → FRITZ!Box Users → your user and tick "Smart Home". Save and try again.

SSL/TLS errors on port 443. The box is behind another router or gateway that intercepts 443. Switch port to 49443 (the AHA-native HTTPS port) or, on a fully isolated LAN, use plain HTTP on 49000.

get_devices returns an empty list. No DECT devices paired with the box, or the user account has restricted Smart Home visibility. Pair a device at fritz.box → Home Network → Smart Home first.

set_temperature reports success but the radiator does not respond. The AIN was probably wrong or belongs to a different device class (e.g. sending set_temperature to a plug). Run get_devices and confirm the device's functionbitmask includes the thermostat capability (bit 6 = HKR).

Zone attributes stop updating for a period, then resume. FRITZ!OS is polling its DECT children on its own cadence (~15 s baseline). If the DECT link is momentarily lost, present flips to false and the driver stops writing readings; recovery is automatic when the device rejoins.

"Login rejected (SID 0)" after previously working. The account password was changed (or the account was reset by the FRITZ!Box "reset all users" upgrade path). Update the password attribute; the driver re-logs in within one poll cycle.

Under the hood — the login flow

FRITZ!OS uses a two-round challenge-response on /login_sid.lua?version=2:

  1. Get challenge. An unauthenticated GET returns an XML <SessionInfo> with <Challenge> and current <SID>. On FRITZ!OS 7.24+, the challenge is prefixed 2$ and encodes a PBKDF2 parameter block; on older firmware it is a plain hex nonce.
  2. Compute response.
    • PBKDF2 path (recommended by AVM since 7.24): 2$iter1$salt1$iter2$salt2. Compute hash1 = PBKDF2-SHA256(password, salt1, iter1, 32), then hash2 = PBKDF2-SHA256(hash1, salt2, iter2, 32). Response is salt2$hex(hash2).
    • MD5 path (pre-7.24): compute MD5(challenge + "-" + password) where the string is re-encoded UTF-16 little-endian before hashing. Response is challenge-hex(md5).
  3. Post response back. GET /login_sid.lua?version=2&username=X&response=Y. If accepted, the returned <SID> is a 16-hex-character session token; otherwise it is 0000000000000000 and the SID is rejected.

The SID has a 60 minute idle timeout on the box. The driver refreshes proactively at 45 minutes and lazily on any AHA request that returns HTTP 403 or the sentinel inval body.