ucapi-framework 1.9.0b4__tar.gz → 1.9.1__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.
Files changed (51) hide show
  1. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/PKG-INFO +20 -27
  2. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/README.md +19 -26
  3. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/pyproject.toml +1 -1
  4. ucapi_framework-1.9.1/tests/test_media_player_entity.py +538 -0
  5. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_select_entity.py +10 -6
  6. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/__init__.py +1 -1
  7. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/driver.py +5 -5
  8. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/select.py +12 -3
  9. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework.egg-info/PKG-INFO +20 -27
  10. ucapi_framework-1.9.0b4/tests/test_media_player_entity.py +0 -259
  11. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/setup.cfg +0 -0
  12. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_button_entity.py +0 -0
  13. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_climate_entity.py +0 -0
  14. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_config.py +0 -0
  15. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_cover_entity.py +0 -0
  16. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_device.py +0 -0
  17. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_discovery.py +0 -0
  18. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_driver.py +0 -0
  19. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_entity.py +0 -0
  20. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_factory_pattern.py +0 -0
  21. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_helpers.py +0 -0
  22. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_ir_emitter_entity.py +0 -0
  23. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_light_entity.py +0 -0
  24. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_migration.py +0 -0
  25. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_remote_entity.py +0 -0
  26. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_sensor_entity.py +0 -0
  27. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_setup.py +0 -0
  28. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_switch_entity.py +0 -0
  29. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/tests/test_voice_assistant_entity.py +0 -0
  30. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/config.py +0 -0
  31. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/device.py +0 -0
  32. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/discovery.py +0 -0
  33. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/__init__.py +0 -0
  34. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/button.py +0 -0
  35. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/climate.py +0 -0
  36. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/cover.py +0 -0
  37. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/ir_emitter.py +0 -0
  38. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/light.py +0 -0
  39. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/media_player.py +0 -0
  40. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/remote.py +0 -0
  41. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/sensor.py +0 -0
  42. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/switch.py +0 -0
  43. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entities/voice_assistant.py +0 -0
  44. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/entity.py +0 -0
  45. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/helpers.py +0 -0
  46. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/migration.py +0 -0
  47. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework/setup.py +0 -0
  48. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework.egg-info/SOURCES.txt +0 -0
  49. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework.egg-info/dependency_links.txt +0 -0
  50. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework.egg-info/requires.txt +0 -0
  51. {ucapi_framework-1.9.0b4 → ucapi_framework-1.9.1}/ucapi_framework.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ucapi-framework
3
- Version: 1.9.0b4
3
+ Version: 1.9.1
4
4
  Summary: ucapi framework that provides core functionality for building integrations.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -10,7 +10,7 @@ Requires-Dist: aiohttp>=3.9.0
10
10
 
