Skip to content

Latest commit

 

History

1,402 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SPAN Panel Integration for Home Assistant

Home Assistant Integration for SPAN Panel, a smart electrical panel that provides circuit-level monitoring and control of your home's electrical system.

hacs_badge GitHub Release GitHub Activity License

Python Ruff Mypy prettier prek

The software is provided as-is with no warranty or guarantee of performance or suitability to your particular setting.

IMPORTANT: This integration controls real electrical equipment. Circuit switches open and close physical relays. The GFE override button changes how the panel manages load shedding during power outages. These actions carry the same consequences as operating the panel manually — because they are. Automations can execute these actions without user presence; design them with the same care you would apply to any unattended electrical control. This integration is not a safety device and must not be relied upon for life-safety applications. Use this software at your own risk. If you cannot accept that risk, do not use this software. See LICENSE for the full warranty disclaimer.

The SPAN Client documentation has warnings regarding the use of the API (the API used by this integration) which should be heeded just as if you were using that API directly:

An API client that attempts to implement its own load-shedding decisions, grid-state detection, or other critical automation is operating outside the scope of what SPAN API was designed and engineered for. Such use is entirely at the client developer's and homeowner's own risk and may void the SPAN Panel Limited Warranty. See the SPAN API Scope & Responsibility Model in the SPAN API documentation.

This integration provides sensors and controls for understanding an installation's power consumption, energy usage, and controlling user-manageable panel circuits.

The integration includes a built-in dashboard accessible from the Home Assistant sidebar, providing real-time circuit-level power visualization, current monitoring with configurable alerts, and circuit settings for relays and load shedding. See Frontend Dashboard for details. You can optionally use the span-card Lovelace card for visualization and switch control.

The SPAN Panel PanelBench HA App lets you clone your panel's circuit layout for testing, or model an upgrade to evaluate firmware or integration changes in a sandbox before applying them to your real panel.

This integration communicates with the SPAN Panel over your local network using SPAN's official Electrification Bus (eBus) framework — an open, multi-vendor integration standard for home energy infrastructure. eBus uses the Homie Convention for MQTT topics and messages, with the panel's built-in MQTT broker delivering real-time state updates without polling.

Prerequisites

  • Home Assistant installed
  • HACS installed
  • SPAN Panel with firmware spanos2/r202603/05 or later
  • Panel passphrase (found via the SPAN app) or physical access to the panel door

Installation

  1. Install HACS
  2. Go to HACS in the left side bar of your Home Assistant installation
  3. Search for "Span"
  4. Open the repository and click "Download"
  5. Restart Home Assistant (you will be prompted by a repair notification)
  6. Go to Settings > Devices & Services
  7. Click + Add Integration and search for "Span"
  8. Pick your panel from the discovered list, or enter its IP address or .local name (both shown in the mobile app)
  9. The integration detects the panel as v2 and presents an authentication choice:
    • Enter Panel Passphrase — type the passphrase found in the SPAN mobile app under On-premise settings
    • Proof of Proximity — open and close the panel door 3 times, then click Submit
  10. Choose your entity ID naming pattern (see naming patterns below)
  11. Optionally adjust the snapshot update interval — 0 is real-time, up to 15 seconds based on CPU

If you encounter issues, restore from your backup or check the troubleshooting section below.

Key Terms

The following terms appear throughout this document and in the integration's sensors:

  • Grid-forming entity (GFE) — The power source that sets the voltage and frequency reference for the home. When the utility grid is up, it is the GFE. When islanded on battery, the battery inverter becomes the GFE.
  • Islanded — The home is electrically disconnected from the utility grid and running on its own power source, typically battery. Circuits may be shed to conserve battery life.
  • Microgrid — When the home is islanded, the battery inverter creates a small, self-contained electrical grid for the home. This local grid functions independently of the utility — the inverter generates AC power at the correct voltage and frequency, and the home's circuits run on it just as they would on utility power.
  • Microgrid Interconnect Device (MID) — A switch, part of or alongside the battery system, that disconnects the home from the utility grid during an outage. While open, the panel's sensors can only see the home side.
  • Shedding — Automatically turning off lower-priority circuits to conserve battery during an outage, based on each circuit's configured shed priority.

Entity Reference

Panel-Level Sensors

Sensor Device Class Unit Notes
Current Power Power W Total panel power (grid import/export)
Feed Through Power Power W Feedthrough (non-breaker) power
Main Meter Produced Energy Energy Wh Grid energy exported
Main Meter Consumed Energy Energy Wh Grid energy imported
Main Meter Net Energy Energy Wh Consumed minus produced
Feed Through Produced Energy Energy Wh Feedthrough energy exported
Feed Through Consumed Energy Energy Wh Feedthrough energy imported
Feed Through Net Energy Energy Wh Feedthrough net energy
DSM State dsm_on_grid (grid connected), dsm_off_grid (islanded), unknown. Derived from multiple eBus signals
Current Run Config panel_on_grid (grid connected), panel_off_grid (islanded on PV/generator), panel_backup (islanded on battery), unknown
Grid Forming Entity GRID, BATTERY, PV, GENERATOR, NONE, UNKNOWN. SeeGrid Forming Entity
Main Relay State closed (power flowing), open (disconnected), unknown
Vendor Cloud CONNECTED, UNCONNECTED, UNKNOWN
Software Version Firmware version string

Panel Diagnostic Sensors

Sensor Device Class Unit Notes
L1 Voltage Voltage V L1 leg actual voltage
L2 Voltage Voltage V L2 leg actual voltage
Upstream L1 Current Current A Upstream lugs L1 current
Upstream L2 Current Current A Upstream lugs L2 current
Downstream L1 Current Current A Downstream lugs L1 current. Off by default from 2.1.x — see below
Downstream L2 Current Current A Downstream lugs L2 current. Off by default from 2.1.x — see below
Main Breaker Rating Current A Main breaker amperage. Off by default

