MQTT - dalathegreat/Battery-Emulator GitHub Wiki

Introduction

v5.0.0 introduces basic MQTT support. The battery emulator can now be configured to publish data to your MQTT broker and then be used in whatever way you choose. You can modify the battery emulator code to publish more data, less data, or other data, as well as subscribing to MQTT topics.

Main purpose for this implementation is better integration with popular home automation platforms such as Home Assistant, in order to for example keep track of battery temperature and cell deviation. If "MQTT" and "Home Assistant" are not familiar words, you will likely not benefit from this until you're up to speed on the current state of home automation.

Enabling MQTT in the software

To start using MQTT, make sure that the line #define MQTT is set in the USER_SETTINGS.h file. Here you can also specify the IP address for the server on the MQTT_SERVER line, and the port used on the MQTT_PORT line.

image

MQTT settings

The username and password for MQTT can be set in the USER_SETTINGS.cpp file. Incase you want to use no login info, set fields to NULL

image

Published data

Out of the box, the MQTT implementation publishes to a BE/info topic that holds SOC, SOH, min/max temperature and min/max cell voltage. On select battery implementations that update cell voltage data, all cell voltages are published in a separate BE/spec_data topic. Battery emulator events are published to BE/events topic. By default, all data is published with the retain flag set, which simplifies having e.g. MQTT Sensors in Home Assistant.

BE/info example payload (sensor configuration autodiscovery topic is avalilable for each value ):

{
  "SOC": 63.300,
  "StateOfHealth": 92.000,
  "temperature_min": 5.800,
  "temperature_max": 7.400,
  "cell_max_voltage": 3787,
  "cell_min_voltage": 3765
}

BE/spec_data example payload (has a autodiscovery topic):

{
"cell_voltages": [3779, 3780, 3782, 3767, 3783, 3769, 3782, 3768, 3782, 3777, 3782, 3776, 3781, 3776, 3775, 3765, 3782, 3776, 3782, 3777, 3773, 3765, 3774, 3768, 3773, 3765, 3772, 3771, 3773, 3772, 3772, 3768, 3773, 3772, 3772, 3767, 3772, 3778, 3784, 3778, 3773, 3769, 3773, 3767, 3783, 3769, 3782, 3769, 3779, 3777, 3775, 3777, 3774, 3774, 3780, 3767, 3773, 3770, 3773, 3769, 3775, 3765, 3777, 3777, 3783, 3774, 3787, 3776, 3776, 3775, 3784, 3767, 3778, 3763, 3776, 3763, 3784, 3773, 3778, 3767, 3777, 3771, 3787, 3775, 3783, 3774, 3784, 3772, 3781, 3773, 3780, 3773, 3773, 3766, 3773, 3765]
}

BE/events example payload (has a autodiscovery topic):

{
	"event_type": "RESET_SW",
	"severity": "INFO",
	"last_event": "9",
	"count": "1",
	"data": "3",
	"message": "Info: The board was reset via software, webserver or OTA. Normal operation",
	"milis": "10001"
}

Custom publishing

The SW supports publishing of whatever data you have to whatever topic you want, whenever and where ever you want (with some caveats). To avoid clashes in publications you should only publish from the main/loop() thread, i.e. only from functions that have their origin in the loop() function of Software.ino. This is because the current MQTT implementation uses a common global message buffer, so if you access it from another thread for some reason, it might clash with the recurring publication of general data.

To implement your own publishing code, use the mqtt_publish_retain() and snprintf() functions along with the mqtt_msg global buffer:

float my_float = 1.234f;
snprintf(mqtt_msg, sizeof(mqtt_msg), "{\"some_float_data\": %.3f}", my_float);
mqtt_publish_retain("category/subcategory/topic");

See online documentation for snprintf to understand the details. For one-shot messages there's nothing to consider, but when you need to build your message cumulatively/iteratively (for example with a loop or just line by line for some reason), basically with several calls to snprintf() you need to be careful with the two first parameters. See mqtt.cpp:publish_cell_data(), in the else clause for more info and a tricky example with cell voltages.

Discovery

If you want to implement discovery topics for your data, an example can be found in mqtt.cpp:publish_cell_data(), in the block below if (mqtt_first_transmission == true). The example is a bit complex since it publishes discovery topics for a dynamic amount of cell voltages, but it should sink in after staring at it for a few minutes. The current discovery topic is hardcoded to homeassistant/... which should probably be configurable in the future.

homeassistant/sensor/BE/cell_voltage96/config example payload:

