Files
lostakj 9ec7a92fa1
Build Docker image on push / docker (push) Successful in 20s
Build and push Docker image on tag / docker (push) Successful in 9s
Fixed issue with shelly self signed certificate.
2026-08-18 01:00:56 +02:00

7.0 KiB
Raw Permalink Blame History

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

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:

[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:

docker build --rm -t shelly-exporter:latest .

Run it with a read-only configuration mount:

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

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 1560 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:

shelly_meter_power_watts

Consumed energy over 24 hours in kWh:

increase(shelly_meter_energy_watt_hours_total[24h]) / 1000

EM/3EM imported and exported energy over 24 hours in kWh:

increase(shelly_emeter_energy_watt_hours_total[24h]) / 1000
increase(shelly_emeter_returned_energy_watt_hours_total[24h]) / 1000

Devices currently unavailable:

shelly_up == 0

Free RAM percentage where both fields are reported:

100 * shelly_ram_free_bytes / shelly_ram_size_bytes

Example alert rules

Adjust durations and exclude sleeping products according to the installation.

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:

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.

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.