L1/L2 Voltage and Main Breaker Rating have always been off by default; enable them from the panel's device page if you want them.

The three Feedthrough sensors and the two Downstream current sensors are off by default from 2.1.x. The eBus specification's maintainer has documented that the panel's feedthrough (downstream lugs) figures cannot be relied on: the energy registers can decrease or go negative, the power reading is inverted relative to every other terminal, and the downstream currents report the upstream service conductors. The defects predate r202633.

Existing installations keep all five, with their history and entity ids — Home Assistant applies the setting only when an entity is first created. If you use them somewhere, removing them is worth considering, but that is your call.

Shed Forecast Sensors

Created only when your panel publishes the shed-forecast capability, and only for the estimates it actually publishes.

Sensor Device Class Unit Notes
Time to Priority Shed Duration min Estimated time before the next priority tier of circuits is shed
Backup Time Remaining Duration min Estimated time before every sheddable circuit is shed (off-grid)

Shed Forecast Sensor Attributes

Present only when the panel publishes them.

Attribute Type On Notes
full_charge_time_to_priority_shed int Time to Priority Shed The same estimate assuming the battery starts full
full_charge_total_time_remaining int Backup Time Remaining The same estimate assuming the battery starts full
forecast_confidence string both The panel's own assessment:LOW, MEDIUM, or HIGH

Power Control System Sensors

Created only when your panel publishes the pcs capability, and created whether or not the PCS is switched on — a PCS reporting a limit of 0 A is reporting a state, not an absence.

Sensor Device Class Unit Notes
Import Limit Current A The limit actually being enforced: the most restrictive active constraint (diagnostic)
Binding Constraint Enum Which constraint sets that limit: Firm Service Rating, Grid Envelope, Voltage Support, Off-Grid, Requested, Operator, None

Power Control System Sensor Attributes

On Import Limit, and present only when the panel publishes them. These are the inputs the panel reconciled to produce the enforced limit above.

Attribute Type Notes
pcs_enabled bool Whether the panel's PCS is enabled at all
feed_import_limit float The Firm Service Rating: the commissioned, always-on floor (A)
operator_import_limit float A cap imposed by a fleet or aggregator operator (A)
off_grid_import_limit float The import cap while islanded (A)
requested_import_limit float A voluntary limit requested by the owner or installer (A)
<name>_enablement string Per limit:UNSPECIFIED, UNCONFIGURED, DISABLED, ENABLED
<name>_active bool Per limit: whether that constraint is currently enforcing

Power Flow Sensors

Sensor Device Class Unit Notes
Grid Power Power W Grid power flow
Site Power Power W Total site power (grid + PV + battery)
Battery Power Power W Battery charge/discharge (+discharging, −charging). Only when BESS commissioned
PV Power Power W PV generation (+producing). Only when PV commissioned

PV Metadata Sensors (on the Solar sub-device)

From 2.1.x these live on a Solar device of their own rather than on the panel's card, alongside PV Power and PV Panel Link.

Sensor Device Class Unit Notes
PV Vendor PV inverter vendor (e.g., "Enphase", "Other")
PV Product PV inverter product (e.g., "IQ8+")
Nameplate Capacity Power kW Rated inverter capacity. Off by default

If you upgraded, these keep their entity ids, unique ids and history — but not the panel's area, since an entity takes its area from its device and the Solar device starts without one. Assign it an area, or anything area-scoped (dashboards, automations, voice targeting a room) stops matching them. New installations get ids from the new device name — sensor.span_panel_solar_pv_vendor rather than sensor.span_panel_pv_vendor. Both are correct and neither changes again.

Deprecated:

Sensor Reason
DSM Grid State Deprecated — still available, but users should rely onDSM State as DSM Grid State may be removed in a future version

Microgrid Interconnect Device

Your panel publishes its Microgrid Interconnect Device — the switch that disconnects your home from the utility during an outage — as a device of its own, linked to the panel. It appears automatically where the panel reports one; nothing existing moves onto it.

Sensor Device Class Unit Notes
Grid State Enum Health of the utility supply itself:up, down, degraded or unknown

This is new information — the previous firmware did not report the utility supply at all. It is not DSM Grid State, which is whether your home is islanded: the grid can be down while your home runs happily off the battery.

A panel with no battery has no MID, and that is itself an answer. The specification makes backup capability structural — having a MID is what says a panel can island — so Grid Islandable reads Off and Grid Forming Entity reads Grid rather than either going unavailable.

DSM Grid State keeps its entity id and history but is no longer inferred from the battery or the dominant power source; it now reads the islanding state the MID actually senses.

Power Sensor Attributes

Applies to Current Power, Feed Through Power, Battery Power, PV Power, Grid Power, and Site Power sensors.

Attribute Type Notes
voltage string Nominal panel voltage ("240")
amperage string Calculated current (power / voltage)

Grid Power carries one more, because its name is only true in some wiring:

Attribute Type Notes
at_service_entrance boolean Whether this panel's upstream lugs are where the utility actually connects

Grid Power reads the upstream lugs. That is grid flow when those lugs are the utility connection point, which is the ordinary case. Put a battery between the utility and your main lugs, or feed this panel from another panel, and the same reading becomes this panel's supply while Grid Power Flow stays the whole-site figure — so the two legitimately disagree. When at_service_entrance is false, use Grid Power Flow for site-level grid import and export.

Software Version Sensor Attributes

Attribute Type Notes
panel_size int Total breaker spaces (e.g., 32, 40)

wifi_ssid used to appear here. It moved to the Wi-Fi Link binary sensor below; a template reading it from this sensor should be pointed there.

