Skip to content

Plugin/integration ecosystem — phased (driver SDK → drop-in plugins → signed marketplace) #25

Description

@ritualnorth

Goal

Turn WattPost into an open-source ecosystem where people can add their own device support (inverters, chargers, BMSes, plugs, sensors) — and eventually discover/install community plugins from the dashboard — without compromising the safety of an appliance that drives real power hardware.

What Home Assistant does, and the one lesson that matters

HA runs a two-tier model, and the marketplace is deliberately not theirs:

  • Core integrations (~3,000) — in the main repo, code-reviewed, shipped with releases, held to an Integration Quality Scale. The curated, trusted set.
  • Custom integrations — anyone drops a Python folder + manifest.json into custom_components/. HA explicitly does not review, audit, or support these. Install at your own risk.
  • HACS ("the marketplace") is community-run, not official — itself a custom integration that indexes/installs from GitHub. HA kept the official store curated and let the community own the long tail.

Primitives: a manifest.json per integration, a config-flow UI for setup (no YAML), and a standard entity interface so everything plugs into one UI + automation engine.

The lesson: HA custom components run fully unsandboxed, same privileges as core — and that has produced real CVEs. For a hobby box that's tolerable. WattPost drives chargers, relays, and BLE — a malicious or merely buggy plugin is a physical/fire risk or a LAN pivot. So we cannot copy "run anything, your risk." Doing better here is a brand differentiator, not just a chore.

We already have the HA-core equivalent

The vendors/ layer is basically HA-core's in-repo integration model already:

  • vendors/registry.pyregister_vendor(info, drivers={device_kind: factory})
  • vendors/base.pyDeviceDriver(abc.ABC) with a stable vendor_id / device_kind, a sections Modbus read-list (or override poll(transport) for non-Modbus), normalized output, and writable_settings() for a vetted control surface
  • VendorInfo(id, display_name, description) — the manifest seed
  • Transport abstraction (Modbus/BLE/…)
  • ~18 vendors shipped (victron, renogy, jbd, jkbms, daly, deye, eg4, epever, voltronic, govee, ruuvi, mopeka, …)

So this epic is mostly about formalising, documenting, opening, and securing what's already there — not a rewrite.

Phased plan (order matters)

Phase 1 — formalise the in-repo driver SDK (do this at open-source launch, ties to #16)

The "send a PR to add your device" path. Lowest infra, highest trust.

  • Promote VendorInfo into a real manifest: add version, author, min_appliance_version, requirements (pip deps), capabilities (see below), iot_class-style hint (local-polled / local-push / cloud).
  • Publish the DeviceDriver + Transport + Section + WritableSetting contract as a documented SDK (docs/extending/driver-sdk.md) with a worked example driver.
  • CONTRIBUTING.md for drivers + a quality bar (normalized keys, no blocking I/O, read-only unless writable_settings ranges are audited — mirrors the existing "Victron stays read-only" rule).
  • A driver conformance test harness (extends the current pytest suite, ties to Establish a test + CI safety net (phased) #20).

Phase 2 — out-of-tree drop-in plugins (no fork)

Today a vendor must live in solar_monitor/vendors/ and be imported. Add discovery so third parties ship their own package:

  • Python entry_points (group wattpost.drivers) auto-discovered at boot, each calling register_vendor(). Optional plugins/ drop-in dir for non-packaged drops.
  • Capability manifest + consent: the plugin declares what it needs — bus:modbus, ble, lan-http, cloud-egress, control:relay, control:charger, fs-write. WattPost surfaces these at install ("this plugin can control your charger — allow?"). This is where we beat HA — capability-scoped + consent-gated because the hardware matters.
  • Enforce capabilities at runtime where feasible (deny egress / control a plugin didn't request).

Phase 3 — signed marketplace (HACS-style), last not first

  • GitHub-backed index of plugins, install/update from the dashboard UI, tagged-release selection.
  • Signing: reuse the existing Ed25519 licensing infra to sign vetted plugins; verify signature + capability manifest before load.
  • Keep HA's hard-won split: a verified tier we sign + a community tier clearly marked "unverified, at your own risk." Don't pretend to audit the long tail.

The sequencing trap to avoid

Don't build the marketplace first. HA had thousands of integrations before HACS existed — HACS just indexed what was already there. SDK → community plugins → marketplace. A marketplace with nothing in it and no stable SDK is wasted effort.

Security model (the differentiator) — needs sign-off, ties to #28

  • Capability declaration + install-time consent + runtime enforcement.
  • Signing + verified/community tiers.
  • Open question: in-process Python drivers (powerful, risky — current model) vs container/subprocess-isolated plugins (safer, heavier) vs both. For a Pi appliance, in-process is the natural fit for v1; isolation may be warranted specifically for control:charger/control:relay capabilities.
  • Hard rule to keep: control surfaces (writable_settings, relay/charger drive) stay opt-in + range-audited, never default-on for a community plugin.

Open questions

  1. Drivers/integrations only, or also "automations/cards" (HA's other extension axes)?
  2. Where does the cloud fit — do plugins get a cloud-side half, or appliance-only for v1?
  3. Marketplace hosting: a static GitHub-backed index (cheap) vs a cloud service (richer, more infra).
  4. Trademark/brand policy for third-party plugins before we publicise.

Suggested first step

Phase 1 only: write docs/extending/driver-sdk.md + extend VendorInfo into a manifest with capabilities, against the existing vendors/ layout. Everything else can follow once there are external contributors.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions