Profile Format¶
A profile is a JSON document that maps Modbus registers to Home Assistant
entities. Profiles are loaded from the built-in profiles/ directory and from
<HA config>/sg_energy_hub/profiles/.
Top-level fields¶
| Field | Required | Meaning |
|---|---|---|
id |
yes | Stable identifier, lowercase a-z0-9_ |
name |
yes | Model name shown in the UI |
vendor |
yes | Manufacturer |
device_type |
yes | inverter, battery, heat_pump, energy_meter, system |
model_pattern |
no | Regex used for display and future discovery |
description |
no | Free text |
version |
no | Profile version, default 1.0.0 |
verified |
no | true only after testing against real hardware |
demo |
no | Marks the simulated profile; exactly one is allowed |
modbus_config |
no | Connection defaults |
registers |
yes | Non-empty list of register entries |
modbus_config¶
| Field | Default | Meaning |
|---|---|---|
default_port |
502 | TCP port |
unit_id |
1 | Modbus unit id |
byte_order |
big |
Byte order inside each 16-bit word |
word_order |
big |
Word order for 32/64-bit values |
timeout |
5 | Seconds |
Register fields¶
| Field | Required | Meaning |
|---|---|---|
address |
yes | 0–65535 |
name |
yes | Stable key, lowercase a-z0-9_ |
label |
no | Display name; defaults to the title-cased key |
type |
no | uint16, int16, uint32, int32, uint64, int64, float32, float64, string |
length |
for string |
Number of characters |
unit |
no | Unit such as W, kWh, %, °C |
scale |
no | Divisor, default 1 |
offset |
no | Added after scaling, default 0 |
precision |
no | Decimal places for display |
access |
no | ro (default) or rw |
function |
no | holding (default) or input |
device_class |
no | Home Assistant device class, e.g. power, energy, battery, temperature |
state_class |
no | measurement, total, total_increasing, or null |
icon |
no | Material icon |
entity_category |
no | diagnostic or config |
enabled_default |
no | Default true |
basic |
no | Default true; false requires Pro |
tier |
no | "pro" is shorthand for basic: false |
entity |
no | Default true; false reads the register but creates no entity |
enum |
no | Map of integer values to labels |
Scaling¶
scale is a divisor:
{"address": 500, "name": "pv1_power", "type": "uint16", "unit": "W", "scale": 10}
Raw 5000 becomes 500.0 W. Writing reverses the calculation.
Multi-register values¶
uint32, int32, float32 occupy two registers, uint64, int64,
float64 occupy four. word_order controls which word comes first:
big: high word first,little: low word first (common for many inverters).
byte_order controls the two bytes inside each word.
Enums¶
{
"address": 540,
"name": "heat_pump_status",
"type": "uint16",
"state_class": null,
"enum": {"0": "off", "1": "heating", "2": "cooling", "5": "fault"}
}
The sensor state is the mapped label. Unknown values are shown as the raw number.
Example¶
{
"id": "example_inverter",
"name": "Example Inverter",
"vendor": "Example",
"device_type": "inverter",
"model_pattern": "EX-.*",
"version": "0.1.0",
"verified": false,
"modbus_config": {
"default_port": 502,
"byte_order": "big",
"word_order": "little"
},
"registers": [
{
"address": 500,
"name": "pv_power",
"type": "uint16",
"unit": "W",
"scale": 10,
"device_class": "power",
"state_class": "measurement"
},
{
"address": 514,
"name": "battery_soc",
"type": "uint16",
"unit": "%",
"device_class": "battery",
"state_class": "measurement"
}
]
}
Validation rules¶
- Profile ids and register names must be unique.
- Register address ranges may not overlap within the same function code.
scalemay not be zero.lengthis only valid forstringregisters.enumis only valid for integer types.- The demo profile must be unique.
scripts/check_repository.pyenforces these rules in CI.