Wi-Fi Link Binary Sensor Attributes

Attribute Type Notes
wifi_ssid string Network this link is to. Absent when the panel publishes no SSID

EVSE (EV Charger) Entities

Created automatically when a SPAN Drive or other EVSE is commissioned on the panel. Each EVSE appears as a separate sub-device linked to the panel via via_device. Vendor, product, serial number, and software version are surfaced as device info attributes — not separate entities.

EVSE Device Naming

The EVSE device name includes the panel device name prefix for collision avoidance across multi-panel installations and to support HA's bulk device rename feature. A display suffix differentiates multiple chargers on the same panel:

  • Friendly names (USE_CIRCUIT_NUMBERS=False): suffix is the fed circuit's panel name (e.g., "Garage")
  • Circuit numbers (USE_CIRCUIT_NUMBERS=True): suffix is the EVSE serial number (e.g., "SN-EVSE-001")
  • No suffix available: the display suffix is omitted entirely (no empty parentheses)
Naming Mode Example Device Name Example Entity ID
Friendly names Main House SPAN Drive (Garage) sensor.main_house_span_drive_garage_charger_status
Circuit numbers Main House SPAN Drive (SN-EVSE-001) sensor.main_house_span_drive_sn_evse_001_charger_status
No suffix Main House SPAN Drive sensor.main_house_span_drive_charger_status

The circuit that feeds a charger has its sensors shown on the charger's device. Their entity IDs name the charger alone — sensor.main_house_span_drive_garage_power — matching the charger's other sensors. A feed sensor you already have keeps its current id until you press Recreate entity IDs, which offers the charger-named one.

EVSE Sensors (per charger)

Sensor Device Class Unit Notes
Charger Status Enum OCPP-based states: AVAILABLE, PREPARING, CHARGING, SUSPENDED_EV, etc. Translated
Advertised Current Current A Amps offered to the vehicle
Lock State Enum LOCKED, UNLOCKED, UNKNOWN. Translated
Part Number Charger part number (diagnostic,off by default)

EVSE Binary Sensors (per charger)

Sensor Device Class Notes
Charging Battery Charging ON when status is CHARGING
EV Connected Plug ON when status is PREPARING, CHARGING, SUSPENDED_*, or FINISHING — a vehicle is plugged in
EVSE Panel Link Connectivity Whether the panel can reach the charger. A different fact from EV Connected, and it can disagree

EVSE Panel Link is not EV Connected. EV Connected is what the charger says about the cable in front of it; EVSE Panel Link is what the panel says about whether it can reach the charger at all. A charger part-way through a session behind a lost link reports a plugged-in vehicle and a dead link at the same time. EVSE Panel Link is a diagnostic and appears only where the circuit feeding that charger publishes the link record.

EVSE Controls (per charger)

Control Platform Unit Notes
EVSE Charge Current Limit Number A The charge-current ceiling you can lower. Bounded by the installer-commissioned maximum

The maximum is read from the panel, never assumed: it is the current the charger was commissioned for, and a value above it is refused rather than clamped. The control is created only where the panel declares the limit settable, and reports unavailable while the panel has not published the commissioned maximum that bounds it. A change the panel has acknowledged but not yet applied appears as a charge_current_limit_target attribute while the state stays the limit the charger is still enforcing.

EVSE Device Info Attributes

Attribute Source
Manufacturer vendor-name
Model product-name
Serial Number serial-number
Software Version software-version

BESS Sub-Device (conditional)

When a Battery Energy Storage System (BESS) is commissioned, the integration creates a separate BESS sub-device linked to the panel via via_device. The BESS device uses manufacturer, model, serial number, and software version from battery metadata as device info attributes.

BESS Sensors

Sensor Device Class Unit Notes
Battery Level Battery % State of energy as percentage
Battery Power Power W Same entity as Power Flow Battery Power, shown on BESS sub-device
Meter Power Power W The BESS's own meter (+discharging, −charging), agreeing with Battery Power
Communication State The BESS's report of its own link health (diagnostic, disabled by default)
BESS Vendor Battery system vendor (diagnostic)
BESS Model Battery system model (diagnostic)
BESS Part Number Battery system part number (diagnostic,off by default)
BESS Serial Number Battery system serial number (diagnostic)
BESS Firmware Battery system firmware (diagnostic)
Nameplate Capacity Energy Storage kWh Rated battery capacity (diagnostic,off by default)
Stored Energy Energy Storage kWh Current stored energy (diagnostic)

BESS Binary Sensors

Sensor Device Class Notes
BESS Connected Connectivity Whether the BESS is communicating with panel

Panel Energy Sensor Attributes

Applies to Main Meter and Feed Through energy sensors.

Attribute Type Notes
voltage string Nominal panel voltage ("240")

Circuit-Level Sensors (per circuit)

Sensor Device Class Unit Notes
Power Power W Instantaneous circuit power (+producing for PV, +consuming otherwise)
Produced Energy Energy Wh Cumulative energy produced
Consumed Energy Energy Wh Cumulative energy consumed
Net Energy Energy Wh Net energy (sign depends on device type — PV circuits invert)
Current Current A Measured circuit current. Only when panel reportscurrent_a
Breaker Rating Current A Circuit breaker amperage (diagnostic). Only when reported

Circuit Power Sensor Attributes

Attribute Type Notes
tabs string Breaker slot position(s)
voltage string 120 or 240 (derived from tab count)
always_on bool Whether circuit is always-on
relay_state string OPEN / CLOSED / UNKNOWN
relay_requester string Who requested relay state
shed_priority string API value: NEVER / SOC_THRESHOLD / OFF_GRID / UNKNOWN
is_sheddable bool Whether circuit can be shed
pcs_managed bool Whether the panel's Power Control System manages this circuit. Present only when the circuit reports it
pcs_priority int This circuit's shed order under an active import limit — distinct fromshed_priority, which is the backup tier