11
11
  [![Tests](https://github.com/jackjpowell/ucapi-framework/actions/workflows/test.yml/badge.svg)](https://github.com/jackjpowell/ucapi-framework/actions/workflows/test.yml)
12
12
  [![Discord](https://badgen.net/discord/online-members/zGVYf58)](https://discord.gg/zGVYf58)
13
- [![Buy Me A Coffee](https://img.shields.io/badge/Buy_Me_A_Coffee ☕-FFDD00?logo=buy-me-a-coffee&logoColor=white&labelColor=grey)](https://buymeacoffee.com/jackpowell)
13
+ [![Buy Me A Coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?logo=buy-me-a-coffee&logoColor=white&labelColor=grey)](https://buymeacoffee.com/jackpowell)
14
14
 
15
15
  # UCAPI Framework
16
16
 
@@ -86,12 +86,12 @@ The driver coordinates everything - device lifecycle, entity management, and Rem
86
86
 
87
87
  The framework provides sensible defaults for:
88
88
 
89
- - **`create_entities()`** - Creates one entity per entity type automatically
90
- - **`map_device_state()`** - Maps common state strings (ON, OFF, PLAYING, etc.)
91
- - **`device_from_entity_id()`** - Parses standard entity ID format
89
+ - **`create_entities()`** - Instantiates entities from the `entity_classes` list passed to the constructor; each item can be a class or a factory lambda `(config, device) -> Entity | list[Entity]`
90
+ - **`map_device_state()`** - Maps common state strings (ON, OFF, PLAYING, etc.) to `media_player.States`
91
+ - **`device_from_entity_id()`** - Parses the standard `entity_type.device_id` format
92
92
  - **`get_entity_ids_for_device()`** - Queries and filters entities by device
93
93
 
94
- **Override only what you need**: Custom state enums? Override `map_device_state()`. Conditional entity creation? Override `create_entities()`. Custom entity ID format? Override `device_from_entity_id()` too.
94
+ **Override only what you need**: Custom state enums? Override `map_device_state()`. Logic that can't fit in a lambda? Override `create_entities()`. Custom entity ID format? Override `device_from_entity_id()`.
95
95
 
96
96
  Everything else is automatic. The framework handles Remote connection events (connect, disconnect, standby), entity subscriptions, device lifecycle management, and state synchronization.
97
97
 
@@ -119,13 +119,13 @@ All discovery classes handle the protocol details, timeouts, and error handling.
119
119
 
120
120
  The driver base class automatically wires up Remote events (connect, disconnect, standby, subscribe/unsubscribe) with sensible defaults. You can override any of them, but the defaults handle most cases.
121
121
 
122
- Device events (state changes, errors) automatically propagate to entity state updates. You just emit events from your device and the framework keeps the Remote in sync.
122
+ State flows from device to Remote via the coordinator pattern: the device stores raw state properties and calls `push_update()` when anything changes. Every entity subscribed via `subscribe_to_device()` has its `sync_state()` method called automatically, which reads from the device and calls `self.update({...})` with a fresh dict. The framework diffs against the last-pushed state and sends only changed attributes to the Remote.
123
123
 
124
124
  ## How It Works
125
125
 
126
126
  You inherit from base classes and override only what you need:
127
127
 
128
- **Driver** - Usually works with defaults! Override only if you need custom state mapping or conditional entity creation.
128
+ **Driver** - Usually works with defaults. Pass `entity_classes` to the constructor. Override only if you need custom state mapping or conditional entity creation.
129
129
 
130
130
  **Device** - Implement your connection pattern (verify, poll, handle messages, etc.).
131
131
 
@@ -176,34 +176,22 @@ Optional discovery implementations for common protocols:
176
176
 
177
177
  Lazy imports mean you only need the dependencies if you use them.
178
178
 
179
- ## Real-World Example
180
-
181
- See the PSN integration in this repository:
182
-
183
- - `intg-psn/driver.py` - 90 lines (was 300)
184
- - `intg-psn/psn.py` - 140 lines (was 240)
185
- - `intg-psn/setup_flow.py` - 50 lines (was 250)
186
- - `intg-psn/config.py` - 15 lines (was 95)
187
-
188
- Total: ~295 lines of integration code vs ~885 lines previously. And the new code is type-safe, testable, and maintainable.
189
179
 
190
180
  ## Migration
191
181
 
192
- If you have an existing integration, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for step-by-step instructions with before/after examples.
193
-
194
- For upgrading from a previous version of ucapi-framework:
195
- - **[Upgrading to 1.6.0](https://jackjpowell.github.io/ucapi-framework/upgrade-to-1.6.0/)** - New dynamic entity management features
182
+ If you have an existing integration, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for step-by-step instructions with before/after examples covering the coordinator pattern, `subscribe_to_device`, `sync_state`, and `push_update`.
196
183
 
197
184
  ## Requirements
198
185
 
199
186
  - Python 3.11+
200
187
  - ucapi
201
188
  - pyee
189
+ - aiohttp (required; used by HTTP and WebSocket device base classes)
190
+
191
+ Optional (only if you use the corresponding discovery classes):
202
192
 
203
- Optional (only if you use them):
204
- - aiohttp (for HTTP devices)
205
- - websockets (for WebSocket devices)
206
193
  - ssdpy (for SSDP discovery)
194
+ - sddp-discovery-protocol (for SDDP discovery)
207
195
  - zeroconf (for mDNS discovery)
208
196
 
209
197
  ## Documentation
@@ -231,9 +219,14 @@ Visit <http://127.0.0.1:8000> to view the docs.
231
219
  uv sync --group dev
232
220
  ```
233
221
 
234
- Git hooks are automatically active from the `git-hooks/` directory:
222
+ A `pre-commit` hook is available in the `git-hooks/` directory. To activate it:
223
+
224
+ ```bash
225
+ cp git-hooks/pre-commit .git/hooks/pre-commit
226
+ chmod +x .git/hooks/pre-commit
227
+ ```
235
228
 
236
- - **pre-commit**: Runs `ruff check --fix` and `ruff format` via `uv run`
229
+ The hook runs `ruff check --fix` and `ruff format` before every commit.
237
230
 
238
231
  All development tools run through `uv` and are configured in `pyproject.toml`.
239
232
 
@@ -1,6 +1,6 @@
1
1
  [![Tests](https://github.com/jackjpowell/ucapi-framework/actions/workflows/test.yml/badge.svg)](https://github.com/jackjpowell/ucapi-framework/actions/workflows/test.yml)
2
2
  [![Discord](https://badgen.net/discord/online-members/zGVYf58)](https://discord.gg/zGVYf58)
3
- [![Buy Me A Coffee](https://img.shields.io/badge/Buy_Me_A_Coffee&nbsp;☕-FFDD00?logo=buy-me-a-coffee&logoColor=white&labelColor=grey)](https://buymeacoffee.com/jackpowell)
3
+ [![Buy Me A Coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?logo=buy-me-a-coffee&logoColor=white&labelColor=grey)](https://buymeacoffee.com/jackpowell)
4
4
 
5
5
  # UCAPI Framework
6
6
 
@@ -76,12 +76,12 @@ The driver coordinates everything - device lifecycle, entity management, and Rem
76
76
 
77
77
  The framework provides sensible defaults for:
78
78
 
79
- - **`create_entities()`** - Creates one entity per entity type automatically
80
- - **`map_device_state()`** - Maps common state strings (ON, OFF, PLAYING, etc.)
81
- - **`device_from_entity_id()`** - Parses standard entity ID format
79
+ - **`create_entities()`** - Instantiates entities from the `entity_classes` list passed to the constructor; each item can be a class or a factory lambda `(config, device) -> Entity | list[Entity]`
80
+ - **`map_device_state()`** - Maps common state strings (ON, OFF, PLAYING, etc.) to `media_player.States`
81
+ - **`device_from_entity_id()`** - Parses the standard `entity_type.device_id` format
82
82
  - **`get_entity_ids_for_device()`** - Queries and filters entities by device
83
83
 
84
- **Override only what you need**: Custom state enums? Override `map_device_state()`. Conditional entity creation? Override `create_entities()`. Custom entity ID format? Override `device_from_entity_id()` too.
84
+ **Override only what you need**: Custom state enums? Override `map_device_state()`. Logic that can't fit in a lambda? Override `create_entities()`. Custom entity ID format? Override `device_from_entity_id()`.
85
85
 
86
86
  Everything else is automatic. The framework handles Remote connection events (connect, disconnect, standby), entity subscriptions, device lifecycle management, and state synchronization.
87
87
 
@@ -109,13 +109,13 @@ All discovery classes handle the protocol details, timeouts, and error handling.
109
109
 
110
110
  The driver base class automatically wires up Remote events (connect, disconnect, standby, subscribe/unsubscribe) with sensible defaults. You can override any of them, but the defaults handle most cases.
111
111
 
112
- Device events (state changes, errors) automatically propagate to entity state updates. You just emit events from your device and the framework keeps the Remote in sync.
112
+ State flows from device to Remote via the coordinator pattern: the device stores raw state properties and calls `push_update()` when anything changes. Every entity subscribed via `subscribe_to_device()` has its `sync_state()` method called automatically, which reads from the device and calls `self.update({...})` with a fresh dict. The framework diffs against the last-pushed state and sends only changed attributes to the Remote.
113
113
 
114
114
  ## How It Works
115
115
 
116
116
  You inherit from base classes and override only what you need:
117
117
 
118
- **Driver** - Usually works with defaults! Override only if you need custom state mapping or conditional entity creation.
118
+ **Driver** - Usually works with defaults. Pass `entity_classes` to the constructor. Override only if you need custom state mapping or conditional entity creation.
119
119
 
120
120
  **Device** - Implement your connection pattern (verify, poll, handle messages, etc.).
121
121
 
@@ -166,34 +166,22 @@ Optional discovery implementations for common protocols:
166
166
 
167
167
  Lazy imports mean you only need the dependencies if you use them.
168
168
 
169
- ## Real-World Example
170
-
171
- See the PSN integration in this repository:
172
-
173
- - `intg-psn/driver.py` - 90 lines (was 300)
174
- - `intg-psn/psn.py` - 140 lines (was 240)
175
- - `intg-psn/setup_flow.py` - 50 lines (was 250)
176
- - `intg-psn/config.py` - 15 lines (was 95)
177
-
178
- Total: ~295 lines of integration code vs ~885 lines previously. And the new code is type-safe, testable, and maintainable.
179
169
 
180
170
  ## Migration
181
171
 
182
- If you have an existing integration, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for step-by-step instructions with before/after examples.
183
-
184
- For upgrading from a previous version of ucapi-framework:
185
- - **[Upgrading to 1.6.0](https://jackjpowell.github.io/ucapi-framework/upgrade-to-1.6.0/)** - New dynamic entity management features
172
+ If you have an existing integration, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for step-by-step instructions with before/after examples covering the coordinator pattern, `subscribe_to_device`, `sync_state`, and `push_update`.
186
173
 
187
174
  ## Requirements
188
175
 
189
176
  - Python 3.11+
190
177
  - ucapi
191
178
  - pyee
179
+ - aiohttp (required; used by HTTP and WebSocket device base classes)
180
+
181
+ Optional (only if you use the corresponding discovery classes):
192
182
 
193
- Optional (only if you use them):
194
- - aiohttp (for HTTP devices)
195
- - websockets (for WebSocket devices)
196
183
  - ssdpy (for SSDP discovery)
184
+ - sddp-discovery-protocol (for SDDP discovery)
197
185
  - zeroconf (for mDNS discovery)
198
186
 
199
187
  ## Documentation
@@ -221,9 +209,14 @@ Visit <http://127.0.0.1:8000> to view the docs.
221
209
  uv sync --group dev
222
210
  ```
223
211
 
224
- Git hooks are automatically active from the `git-hooks/` directory:
212
+ A `pre-commit` hook is available in the `git-hooks/` directory. To activate it:
213
+
214
+ ```bash
215
+ cp git-hooks/pre-commit .git/hooks/pre-commit
216
+ chmod +x .git/hooks/pre-commit
217
+ ```
225
218
 
226
- - **pre-commit**: Runs `ruff check --fix` and `ruff format` via `uv run`
219
+ The hook runs `ruff check --fix` and `ruff format` before every commit.
227
220
 
228
221
  All development tools run through `uv` and are configured in `pyproject.toml`.
229
222
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ucapi-framework"
3
- version = "1.9.0b4"
3
+ version = "1.9.1"
4
4
  description = "ucapi framework that provides core functionality for building integrations."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"