Skip to content

Add relay state monitoring and new plugin to track on-time - #544

Open
samcorky wants to merge 5 commits into
masterfrom
533-relay-state-change-on-time-logging
Open

samcorky wants to merge 5 commits into
masterfrom
533-relay-state-change-on-time-logging

Conversation

@samcorky

@samcorky samcorky commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a new space/relaystate plugin that tracks relay on/off state and cumulative on-time reported by SMIBHID devices, computing its own authoritative on-time from received transitions and cross-checking it against the device's self-reported counter. Also generalizes timestamp handling shared with the existing smibhid plugin.

New plugin: space/relaystate

  • HTTP endpoints (listeners/http.py):
    • POST /space/relay/state — receive relay on/off + cumulative on-time reports from a device.
    • POST /space/relay/reset — record that a device's on-time counter was manually reset (e.g. filter change).
  • State tracking (common.py, models.py): SMIB computes its own computed_total_active_seconds from ON→OFF transition durations (not just trusting the device's reported value), stored per-device in RelayState, with full event history in RelayStateHistory and reset history in RelayResetHistory.
  • Two Slack alert types, each with independent channel/threshold/resend-interval config and shared debounce logic:
    • Relay-lifetime alert — fires when on-time since the last reset exceeds a configurable threshold (e.g. "filter needs replacing").
    • Drift warning — fires when SMIB's computed on-time and the device's reported on-time diverge beyond a threshold, both measured since a shared baseline established on first observation of a device or at an explicit reset (so a device with pre-existing on-time doesn't immediately look "drifted").
  • Scheduled monitor (listeners/scheduled.py): periodic sweep of all known relay states re-checks both alert types independent of new incoming reports, so a relay stuck ON with no new events still gets caught.
  • Supports multiple independent SMIBHID devices (one RelayState record each), though plugin configuration (thresholds, channels, message template) is currently global/shared rather than per-device — tracked separately in multiple smibhids reporting data #510.

Shared timestamp handling (smibhid/common.py)

  • validate_timestamp now accepts Unix epoch (int/float) or ISO 8601 strings/datetimes, not just epoch numbers.
  • Requires timezone-aware input for strings/datetimes — naive values are rejected outright rather than silently misinterpreted as local server time.
  • Extracted into a reusable SMIBHIDTimestamp annotated type; the existing smibhid sensor and UI-log models were migrated to use it instead of their own duplicated validator wiring.

Robustness fixes

  • Out-of-order/replayed timestamp reports no longer corrupt the computed on-time counter — a negative duration is clamped to 0 and logged instead of being subtracted.
  • Drift-check baseline (reported_total_active_seconds_at_last_reset) prevents a false persistent drift alert on the very first report from a device that already had accumulated on-time before SMIB started tracking it.

Docs

  • README.md and SETTINGS.md updated with the new plugin's description and full list of SMIB_PLUGIN_SPACE_RELAY_STATE_* environment variables.

…ative on-time

- Introduced the `Space Relay State` plugin with API endpoints to receive relay state and reset reports.
- Added models for relay state reports, reset reports, and history tracking.
- Implemented Slack alerting for relay lifetime warnings and state drift notifications.
- Updated `README.md` and `SETTINGS.md` with plugin information and configuration options.
…nitoring

- Introduced scheduled monitoring of relay states with configurable intervals.
- Implemented Slack alerting for relay-lifetime thresholds and drift detection during periodic checks.
- Extended configuration options (`monitor_interval`) for enabling and customizing periodic sweeps.
- Updated related documentation (`README.md`, `SETTINGS.md`) and refactored code for enhanced maintainability.
@samcorky samcorky linked an issue Aug 18, 2026 that may be closed by this pull request
…ove debounce logic

- Replaced individual alert fields with a unified `AlertState` model for relay lifetime and drift alerts.
- Unified debounce logic using `_should_resend_alert`, allowing consistent alert triggering rules.
- Introduced device-level locks to enforce atomic operations during state updates.
- Updated Slack alert templates to support `{threshold}` placeholder.
- Adjusted `SETTINGS.md` to document the updated alert message template.
- Added validation for timezone-aware timestamps in `common.py` to prevent usage of naive datetimes.
- Introduced `reported_total_active_seconds_at_last_reset` to improve drift-check baseline accuracy.
- Improved handling of out-of-order timestamps by clamping negative durations to zero.
- Refactored `_update_drift_alert_state` to use `reported_since_reset` for clearer comparisons.
- Updated relay state models and state-saving logic to support enhanced drift detection.
@samcorky
samcorky requested a review from sjefferson99 August 18, 2026 21:04

@sjefferson99 sjefferson99 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appears to meet the requirement.

- Document new SMIB_PLUGIN_SPACE_RELAY_STATE_* environment
  variables in template.env, including monitor interval, drift
  warning threshold, relay lifetime warning/alert settings, and
  alert channel/resend configuration
- Provides example defaults so operators can configure the new
  space relay state plugin alongside the existing space state
  plugin section
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Relay state change on time logging

2 participants