⚠️ AI-Generated Code Warning: This project was "vibe coded" using generative AI and should be thoroughly reviewed before use. It comes with no warranty or guarantee of functionality, security, or reliability.
Pentameter is a Prometheus exporter for Pentair IntelliCenter pool controllers that connects via WebSocket and exposes pool equipment data as Prometheus metrics with pre-configured Grafana dashboards for visualization.
- Temperature Monitoring: Pool, spa, and outdoor air sensors
- Pump Monitoring: Variable speed RPM and flow rates
- Equipment Status: Circuit and feature on/off states
- Connection Health: Automatic failure detection and recovery
- Auto-Discovery: Finds IntelliCenter automatically via mDNS (multicast DNS)
- Prometheus Metrics: Standard format compatible with any monitoring tool
- Pre-configured Dashboards: Grafana dashboards with automatic provisioning
- Kiosk Mode: Clean displays for dedicated monitoring screens
- Historical Trends: Long-term data visualization and analysis
- Intelligent Filtering: Focus on meaningful equipment vs virtual controls
- User-Controlled Feature Visibility: Respects IntelliCenter's "Show as Feature" settings
- Graceful Degradation: Handle missing sensors without errors
- Browser Compatibility: Standard metrics endpoint works everywhere
- WebSocket connection to IntelliCenter controllers
- Automatic IntelliCenter discovery via mDNS (finds
pentair.localon network) - Listen mode for real-time equipment change monitoring and debugging
- Robust connection management with exponential backoff retry logic
- Health checks with automatic reconnection on failures
- Configurable via command line flags or environment variables
- Health check endpoint
Pentameter connects to IntelliCenter controllers via WebSocket and transforms pool data into standard Prometheus metrics for monitoring and alerting.
-
Go Service - Core monitoring service
- WebSocket client for IntelliCenter communication
- Prometheus metrics endpoint (
/metrics) - Health checks and connection management
-
IntelliCenter Interface
- WebSocket connection (default port 6680)
- JSON message protocol using GetParamList API
- Exponential backoff retry with health checks
- Request/response polling - API does not support push notifications (verified 2025-11-08)
- Persistent connection with configurable poll intervals (2s for listen mode, 60s default)
-
Metrics Export
- HTTP server (default port 8080)
- Standard Prometheus format
- Compatible with any monitoring tool
-
Docker Deployment
- Multi-stage builds with scratch base images (~12MB)
- Docker Compose orchestration
- Prometheus and Grafana included
- Language: Go with standard library HTTP server
- WebSocket:
github.com/gorilla/websocket - Metrics:
github.com/prometheus/client_golang - Build: Makefile with Docker integration
- Deployment: Docker Compose with restart policies
Pentameter offers multiple installation methods to suit different deployment preferences:
| Method | Platform | Use Case | Features |
|---|---|---|---|
| Homebrew | macOS | Single exporter, integrate with existing monitoring | Instant install, pre-built binaries |
| Docker Compose | All platforms | Complete monitoring stack | Grafana dashboards, Prometheus included |
| Docker | All platforms | Container deployment | Lightweight, configurable |
| Go Install | All platforms | Go developers, build from source | Latest source, Go toolchain integration |
| Source Build | All platforms | Development, customization | Full control, latest changes |
Recommended for macOS users who want just the metrics exporter:
# One-line install (automatically adds tap)
brew install astrostl/pentameter/pentameter
# Start the exporter (auto-discovers IntelliCenter)
pentameter
# Or manually specify IP address if needed
export PENTAMETER_IC_IP=192.168.1.100
pentameterAlternative two-step install:
# Add the tap (one time setup)
brew tap astrostl/pentameter https://github.com/astrostl/pentameter
brew install pentameter✅ Instant installation - No build time, no dependencies
✅ Pre-built binaries - Intel and Apple Silicon supported
✅ Automatic updates - brew upgrade pentameter
Metrics are available at http://localhost:8080/metrics
For complete monitoring with Grafana dashboards, use the Docker Compose option below.
Recommended for Go developers who want to build from source:
# Install latest version
go install github.com/astrostl/pentameter@latest
# Or install specific version
go install github.com/astrostl/pentameter@v0.2.2
# Start the exporter (auto-discovers IntelliCenter)
pentameter
# Or manually specify IP address if needed
export PENTAMETER_IC_IP=192.168.1.100
pentameter✅ Latest source - Always up-to-date with repository
✅ Go toolchain integration - Uses your existing Go installation
✅ All platforms - Works wherever Go runs
Note: Version information (pentameter --version) will show as "dev" since go install doesn't include build-time version injection.
Metrics are available at http://localhost:8080/metrics
Recommended for full monitoring setup with Grafana dashboards:
# Clone the repository (includes all config files)
git clone https://github.com/astrostl/pentameter.git
cd pentameter
# Start the complete monitoring stack (auto-discovers IntelliCenter)
docker compose up -d
# Or manually configure IP if auto-discovery doesn't work
cp .env.example .env
# Edit .env and set your PENTAMETER_IC_IP
docker compose up -d✅ Complete monitoring - Pentameter + Prometheus + Grafana
✅ Pre-configured dashboards - Ready-to-use Grafana setup
✅ No build time - Uses published DockerHub images
✅ All platforms - Works on macOS, Linux, Windows
Access Points:
- Grafana Dashboard:
http://localhost:3000/d/pentameter/ - Metrics:
http://localhost:8080/metrics - Prometheus:
http://localhost:9090
- Metrics:
http://HOSTNAME:8080/metrics- Prometheus metrics - Health:
http://HOSTNAME:8080/health- Health check - Prometheus:
http://HOSTNAME:9090- Prometheus web interface - Grafana:
http://HOSTNAME:3000/d/pentameter/- Grafana dashboards (no login required) - Kiosk Mode:
http://HOSTNAME:3000/d/pentameter/?kiosk- Clean dashboard display
Pentameter respects IntelliCenter's "Show as Feature" settings to avoid duplicate controls and maintain clean dashboards.
IntelliCenter allows users to control whether features appear in the interface through a "Show as Feature" checkbox in the Feature Circuits configuration. Pentameter automatically detects and respects this setting.
Common Use Case: Pool heating equipment often appears as both:
- Feature: User control (e.g., "Spa Heat" - enable/disable heating)
- Thermal Equipment: Actual equipment status (e.g., "Spa Heater" - heating/idle/cooling)
This creates duplication in monitoring dashboards where both the user control and equipment status are shown.
Users can eliminate this duplication through their IntelliCenter interface:
- Access IntelliCenter → Settings → Feature Circuits
- Select the feature (e.g., "Spa Heat")
- Uncheck "Show as Feature" to hide the user control
- Keep thermal equipment monitoring for actual operational status
Pentameter uses IntelliCenter's SHOMNU parameter to detect the "Show as Feature" setting:
- Show as Feature: YES → Feature appears in
feature_statusmetrics - Show as Feature: NO → Feature is automatically hidden from metrics
- User-Controlled: No hardcoded logic - users decide what to show
- Universal: Works with any equipment configuration and naming
- Clean Dashboards: Eliminates duplicate controls when desired
- Flexible: Users can show both if they want different information
Scenario 1: Show Both Controls
feature_status{name="Spa Heat"}→ User enable/disable controlthermal_status{name="Spa Heater"}→ Equipment operational status- Use Case: Monitor both user intent and equipment response
Scenario 2: Show Equipment Only
- User disables "Show as Feature" for "Spa Heat"
- Only
thermal_status{name="Spa Heater"}appears - Use Case: Focus on equipment operation, control via IntelliCenter
This approach ensures Pentameter works universally across different pool configurations while giving users full control over their monitoring interface.
All configuration options can be set via command line flags or environment variables:
| Flag | Environment Variable | Default | Description |
|---|---|---|---|
--ic-ip |
PENTAMETER_IC_IP |
(auto-discover) | IntelliCenter IP address (optional, auto-discovers via mDNS if not provided) |
--ic-port |
PENTAMETER_IC_PORT |
6680 |
IntelliCenter WebSocket port |
--http-port |
PENTAMETER_HTTP_PORT |
8080 |
HTTP server port for metrics |
--interval |
PENTAMETER_INTERVAL |
60 |
Polling interval in seconds (minimum 5s) |
--listen |
PENTAMETER_LISTEN |
false |
Enable live event monitoring mode |
--discover |
N/A | N/A | Discover IntelliCenter IP address and exit |
--version |
N/A | N/A | Show version information |
Pentameter can automatically discover your IntelliCenter on the local network using mDNS (multicast DNS). The IntelliCenter broadcasts itself as pentair.local on the network.
How it works:
- When
--ic-ipis not provided, pentameter automatically searches forpentair.localvia mDNS - Discovery timeout is 60 seconds with progress indicators every 2 seconds
- Works on most home networks without additional configuration
- Docker support: Auto-discovery works in Docker using host networking (enabled by default)
- Automatic re-discovery: If the IntelliCenter's IP changes (DHCP renewal, router reboot), pentameter automatically re-discovers it after 3 failed connection attempts
Test discovery:
# Test auto-discovery and show IP address
pentameter --discover
# Example output:
# IntelliCenter discovered at: 192.168.1.100Manual IP specification:
# Bypass auto-discovery and use specific IP
pentameter --ic-ip 192.168.1.100
# Or via environment variable
export PENTAMETER_IC_IP=192.168.1.100
pentameterDocker auto-discovery:
# Docker Compose with auto-discovery (default behavior)
docker compose up -d
# Docker run with auto-discovery
docker run -d --name pentameter --network host astrostl/pentameter:latestTroubleshooting:
- If auto-discovery fails, pentameter provides clear guidance on using the
--ic-ipflag - Check that your IntelliCenter is on the same network
- Some networks may block mDNS multicast traffic (port 5353/UDP)
- Firewalls may need to allow multicast traffic to 224.0.0.251:5353
- Docker: Host networking is required for mDNS (enabled by default in docker-compose.yml)
- Use
--ic-ipflag to manually specify IP address if auto-discovery doesn't work
Listen mode provides real-time event logging for pool equipment changes using a hybrid push + poll architecture. Perfect for debugging, discovering equipment, and monitoring activity.
- Hybrid Push + Poll: Real-time push notifications for instant updates, plus periodic polling (default 60s) to catch equipment that doesn't push (like pump RPM changes)
- Source Identification: Events prefixed with
PUSH:orPOLL:to distinguish real-time vs polled updates - Initial State Discovery: Shows all equipment and current state on startup
- Unknown Equipment Detection: Automatically discovers equipment types not specifically implemented (valves, sensors, remotes, etc.)
- Clean Output: Reports
POLL: [no changes]when poll cycles find no updates
# Basic listen mode (60-second poll interval)
pentameter --ic-ip 192.168.1.100 --listen
# Custom polling interval (10 seconds)
pentameter --ic-ip 192.168.1.100 --listen --interval 10
# Via environment variable
export PENTAMETER_IC_IP=192.168.1.100
export PENTAMETER_LISTEN=true
pentameter2025/11/28 18:51:15 Fetching initial equipment state...
2025/11/28 18:51:15 POLL: Pool temperature detected: 22.0°F
2025/11/28 18:51:15 POLL: Spa temperature detected: 95.0°F
2025/11/28 18:51:15 POLL: VS detected: 3000 RPM
2025/11/28 18:51:16 POLL: Pool detected: ON
2025/11/28 18:51:16 POLL: Spa Heater detected: heating
2025/11/28 18:51:35 Listening for real-time changes (Ctrl+C to stop)...
2025/11/28 18:52:04 PUSH: Spa temp=97°F setpoint=98°F htmode=1 status=ON
2025/11/28 18:53:35 POLL: Spa temperature changed: 95.0°F → 96.0°F
2025/11/28 18:53:35 POLL: VS changed: 3000 → 2500 RPM
2025/11/28 18:54:35 POLL: [no changes]
- Debugging: Watch equipment respond to commands in real-time via
PUSH:events - Discovery: Find all equipment in your IntelliCenter, including unknown types
- Monitoring: Track circuit activation, temperature changes, and pump speed adjustments
- Testing: Verify equipment changes are being reported correctly
- Pump Tracking: Monitor pump RPM changes (not pushed by IntelliCenter, requires polling)
Listen mode monitors all equipment types:
- Water & Air Temperatures: Bodies and sensors
- Circuits: Lights, pumps, valves, cleaners
- Features: Spa jets, fountains, automation features
- Thermal Equipment: Heaters and heat pumps with operational states
- Pumps: Variable speed RPM changes (via polling)
- Unknown Equipment: Any equipment type not specifically implemented
go run main.go --ic-ip 192.168.192.168 --ic-port 6680 --http-port 8080 --interval 60export PENTAMETER_IC_IP=192.168.192.168
export PENTAMETER_IC_PORT=6680
export PENTAMETER_HTTP_PORT=8080
export PENTAMETER_INTERVAL=60
go run main.go# Use environment for IP, override HTTP port via flag
export PENTAMETER_IC_IP=192.168.192.168
go run main.go --http-port 9090# Water temperatures
water_temperature_fahrenheit{body="POOL",name="Pool"} 87
water_temperature_fahrenheit{body="SPA",name="Spa"} 84
# Air temperature (optional)
air_temperature_fahrenheit{sensor="AIR",name="Air Sensor"} 73
# Pump speeds and flow
pump_rpm{pump="PMP01",name="VS"} 3000
pump_rpm{pump="PMP02",name="pool"} 2450
# Circuit status (1=on, 0=off)
circuit_status{circuit="C0001",name="Spa",type="SPA"} 1
circuit_status{circuit="C0003",name="Pool Light",type="LIGHT"} 0
circuit_status{circuit="FTR01",name="Spa Heat",type="GENERIC"} 0
thermal_status Values - Pentameter's Interpretation Layer:
Derived from IntelliCenter Data:
- 0 (off): Based on HTSRC="00000" (no heater assigned)
- 1 (heating): Based on HTMODE=1 or HTMODE=4 (active heating demand)
Pentameter's Logical Inference:
- 2 (idle): Pentameter's interpretation of HTMODE=0 + HTSRC≠"00000" (heater assigned but not demanded)
- 3 (cooling): Pentameter's interpretation of HTMODE=9 (heat pump cooling mode)
IntelliCenter Raw Data:
- HTMODE: 0, 1, 4, 9 (heating/cooling demand states)
- HTSRC: "00000" or heater ID (assignment status)
The thermal_status metric translates IntelliCenter's raw operational data into human-friendly states. The "idle" and "cooling" concepts are pentameter's abstractions - IntelliCenter itself only provides demand and assignment status.
# Thermal equipment operational status (see interpretation above)
thermal_status{heater="H0002",name="Spa Heater",subtyp="GENERIC"} 2
# Temperature setpoints (Fahrenheit)
thermal_low_setpoint_fahrenheit{heater="H0002",name="Spa Heater",subtyp="GENERIC"} 95
thermal_high_setpoint_fahrenheit{heater="H0001",name="Pool Heat Pump",subtyp="ULTRA"} 88
Setpoint Display Logic:
- Heatpoint (low setpoint): Always shown for any assigned heater
- Coolpoint (high setpoint): Only shown when < 100°F and equipment is idle or cooling
- 100°F Threshold: Filters out impractical cooling setpoints from heating-only equipment
# Connection monitoring
intellicenter_connection_failure 0
intellicenter_last_refresh_timestamp_seconds 1751302319
# Equipment connection status (1=connected, 0=disconnected)
thermal_status{heater="H0001",name="Pool Heat Pump",subtyp="ULTRA"} 0
pump_status{pump="PMP01",name="VS",subtyp="PUMP"} 1
Connection Status Behavior:
- Service Level:
intellicenter_connection_failuretracks WebSocket connectivity to IntelliCenter - Equipment Level: Individual equipment metrics disappear when equipment is offline/disconnected
- Graceful Degradation: Missing equipment doesn't cause service failures
- Automatic Recovery: Equipment metrics reappear when equipment comes back online
| Metric Type | Source | API Query | Parameter |
|---|---|---|---|
| Water Temperature | Pool/Spa bodies | OBJTYP=BODY | TEMP |
| Air Temperature | Outdoor sensor | Object _A135 | PROBE |
| Pump RPM | Variable speed pumps | OBJTYP=PUMP | RPM |
| Circuit Status | Equipment controls | OBJTYP=CIRCUIT | STATUS |
| Thermal Status | Heating equipment | OBJTYP=HEATER | STATUS + HTMODE |
| Thermal Setpoints | Pool/Spa bodies | OBJTYP=BODY | LOTMP, HITMP |
| Connection Health | Internal monitoring | N/A | WebSocket health checks |
| Equipment Health | Individual equipment | API responses | Missing data = offline |
| Refresh Timestamp | Internal tracking | N/A | Unix timestamp |
- Exponential Backoff: 1s → 2s → 4s → 8s → 16s → 30s max
- Health Checks: WebSocket ping/pong every 30 seconds
- Retry Limits: Maximum 5 attempts before giving up
- Connection Failure Metric:
intellicenter_connection_failure(0=connected, 1=failed)
- Individual Equipment Status: Each piece of equipment reports its own connection state
- Missing Data Detection: Equipment metrics disappear when equipment goes offline
- No Service Impact: Individual equipment failures don't affect service or other equipment
- Automatic Reappearance: Equipment metrics return when equipment comes back online
- Pump Offline:
pump_rpmmetrics disappear, water temperature monitoring continues - Heater Offline:
thermal_statusmetrics disappear, circuit monitoring continues - Sensor Offline:
air_temperaturemetrics disappear, pool/spa monitoring continues - Service Recovery: All equipment metrics reappear when service reconnects to IntelliCenter
RetryConfig{
MaxRetries: 5,
BaseDelay: 1 * time.Second,
MaxDelay: 30 * time.Second,
BackoffFactor: 2.0,
HealthCheckRate: 30 * time.Second,
}Pentameter filters IntelliCenter's ~35 circuits down to ~9 meaningful equipment items:
Included (Useful Equipment):
- C-prefixed: Core equipment (Pool, Spa, Lights, Cleaner)
- FTR-prefixed: Features (Spa Heat, Fountain, Spa Jets)
Excluded (Virtual Controls):
- AUX circuits: Unused placeholder circuits
- X-prefixed: Virtual buttons (Pump Speed +/-)
- _A-prefixed: Action commands (All Lights On/Off)
- Duplicates: Multiple entries for same equipment
The project includes comprehensive build automation via Makefile:
# Development workflow
make dev # Build + quality checks (recommended for development)
make build # Build binary only
make quality # Run all quality checks
# Release workflow
make release # Complete release (Docker + Homebrew + GitHub assets)
# Docker development
make docker-build # Build with aggressive cache clearing (nuclear rebuild)
make compose-up # Start full monitoring stack
# Homebrew development
make build-macos-binaries # Build macOS binaries (Intel + Apple Silicon)
make update-homebrew-formula # Update Formula/pentameter.rb with checksums
# View all available targets (organized by category)
make helpThe project uses a consolidated repository structure:
pentameter/
├── Formula/
│ └── pentameter.rb # Homebrew formula (consolidated tap)
├── dist/ # Generated during release (macOS binaries)
├── grafana/ # Dashboard and datasource configs
├── prometheus.yml # Prometheus scraping configuration
├── docker-compose.yml # Complete monitoring stack
├── Makefile # Build automation (Docker + Homebrew)
├── main.go # Core application
└── README.md
Key Features:
- Homebrew tap included - No separate repository needed
- Multi-platform releases - Docker (all platforms) + Homebrew (macOS)
- Automated workflows - Single
make releasecommand - Development friendly - Nuclear rebuild options for reliable Docker development
go build -o pentameter main.go
./pentameter --ic-ip 192.168.192.168# Using Makefile (recommended)
make compose-up # Start pentameter, Prometheus, and Grafana
make compose-logs # View logs
make compose-down # Stop all services
# Or manually
docker-compose up -d
docker-compose logs -f
docker-compose down
docker-compose restartThis starts the complete monitoring stack:
- Pentameter: Pool data collection service
- Prometheus: Metrics storage and querying
- Grafana: Pre-configured dashboard at http://HOSTNAME:3000/d/pentameter/
The docker-compose.yml uses environment variables that you can override:
environment:
- PENTAMETER_IC_IP=192.168.192.168
- PENTAMETER_IC_PORT=6680
- PENTAMETER_HTTP_PORT=8080
- PENTAMETER_INTERVAL=60# Build the image (required during early development)
docker build --no-cache -t pentameter .
# Run the container
docker run -d \
--name pentameter \
-p 8080:8080 \
-e PENTAMETER_IC_IP=192.168.192.168 \
pentameter- Base Image:
scratch(minimal ~12MB image) - Multi-stage build: Go compilation in
golang:1.24-alpine, final binary in scratch - Networking: Host networking mode for mDNS auto-discovery support
- Health Check: Built-in health check endpoint at
/health - Restart Policy:
unless-stoppedfor automatic recovery
The pentameter-app service uses host networking (network_mode: "host") to enable mDNS auto-discovery:
- Auto-Discovery: Allows pentameter to find IntelliCenter via
pentair.localmulticast DNS - Why Host Networking: Docker's default bridge network doesn't forward multicast traffic required for mDNS
- Security: Appropriate for local network monitoring tools that need direct network access
- Performance: Eliminates NAT overhead for WebSocket connections
Prometheus and Grafana remain on the bridge network (pentameter-net) and connect to pentameter via localhost.
- Scrape Interval: 60 seconds (matches polling interval)
- Data Retention: 730 days (2 years) for long-term historical analysis
- Network: Docker bridge communication via pentameter-net
- Format: Standard Prometheus metrics with label-based time series
Add to your Prometheus prometheus.yml:
scrape_configs:
- job_name: 'pentameter'
static_configs:
- targets: ['pentameter-app:8080']
scrape_interval: 60s# Specific equipment
water_temperature_fahrenheit{body="POOL"}
pump_rpm{name="VS"}
circuit_status{type="LIGHT"}
# All equipment types
water_temperature_fahrenheit
pump_rpm
circuit_status
# System health
intellicenter_connection_failure
intellicenter_last_refresh_timestamp_seconds
- Pre-configured: Automatically provisioned "Pool Monitoring" dashboard
- Anonymous Access: No authentication required for local use
- Adaptive Layout: Handles missing air sensors gracefully
- Real-time Updates: 30-second refresh with 6-hour default range
- Standard View: Full dashboard at
http://HOSTNAME:3000/d/pentameter/ - Kiosk Mode: Clean display at
http://HOSTNAME:3000/d/pentameter/?kiosk - Recommended Dashboard:
http://HOSTNAME:3000/d/pentameter/?kiosk&autofitpanels=true - Mobile Friendly: Responsive design for all screen sizes
- Water temperature trends (Pool & Spa)
- Air temperature trends (if available)
- Connection status indicators
- Human-readable timestamps ("X minutes ago" format)
Create custom panels using these queries:
water_temperature_fahrenheit{body="POOL"}
water_temperature_fahrenheit{body="SPA"}
air_temperature_fahrenheit{sensor="AIR"}
intellicenter_connection_failure
intellicenter_last_refresh_timestamp_seconds
- Refactor monolithic main.go into focused modules
- Implement structured logging with configurable levels
- Add comprehensive integration tests
- Implement automated coverage reporting
- Alert rule templates and notification integrations
- Update Makefile release targets to reflect current multi-step workflow
