Skip to main content

aranet_service/
lib.rs

1//! Background collector and HTTP REST API for Aranet sensors.
2//!
3//! This crate provides a service that:
4//! - Polls configured Aranet devices on a schedule
5//! - Stores readings in the local database
6//! - Exposes a REST API for querying data
7//! - Provides WebSocket connections for real-time updates
8//! - Optional API key authentication and rate limiting
9//!
10//! # REST API Endpoints
11//!
12//! - `GET /api/health` - Service health check (no auth required)
13//! - `GET /api/devices` - List all known devices
14//! - `GET /api/devices/:id` - Get device info
15//! - `GET /api/devices/:id/current` - Latest reading for device
16//! - `GET /api/devices/:id/readings` - Query readings with filters
17//! - `GET /api/devices/:id/history` - Query cached history
18//! - `GET /api/readings` - All readings across devices
19//! - `WS /api/ws` - Real-time readings stream
20//!
21//! # Configuration
22//!
23//! The service reads configuration from `~/.config/aranet/server.toml`:
24//!
25//! ```toml
26//! [server]
27//! bind = "127.0.0.1:8080"
28//!
29//! [storage]
30//! path = "~/.local/share/aranet/data.db"
31//!
32//! [[devices]]
33//! address = "Aranet4 17C3C"
34//! alias = "office"
35//! poll_interval = 60
36//! ```
37//!
38//! # Security
39//!
40//! Optional security features can be enabled:
41//!
42//! ```toml
43//! [security]
44//! # Require X-API-Key header for all requests (except /api/health)
45//! api_key_enabled = true
46//! api_key = "your-secure-random-key-at-least-16-chars"
47//!
48//! # Rate limit requests per IP address
49//! rate_limit_enabled = true
50//! rate_limit_requests = 100   # max requests per window
51//! rate_limit_window_secs = 60 # window duration
52//! ```
53//!
54//! For WebSocket connections, browsers cannot set custom headers. Use the `token`
55//! query parameter instead: `ws://localhost:8080/api/ws?token=your-api-key`
56//!
57//! # Platform Setup
58//!
59//! ## macOS
60//!
61//! ### Bluetooth Permissions
62//!
63//! The Aranet devices use Bluetooth Low Energy. On macOS, you need to grant
64//! Bluetooth permissions:
65//!
66//! 1. **Terminal App**: When running from Terminal, the Terminal app must have
67//!    Bluetooth permission in System Preferences > Privacy & Security > Bluetooth.
68//!
69//! 2. **VS Code Terminal**: Add VS Code to the Bluetooth permissions list.
70//!
71//! 3. **LaunchAgent**: For background services, add `aranet-service` to the
72//!    Bluetooth permission list. You may need to use a signed binary or run
73//!    with appropriate entitlements.
74//!
75//! ### User-Level Service (Recommended)
76//!
77//! Install as a user LaunchAgent (no root required):
78//!
79//! ```bash
80//! # Install the service
81//! aranet-service service install --user
82//!
83//! # Start the service
84//! aranet-service service start --user
85//!
86//! # Check status
87//! aranet-service service status --user
88//!
89//! # Stop and uninstall
90//! aranet-service service stop --user
91//! aranet-service service uninstall --user
92//! ```
93//!
94//! The LaunchAgent plist is created at `~/Library/LaunchAgents/dev.rye.aranet.plist`.
95//!
96//! ## Linux
97//!
98//! ### BlueZ D-Bus Access
99//!
100//! The service needs access to the BlueZ D-Bus interface. For user-level services:
101//!
102//! 1. **Ensure your user is in the bluetooth group:**
103//!    ```bash
104//!    sudo usermod -a -G bluetooth $USER
105//!    # Log out and back in for group changes to take effect
106//!    ```
107//!
108//! 2. **D-Bus session access**: User-level systemd services need the D-Bus session.
109//!    Create a drop-in config if needed:
110//!    ```bash
111//!    mkdir -p ~/.config/systemd/user/aranet.service.d
112//!    cat > ~/.config/systemd/user/aranet.service.d/dbus.conf << EOF
113//!    [Service]
114//!    Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus"
115//!    EOF
116//!    systemctl --user daemon-reload
117//!    ```
118//!
119//! ### User-Level Service
120//!
121//! ```bash
122//! # Install the user service
123//! aranet-service service install --user
124//!
125//! # Enable and start
126//! systemctl --user enable --now dev.rye.aranet
127//!
128//! # Check status
129//! systemctl --user status dev.rye.aranet
130//!
131//! # View logs
132//! journalctl --user -u dev.rye.aranet -f
133//!
134//! # Stop and uninstall
135//! systemctl --user stop dev.rye.aranet
136//! aranet-service service uninstall --user
137//! ```
138//!
139//! ### System-Level Service
140//!
141//! For system services, you need to create a dedicated user:
142//!
143//! ```bash
144//! # Create aranet user (with bluetooth group membership)
145//! sudo useradd -r -s /sbin/nologin -G bluetooth aranet
146//!
147//! # Install as system service
148//! sudo aranet-service service install
149//!
150//! # Start the service
151//! sudo systemctl enable --now dev.rye.aranet
152//! ```
153//!
154//! ## Windows
155//!
156//! ### Bluetooth Permissions
157//!
158//! Windows requires the app to be granted Bluetooth access through Settings:
159//! - Settings > Privacy & Security > Bluetooth > Allow apps to access your Bluetooth
160//!
161//! ### Running as a Service
162//!
163//! On Windows, the service runs as a Windows Service. Install and manage via:
164//!
165//! ```powershell
166//! # Run as Administrator
167//! aranet-service service install
168//! aranet-service service start
169//!
170//! # Check status (in Services panel or via)
171//! aranet-service service status
172//!
173//! # Stop and uninstall
174//! aranet-service service stop
175//! aranet-service service uninstall
176//! ```
177//!
178//! **Note**: Windows Services run in session 0 without a desktop, which may affect
179//! Bluetooth access. Consider using Task Scheduler to run the service at logon
180//! if you encounter Bluetooth issues:
181//!
182//! ```powershell
183//! # Create a scheduled task to run at logon
184//! schtasks /create /tn "AranetService" /tr "aranet-service run" /sc onlogon /rl highest
185//! ```
186
187pub mod api;
188pub mod collector;
189pub mod config;
190pub mod middleware;
191pub mod state;
192pub mod ws;
193
194pub use collector::Collector;
195pub use config::{
196    Config, ConfigError, DeviceConfig, MqttConfig, PrometheusConfig, SecurityConfig, ServerConfig,
197    StorageConfig,
198};
199pub use state::{AppState, ReadingEvent};
200
201#[cfg(feature = "mqtt")]
202pub mod mqtt;
203
204#[cfg(feature = "prometheus")]
205pub mod prometheus;