Interface contract between Enexa Platform and Amperio Middleware
Optimization engine, asset registry, configuration repository, and monitoring dashboards
Enexa ResponsibilityCentralized backend that routes commands to site controllers via Modbus/TCP
Amperio Team ResponsibilityUltrafast charging hardware with integrated battery storage (up to 300 kW)
Amperio TeamRegister station.mgmt.watchdog_interval (addr 2500) must be written every 2-60 seconds. If timer expires, system reverts to fallback configuration values. Amperio Middleware must maintain this heartbeat.
Optimization
Monitoring
Dispatch
Impact
Data required by the Enexa optimization algorithm to compute optimal dispatch schedules. These fields directly influence charge/discharge decisions.
Data displayed on NOC dashboards for real-time operational awareness. Enables operators to monitor system health and troubleshoot issues.
Data used to verify that dispatched commands were executed correctly. Compares commanded setpoints to actual system response.
Data used to calculate cost savings, demonstrate optimization value, and generate customer reports showing ROI of Smart Enexa layer.
Multi-Purpose Fields: Some fields serve multiple purposes. For example, P_grid_w is taggedOPT (optimization uses current grid power) andIMP (time-series used for cost calculation). When a field has multiple tags, it means the same data point flows to multiple systems.
Site Identifier
Unique identifier for the physical location. Assigned during site registration in Enexa portal.
"site_id": "site_de_munich_01"ChargePost Identifier
Unique identifier for the ADS-TEC ChargePost unit at this site. Maps to hardware serial number.
"asset_id": "cp_adstec_4872"Power Unit Identifier
Sub-component within ChargePost (1 or 2). Each unit has independent battery + charger.
"unit_id": 1// Every telemetry POST includes envelope with identifiers
POST /api/v1/telemetry
{
"site_id": "site_de_munich_01", // From Enexa Site Registry
"asset_id": "cp_adstec_4872", // ChargePost serial/asset ID
"timestamp": "2024-01-15T14:30:00Z", // ISO8601 UTC
"batteries": [
{ "unit_id": 1, "soc_pct": 65, ... },
{ "unit_id": 2, "soc_pct": 62, ... }
],
"chargers": [...],
"grid": {...}
}
// Dispatch commands are routed using same identifiers
POST /api/v1/dispatch
{
"site_id": "site_de_munich_01",
"asset_id": "cp_adstec_4872",
"command_id": "cmd_20240115_143000_001", // Unique for ACK tracking
"timestamp": "2024-01-15T14:30:00Z",
"station": {...},
"units": [
{ "unit_id": 1, "charging_mode": 1, ... },
{ "unit_id": 2, "charging_mode": 1, ... }
]
}Telemetry Direction
Middleware → Enexa: Middleware includes site_id + asset_id in every telemetry push. Enexa uses these to route data to correct site dashboard and optimizer instance.
Dispatch Direction
Enexa → Middleware: Enexa includes site_id + asset_id in dispatch commands. Middleware validates these match its configured identity before executing.
Enexa cannot see the physical hardware directly. The Amperio Middleware acts as the "eyes" of the optimization system, aggregating data from all site controllers and pushing it to Enexa. Without accurate, real-time telemetry, Enexa cannot make optimal dispatch decisions. Every field below directly influences how the algorithm allocates energy between grid, battery, and EVs.
ADS-TEC ChargePost has two independent battery strings. Data mapped from Modbus registers charger.X.status.battery.*
{
"batteries": [
{
"unit_id": 1,
"soc_pct": 65,
"power_w": -25000,
"temp_min_c": 28.5,
"temp_max_c": 32.5,
"max_charge_w": 110000,
"max_discharge_w": 110000,
"energy_empty_kwh": 45.2,
"energy_full_kwh": 12.8,
"contactor_state": "closed"
},
{
"unit_id": 2,
"soc_pct": 62,
"power_w": -22000,
...
}
]
}| Field | Purpose | Modbus Source | Why Needed & How Used |
|---|---|---|---|
| unit_id | MON | charger.1 / charger.2 | Identifies which power unit (1 or 2). Used in dashboards to display per-unit status and in dispatch logs to track which unit executed commands. |
| soc_pct | OPT | soc_cp (7006/17006) | Critical optimization input. Compared to target SOC curve to decide charge/discharge actions. Drives arbitrage decisions - if SOC low during cheap hours, charge; if SOC high during expensive hours, available for EV boost. |
| power_w | DSP | P_bat (7000/17000) | Dispatch verification. Compares actual power to commanded setpoint. Negative = discharge. Used to confirm commands executed correctly and detect deviations for alert generation. |
| temp_min_c / temp_max_c | MON | T_bat_min/max (7008-7010) | Safety monitoring only. Displayed on dashboard for operator awareness. Not used in optimization - hardware handles thermal derating automatically via P_bat_chg_max limits. |
| max_charge_w | OPT | P_bat_chg_max (7012/17012) | Optimization constraint. Real-time available charging headroom. Optimizer uses this to cap scheduled charge power - never commands more than hardware can accept. Reflects thermal/SOC derating. |
| max_discharge_w | OPT | P_bat_dischg_max (7014/17014) | Optimization constraint. Real-time available discharge capacity (up to 110kW/unit). Used to calculate maximum EV boost power and grid export potential during peak pricing. |
| energy_empty_kwh | OPT | E_empty (7016/17016) | Optimization input. Usable energy available for discharge. Critical for calculating: (1) How long can we boost EVs at a given power? (2) Total arbitrage potential in EUR during expensive hours. |
| energy_full_kwh | OPT | E_full (7018/17018) | Optimization input. Usable energy capacity for charging. Used to calculate: (1) How much cheap energy can we store? (2) Time required to reach target SOC at given charge rate. |
| contactor_state | MON | battery_contactor_state (7024/17024) | Operational monitoring. 0=undefined, 1=open, 2=closed. Displayed on dashboard. Must be closed for power flow - open state indicates fault or startup sequence. |
Data from ChargePost integrated smart meter. Registers in "grid.*" namespace (addresses 1000+).
{
"grid": {
"P_grid_w": 35000,
"E_grid_imp_kwh": 245.6,
"E_grid_exp_kwh": 12.3,
"P_aux_w": 3200,
"f_grid_hz": 50.01,
"cos_phi": 0.98
}
}| Field | Purpose | Modbus Source | Why Needed & How Used |
|---|---|---|---|
| P_grid_w | OPT IMP | grid.P_grid (1000) | Primary cost driver. Real-time grid import/export. Multiplied by EPEX price for cost calculation. Negative = export. Used in: (1) Optimization for real-time adjustments, (2) Impact dashboards showing actual vs baseline costs. |
| E_grid_imp_kwh | IMP | grid.E_grid_imp (1022) | Cost settlement. Cumulative import counter. Used for: (1) Daily/monthly cost calculations, (2) EPEX settlement validation, (3) KPI: total grid consumption vs baseline. Essential for uplift reporting. |
| E_grid_exp_kwh | IMP | grid.E_grid_exp (1024) | Revenue tracking. Cumulative export counter. Used for: (1) Feed-in tariff calculations if applicable, (2) Arbitrage profit calculation (sold high, bought low), (3) Grid support revenue attribution. |
| P_aux_w | OPT | grid.P_aux (1026) | Optimization constraint. Auxiliary load (HVAC, displays) up to 8kW. Subtracted from P_grid_clearance to get actual available capacity for charging. Important during hot/cold weather when HVAC load increases. |
| f_grid_hz | MON | grid.f_grid (1008) | Future use - monitoring only. Grid frequency (nominal 50Hz). Displayed on dashboard for grid health awareness. Phase 2: May trigger frequency containment reserve (FCR) participation if contracted. |
| cos_phi | MON | grid.cos_phi (1006) | Grid compliance monitoring. Power factor. Displayed on dashboard. Low values may indicate power quality issues. Some grid operators penalize poor power factor - useful for compliance reporting. |
Note: Per-phase voltages (U_L1/L2/L3) and currents (I_L1/L2/L3) are available in registers 1010-1020 but not included in Phase 1 scope. These are diagnostic data points useful for fault analysis but not required for optimization or standard monitoring. Add if grid quality analysis becomes a requirement.
ChargePost has 2 charging points (charger.1 and charger.2). In coupled mode, both power units serve one connector.
{
"chargers": [
{
"unit_id": 1,
"charging_state": "InProgress",
"charging_process_state": "Charging",
"plug_state": "Plugged",
"P_EV_w": 145000,
"P_EV_max_w": 150000,
"P_cp_max_w": 150000,
"soc_EV_pct": 45,
"E_EV_chg_kwh": 23.5,
"boost_contactor": "closed"
},
{
"unit_id": 2,
"charging_state": "Available",
...
}
]
}| Field | Purpose | Modbus Source | Why Needed & How Used |
|---|---|---|---|
| unit_id | MON | charger.1 / charger.2 | Charger identification. Identifies which charging unit (1 or 2). Used in dashboards to show per-connector status and in logs to track which unit served which session. |
| charging_state | MON DSP | charging_state (3000/13000) | Dashboard & dispatch prerequisite. 0=NotAvailable, 1=Available, 2=InProgress. Displayed on monitoring dashboard. Optimizer checks state before sending EV-related commands - no commands sent if NotAvailable. |
| charging_process_state | MON | process_state (3001/13001) | Detailed monitoring only. States: Offline, ReadyToCharge, Authorization, ChargingSetup, Charging, ChargingTeardown, ChargingFinished, ChargingError. Enables detailed dashboard status and error diagnosis. |
| plug_state | OPT | plug_state (3002/13002) | Optimization trigger. 0=Unplugged, 1=Plugged. When plug_state changes to 1, optimizer immediately re-evaluates: Should we boost from battery? Throttle charging to cheap hours? Key event for real-time decisions. |
| P_EV_w | DSP IMP | P_EV (3008/13008) | Dispatch verification + KPI. Actual charging power in watts. Compared to P_cp_lim setpoint for verification. Summed over session for impact analysis: "Session delivered X kWh at Y EUR average cost." |
| P_EV_max_w | OPT | P_EV_max (3010/13010) | Optimization constraint. Maximum power EV currently accepts (ISO 15118/CHAdeMO). Optimizer never commands P_cp_lim above this - would be wasted headroom. Used to calculate: Can we shift load to cheaper hours and still finish in time? |
| P_cp_max_w | OPT | P_cp_max (3004/13004) | Optimization constraint. Maximum power deliverable by chargepoint (hardware limit). Combined with P_EV_max and battery availability to calculate actual charging headroom for optimization. |
| soc_EV_pct | OPT | soc_EV (3020/13020) | Optimization input (if available). EV battery SOC communicated by vehicle. Used with energy_target (if V2G/smart charging) to calculate remaining kWh needed. Not all vehicles report this - optional field. |
| E_EV_chg_kwh | IMP | E_EV_chg (3021/13021) | Impact KPI. Energy delivered this session. Used for: (1) Session billing, (2) Calculating per-session cost with time-weighted EPEX prices, (3) Impact dashboard: "Saved X EUR vs flat-rate charging." |
| boost_contactor | MON | boost_contactor_state (3031) | Monitoring only. 0=undefined, 1=open, 2=closed. Shows on dashboard whether 300kW coupled mode is active. Hardware manages coupling automatically based on charging_mode command. |
Station-level status from registers in station.status.* namespace. Important for operational awareness.
{
"station": {
"operation_state": "Ready",
"P_grid_consumption_limit_w": 79000,
"P_grid_generation_limit_w": 79000,
"warnings": [],
"errors": []
}
}| Field | Purpose | Modbus Source | Why Needed & How Used |
|---|---|---|---|
| operation_state | MON | operation_state (2000) | Dashboard status. Values: Off, Startup, Ready, LeftCharge, RightCharge, BothCharge, Shutdown. Shows operational state on monitoring dashboard and helps diagnose why commands may not execute. |
| P_grid_consumption_limit_w | OPT | P_grid_consumption_limit (2010) | Optimization constraint. Maximum grid power consumption allowed without violating clearance. Dynamic value reflecting current limits. Optimizer uses this as upper bound for charge commands. |
| P_grid_generation_limit_w | OPT | P_grid_generation_limit (2012) | Optimization constraint. Maximum grid export power allowed. Limits how much battery discharge power can be fed back to grid. Critical for arbitrage optimization. |
| warnings | MON | station.status.warnings (2100) | Alert generation. Bitfield: watchdog_triggered, no_modbus_ctrl, manual_ctrl, P_clearance_violation, etc. Mapped to dashboard alerts. Helps diagnose control issues. |
| errors | MON | station.status.errors.* (2110+) | Critical alerts. Hardware errors: CrashSensor_Triggered, USV_GridSupplyFailure, HVAC errors. Triggers immediate alerts to operators. Not used in optimization - system is typically non-functional. |
Enexa Platform calculates: Optimal battery SOC targets, charge/discharge timing, price-aware scheduling, and energy allocation between sources.
Amperio Middleware executes: Receives commands via API, routes to site controllers internally, enforces safety limits, handles real-time adjustments within commanded bounds.
Every 15 minutes (aligned with EPEX slots) + event-driven updates when conditions change
Middleware must ACK within 5 seconds or Enexa retries (3x then alert)
Commands mapped to ADS-TEC Modbus holding registers in station.mgmt.* namespace. Middleware writes these via Modbus/TCP.
{
"station": {
"operation_mode": 1,
"grid_mgmt_mode": 1,
"P_grid_clearance_w": 79000,
"external_control_id": "ENEXA_PROD"
}
}| Field | Purpose | Modbus Register | Why Needed & How Used |
|---|---|---|---|
| operation_mode | DSP | operation_mode (2501) | Master on/off switch. 0 = Off (system offline), 1 = On (Enexa control enabled). Set to 1 on deployment, rarely changed. Used in dispatch logs to confirm system is controllable. |
| grid_mgmt_mode | OPT | grid_mgmt_mode (2502) | Optimization control mode. 0 = Automatic (system manages using P_grid_clearance), 1 = Manual (Enexa sets per-unit P_grid targets). For price optimization, use Manual mode to control charge/discharge timing precisely. |
| P_grid_clearance_w | OPT | P_grid_clearance (2506) | Primary optimization lever. Maximum grid power limit in watts. In Automatic mode: controls how much grid power to use before battery kicks in. Higher value = more grid, less battery. Set based on EPEX price - low during cheap hours, high during expensive hours. |
| external_control_id | DSP | external_control_id (2514) | Audit trail. Identifier string (max 32 chars). Middleware writes "ENEXA_PROD" or "ENEXA_TEST". Visible on hardware UI and logs - helps diagnose who is controlling the system. |
Not included: silent_mode, power_gradient_mode, energy_saving_mode_reaction_speed, adv_display_priority_mode - these are static configuration fields set once at commissioning. Not relevant for dynamic energy optimization.
Commands for each power unit. In manual grid_mgmt_mode, Enexa can control power independently per battery string.
{
"chargers": [
{
"unit_id": 1,
"charging_mode": 2,
"P_grid_w": -30000,
"P_cp_lim_w": 150000,
"soc_cp_max_pct": 90
},
{
"unit_id": 2,
"charging_mode": 2,
"P_grid_w": -30000,
"P_cp_lim_w": 150000,
"soc_cp_max_pct": 90
}
]
}| Field | Purpose | Modbus Register | Why Needed & How Used |
|---|---|---|---|
| unit_id | DSP | charger.1 / charger.2 | Target unit identifier. Specifies which power unit (1 or 2) receives the command. Required to route commands to correct Modbus address space (12xxx vs 22xxx). |
| charging_mode | OPT | charging_mode (12000/22000) | EV charging strategy. 0 = Off (unit disabled), 1 = Single (max 150kW), 2 = Dual (max 300kW coupled), 3 = Disabled (grid ops only). Use mode 3 during expensive hours to block EV charging while still allowing arbitrage. |
| P_grid_w | OPT | P_grid (12005/22005) | Core dispatch command (manual mode). Target grid power in producer counting. Negative = discharge to grid (export during expensive hours). Positive = charge from grid (cheap hours). Optimizer calculates based on EPEX price and SOC. |
| P_cp_lim_w | OPT | P_cp_lim (12001/22001) | EV load management. Maximum EV charging power (0-300000W). Set low during expensive hours to throttle EV charging. Set high during cheap hours to maximize grid-to-EV charging. 0 = block charging entirely. |
| soc_cp_max_pct | OPT | soc_cp_max (12009/22009) | Battery target SOC. Maximum battery SOC to charge to. Set high (90%) during cheap hours to store energy. Set lower during volatile periods to leave room for arbitrage opportunities. Must be below station backup reserve. |
Not included: I_cp_lim (current limit) - redundant with P_cp_lim for most use cases. Power limit is the primary constraint; current limit only relevant for specific cable/connector limitations.
If sum of charger.X.mgmt.P_grid exceeds station.mgmt.P_grid_clearance:
Automatic Battery Assist: When EV demand exceeds grid clearance (P_grid_clearance), the internal battery automatically supplements power. This is hardware-level behavior.
Enexa's Role: Control the constraints that shape this behavior:
Grid Priority Mode: ChargePost prioritizes grid over battery. If EV demands 100kW and grid clearance is 80kW, it takes 80kW from grid and 20kW from battery.
// Example: Peak pricing - limit EV charging, preserve battery
{
"station": {
"P_grid_clearance_w": 40000 // Reduce grid usage
},
"chargers": [
{
"unit_id": 1,
"P_cp_lim_w": 80000, // Limit EV to 80kW (forces battery use)
"soc_cp_max_pct": 95 // Keep battery full for boost
}
]
}
// Example: Cheap hours - maximize grid charging
{
"station": {
"P_grid_clearance_w": 87000 // Full grid capacity
},
"chargers": [
{
"unit_id": 1,
"P_cp_lim_w": 300000, // No limit on EV
"soc_cp_max_pct": 95 // Charge battery to max
}
]
}What is the gate? A control mechanism that limits or blocks grid power import during expensive price periods. Think of it as a "valve" that Enexa opens or closes based on electricity prices.
Why is this needed? Without the gate, the system would draw grid power whenever demanded, regardless of price. The gate enforces price-aware behavior:
Emergency override: Even when gate is closed, if battery SOC drops below emergency threshold (e.g., 15%), the gate opens to prevent system failure.
{
"grid": {
"import_allowed": true,
"max_import_kw": 80.0,
"export_allowed": false,
"max_export_kw": 0.0,
"price_zone": "peak",
"gate_reason": "peak_pricing"
}
}| Field | Calculated By | Purpose & Logic |
|---|---|---|
| import_allowed | Enexa | Master switch for grid import. When false, middleware must not draw any power from grid for battery charging. EV charging may still use grid if source_priority includes it and other sources insufficient. |
| max_import_kw | Enexa | Power limit for grid import. During cheap hours = full 80 kW. During moderate = throttled (e.g., 30 kW). During expensive/peak = 0 kW (unless emergency). This is the "valve opening" amount. |
| export_allowed | Enexa | Whether grid export (selling power back) is permitted. Usually false unless feed-in tariff is favorable or V2G is enabled. |
| max_export_kw | Enexa | Power limit for grid export. Set to 0 if no export contract. If V2G enabled, this limits how much power can be sold back. |
| price_zone | Enexa | Current price classification. Enexa calculates this from EPEX prices using percentile thresholds. Informational for middleware logging and operator dashboards. |
| gate_reason | Enexa | Human-readable explanation: "cheap_slot", "peak_pricing", "emergency_override", "demand_limit". Helps operators understand why gate is in current state. |
POST /api/v1/dispatch
Content-Type: application/json
Authorization: Bearer <site_token>
{
"site_id": "site_enexa_001",
"command_id": "cmd_20240115_103000_001",
"timestamp": "2024-01-15T10:30:00Z",
"valid_until": "2024-01-15T10:45:00Z",
"battery": { ... },
"connectors": [ ... ],
"grid": { ... }
}
// Expected Response (within 5 seconds):
{
"command_id": "cmd_20240115_103000_001",
"status": "accepted", // "accepted" | "rejected" | "partial"
"applied_at": "2024-01-15T10:30:00.234Z",
"warnings": [], // Non-fatal issues
"errors": [] // Reasons for rejection
}{
"emergency": {
"type": "low_soc",
"action": "force_charge",
"target_soc_pct": 25.0,
"ignore_price": true,
"max_rate_kw": 60.0
}
}Emergency commands take precedence over all other dispatch instructions. The middleware must execute immediately regardless of current state or price zone. Types: "low_soc" (battery critical), "grid_fault" (switch to island), "thermal" (reduce power), "ev_priority" (must charge EV now).
| Address | Register Name | Type | Description |
|---|---|---|---|
| 2000 | station.status.operation_state | uint16 | 0=Off, 1=Startup, 2=Ready, 3=LeftCharge, 4=LeftConCharge, 5=RightCharge, 6=RightConCharge, 7=BothCharge, 8=Shutdown |
| 2006 | station.status.T_ambient | float | Ambient temperature near heat exchanger (°C) |
| 2009 | station.status.watchdog_timeout | uint16 | Seconds until watchdog expires |
| 2010 | station.status.P_grid_consumption_limit | uint32 | Max grid consumption power (W) without clearance violation |
| 2012 | station.status.P_grid_generation_limit | uint32 | Max grid feed-in power (W) without clearance violation |
| 2100 | station.status.warnings | bitlist | Bit 0: watchdog_triggered, Bit 1: no_modbus_ctrl, Bit 2: manual_ctrl, Bit 3: P_clearance_violation, Bit 4: I_clearance_violation |
| 2110 | station.status.errors.general | bitlist | Bit 0: error_flags_corrupted, Bit 1: CrashSensor_Triggered, Bit 2: USV_GridSupplyFailure |
| Address | Register Name | Type | Description |
|---|---|---|---|
| 2500 | station.mgmt.watchdog_interval | uint16 | CRITICAL: Write every 2-60s to maintain control. Expiry reverts to fallback config. |
| 2501 | station.mgmt.operation_mode | uint16 | 0=Off (system offline), 1=On (system active) |
| 2502 | station.mgmt.grid_mgmt_mode | uint16 | 0=Automatic (system manages), 1=Manual (per-unit P_grid setpoints) |
| 2504 | station.mgmt.energy_saving_mode_reaction_speed | uint16 | 0=Fast (always active), 1=Slow (sleep after 60s idle) |
| 2506 | station.mgmt.P_grid_clearance | uint32 | Maximum grid power (W). Can exceed config limit with active Modbus control. Max 87kVA. |
| 2512 | station.mgmt.power_gradient_mode | uint16 | 0=No gradient, 1=VDE4105 third party gradient (for direct marketing) |
| 2514 | station.mgmt.external_control_id | string | Identifier of external EMS (max 32 chars). Write "ENEXA_PROD" for audit trail. |
charger.1 addresses shown. Add 10000 for charger.2 (e.g., 3000 → 13000, 7000 → 17000, 12000 → 22000).
| Address | Register Name | Type | Description |
|---|---|---|---|
| Status Registers (Input - FC 04) | |||
| 3000 | charger.1.status.charging_state | uint16 | 0=NotAvailable, 1=Available, 2=InProgress |
| 3001 | charger.1.status.charging_process_state | uint16 | 0=Offline, 1=ReadyToCharge, 2=Authorization, 3=ChargingSetup, 4=Charging, 5=ChargingTeardown, 6=ChargingFinished, 7=ChargingError |
| 3002 | charger.1.status.plug_state | uint16 | 0=Unplugged, 1=Plugged |
| 3008 | charger.1.status.P_EV | int32 | Current EV charging power (W) |
| 3010 | charger.1.status.P_EV_max | int32 | Maximum power EV accepts (W) |
| 3020 | charger.1.status.soc_EV | uint16 | EV battery SOC (%) |
| 3021 | charger.1.status.E_EV_chg | float | Energy delivered this session (kWh) |
| Battery Status Registers (Input - FC 04) | |||
| 7000 | charger.1.status.battery.P_bat | float | Battery power in producer counting (W). Negative = discharge. |
| 7006 | charger.1.status.battery.soc_cp | uint16 | Internal battery SOC (%) |
| 7008 | charger.1.status.battery.T_bat_min | float | Min battery string temperature (°C) |
| 7010 | charger.1.status.battery.T_bat_max | float | Max battery string temperature (°C) |
| 7012 | charger.1.status.battery.P_bat_chg_max | float | Max battery charging power available (W) |
| 7014 | charger.1.status.battery.P_bat_dischg_max | float | Max battery discharge power available (W) |
| Management Registers (Holding - FC 03/06/16) | |||
| 12000 | charger.1.mgmt.charging_mode | uint16 | 0=Off, 1=Single (150kW), 2=Dual (300kW), 3=Disabled (grid only) |
| 12001 | charger.1.mgmt.P_cp_lim | uint32 | Max EV charging power (W). 0=no charging. >300000 treated as 300000. |
| 12003 | charger.1.mgmt.I_cp_lim | uint32 | Max EV charging current (A). 0=no charging. >500 treated as 500. |
| 12005 | charger.1.mgmt.P_grid | int32 | Target grid power in manual mode (W). Negative = feed to grid. |
| 12009 | charger.1.mgmt.soc_cp_max | uint16 | Max battery SOC target (%). Must be < backup config value. |
| Address | Register Name | Type | Description |
|---|---|---|---|
| 1000 | grid.P_grid | float | Active grid power in producer counting (W). Negative = export. |
| 1002 | grid.Q_grid | float | Reactive grid power (VA) |
| 1008 | grid.f_grid | float | Grid frequency (Hz) |
| 1010-1014 | grid.U_L1/L2/L3_grid | float | Per-phase grid voltages (V) |
| 1016-1020 | grid.I_L1/L2/L3_grid | float | Per-phase grid currents (A) |
| 1022 | grid.E_grid_imp | float | Grid import energy counter (kWh) |
| 1024 | grid.E_grid_exp | float | Grid export energy counter (kWh) |
| 1026 | grid.P_aux | float | Auxiliary consumer power - HVAC, displays (W) |
Base URL: https://api.enexa.io/v1/
Current Version: v1 (stable)
Deprecation Policy: 12 months notice
Version is included in the URL path. Breaking changes will increment the major version. Enexa will maintain backwards compatibility within a major version.
Telemetry: 2 requests/second per site
Commands: 10 requests/minute per site
Burst: 5 requests allowed
HTTP 429 returned when exceeded. Retry-After header indicates wait time. Contact Enexa to increase limits for high-throughput sites.
4xx Client Errors
5xx Server Errors
On 5xx errors: retry with exponential backoff (1s, 2s, 4s, 8s, max 60s). After 5 failures, switch to LOCAL AUTONOMOUS mode.
POST /api/v1/heartbeat
Frequency: Every 10 seconds
{ "site_id": "...", "status": "healthy", "uptime_s": 3600, "mode": "cloud_connected" }
If Enexa receives no heartbeat for 30 seconds, the site is marked OFFLINE. Alerts are sent to configured operators.
GET /api/v1/health
Response: { "status": "ok", "time": "..." }
Middleware should check Enexa health before critical operations. If unhealthy, cache commands locally and retry later.
Live status of all sites - used by NOC operators and site managers
Command execution tracking - used for troubleshooting and audit
Value showcase - used for customer reporting and ROI validation
Scenario analysis - used for demonstrating optimization value
The optimizer runs every 15 minutes and requires these exact fields to compute optimal dispatch:
// Required inputs for optimization (per 15-min slot)
{
// Battery State (per unit)
"soc_pct": 65, // Current SOC - where are we now?
"max_charge_w": 110000, // Can we charge? How much headroom?
"max_discharge_w": 110000, // Can we discharge? How much capacity?
"energy_empty_kwh": 45.2, // How much can we sell?
"energy_full_kwh": 12.8, // How much can we buy?
// Grid State
"P_grid_w": 35000, // Current grid power (cost driver)
"P_aux_w": 3200, // Reserved for HVAC (reduces capacity)
// EV State (if active session)
"plug_state": 1, // Is EV connected?
"P_EV_max_w": 150000, // What does EV want?
"soc_EV_pct": 45, // Where is EV at? (optional)
// External Inputs (from Enexa)
"epex_price_eur_mwh": 85.5, // Current electricity price
"forecast_prices": [...], // Next 24h price forecast
"grid_carbon_g_kwh": 320 // Optional: carbon intensity
}