Circuit Energy Sensor Attributes

Attribute Type Notes
tabs string Breaker slot position(s)
voltage string 120 or 240 (derived from tab count)

Binary Sensors

Sensor Device Class Notes
Door State Tamper Panel door open/closed
Ethernet Link Connectivity Wired network status
Wi-Fi Link Connectivity Wireless network status
Panel Status Connectivity Overall panel online/offline
Grid Islandable Whether the panel can island from the grid. Off on a panel with no MID — see below
PCS Active Running Whether the Power Control System is limiting import right now. Only when the panel runs one
PV Panel Link Connectivity Whether the panel can reach the solar inverter. Only when the feeding circuit reports it

Removed from binary sensors:

Sensor Reason
Cellular (wwan) Replaced byVendor Cloud sensor (cloud connectivity)

Circuit Controls (per user-controllable circuit)

Entity Type Notes
Breaker Switch On/off relay control
Circuit Priority Select Controls when the circuit is shed during off-grid (translated, see below)

Panel Controls

Entity Type Notes
GFE Override: Grid Connected Button Tell the panel the grid is up when BESS communication interrupted

Adopted Devices and Readings

The eBus schema is vendor-extensible, so your panel can publish a device type this integration has never modeled. Rather than ignoring it, the integration gives it a card of its own hanging off the panel, carrying whatever identity it publishes, with its readings as entities beneath it.

Everything adopted arrives disabled and filed under Diagnostics until you promote it from the dashboard Adopted tab; the new-entity notification names the device so you can find it. A property the device accepts writes to becomes a control rather than a reading — a boolean becomes a switch, an enumeration becomes a select, a number becomes a number entity — and those arrive switched off too.

Three things worth knowing before you build on one:

  • Nothing adopted enters long-term statistics until you say it should. Adopted entities arrive with no statistics class, because the correct one is not published on the wire. You are welcome to supply it in the Adopted tab.

  • A new property on a device this integration already models is adopted too, but as a reading on that device's existing card rather than as a device of its own.

  • What the delete button does, since it is not quite what you would expect:

    • Delete a reading while your panel is still publishing that property and it comes back — switched off — at the next reload, carrying whatever you curated for it. Curation is keyed on the wire address rather than on the entity, so deleting the entity does not discard it. There is no setting to suppress the entity, because leaving it switched off is already that.
    • Delete one after your panel has stopped publishing it and it stays gone, because nothing exists to recreate it from.

So deletion means "hide it until next time" for a live reading and "clear it out" for a dead one, and your panel decides which.

These entities are permanent in id, not in identity. If one of these readings is later modeled properly (delivered as an official part of the integration), that entity is a new entity with its own id and its own history — the adopted one is not renamed into it. That is why a vendor reading you have come to depend on is worth raising in an issue: being modeled is what turns it into something with a real name, a proper category and statistics out of the box.

The Adopted Tab

The integration will not guess what an adopted reading means. You are not guessing — it is your device — so the built-in dashboard has an Adopted tab where you can tell the integration about the reading.

A row that arrived as a control rather than a reading — a switch, a select or a number box — offers prominence alone, because a device class and a statistics class both describe a value being read.

You are only offered choices your panel's own declaration allows. A statistics class is offered only on a reading whose declared datatype is numeric; the device classes listed are the ones that fit both what the panel says the reading is and the unit it publishes, so a text reading is never offered a class that expects a number, and the unit itself stays whatever the publisher sends.

Saving reloads the integration, and setting or clearing a statistics class asks you to confirm before it does.

Two consequences are what that confirmation is about:

  • total_increasing tells Home Assistant the reading is a meter that only counts up. The recorder treats a drop of more than a tenth as the meter being reset and starts a new cycle, so choosing it for a reading that legitimately falls will manufacture consumption that never happened. Choose it only for a genuine lifetime total.
  • Removing a statistics class stops statistics, and Home Assistant will say so. If an entity already has statistics and then loses its statistics class, Home Assistant raises a repair notice against it — a warning rather than something with a fix button — and stops compiling new statistics for it. The statistics already collected are not deleted, and the notice clears by itself if you put a statistics class back.

BESS & Grid Management

This section explains how the SPAN panel manages power sources and load shedding when a Battery Energy Storage System (BESS) is installed, and what the integration can and cannot tell you about grid status.

Grid Forming Entity

The Grid Forming Entity (GFE) sensor identifies which power source provides the voltage and frequency reference for the home — not which source is producing the most watts. When GFE is Grid, the utility grid sets the reference and all circuits remain on, even if 100% of consumption comes from solar. When GFE is Battery, the battery inverter is the reference and circuits are shed based on each circuit's configured shed priority.

GFE Value Meaning
GRID Panel is grid-connected (includes generator power, see deep dive)
BATTERY Panel is islanded, running on battery
PV Panel is islanded, running on solar (future)
GENERATOR Panel is islanded, running on generator (future)
NONE Panel is islanded with no power source
UNKNOWN State not yet determined or fault condition

When a BESS is installed, the panel relies on the BESS to determine whether the grid is online and to set the GFE accordingly. If BESS communication is lost while the panel is islanded, the GFE value becomes stale — it may show Battery when the grid has actually been restored, causing unnecessary shedding to continue.

On a panel with no battery, GFE is Grid, on both firmware generations. The newer firmware moves this value onto the Microgrid Interconnect Device, which is part of a battery system — so a panel without one has nothing publishing it. The answer is still settled, by what cannot be there: Battery needs a BESS (which brings a MID), PV cannot form a grid on its own (anything that can is a grid-forming inverter, which is a MID), and None describes a panel supplying nothing, which is a panel that is not reporting at all. What remains is a generator, and SPAN with no generator interface treats one as the grid. So Grid is what a battery-less panel reports, which is what the older firmware reported too.