{
	"name": "Battery Cell Voltage 96",
	"object_id": "be_battery_voltage_cell96",
	"unique_id": "BE_battery_voltage_cell96",
	"device_class": "voltage",
	"state_class": "measurement",
	"state_topic": "BE/spec_data",
	"unit_of_measurement": "V",
	"enabled_by_default": true,
	"expire_after": 240,
	"value_template": "{{ value_json.cell_voltages[95] }}",
	"device": {
		"identifiers": [
			"battery-emulator"
		],
		"manufacturer": "DalaTech",
		"model": "BatteryEmulator",
		"name": "Battery Emulator"
	},
	"origin": {
		"name": "BatteryEmulator",
		"sw": "7.6.0",
		"url": "https://github.com/dalathegreat/Battery-Emulator"
	}
}

homeassistant/sensor/BE/SOC/config example payload:

{
	"name": "SOC (scaled)",
	"state_topic": "BE/info",
	"unique_id": "BE_SOC",
	"object_id": "be_SOC",
	"value_template": "{{ value_json.SOC }}",
	"unit_of_measurement": "%",
	"device_class": "battery",
	"state_class": "measurement",
	"enabled_by_default": true,
	"expire_after": 240,
	"device": {
		"identifiers": [
			"battery-emulator"
		],
		"manufacturer": "DalaTech",
		"model": "BatteryEmulator",
		"name": "Battery Emulator"
	},
	"origin": {
		"name": "BatteryEmulator",
		"sw": "7.6.0",
		"url": "https://github.com/dalathegreat/Battery-Emulator"
	}
}

⚠️ NOTE: Entity availability (or rather unavailability) with discovery has not been tested

MQTT Sensor

All data plublished has a discovery topic so you dont have to configure anything on Home assistant. It's recommended your MQTT broker has persistence enabled to ensure the availability is retained when restarting HA.

You can use this for inspiration on how to implement your own MQTT data publishing and integrate it into Home Assistant without using discovery. Also, see the References section.

Subscriptions

Subscriptions are not supported at this time.

Usage

Ideas for usage would be charge/discharge automation (if your inverter supports charge/discharge limits from the battery), manipulating other functionality that the battery emulator has control over, or simply overriding data. Be creative but careful 😺

Limitations

  • Publishing is limited to QoS 0
  • Subscription is limited to QoS 0 or 1
  • Last Will and Testament (LWT) is not supported (Birth could be, but doesn't help much)

Future improvments

  • Changing to a more complete MQTT library
  • Investigating availability when using discovery without LWT, which might be solved in your MQTT Broker instead

Inspiration

A fairly complex Home Assistant example that uses MQTT for cell voltages, SOC and temperature. Other graphs are based on a mix of MQTT, Fronius Modbus TCP and an internal Fronius API:

HA_prt_sc

Another Battery-Emulator dashboard on Home Assistant:

image

Breaking Changes

Changes in PRs #566 and #567 introduced on v7.6.0 have introduced updates to the MQTT topic naming conventions for Home Assistant (HA), sensor names, and the addition of a prefix to the cell information. These updates bring consistency across sensor object IDs but may break compatibility for users already using MQTT in HA.

For new installations, the default values are now set in usersettings.cpp as follows:

const char* mqtt_topic_name = "BE";

const char* mqtt_object_id_prefix = "be_";

const char* mqtt_device_name = "Battery Emulator";

To keep previous naming conventions and maintain backward compatibility, you can comment out the following line in user_settings.h:

#define MQTT_MANUAL_TOPIC_OBJECT_NAME

However, please note that the cell voltage sensor IDs will still change, as they now include the prefix to align with other sensors.

If you prefer to maintain the current sensor configurations in HA and avoid any updates, you can disable the autodiscovery feature by commenting out the following line in user_settings.h:

#define HA_AUTODISCOVERY

With HA_AUTODISCOVERY commented out, configuration topics will not be sent to HA, thereby preventing the creation of new sensors.

Summary To retain the existing configuration from installations before v7.6.0 in upcoming updates, comment out the following lines:

#define MQTT_MANUAL_TOPIC_OBJECT_NAME

#define HA_AUTODISCOVERY

References

  • Home Assistant MQTT overview Covers brokers, discovery, various configuration and Home Assistant services related to MQTT

  • Home Assistant MQTT Sensor Explains manual (non-discovery) setup of MQTT related sensors. In a way offers more control over details compared to using Discovery, but requires more work

  • PubSubClient The library currently used for MQTT