Data Models

Novacore's data model architecture covering identities, organizations, sites, devices, and distributed energy resources.

Platform Hierarchy

Novacore organizes energy resources in a five-level hierarchy:

IDENTITY → ORGANIZATION → SITE → DEVICE → DER

IDENTITY (Authentication Layer)

An Identity is the authentication primitive in Novacore — a public key bound to a type:

  • Uniquely identified by a public key (Ed25519 or ES256)
  • Types: user, gateway, device, integration, admin, root
  • ID format: prefixed text (e.g., usr-..., zap-12345, smd-wallbox-001)
  • An identity can belong to multiple organizations

Human identities (user, admin) authenticate with Ed25519 keys. Machine identities (gateway, device, integration) authenticate with ES256 keys.

See Authentication for details on the challenge/verify flow.

ORGANIZATION (Ownership Layer)

An Organization is the root ownership entity:

  • Owns sites, devices, and gateways
  • Has an owner (the identity that created it)
  • Members with roles: owner, admin, operator, viewer
  • The boundary for access control and billing

See Organizations for details on roles and membership.

SITE (Logical Grouping)

A Site represents a complete energy system — everything "behind the meter":

  • The logical boundary for energy optimization
  • Typically corresponds to a physical location (home, building, facility)
  • Contains all energy resources at that location
  • The level where energy flows are balanced and optimized
  • Belongs to exactly one organization

Example Site composition:

  • Grid connection point (meter)
  • Solar panels (PV)
  • Battery storage
  • EV charger
  • Hybrid inverter

DEVICE (Physical Connection Point)

A Device represents the physical hardware you communicate with:

  • The actual communication endpoint (Modbus address, MQTT client, P1 port)
  • Often the electrical connection point
  • What the Zap directly talks to via protocols
  • Links to a gateway via comm_identity_id

Device types:

TypeDescription
inverterSolar/hybrid inverter
batteryBattery storage system
ev_chargerEV charger
v2x_chargerBidirectional EV charger
energy_meterGrid or sub meter

Device states:

StateDescription
pendingNewly created, not yet active
activeOperational, sending telemetry
staleNo recent telemetry
errorHardware fault detected
disconnectedNo connection
orphanedGateway reclaimed by different org

One Device may expose multiple DERs.

DER (Distributed Energy Resource)

A DER is the logical representation of an energy resource or function:

  • What the energy system "sees" and models
  • The unit of energy generation, storage, or consumption
  • Can be a physical component or a logical representation

DERs are often representations of capabilities "under" a Device, not always directly addressable entities.

Example: Hybrid Inverter

  • DEVICE: The inverter itself (communication point via Modbus)
  • DER #1: Solar PV (generation capability)
  • DER #2: Battery (storage capability)
  • DER #3: Grid connection (import/export measurement)

DER Types:

TypeDescriptionAllowed on Device Types
solarSolar generationinverter
batteryEnergy storageinverter, battery
meterGrid import/export measurementinverter, battery, energy_meter
ev_charger_portEV charger portev_charger, v2x_charger

Hierarchy Example

IDENTITY: usr-paul-abc123 (Ed25519, user)
  └─ ORGANIZATION: org-sourceful-home
      ├─ Members: paul (owner), tobias (admin), johan (operator)
      └─ SITE: sit-main-street-42
          ├─ GATEWAY: zap-04772a97 (claimed to this org)
          ├─ DEVICE: dev-hybrid-inverter-01 (inverter, Modbus-TCP)
          │   ├─ DER: pv-rooftop (solar)
          │   └─ DER: battery-01 (battery)
          ├─ DEVICE: dev-v2x-charger-01 (v2x_charger, MQTT)
          │   └─ DER: ev-port-1 (ev_charger_port)
          └─ DEVICE: dev-smart-meter-01 (energy_meter, P1)
              └─ DER: grid-meter (meter)

Telemetry Data Models

Units and Conventions

Units:

MeasurementUnit
PowerW (watts)
EnergyWh (watt-hours)
VoltageV (volts)
CurrentA (amperes)
FrequencyHz (hertz)
TemperatureC (Celsius)
State of Chargefraction (0.0 - 1.0)
Times or ms

Sign Conventions:

ConditionSign
Generation (PV)Negative
Charging (Battery)Positive
Discharging (Battery)Negative
Import (Meter)Positive
Export (Meter)Negative

See Core Principles for detailed sign convention rules.

BaseDeviceData