What the Panel Can Detect

Grid loss — The panel independently detects grid loss via its own voltage monitoring, even if BESS communication is already lost. The MID is still closed at this point, so the panel's sensors see the real voltage drop and respond immediately.

Grid restoration while islanded — Not detectable by the panel. While the MID is open, the panel's sensors are on the home side and measure only battery-supplied power. Grid restoration on the utility side of the open MID is invisible to any panel-side measurement. This is a physical limitation, not a software gap. A utility-side sensor — such as a current clamp (e.g., Emporia Vue), ATS/MTS contact closure, or any device that can see the grid side of the MID — integrated into Home Assistant as a binary sensor can provide this signal.

DSM State Sensor

The integration's DSM State sensor combines multiple panel signals to provide defense-in-depth for grid status detection. It corroborates the Grid Forming Entity with BESS grid state and power measurements, which adds confidence during transient inconsistencies and detects some edge cases — for example, when BESS communication is lost while on-grid and the grid subsequently drops, the panel self-corrects via voltage detection and the corroborating signals confirm it.

However, when the panel is islanded and the MID is open, all of the panel's signals measure the home side. No combination of panel-sourced data can detect grid restoration in this state. Only an external signal (utility-side sensor) or manual confirmation via the GFE Override button can resolve it.

GFE Override Button

The GFE Override: Grid Connected button tells the panel that the grid is back and shedding can stop. When the BESS restores communication, it automatically reclaims control and the override is superseded — no manual undo is needed.

Risk asymmetry — Telling the panel to shed (conservative direction) is low-risk; worst case is unnecessary circuit disruption. Telling the panel the grid is back when it is not means unmanaged battery drain and reduced runtime, which could affect critical equipment. The battery protects itself by disconnecting when depleted, so there is no overload risk, but runtime will be reduced. Use the override button only with confidence that the grid has actually been restored — via a utility-side sensor or manual confirmation.

WARNING — Do not automate the GFE override button based on DSM State — it inherits the same MID blind spot described above and will read dsm_off_grid even after the grid is restored. Manual confirmation or an external sensor is required before pressing the button.

When bess_connected returns to on, no action is needed — firmware resumes normal GFE management automatically.

For a detailed discussion of failure scenarios, the MID topology, generator and non-integrated BESS behavior, and /set risk analysis, see BESS & Grid Management Deep Dive.

Configuration Options

Snapshot Update Interval

Controls how often the integration rebuilds the panel snapshot from incoming MQTT data. The SPAN panel publishes high-frequency MQTT messages (~100/second), but each individual message is a cheap dictionary write. The expensive operation — rebuilding the full snapshot and dispatching entity updates — is rate-limited by this timer.

  • Default: 1 second
  • Range: 0–15 seconds
  • Set to 0 for no debounce (every MQTT message triggers a snapshot rebuild)
  • Increase on low-power hardware (e.g., Raspberry Pi) to reduce CPU usage

Configure via Settings > Devices & Services > SPAN Panel > Configure > General Options.

Entity Naming Pattern

The integration provides flexible entity naming patterns, configured during initial setup:

  1. Friendly Names (Recommended for new installations)

    • Entity IDs use descriptive circuit names from your SPAN panel
    • Example: sensor.span_panel_kitchen_outlets_power
    • Renaming a circuit in the SPAN app updates the displayed name automatically — the integration reloads itself to pick the new name up, since it travels as the entity's original name and only a rebuild refreshes it; the entity ID changes only if you accept the offer from Recreate entity IDs
    • More intuitive for automations and scripts
  2. Circuit Numbers (Stable entity IDs)

    • Entity IDs use generic circuit numbers
    • Example: sensor.span_panel_circuit_15_power
    • Entity IDs stay stable when circuits are renamed
    • Friendly names still sync from SPAN panel for display

The integration supplies only the circuit half of the ID shown above — Kitchen Outlets Power or Circuit 15 Power. Home Assistant composes the rest from your own entity ID settings (entity_id_parts, Home Assistant 2026.8 and newer), which decide whether the device name and the area are prefixed.

For an entity that already exists, the suffix wording in that half is read back from the ID the entity has rather than reworded. Circuit energy IDs have shipped in two spellings — consumed_energy and energy_consumed — so an installation is offered whichever one it is already using, and never the other; only new sensors get the consumed_energy word order that the panel-level sensors use. Because your entity ID settings decide the rest of the ID, an installation whose circuits were named before those settings existed — a SPAN Drive feed circuit, a second panel, or an installation predating the device prefix — may be offered an ID with a different device half. Entities you already have keep the IDs they have until you press Recreate entity IDs and accept the offer.

Energy Dip Compensation

SPAN panels occasionally report lower energy readings for cumulative energy sensors after firmware updates or resets. Home Assistant's statistics engine interprets any decrease as a counter reset, creating negative spikes in the energy dashboard.

When enabled, the integration automatically detects these dips and maintains a cumulative offset per sensor so Home Assistant always sees a monotonically increasing value.

  • Default for new installs: ON
  • Default for existing installs: OFF (enable via General Options)
  • Threshold: 1.0 Wh minimum to avoid false triggers from float precision noise
  • Disabling: Clears all accumulated offsets (starts fresh if re-enabled)

A dip is compensated as soon as it is seen, but not believed straight away. A counter reset is permanent — the counter restarts low and counts up from there — so a reading that drops and then returns to where it was is a transport artifact rather than a reset, and its offset is taken back. The offset stays provisional until a later reading either disproves it (the counter comes back) or corroborates it (the counter climbs from the new, lower base).

