piphi-runtime-kit-python 0.3.0__tar.gz → 0.4.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.
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/PKG-INFO +77 -5
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/README.md +76 -4
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/pyproject.toml +1 -1
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/__init__.py +8 -1
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/starter.py +29 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/schemas.py +63 -1
- piphi_runtime_kit_python-0.4.1/tests/test_runtime_starter.py +53 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_schemas_matrix.py +45 -1
- piphi_runtime_kit_python-0.3.0/tests/test_runtime_starter.py +0 -21
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/LICENSE +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/adapters/__init__.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/adapters/fastapi.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/fastapi.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/__init__.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/auth.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/config_sync.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/configuration.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/context.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/discovery.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/dispatch.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/errors.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/events.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/health.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/lifespan.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/mqtt.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/registry.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/state.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/tasks.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/src/piphi_runtime_kit_python/runtime/telemetry.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/__init__.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_config_sync.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_fastapi_adapter.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_auth.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_auth_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_config_sync_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_configuration.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_configuration_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_delivery_errors.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_discovery.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_discovery_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_dispatch.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_dispatch_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_errors_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_events.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_events_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_health.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_lifespan.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_mqtt.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_mqtt_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_registry.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_registry_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_support_matrix.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_tasks.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_telemetry.py +0 -0
- {piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_telemetry_matrix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: piphi-runtime-kit-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: PiPhi Network runtime integration helpers
|
|
5
5
|
Keywords: piphi,runtime,integration,iot
|
|
6
6
|
Author-Email: KelvinSan <support@piphi.network>
|
|
@@ -113,18 +113,28 @@ hide vendor logic behind an overly magical abstraction.
|
|
|
113
113
|
|
|
114
114
|
The package currently supports Python `>=3.11`.
|
|
115
115
|
|
|
116
|
-
Install from
|
|
116
|
+
Install from PyPI:
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
pdm add
|
|
119
|
+
pdm add piphi-runtime-kit-python
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
If you need the optional FastAPI helpers:
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
|
-
pdm add "
|
|
125
|
+
pdm add "piphi-runtime-kit-python[fastapi]"
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
If you prefer `pip`:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
pip install piphi-runtime-kit-python
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Package page:
|
|
135
|
+
|
|
136
|
+
- https://pypi.org/project/piphi-runtime-kit-python/0.3.0/
|
|
137
|
+
|
|
128
138
|
## First 15 Minutes
|
|
129
139
|
|
|
130
140
|
If you want the shortest path to a working runtime, do this:
|
|
@@ -160,9 +170,71 @@ These are the most common runtime routes and what they are for.
|
|
|
160
170
|
| `/deconfigure` | `POST` | Usually | Remove one config | `RuntimeConfigRemoveResponse` |
|
|
161
171
|
| `/events` | `GET` | Common | Show recent local runtime events | `build_event_list_response(...)` |
|
|
162
172
|
| `/state` | `GET` | Common | Show current runtime state | `registry.entries`, `registry.state_snapshots` |
|
|
163
|
-
| `/entities` | `GET` | Integration-specific | Show normalized entity list |
|
|
173
|
+
| `/entities` | `GET` | Integration-specific | Show normalized entity list | `build_entities_response(...)`, `starter.entities_response(...)` |
|
|
164
174
|
| `/ui` or `/ui-config` | `GET` | Optional | Return config UI metadata | integration-owned |
|
|
165
175
|
|
|
176
|
+
## Modeling `/entities`
|
|
177
|
+
|
|
178
|
+
For simple integrations, `/entities` can still be a plain list of generic
|
|
179
|
+
entities.
|
|
180
|
+
|
|
181
|
+
For smart-home and multi-device integrations, PiPhi now recommends a richer
|
|
182
|
+
runtime-owned entity shape that ties each entity to a real saved config or
|
|
183
|
+
device. That lets Core make better device-first dashboard suggestions, and it
|
|
184
|
+
gives the frontend enough context to render better widget defaults for plugs,
|
|
185
|
+
bulbs, thermostats, and other device-specific entities.
|
|
186
|
+
|
|
187
|
+
Recommended fields:
|
|
188
|
+
|
|
189
|
+
- `id`: stable runtime entity id
|
|
190
|
+
- `name`: user-facing label
|
|
191
|
+
- `capabilities`: actual capabilities for that specific device
|
|
192
|
+
- `config_id` / `configId`: PiPhi config UUID when available
|
|
193
|
+
- `device_id` / `deviceId`: integration-native device id
|
|
194
|
+
- `device_type` / `device_class`: values like `plug`, `bulb`, `sensor`, `climate`
|
|
195
|
+
- `entity_type`: values like `switch`, `light`, `sensor`, `media`
|
|
196
|
+
- `dashboard.allowed_widgets`, `dashboard.default_widget`, `dashboard.recommended_widgets`: optional UI hints
|
|
197
|
+
|
|
198
|
+
The SDK now includes `RuntimeEntityResponse`, `RuntimeEntitiesResponse`,
|
|
199
|
+
`build_entities_response(...)`, and `starter.entities_response(...)` to make
|
|
200
|
+
that payload easier to return.
|
|
201
|
+
|
|
202
|
+
The helper returns the standard wrapper shape:
|
|
203
|
+
|
|
204
|
+
- `entities`: the runtime-owned list you generated
|
|
205
|
+
- `capabilities`: optional manifest capability metadata
|
|
206
|
+
- `commands`: optional manifest command metadata
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from piphi_runtime_kit_python import build_entities_response
|
|
210
|
+
|
|
211
|
+
@app.get("/entities")
|
|
212
|
+
async def entities() -> dict[str, Any]:
|
|
213
|
+
return build_entities_response(
|
|
214
|
+
entities=[
|
|
215
|
+
{
|
|
216
|
+
"id": "office-plug",
|
|
217
|
+
"name": "Office Plug",
|
|
218
|
+
"config_id": "core-config-uuid",
|
|
219
|
+
"device_id": "office-plug",
|
|
220
|
+
"device_class": "plug",
|
|
221
|
+
"entity_type": "switch",
|
|
222
|
+
"capabilities": ["switch", "power", "energy_today"],
|
|
223
|
+
"dashboard": {
|
|
224
|
+
"allowed_widgets": ["tile", "button", "stat"],
|
|
225
|
+
"default_widget": "tile",
|
|
226
|
+
},
|
|
227
|
+
}
|
|
228
|
+
],
|
|
229
|
+
capabilities=manifest["capabilities"],
|
|
230
|
+
commands=manifest.get("commands", {}),
|
|
231
|
+
).model_dump(exclude_none=True)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
If you are already using the starter object, the same response can be built with
|
|
235
|
+
`starter.entities_response(...)` instead of calling the standalone helper
|
|
236
|
+
directly.
|
|
237
|
+
|
|
166
238
|
## UI Config Endpoints
|
|
167
239
|
|
|
168
240
|
Many integrations expose `/ui` or `/ui-config` so the PiPhi frontend knows how
|
|
@@ -87,18 +87,28 @@ hide vendor logic behind an overly magical abstraction.
|
|
|
87
87
|
|
|
88
88
|
The package currently supports Python `>=3.11`.
|
|
89
89
|
|
|
90
|
-
Install from
|
|
90
|
+
Install from PyPI:
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
pdm add
|
|
93
|
+
pdm add piphi-runtime-kit-python
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
If you need the optional FastAPI helpers:
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
pdm add "
|
|
99
|
+
pdm add "piphi-runtime-kit-python[fastapi]"
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
+
If you prefer `pip`:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pip install piphi-runtime-kit-python
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Package page:
|
|
109
|
+
|
|
110
|
+
- https://pypi.org/project/piphi-runtime-kit-python/0.3.0/
|
|
111
|
+
|
|
102
112
|
## First 15 Minutes
|
|
103
113
|
|
|
104
114
|
If you want the shortest path to a working runtime, do this:
|
|
@@ -134,9 +144,71 @@ These are the most common runtime routes and what they are for.
|
|
|
134
144
|
| `/deconfigure` | `POST` | Usually | Remove one config | `RuntimeConfigRemoveResponse` |
|
|
135
145
|
| `/events` | `GET` | Common | Show recent local runtime events | `build_event_list_response(...)` |
|
|
136
146
|
| `/state` | `GET` | Common | Show current runtime state | `registry.entries`, `registry.state_snapshots` |
|
|
137
|
-
| `/entities` | `GET` | Integration-specific | Show normalized entity list |
|
|
147
|
+
| `/entities` | `GET` | Integration-specific | Show normalized entity list | `build_entities_response(...)`, `starter.entities_response(...)` |
|
|
138
148
|
| `/ui` or `/ui-config` | `GET` | Optional | Return config UI metadata | integration-owned |
|
|
139
149
|
|
|
150
|
+
## Modeling `/entities`
|
|
151
|
+
|
|
152
|
+
For simple integrations, `/entities` can still be a plain list of generic
|
|
153
|
+
entities.
|
|
154
|
+
|
|
155
|
+
For smart-home and multi-device integrations, PiPhi now recommends a richer
|
|
156
|
+
runtime-owned entity shape that ties each entity to a real saved config or
|
|
157
|
+
device. That lets Core make better device-first dashboard suggestions, and it
|
|
158
|
+
gives the frontend enough context to render better widget defaults for plugs,
|
|
159
|
+
bulbs, thermostats, and other device-specific entities.
|
|
160
|
+
|
|
161
|
+
Recommended fields:
|
|
162
|
+
|
|
163
|
+
- `id`: stable runtime entity id
|
|
164
|
+
- `name`: user-facing label
|
|
165
|
+
- `capabilities`: actual capabilities for that specific device
|
|
166
|
+
- `config_id` / `configId`: PiPhi config UUID when available
|
|
167
|
+
- `device_id` / `deviceId`: integration-native device id
|
|
168
|
+
- `device_type` / `device_class`: values like `plug`, `bulb`, `sensor`, `climate`
|
|
169
|
+
- `entity_type`: values like `switch`, `light`, `sensor`, `media`
|
|
170
|
+
- `dashboard.allowed_widgets`, `dashboard.default_widget`, `dashboard.recommended_widgets`: optional UI hints
|
|
171
|
+
|
|
172
|
+
The SDK now includes `RuntimeEntityResponse`, `RuntimeEntitiesResponse`,
|
|
173
|
+
`build_entities_response(...)`, and `starter.entities_response(...)` to make
|
|
174
|
+
that payload easier to return.
|
|
175
|
+
|
|
176
|
+
The helper returns the standard wrapper shape:
|
|
177
|
+
|
|
178
|
+
- `entities`: the runtime-owned list you generated
|
|
179
|
+
- `capabilities`: optional manifest capability metadata
|
|
180
|
+
- `commands`: optional manifest command metadata
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from piphi_runtime_kit_python import build_entities_response
|
|
184
|
+
|
|
185
|
+
@app.get("/entities")
|
|
186
|
+
async def entities() -> dict[str, Any]:
|
|
187
|
+
return build_entities_response(
|
|
188
|
+
entities=[
|
|
189
|
+
{
|
|
190
|
+
"id": "office-plug",
|
|
191
|
+
"name": "Office Plug",
|
|
192
|
+
"config_id": "core-config-uuid",
|
|
193
|
+
"device_id": "office-plug",
|
|
194
|
+
"device_class": "plug",
|
|
195
|
+
"entity_type": "switch",
|
|
196
|
+
"capabilities": ["switch", "power", "energy_today"],
|
|
197
|
+
"dashboard": {
|
|
198
|
+
"allowed_widgets": ["tile", "button", "stat"],
|
|
199
|
+
"default_widget": "tile",
|
|
200
|
+
},
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
capabilities=manifest["capabilities"],
|
|
204
|
+
commands=manifest.get("commands", {}),
|
|
205
|
+
).model_dump(exclude_none=True)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
If you are already using the starter object, the same response can be built with
|
|
209
|
+
`starter.entities_response(...)` instead of calling the standalone helper
|
|
210
|
+
directly.
|
|
211
|
+
|
|
140
212
|
## UI Config Endpoints
|
|
141
213
|
|
|
142
214
|
Many integrations expose `/ui` or `/ui-config` so the PiPhi frontend knows how
|
|
@@ -70,7 +70,7 @@ from .runtime.mqtt import (
|
|
|
70
70
|
)
|
|
71
71
|
from .runtime.registry import RuntimeRegistry
|
|
72
72
|
from .runtime.state import RuntimeProcessState
|
|
73
|
-
from .runtime.starter import RuntimeStarter, create_runtime_starter
|
|
73
|
+
from .runtime.starter import RuntimeStarter, build_entities_response, create_runtime_starter
|
|
74
74
|
from .runtime.tasks import create_tracked_task, shutdown_background_tasks, track_background_task
|
|
75
75
|
from .runtime.telemetry import TelemetryClient, build_core_auth_headers
|
|
76
76
|
from .schemas import (
|
|
@@ -80,6 +80,9 @@ from .schemas import (
|
|
|
80
80
|
IntegrationCommandRequest,
|
|
81
81
|
IntegrationDiscoveryRequest,
|
|
82
82
|
IntegrationDiscoveryResponse,
|
|
83
|
+
RuntimeEntityDashboardResponse,
|
|
84
|
+
RuntimeEntitiesResponse,
|
|
85
|
+
RuntimeEntityResponse,
|
|
83
86
|
IntegrationEventIngestResponse,
|
|
84
87
|
IntegrationEventListResponse,
|
|
85
88
|
IntegrationEventRequest,
|
|
@@ -110,6 +113,9 @@ __all__ = [
|
|
|
110
113
|
"IntegrationCommandRequest",
|
|
111
114
|
"IntegrationDiscoveryRequest",
|
|
112
115
|
"IntegrationDiscoveryResponse",
|
|
116
|
+
"RuntimeEntityDashboardResponse",
|
|
117
|
+
"RuntimeEntitiesResponse",
|
|
118
|
+
"RuntimeEntityResponse",
|
|
113
119
|
"IntegrationEventRequest",
|
|
114
120
|
"RuntimeAuthContext",
|
|
115
121
|
"RuntimeAuthHeaders",
|
|
@@ -141,6 +147,7 @@ __all__ = [
|
|
|
141
147
|
"build_core_auth_headers",
|
|
142
148
|
"build_config_apply_response",
|
|
143
149
|
"build_config_remove_response",
|
|
150
|
+
"build_entities_response",
|
|
144
151
|
"build_runtime_auth_headers",
|
|
145
152
|
"build_runtime_diagnostics_response",
|
|
146
153
|
"build_runtime_health_response",
|
|
@@ -11,6 +11,7 @@ from .events import DEFAULT_CORE_BASE_URL as DEFAULT_EVENTS_CORE_BASE_URL, Event
|
|
|
11
11
|
from .health import build_runtime_diagnostics_response, build_runtime_health_response
|
|
12
12
|
from .registry import RuntimeRegistry
|
|
13
13
|
from .telemetry import DEFAULT_CORE_BASE_URL as DEFAULT_TELEMETRY_CORE_BASE_URL, TelemetryClient
|
|
14
|
+
from ..schemas import RuntimeEntitiesResponse
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
@dataclass(slots=True)
|
|
@@ -77,6 +78,34 @@ class RuntimeStarter:
|
|
|
77
78
|
},
|
|
78
79
|
)
|
|
79
80
|
|
|
81
|
+
def entities_response(
|
|
82
|
+
self,
|
|
83
|
+
*,
|
|
84
|
+
entities: list[dict[str, Any]],
|
|
85
|
+
capabilities: dict[str, Any] | None = None,
|
|
86
|
+
commands: dict[str, Any] | None = None,
|
|
87
|
+
) -> RuntimeEntitiesResponse:
|
|
88
|
+
"""Build the standard /entities response body for this runtime."""
|
|
89
|
+
return build_entities_response(
|
|
90
|
+
entities=entities,
|
|
91
|
+
capabilities=capabilities,
|
|
92
|
+
commands=commands,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def build_entities_response(
|
|
97
|
+
*,
|
|
98
|
+
entities: list[dict[str, Any]],
|
|
99
|
+
capabilities: dict[str, Any] | None = None,
|
|
100
|
+
commands: dict[str, Any] | None = None,
|
|
101
|
+
) -> RuntimeEntitiesResponse:
|
|
102
|
+
"""Return the standard runtime /entities response wrapper."""
|
|
103
|
+
return RuntimeEntitiesResponse(
|
|
104
|
+
entities=entities,
|
|
105
|
+
capabilities=capabilities or {},
|
|
106
|
+
commands=commands or {},
|
|
107
|
+
)
|
|
108
|
+
|
|
80
109
|
|
|
81
110
|
def create_runtime_starter(
|
|
82
111
|
*,
|
|
@@ -6,7 +6,7 @@ from datetime import datetime, timezone
|
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
9
|
+
from pydantic import AliasChoices, BaseModel, ConfigDict, Field
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class RuntimeConfig(BaseModel):
|
|
@@ -74,6 +74,68 @@ class IntegrationCommandRequest(BaseModel):
|
|
|
74
74
|
args: dict[str, Any] = Field(default_factory=dict)
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
class RuntimeEntityDashboardResponse(BaseModel):
|
|
78
|
+
"""Optional per-entity dashboard hints returned by a runtime."""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
81
|
+
|
|
82
|
+
allowed_widgets: list[str] = Field(
|
|
83
|
+
default_factory=list,
|
|
84
|
+
validation_alias=AliasChoices("allowed_widgets", "allowedWidgets"),
|
|
85
|
+
)
|
|
86
|
+
default_widget: str | None = Field(
|
|
87
|
+
default=None,
|
|
88
|
+
validation_alias=AliasChoices("default_widget", "defaultWidget"),
|
|
89
|
+
)
|
|
90
|
+
recommended_widgets: list[str] = Field(
|
|
91
|
+
default_factory=list,
|
|
92
|
+
validation_alias=AliasChoices("recommended_widgets", "recommendedWidgets"),
|
|
93
|
+
)
|
|
94
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class RuntimeEntityResponse(BaseModel):
|
|
98
|
+
"""One live runtime entity tied to a configured device/account."""
|
|
99
|
+
|
|
100
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
101
|
+
|
|
102
|
+
id: str
|
|
103
|
+
name: str
|
|
104
|
+
capabilities: list[str] = Field(default_factory=list)
|
|
105
|
+
config_id: str | None = Field(
|
|
106
|
+
default=None,
|
|
107
|
+
validation_alias=AliasChoices("config_id", "configId"),
|
|
108
|
+
)
|
|
109
|
+
device_id: str | None = Field(
|
|
110
|
+
default=None,
|
|
111
|
+
validation_alias=AliasChoices("device_id", "deviceId"),
|
|
112
|
+
)
|
|
113
|
+
device_type: str | None = Field(
|
|
114
|
+
default=None,
|
|
115
|
+
validation_alias=AliasChoices("device_type", "deviceType"),
|
|
116
|
+
)
|
|
117
|
+
device_class: str | None = Field(
|
|
118
|
+
default=None,
|
|
119
|
+
validation_alias=AliasChoices("device_class", "deviceClass"),
|
|
120
|
+
)
|
|
121
|
+
entity_type: str | None = Field(
|
|
122
|
+
default=None,
|
|
123
|
+
validation_alias=AliasChoices("entity_type", "entityType"),
|
|
124
|
+
)
|
|
125
|
+
dashboard: RuntimeEntityDashboardResponse | None = None
|
|
126
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class RuntimeEntitiesResponse(BaseModel):
|
|
130
|
+
"""Standard response body returned by runtime /entities endpoints."""
|
|
131
|
+
|
|
132
|
+
model_config = ConfigDict(populate_by_name=True, extra="allow")
|
|
133
|
+
|
|
134
|
+
entities: list[RuntimeEntityResponse] = Field(default_factory=list)
|
|
135
|
+
capabilities: dict[str, Any] = Field(default_factory=dict)
|
|
136
|
+
commands: dict[str, Any] = Field(default_factory=dict)
|
|
137
|
+
|
|
138
|
+
|
|
77
139
|
class IntegrationEventRequest(BaseModel):
|
|
78
140
|
"""Generic event payload emitted by a runtime integration."""
|
|
79
141
|
event_type: str
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from piphi_runtime_kit_python import (
|
|
2
|
+
RuntimeEntitiesResponse,
|
|
3
|
+
RuntimeStarter,
|
|
4
|
+
create_runtime_starter,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_create_runtime_starter_bundles_common_runtime_parts() -> None:
|
|
9
|
+
starter = create_runtime_starter(
|
|
10
|
+
integration_id="demo-runtime",
|
|
11
|
+
integration_name="Demo Runtime",
|
|
12
|
+
version="0.1.0",
|
|
13
|
+
max_recent_events=25,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
assert isinstance(starter, RuntimeStarter)
|
|
17
|
+
assert starter.integration_metadata == {
|
|
18
|
+
"id": "demo-runtime",
|
|
19
|
+
"name": "Demo Runtime",
|
|
20
|
+
"version": "0.1.0",
|
|
21
|
+
}
|
|
22
|
+
assert starter.registry.max_recent_events == 25
|
|
23
|
+
assert starter.telemetry_client.process_state is starter.runtime.process_state
|
|
24
|
+
assert starter.event_client.process_state is starter.runtime.process_state
|
|
25
|
+
assert starter.config_sync.process_state is starter.runtime.process_state
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_runtime_starter_entities_response_wraps_runtime_entities() -> None:
|
|
29
|
+
starter = create_runtime_starter(
|
|
30
|
+
integration_id="demo-runtime",
|
|
31
|
+
integration_name="Demo Runtime",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
response = starter.entities_response(
|
|
35
|
+
entities=[
|
|
36
|
+
{
|
|
37
|
+
"id": "office-plug",
|
|
38
|
+
"name": "Office Plug",
|
|
39
|
+
"capabilities": ["switch", "power"],
|
|
40
|
+
"config_id": "cfg-1",
|
|
41
|
+
"device_id": "office-plug",
|
|
42
|
+
"device_class": "plug",
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
capabilities={"switch": {"kind": "action"}},
|
|
46
|
+
commands={"turn_on": {"description": "Turn on"}},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
assert isinstance(response, RuntimeEntitiesResponse)
|
|
50
|
+
assert response.entities[0].name == "Office Plug"
|
|
51
|
+
assert response.entities[0].device_class == "plug"
|
|
52
|
+
assert response.capabilities == {"switch": {"kind": "action"}}
|
|
53
|
+
assert response.commands == {"turn_on": {"description": "Turn on"}}
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_schemas_matrix.py
RENAMED
|
@@ -16,6 +16,9 @@ from piphi_runtime_kit_python import (
|
|
|
16
16
|
RuntimeConfigSnapshot,
|
|
17
17
|
RuntimeConfigSyncResponse,
|
|
18
18
|
RuntimeDiagnosticsResponse,
|
|
19
|
+
RuntimeEntitiesResponse,
|
|
20
|
+
RuntimeEntityDashboardResponse,
|
|
21
|
+
RuntimeEntityResponse,
|
|
19
22
|
RuntimeHealthResponse,
|
|
20
23
|
TelemetryPayload,
|
|
21
24
|
)
|
|
@@ -72,6 +75,48 @@ def test_integration_event_request_defaults_payload() -> None:
|
|
|
72
75
|
assert request.payload == {}
|
|
73
76
|
|
|
74
77
|
|
|
78
|
+
def test_runtime_entity_models_support_aliases_and_defaults() -> None:
|
|
79
|
+
entity = RuntimeEntityResponse.model_validate(
|
|
80
|
+
{
|
|
81
|
+
"id": "office-plug",
|
|
82
|
+
"name": "Office Plug",
|
|
83
|
+
"capabilities": ["switch", "power"],
|
|
84
|
+
"configId": "cfg-1",
|
|
85
|
+
"deviceId": "office-plug",
|
|
86
|
+
"deviceClass": "plug",
|
|
87
|
+
"entityType": "switch",
|
|
88
|
+
"dashboard": {
|
|
89
|
+
"allowedWidgets": ["tile", "stat"],
|
|
90
|
+
"defaultWidget": "tile",
|
|
91
|
+
"recommendedWidgets": ["tile"],
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
assert entity.config_id == "cfg-1"
|
|
97
|
+
assert entity.device_id == "office-plug"
|
|
98
|
+
assert entity.device_class == "plug"
|
|
99
|
+
assert entity.entity_type == "switch"
|
|
100
|
+
assert entity.dashboard is not None
|
|
101
|
+
assert entity.dashboard.allowed_widgets == ["tile", "stat"]
|
|
102
|
+
assert entity.dashboard.default_widget == "tile"
|
|
103
|
+
assert entity.dashboard.recommended_widgets == ["tile"]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_runtime_entities_response_defaults_cleanly() -> None:
|
|
107
|
+
response = RuntimeEntitiesResponse()
|
|
108
|
+
assert response.entities == []
|
|
109
|
+
assert response.capabilities == {}
|
|
110
|
+
assert response.commands == {}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_runtime_entity_dashboard_defaults_metadata() -> None:
|
|
114
|
+
dashboard = RuntimeEntityDashboardResponse()
|
|
115
|
+
assert dashboard.allowed_widgets == []
|
|
116
|
+
assert dashboard.recommended_widgets == []
|
|
117
|
+
assert dashboard.metadata == {}
|
|
118
|
+
|
|
119
|
+
|
|
75
120
|
def test_event_list_and_ingest_responses_default_cleanly() -> None:
|
|
76
121
|
assert IntegrationEventListResponse().events == []
|
|
77
122
|
assert IntegrationEventIngestResponse().status == "accepted"
|
|
@@ -121,4 +166,3 @@ def test_core_event_payload_model_dump_json_serializes_enums_and_datetimes() ->
|
|
|
121
166
|
assert dumped["severity"] == "error"
|
|
122
167
|
assert dumped["transport"] == "mqtt"
|
|
123
168
|
assert dumped["ts"].endswith("Z")
|
|
124
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from piphi_runtime_kit_python import RuntimeStarter, create_runtime_starter
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def test_create_runtime_starter_bundles_common_runtime_parts() -> None:
|
|
5
|
-
starter = create_runtime_starter(
|
|
6
|
-
integration_id="demo-runtime",
|
|
7
|
-
integration_name="Demo Runtime",
|
|
8
|
-
version="0.1.0",
|
|
9
|
-
max_recent_events=25,
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
assert isinstance(starter, RuntimeStarter)
|
|
13
|
-
assert starter.integration_metadata == {
|
|
14
|
-
"id": "demo-runtime",
|
|
15
|
-
"name": "Demo Runtime",
|
|
16
|
-
"version": "0.1.0",
|
|
17
|
-
}
|
|
18
|
-
assert starter.registry.max_recent_events == 25
|
|
19
|
-
assert starter.telemetry_client.process_state is starter.runtime.process_state
|
|
20
|
-
assert starter.event_client.process_state is starter.runtime.process_state
|
|
21
|
-
assert starter.config_sync.process_state is starter.runtime.process_state
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_fastapi_adapter.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_auth.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_auth_matrix.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_discovery.py
RENAMED
|
File without changes
|
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_dispatch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_events.py
RENAMED
|
File without changes
|
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_health.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_lifespan.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_mqtt.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_mqtt_matrix.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_tasks.py
RENAMED
|
File without changes
|
{piphi_runtime_kit_python-0.3.0 → piphi_runtime_kit_python-0.4.1}/tests/test_runtime_telemetry.py
RENAMED
|
File without changes
|
|
File without changes
|