npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

signalk-grafana

v1.2.1

Published

Managed Grafana with auto-provisioned QuestDB dashboards for Signal K

Readme

signalk-grafana

Managed Grafana with auto-provisioned QuestDB and Signal K datasources for Signal K.

Runs Grafana in a container (via signalk-container), automatically connects it to signalk-questdb via a shared container network, and provisions both datasources.

Features

  • Zero-config Grafana -- container managed automatically, no manual setup
  • Auto-provisioned datasources -- QuestDB (PostgreSQL) and Signal K datasources configured automatically
  • Shared container network -- Grafana and QuestDB communicate on a private Podman/Docker network
  • Table auto-discovery -- QuestDB supports information_schema, Grafana query builder works
  • Anonymous access -- view dashboards without login (configurable)
  • Live reachability -- config panel shows whether Grafana can actually reach your Signal K server
  • One-click update -- check for new Grafana versions and update from the config panel
  • Password management -- set admin password from Signal K config panel
  • Config panel -- Grafana status with direct link, settings, all in Admin UI
  • Backup & restore integration -- exposes /api/full-export/{db,dashboards,provisioning} endpoints for signalk-backup to pull a consistent SQLite checkpoint plus dashboard JSONs and provisioning YAMLs. On plugin start, if a kopia restore left a staged grafana.db on disk but the live one is missing, it's automatically copied into place before Grafana starts -- dashboards and datasources come back without any manual step.

How It Works

  1. Plugin creates a Podman/Docker network (sk-network)
  2. Starts Grafana container on the network
  3. Auto-provisions QuestDB datasource (connects via container DNS sk-signalk-questdb:8812)
  4. Auto-provisions Signal K datasource (connects via host.containers.internal)
  5. Sets admin password on every startup to match config

QuestDB must also be on sk-network -- set Container network to sk-network in the QuestDB plugin config.

Example Queries

Create dashboards in Grafana using the QuestDB datasource with raw SQL. QuestDB uses SAMPLE BY for time bucketing:

Speed Over Ground (knots):

SELECT ts AS "time", avg(value) * 1.94384 AS "SOG"
FROM signalk
WHERE path = 'navigation.speedOverGround'
  AND context = 'self'
  AND ts >= $__timeFrom() AND ts <= $__timeTo()
SAMPLE BY 10s

Wind Speed and Angle:

SELECT ts AS "time",
  avg(value) * 1.94384 AS "AWS"
FROM signalk
WHERE path = 'environment.wind.speedApparent'
  AND context = 'self'
  AND ts >= $__timeFrom() AND ts <= $__timeTo()
SAMPLE BY 10s

Battery Voltage:

SELECT ts AS "time", avg(value) AS "Voltage"
FROM signalk
WHERE path LIKE 'electrical.batteries.%.voltage'
  AND context = 'self'
  AND ts >= $__timeFrom() AND ts <= $__timeTo()
SAMPLE BY 10s

Engine RPM (rev/s to RPM):

SELECT ts AS "time", avg(value) * 60 AS "RPM"
FROM signalk
WHERE path LIKE 'propulsion.%.revolutions'
  AND context = 'self'
  AND ts >= $__timeFrom() AND ts <= $__timeTo()
SAMPLE BY 10s

Temperature (Kelvin to Celsius):

SELECT ts AS "time", avg(value) - 273.15 AS "Temp"
FROM signalk
WHERE path = 'environment.water.temperature'
  AND context = 'self'
  AND ts >= $__timeFrom() AND ts <= $__timeTo()
SAMPLE BY 10s

Unit Conversions

Signal K stores values in SI units. Common conversions for Grafana:

| Conversion | Formula | | ------------------ | --------------------- | | m/s to knots | value * 1.94384 | | radians to degrees | value * 57.2958 | | Kelvin to Celsius | value - 273.15 | | Pascals to hPa | value / 100 | | rev/s to RPM | value * 60 | | Pascals to PSI | value * 0.000145038 |

Grafana Macros

Use these Grafana PostgreSQL macros in your queries:

| Macro | Expands to | | --------------- | ---------------------------- | | $__timeFrom() | Start of selected time range | | $__timeTo() | End of selected time range |

QuestDB's SAMPLE BY handles time bucketing (e.g., SAMPLE BY 10s, SAMPLE BY 1m, SAMPLE BY 1h).

Configuration

| Setting | Default | Description | | --------------------- | ----------------- | ------------------------------------------------------------ | | Grafana port | 3001 | Host port for Grafana UI | | Image version | latest | Grafana Docker image tag | | Admin password | admin | Grafana admin password (applied on every start) | | Anonymous access | true | Allow viewing without login | | Signal K URL override | auto | Auto-detected; set to override (use http:// or https://) | | QuestDB container | signalk-questdb | Container name (without sk- prefix) | | PostgreSQL port | 8812 | QuestDB PG wire port | | Network name | sk-network | Shared container network name | | Bind to 0.0.0.0 | false | Expose Grafana outside localhost | | Sub-path | empty | Set to /grafana/ when running behind a reverse proxy | | Auto-request token | true | On secured Signal K servers, request a device-access token |

Secured Signal K servers

When Signal K security is enabled, the plugin drives the standard SK device-access-request flow on startup so the Grafana Signal K datasource can read paths and history from the secured server.

  1. Plugin POSTs /signalk/v1/access/requests with clientId: signalk-grafana, permissions: readwrite.
  2. Plugin status shows Awaiting Signal K token approval — see Security → Access Requests.
  3. Approve in Signal K Admin → Security → Access Requests.
  4. The plugin caches the JWT to ${dataDir}/signalk-token (mode 0600), injects it into the Grafana datasource provisioning, and recreates the Grafana container so the new credentials take effect.

Disable with requestSignalkToken: false if you prefer to paste a token into the Grafana datasource UI manually.

What works and what doesn't on secured SK

| Use case | Works on secured SK? | | ---------------------------------------------------------------------------------- | -------------------- | | Explore → Signal K → pick a path | ✅ | | Historical range queries (from/to are explicit times, or now-1h to now-1m) | ✅ | | /api/health and datasource Test button | ✅ | | Live-updating panels (range now-X to now that streams values in real time) | ❌ |

The live-update gap is in the upstream tkurki-signalk-datasource plugin: it opens its WebSocket from the browser where Grafana's secret store is not accessible by design, so the upgrade request goes out without an Authorization header and Signal K rejects it. HTTP queries are unaffected because Grafana's datasource proxy injects the bearer token server-side for those. Tracked at tkurki/signalk-grafana-datasource#12 — until that lands, use the QuestDB datasource for live-updating panels (the intended architecture: SK → questdb → Grafana, with the SK datasource reserved for ad-hoc Explore and historical queries).

Requirements

  • Node.js >= 22.16 (needs node:sqlite backup() for the SQLite checkpoint endpoint)
  • signalk-container plugin
  • signalk-questdb plugin (with network set to sk-network)
  • Signal K server

License

MIT