The persistent notification therefore lists a dip once it settles — when that window closes — and a dip that is disproved produces no notification at all — the sensor was compensated the whole time and nothing needs your attention. Reporting on corroboration alone left a notice standing for an event the next reading undid, which a persistent notification cannot take back the way the offset can. Seeing no notification after a momentary dip is the feature working, not failing.

Diagnostic attributes (visible when compensation is active):

Attribute Description
energy_offset Cumulative Wh compensation applied (when > 0)
last_dip_delta Size of the most recent dip in Wh

Configure via Settings > Devices & Services > SPAN Panel > Configure > General Options.

Customizing Entity Precision

The power sensors report with the exact precision from the SPAN panel, which may be more decimal places than you need. By default, sensors display with precision 2 (e.g., 0.00), except battery percentage which uses precision 0 (e.g., 39).

You can change the display precision for any entity via Settings > Devices & Services > Entities tab. Find the entity, click on it, click the gear wheel, and select your preferred precision from the "Display Precision" menu.

Security

The integration cannot enforce much on its own. Anything holding the eBus broker password — including another integration in the same Home Assistant process — talks to the panel directly, outside Home Assistant's permission model.

What pinning the panel's certificate authority buys. The authority is fetched over your network on a connection with nothing to verify itself against, because it is the anchor everything else is checked against:

  • A listener cannot read your passphrase or the credentials the panel returns for it.
  • A device actively in the path at that first fetch can answer with an authority of its own and read both. Pinning alone cannot detect this.

Comparing the fingerprint against another source closes the second case. It is in diagnostics under panel_ca, in the setup log, and reported identically by another install of this integration on the same panel. After the first pin, any change stops the integration and raises a repair — see Troubleshooting.

Situation What happens
Setting up by hostname Verified, never relaxed. A domain joins the certificate's SAN only after you authenticate; everything before that runs against an address the certificate already names.
Panel announces a new address, or you re-add it The entry moves only if the candidate serves a certificate its own anchor validates. Otherwise the move is refused and logged atWARNING.
The panel really has moved UseReconfigure. A host that does not chain is refused, one that does not answer is reported unreachable, and one that chains but is not named is your panel — move it to an FQDN (the panel regenerates its certificate around that name) or the panel's .local name (already covered). A bare new IP the certificate does not name is refused.
A panel announced by anadd-on The add-on's ports are taken as published, because add-ons reallocate their own. The address you configured is kept while it still answers for that panel, and replaced only when it has stopped answering.
The entry has no anchor, or a stored one won't load Reauthenticate acquires one before either sign-in method is offered.

Entries from before pinning pin at the first startup that reaches the panel, logged at WARNING with the fingerprint. Until that succeeds the authority is re-fetched over plaintext on every connection and whatever answers is trusted. If the panel is unreachable the integration starts anyway and retries, because refusing to start would remove the integration without making the credential any safer.

Proxies cut both ways. One terminating the broker port with a certificate of its own leaves the entry unpinned, warning at every start with no repair raised. One terminating only port 443 lets the entry pin, but startup then refuses to connect and keeps retrying, with a repair naming the port — every REST call a pinned entry makes, the schema read at startup included, verifies against the pin, and a certificate the pin does not validate is refused rather than downgraded to plaintext — until the port serves the panel's own certificate. If your panel serves TLS on another port, the setup flow asks once you have moved the HTTP port off 80, and Reconfigure offers the HTTPS port to any pinned entry.

Restricting who can operate the panel

Four options in Settings → Devices & Services → Span Panel → Configure. Every one defaults to the behavior your panel already has, so upgrading changes nothing until you choose otherwise.

Option What it does What it does not do
Who may operate the panel Administrators only refuses circuit switches, priority selects, the GFE override, EVSE limits and adopted controls from non-admin users. Nobody stops creating those entities altogether. Neither affects sensors, and neither constrains anything holding the broker password.
Allow control without a logged-in user Turning it off refuses commands from automations, scripts and other integrations, which arrive with no user attached. It cannot tell a well-behaved automation from a runaway one — only that neither has a user.
Control lock auto-relock Adds a switch that, while armed, refuses every control command. Anyone can arm it; only an administrator can disarm it, and never an automation. It is not a password. It defends against misclicks and runaway automations, which is what a local control can actually do.
Relay debounce Refuses a second command to the same circuit's relay within the window. It is per circuit, so an automation cycling many circuits still gets through.

Why Administrators only is worth setting. Home Assistant's default user policy grants every non-admin user control of every entity. Until you change this, a dashboard-only household member can open any breaker in the house.

Administrators only does not reach an automation a non-admin triggered. It checks the user a command arrived with, and Home Assistant gives an automation a fresh context with no user on it — the triggering context is recorded as the parent, not carried through — so an automation a non-admin set off publishes with nothing for the admin test to hold. (A script is different: run by a person it keeps that person's user, and run from an automation it inherits the automation's userless one.) The option that covers those callers is Allow control without a logged-in user; the two are separate settings because most households want their automations to keep working. Set both if you want control limited to administrators acting in person.

What none of this defends against. These options constrain callers arriving through Home Assistant. They do not constrain anything that already holds the broker credential — a second Home Assistant instance, a script you wrote, or a malicious custom integration running inside this same Home Assistant process, which reads the credential straight out of memory. For that, see Recommended deployment below; network topology and a locked enclosure are the real boundary.

Nothing is deleted when you choose Nobody. The control entities stop being created and read as unavailable; their registry entries, names, areas and customizations are kept, so turning the option back on restores exactly the entities you had. The option is also enforced where commands are published, not only by the absence of entities, so a command reaching the panel by any other route is refused rather than sent. Dashboards and automations referencing them will show them unavailable in the meantime — including the shipped SPAN Panel card, whose toggles call switch.turn_on and select.select_option directly and have no card-side message for a refusal. A non-admin using that card under Administrators only gets a refusal with no explanation on the card.