Common fields shared by all device types:

FieldTypeDescription
typestringObject type ("pv", "battery", "meter", "v2x_charger")
makestringManufacturer/brand name (optional)
timestampintegerTimestamp of reading start (ms)
read_time_msintegerTime taken to complete the reading

PV (Solar) Data Model

{
  "type": "pv",
  "make": "Deye",
  "W": -1500,
  "rated_power_W": 3000,
  "mppt1_V": 400,
  "mppt1_A": -3.75,
  "mppt2_V": 380,
  "mppt2_A": -3.68,
  "heatsink_C": 45,
  "total_generation_Wh": 15000
}
FieldUnitTypeDescription
WWintegerPower Generation (always negative)
rated_power_WWintegerSystem Rated Power
mppt1_VVfloatMPPT1 Voltage
mppt1_AAfloatMPPT1 Current
mppt2_VVfloatMPPT2 Voltage
mppt2_AAfloatMPPT2 Current
heatsink_CCfloatInverter Temperature
total_generation_WhWhintegerTotal Energy Generated

Battery Data Model

{
  "type": "battery",
  "make": "Tesla",
  "W": 500,
  "A": 10.5,
  "V": 48.2,
  "SoC_nom_fract": 0.75,
  "heatsink_C": 25,
  "total_charge_Wh": 8000,
  "total_discharge_Wh": 7200
}
FieldUnitTypeDescription
WWintegerActive Power (+ charge, - discharge)
AAfloatCurrent (+ charge, - discharge)
VVfloatVoltage
SoC_nom_fractfractionfloatState of Charge (0.0-1.0)
heatsink_CCfloatBattery Temperature
total_charge_WhWhintegerTotal Energy Charged
total_discharge_WhWhintegerTotal Energy Discharged

Meter Data Model

{
  "type": "meter",
  "make": "Kamstrup",
  "W": 1200,
  "Hz": 50.0,
  "L1_V": 230,
  "L1_A": 5.2,
  "L1_W": 400,
  "L2_V": 229,
  "L2_A": 5.1,
  "L2_W": 380,
  "L3_V": 231,
  "L3_A": 5.3,
  "L3_W": 420,
  "total_import_Wh": 25000,
  "total_export_Wh": 18000
}
FieldUnitTypeDescription
WWintegerTotal Active Power (+ import, - export)
HzHzfloatGrid Frequency
L1_VVfloatL1 Phase Voltage
L1_AAfloatL1 Phase Current
L1_WWfloatL1 Phase Power
L2_VVfloatL2 Phase Voltage
L2_AAfloatL2 Phase Current
L2_WWfloatL2 Phase Power
L3_VVfloatL3 Phase Voltage
L3_AAfloatL3 Phase Current
L3_WWfloatL3 Phase Power
total_import_WhWhintegerTotal Energy Imported
total_export_WhWhintegerTotal Energy Exported

EV Charger Data Model

Telemetry for AC EV chargers (sourced from OCPP 1.6 / 2.0.1). Each connector on a charger is published as its own DER. For bidirectional V2X chargers, see V2X Charger Data Model.

{
  "type": "ev_charger_port",
  "make": "Zaptec",
  "connector_status": "occupied",
  "charging_state": "charging",
  "W": 7200,
  "L1_V": 230.5,
  "L1_A": 10.4,
  "L2_V": 231.2,
  "L2_A": 10.3,
  "L3_V": 229.8,
  "L3_A": 10.5,
  "total_charge_Wh": 125000,
  "session_charge_Wh": 5000,
  "session_id": 12345,
  "upper_limit_W": [0, 11000],
  "lower_limit_W": [0, 4500]
}
FieldUnitTypeDescription
connector_status-stringConnector availability (see Connector Status)
charging_state-stringVehicle/session charging state (see Charging State)
status-stringDeprecated. Use connector_status + charging_state instead
plug_connected-booleanDeprecated. Use connector_status instead
WWintegerActive power delivered to the EV
L1_V / L2_V / L3_VVfloatPhase Voltage
L1_A / L2_A / L3_AAfloatPhase Current
total_charge_WhWhintegerLifetime energy delivered to vehicles
session_charge_WhWhintegerEnergy delivered in the current session
session_id-integerOCPP transaction ID for the active session, null when no session
upper_limit_WWint arrayUpper bound of each allowed power band (see Power Limits)
lower_limit_WWint arrayLower bound of each allowed power band (see Power Limits)

V2X Charger Data Model

