# 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 or HTTPS because Basic Authentication does not encrypt credentials over plain HTTP. - 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 certificate verification is enabled and cannot be bypassed by configuration. ## 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 device certificate must be trusted by the exporter operating system or container. Use a certificate issued by a trusted internal CA and add that CA to the runtime trust store. ### 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.