The record of what was commanded

Every control command fires a span_panel_control_command event and appears in the logbook, whether it succeeded, was refused, or never reached the panel. When there is no user — an automation — the originating automation or script is named instead, so an unattended write is attributed to what rather than left blank. Every command is also logged at INFO.

Commands report one of four outcomes, and the distinctions matter:

Outcome Meaning
confirmed The panel reported the value you asked for.
accepted The broker acknowledged the message and the panel did not report a change.
unconfirmed Nothing came back within the deadline.Not an error — see the troubleshooting entry.
failed The command was never handed to the broker and will not be delivered.
refused:… This integration refused it, for the named reason.

Rotating panel credentials

The span_panel.rotate_credentials action asks the panel for a new eBus MQTT broker password, stores it, and reloads the integration.

action: span_panel.rotate_credentials
data: {}

Run it after a contractor visit, a suspected credential exposure, or any event that put someone else in front of the panel.

Name the panel when you have more than one. The config_entry_id field is optional with a single panel loaded and required beyond that: rotating stops the previous broker password working for every other local client of whichever panel it ran against, so the action refuses an ambiguous call rather than picking one.

Know the blast radius before you run it. The previous broker password stops working the moment the panel issues the new one, so every other local client using it — a second Home Assistant instance, a script, third-party tooling — must be re-provisioned from the panel before it will reconnect. This integration re-provisions itself automatically; nothing else does. The panel access token and the panel passphrase are not changed.

Only a Home Assistant administrator can run it, and it cannot be called from an automation or script: a call arriving without a logged-in user is refused outright. If the panel rejects the stored access token, reauthenticate the integration first — the existing credentials are left untouched on every failure path.

It will not run over an unverified connection. The rotation carries the access token out and the new broker password back, so an entry whose stored authority cannot be read is refused with nothing changed rather than falling back to plaintext; repair the panel's certificate authority and run it again. An entry that was never pinned has no anchor to fall back from and keeps the connection it has always used.

If the reload afterwards fails, do not rotate again. The new password is stored and the panel has already accepted it, so a second rotation would invalidate the one that works. The action reports the failure and says so; check the log and reload the integration.

Recommended deployment

The panel credential is a single all-or-nothing secret, and anyone standing at the panel can mint a fresh one with three presses of the door switch. Network topology and physical control of the panel are the real boundary; everything above is defense in depth behind it.

  • Put the panel on a trusted VLAN, with default-deny between VLANs, and allow only the Home Assistant host to reach it. Open tcp/443 (REST), tcp/8883 (MQTTS) and tcp/80 (the plaintext certificate-authority fetch, and REST too until the entry pins), and deny tcp/9001 and tcp/9002 unless you are actively using the SPAN Home on-premise UI.
  • Use the IP address or an FQDN, not the .local name, because mDNS does not cross VLAN boundaries. The panel's IP is already in its certificate SAN, and for an FQDN the integration registers it so the panel adds it.
  • If Home Assistant cannot be on the panel's VLAN, put a reverse proxy there and restrict its inbound to the Home Assistant host; it holds no panel credential and only relays. MQTTS is a TCP stream rather than HTTP, so tcp/8883 needs a stream proxy (HAProxy, nginx stream, or Caddy's layer4 plugin) while a plain HTTP proxy covers the REST port alone.
  • Secure the panel enclosure, because the three-press proximity bypass hands full credentials to anyone who can open the door — the equivalent of a printed root password. This outranks every software control on this page.
  • Put dashboard-only household members in Home Assistant's read-only group. Home Assistant's default user policy grants every non-admin user control of every entity, which includes this integration's circuit switches and priority selects.
  • Encrypt your Home Assistant backups. An unencrypted backup contains .storage/core.config_entries, and the panel credentials in it are in plaintext.
  • Enable multi-factor authentication on Home Assistant and do not expose its API directly to the Internet. A compromised Home Assistant administrator account is a compromised panel.

WebSocket API

The integration provides a span_panel/panel_topology WebSocket command that returns the full physical layout of a panel in a single call — circuits with their breaker slot positions, entity IDs grouped by role, and sub-devices (BESS, EVSE) with their entities.

See WebSocket API Reference for the full schema, response format, and usage examples.

Troubleshooting

