210 lines
7.0 KiB
Markdown
210 lines
7.0 KiB
Markdown
# Operations and troubleshooting
|
||
|
||
## HTTP endpoints
|
||
|
||
| Path | Purpose | Device access |
|
||
| --- | --- | --- |
|
||
| `/metrics` | Prometheus/OpenMetrics output. Each request triggers collection from all configured devices. | yes |
|
||
| `/-/healthy` | Exporter process health; returns HTTP 200 and `OK`. | no |
|
||
|
||
The health endpoint proves that the HTTP process can respond. It deliberately does not contact Shelly devices. Use `shelly_up` to monitor individual device availability.
|
||
|
||
## Native deployment
|
||
|
||
```sh
|
||
go build -trimpath -o shelly-exporter .
|
||
./shelly-exporter -config config.yaml
|
||
```
|
||
|
||
The process handles `SIGINT` and `SIGTERM`, stops accepting requests, and gives the HTTP server up to 10 seconds to shut down.
|
||
|
||
Example systemd unit:
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Shelly Prometheus Exporter
|
||
After=network-online.target
|
||
Wants=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=shelly-exporter
|
||
Group=shelly-exporter
|
||
ExecStart=/usr/local/bin/shelly-exporter -config /etc/shelly-exporter/config.yaml
|
||
Restart=on-failure
|
||
RestartSec=5s
|
||
NoNewPrivileges=true
|
||
PrivateTmp=true
|
||
ProtectSystem=strict
|
||
ProtectHome=true
|
||
ReadOnlyPaths=/etc/shelly-exporter/config.yaml
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
Ensure the service account can read the configuration and reach every device over the network.
|
||
|
||
## Docker deployment
|
||
|
||
Build the image:
|
||
|
||
```sh
|
||
docker build --rm -t shelly-exporter:latest .
|
||
```
|
||
|
||
Run it with a read-only configuration mount:
|
||
|
||
```sh
|
||
docker run --rm -d \
|
||
--name shelly-exporter \
|
||
-p 9090:9090 \
|
||
-v "$PWD/config.yaml:/opt/shelly-exporter/config.yaml:ro" \
|
||
shelly-exporter:latest
|
||
```
|
||
|
||
The image runs as an unprivileged user and includes a health check against `/-/healthy`. The configuration bundled in the image is only an example; mount the actual configuration for production.
|
||
|
||
## Prometheus setup
|
||
|
||
```yaml
|
||
scrape_configs:
|
||
- job_name: shelly
|
||
scrape_interval: 30s
|
||
scrape_timeout: 15s
|
||
static_configs:
|
||
- targets:
|
||
- shelly-exporter:9090
|
||
```
|
||
|
||
Keep the Prometheus `scrape_timeout` greater than `shelly.timeoutSeconds` plus a small allowance for metric encoding and network latency. Devices are queried concurrently, so the worst normal collection duration is close to the slowest device request rather than the sum of all requests.
|
||
|
||
The exporter contacts every device for every Prometheus scrape. Very short scrape intervals add unnecessary work to low-power hardware. A 15–60 second interval is a reasonable starting point for powered devices.
|
||
|
||
### Battery-powered sensors
|
||
|
||
Shelly Gen1 H&T, Flood, Door/Window, Button1, and similar battery devices sleep to conserve power. They may be unavailable during most scheduled scrapes, causing expected `shelly_up == 0` results. Consider MQTT or event callbacks when continuous collection from these products is required.
|
||
|
||
## Useful PromQL
|
||
|
||
Current power per standard meter:
|
||
|
||
```promql
|
||
shelly_meter_power_watts
|
||
```
|
||
|
||
Consumed energy over 24 hours in kWh:
|
||
|
||
```promql
|
||
increase(shelly_meter_energy_watt_hours_total[24h]) / 1000
|
||
```
|
||
|
||
EM/3EM imported and exported energy over 24 hours in kWh:
|
||
|
||
```promql
|
||
increase(shelly_emeter_energy_watt_hours_total[24h]) / 1000
|
||
```
|
||
|
||
```promql
|
||
increase(shelly_emeter_returned_energy_watt_hours_total[24h]) / 1000
|
||
```
|
||
|
||
Devices currently unavailable:
|
||
|
||
```promql
|
||
shelly_up == 0
|
||
```
|
||
|
||
Free RAM percentage where both fields are reported:
|
||
|
||
```promql
|
||
100 * shelly_ram_free_bytes / shelly_ram_size_bytes
|
||
```
|
||
|
||
## Example alert rules
|
||
|
||
Adjust durations and exclude sleeping products according to the installation.
|
||
|
||
```yaml
|
||
groups:
|
||
- name: shelly
|
||
rules:
|
||
- alert: ShellyDeviceDown
|
||
expr: shelly_up == 0
|
||
for: 5m
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: "Shelly {{ $labels.device }} is unreachable"
|
||
|
||
- alert: ShellyDeviceOvertemperature
|
||
expr: shelly_overtemperature == 1
|
||
for: 1m
|
||
labels:
|
||
severity: critical
|
||
annotations:
|
||
summary: "Shelly {{ $labels.device }} reports overtemperature"
|
||
|
||
- alert: ShellyWeakWiFi
|
||
expr: shelly_wifi_rssi_dbm < -80
|
||
for: 10m
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: "Shelly {{ $labels.device }} has weak Wi-Fi signal"
|
||
```
|
||
|
||
## Security
|
||
|
||
- Store `config.yaml` outside source control and restrict it to the exporter account, for example with mode `0600` on Linux.
|
||
- Prefer a trusted management network. HTTPS encrypts credentials in transit, but the exporter does not verify device certificates and therefore does not authenticate the remote endpoint.
|
||
- The exporter endpoints themselves do not require authentication. Restrict port 9090 with firewall, reverse proxy, or network policy when necessary.
|
||
- Device passwords are not metric labels, but request failures can include the target URL in logs. Do not put credentials in URL user-info; use `username` and `password` fields.
|
||
- HTTPS device certificates are not verified. Restrict device traffic to a trusted network to reduce man-in-the-middle risk.
|
||
|
||
## Troubleshooting
|
||
|
||
### Exporter does not start
|
||
|
||
Read the fatal error first. Configuration loading is strict, and common causes are:
|
||
|
||
- an unknown or misspelled YAML key;
|
||
- a hostname in `host` instead of a literal IP address;
|
||
- an empty device list;
|
||
- duplicate device names;
|
||
- an unsupported product identifier;
|
||
- a URL missing `http://` or `https://`.
|
||
|
||
Increase `logLevel` to `5` or `6` only after configuration validation succeeds.
|
||
|
||
### `shelly_up` is zero
|
||
|
||
Test the same request from the exporter host or container network:
|
||
|
||
```sh
|
||
curl -v -u admin:password http://192.168.0.30/status
|
||
```
|
||
|
||
Check routing, firewall rules, device power, credentials, and the configured timeout. HTTP errors and JSON decoding failures increment `shelly_scrape_errors_total`.
|
||
|
||
### HTTP 401 Unauthorized
|
||
|
||
Confirm that the configured username and password match the device. The exporter uses HTTP Basic Authentication. A device configured for a different authentication scheme will not work with the current client.
|
||
|
||
### TLS certificate error
|
||
|
||
The exporter deliberately ignores certificate validity for HTTPS device connections, including trust, expiry, and hostname checks. A certificate validation error therefore indicates that an older exporter build may still be running; update and restart it. Other TLS errors, such as unsupported protocol versions or cipher suites, are not certificate validation errors and can still fail the scrape.
|
||
|
||
### Device is up but an expected metric is absent
|
||
|
||
Metrics are intentionally conditional. Capture the raw `/status` JSON and verify that the corresponding field is present. Firmware versions and device modes can change response blocks—for example, Shelly 2.5 reports either relays or rollers depending on its operating mode.
|
||
|
||
For an unlisted Gen1 device, try `product: gen1`. If the field exists but is not modeled, follow the [extension guide](architecture.md#extending-the-gen1-schema).
|
||
|
||
### Scrapes time out
|
||
|
||
- Increase `shelly.timeoutSeconds` and Prometheus `scrape_timeout` together.
|
||
- Verify Wi-Fi RSSI and packet loss.
|
||
- Avoid overly short scrape intervals.
|
||
- Check whether a configured battery device is normally asleep.
|