Add InfluxDB3 writer with deconz support and tests to validate mappin…#9
Open
xlfe wants to merge 8 commits into
Open
Add InfluxDB3 writer with deconz support and tests to validate mappin…#9xlfe wants to merge 8 commits into
xlfe wants to merge 8 commits into
Conversation
…g plus config/docs updates to clarify measurement and whitelist behavior
Queue writes off the main loop, tag/alias ESPHome props, and store deCONZ state under :radiale.deconz so domain filters line up.
- Fix Python NaN/Inf filtering in pod.py using math.isnan()/isinf() instead of identity comparison which silently passed bad values - Prevent channel deadlocks by replacing blocking async/>!! with non-blocking async/offer! in state.clj and watch.clj, logging warnings when the channel is full instead of blocking the main loop - Add error handling and logging throughout: - Wrap ::fn handler invocation in try-catch (core.clj) - Add try-catch around watch handlers (watch.clj) - Log when events are filtered or channels uninitialized (influx.clj) - Optimize InfluxDB3 writes with time-based batching: - Accumulate points for 100ms before writing - Use writePoints() batch API instead of individual writePoint() calls - Enable noSync=true in WriteOptions to skip WAL persistence wait - Reduces write latency from ~1s per point to ~50ms per batch - Convert high-frequency debug logs to trace level for cleaner output
…oot) Previously, on_disconnect returned early when expected=True, skipping the reconnect loop entirely. Now it waits 30s for the device to reboot, then enters the normal reconnect loop. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Generic primitives — extend!/clear!/bump!/bump-cmd — for any device that should turn off after a deadline that multiple event sources can push forward. Keyed by ::watchdog/key so multiple instances coexist in one state* atom. Also adds: - deconz/on-press: watch-handler factory for button-style sensors. Gates on :lastupdated and reads :buttonevent from @State*, fixing dropped repeat presses where clojure.data/diff strips :buttonevent from ::state/now because only :lastupdated changed. - schedule/cancel: kills a pending at-most-once job and clears its state-path entry. Used by watchdog/clear! so an off-button can stop a running watchdog without scheduling a new fire. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
A self-rescheduling rc-fn that reads a watchdog's deadline, calls a render function with minutes-remaining (or nil when the deadline is gone), pushes the resulting commands to send-chan, and reschedules itself for tick-seconds (default 60) later. Self-terminates when the deadline is past. Mechanism: the rescheduling schedule/after carries an ::rc/then that back-references ticks via (assoc cfg ::rc/fn ticks). When the schedule fires, try-fn merges clean-m with the ::rc/then map and dispatches ticks again — the chain re-enters via the channel, not the stack. Useful for any watchdog client that wants a recurring side-effect (a keypad showing minutes-remaining, a periodic log line, a heartbeat). Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
On a clean device reboot (expected disconnect), two reconnectors raced: the mDNS-driven subscribe-esp* path and the on_disconnect retry loop. The loop slept 30s for the expected disconnect *before* claiming `connecting`, so it didn't block the mDNS path; it then fired a second connect() that reassigned self.cli and awaited APIClient.connect() with no timeout — stacking a duplicate connection on a device that already had one. That await hung indefinitely. Because `connecting` was reset only after the loop, the hang latched connecting=True forever, wedging the mDNS fallback too, while self.cli (never nulled on disconnect) let service_command fire execute_service into a dead client and report success:true. A keypad stayed silently dead for ~34h until radiale was restarted. esphome.py: - _close_cli(): null self.cli/self.connected before force-disconnecting, and call it before every connect() so we never stack a 2nd connection. - connect(): wrap APIClient.connect() in asyncio.wait_for(CONNECT_TIMEOUT) so a stalled post-TCP handshake can't hang the reconnector. - on_disconnect(): claim `connecting` before any await (closing the race window), reset it in finally (can never latch), and retry unbounded with capped exponential backoff (5..60s) instead of giving up after 15 tries. Refresh services on reconnect (parity with the mDNS path). - _is_live() gate on command handlers: report success:false when not holding a live connection instead of firing into a corpse. (execute_service is one-way, so success:true still only means "delivered to a live connection", never "the device acted".) pod.py: hold `connecting` across the subscribe-esp* connect with try/finally so it and on_disconnect are mutually exclusive. tests: update on_disconnect tests for unbounded/backoff behavior; gate command tests on connected=True; add tests for _close_cli, _is_live, connect-timeout teardown, and not-connected command handling. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… 45.x
aioesphomeapi flips its fire-and-forget commands between sync and async across
versions. radiale called them synchronously, which was correct for 42.x. The
build on `free` now runs 45.0.2, where execute_service is an `async def` — so
service_command created a coroutine and discarded it ("coroutine
APIClient.execute_service was never awaited"), logging success:true while the
keypad beeper/display services never reached the device. (switch_command,
light_command and send_home_assistant_state are still sync in 45.0.2; only
execute_service flipped, which is why keypad display *text* still worked.)
Route all four fire-and-forget commands through _maybe_await(), which awaits the
result iff it is awaitable — correct whether the installed aioesphomeapi makes
them sync or async, so a future version flip can't silently drop commands again.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…g plus config/docs updates to clarify measurement and whitelist behavior