Issue Symptoms Resolution
Energy Dashboard spikes after firmware updates Huge energy-consumption spikes after panel firmware updates; charts showing untracked values that dwarf normal usage; negative energy values in statistics. Caused by the panel reporting decreased values on otherwiseTOTAL_INCREASING sensors. Prevention: enable Energy Dip Compensation in General Options (on by default for new installs). Fix existing spikes: in Developer Tools → Statistics, search for the affected sensor (e.g. sensor.span_panel_main_meter_consumed_energy) and use Adjust sum to correct the errant entry. The integration also notifies when a decrease in the main meter consumed sensor is detected. If you enabled compensation before 2.1.0 and saw spikes at restart: check energy_offset on your energy sensors in Developer Tools → States — an offset far larger than the sensor's own reading is compensation for a dip that never happened, and toggling Energy Dip Compensation off discards it. Offsets booked before 2.1.0 were never corroborated, so the integration cannot tell a good one from a bad one retrospectively; the spikes already in statistics still need Adjust sum either way.
High CPU usage Elevated CPU on low-power hardware (e.g. Raspberry Pi). The integration rebuilds a full panel snapshot from MQTT messages at a configurable interval (default 1 s). IncreaseSnapshot Update Interval in General Options. 10–15 s is recommended for resource-constrained systems. Setting it to 0 disables debouncing and rebuilds on every MQTT message — not recommended.
Replaced sub-device shows the old serial number After replacing a SPAN sub-device (Drive / EVSE, BESS, PV inverter), the device entry in Home Assistant keeps showing the previous hardware's serial number. The integration keys entities off the panel-assigned node identity, which is intentionally stable across hardware swaps so long-term history (e.g. lifetime charging kWh for a Drive) is preserved. The device-registry serial number, however, does not auto-refresh. InSettings → Devices & Services → Span Panel, open the affected sub-device and delete it, then reload the integration (or restart Home Assistant). The device re-registers with the new serial number. Entity IDs and their recorded history are preserved.
Door sensor unavailable The SPAN API returns UNKNOWN if the cabinet door has not been operated recently. This is a defect in the SPAN API. The integration reports the sensor as unavailable until a proper value arrives. Opening or closing the door publishes the correct state. The door is classified as a tamper sensor (Detected / Clear) to differentiate it from a normal entry door.
No switch on a circuit A circuit has no switch entity exposed in Home Assistant. The circuit is configured in the SPAN App as one of the "Always on Circuits". The API does not permit user control of those circuits, so no switch is created.
Reinstalling to change the entity ID style gives back the old entity IDs The naming style is chosen at install and cannot be changed from the options, so reinstalling looks like the way to switch. It is not: every entity returns with the entity ID it had before. Home Assistant remembers a removed entity for30 days, keyed on its unique ID, and restores that record's entity ID — along with its name, area, labels and icon — as soon as an entity with the same unique ID appears again. This integration's unique IDs do not change with the naming style, so the remembered ID wins over the one the new style asks for. Either clear the leftover registry entries between removing and reinstalling, or wait out the 30 days and let Home Assistant discard them. A tool such as ha-registry-clean can do the clearing; it is a separate project, not part of this integration. Clearing also discards the names, areas and labels you had assigned.
Setup fails after downgrading the integration After installing an older release, the SPAN Panel config entry fails to set up and Home Assistant reports an unsupported configuration version. The release that stopped storing the panel passphrase migrated the config entry to version 7. Home Assistant refuses to load a config entry whose version is newer than the installed integration understands, and there is no automatic downgrade. Reinstall the newer release, or restore a backup taken before the upgrade. Removing and re-adding the integration also works and preserves entity IDs, but needs the panel passphrase or physical access to the door again.
"SPAN Panel certificate authority changed" repair The integration has stopped connecting and a repair reports two fingerprints: the one it pinned and the one the panel now advertises. Entities are unavailable. The panel is presenting a different certificate authority than the one you accepted at setup. Two things look identical from here and only you can tell them apart: a firmware upgrade or a factory reset rotates the authority legitimately, and so does a device on your network standing in for your panel.If you know why it changed, open the repair, compare the new fingerprint, and accept it — that re-pins and reconnects. If nothing should have changed, do not accept. Check what else is on the panel's network segment first. The integration will not reconnect on its own and will not re-pin on its own, deliberately: retrying would mean waiting to succeed against whatever is answering.
A circuit re-commissioned in the SPAN App has the wrong controls A circuit whose configuration changed in the SPAN App — made controllable, locked, or set to never back up — still has the controls it had before. A newly controllable circuit has no Breaker switch. A newly locked one still shows its switch, and operating it reports that the command was refused. Reload the integration (Settings → Devices & Services → Span Panel → ⋮ → Reload). Which control entities exist is decided when the integration starts, from what the panel declares about each circuit at that moment; a change made afterwards is picked up at the next reload or restart. Reloading is safe — entity IDs, history, names and areas are preserved, because they are keyed on identifiers that do not change. Until you reload, a control the panel no longer accepts is refused rather than published: the command is not queued and the breaker does not move.
The Adopted tab is missing from the dashboard The dashboard offers By Activity, By Area and Monitoring, but neither Adopted nor By Panel. The panel dropdown at the top of the dashboard is on Favorites, which merges every configured panel into one workspace rather than being a panel itself, so the tabs that only mean something for a single panel are not offered there. Switch the dropdown to a panel and both come back; the selection is remembered per browser. Adopted is also administrator-only.
A control reports unconfirmed The logbook or thespan_panel_control_command event says a command was unconfirmed. Nothing appears broken. This is not an error. It means the panel took the command and did not report a change within the deadline, and the most common reason by far is that there was no change to report — the relay was already open, the priority was already that value. It is also indistinguishable from a silent rejection by the panel, because SPAN's firmware sends no reason code; the integration reports what it observed rather than guessing. The two outcomes that do mean something went wrong are failed, which means the command was never sent, and refused:…, which means this integration refused it and names why.

Development

See Developer Documentation for setup instructions, prerequisites, and tooling.

License

This integration is published under the MIT license.

Attribution and Contributions

This repository is set up as part of an organization so a single committer is not the weak link. The repository is a fork in a long line of SPAN forks that may or may not be stable (from newer to older):

  • SpanPanel/span (current GitHub organization, current repository, currently listed in HACS)
  • SpanPanel/Span (was moved to SpanPanel/SpanCustom)
  • cayossarian/span
  • haext/span
  • gdgib/span
  • thetoothpick/span-hacs
  • wez/span-hacs
  • galak/span-hacs

Additional contributors:

  • pavandave
  • sargonas
  • NickBorgersOnLowSecurityNode

Issues

If you have a problem with the integration, feel free to open an issue, but please know that issues regarding your network, SPAN configuration, or home electrical system are outside of our purview.

For those motivated, please consider offering suggestions for improvement in the discussions or opening a pull request. We're generally very happy to have a starting point when making a change.

About

Default SPAN Integration for HomeAssistant/HACS

Topics

Resources

Stars

47 stars

Watchers

7 watching

Forks

Releases

Used by

Contributors

Languages