The Live MQTT control is meant for live control. For sending schedules ahead of time, see Scheduled MQTT Control instead.
This guide will help you configure MQTT on your SmartgridOne Controller to remotely control and monitor battery and solar panel installations.
I have a SmartgridOne Controller that I'd like to setup for MQTT Remote Control.
Before continuing, make sure your network and devices are ready by following the MQTT Setup guide.
Request the required Eniris MQTT username and password through the Eniris webshop before starting the configuration. Support tickets and SmartgridX/Insights are not provisioning channels for new MQTT credentials.
The fallback mechanism timeout tells the SmartgridOne Controller how long it should wait for new commands. When the SmartgridOne Controller stops receiving commands, it automatically picks up the default strategy after this timeout.
After, select all devices that you'd wish to include in MQTT Remote Control.
The MQTT Remote Control interface has now been activated on the SmartgridOne Controller.
We are now ready to send some basics commands using a simple example. The Status column tells you if any command is active.
A good first starting point would be to test your newly setup integration with a simple example.
This test code does a simple job of continuously sending the following commands:
The SmartgridOne Controller continuously responds with a 'feedback' message containing the observed grid and asset power values. This feature is also included in this example.
Please download the file below in your preferred Python IDE. Fill in your serial number and the MQTT credentials requested through the Eniris webshop, then execute the script:
When the above is successful, you can continue with sending other type of commands. All commands are described in our MQTT Remote Control Documentation.
This section details the MQTT messaging format and payload requirements for remotely controlling power policies on devices within the SmartgridOne Controller's network.
The MQTT topic used for sending commands is structured as follows:
standard1/rp_one_s/remoteControlMetrics/'controller SN'
Where 'controller SN' should be replaced with the actual serial number of the SmartgridOne Controller you intend to control.
Commands are sent as JSON payloads. The payload structure is designed to specify various power management policies and setpoints for different components of the smart grid system. Here is the outline of the payload with detailed field descriptions:
{
"extraTags": {
"nodeId": "<Controller SN>_site_0"
},
"time": "<Unix Timestamp>",
"fields": {
"<Component Policy>": "<Policy Type>",
"<Component Power Setpoint>": <Setpoint in watts>,
"site_<policy>": "<Value in watts>"
}
}
Multiple device types (e.g. batteries + solar) can be controlled at the same time.
Assets of the same type (e.g. two batteries) will be combined as one component. For example, when two 5 kWh batteries are installed, it will be treated as one 10 kWh battery.
Each component in the fields object can include a policy and a power setpoint. The following components can be controlled:
solar_policy and solar_power_setpoint_w:
storage_policy and storage_power_setpoint_w:
heat_pump_policy:
switched_load_policy:
variable_power_load_policy and variable_power_load_power_setpoint_w:
Instead of setting control strategies and setpoint, power limits can also be set for storage and solar devices.
For example:
{
"extraTags": {
"nodeId": "<Controller SN>_site_0"
},
"time": "<Unix Timestamp>",
"fields": {
"{prefix}_maxChargePower_W": <Max Charge Power W>,
"{prefix}_maxDischargePower_W": <Max Discharge Power W>,
"{prefix}_maxProductionPower_W": <Max Production Power W>,
}
}
where prefix is either storage, solar or the applicable device nodeID.
The site can be controlled seperately. The following site commands can be sent to the controller:
default or fallback
Remove any active site commandsexport
Set the site export limitimport
Set the site import limitsetpoint
A site setpoint can vary up to 5% in both directionssetpoint_A
Not yet implementedThe following variables are peak-shaving parameters, and will only be applied when the battery strategy is set to peak-shaving.
startChargeBelow_WstopChargeAbove_WstartDischargeAbove_WstopDischargeBelow_WA site setpoint is NOT compatible with an import/export limit.
For example:
{
"extraTags": {
"nodeId": "<Controller SN>_site_0"
},
"time": "<Unix Timestamp>",
"fields": {
"<Component Policy>": "<Policy Type>",
"<Component Power Setpoint>": <Setpoint in watts>,
"site_export": <Export Limit W>,
"site_import": <Import Limit W>,
"site_setpoint": <Setpoint W>,
"site_startChargeBelow_W": <Value_W>
}
}
Specific devices can also be controlled, instead of groups of devices based on their types. The message is identically structured:
nodeId_policy and nodeId_power_setpoint_wWhen two commands are sent to the same asset (e.g. one device-specific command to a solar inverter, and a command to all solar devices), the device-specific control method will take preference over the device type control.
For each component, if the _policy and _power_setpoint_w is not specified, the system will automatically use the fallback policy configured in the SmartgridOne Controller. This ensures that each device or device group operates safely and continues to function even if specific instructions are not provided.
If no command is being send at all, after 60 seconds (or configured timeout period), the default policies for assets will be reactivated.
An active command can be cancelled by sending a fallback command message.
A fallback command will cancel the existing command immediately and the SmartgridOne Controller will take over control of the installation. The executed policy depends on what is set in the SmartgridOne Controller Settings.
This can also be used in cases where a secondary control signal, such as a schedule, is used as a fallback.
Message examples:
{
"extraTags": {
"nodeId": "<Controller SN>_site_0"
},
"time": "<Unix Timestamp>",
"fields": {
"<Component Policy>": "fallback",
}
}
An empty command can be sent at all times to collect site information. This will not cancel the current command.
The empty command is structured as follows:
{
"extraTags": {
"nodeId": "<Controller SN>_site_0"
},
"time": "<Unix Timestamp>",
"fields": {}
}
Below is an example of a payload to set various policies and setpoints:
{
"extraTags": {
"nodeId": "OM12404080000000000_site_0"
},
"time": 1714652046,
"fields": {
"solar_policy": "setpoint",
"solar_power_setpoint_w": 5000,
"storage_policy": "setpoint",
"storage_power_setpoint_w": -5000
}
}
In this example, the solar power is set to generate up to 5000 watts, and the energy storage system is set to either charge or discharge at a rate of 5000 watts, depending on the sign of the setpoint value. If either the solar_policy or storage_policy were omitted, the respective device would revert to the default settings determined by the SmartgridOne Controller.
This section outlines the structure and content of the feedback messages sent by the SmartgridOne Controller via MQTT. These messages are published to the topic standard1/outbound/remoteControlMetrics/feedback/<Controller SN> after a command has been processed.
The feedback MQTT topic is structured as follows:
standard1/outbound/remoteControlMetrics/feedback/<Controller SN>
Where <Controller SN> should be replaced with the serial number of the SmartgridOne Controller that is sending the feedback.
All assets are grouped by their type. This means that two individual solar installations of 3 kW will be treated as one 6 kW asset.
Feedback messages are formatted as JSON payloads. These payloads provide detailed feedback on the state of the system after applying the setpoint commands, considering grid/device limits. Below is the structure of the feedback payload with descriptions of its fields:
{
"time": "<Unix Timestamp>",
"data": {
"state": {
"grid": {
"active_power_W": <Grid Active Power in Watts>,
"today_imported_energy_Wh": <Grid Imported Energy in Watt-hours>,
"today_exported_energy_Wh": <Grid Exported Energy in Watt-hours>,
"import_limit_W": <Grid Import Limit in Watts>,
"export_limit_W": <Grid Export Limit in Watts>,
},
"storage": {
"energy_stored_Wh": <Energy Stored in Watt-hours>,
"energy_capacity_Wh": <Total Energy Capacity in Watt-hours>,
"mean_soc_perc": <Mean State of Charge Percentage>,
"active_power_W": <Active Power in Watts>,
"executed_power_W": <Power Setpoint Sent to Devices in Watts>,
"executed_policy": <Policy Executed by the Controller>,
"max_charge_power_W": <Maximum Charge Power in Watts>,
"max_discharge_power_W": <Maximum Discharge Power in Watts>,
"today_charged_Wh": <Energy Charged Today in Watt-hours>,
"today_discharged_Wh": <Energy Discharged Today in Watt-hours>,
"realised_charge_power_W": <Adapted maximum charge power>,
"realised_discharge_power_W": <Adapted maximum discharge power>,
"constraint_ph0_label": <Constraint reason for limiting power setpoint>,
"errorCodes": <Error status messages per device>,
"nr_devices": <Number of Controlled Storage Devices Installed>
},
"solar": {
"active_power_W": <Solar Active Power in Watts>,
"executed_power_W": <Power Setpoint Sent to Devices in Watts>,
"executed_policy": <Policy Executed by the Controller>,
"capacity_W": <Solar Capacity in Watts>,
"today_energy_Wh": <Energy Produced Today in Watt-hours>,
"constraint_ph0_label": <Constraint reason for limiting power setpoint>,
"errorCodes": <Error status messages per device>,
"nr_devices": <Number of Controlled Solar Devices Installed>
},
"heat_pump": {
"executed_policy": <Policy Executed by the Controller>,
"operation_modes": <Heatpump Operation Modes>,
"executed_power_W": <Power Setpoint Sent to Devices in Watts>,
"constraint_ph0_label": <Constraint reason for limiting power setpoint>,
"errorCodes": <Error status messages per device>,
"nr_devices": <Number of Controlled Heat Pump Devices Installed>
},
"switched_load": {
"executed_policy": <Policy Executed by the Controller>,
"devices_on": <Number of Devices On>,
"devices_off": <Number of Devices Off>,
"executed_power_W": <Power Setpoint Sent to Devices in Watts>,
"constraint_ph0_label": <Constraint reason for limiting power setpoint>,
"errorCodes": <Error status messages per device>,
"nr_devices": <Number of Controlled Switched Load Devices Installed>
},
"variable_load": {
"active_power_W": <Power of the device in Watts>,
"ev_charging": <How many EVs are currently charging>,
"ev_not_charging": <How many EVs are currently unconnected>,
"executed_policy": <Policy Executed by the Controller>,
"executed_power_W": <Power Setpoint Sent to Devices in Watts>,
"ev_requiring_charge": <Does the EV require charge>,
"currentL1_A": <Current of the device on phase 1 in Ampere>,
"currentL2_A": <Current of the device on phase 2 in Ampere>,
"currentL3_A": <Current of the device on phase 3 in Ampere>,
"executed_current_A": <Current Setpoint Sent to Devices in Ampere>,
"today_charged_Wh": <Energy Charged Today in Watt-hours>,
"today_discharged_Wh": <Energy Discharged Today in Watt-hours>,
"total_charged_Wh": <Total Energy Charged in Watt-hours>,
"total_discharged_Wh": <Total Energy Discharged in Watt-hours>,
"min_charge_current_A": <Minimum Charge in Ampere>,
"max_charge_current_A": <Maximum Charge in Ampere>,
"allow_zero_current": <Does the Charger Support Pausing>,
"current_charging_session": {
"pluginTime": <The session start time>,
"endTime": <The session end time>,
"firstChargingStartTime": <The time when the vehicle first charged>,
"isFull": <Is the vehicle fully charged or not>,
"chargedEnergy_Ws": <How much energy has been charged this session>,
"usedPhases": <The list of phases used during charging>,
"historicMaxChargeCurrent_A": <The maximum current at which the vehicle was charged during the session>
},
"previous_charging_session": {
"pluginTime": <The session start time>,
"endTime": <The session end time>,
"firstChargingStartTime": <The time when the vehicle first charged>,
"isFull": <Is the vehicle fully charged or not>,
"chargedEnergy_Ws": <How much energy has been charged this session>,
"usedPhases": <The list of phases used during charging>,
"historicMaxChargeCurrent_A": <The maximum current at which the vehicle was charged during the session>
},
"constraint_ph0_label": <Constraint reason for limiting power setpoint>,
"errorCodes": <Error status messages per device>,
"nr_devices": <Number of Variable Power Load Devices Installed>
}
},
"error": {
<Errors occured during driver execution>
}
"response_code": <Response Code>
},
"fields": {},
"requestTime": "<Unix Timestamp>",
"time": "<Unix Timestamp>",
"siteNodeId": "<Controller SN>_site_0"
}
The setpoints sent by an external signal can be internally limited by the EMS. The table below gives an overview of possible constraints for the constraint_ph0_label feedback field.
| Label | Node Types | Description |
|---|---|---|
breaker_current | Site | Site level breaker current |
max_charge_current (EV) | EV | Maximum charge current limit. |
min_charge_current | EV | Minimum charge current limit. |
nom_current | EV | Device nominal current limit. |
max_export_power | Site | Site export limit |
max_import_power | Site | Site import limit |
max_charge_power | EV, Storage | Maximum charge power limit. |
max_discharge_power | Storage | Maximum discharge power limit. |
nom_charge_power | EV, Storage | Nominal charge power limit. |
nom_discharge_power | Storage | Nominal discharge power limit. |
nom_production_power | PV | Nominal production power limit. |
device_reported_max_charge_power | Storage | Device maximum charge power limit. |
device_reported_max_charge_current | Storage | Device maximum charge current limit. |
device_reported_max_discharge_power | Storage | Device maximum discharge power limit. |
device_reported_max_discharge_current | Storage | Device maximum charge current limit. |
ev_charging_suspended | EV | EV Charging is paused |
setpoint_power | All | The setpoint is the limiting factor - no internal constraints. |
high_soc_limit_charge_power | Storage | Charging is limited by the high battery SOC. |
low_soc_limit_discharge_power | Storage | Discharging is limited by the low battery SOC. |
soc_power_curve_max_charge_power | Storage | Charging is limited by the SOC power curve. |
soc_power_curve_max_discharge_power | Storage | Discharging is limited by the SOC power curve. |
too_low_soc_force_charge_power | Storage | Minimum charging power due to a too low SOC. |
peakshaving_charge_threshold | Storage | Charge due to peak-shaving-parameters. |
peakshaving_discharge_threshold | Storage | Discharge due to peak-shaving-parameters. |
self_consumption_charge_power | EV, Storage | Charge due to the self-consumption strategy. |
self_consumption_discharge_power | EV, Storage | Discharge due to the self-consumption strategy. |
self_consumption_load_power | Switched Load | Consume due to the self-consumption strategy. |
external_signal_device_power_consumption_limit | EV, Switched Load | External signal limits the device consumption. |
external_signal_device_power_production_limit | PV | External signal limits the device production. |
external_signal_battery_charge_power_limit | Storage | External signal limits the battery charging power. |
external_signal_battery_discharge_power_limit | Storage | External signal limits the battery discharging power. |
setpoint_current | EV | Current Setpoint limit. |
observed_max_current_demand | EV | Observed max current used by EV. |
near_fully_charged | EV | Current limited by a nearly full EV. |
fully_charged | EV | The EV is fully charged |
dynamic_derated_min_power | Storage | Setpoint is limited due to the device not being able to reach the expected setpoint power. |
dynamic_derated_max_power | Storage | Setpoint is limited due to the device not being able to reach the expected setpoint power. |
Error codes are grouped into ranges that indicate the general category of the problem:
| Range | Category |
|---|---|
-200 | Connection errors |
-300 | Response errors |
-500 | Driver errors |
-600 | Control errors |
The individual error codes are listed below.
Connection issues between the EMS and the device.
| Code | Label | Additional Fields |
|---|---|---|
-204 | Connection Refused | |
-209 | No Route To Host | |
-210 | No IP For MAC Address |
The device is connected, but its responses are invalid.
| Code | Label | Additional Fields |
|---|---|---|
-300 | Device Unavailable Error | |
-310 | No Response Error | |
-402 | Device Status Error | Message |
| Code | Label | Additional Fields |
|---|---|---|
-600 | Setpoint Ignored Error | |
-602 | Setpoint Rejected Error |
| Code | Label | Additional Fields |
|---|---|---|
-1000 | No Measurements | |
-1001 | No Power Measurements | |
-1003 | No Power Setpoint | |
-1005 | Setpoints Not Followed | nomPowerDeviation_frac, setpointDeviation_frac |
-1006 | Limits Not Followed |
When using MQTT, it is important to consider the differences in specifications between versions 3.1, 3.1.1, and 5.0, particularly regarding the broker’s behavior when clients publish to unauthorized topics.
According to the MQTT 3.1.1 specification (see OASIS MQTT 3.1.1 Specification, section MQTT-3.3.5-2), a broker must terminate the connection as soon as a client sends a PUBLISH to a topic for which it does not have permission. This behavior can lead to unexpected disconnections for clients attempting to publish to misconfigured or unauthorized topics.
In MQTT 3.1, this requirement is not present. When a client publishes to an unauthorized topic under this version, the broker typically ignores the message (silent drop) without terminating the connection. This makes MQTT 3.1 in some cases more suitable when robustness against configuration errors or temporarily missing permissions is more important than strict security enforcement.
Although MQTT 5.0 introduces the ability to work with reason codes (such as PUBACK with a refusal reason), this requires support on both the client and server sides. Migrating to MQTT 5.0 therefore involves additional implementation effort.
Consequences of Ignoring Compatibility: If a client connects using MQTT 3.1.1 and attempts to publish messages to unauthorized topics, the broker will abruptly terminate the session. This may lead to instability, loss of connectivity, or increased load due to repeated reconnect attempts.
Recommended Approach: For systems where clients may (temporarily) attempt to publish to unauthorized topics, or where error handling is not strictly implemented, we recommend using MQTT 3.1. This ensures more stable connections and avoids unintended disconnects during runtime.