- Add equipment_events table and Event schema for tracking device changes
- Implement automatic change detection for interface attributes during SNMP polling
- Detects operational status changes (up/down)
- Detects admin status changes
- Detects speed changes with warning severity for speed drops
- Detects MAC address changes
- Add Logs tab to equipment detail page with event display
- Fix temperature sensor display bug (was showing 4.3C instead of 43C due to double division)
- Remove response time tracking from monitoring checks and UI
- Move Rediscover Device button to equipment edit page
This fixes critical issues where SNMP sensor readings, interface stats, and
monitoring checks were not being saved to the database due to schema mismatches.
Database schema fixes:
- Recreate snmp_sensor_readings table with binary_id primary key
- Recreate snmp_interface_stats table with binary_id primary key
- Recreate monitoring_checks table with binary_id primary key
The original migrations used default integer primary keys, but the schemas
expected binary_id (UUID). This caused Ecto to generate UUID strings that
Postgrex tried to encode as binaries, resulting in silent insert failures.
SNMP interface stats fixes:
- Fix field name mismatch in get_interface_stats (if_in_octets vs in_octets)
- Remove unnecessary tuple handling code (Client already unwraps SNMPKit tuples)
- Clean up decode_snmp_value function and improve error messages
Monitoring check fixes:
- Fix response_time type from float to integer in Poller.check_device
- Add error logging to catch and report check creation failures
These changes enable:
- SNMP sensor readings to be collected and stored (disk usage, memory, CPU, etc.)
- Interface statistics to be collected (Counter64 octets, errors, discards)
- Equipment availability metrics to update on the dashboard
Prevents duplicate polling when multiple pods are running by using
database-based coordination.
Changes:
- Added last_snmp_poll_at timestamp to equipment table
- Added Equipment.update_snmp_poll_time/1 function
- Updated PollerWorker to check last_snmp_poll_at before polling
- Polls are skipped if equipment was polled within (interval - 5s)
- Updates timestamp before polling (optimistic locking)
This ensures that when K8s scales up/down or pods restart, only one
pod polls each piece of equipment at a time, preventing wasteful
duplicate SNMP queries and database writes.
The 5-second grace period accounts for clock drift and processing delays
between pods.
Storage sensors (disk/memory usage) need to fetch two OIDs to calculate
percentages: the 'used' value and the 'size' value. Previously, only the
'used' OID was stored and polled, resulting in meaningless raw values.
Changes:
- Added metadata JSONB field to snmp_sensors table
- Updated Sensor schema to include metadata field
- Updated MikroTik profile to store size_oid in metadata for storage sensors
- Updated PollerWorker to handle percentage calculation sensors:
- poll_simple_sensor: Standard OID fetch with divisor
- poll_percentage_sensor: Fetches both used and size OIDs, calculates percentage
Storage sensors now properly calculate and store percentage values during polling.
NOTE: Existing MikroTik devices need to re-run SNMP discovery to populate
the metadata field for storage sensors.
- Convert snmp_sensor_readings to standard table
- Convert snmp_interface_stats to standard table
- Disable snmp_sensor_aggregates (continuous aggregates)
- Disable snmp_interface_aggregates (continuous aggregates)
All TimescaleDB commercial features (hypertables, continuous aggregates,
retention/compression policies) are disabled. Using standard PostgreSQL
tables with proper indexing instead.
Commented out retention and compression policies which require
TimescaleDB commercial license. Apache-licensed version only supports
basic hypertable functionality.
Monitoring Infrastructure:
- lib/towerops/monitoring/ping.ex - OS-agnostic ping functionality that works on macOS, Linux, and Windows
- lib/towerops/monitoring/equipment_monitor.ex - GenServer that monitors individual equipment at configurable intervals
- lib/towerops/monitoring/supervisor.ex - DynamicSupervisor with Registry for managing monitor workers
- lib/towerops/monitoring.ex - Context for creating and querying monitoring checks
Database:
- monitoring_checks table stores historical ping results with status, response time, and timestamps
- Indexed on (equipment_id, checked_at) for efficient querying
Real-Time Updates:
- PubSub broadcasting on equipment:#{id} topic when status changes
- Equipment show page subscribes to updates and refreshes automatically
- Manual "Check Now" button to trigger immediate checks
Application Integration:
- Monitoring.Supervisor added to application supervision tree
- All monitored equipment starts monitoring automatically on app startup
- Recent checks displayed in Equipment show page
How It Works
1. On application start, a monitor GenServer is spawned for each equipment with monitoring_enabled: true
2. Each monitor pings its equipment at the configured interval (default 5 minutes)
3. Results are saved to monitoring_checks table
4. Equipment status is updated if it changes (up ↔ down)
5. Status changes are broadcast via PubSub to all connected LiveViews
6. The Equipment show page updates in real-time when status changes
- Sites schema with hierarchical parent-child relationships
- CRUD operations for sites
- Sites context with helper functions
- LiveView pages:
- /orgs/:slug/sites - List all sites
- /orgs/:slug/sites/new - Create new site
- /orgs/:slug/sites/:id - View site details
- /orgs/:slug/sites/:id/edit - Edit site
- Support for site locations and descriptions
- Site tree builder for hierarchy visualization
2. Equipment Management
- Equipment schema with monitoring fields
- IP address validation (IPv4 & IPv6)
- Equipment status tracking (up/down/unknown)
- Customizable check intervals per equipment
- Equipment context with CRUD operations
- LiveView pages:
- /orgs/:slug/equipment - List all equipment
- /orgs/:slug/equipment/new - Add equipment
- /orgs/:slug/equipment/:id - View equipment details
- /orgs/:slug/equipment/:id/edit - Edit equipment
- Equipment can be added from site pages
- Status badges and last checked timestamps
3. Database Schema
- sites table with self-referencing parent_site_id
- equipment table with status tracking
- All migrations run successfully
- Proper indexes on foreign keys and status
4. Features Implemented
- ✅ IP address validation using :inet.parse_address
- ✅ Site hierarchy with parent-child relationships
- ✅ Equipment linked to sites
- ✅ Monitoring enabled/disabled per equipment
- ✅ Customizable check intervals (30s - 3600s)
- ✅ Status tracking (up/down/unknown)
- ✅ Timestamps for last check and last status change
- ✅ Organization-scoped data (users only see their org's data)