Skip to content

Dashboard Stats Configuration - Admin Notes

⚙️ Quick Configuration

Adjustable Thresholds

Edit these values in the respective controller files to customize warning/error behavior:

Streams (Controller_Connections.cs)

private static class StreamStatsConfig
{
    public const int ERROR_NO_DATA_MINUTES = 5;        // ❌ Error if no data for X minutes
    public const int WARNING_NO_DATA_SECONDS = 30;     // ⚠️ Warning if no data for X seconds
}

Sensors (Controller_Collectors.cs)

private static class CollectorStatsConfig
{
    public const int SENSOR_ERROR_LOST_THRESHOLD = 5;      // ❌ Error if X+ sensors lost
    public const int SENSOR_WARNING_LOST_THRESHOLD = 1;    // ⚠️ Warning if any sensors lost
}

Overview

The Dashboard Stats component provides real-time system health monitoring across four key areas: Junctions, Collectors, Streams, and Sensors. It aggregates data from multiple API endpoints and displays overall system health with expandable warning details.

Data Sources

API Endpoints

Endpoint Refresh Rate Purpose
/api/collectors/stats 5 seconds Collector health, activity, and sensor aggregation
/api/connections/streams/stats 5 seconds Stream health and activity
In-memory (props) Real-time Junction status from parent component

System Areas Monitored

🔗 Junctions

Data Source: Direct from parent component (junction status array)

Metrics Tracked: - Active count: Junctions with status === 'Running' - Total count: All junctions in system - Health: Currently always "All Healthy" (no error conditions implemented yet)

Health Determination: - ✅ Success: Default state (no checks performed) - ⚠️ Warning: Not implemented - ❌ Error: Not implemented


💾 Collectors

Data Source: GET /api/collectors/statscollectors object

Metrics Tracked: - Active count: Number of active polling operations - Total count: All collectors (excluding EventEngine) - Locked count: Collectors requiring password unlock - Failed fetch count: Collectors with LastFetchSuccessful == false - Never fetched count: Collectors with LastFetchTime == null

Exclusions: - ⚠️ EventEngine collectors are excluded from all stats (special internal collector)

Health Determination: - ❌ Error: Any collector has LastFetchSuccessful == false - Example: "Collector ABC fetch failed - Connection timeout" - ⚠️ Warning: Any collector is locked OR has never fetched data - Example: "Collector XYZ is locked - Collector requires password to unlock" - Example: "Collector DEF not fetched - Collector has never fetched data" - ✅ Success: All collectors healthy (fetched successfully, not locked)

Issue Types: | Type | Condition | Example Title | Example Description | |------|-----------|---------------|---------------------| | Error | LastFetchSuccessful == false | "SensorPush fetch failed" | Content from LastFetchErrorMessage | | Warning | ExternalAccessToken == true && !IsUnlocked() | "SensorPush is locked" | "Collector requires password to unlock" | | Warning | LastFetchTime == null | "HomeKit not fetched" | "Collector has never fetched data" |


📡 Streams

Data Source: GET /api/connections/streams/stats

Metrics Tracked: - Active count: All currently running streams - Total count: Same as active (only active streams are returned) - Breakdown by type: HTTP, MQTT, COM, WebSocket, Virtual - Inactive count: Streams not sending data for 5+ minutes - Slow count: Streams not sending data for 30+ seconds

Health Determination: - ❌ Error: Any stream hasn't sent data in 5+ minutes (inactive/dead) - Threshold: timeSinceLastSend.TotalMinutes > StreamStatsConfig.ERROR_NO_DATA_MINUTES - Example: "Virtual--1 stream inactive - No data sent for 6.2 minutes" - ⚠️ Warning: Stream hasn't sent data in 30+ seconds OR never sent data - Threshold: timeSinceLastSend.TotalSeconds > StreamStatsConfig.WARNING_NO_DATA_SECONDS - Example: "HTTP Stream 2 stream slow - No data sent for 45 seconds" - Example: "MQTT Stream 1 stream not sending - Stream has never sent data" - ✅ Success: All streams sending data within 30 seconds

Issue Types: | Type | Condition | Example Title | Example Description | |------|-----------|---------------|---------------------| | Error | No data for 5+ minutes | "Device-123 stream inactive" | "No data sent for 6.2 minutes" | | Warning | No data for 30+ seconds | "Device-456 stream slow" | "No data sent for 45 seconds" | | Warning | LastSentTime == null | "Device-789 stream not sending" | "Stream has never sent data" |

Stream Type Detection: Uses reflection to inspect stream objects: - LastSentTime property: Determines last activity - DeviceName property: Stream identifier - ScreenId property: Associated device screen


🎛️ Sensors

Data Source: GET /api/collectors/statssensors object

Metrics Tracked: - Active count: Total sensors from successful collectors - Total count: Sum of all LastFetchTotalSensors across collectors - Lost sensors: Sum of all LastFetchLostSensors across collectors - New sensors: Sum of all LastFetchNewSensors across collectors

Why Sensors Come from Collectors API: - Collectors track sensor health through delta operations - Collectors know about lost sensors, new sensors, fetch success/failure - Single source of truth for sensor data - Better context (which collector is causing sensor issues) - Simpler architecture (one less endpoint to maintain)

Health Determination: - ❌ Error: 5 or more sensors lost across all collectors - Threshold: totalLostSensors >= CollectorStatsConfig.SENSOR_ERROR_LOST_THRESHOLD - Example: "SensorPush lost 6 sensors - 6 sensors no longer detected" - ⚠️ Warning: Any sensors lost (1-4 sensors) - Threshold: totalLostSensors >= CollectorStatsConfig.SENSOR_WARNING_LOST_THRESHOLD - Example: "HomeKit lost 2 sensors - 2 sensors no longer detected" - ✅ Success: No sensors lost

