fumis 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fumis-0.1.0/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2019-2026 Franck Nijhof
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
fumis-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,432 @@
1
+ Metadata-Version: 2.4
2
+ Name: fumis
3
+ Version: 0.1.0
4
+ Summary: Asynchronous Python client for the Fumis WiRCU API.
5
+ License-Expression: MIT
6
+ License-File: LICENSE.md
7
+ Keywords: api,async,austroflamm,client,eco-spar,fumis,heating,heta,home-assistant,home-automation,iot,pellet-stove,smart-home,stove,wircu
8
+ Author: Franck Nijhof
9
+ Author-email: opensource@frenck.dev
10
+ Maintainer: Franck Nijhof
11
+ Maintainer-email: opensource@frenck.dev
12
+ Requires-Python: >=3.11
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Natural Language :: English
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Provides-Extra: cli
24
+ Requires-Dist: aiohttp (>=3.0.0)
25
+ Requires-Dist: awesomeversion (>=22.0.0)
26
+ Requires-Dist: mashumaro (>=3.13,<4.0.0)
27
+ Requires-Dist: orjson (>=3.9.8)
28
+ Requires-Dist: rich (>=13.0.0) ; extra == "cli"
29
+ Requires-Dist: textual (>=3.0.0,<4.0.0) ; (python_version < "4.0") and (extra == "cli")
30
+ Requires-Dist: textual-plotext (>=0.2.0,<1.0.0) ; (python_version < "4.0") and (extra == "cli")
31
+ Requires-Dist: typer (>=0.15.1) ; extra == "cli"
32
+ Requires-Dist: yarl (>=1.6.0)
33
+ Project-URL: Bug Tracker, https://github.com/frenck/python-fumis/issues
34
+ Project-URL: Changelog, https://github.com/frenck/python-fumis/releases
35
+ Project-URL: Documentation, https://github.com/frenck/python-fumis
36
+ Project-URL: Homepage, https://github.com/frenck/python-fumis
37
+ Project-URL: Repository, https://github.com/frenck/python-fumis
38
+ Description-Content-Type: text/markdown
39
+
40
+ # Python: Asynchronous client for the Fumis WiRCU API
41
+
42
+ [![GitHub Release][releases-shield]][releases]
43
+ [![Python Versions][python-versions-shield]][pypi]
44
+ ![Project Stage][project-stage-shield]
45
+ ![Project Maintenance][maintenance-shield]
46
+ [![License][license-shield]](LICENSE.md)
47
+
48
+ [![Build Status][build-shield]][build]
49
+ [![Code Coverage][codecov-shield]][codecov]
50
+ [![OpenSSF Scorecard][scorecard-shield]][scorecard]
51
+ [![Open in Dev Containers][devcontainer-shield]][devcontainer]
52
+
53
+ [![Sponsor Frenck via GitHub Sponsors][github-sponsors-shield]][github-sponsors]
54
+
55
+ [![Support Frenck on Patreon][patreon-shield]][patreon]
56
+
57
+ Asynchronous Python client for the Fumis WiRCU API.
58
+
59
+ ## About
60
+
61
+ This package allows you to control and monitor Fumis WiRCU pellet stove
62
+ devices programmatically. It is mainly created to allow third-party programs
63
+ to automate the behavior of a Fumis WiRCU device.
64
+
65
+ An excellent example of this might be Home Assistant, which allows you to write
66
+ automations, to turn on your pellet stove and set a target temperature.
67
+
68
+ Known compatible stove brands:
69
+
70
+ - Austroflamm (Clou Duo, MO DUO, Polly 2.0)
71
+ - Heta (Green 200)
72
+ - HAAS+SOHN
73
+ - Eco Spar (Auriga, Solara, Tukana, Karina, Nova)
74
+ - Prity
75
+
76
+ ## Installation
77
+
78
+ ```bash
79
+ pip install fumis
80
+ ```
81
+
82
+ To install with the optional CLI:
83
+
84
+ ```bash
85
+ pip install "fumis[cli]"
86
+ ```
87
+
88
+ ## CLI
89
+
90
+ The optional CLI lets you control your stove directly from the terminal.
91
+ The `--mac` and `--password` options can also be set via the `FUMIS_MAC`
92
+ and `FUMIS_PASSWORD` environment variables.
93
+
94
+ ```bash
95
+ # Set credentials once via environment variables
96
+ export FUMIS_MAC=AABBCCDDEEFF
97
+ export FUMIS_PASSWORD=1234
98
+
99
+ # Launch the live TUI dashboard
100
+ fumis
101
+
102
+ # Show device information
103
+ fumis info
104
+
105
+ # Turn the stove on/off
106
+ fumis on
107
+ fumis off
108
+
109
+ # Set target temperature
110
+ fumis temperature 23.5
111
+
112
+ # Set power level (1-5)
113
+ fumis power 3
114
+
115
+ # Enable/disable eco mode
116
+ fumis eco true
117
+
118
+ # Show weekly timer schedule / enable / disable
119
+ fumis timer
120
+ fumis timer true
121
+
122
+ # Sync the stove's clock to your system time
123
+ fumis sync-clock
124
+
125
+ # Show service diagnostics (sensors, IO, temperature channels)
126
+ fumis diagnostics
127
+
128
+ # Dump raw API response as JSON
129
+ fumis dump
130
+
131
+ # Emit machine-readable JSON
132
+ fumis info --json
133
+ ```
134
+
135
+ The default command (no subcommand) launches a live TUI dashboard with
136
+ real-time temperature graphs, status display, and keyboard controls for
137
+ on/off, temperature, and power level.
138
+
139
+ ## Usage
140
+
141
+ The client is an async context manager; every API call is a coroutine:
142
+
143
+ ```python
144
+ import asyncio
145
+
146
+ from fumis import Fumis, StoveStatus
147
+
148
+
149
+ async def main() -> None:
150
+ """Show example on controlling your Fumis WiRCU device."""
151
+ async with Fumis(mac="AABBCCDDEEFF", password="1234") as fumis:
152
+ info = await fumis.update_info()
153
+
154
+ # Stove identity
155
+ print(info.controller.manufacturer) # "Austroflamm"
156
+ print(info.controller.model_name) # "Clou Duo"
157
+
158
+ # Status
159
+ print(info.controller.stove_status) # StoveStatus.OFF
160
+ print(info.controller.on) # False
161
+
162
+ # Temperatures
163
+ main_temp = info.controller.main_temperature
164
+ if main_temp:
165
+ print(f"Room: {main_temp.actual}° → {main_temp.setpoint}°")
166
+
167
+ # Combustion chamber
168
+ print(info.controller.combustion_chamber_temperature)
169
+
170
+ # Power
171
+ print(f"{info.controller.power.kw} kW (level {info.controller.power.set_power})")
172
+
173
+ # Door sensor
174
+ print(f"Door open: {info.controller.door_open}")
175
+
176
+ # Fuel level
177
+ fuel = info.controller.fuel()
178
+ if fuel:
179
+ print(f"Fuel: {fuel.quantity_percentage}%")
180
+
181
+ # Weekly timer schedule
182
+ schedule = info.controller.schedule
183
+ print(f"Timer: {'on' if info.controller.timer_enable else 'off'}")
184
+ for prog in schedule.programs:
185
+ if prog.active:
186
+ print(f" {prog}") # "21:00-22:10"
187
+ print(f"Active days: {schedule.active_days}")
188
+
189
+ # Control the stove
190
+ await fumis.turn_on()
191
+ await fumis.set_target_temperature(23.0)
192
+ await fumis.set_power(3)
193
+ await fumis.set_eco_mode(enabled=True)
194
+ await fumis.set_timer(enabled=True)
195
+ await fumis.set_fan_speed(3)
196
+ await fumis.set_clock()
197
+ await fumis.turn_off()
198
+
199
+
200
+ if __name__ == "__main__":
201
+ asyncio.run(main())
202
+ ```
203
+
204
+ ### Raw API access
205
+
206
+ For diagnostics, debugging, or fixture capture (useful for Home Assistant
207
+ diagnostic downloads):
208
+
209
+ ```python
210
+ async with Fumis(mac="AABBCCDDEEFF", password="1234") as fumis:
211
+ # Get the raw, unprocessed JSON dict from the API
212
+ raw = await fumis.raw_status()
213
+ print(json.dumps(raw, indent=2))
214
+ ```
215
+
216
+ ### Accessing diagnostic data
217
+
218
+ All diagnostic variables and parameters from the Fumis controller are
219
+ accessible via the structured model:
220
+
221
+ ```python
222
+ info = await fumis.update_info()
223
+ c = info.controller
224
+
225
+ # Convenience properties (return None if not available)
226
+ c.exhaust_temperature # Exhaust gas temp (var[11])
227
+ c.fan1_speed # Fan 1 speed (var[4])
228
+ c.fan2_speed # Fan 2 speed (var[12])
229
+ c.f02 # F02 sensor input (var[34])
230
+ c.pressure # Pressure sensor (var[35])
231
+ c.door_open # Door sensor (var[33]) - True/False/None
232
+ c.stove_model # Stove model ID (var[96])
233
+ c.parameter_version # Parameter version (var[97])
234
+ c.backwater_temperature # Backwater temp for hydronic stoves (var[22])
235
+
236
+ # Raw diagnostic access (escape hatch)
237
+ c.diagnostic.variable(42) # Any variable by ID → int | None
238
+ c.diagnostic.parameter(14) # Any parameter by ID → int | None
239
+
240
+ # All temperature channels
241
+ for temp in c.temperatures:
242
+ print(f" Channel {temp.id}: {temp.actual}° (on screen: {temp.on_main_screen})")
243
+
244
+ # Iterate fans, fuels, etc.
245
+ for fan in c.fans:
246
+ print(f" Fan {fan.id}: speed {fan.speed}")
247
+ ```
248
+
249
+ ### Error handling
250
+
251
+ The exception hierarchy allows catching at any granularity:
252
+
253
+ ```python
254
+ from fumis import (
255
+ Fumis,
256
+ FumisAuthenticationError,
257
+ FumisConnectionError,
258
+ FumisConnectionTimeoutError,
259
+ FumisError,
260
+ FumisResponseError,
261
+ FumisStoveOfflineError,
262
+ )
263
+
264
+ try:
265
+ async with Fumis(mac="AABBCCDDEEFF", password="1234") as fumis:
266
+ await fumis.turn_on()
267
+ except FumisAuthenticationError:
268
+ # Invalid MAC address or PIN (HTTP 401)
269
+ ...
270
+ except FumisStoveOfflineError:
271
+ # WiRCU not connected to cloud (HTTP 404)
272
+ ...
273
+ except FumisConnectionTimeoutError:
274
+ # Request timed out
275
+ ...
276
+ except FumisConnectionError:
277
+ # Any connectivity issue (timeout, DNS, HTTP error)
278
+ ...
279
+ except FumisError:
280
+ # Any Fumis-specific error
281
+ ...
282
+ ```
283
+
284
+ Exception hierarchy:
285
+
286
+ ```
287
+ FumisError
288
+ ├── FumisConnectionError
289
+ │ └── FumisConnectionTimeoutError
290
+ ├── FumisResponseError
291
+ ├── FumisAuthenticationError
292
+ └── FumisStoveOfflineError
293
+ ```
294
+
295
+ ### Enums
296
+
297
+ Status codes use proper Python enums, booleans where they make sense:
298
+
299
+ ```python
300
+ from fumis import StoveStatus
301
+
302
+ info.controller.stove_status == StoveStatus.COMBUSTION # True
303
+ info.controller.on # True
304
+ info.controller.eco_mode.enabled # False
305
+
306
+ # Unknown values from the API are handled gracefully
307
+ StoveStatus(999) # StoveStatus.UNKNOWN (never crashes)
308
+ ```
309
+
310
+ ## Changelog & Releases
311
+
312
+ This repository keeps a change log using [GitHub's releases][releases]
313
+ functionality. The format of the log is based on
314
+ [Keep a Changelog][keepchangelog].
315
+
316
+ Releases are based on [Semantic Versioning][semver], and use the format
317
+ of `MAJOR.MINOR.PATCH`. In a nutshell, the version will be incremented
318
+ based on the following:
319
+
320
+ - `MAJOR`: Incompatible or major changes.
321
+ - `MINOR`: Backwards-compatible new features and enhancements.
322
+ - `PATCH`: Backwards-compatible bugfixes and package updates.
323
+
324
+ ## Contributing
325
+
326
+ This is an active open-source project. We are always open to people who want to
327
+ use the code or contribute to it.
328
+
329
+ We've set up a separate document for our
330
+ [contribution guidelines](CONTRIBUTING.md).
331
+
332
+ For in-depth API documentation and reverse engineering notes, see
333
+ [RESEARCH.md](RESEARCH.md).
334
+
335
+ Thank you for being involved! :heart_eyes:
336
+
337
+ ## Setting up development environment
338
+
339
+ The easiest way to start, is by opening a CodeSpace here on GitHub, or by using
340
+ the [Dev Container][devcontainer] feature of Visual Studio Code.
341
+
342
+ [![Open in Dev Containers][devcontainer-shield]][devcontainer]
343
+
344
+ This Python project is fully managed using the [Poetry][poetry] dependency
345
+ manager. But also relies on the use of NodeJS for certain checks during
346
+ development.
347
+
348
+ You need at least:
349
+
350
+ - Python 3.11+
351
+ - [Poetry][poetry-install]
352
+ - NodeJS 24+ (including NPM)
353
+
354
+ To install all packages, including all development requirements:
355
+
356
+ ```bash
357
+ npm install
358
+ poetry install
359
+ ```
360
+
361
+ As this repository uses the [prek][prek] framework, all changes
362
+ are linted and tested with each commit. You can run all checks and tests
363
+ manually, using the following command:
364
+
365
+ ```bash
366
+ poetry run prek run --all-files
367
+ ```
368
+
369
+ To run just the Python tests:
370
+
371
+ ```bash
372
+ poetry run pytest
373
+ ```
374
+
375
+ ## Authors & contributors
376
+
377
+ The original setup of this repository is by [Franck Nijhof][frenck].
378
+
379
+ For a full list of all authors and contributors,
380
+ check [the contributor's page][contributors].
381
+
382
+ ## License
383
+
384
+ MIT License
385
+
386
+ Copyright (c) 2019-2026 Franck Nijhof
387
+
388
+ Permission is hereby granted, free of charge, to any person obtaining a copy
389
+ of this software and associated documentation files (the "Software"), to deal
390
+ in the Software without restriction, including without limitation the rights
391
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
392
+ copies of the Software, and to permit persons to whom the Software is
393
+ furnished to do so, subject to the following conditions:
394
+
395
+ The above copyright notice and this permission notice shall be included in all
396
+ copies or substantial portions of the Software.
397
+
398
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
399
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
400
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
401
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
402
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
403
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
404
+ SOFTWARE.
405
+
406
+ [build-shield]: https://github.com/frenck/python-fumis/actions/workflows/tests.yaml/badge.svg
407
+ [build]: https://github.com/frenck/python-fumis/actions/workflows/tests.yaml
408
+ [codecov-shield]: https://codecov.io/gh/frenck/python-fumis/branch/main/graph/badge.svg
409
+ [codecov]: https://codecov.io/gh/frenck/python-fumis
410
+ [contributors]: https://github.com/frenck/python-fumis/graphs/contributors
411
+ [devcontainer-shield]: https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode
412
+ [devcontainer]: https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/frenck/python-fumis
413
+ [frenck]: https://github.com/frenck
414
+ [github-sponsors-shield]: https://frenck.dev/wp-content/uploads/2019/12/github_sponsor.png
415
+ [github-sponsors]: https://github.com/sponsors/frenck
416
+ [keepchangelog]: http://keepachangelog.com/en/1.0.0/
417
+ [license-shield]: https://img.shields.io/github/license/frenck/python-fumis.svg
418
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
419
+ [patreon-shield]: https://frenck.dev/wp-content/uploads/2019/12/patreon.png
420
+ [patreon]: https://www.patreon.com/frenck
421
+ [poetry-install]: https://python-poetry.org/docs/#installation
422
+ [poetry]: https://python-poetry.org
423
+ [prek]: https://github.com/frenck/prek
424
+ [project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg
425
+ [pypi]: https://pypi.org/project/fumis/
426
+ [python-versions-shield]: https://img.shields.io/pypi/pyversions/fumis
427
+ [releases-shield]: https://img.shields.io/github/release/frenck/python-fumis.svg
428
+ [releases]: https://github.com/frenck/python-fumis/releases
429
+ [scorecard]: https://scorecard.dev/viewer/?uri=github.com/frenck/python-fumis
430
+ [scorecard-shield]: https://api.scorecard.dev/projects/github.com/frenck/python-fumis/badge
431
+ [semver]: http://semver.org/spec/v2.0.0.html
432
+