🚀 Welcome to Better Thermostat 2.0!
Better Thermostat 2.0 is a generational upgrade re-architected from the ground up for rock-solid reliability, fail-soft safety, and total transparency.
Special Thanks to @cl445, for helping me to build the next level of BT
Your rooms, settings, target temperatures, and learned heating profiles carry over automatically. You do not need to reconfigure anything.
Note
Requirements: Home Assistant 2026.9.0 or newer is required.
🌐 Website update (https://better-thermostat.org/)
- Update layout and style
- Add new overview
- Reorganized the Better Thermostat 2.0 overview, quickstart, setup walkthrough, and configurator, including installation requirements and practical room and TRV setup guidance.
- Expanded configuration and calibration references with calibration types, control modes, compatibility details, valve-opening behavior, and selection advice.
- Updated recommended settings, device compatibility, and buying guides with room-specific profiles and TRV and sensor recommendations.
- Added symptom-based troubleshooting and clarified how room heating demand can coordinate with central heating.
- Refreshed guidance for use cases, automation blueprints, schedules, and migrating older custom automations.
- Expanded virtual hydraulic balancing guidance with examples of how valve opening varies by calibration and room setup.
🏗️ A rock-solid decision engine that never guesses
In earlier releases, sensor event handling, thermal calculations, and device network calls were intertwined, which could cause race conditions or repetitive device writes when multiple sensors updated at the same time.
- Clean separation of decisions and device writes. Better Thermostat now separates a pure decision core from device communication. At each cycle, it captures a single, coherent snapshot of your room and computes exactly what each radiator should do before sending any commands.
- Event bursts coalesce into single decisions. Rapid bursts of sensor updates or manual adjustments are gathered into a single decision rather than hammering your Zigbee or Z-Wave network with repeated writes.
- Built-in flight recorder. The decision engine records exactly why every heating decision was made (e.g. window opened, target reached, or sensor degraded), making troubleshooting and diagnostics transparent and fully reproducible.
🛡️ Smarter fail-soft protection keeps your home warm
When hardware glitches or batteries run out, Better Thermostat 2.0 ensures your home stays comfortable rather than shutting down.
- Offline window and door sensors no longer freeze your room. In 1.9, an unavailable window or door sensor was treated as "open", turning heating completely off. In 2.0, an offline contact sensor is treated as closed, keeping your room heated while gently notifying you with a degraded-mode repair notice in your Home Assistant dashboard.
- Graceful room sensor step-down ladder. If your external room temperature sensor loses connection:
- Better Thermostat first regulates on the average of your radiators' built-in temperature sensors.
- If all sensors become unavailable, it holds the last known valve position instead of shutting off.
- Once your room sensor has reported reliably for five minutes, control returns seamlessly to optimal mode.
- Total visibility into degraded mode. The climate entity now exposes new attributes:
control_mode(optimal,sensor_fallback, orhold),degraded_for_seconds, andcalibrator_health, so you always know when and why a room is running in fallback mode.
☀️ Gentle, time-damped Summer Mode
- No more sudden heating shut-offs on warm afternoons. 1.9 averaged raw calendar-day readings, meaning a sunny afternoon could prematurely stop heating and cause abrupt shifts at midnight. 2.0 damps outdoor temperature readings across a rolling 24-hour time window, providing smooth seasonal transitions.
- 1.0 °C (1.8 °F) switch-back margin. Summer mode now features a built-in hysteresis margin. Once heating turns off for summer, it only turns back on when the outdoor temperature drops a full 1.0 °C below your threshold, preventing annoying day-to-day toggling during spring and autumn.
- Day and night forecast averaging. Weather entity forecasts now average daily highs and lows together rather than only looking at peak daytime temperatures, ensuring your radiators heat on chilly nights.
❄️ Compressor protection for air conditioning & cooling
- 240-second anti-short-cycling hold. To protect cooling compressors from premature wear, Better Thermostat now automatically holds back unchanged mode or temperature commands if the same command was sent less than 240 seconds earlier.
- Graceful retry backoff. Failed cooling commands are retried with an expanding pause (from 30 seconds up to 30 minutes) rather than repeatedly spamming your climate unit.
🧮 Real-time diagnostic sensors for MPC v2
For setups using the advanced Model Predictive Control (MPC v2) algorithm, four new real-time diagnostic sensors provide full visibility into your room's thermal physics:
- Virtual Temperature: The internal estimated thermal state of the radiator.
- Radiator-Room Coupling: The estimated heat transfer rate between the radiator and the room.
- Thermal Disturbance: Estimated extra heat entering the room (such as sunshine or extra occupants).
- Room Time Constant: How slowly or quickly your room loses heat to the outside.
🔌 Native Shelly BLU TRV support & expanded quirks
- Direct Shelly BLU TRV integration. Better Thermostat now communicates directly with Shelly BLU TRVs, commanding valve opening percentages natively without intermediate helper entities.
- Dedicated valve entities. Seamless support for devices that expose dedicated valve position number or valve entities.
- Expanded model quirks. Added dedicated device quirks and fixes for the Sonoff TRV-ZBT (TRV Gen2), Tuya ME167, Z-TRV-V01, COZB0001, and Eurotronic Spirit.
🔄 Seamless settings migration & automatic entity tracking
- Settings moved to options. Configuration is now cleanly stored in config entry
optionsrather thandata, matching modern Home Assistant architecture. - Automatic rename tracking. If you rename a climate entity, room sensor, window contact, or cooler in Home Assistant, Better Thermostat automatically follows the entity to its new ID so your automations and rooms never break.
- Automatic sensor cleanup. Diagnostic sensors that are no longer needed (such as the legacy solar intensity sensor) and old PID sensor entities are automatically cleaned up from your entity registry.
- Self-clearing repairs. Dashboard repair issues are tied directly to config entries and clear themselves automatically as soon as the underlying issue is resolved.
🎨 Modern brand identity & Platinum Quality Scale
- Official brand assets. High-resolution brand icons and logos are now bundled directly within the integration.
- Home Assistant Platinum Quality Scale compliance. Better Thermostat now achieves Home Assistant's highest quality tier (Platinum Quality Scale), featuring strict end-to-end type safety, standard entity categorization, comprehensive error handling, and clean lifecycle management.
🔙 Seamless rollback to 1.9.4
If you ever need to go back to the 1.9 maintenance line, you can safely reinstall 1.9.3 or newer via HACS. 1.9.3 was specifically designed to read settings from the new 2.0 configuration format, so all your rooms and settings remain completely intact.
Full commit-level changelog
What's Changed
- chore: merge develop into v2 by @cl445 in #2060
- chore: merge develop into v2 by @cl445 in #2076
- chore: merge develop into v2 by @cl445 in #2080
- chore: merge develop into v2 by @cl445 in #2086
- chore: merge develop into v2 by @cl445 in #2117
- arch 01: time seam (Clock) + WorldSnapshot/DesiredState core types by @cl445 in #2079
- arch 02: the decide() decision kernel by @cl445 in #2081
- arch 03: orthogonal FSM regions as pure core modules by @cl445 in #2082
- arch 04: wire the functional core into the shell (control-path switchover) by @cl445 in #2084
- arch 05: developer handbook for the core/shell architecture by @cl445 in #2085
- i18n: sync the degraded-mode text across all languages by @cl445 in #2092
- fix: publish and apply hvac_mode-only payloads in async_set_temperature by @cl445 in #2119
- fix: consult sensor fallback before skipping balance calibration by @cl445 in #2120
- fix: retry the boost safety valve reset when the write fails by @cl445 in #2121
- fix: register valve maintenance tick regardless of calibration mode by @cl445 in #2122
- fix: reject non-finite values at the input boundary by @cl445 in #2123
- fix: honor explicit entity_id and merge extra key in Trv.from_legacy_dict by @cl445 in #2124
- fix: dispatch window events even when the sensor is unavailable by @cl445 in #2126
- ci: restrict types workflow token to read-only contents by @cl445 in #2125
- feat: MPC v2 offline batch re-identification of the plant prior by @cl445 in #2118
- fix: address v2 branch review findings by @cl445 in #2138
- fix: address second-pass v2 review findings by @cl445 in #2140
- chore(v2): sync develop and port the cooler inbound and range-write fixes by @cl445 in #2148
- fix(v2): review findings round 3 by @cl445 in #2152
- fix(cooler): guard the cool target against None and seed it from the range by @cl445 in #2157
- fix(controlling): drop the deprecated interval converter by @cl445 in #2158
- chore(v2): sync develop and resolve the cooler-path divergence by @cl445 in #2159
- fix(cooler): bound the cooler write rate and derive the resend interval by @cl445 in #2160
- fix(cooler): suppress the cooler while a window or door is open by @cl445 in #2161
- fix(cooler): delay the cooling switch-on by the tolerance by @cl445 in #2165
- fix(state-manager): reject persisted numbers the store cannot carry by @cl445 in #2176
- fix(events): clamp an inbound setpoint instead of moving the other target by @cl445 in #2166
- fix(cooler): seed an unknown cool target from the cooler's own setpoint by @cl445 in #2167
- fix(cooler): decline a setpoint reported on a dead cooler state by @cl445 in #2180
- fix(mpc-v2): bound the restored plant prior on both sides by @cl445 in #2183
- chore(helpers): read a published setpoint step through one shared rule by @cl445 in #2185
- fix(setpoint): match an inbound setpoint against the report and the clamp by @cl445 in #2191
- fix(cooler): bound re-injected targets and order the restored pair by @cl445 in #2178
- fix(mpc_v2): tie restored _initialised to the snapshot that seeded it by @cl445 in #2182
- docs: point the schedule guide at the preset actions by @cl445 in #2195
- fix: resolve a device-less thermostat model in the options flow by @cl445 in #2197
- fix: stop sending HVAC modes the TRV does not offer by @cl445 in #2199
- fix: re-assert a calibration offset the device did not confirm by @cl445 in #2200
- fix(cooler): surface an unavailable cooler through degraded mode by @cl445 in #2187
- chore(cooler): converge cooler-path wording and step tests across lines by @cl445 in #2189
- fix(calibration): make the cooling report and the idle gates agree by @cl445 in #2193
- fix(v2): exercise TRV valves while the thermostat is off by @cl445 in #2209
- fix(v2): agree on one default calibration mode by @cl445 in #2211
- docs(v2): add a preset reference and a central-thermostat guide by @cl445 in #2213
- docs: remove AI writing patterns from the v2 documentation by @cl445 in #2214
- test(integration): parametrize the harness over real device forms by @cl445 in #2215
- test: spec the adapter-seam mocks against the contract they replace by @cl445 in #2216
- fix(v2): give a dual-role climate entity a single controlling channel by @cl445 in #2203
- test: hold every adapter's write paths to one contract by @cl445 in #2217
- test: cover the quirk that runs for every device without one by @cl445 in #2219
- test: pin what a quirk module may define, and what it must by @cl445 in #2221
- fix(trvzb): land the requested valve position after a de-sticking bump by @cl445 in #2227
- fix(mpc_v2): bound the disturbance estimate without dropping short intervals by @cl445 in #2235
- chore(v2): sync develop into v2 by @cl445 in #2231
- chore(v2): merge develop into v2 by @cl445 in #2236
- v2: functional core / imperative shell architecture by @cl445 in #2128
- test(integration): drive the config and options flows through Home Assistant by @cl445 in #2237
- chore(review): correct the test-review instructions for CodeRabbit by @cl445 in #2239
- test(integration): drive startup and availability over time by @cl445 in #2238
- fix: make the device automation surface work, and test it end to end by @cl445 in #2240
- docs: close a device-specific bug with a matrix row, not just a test by @cl445 in #2241
- ci: hold each module's coverage instead of a project-wide number by @cl445 in #2242
- test: drive a room with several heads end to end by @cl445 in #2245
- fix: treat a missing child lock flag as unlocked by @cl445 in #2246
- chore: ignore Playwright MCP session artifacts by @cl445 in #2249
- chore: gate type strictness globally and exempt named files by @cl445 in #2250
- chore: gate blind exception handlers with ruff BLE001 by @cl445 in #2251
- chore: drop unreferenced helpers and the empty calibration types module by @cl445 in #2252
- chore: drop inert type suppressions and state comments as contracts by @cl445 in #2253
- chore: prune orphaned linter configuration and wire up yamllint by @cl445 in #2254
- chore: enforce top-level imports outside two justified deferrals by @cl445 in #2255
- fix: give broad exception handlers a trace or a proven boundary by @cl445 in #2256
- fix: patch find_valve_entity where the mqtt adapter binds it by @cl445 in #2260
- chore: type the ecosystem adapters against an explicit host protocol by @cl445 in #2257
- chore: annotate the model-fix quirk host parameters by @cl445 in #2258
- chore: annotate the instance parameter of the shell modules by @cl445 in #2259
- fix: presets are reset by an options change by @cl445 in #2261
- fix: reset an MQTT TRV onto its manual preset instead of "none" by @cl445 in #2274
- fix: restore the HVAC mode after maintenance only when it moved by @cl445 in #2276
- fix: re-send the room temperature to mirroring TRVs on a timer by @cl445 in #2278
- fix: rename BT entity ids only when the thermostat was renamed by @cl445 in #2272
- test: assert the startup registration sets in full and measure branch coverage by @cl445 in #2280
- fix: keep the degradation ladder on a five-minute tick for every calibration mode by @cl445 in #2282
- test: round-trip the settings a user configured (TG12) by @cl445 in #2264
- docs: settle naming on PEP 8, Google §3.16 and a project glossary by @cl445 in #2263
- 1.9.2 by @KartoffelToby in #2286
- fix: let the MPC governor follow setpoint reductions by @cl445 in #2293
- fix: debounce internal TRV temperature per device instead of per room by @cl445 in #2292
- fix: apply temperature readings in the order they arrived by @cl445 in #2329
- fix: serialise concurrent temperature updates per entity by @cl445 in #2305
- fix: read "a head is off" the same way at startup and at runtime by @cl445 in #2284
- fix: cancel the plateau timer when the entity is removed by @cl445 in #2294
- fix: wait for the device before reporting an adopted TRV as tweaked by @cl445 in #2334
- test: assert sequence properties on the stateful controllers (TG15) by @cl445 in #2315
- fix: report refused valve writes in the TRVZB quirk by @cl445 in #2320
- fix: write the deCONZ calibration offset in the units deCONZ reads by @cl445 in #2327
- refactor: give every adapter one offset interface and one set of defaults by @cl445 in #2319
- chore: remove unreachable branches and correct stale comments by @cl445 in #2301
- fix: report refused device writes in the model quirks by @cl445 in #2331
- fix: stop reporting valve support for TRVs without a valve quirk by @cl445 in #2307
- feat: allow overriding the target temperature range in the config flow by @cl445 in #2314
- refactor: name the heated entity by its glossary term by @cl445 in #2321
- fix: let the naming gate accept newly added test files by @cl445 in #2324
- chore: re-record four coverage floors against the tree they guard by @cl445 in #2333
- fix: write select-based calibration offsets through the right service by @cl445 in #2300
- fix: acknowledge queue sentinels and stop retrying programming errors by @cl445 in #2303
- fix: keep the control cycle running when a TRV write fails by @cl445 in #2291
- fix: skip unreadable TRV modes when snapshotting for valve maintenance by @cl445 in #2299
- fix: reject non-finite values on the persistence and telemetry paths by @cl445 in #2310
- chore: report the maintenance-line commits that never reached develop by @cl445 in #2311
- fix: let infrastructure errors reach the retry decorator in the adapter delegate by @cl445 in #2316
- fix: fail the coverage gate when a recorded floor leaves the report by @cl445 in #2336
- fix: keep the Kalman covariance symmetric and round valve percentages half up by @cl445 in #2302
- fix: report unusable MPC state and valve caps instead of dropping them by @cl445 in #2326
- fix: clear contact and temperature repair issues once a reading is valid again by @cl445 in #2308
- fix: let the entity cancel the background tasks it started by @cl445 in #2337
- fix: stop cutting TRV write retries short in the control cycle by @cl445 in #2323
- fix: leave the cooler out of the startup heating-member check by @cl445 in #2339
- chore: drop the remaining dead state fields and read humidity once by @cl445 in #2328
- fix: re-read battery levels after a device recovers and log the sensor warning once by @cl445 in #2306
- refactor: read battery levels directly instead of through a background task by @cl445 in #2325
- fix: restore Eurotronic Spirit valve control and deterministic TRVZB sibling lookup by @cl445 in #2312
- test: give the watcher tests real states to read by @cl445 in #2340
- test: state the requirement in a test docstring, not the run by @cl445 in #2309
- Merge master back into develop so the 2.0.0 release PR can merge by @cl445 in #2344
- Re-record the forward-port gaps against both current lines by @cl445 in #2346
- test: refuse a trigger on a device that carries no thermostat by @cl445 in #2343
- fix: restore the temperature range a cooler publishes by @cl445 in #2348
- fix: refresh the cached TRV mode when a control cycle ends by @cl445 in #2350
- fix: offer direct valve control where the model's quirk drives the valve by @cl445 in #2353
- fix: observe a TRV switched back on at its own knob by @cl445 in #2355
- test: run the async tests without a file-local anyio backend by @cl445 in #2351
- fix: link the BT device by via device id by @cl445 in #2362
- chore: record the MQTT offset-bounds fix as carried forward in another shape by @cl445 in #2368
- fix: read the TRV key when migrating a config entry to version 18 by @cl445 in #2370
- fix: pin the setpoint adoption rule in production instead of rebuilding it in tests by @cl445 in #2375
- fix: confirm a calibration offset the device reports a full step away by @cl445 in #2378
- fix: remember the setpoints a device may still echo after an unconfirmed write by @cl445 in #2381
- refactor: finish naming a TRV entity id by its glossary term by @cl445 in #2372
- refactor: tell a TRV entity id apart from its configuration entry by @cl445 in #2374
- refactor: use one name for the TRV behind a real_trvs entry by @cl445 in #2376
- chore: enforce PEP 8 naming with ruff's N rules by @cl445 in #2373
- chore: re-record the naming budget against the current tree by @cl445 in #2369
- chore: re-record the coverage floors against the tree they guard by @cl445 in #2380
- test: state requirements instead of the behaviour a defect produces by @cl445 in #2397
- test: drive every trigger entrance of a room while one TRV is unavailable by @cl445 in #2398
- test: pin device events that arrive during a control cycle or a confirmation wait by @cl445 in #2399
- test: cover the Home Assistant boot order and a host reboot by @cl445 in #2400
- test: pin every temperature write path on a Fahrenheit system by @cl445 in #2401
- test: run MPC v2 under free heat, setpoint steps and airing by @cl445 in #2403
- docs: state the Python 3.14 floor for contributors by @cl445 in #2386
- test: build registry fixtures from the production RegistryEntry type by @cl445 in #2402
- fix: skip disabled and device-less registry entries when looking up TRV siblings by @cl445 in #2412
- fix: plan MPC v2 around free heat without hunting the valve by @cl445 in #2414
- fix: protect the HomematicIP duty cycle on the write side instead of slowing the room sensor by @cl445 in #2415
- fix: keep device reports that arrive during a control cycle by @cl445 in #2408
- fix: keep Fahrenheit writes, bounds and defaults inside what the device accepts by @cl445 in #2407
- fix: resume PID and MPC after a host reboot or clock step and report dropped stored values by @cl445 in #2411
- fix: keep the room heating on a silent forecast and on heat_cool or auto reports by @cl445 in #2413
- fix: read a report held during a cycle against the state it replaced by @cl445 in #2433
- fix: keep a room listening to its window, sensors and ticks while one TRV is unreachable by @cl445 in #2410
- fix: start a room without a TRV that outlasts the startup grace window by @cl445 in #2416
- chore: let CodeRabbit accept prose docstrings on private helpers and properties by @cl445 in #2435
- fix: leave the config entry data untouched when building diagnostics by @cl445 in #2458
- fix: remove the door sensor repair issue with the config entry by @cl445 in #2459
- test: run the MPC v2 contact gates without the daqp wheel by @cl445 in #2431
- fix: keep MPC v2 controlling after the wall clock steps back by @cl445 in #2428
- fix: keep the room target when a device without the swap option reports auto by @cl445 in #2429
- fix: round a preset's cooling target onto the configured step by @cl445 in #2434
- fix: apply room sensor readings in arrival order when a plateau timer fires late by @cl445 in #2430
- fix: watch a setpoint write whose service call raises by @cl445 in #2432
- refactor: drop the saved_temperature slot nothing writes by @cl445 in #2476
- chore: record six maintenance-line fixes develop carries in another shape by @cl445 in #2482
- fix: save the controller state once a failed copy of an unreadable store succeeds by @cl445 in #2440
- fix: report a refused mode write and give an out-of-reach TRV one write attempt per cycle by @cl445 in #2442
- fix: back off a control cycle that keeps failing and stop the loop's timers with the entity by @cl445 in #2443
- fix: bound the weather forecast call so startup cannot stall on it by @cl445 in #2471
- fix: name the thermostat in blueprint notifications from the device input by @cl445 in #2473
- fix: re-read a stored battery level when the battery entity reports a new one by @cl445 in #2477
- Fix the sensor fallback reading stale TRV temperatures and not reacting to rung changes by @cl445 in #2487
- fix: adopt a one-step cooling press, turn a child-locked device back at once, and keep a switched-on room as heat by @cl445 in #2444
- fix: keep each thermostat to one entry and make migration, repairs and settings consistent by @cl445 in #2438
- fix: let platform entities follow algorithm and name changes, and make device triggers fire on the change they name by @cl445 in #2441
- fix: log the setpoint a TRV reported, not only BT's clamped view of it by @cl445 in #2465
- fix: cancel a pending Away on return and apply the battery throttle by @cl445 in #2466
- Write a range-only head's setpoint as its lower bound by @cl445 in #2489
- fix: reuse the outdoor history mean instead of querying the recorder on every update by @cl445 in #2468
- fix: send the cooler its setpoint on its own grid, turn back a locked press during a cycle, and log failed retries once by @cl445 in #2445
- fix: start a room on the TRV temperature when its sensor outlasts the startup grace window by @cl445 in #2483
- fix: keep valve maintenance away from a TRV that is not set up yet by @cl445 in #2447
- chore: re-record the four lowered budgets by @cl445 in #2481
- chore: record seven maintenance-line fixes develop carries in another shape by @cl445 in #2486
- chore: record 28 maintenance-line fixes develop carries in another shape by @cl445 in #2497
- fix: let a TRV speak for the room only on a temperature it reports by @cl445 in #2498
- test: drive the decision kernel through random event sequences by @cl445 in #2493
- fix: evaluate the degradation ladder every minute in every configuration by @cl445 in #2494
- test: hold the timing constants to the relations their comments claim by @cl445 in #2495
- fix: report a stalled control loop only when a device diverges by @cl445 in #2496
- fix: let MPC v2 without daqp command what daqp would, and hold the valve on a non-finite plan by @cl445 in #2446
- fix: start the room at its heads' setpoint and let learning reach the measured rates by @cl445 in #2439
- docs: correct the contributor docs against the tree and CI by @cl445 in #2462
- docs: correct internals against the code, add door-suppression golden by @cl445 in #2463
- docs: correct the user documentation against the code by @cl445 in #2464
- chore: record the controller-state copy develop carries in another shape by @cl445 in #2503
- docs: wrap the long lines in the MPC v2 QP solver docstrings by @cl445 in #2501
- fix: check thermostat ownership again right before an entry is saved by @cl445 in #2504
- fix: read a held-back temperature and a Fahrenheit cooling write on replay by @cl445 in #2505
- fix: restart the room temperature filter when the sensor returns by @cl445 in #2506
- fix: unblock the forward-port gate and let the budget gates see new files by @cl445 in #2437
- fix: retry the quarantine copy on its own timer by @cl445 in #2500
- fix: leave a head that cools out of the startup heating target by @cl445 in #2507
- fix: control on a fallback reading that also confirms an offset write by @cl445 in #2509
- fix: hold each channel of a room with a cooler to its own device range by @cl445 in #2485
- fix: make the advanced config-flow strings match the behaviour by @cl445 in #2480
- chore: record two maintenance fixes develop carries in another shape by @cl445 in #2510
- fix: read a head turned back to its last confirmed setpoint as the user's turn by @cl445 in #2512
- chore: record six maintenance fixes develop carries in another shape by @cl445 in #2519
- test: drive a room through random event sequences and judge it by convergence by @cl445 in #2511
- fix: restore a preset target as it is applied by @cl445 in #2508
- chore: record the held-report replay develop carries in another shape by @cl445 in #2531
- Fix two sensor fallback gaps: marker reports and a stale ladder observation by @cl445 in #2528
- fix: switching a head on does not adopt a setpoint turned while it was off by @cl445 in #2520
- chore: record the switch-on replay cycle develop carries in another shape by @cl445 in #2532
- fix: judge a later switch-on report held in a cycle against off by @cl445 in #2537
- test(benchmark): run MPC v2 in the calibration benchmark by @cl445 in #2515
- test(benchmark): map indirect-TRV intent onto a setpoint as production does by @cl445 in #2516
- chore: record the sensor fallback develop carries in another shape by @cl445 in #2542
- fix: the v0 migration's save is a task the final flush waits for by @cl445 in #2539
- test(benchmark): close the valve for every controller while a window is open by @cl445 in #2540
- fix: keep a setpoint-steered TRV's opening out of MPC v2's command by @cl445 in #2517
- test: run unit-layer sleeps at a thousandth of their length by @cl445 in #2533
- test: a thermostat stand-in that refuses to invent state by @cl445 in #2534
- fix: correct a head turned to the room's target during a cycle by @cl445 in #2525
- fix: take a setpoint the device already holds as Better Thermostat's own by @cl445 in #2529
- chore: record the quarantine copy and its runtime retry develop carries in another shape by @cl445 in #2543
- test: replay and shrink room event sequences, and search three rooms under four rules by @cl445 in #2514
- test: drive the room search through reloads and restarts, booted like Home Assistant by @cl445 in #2518
- test: drive the room search through the window and the room's mode by @cl445 in #2522
- fix: correct a cooling turn adopted at the cooling target it already had by @cl445 in #2552
- docs: wrap the held-report docstring to the line width by @cl445 in #2545
- fix: take a reading the debounce turned away once the interval is over by @cl445 in #2523
- test: drive the room search through sensor readings and Fahrenheit rooms by @cl445 in #2527
- test: build 38 files' thermostat stand-ins on the strict stand-in by @cl445 in #2535
- test: let the lost-write heal wait for the confirmation instead of a timeout by @cl445 in #2546
- test: run each balance strategy against a real TRV by @cl445 in #2547
- chore: record the debounce fixes develop carries in another shape by @cl445 in #2561
- test: build every remaining thermostat stand-in on the strict stand-in by @cl445 in #2536
- chore: drop the hasattr guards in advance_hvac_action by @cl445 in #2538
- test: sort the suite into unit and gates by @cl445 in #2541
- test: let the control-queue tests wait on the queue instead of the clock by @cl445 in #2548
- refactor: keep the climate entity in the entry's runtime data by @cl445 in #2560
- perf: keep the climate entity's controller telemetry out of the recorder by @cl445 in #2549
- chore: fail the budget and floor gates on unrecorded slack and on a module without a floor by @cl445 in #2558
- Move onto current Home Assistant APIs: device lookup, recorder, dispatcher, dead hooks by @cl445 in #2550
- feat: translate the errors a refused climate service call shows by @cl445 in #2551
- feat: register the services on load and let valve maintenance say why it did not run by @cl445 in #2553
- feat: say why resetting the PID learnings did not do what was asked by @cl445 in #2554
- feat: ship the brand images with the integration by @cl445 in #2556
- feat: put what a bug report needs into the diagnostics download by @cl445 in #2555
- feat: take entity and service icons from icons.json by @cl445 in #2557
- fix: keep idle overheating protection from opening the valve by @cl445 in #2562
- test: hold the idle overheating sweep to equality up to the line by @cl445 in #2564
- docs: add an upgrade page from 1.9 to 2.0 by @cl445 in #2559
- feat: mirror the room temperature into the Sonoff TRV-ZBT (TRV Gen2) by @micmatmoc in #2499
- feat(shelly): write the valve of a Shelly BLU TRV directly by @cl445 in #2570
- fix: take no valve position as sent while the valve entity has no state by @cl445 in #2572
- chore: update the development toolchain by @cl445 in #2569
- fix: solve the polished MPC v2 plan apart from its multipliers by @cl445 in #2571
- fix: read a device command its library cancelled as a lost connection by @cl445 in #2592
- test: read the device's config entry from config_entry_id by @cl445 in #2593
- refactor: spell out value and config in local names by @cl445 in #2574
- refactor: name temperature differences delta_kelvin in the controllers by @cl445 in #2577
- refactor: name the cooling target cool_target_temperature by @cl445 in #2578
- refactor!: name the learning attributes' temperature difference delta_kelvin by @cl445 in #2581
- refactor: name the heating target heat_target_temperature by @cl445 in #2583
- fix: read the saved thermostat state before Home Assistant starts by @cl445 in #2594
- fix: keep a Shelly TRV (Gen1) from reading a closed valve as off by @cl445 in #2588
- fix: name the device boundaries that keep a broad handler, inline by @cl445 in #2590
- fix: narrow or drop blind exception handlers around code that cannot fail by @cl445 in #2575
- fix: log internal failures with their traceback instead of swallowing them by @cl445 in #2579
- fix: keep an entry's settings in its options by @cl445 in #2596
- test: hold the Bronze rules of the Integration Quality Scale by @cl445 in #2576
- fix: refuse a thermostat Home Assistant does not know in the flows by @cl445 in #2582
- test: cover the config flow in full by @cl445 in #2587
- fix: stop polling the number and switch entities by @cl445 in #2580
- fix: describe every field of the config and options flows by @cl445 in #2584
- docs: describe the actions, device conditions and removal by @cl445 in #2585
- fix: never write a TRV setpoint on a finer grid than the device's by @cl445 in #2597
- fix: point a TRVZB at the remote sensor under the new Zigbee2MQTT names by @cl445 in #2598
- fix: compare forward-port gaps against origin/develop by default by @cl445 in #2586
- test: hold calibration.py above 95 % coverage by @cl445 in #2608
- test: raise the coverage floors the suite has outgrown by @cl445 in #2609
- fix: meet the Silver rules of the Integration Quality Scale by @cl445 in #2603
- test: hold the Silver rules of the Integration Quality Scale by @cl445 in #2601
- test: hold the Gold and Platinum rules of the Integration Quality Scale by @cl445 in #2602
- refactor: name the snapshot fields by their glossary terms by @cl445 in #2607
- refactor: name the room reading room_temperature by @cl445 in #2605
- refactor: name the commanded TRV setpoint, the outdoor reading and the cooler setpoint by @cl445 in #2606
- test: hold the device triggers, conditions and actions to full coverage by @cl445 in #2604
- chore: record the device trigger typing as carried forward by @cl445 in #2621
- fix: match rejected spellings behind a leading underscore by @cl445 in #2615
- refactor: name what calibration writes calibration_output by @cl445 in #2610
- refactor: name the calibration offset and open the adapter contract for it by @cl445 in #2611
- refactor: name the contact delays and the remaining short spellings by @cl445 in #2612
- refactor: name the benchmark valve series valve_percent and retire the naming budget by @cl445 in #2613
- fix: refuse a naming exception for a spelling no term rejects by @cl445 in #2614
- feat: publish the filtered room reading, the slope and the degraded time under their terms by @cl445 in #2620
- refactor: name the sensor entity ids *_entity_id by @cl445 in #2616
- refactor: name the temperature step and the configured target range by @cl445 in #2617
- refactor: name the config constants after the keys they hold by @cl445 in #2618
- feat: publish the preset attributes without the bt_ prefix by @cl445 in #2619
- fix: size the heating-power valve from the effective room temperature by @cl445 in #2624
- refactor: type the model-fix, Trv and state-manager surfaces directly by @cl445 in #2623
- refactor: read guaranteed attributes directly in the entity shell by @cl445 in #2627
- refactor(calibration): direct field access and object-typed debug payloads; drop MPC phantom params by @cl445 in #2628
- refactor: hold the platforms and the config flow to full pyrefly strictness by @cl445 in #2625
- refactor: name the room temperature EMA after the glossary by @cl445 in #2629
- feat: spell out units in the PID and MPC v2 telemetry attributes by @cl445 in #2626
- test: let thermostat stand-ins carry constructor attributes and read them directly by @cl445 in #2634
- refactor(adapters): annotate the delegate and drop its pyrefly exemption by @cl445 in #2630
- refactor: type the event handlers and control_cooler strictly by @cl445 in #2632
- refactor: drop the pyrefly exemptions of watcher.py and helpers.py by @cl445 in #2631
- refactor(calibration): type the calibration shell and drop the unused valve calibration hook by @cl445 in #2633
- refactor: name the temperature slope after the glossary by @cl445 in #2636
- feat: name the remaining controller diagnostics after what they estimate by @cl445 in #2635
- chore: drop config flow attributes nothing reads by @cl445 in #2640
- refactor: type utils/weather.py under strict pyrefly by @cl445 in #2641
- refactor: read thermostat attributes directly in watcher, helpers and diagnostics by @cl445 in #2644
- refactor: type Trv.calibration_balance as CalibrationBalance by @cl445 in #2642
- refactor: drop the pyrefly exemption for climate.py by @cl445 in #2643
- Add z-trv-v01 quirk for valve control by @butonche in #2638
- fix: read the advanced boolean options the way the options flow saves them by @cl445 in #2648
- refactor: type the stored-value coercers on object in a stdlib-only module by @cl445 in #2646
- refactor: spell out the unit of the stored re-identification RMSEs by @cl445 in #2647
- refactor: parse the entry settings into TypedDicts once at setup by @cl445 in #2649
- fix: read the calibration mode and type alike in every reader by @cl445 in #2650
- refactor: accept the control-theory notation by name and place by @cl445 in #2653
- refactor: drop the _C suffix from absolute temperatures by @cl445 in #2652
- fix: calibrate the COZB0001 on the offset it adds to its setpoint by @cl445 in #2651
- refactor: read the legacy stores as Mapping[str, object] by @cl445 in #2655
- refactor: declare every PEP 8 naming exception in pyproject.toml by @cl445 in #2658
- refactor: read the unified state store and the MPC v2 snapshot as Mapping[str, object] by @cl445 in #2656
- refactor: read other entries' settings through lenient typed accessors by @cl445 in #2659
- refactor: build the climate entity from the parsed settings by @cl445 in #2657
- refactor: type the config flow's working state as drafts by @cl445 in #2665
- refactor: take restored attributes as object and narrow them at each consumer by @cl445 in #2666
- refactor: write the unified state store through typed per-section writers by @cl445 in #2667
- test: hold climate.py at the coverage target and mark test-coverage done by @cl445 in #2664
- test: cover the adapters, the safety hull and the scheduler by @cl445 in #2660
- test: cover the model quirk modules toward the test-coverage rule by @cl445 in #2661
- test: cover the PID and MPC v1 calibration controllers by @cl445 in #2662
- test: raise switch, number and TRV event coverage to 95 % and above by @cl445 in #2663
- fix: compare the options flow's calibration algorithms the way the runtime reads them by @cl445 in #2669
- refactor: clamp the typed thermal stats without reparsing them by @cl445 in #2670
- feat: check rejected word parts and unit suffixes in names by @cl445 in #2671
- test: allow typing.Any only where a foreign signature puts it by @cl445 in #2680
- refactor: type the cooler send cache, the diagnostics payload and the reported-mode readers by @cl445 in #2675
- refactor: type the model quirks through module protocols by @cl445 in #2679
- fix: restore the typed legacy store reads a merge resolution reverted by @cl445 in #2674
- refactor: type the ecosystem adapters through a module protocol by @cl445 in #2676
- fix: keep a PID gain set anywhere its number allows by @cl445 in #2677
- feat: categorise, class and disable the sensors as the Gold entity rules ask by @cl445 in #2673
- docs: meet the Gold documentation rules of the quality scale by @cl445 in #2672
- fix: let a TypeError from the climate mode write reach the retrying caller by @cl445 in #2668
- fix: decide summer mode on a damped outdoor temperature with hysteresis by @cl445 in #2678
- refactor: drop the type conversions pyrefly finds redundant and hold them as errors by @cl445 in #2683
- refactor: spell out temperature, percent and time units outside the notation by @cl445 in #2682
- refactor: read the persisted state through typed per-field readers by @cl445 in #2684
- refactor: read attributes directly where their owner declares them by @cl445 in #2686
- feat: drop the sun intensity sensor no controller reads by @cl445 in #2685
- refactor: spell out temperature and percent in the calibration code by @cl445 in #2687
- fix: damp the weather entity's temperature and read daily forecasts as high and low by @cl445 in #2681
- test: type-check scripts and the gate tests by @cl445 in #2688
- refactor: spell out temperature and minutes in the persisted MPC and PID fields by @cl445 in #2689
- test: type-check the integration and benchmark tests by @cl445 in #2692
- fix: check number.py at full type strictness and mark strict-typing done by @cl445 in #2691
- refactor: spell out the remaining word parts in the tests, empty the naming budget by @cl445 in #2690
- fix: refuse a Better Thermostat or a setpoint-less climate as thermostat or cooler by @cl445 in #2701
- test: type-check the unit tests by @cl445 in #2693
- docs: document device trigger parameters and the damped outdoor temperature by @cl445 in #2699
- fix: key repair issues by config entry and drop the confirm-only fix flow by @cl445 in #2700
- test: type-check the shared test factories and the root conftest by @cl445 in #2736
- refactor: drop the MPC cycle temperature that nothing reads by @cl445 in #2702
- fix: hold the naming budget per name, not per file by @cl445 in #2703
- fix: translate the config-flow help texts and correct the PID reset action texts by @cl445 in #2709
- fix: derive the room mode of a head without off mode only from a press by @cl445 in #2706
- fix: stop treating stale inputs as current readings by @cl445 in #2720
- fix: keep the PID integral and the user's PID settings per TRV across target changes by @cl445 in #2724
- fix: keep MPC v2 on its plan, inside the valve cap and across prior changes by @cl445 in #2717
- test: write out pending core store saves before counting listeners after an unload by @cl445 in #2737
- fix: stop re-sending off-grid setpoints and turn TRVs off reliably by @cl445 in #2723
- fix: keep an off cooler's placeholder and a coarser answer out of the cooling target by @cl445 in #2715
- fix: make the device triggers and the hvac action condition work with string batteries, coolers and no threshold by @cl445 in #2711
- fix: keep a knob turn made while a window or door is open as the room's target by @cl445 in #2738
- fix: pick the writable valve entity, skip the closing degree and share the child-lock lookup by @cl445 in #2708
- fix: calibrate the ME167 with the standard offset sign by @cl445 in #2705
- fix: keep the thermostat working after its entity_id is changed by @cl445 in #2710
- perf: keep the filtered room temperature out of the recorder and write the minute EMA tick only on a published change by @cl445 in #2716
- fix: smooth the PID derivative over time and tune Kd only on real overshoots by @cl445 in #2712
- fix: hold a separate cooler to the decided mode, and write it no setpoint while it is off by @cl445 in #2726
- fix: restore and stop background work cleanly when a thermostat is unloaded by @cl445 in #2721
- fix: leave a preset on a manual cooling target and drop its saved cooling target by @cl445 in #2714
- fix: keep a press at a TRV that lands during or right after a control cycle by @cl445 in #2728
- fix: bound TRV, quirk and cooler writes and the initial tweak so one silent device cannot stall the room by @cl445 in #2719
- fix: let the options flow repair a refused entry and prefill only what it offers by @cl445 in #2725
- fix: pause the external temperature keepalive while the room sensor gives no reading by @cl445 in #2704
- fix: convert temperatures at number entities into the unit they publish by @cl445 in #2718
- fix: write a setpoint on the whole degrees a Fahrenheit TRV is shown in by @cl445 in #2713
- fix: carry sensor changes, the room filter and a removed preset correctly through startup by @cl445 in #2722
- fix: follow a configured entity to its new entity id by @cl445 in #2727
- docs: compare the 2.0 upgrade page with 1.9.3 and fix stale pages before the release by @cl445 in #2707
- refactor: type calibration debug payloads, enums, tuples and lookup tables by @cl445 in #2696
- fix: keep the MPC adaptation flags in the identification debug payload by @cl445 in #2730
- refactor: tag the calibration balance with the controller that wrote it by @cl445 in #2731
- fix: match the pyproject version to the manifest's 2.0.0-Beta-1 by @cl445 in #2745
- fix: read offset back on offset-calibrated TRVs; type Trv.calibration by @cl445 in #2694
- fix: limit the calibration offset wait, read and reconcile to offset-calibrated TRVs by @cl445 in #2729
- refactor: mark absent MPC v2 cycle stamps with None by @cl445 in #2733
- refactor: type the core's coupled state fields and preset vocabulary by @cl445 in #2734
- refactor: type TRV write path, cooler send cache, reported HVAC action by @cl445 in #2697
- refactor: type adapter channels, config flow and platform entity records by @cl445 in #2695
- refactor: type device automation, valve maintenance, thermal readings by @cl445 in #2735
- refactor: type climate settings, store records and entity bookkeeping by @cl445 in #2698
- refactor: drop the never-updated last_change state attribute by @cl445 in #2732
- fix: close the valve of a direct-valve TRV when BT switches off by @cl445 in #2761
- fix: detect the Tuya offset entity and keep its head's mode on offset writes by @cl445 in #2760
- fix: count the setpoint a TRV holds when the write watchdog gives up as BT's own by @cl445 in #2772
- fix: say when the offset calibration type is offered by @cl445 in #2773
- fix: keep a TRVZB's own reading out of its external temperature input by @jpjonte in #2766
- fix: let MPC v2 open the valve for a setpoint above the flow temperature by @cl445 in #2776
- feat: expose the outdoor threshold and the tolerance as live number entities by @cl445 in #2774
- feat: make the MPC v2 flow temperature configurable by @cl445 in #2777
- fix: back off and report a setpoint the TRV does not take by @cl445 in #2778
- feat: keep powered-off thermostats out of repairs with an availability guard by @cl445 in #2775
- test: pin the decision cascade over every combination of its inputs by @cl445 in #2780
- feat: add a switch that turns window detection off by @cl445 in #2783
- feat: add a switch that pauses learning by @cl445 in #2784
- feat: add a switch that releases the devices to the user by @cl445 in #2782
- refactor: narrow live device states with a state_is_live TypeGuard by @cl445 in #2785
- fix: carry a restored or manually ended preset into the kernel's mode region by @cl445 in #2787
- refactor: carry a TRV's budget retry and unread report as one value each by @cl445 in #2789
- refactor: type balance results per strategy and build state keys in one place by @cl445 in #2788
- test: stop the benchmark scoring scenarios that measure nothing by @cl445 in #2794
- refactor: keep the tracked entities of an entry on its runtime data by @cl445 in #2786
- refactor: model the maintenance region as one class per phase by @cl445 in #2790
- test: clear the pyrefly warnings under tests/ by @cl445 in #2795
- test: score benchmark energy by the heat the radiator delivers by @cl445 in #2797
- test: ratchet the benchmark regression gate per controller and dimension by @cl445 in #2798
- test: size the winter-week plant for its design temperature by @cl445 in #2801
- refactor: type the heating target as never None by @cl445 in #2791
- refactor: require the system unit and plain floats for step rounding by @cl445 in #2793
- refactor: hand the controllers both temperatures as floats by @cl445 in #2792
- refactor: require adapter, quirks and model on every TRV record by @cl445 in #2804
- fix: fall back to the TRV's own configured model when the registry names none by @cl445 in #2807
- refactor: hold the learners through a device release as through a learning pause by @cl445 in #2799
- feat: publish why the thermostat is not heating and which overrides are held by @cl445 in #2800
- test: run the benchmark through production's signal path by @cl445 in #2805
- test: read the released and blocked flags into annotated locals by @cl445 in #2809
- feat: give ZHA its own adapter with the valve number as valve channel by @cl445 in #2803
- test: score benchmark comfort by the deviation beyond the band by @cl445 in #2810
- refactor: take what an adapter shares with generic by import, not by wrapper by @cl445 in #2806
- test: raise the coverage floors to the level develop reached by @cl445 in #2808
- docs: add automation recipes and two pause-learning blueprints by @cl445 in #2802
- refactor: take the heating target as a float in the helpers downstream by @cl445 in #2815
- refactor: default the valve cap to fully open instead of None by @cl445 in #2816
- refactor: carry the re-identification fit as one ReidFit on ReidOutcome by @cl445 in #2817
- refactor: require the room temperature sensor in the entry settings by @cl445 in #2819
- refactor: narrow small fields that never hold None by @cl445 in #2820
- feat: take up the model the device registry names when a TRV is initialised by @cl445 in #2821
- refactor: start Trv.last_calibration at 0.0 and Trv.max_temp at 30.0 by @cl445 in #2818
- docs: note how the two pause blueprints interact and give the Fahrenheit values by @cl445 in #2813
- feat: add a switch per TRV that releases that TRV to the user by @cl445 in #2814
- feat: let MPC v2 cope with room sensors that report only on a change by @cl445 in #2822
- docs: list the removed last_change attribute on the 2.0 upgrade page by @cl445 in #2824
- refactor: drop the startup-only Optionals from the thermostat entity by @cl445 in #2826
- fix: clamp each TRV's MPC v1 share to its own max opening by @cl445 in #2827
- refactor: drop guards against a missing control queue, tolerance and TRV options by @cl445 in #2829
- refactor: build each entity unique id in one place and key the trackers by str by @cl445 in #2830
- refactor: give the maintenance region a schedule in every phase by @cl445 in #2831
- test(benchmark): show MPC v2 on a coarse sensor with its threshold learned by @cl445 in #2828
- fix: drop the TRV override from the room's HVAC action by @cl445 in #2833
- fix: keep the valve maintenance date across restarts and hide it while unused by @cl445 in #2832
- fix(mpc_v2): widen the disturbance bound on fast priors only while the room is settled by @cl445 in #2834
- fix(shelly): enforce BLU TRV valve-only control by @acuiuli in #2779
- fix: label the room sensor field as a room sensor in every language by @cl445 in #2835
- fix(quirks): negate the offset of TermoWeb heaters at the adapter boundary by @cl445 in #2836
- test(benchmark): model a heat source whose flow temperature moves and pauses by @cl445 in #2837
- refactor: drop the MPC v2 flow temperature option by @cl445 in #2843
- Fix switch state restoration on Home Assistant 2026.11 by @gerrit117 in #2857
- fix: take the range a TRV publishes while it heats by @cl445 in #2844
- fix: read a unitless room sensor in the system unit by @cl445 in #2854
- feat: write the room temperature to the Danfoss Ally external room sensor by @cl445 in #2851
- feat: add Aqara SRTS-A01 quirk by @infy1995 in #2855
- fix: bound the room's heating range by the ranges its TRVs heat in by @cl445 in #2852
- refactor: give every TRV of a group the group's valve command by @cl445 in #2848
- fix: step a TRV group's MPC v2 controller once per control cycle by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2864
- fix(calibration): log the overheating protection term by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2880
- chore: record the 1.9.4 backports in the forward-port gaps by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2882
- fix(tado): clamp the calibration offset to the ±9.99 range Tado's API accepts by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2866
- fix: feed the room temperature to a Sonoff TRVZB paired through ZHA by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2881
- fix: close the valve again when a closed TRV reports it open by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2883
- refactor: read a TRV's startup temperature through attr_to_celsius by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2886
- fix: read a valve write back from every entity it set, and trust no assumed state by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2884
- feat: read and write Z-Wave offsets counted in tenths of a degree by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2888
- docs: describe TPI as a steady valve opening in the README by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2896
- fix(calibration): keep an open valve's setpoint above the TRV's own reading by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2889
- fix: read a valve back in the units its entity publishes by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2887
- docs: describe MPC v2 without direct valve control by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2900
- feat: write the room temperature to a Shelly BLU TRV's external temperature number by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2891
- feat: keep a TRV's own sensor selection, split a group's valve by TRV temperature by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2893
- feat: leave a TRV that regulates on a Matter-bound sensor to its own control by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2892
- chore: let Dependabot propose monthly action and lock file updates on develop by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2901
- chore(deps): update dependencies to Home Assistant 2026.10.4 by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2902
- docs: name the model valve controls wherever Direct Valve Based availability is described by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2905
- ci: measure the maintenance line from its fork point by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2908
- test: feed counted room values through the sensors in the device automation tests by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2906
- docs: name the model valve controls wherever Direct Valve Based availability is described by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2904
- ci: boot the integration in the coming Home Assistant images every night by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2903
- chore: record 1.9 as merged into develop without taking its tree by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2910
- Release 1.9.4 on master by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2909
- fix: match the pyproject version to the manifest's 2.0.0-Beta-2 by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2935
- Add support for Simplified Chinese by @If-Real in https://github.com/KartoffelToby/better_thermostat/pull/2861
- chore: bump dependencies to their latest releases by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2936
- chore: move the website to Astro 7 and Starlight 0.42 by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2937
- chore: build the website on pull requests and fill in its metadata by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2938
- fix: keep a Bosch BTH-RA on the valve demand Better Thermostat wrote by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2941
- fix: keep the Aqara W600 inside its applied offset range and stop offset calibration on the IKEA LILJEBAGGE by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2942
- chore: record the quirk valve probe of the 1.9 line as carried forward by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2945
- feat: report a calibration offset that stays at the limit of its range by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2944
- chore: require Home Assistant 2026.11 and test with pytest-homeassistant by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2939
- fix: drive the Sonoff TRV-ZBT valve through its heating and idle opening by @cl445 in https://github.com/KartoffelToby/better_thermostat/pull/2943
- feat: optimize website for SEO, LLMs, and accessibility by @KartoffelToby in https://github.com/KartoffelToby/better_thermostat/pull/2946
- test: fix trailing slash in /schedule redirect assertion by @KartoffelToby in https://github.com/KartoffelToby/better_thermostat/pull/2947
- Update the website for v2 and more information in general by @KartoffelToby in https://github.com/KartoffelToby/better_thermostat/pull/2860
New Contributors
- @micmatmoc made their first contribution in #2499
- @butonche made their first contribution in #2638
- @jpjonte made their first contribution in #2766
- @acuiuli made their first contribution in #2779
- @infy1995 made their first contribution in #2855
- @If-Real made their first contribution in https://github.com/KartoffelToby/better_thermostat/pull/2861
Full Changelog: 1.9.4...2.0.0