Issue Types: | Type | Condition | Example Title | Example Description | |------|-----------|---------------|---------------------| | Error | Lost count ≥ 5 | "Collector XYZ lost 6 sensors" | "6 sensors no longer detected" | | Warning | Lost count ≥ 1 | "Collector ABC lost 2 sensors" | "2 sensors no longer detected" |

Data Aggregation: - Sensors are aggregated across all collectors - Only collectors with CollectorType != "EventEngine" are included - Active sensors = sensors from collectors where LastFetchSuccessful == true


Warning Thresholds Summary

Critical Error Thresholds

Area Threshold Condition
Collectors Immediate Fetch operation fails
Streams 5 minutes No data transmission
Sensors 5+ lost Multiple sensors lost across collectors

Warning Thresholds

Area Threshold Condition
Collectors Immediate Locked or never fetched
Streams 30 seconds Slow data transmission
Streams Immediate Never sent data
Sensors 1+ lost Any sensors lost

UI Behavior

Stats Display

  • Always visible 2x2 grid (mobile) or 4-column grid (desktop)
  • Real-time updates every 5 seconds
  • Loading spinner on initial load
  • Dynamic health icons based on severity

Health Icons

  • ✅ Green checkmark: Success
  • ⚠️ Yellow warning triangle: Warnings present
  • ❌ Red error icon: Errors present

Collapsible Warnings Section

Default State: Collapsed (saved to localStorage)

Header Display: - No issues: "No Warnings" with green checkmark - Issues present: "Current Warnings" with counts - Shows separate counts for errors and warnings - Example: "2 Errors, 3 Warnings"

Expanded Table Columns: 1. Area (chip badge: Collectors, Streams, Sensors, Junctions) 2. Severity (icon + type) 3. Issue (title) 4. Description (details) 5. Time (timestamp)

Sorting: Most recent issues first (by timestamp descending)

Local Storage Keys

Key Value Purpose
dashboard_overview_expanded "true" / "false" Warnings section expansion state

Performance Considerations

Polling Strategy

  • Interval: 5 seconds for all API calls
  • Batch Requests: Uses Promise.all() for parallel fetching (collectors + streams)
  • Loading State: Only shown on initial load, not on refresh

Memory Management

  • Component cleanup on unmount stops polling intervals
  • State updates only occur when data changes
  • useMemo prevents unnecessary recalculations

API Response Structure

/api/collectors/stats Response

{
  "collectors": {
    "active": 8,
    "total": 10,
    "health": {
      "status": "2 Warnings",
      "severity": "warning"
    },
    "hasIssues": true,
    "details": [...],
    "breakdown": {
      "locked": 1,
      "failedFetch": 0,
      "neverFetched": 1,
      "healthy": 8,
      "errors": 0,
      "warnings": 2
    }
  },
  "sensors": {
    "active": 342,
    "total": 350,
    "health": {
      "status": "5 Lost",
      "severity": "error"
    },
    "hasIssues": true,
    "details": [...],
    "breakdown": {
      "lost": 5,
      "new": 2,
      "healthy": 345
    }
  }
}

Error Handling

API Failures

  • Logs errors to console
  • Shows "Loading..." status for failed area
  • Continues polling (doesn't crash on single failure)
  • No user-facing error messages (fails gracefully)

Missing Data

  • Collectors: Shows 0 active, "Unknown" health
  • Streams: Shows 0 active, "Unknown" health
  • Sensors: Shows 0 active, "Unknown" health

Security Considerations

  1. No sensitive data exposure: Only aggregated counts and status
  2. Read-only operations: No ability to modify system state
  3. Rate limiting: Covered by Dashboard policy (200 tokens / 10 seconds)
  4. Authentication required: Dashboard route protected by auth middleware

Future Enhancements

Planned Additions

  • [ ] Junction health monitoring (error detection)
  • [ ] Configurable warning thresholds via UI
  • [ ] Historical trend data
  • [ ] Alert notifications for critical errors
  • [ ] Export functionality for warning logs
  • [ ] Time-based sensor staleness tracking (in addition to lost sensors)

Potential Improvements

  • Add "Acknowledge" feature for warnings
  • Link warnings directly to affected resources
  • Customize polling intervals per user preference
  • Add webhook notifications for critical errors
  • Implement warning suppression rules
  • Add device-level sensor tracking (in addition to collector-level)

Troubleshooting

Stats Not Updating

  • Check browser console for API errors
  • Verify endpoints return valid JSON
  • Check network tab for 429 rate limit errors
  • Ensure polling interval cleanup on unmount

Incorrect Counts

  • Collectors: Verify EventEngine is excluded
  • Streams: Check that all stream managers are queried
  • Sensors: Verify aggregation across all collectors
  • Compare API response to displayed values

Sensor Stats Issues

  • Lost sensors not showing: Check LastFetchLostSensors is being tracked
  • Verify collectors are performing delta operations
  • Check collector fetch success/failure states

Performance Issues

  • Reduce polling interval if server load is high
  • Consider implementing WebSocket for real-time updates
  • Check for memory leaks in polling cleanup

Warning Table Issues

  • Verify timestamp parsing for all warning types
  • Check localStorage for expansion state persistence
  • Ensure all warning details have required fields (id, type, title, description, timestamp, area)
  • Sensor warnings should have collectorId and lostCount properties