5.5 KiB
5.5 KiB
Route-Switcher API Design
Overview
HTTP REST API with Basic Authentication for Home Assistant integration, exposing state machine state and ping statistics.
Design Principles
- Minimal surface area: Only expose necessary information
- Simple authentication: HTTP Basic Auth (no JWT complexity)
- State-focused: Centered on state machine state and ping history
- Home Assistant friendly: Structured for HA REST integration
- Opt-in: API disabled by default
API Endpoints
GET /api/state
Returns current state machine state with ping statistics.
Response:
{
"state": "Primary",
"primary_stats": {
"success_rate": 95.5,
"failures": 2,
"total_pings": 44,
"last_ping": "Ok"
},
"secondary_stats": {
"success_rate": 98.2,
"failures": 1,
"total_pings": 56,
"last_ping": "Ok"
},
"last_failover": "2024-02-15T10:30:00Z"
}
Fields:
state: Current state machine state (Boot/Primary/Fallback)primary_stats: Ping statistics for primary interfacesecondary_stats: Ping statistics for secondary interfacelast_failover: ISO 8601 timestamp of last failover (null if never)
POST /api/state
Manually set state machine state.
Request:
{
"state": "fallback"
}
Response:
{
"state": "Fallback",
"previous_state": "Primary",
"primary_stats": { ... },
"secondary_stats": { ... },
"last_failover": "2024-02-15T10:30:00Z"
}
Valid states: primary, fallback
Authentication
HTTP Basic Authentication with username/password configured via environment variables.
Security considerations:
- Passwords stored as bcrypt hash
- HTTPS recommended for production
- Local network access only
- No token management (stateless)
Data Structures
PingStats
Calculated from state machine ping history (60 entries per interface):
struct PingStats {
success_rate: f64, // Percentage of successful pings
failures: usize, // Number of failed pings in history
total_pings: usize, // Total pings in history
last_ping: String, // "Ok" or "Failed"
}
StateResponse
struct StateResponse {
state: String,
primary_stats: PingStats,
secondary_stats: PingStats,
last_failover: Option<String>,
}
Home Assistant Integration
REST Sensor Configuration
sensor:
- platform: rest
name: Route Switcher State
resource: http://route-switcher.local:8080/api/state
username: !secret route_switcher_user
password: !secret route_switcher_pass
value_template: "{{ value_json.state }}"
json_attributes:
- primary_stats
- secondary_stats
- last_failover
- platform: template
sensors:
route_switcher_primary_success_rate:
value_template: "{{ state_attr('sensor.route_switcher_state', 'primary_stats').success_rate | default(0) }}"
unit_of_measurement: "%"
route_switcher_secondary_success_rate:
value_template: "{{ state_attr('sensor.route_switcher_state', 'secondary_stats').success_rate | default(0) }}"
unit_of_measurement: "%"
route_switcher_primary_failures:
value_template: "{{ state_attr('sensor.route_switcher_state', 'primary_stats').failures | default(0) }}"
route_switcher_secondary_failures:
value_template: "{{ state_attr('sensor.route_switcher_state', 'secondary_stats').failures | default(0) }}"
switch:
- platform: rest
name: Route Switcher Control
resource: http://route-switcher.local:8080/api/state
username: !secret route_switcher_user
password: !secret route_switcher_pass
body_on: '{"state": "fallback"}'
body_off: '{"state": "primary"}'
is_on_template: "{{ value_json.state == 'fallback' }}"
Configuration
Environment Variables
# API Configuration
API_ENABLED=true
API_BIND_ADDRESS=0.0.0.0
API_PORT=8080
API_USERNAME=admin
API_PASSWORD_HASH=<bcrypt-hash>
# CORS Configuration
API_CORS_ORIGINS=http://homeassistant.local:8123
Password Hash Generation
# Generate bcrypt hash
echo -n "your-password" | bcrypt
Implementation Details
Dependencies
axum = "0.7"
tokio = { version = "1.42", features = ["full"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["cors", "auth"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
bcrypt = "0.15"
base64 = "0.22"
Architecture
- API Module:
src/api.rs- HTTP server and endpoints - State Sharing: Thread-safe access to state machine and ping history
- Authentication: Basic Auth middleware with bcrypt validation
- Error Handling: Standardized JSON error responses
- Integration: Minimal changes to existing state machine
Thread Safety
Arc<Mutex<StateMachine>>for shared state access- Non-blocking async operations
- Minimal locking duration
Error Handling
Standardized error responses:
{
"error": "Invalid state",
"message": "State must be 'primary' or 'fallback'"
}
HTTP Status Codes:
- 200: Success
- 400: Bad Request (invalid state)
- 401: Unauthorized (invalid credentials)
- 500: Internal Server Error
Security Considerations
- Network access restrictions (local only recommended)
- HTTPS for credential protection
- Rate limiting considerations
- Audit logging for manual state changes
- No configuration exposure (state only)
Backward Compatibility
- API disabled by default
- No changes to existing CLI functionality
- Service continues without API if disabled
- Graceful degradation on API errors