Skip to content

Grafana and the Full Stack

Grafana reads the same SQLite database the service writes, through the community frser-sqlite-datasource plugin. No exporter and no separate time-series service sit in between.

The stack

examples/docker-compose-full-stack.yaml runs the service, Grafana, and the image renderer that Grafana needs for rendered panels:

version: "3"
services:
  solaredge2mqtt:
    container_name: solaredge2mqtt
    image: ghcr.io/deroetzi/solaredge2mqtt:latest
    volumes:
      - ./config:/app/config
      - ./cache:/app/cache
    environment:
      - TZ=Europe/Berlin
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    environment:
      GF_RENDERING_SERVER_URL: http://renderer:8081/render
      GF_RENDERING_CALLBACK_URL: http://grafana:3000/
      GF_INSTALL_PLUGINS: frser-sqlite-datasource
    ports:
      - "3000:3000"
    volumes:
      - "grafana:/var/lib/grafana"
      - "grafana.ini:/etc/grafana/grafana.ini"
      # Mounted read-write on purpose: SQLite has to create the -wal and -shm
      # sidecar files, a read-only mount of a WAL database cannot be opened.
      # Point the datasource at /app/config/solaredge2mqtt.db
      - "./config:/app/config"
    user: "1000:1000"
    restart: always
    networks:
      default:
  renderer:
    image: grafana/grafana-image-renderer:latest
    container_name: renderer
    environment:
      RENDERING_MODE: reusable
    user: "1000:1000"
    restart: always
    networks:
      default:

# Configuration is now managed via YAML files in ./config/
# See config/configuration.yml.example and config/secrets.yml.example for reference
# 
# For migration from environment variables or .env files:
# The service will automatically create YAML files on first run if they don't exist

The accompanying examples/grafana.ini sets the server URL for the container network and allows anonymous read access:

[server]
domain = grafana
root_url = http://grafana:3000

[auth.anonymous]
# enable anonymous access
enabled = true

# specify organization name that should be used for unauthenticated users
org_name = Main Org.

# specify role for unauthenticated users
org_role = Viewer

Download both next to your config/ directory:

curl -o docker-compose.yml \
    https://raw.githubusercontent.com/DerOetzi/solaredge2mqtt/master/examples/docker-compose-full-stack.yaml
curl -o grafana.ini \
    https://raw.githubusercontent.com/DerOetzi/solaredge2mqtt/master/examples/grafana.ini

docker compose up -d

Grafana is then on port 3000.

The database mount is read-write on purpose

SQLite runs in write-ahead-log mode and has to create the -wal and -shm sidecar files. A read-only mount of such a database cannot be opened at all, so Grafana gets the configuration directory read-write.

Wiring up the datasource

  1. In Grafana, add a datasource of type SQLite. The plugin is installed by the GF_INSTALL_PLUGINS variable in the compose file.
  2. Set the path to /app/config/solaredge2mqtt.db.
  3. Save and test.

Grafana runs as UID 1000 in this stack, matching the service, so it can open the file.

The dashboard

examples/grafana_dashboard_sqlite.json covers the headline panels in SQL. Import it through Dashboards, New, Import.

The older Flux dashboard for InfluxDB is kept in examples/legacy/ as a reference for porting the remaining panels. It does not work against SQLite.

Without containers

Nothing about this is Docker specific. Point any Grafana installation with the frser-sqlite-datasource plugin at the database file, and give the Grafana user read and write access to the directory holding it.