Skip to main content

Controlel

Adaptive intelligent heating control platform.

Vision

Controlel is a modular, explainable and adaptive heating regulation platform designed for Home Assistant integration.

The goal is to create a reliable heating controller capable of optimizing comfort, efficiency and condensation performance while maintaining safety and transparency.

Main principles

  • Safety first
  • Explainable decisions
  • Modular architecture
  • Hardware independence
  • Configuration through UI
  • Open-source ready
  • Adaptive regulation

Status

Project phase: Home Assistant one-zone host vertical slice

Core package candidate version: 0.7.0 (not yet published)

Home Assistant integration candidate version: 0.8.2

Use the latest published release for HACS custom-repository installation. Core 0.6.0 and integration 0.8.1 are published and immutable. Core 0.7.0 is the separate M31A release candidate and is not yet published. Integration 0.8.2 remains pinned exactly to controlel==0.6.0; its version and dependency do not move as part of the core release boundary. Controlel is not listed in the default HACS store.

Home Assistant installation

The supported distribution uses the public repository https://github.com/vmshops/controlel as a HACS custom repository. The primary installation flow is:

  1. In HACS, open the menu and select Custom repositories.
  2. Add https://github.com/vmshops/controlel with category Integration.
  3. Download the latest released integration and restart Home Assistant.
  4. Open Settings > Devices & services > Add integration and select Controlel.

The integration manifest makes Home Assistant install the exact public core dependency controlel==0.6.0; users must not install the core manually. Detailed prerequisites, configuration, safety behavior, manual installation, upgrades, removal, and current limitations are in the Home Assistant installation guide.

Home Assistant development integration

The reusable core remains under src/controlel. The first Home Assistant host is a custom component under custom_components/controlel; its dependency direction is strictly custom component to core.

The integration supports one config entry, one zone, one explicitly bound temperature sensor, and one shared heat source. New entries use a filtered temperature selector, generated stable IDs, safe timing defaults, and a simple controlled-switch mode. Existing entries can be edited through Configure; advanced mode preserves separate enable and disable service calls. Options updates fully unload and rebuild the runtime. It uses a dedicated single-worker executor for every synchronous ControlRuntime operation. No core method runs on Home Assistant's event-loop thread.

The core runtime now supports deterministic multi-zone demand composition ahead of a future Home Assistant multi-zone configuration UI. Hysteresis and demand confirmation remain zone-local; a simple unweighted any-zone rule produces one building demand for the unchanged shared-source protection and dispatch path. Source minimum-time configuration is therefore not duplicated per zone.

Milestone 30 adds an optional zone heat-delivery branch after confirmed zone demand. Existing entries remain unmanaged by default. The first Home Assistant slice can drive a generic climate entity with deterministic setpoint assist: confirmed heat selects a configured assist target and no heat restores the zone target. Core contracts also model native, direct-position, binary, remote- temperature, and multiple-actuator capabilities without vendor-specific logic. Commanded and reported actuator state remain distinct; no command claims a physical valve position without device feedback. Adaptive assist, learning, actuator travel verification, and source-water-temperature control are not part of this milestone.

New entries default to asymmetric hysteresis of 0.3 °C below and 0.1 °C above the target, a two-minute heat-demand confirmation interval, plus command-based minimum on/off times of 10/5 minutes. Existing entries resolve all five settings to zero until the user explicitly changes them. The controller preserves its last logical demand within the deadband and reevaluates current demand at a lockout deadline instead of replaying a stored command. Safety-disable commands bypass minimum-on protection; safety-enable commands remain subject to minimum-off protection.

Source observability distinguishes a passive protection boundary from an active lockout. earliest_next_enable_time and earliest_next_disable_time may exist when no command is blocked. Active lockout and deferred-command fields exist only while the current aggregate demand requests a transition that protection prevents. A deadline callback reevaluates current demand and protection instead of replaying a stored command. Successful enable/disable dispatch timestamps are command evidence, not physical boiler feedback; Controlel does not infer whether a burner or boiler is physically running.

Milestone 30.2 adds core-only operational resilience contracts. Source ownership distinguishes externally controlled sources from sources Controlel may reconcile. Requested commands, successful or failed command outcomes, reported controller state, and physical burner state remain separate evidence; unknown is never treated as false. A Controlel-owned source with external-on, no-heat drift and unknown transition age is held conservatively for five minutes before corrective disable is considered. Failed or still-unconfirmed correction remains retryable on a bounded 30-second cadence without polling or command storms. Restart and reload begin with unknown transition history and never reconstruct prior transitions.

The same core boundary adds explicit NORMAL, SAFE_HEATING, EMERGENCY_OFF, and MANUAL_RECOVERY_HEAT operating modes. Recovery waits at most 30 seconds for current demand and reported-source evidence. Manual recovery defaults to two hours and is explicitly cancelled across reload. Safe heating can produce a capability-gated WATER_TARGET intent, but physical water-target dispatch is intentionally unsupported. Bounded diagnostics use stable reason codes and never reinterpret permission or dispatch as physical heat production.

Core 0.6.0 also includes M30.2D Runtime Supervision & Failsafe Recovery. An application-level supervisor quarantines a failed normal-runtime generation, transfers exclusive command authority to a minimal failsafe controller, and uses protected SAFE_HEATING or EMERGENCY_OFF decisions while attempting a bounded restart campaign. The 0.8.2 Home Assistant host binds this supervisor to its one-shot scheduler, failsafe and normal-runtime factories, and explicit reported-source evidence. Supervision works only while the Home Assistant process remains alive; it cannot protect against complete HA, OS, power, or hardware failure.