{
  "type": "v2x_charger",
  "make": "Ferroamp",
  "connector_status": "occupied",
  "charging_state": "charging",
  "protocol": "ISO_15118_20",
  "control_mode": "bi_dir",
  "plug_connected": true,
  "W": 5300,
  "ac_W": 5300,
  "A": 23.0,
  "V": 230.5,
  "Hz": 49.98,
  "L1_V": 232.8,
  "L1_A": 23.0,
  "L1_W": 5354,
  "dc_W": 5100,
  "dc_V": 400.0,
  "dc_A": 12.75,
  "vehicle_soc_fract": 0.55,
  "session_charge_Wh": 1500,
  "session_discharge_Wh": 0,
  "total_charge_Wh": 142000,
  "total_discharge_Wh": 5100
}
FieldUnitTypeDescription
connector_status-stringConnector availability (see Connector Status)
charging_state-stringVehicle/session charging state (see Charging State)
status-stringDeprecated. Use connector_status + charging_state instead
protocol-stringActive protocol (e.g., ISO_15118_2, ISO_15118_20, DIN)
control_mode-string"unknown", "bi_dir" (bidirectional), or "uni_dir" (charge only)
plug_connected-booleanDeprecated. Use connector_status instead
WWintegerActive Power, derived from ac_W or dc_W * 0.95. (+) Charging, (-) V2G
ac_WWintegerAC Active Power (+) Charging, (-) V2G
AAfloatAC Grid Current (Total)
VVfloatAC Grid Voltage (Average)
HzHzfloatGrid Frequency
L1_V / L2_V / L3_VVfloatPhase Voltage
L1_A / L2_A / L3_AAfloatPhase Current
L1_W / L2_W / L3_WWfloatPhase Power
dc_WWintegerDC Battery Power
dc_VVfloatDC Voltage level of the EV battery
dc_AAfloatDC Current flow
vehicle_soc_fractfractionfloatVehicle State of Charge (0.0 - 1.0)
ev_target_energy_req_WhWhintegerEnergy needed to reach driver's target SoC
ev_max_energy_req_WhWhintegerEmpty space in battery available for charging
ev_min_energy_req_WhWhintegerEnergy available for V2G export
session_charge_WhWhintegerEnergy imported by EV this session
session_discharge_WhWhintegerEnergy exported by EV this session
total_charge_WhWhintegerLifetime energy delivered to EV
total_discharge_WhWhintegerLifetime energy exported from EV (V2G)

Connector Status

Based on OCPP 2.0.1, with preparing and finishing retained from OCPP 1.6 for backward compatibility.

ValueMeaning
"unknown"State not yet determined
"available"Ready, nothing plugged in
"preparing"Cable plugged in, session not started yet
"finishing"Session ending, cable still plugged in
"reserved"Locked for a specific user
"unavailable"Intentionally offline (maintenance, admin)
"faulted"Hardware/software fault
"occupied"In use (charging, discharging, or connected)

Charging State

Based on OCPP 2.0.1, extended with discharging for V2G.

ValueMeaning
"unknown"State not yet determined
"charging"Energy actively flowing to vehicle
"discharging"Energy flowing from vehicle to grid (V2G)
"suspended_ev"Vehicle not accepting power
"suspended_evse"Charger not delivering power
"ev_connected"Cable plugged in, no energy flowing yet
"idle"Transaction open but no EV connected

Power Limits

upper_limit_W and lower_limit_W are arrays that together describe the allowed power bands. Each index i defines a band [lower_limit_W[i], upper_limit_W[i]]. The charger may operate at any power inside any of these bands; values between bands are not allowed.

AC EV charger (charge only) — typically two bands: idle and charge.

"upper_limit_W": [0, 11000],
"lower_limit_W": [0, 4500]
  • Band 0: [0, 0] — idle (0 W is always allowed)
  • Band 1: [4500, 11000] — charging band

The charger can run at 0 W or anywhere from 4500 W to 11000 W. Values like 3000 W are not valid (they fall between bands).

When charging is not allowed at all (e.g., faulted or finishing), both arrays collapse to [0].

V2X charger (bidirectional) — typically three bands: discharge, idle, charge.

"upper_limit_W": [-500, 50, 7000],
"lower_limit_W": [-7000, -50, 500]
  • Band 0: [-7000, -500] — discharge (V2G) band
  • Band 1: [-50, 50] — idle band
  • Band 2: [500, 7000] — charge band