docs: TODO + CLAUDE.md notes + locale keys for new features
TODO.md grows the device-support follow-up roadmap. CLAUDE.md trims a stale section. en/ru/zh locales add the strings used by the new HTTP-endpoint editor, MiniSelect labels, automations expansion, and value-source kinds. Ru/zh parity for the older keys is tracked separately in REVIEW_TODO.md.
This commit is contained in:
@@ -1,5 +1,170 @@
|
||||
# LedGrab TODO
|
||||
|
||||
## HTTP polling automation trigger
|
||||
|
||||
Goal: a new automation trigger that periodically polls an HTTP endpoint
|
||||
and activates a scene when the response matches a condition. Split into
|
||||
three single-responsibility entities so the endpoint can be reused
|
||||
beyond automations (e.g. as a value-source driving brightness/color):
|
||||
|
||||
- `HTTPEndpoint` (storage/http_endpoint.py) — connection definition:
|
||||
URL + auth + headers + timeout. NO polling cadence; NO extraction.
|
||||
- `HTTPValueSource` (storage/value_source.py, source_type='http') —
|
||||
references an endpoint + owns json_path + interval + min/max + EMA
|
||||
smoothing. Backed by `HTTPValueStream` (core/processing/value_stream.py)
|
||||
which lives under the existing `ValueStreamManager` (ref-counted,
|
||||
one poll task per unique value source).
|
||||
- `HTTPPollRule` (storage/automation.py) — thin: `{value_source_id,
|
||||
operator, value}`. Reads `stream.get_raw_value()` from the value
|
||||
source and compares with `_apply_operator`.
|
||||
|
||||
Pivoted from a 2-entity shape mid-build (was: HTTPSource+rule with
|
||||
interval+json_path mushed). The 3-entity shape mirrors HA's pattern
|
||||
(HomeAssistantSource → HAEntityValueSource → rule).
|
||||
|
||||
### Phase 1 — endpoint + value source + thin rule (backend) ✅
|
||||
|
||||
- [x] `storage/http_endpoint.py` — `HTTPEndpoint` dataclass with
|
||||
secret_box auth_token encryption + `__post_init__` plaintext
|
||||
invariant. NO `default_interval_s` (moved to value source).
|
||||
- [x] `storage/http_endpoint_store.py` — `HTTPEndpointStore` with
|
||||
`_migrate_plaintext_tokens()`. ID prefix `htep_`.
|
||||
- [x] `storage/database.py` — `"http_endpoints"` in `_ENTITY_TABLES`
|
||||
(replaces the old `"http_sources"`).
|
||||
- [x] `storage/value_source.py` — added `HTTPValueSource` alongside
|
||||
`HAEntityValueSource` (endpoint_id, json_path, interval_s,
|
||||
min/max, smoothing). Registered in `_VALUE_SOURCE_MAP`.
|
||||
- [x] `storage/value_source_store.py` — CRUD branch for `source_type =
|
||||
"http"` + new kwargs on create/update.
|
||||
- [x] `core/processing/value_stream.py` — `HTTPValueStream` with poll
|
||||
task + `get_value()` (normalized 0-1) + `get_raw_value()` (raw
|
||||
extracted value). Dispatched in `ValueStreamManager._create_stream`.
|
||||
Manager now takes `http_endpoint_store` so the stream can resolve
|
||||
endpoints at fetch time.
|
||||
|
||||
### Phase 2 — rule + engine wiring ✅
|
||||
|
||||
- [x] `storage/automation.py` — `HTTPPollRule` is now thin: just
|
||||
`{value_source_id, operator, value}` (no http_source_id, no
|
||||
json_path on the rule). Legacy keys silently dropped on load.
|
||||
- [x] `core/automations/automation_engine.py` — drops the standalone
|
||||
http_poll_manager; takes `value_stream_manager`. Engine
|
||||
`_sync_value_stream_refs` acquires/releases value streams for
|
||||
every enabled HTTPPollRule, mirroring the HA/MQTT sync pattern.
|
||||
`_evaluate_http_poll` reads `stream.get_raw_value()` and applies
|
||||
the operator. `_apply_operator` kept at module top.
|
||||
- [x] `api/schemas/automations.py` — RuleSchema fields are now
|
||||
`value_source_id + operator + value` (dropped http_source_id +
|
||||
json_path).
|
||||
- [x] `api/routes/automations.py` — `http_poll` factory updated.
|
||||
|
||||
### Phase 3 — CRUD endpoints + wiring ✅
|
||||
|
||||
- [x] `api/schemas/http_endpoints.py` — Create/Update/Response/List/Test
|
||||
(no interval field; that's on the value source).
|
||||
- [x] `api/routes/http_endpoints.py` — full CRUD + `/test` +
|
||||
plaintext-http-token warning.
|
||||
- [x] `api/schemas/value_sources.py` — `HTTPValueSource{Create,Update,Response}`
|
||||
added to the discriminated unions.
|
||||
- [x] `api/routes/value_sources.py` — `_RESPONSE_MAP` entry for
|
||||
`HTTPValueSource`.
|
||||
- [x] `api/__init__.py` — `http_endpoints_router` registered.
|
||||
- [x] `api/dependencies.py` — `get_http_endpoint_store` (dropped the
|
||||
http_poll_manager getter).
|
||||
- [x] `main.py` — instantiate `HTTPEndpointStore`, pass it through
|
||||
`ProcessorDependencies`, wire `value_stream_manager` +
|
||||
`value_source_store` into `AutomationEngine`.
|
||||
- [x] `core/processing/processor_manager.py` — `ProcessorDependencies`
|
||||
gains `http_endpoint_store`; threaded into `ValueStreamManager`.
|
||||
|
||||
### Phase 4 — tests ✅
|
||||
|
||||
- [x] `tests/storage/test_http_endpoint_store.py` — 14 tests (CRUD +
|
||||
auth_token encryption + headers + case-insensitive Authorization).
|
||||
- [x] `tests/core/test_automation_engine.py` — `TestApplyOperator` +
|
||||
`TestHTTPPollRuleEvaluation` (new shape: mock ValueStreamManager
|
||||
with `_streams` dict) + `TestSyncValueStreamRefs` (acquire /
|
||||
release / disabled-ignored) + `TestHTTPValueStreamExtraction`
|
||||
(`_extract_simple_path` now lives in value_stream.py).
|
||||
- [x] `tests/api/routes/test_http_endpoints_routes.py` — CRUD shape, no
|
||||
auth_token leak in responses, schema-layer method allowlist,
|
||||
CRLF / invalid header rejection, `/test` endpoint, LAN policy.
|
||||
- [x] Removed: `tests/core/test_http_poll_manager.py` (manager deleted —
|
||||
polling now lives inside `HTTPValueStream`).
|
||||
- [x] Full suite: 1426 passed, ruff clean.
|
||||
|
||||
### Phase 5 — frontend ✅
|
||||
|
||||
- [x] `static/js/features/http-endpoints.ts` (new, ~540 LOC) — endpoint
|
||||
CRUD, modal subclass with dirty-check, headers row editor, test
|
||||
result rendering, card builder, event delegation. Mirrors
|
||||
`home-assistant-sources.ts`.
|
||||
- [x] `templates/modals/http-endpoint-editor.html` (new) — sectioned
|
||||
rack-panel modal (Identity / Request / Headers / Notes) with
|
||||
IconSelect method picker, password-toggle on auth token, inline
|
||||
Test button + result block.
|
||||
- [x] `static/js/features/value-sources.ts` — added `http` branch with
|
||||
EntitySelect over `httpEndpointsCache`, edit-data/defaults,
|
||||
`onValueSourceTypeChange` section toggle, save-payload assembly
|
||||
+ required-field validation.
|
||||
- [x] `templates/modals/value-source-editor.html` — new
|
||||
`#value-source-http-section` with endpoint picker + json_path +
|
||||
interval + min/max + smoothing.
|
||||
- [x] `static/js/features/automations.ts` — `http_poll` rule type with
|
||||
operator IconSelect + value-source EntitySelect; hides Value
|
||||
field when operator is `exists`.
|
||||
- [x] `static/js/features/integrations.ts` — `csHTTPEndpoints` section,
|
||||
tree/tab entry, render + reconcile + delegation paths.
|
||||
- [x] `static/js/types.ts` — `HTTPEndpoint`, `HTTPMethod`,
|
||||
`HTTPEndpointListResponse`, `HTTPTestRequest/Response`,
|
||||
`HTTPValueSource`, `HTTPPollOperator`; extended `RuleType` +
|
||||
`AutomationRule`.
|
||||
- [x] `static/js/core/state.ts` — `httpEndpointsCache` (`/http/endpoints`).
|
||||
- [x] `static/js/core/icons.ts` — `http: P.globe` in
|
||||
`_valueSourceTypeIcons`.
|
||||
- [x] `templates/index.html` — includes
|
||||
`modals/http-endpoint-editor.html`.
|
||||
- [x] Locales: 77 new keys per file in `en.json` / `ru.json` /
|
||||
`zh.json` (parity confirmed).
|
||||
- [x] Verification: `npx tsc --noEmit` clean; `npm run build` clean
|
||||
(app.bundle.css 366.6kb, app.bundle.js 2.7mb).
|
||||
|
||||
### Follow-ups (out of scope for initial PR)
|
||||
|
||||
- [ ] **Global concurrency cap / minimum interval.** Each
|
||||
`HTTPValueStream` runs its own task at `interval_s` (min 1s); no
|
||||
project-wide cap. Reviewer flagged: pick a min (e.g. 5s) + max
|
||||
active runtimes (e.g. 32) + shared `httpx.AsyncClient` with
|
||||
`limits=httpx.Limits(max_connections=N)`.
|
||||
- [ ] **DNS-rebinding hardening.** `safe_request_bounded` validates
|
||||
the URL hostname's resolved IPs once; httpx independently
|
||||
re-resolves. The window is short but not zero. True fix: pin
|
||||
to the validated IP + set Host header (and SNI for HTTPS). This
|
||||
affects every outbound caller (`safe_fetch`, weather, image
|
||||
sources) — handle as a project-wide hardening, not local to
|
||||
this feature.
|
||||
- [ ] **`delete_http_endpoint` orphan refs.** When an admin deletes an
|
||||
endpoint referenced by N value sources, the value-stream task
|
||||
keeps polling until its source is also deleted. Same shape as
|
||||
the MQTT defect — fix both together (refuse-with-409 when in
|
||||
use, or cascade value-source deletion).
|
||||
- [ ] **Per-endpoint `connected` / last-poll status on the response**
|
||||
(frontend agent flagged). `HTTPEndpointResponse` has no live
|
||||
status, unlike HA/MQTT sources. Card LEDs default to "on".
|
||||
Could aggregate `last_status_code` / `last_error` from all
|
||||
`HTTPValueStream` instances referencing the endpoint and surface
|
||||
on `GET /http/endpoints/{id}`.
|
||||
- [x] **Per-endpoint live `/test` after save** — added `POST
|
||||
/http/endpoints/{id}/test` (runs stored config server-side so the
|
||||
auth token never round-trips) and wired a flask-icon test action
|
||||
on the endpoint card (toasts the result). Custom-headers section
|
||||
and inline test-result UI in the editor modal also restyled to
|
||||
match the `.group-child-row` and result-card vocabulary.
|
||||
- [ ] **Dedicated icon for HTTP value source / endpoint** (frontend
|
||||
agent flagged). Both use `P.globe` — visually fine in practice
|
||||
but adding a `cable`/`webhook` glyph in `icon-paths.ts` would
|
||||
improve differentiation.
|
||||
|
||||
## Multi-broker MQTT refactor
|
||||
|
||||
Goal: drop the global `MQTTService` / `MQTTConfig`. Every MQTT consumer
|
||||
|
||||
Reference in New Issue
Block a user