Skip to main content

Cordex HP Controller (Alpha / EnerSys)

The Cordex HP driver polls an Alpha Technologies (EnerSys) Cordex HP system controller — CXC HP, CXCi HP, or CXCM1 HP — over Modbus TCP and surfaces DC system telemetry as device attributes with history enabled. The Limited Data Set (battery voltage / current / runtime, total load, AC mains, alarm thresholds, system mode) lives at fixed input-register addresses; an extra_register_map lets you pull additional points out of the full DC System and AMPS HP2 register tables.

The integration is read-only. The Cordex HP does not implement Modbus Holding Registers (FC03), so setpoint changes need the controller's HTTP control plane and are out of scope here.

Status​

Built against the Alpha Cordex HP Modbus Integrator Guide 0350114-J0 Rev K (08/2021). Limited Data Set addresses are stable across firmware revisions; full data set addresses are dynamic per install.

Prerequisites​

  • Modbus enabled on the CXC HP. By default it is off — turn it on under Controller > Configure Controller > Communications > Modbus in the controller web UI.
  • Note the Limited Data Set Device ID (default 247) and any System Device IDs (one per DC system; one per AMPS HP2 inverter system).
  • Outbound TCP/502 from the GEM controller to the Cordex HP IP.
  • For points outside the Limited Data Set: export the controller's Modbus Table CSV from the web UI and translate it into the extra_register_map JSON shape below.

Setup​

  1. Enable Modbus on the controller. Note the configured byte order — the CXC HP default is Least significant bytes first, which maps to little_endian on this driver.
  2. Note the device IDs — Limited Data Set ID (default 247), DC System ID (typically 1), AMPS HP2 System ID(s) (typically 2+).
  3. Create the device — open Devices (System → Devices → Add Device) and pick the Cordex HP Controller (Alpha / EnerSys) driver. Set:
    • ip — controller IP
    • port — 502 (default)
    • limited_data_set_unit_id — match the controller (default 247)
    • byte_order — match the controller (default little_endian)
  4. (Optional) Add an extra register map for points beyond the Limited Data Set. Paste a JSON array into the extra_register_map attribute. Each entry: {name, unit_id, register, format, unit?, scale?, codes?}.
  5. Watch the device attributes populate after one polling cycle (default 10 s).
tip

The full DC System and AMPS HP2 register addresses are dynamic per install — the controller assigns them as inventory is added or removed. Always pull the live map from the controller's web UI rather than copying from another install. Use the controller's Re-number Modbus Table By Name button before importing if you need address stability across identical sites.

Attributes​

Device​

AttributeRequiredTypeNotes
ipyesstringController IP.
portnointTCP port. Default 502.
limited_data_set_unit_idnointModbus unit ID for the Limited Data Set. Default 247.
byte_ordernostringlittle_endian (default) | big_endian | mid_big | mid_little. Must match the controller.
polling_ratenointPoll interval in ms. Default 10000. Below 5000 ms can stress the controller under heavy alarm activity.
timeoutnointModbus request timeout in ms. Default 10000.
reconnect_timeoutnointDelay between reconnect attempts in ms. Default 3000.
extra_register_mapnojsonList of additional points to poll. See format below.

Limited Data Set (auto-populated)​

Each value is a 32-bit float spanning two consecutive input registers (30001..30036).

AttributeUnit
system_voltageV
total_load_currentA
total_capacity_installedA
system_mode_code— (numeric)
system_modestring (resolved label — see list below)
estimated_rectifier_ac_voltageV
estimated_battery_runtimemin
last_discharge_durationmin
output_voltage_low_alarm_limitV
output_voltage_high_alarm_limitV
battery_runtime_low_alarm_limitmin
ac_mains_voltage_low_alarm_limitV
ac_mains_voltage_high_alarm_limitV
battery_capacity_ratingAh
battery_average_temperature°C
battery_currentA
battery_temp_low_alarm_limit°C
battery_temp_high_alarm_limit°C
battery_charge_current_high_limitA

system_mode resolves the numeric system_mode_code to one of these exact strings — use them verbatim when writing triggers or conditions on plant state:

Unknown · NoBattery · Disconnected · Discharging · Conditioning · Charging · BatteryTest

A mains/AC-fail (the plant running off batteries) shows up as Discharging; a code the driver doesn't recognize is reported as Unknown(<n>).