Each entry creates one Controlel — <Zone name> device with a translated operational summary and stable operational/diagnostic entities. The summary describes logical demand, safety, deferred commands, requested commands, and command outcomes; it never claims physical heat-source state. Configured durations remain visible, while deadline and remaining entities are unavailable when their countdown is inactive. Every public entity, value domain, source projection, control relevance, and truthfulness warning is indexed in the Home Assistant entity reference.

The Options Flow offers Basic, Detailed, and Debug diagnostic profiles. New 0.5.0 and later entries default to Basic. Existing entries without a stored profile resolve to Detailed, preserving periodic operational timing visibility without a setup-time migration write. Basic refreshes presentation on meaningful runtime events and retains 20 trace records; Detailed refreshes active countdowns every 10 seconds and retains 100; Debug refreshes only active countdown entities every second and retains 500. Debug expires after 60 minutes by default and returns to the previous Basic/Detailed profile, or can be kept active until manually changed. Profiles affect presentation, logging, and in-memory evidence only—not regulation.

Core candidate 0.7.0 contains the M31A Operational Events Foundation: immutable operational-event contracts; canonical category and severity taxonomies; and a bounded in-memory stream with a default capacity of 200, deterministic ordering, and explicit drop metadata. Transition and lifecycle de-duplication keeps the stream semantic. Deterministic supervision-campaign correlation connects fatal, failsafe, restart, and recovery evidence, while both normal and failsafe command attempts and outcomes remain visible. Recorder failures are isolated from control behavior, and ControlRuntime.record_runtime_started() is the narrow public lifecycle boundary. Operational events remain separate from the decision trace. M31A adds no notifications, statistics, persistence, polling, or control behavior, and command dispatch or reported source state never claims physical heat.

The integration manifest requires the exact public core release controlel==0.6.0. A supported custom-component deployment can therefore let Home Assistant obtain the core dependency automatically; users do not need to install the core manually. Editable installation remains available for local source compatibility testing. The core test suite does not require Home Assistant, while Home Assistant framework tests use separate local-source and public-package compositions against the same immutable core 0.6.0 release.

Framework compatibility is tested against Home Assistant 2026.7.3 with pytest-homeassistant-custom-component==0.13.347 on Python 3.14.2 or newer. The isolated, hashed environment is defined by requirements/ha-test.in and requirements/ha-test.txt; setup and suite commands are in the development guide. The compatibility harness is separate from HACS release validation. HACS metadata and deterministic release packaging are prepared for 0.8.2, but that candidate has not been published and no default-store publication exists.

Core package artifacts

The reusable core is published as the controlel distribution and import package. Version 0.6.0 is the latest public immutable release; repository version 0.7.0 is the unpublished M31A release candidate. The static version source and PEP 517 build configuration live in pyproject.toml; normal installation depends only on Pydantic. Packaging validation builds one wheel and one sdist, inspects their contents, and installs the wheel into a clean environment outside the checkout.

Core versions 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.5.0, and 0.6.0 are published on PyPI and immutable. Future core corrections require a new version; rebuilt artifacts for an already published version must never be uploaded. Repository packaging CI remains validation-only and contains no publication automation. See the core release guide for the published release record, build validation, and version separation.

Zone heat-demand confirmation

Core 0.3.0 inserts a zone-owned confirmation policy after hysteresis. Milestone 29 keys that state independently per zone and places deterministic building aggregation immediately afterward. Positive-duration heat demand must remain continuous until its deadline; the deadline reevaluates current hysteresis demand rather than replaying stored state. No-heat demand clears immediately. Invalid, unavailable, stale, or future-dated input cancels a pending interval, and valid recovery starts a complete new interval. Zero duration preserves legacy immediate behavior.

This filter is separate from heat-source minimum-off protection and does not detect an open window. The shared source policy consumes confirmed aggregate demand only. Pending state is not persisted across reload or restart, and no state claims that a physical heat source is on or off.

Metadata

Release files for controlel 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for controlel 0.7.0
File Size Uploaded
controlel-0.7.0.tar.gz 81.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for controlel 0.7.0
File Interpreter ABI Platform
controlel-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 211.7 kB

Release files / controlel-0.7.0.tar.gz

Download URL controlel-0.7.0.tar.gz
Size 81.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d333e10b9a3e0d5fa31cac9877279971cb6c330ac1b755fc64936365bd01c765
BLAKE2b-256 checksum
How to use checksums
9ecc664d116e2b5ba6aa0907b4b7e79bd111eb4435eb628ff1b7468b9b28130c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release files / controlel-0.7.0-py3-none-any.whl

Download URL controlel-0.7.0-py3-none-any.whl
Size 130.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
caf5b68a4045a458958cd60ed004b7660b45340ed44316554d2d4ced81f32bbd
BLAKE2b-256 checksum
How to use checksums
6fdba3b7d183c3c7e296e968102294476e077c427b3b0d260df97ab6e75d1d7d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.5

Release history Release notifications | RSS feed

0.17.0

2 release files

0.16.0

2 release files

0.15.0

2 release files

0.14.0

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page