aiosolarfocus
Async Python client for Solarfocus ecomanager-touch heating systems, over Modbus TCP. The successor of pysolarfocus.
Install
pip install aiosolarfocus
Read
import asyncio
from aiosolarfocus import ApiVersion, SolarfocusClient, SolarfocusConfig, Systems
async def main() -> None:
config = SolarfocusConfig(
host="10.0.0.5",
system=Systems.VAMPAIR,
api_version=ApiVersion.V_26_020,
heating_circuits=1,
buffers=1,
boilers=1,
)
async with SolarfocusClient(config) as client:
result = await client.update()
print(client.heat_pump.supply_temperature) # float | None
print(client.heating_circuits[0].mode) # HeatingCircuitMode | None
print(client.heat_pump.cop_heating) # float | None
if not result.ok:
print("not read:", *result.failed)
asyncio.run(main())
Reading a value is not asynchronous — it is the last reading, already decoded. Only the calls that talk to the controller are awaited.
None means one of three things, and callers almost always want the same
behaviour for all of them: this firmware or system does not have the register,
it has not been read yet or its last read failed, or the channel is reporting
one of the values an open sensor gives instead of a measurement.
component.raw() and component.info() tell them apart.
Values the library works out from registers — the heat pump's coefficients of
performance, its seasonal figures — are declared beside the registers they come
from, so component.available_values() offers them alongside everything else
and component.info() describes them. An idle heat pump reports None for a
coefficient of performance rather than zero.
Write
from aiosolarfocus import HeatingCircuitMode
await client.heating_circuits[0].set_mode(HeatingCircuitMode.AUTOMATIC)
await client.heating_circuits[0].set_target_supply_temperature(45.0)
await client.photovoltaic.set_smart_meter(-1500) # the library does the two's complement
# Registers the controller wants written together go out together.
await client.heating_circuits[0].set_operating_state(
mode=HeatingCircuitMode.AUTOMATIC,
target_supply_temperature=18.0,
)
A successful write updates the component's own cache, so the new value is readable straight away without re-reading anything.
Errors
update() raises only when the connection itself is the problem, because that
is the one failure that says nothing about any particular component. Everything
else — a range this firmware refuses, a controller answering an exception — is
attributed to the components whose registers were in that read:
try:
result = await client.update()
except SolarfocusConnectionError:
... # the whole controller is unreachable
for key, error in result.failed.items():
... # just these components went quiet
Without asyncio
from aiosolarfocus import SolarfocusConfig, SolarfocusSync
with SolarfocusSync(SolarfocusConfig(host="10.0.0.5")) as sync:
sync.update()
print(sync.client.heat_pump.supply_temperature)
Command line
python -m aiosolarfocus detect --host 10.0.0.5 --evidence
python -m aiosolarfocus dump --host 10.0.0.5
python -m aiosolarfocus watch --host 10.0.0.5 --interval 10 # prints only what changed
python -m aiosolarfocus set --host 10.0.0.5 heating_circuits.1.mode automatic
python -m aiosolarfocus registers --system Vampair --api-version 26.020 # no controller needed
python -m aiosolarfocus plan --system Vampair --api-version 26.020 # no controller needed
Supported
Systems: vampair, therminator, ecotop, Pellet Elegance, octoplus. Firmware: 20.110 through 26.020. Give the version the controller prints on its own screen; a newer one clamps to the newest this library knows.
Only the vampair has been tested against real hardware. The other four are reasoned from the register specification — a register dump from one of them is the most useful thing you can contribute.
Documentation
docs/registers.md— the register map, generated from the tables.docs/protocol.md— how the controller actually behaves, including the ways it misbehaves.docs/register-document.md— the vendor specification everything is read from, and where it is wrong.docs/porting-from-pysolarfocus.md— coming from the synchronous library.
Testing against it
aiosolarfocus.testing ships in the wheel, so a downstream test suite can drive
a real client against a fake controller that reproduces the real one's
behaviour — including refusing unmapped addresses and compacting reads that span
a gap.
from aiosolarfocus.testing import FakeController
config = SolarfocusConfig(host="test")
client = SolarfocusClient(config, transport=FakeController.for_config(config))
About
Successor to pysolarfocus,
rewritten async-native with the register map as validated data. Portions of this
work derive from that project; see NOTICE.
Not affiliated with, endorsed by, or supported by Solarfocus GmbH.
Metadata
Release files for aiosolarfocus 0.2.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aiosolarfocus-0.2.4.tar.gz | 106.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aiosolarfocus-0.2.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 192.4 kB
Release files / aiosolarfocus-0.2.4.tar.gz
| Download URL | aiosolarfocus-0.2.4.tar.gz |
|---|---|
| Size | 106.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e8b8146806a0f134576e96ef61308e9c039c91c1c23f2348d05a5879cf37e6f3
|
|
BLAKE2b-256 checksum How to use checksums |
fc7c9a98242f2ad3a7b1d1c14171a381e98df11dba1d822387e55f47fd8a0713
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / aiosolarfocus-0.2.4-py3-none-any.whl
| Download URL | aiosolarfocus-0.2.4-py3-none-any.whl |
|---|---|
| Size | 85.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
30f3013a5d76037f0bc1283a651fc889e2cd9d2b66c1d5b4d02c18cdee8bbd9b
|
|
BLAKE2b-256 checksum How to use checksums |
d833524fabff2f3c0b439dcff8edc006ebbe6f690465656e808ca725b32ed90d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|