Derived power (Power Flow)​

The Cordex reports volts and amps, not watts. After each poll the driver derives DC power on the bus (P = V × I) so the plant appears alongside other power devices in the Power Management dashboard. Each input is guarded against the null sentinel, so a missing reading is skipped rather than published as a bogus 0 W.

AttributeUnitRoleDerived from
load_power_wWpower.loadsystem_voltage × total_load_current
battery_power_wWpower.batterysystem_voltage × battery_current
Battery sign convention

battery_power_w follows the Cordex battery_current sign. Verify it against a discharge (AC-fail) event; if the sign is reversed, set metric_sign: 'inverted' on the registry row so the dashboard reads charge/discharge correctly. See Power Management — canonical metric roles.

Extra register map format​

[
{ "unit_id": 1, "name": "dc_battery_voltage", "register": 35157, "format": "float32", "unit": "V" },
{ "unit_id": 1, "name": "dc_battery_current", "register": 35159, "format": "float32", "unit": "A" },
{ "unit_id": 2, "name": "ampshp2_inv1_loading_w", "register": 36773, "format": "float32", "unit": "W" },
{ "unit_id": 2, "name": "ampshp2_inv1_ac_output_status", "register": 36775, "format": "float32",
"codes": { "0": "On", "1": "ManualOff", "2": "IrrecoverableError", "3": "RecoverableError" } }
]
FieldNotes
unit_idModbus unit ID for this point. Entries are read grouped by unit ID, and the unit is set on every read so a command issued mid-poll cannot redirect the next point.
nameAttribute name written to the device. An entry without a name, or whose register is missing or not a valid address, is skipped and logged once.
registerThe address from the controller's Modbus Table CSV, in Modicon 5-digit convention (e.g. 35157). The driver strips the table prefix to the zero-based protocol address automatically; the 6-digit extended form (300001+) is accepted too. The format field decides whether it is read as an input register, discrete input, or coil.
formatfloat32 | float64 | uint32 | int32 | input_status | coil.
unitOptional unit label.
scaleOptional numeric multiplier applied after read.
codesOptional integer→string lookup (e.g., AMPS HP2 AC Output Status).

Commands​

NameArgsDescription
get_status—Return last cached register values.
poll_now—Force an immediate poll cycle.
read_registeraddress, unit_idOne-off Modbus read.
read_input_registersaddress, length, unit_idBulk input register read.
read_input / read_inputsaddress, [length], unit_idDiscrete input read.
read_coil / read_coilsaddress, [length], unit_idCoil read.
scan_unit_idsstart, end, timeout_per_unit, test_registerProbe a unit ID range.
get_diagnostics / clear_diagnostics / get_comm_log—Driver-level Modbus diagnostics.

Known limitations​

  • Read-only. The controller does not support Modbus Holding Registers (FC03), so setpoint writes are not possible over Modbus.
  • Sentinel translation. 0xFFFFFFFF (NaN as float, -1 as int) means unknown and 999999999 means deprecated in the Cordex spec. Both are translated to null. A bare 0 is left as-is, since it is indistinguishable from a legitimate zero reading.
  • Dynamic full data set. Full DC System / AMPS HP2 register addresses are not stable across installs — the controller assigns them as inventory changes.
  • Single-master. Multiple unit IDs share one TCP connection and the driver flips slave ID per read group. Do not point a second Modbus master at the controller while this driver is polling.

Troubleshooting​

SymptomCheck
connection refused on 502Modbus is disabled on the controller. Enable it under Controller > Configure Controller > Communications > Modbus.
Limited Data Set values are all nullbyte_order is wrong. The CXC HP default is Least significant bytes first → little_endian.
Extra register map values look scrambledbyte_order mismatch, or the addresses were copied from a different install. Re-export from the live controller's Modbus Table CSV.
Connection alternates up/downPolling rate is too aggressive. Raise polling_rate to 10000+ ms during heavy alarm activity.
Some values read null after firmware updateInventory change may have shifted the dynamic register addresses. Re-export the Modbus Table CSV and update extra_register_map.
  • Modbus — generic Modbus device, scanner, and register browser
  • Power Management — generic energy dashboard the derived DC power feeds
  • Devices — device management (the Cordex HP is a single device with telemetry as device attributes; it creates no zones)