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/stats → collectors 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/stats → sensors 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¶
- No sensitive data exposure: Only aggregated counts and status
- Read-only operations: No ability to modify system state
- Rate limiting: Covered by Dashboard policy (200 tokens / 10 seconds)
- 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
LastFetchLostSensorsis 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
collectorIdandlostCountproperties