A Hubitat device driver for Bosch (and Siemens/Neff/other Home Connect brand) fridge-freezers, talking to the Home Connect cloud API. Not affiliated with BSH Hausgeräte or Bosch.
Live door/setpoint/mode state comes from Home Connect's server-sent-events stream, not polling. Opening the stream costs one API request; everything delivered over it afterwards - including keep-alives - is free. This matters because Home Connect enforces a hard 1000 requests/day quota per client application and account: naive 5-minute polling alone would burn well over half that budget before a single command is ever sent. This driver treats every HTTP call as something to budget, and only falls back to polling when the stream is off or unhealthy.
- Go to the Home Connect Developer Portal and sign in with your Home Connect account (the same one your appliance is paired to in the Home Connect app).
- Register a new application with OAuth Flow = Device Flow.
- Copy the Client ID. Copy the Client Secret too, if the portal shows you one - some Device Flow registrations aren't issued a secret, and the driver handles both cases (see "Client Secret" below).
- No redirect URI is needed - Device Flow doesn't use one, which is exactly why this driver needs no parent app and no Hubitat cloud endpoint.
- In Hubitat, go to Drivers Code → New Driver, paste in
bosch.groovy, and Save. (Or install via Hubitat Package Manager using this repository'spackageManifest.json.) - Devices → Add Device → Virtual → set Type to Bosch Home Connect Fridge Freezer.
- On the device page, set the Client ID preference (and Client Secret if you have one), then Save Preferences.
- Click Start Pairing. The device log (and the
pairingUrl/pairingCodeattributes, for use on a dashboard tile) will show a URL and a short code. - Open that URL on any device, sign in with your Home Connect account, and approve.
- Within about 30 seconds the driver detects approval, finishes pairing, and automatically runs discovery against your appliance. No further clicks needed.
If you have more than one refrigeration appliance on the account, the driver won't guess - it logs a table of
haIds and asks you to set the Appliance haId preference to the right one (listAppliances command shows
this table on demand).
Some Home Connect Device Flow app registrations issue a Client Secret; some don't. This driver handles both:
if you leave the Client Secret preference blank, it authenticates as a public client (client_id only); if you
fill it in, it authenticates as a confidential client. If pairing or token refresh fails with invalid_client,
run ./bosch-probe.sh refresh (see below) - it tries both parameter shapes against the real API and tells you
which one your app registration actually needs.
| Preference | Default | What it does |
|---|---|---|
| Client ID | - | From the Home Connect Developer Portal. Required. |
| Client Secret | blank | Only if your portal application was issued one. |
| Appliance haId | blank (auto) | Leave blank if you have exactly one fridge/freezer on the account. |
| Primary door | Refrigerator | Which door drives the standard contact attribute (for HSM/dashboards). |
| Accept-Language | en-GB | Language for Home Connect's display strings. |
| Use the live event stream | on | Strongly recommended - polling burns the daily quota. |
| Safety reconcile interval | 6 hours | Catches anything missed while the stream was briefly down. |
| Poll interval (stream unavailable) | 20 minutes | Fallback cadence only used when the stream is off/degraded. |
| Read back after a write | off | The event stream confirms writes for free; only useful if you disable the stream. |
| Daily API request cap | 800 | Self-imposed, tighter than Home Connect's own 1000/day hard limit. |
| HTTP timeout | 15s | |
| Failure threshold | 3 | Consecutive failures before commStatus flips to offline. |
| Debug logging | off | Auto-disables after 30 minutes. |
Pairing: startPairing, checkPairing, cancelPairing, clearCredentials, refreshAccessToken
Discovery: listAppliances, refreshConstraints, dumpState
Stream: connectStream, disconnectStream
Control: setFridgeSetpoint, setFreezerSetpoint, setCompartmentSetpoint, setSuperModeRefrigerator,
setSuperModeFreezer, setEcoMode, setSabbathMode, setVacationMode, setFreshMode, setDispenser,
setChildLock, setInternalLight, setExternalLight, setInternalLightBrightness,
setExternalLightBrightness, setTemperatureUnit, setDoorAssistant, setDoorAssistantForce,
setDoorAssistantTrigger, setDoorAssistantTimeout
Escape hatch: setSetting(key, value) - writes any Home Connect setting key directly, for keys this driver's
discovery finds on your appliance but doesn't have a dedicated command for yet.
The driver declares a superset of attributes covering every fridge-freezer key documented by Home Connect. Only the ones your specific appliance actually reports will ever be populated - Hubitat doesn't let a driver create attributes at runtime, so unsupported ones simply stay blank rather than showing wrong data. Notable ones:
| Attribute | Meaning |
|---|---|
commStatus |
Hub ↔ Home Connect cloud connectivity. Not the same as applianceConnected. |
applianceConnected |
Whether the fridge itself is online with Home Connect - it losing WiFi does not mean the hub is broken. |
authStatus |
unconfigured / pairing / authorized / expired / failed. |
streamStatus |
connected / connecting / disconnected / cooldown / disabled. |
contact |
Mirrors whichever door the "Primary door" preference selects, for standard ContactSensor apps. |
door* |
One per physical door/compartment this appliance actually has. |
setpoint* / setpoint*Min / setpoint*Max |
Current setpoints and their appliance-reported valid range. |
apiRequestsToday |
Running count against the daily quota - graph this if you're curious. |
unsupportedKeyCount |
How many keys Home Connect has told this driver it doesn't support. |
- No power-off switch. Home Connect's
PowerStatesetting only supportsOnfor fridge-freezers -Offis never a legal value. Exposing aSwitchcapability would make "turn off the fridge" a command that either silently fails or, if Bosch ever changes that, actually defrosts your freezer. Not worth the risk. - No temperature-measurement capability. Home Connect does not document a "current measured temperature" key for fridges, only setpoints. If your specific appliance turns out to report one, discovery will surface it by name in the log as an unmapped key - please report it.
- No aggressive polling capability.
Pollingis deliberately not declared, so the (deprecated) Poller app can't drive this device on a cadence outside the daily quota's control.
- Home Connect's vendor
Content-Type: application/vnd.bsh.sdk.v1+jsonhas no registered encoder on Hubitat's HTTP stack. Every PUT body is pre-serialised to a JSON string before being sent, specifically to avoid a driver-side crash trying to encode it. - Hubitat's SSE client delivers one line per
parse()call, with the SSE blank-line message delimiter arriving as an empty call - not as noise to discard, but as the only record separator available. Keep-alives arrive as a bare:comment line, never asevent: KEEP-ALIVE. - Hubitat can report a stream as
STOP/ERRORwhile it is, in fact, still alive; the driver cross-checks against whetherparse()has kept firing before actually reconnecting.
These lessons about Hubitat's eventStream behaviour are documented by
craigde/hubitat-homeconnect-v3, credited in the driver's
source comments at each point they apply.
Home Connect allows 1000 requests/day, 50/min, and blocks a client for 10 minutes after 10 error-producing
requests in any 10-minute window. This driver keeps its own tighter internal cooldown (6 errors in 10 minutes)
so it stays under Bosch's limit rather than finding it, and a self-imposed daily budget (default 800, preference
dailyRequestBudget) that refuses new requests locally once reached. In steady state with the stream healthy,
expect roughly 40 requests/day - about 4% of the hard quota.
A standalone bash script that talks to Home Connect directly with curl, no Hubitat required. Useful for
debugging pairing, token refresh, and the raw SSE wire format before (or instead of) doing it on-hub:
export HC_CLIENT_ID=...
export HC_CLIENT_SECRET=... # optional
./bosch-probe.sh pair
# after pairing:
export HC_ACCESS_TOKEN=...
export HC_REFRESH_TOKEN=...
./bosch-probe.sh appliances
export HC_HAID=...
./bosch-probe.sh status
./bosch-probe.sh streamAll secrets come from environment variables and are never echoed or logged - this repository is public.
SSE line-reassembly behaviour, the "Hubitat reports STOP while still alive" quirk, and the "Too many follow-up requests" rate signal are lessons documented by craigde/hubitat-homeconnect-v3. This driver's architecture (single file, no parent app, OAuth Device Flow, hybrid key discovery) is not derived from that project.