v3.9.2 Home Battery not working using MQTT
Describe the bug On version v.3.9.2 the Home Battery Integration no longer seems to be updating. Im feeding updates to the master SmartEVSE via MQTT using a custom Domoticz script.
Basically my script sends the HomeBatteryCurrent value when it changes using moquitto_sub. I can verify the the message being processed in mosquitto using mosquitto_sub.
Manually sending a value also does not update the SmartEVSE.
Sending:
mosquitto_pub -h 10.12.40.32 -t 'SmartEVSE-15494/Set/HomeBatteryCurrent' -m '-16'
Verifying:
mosquitto_sub -h 10.12.40.32 -t 'SmartEVSE-15494/Set/HomeBatteryCurrent'
Upload your config
{
"version": "v3.9.2",
"serialnr": 6678,
"mode": "SOLAR",
"mode_id": 2,
"car_connected": true,
"wifi": {
"status": "WL_CONNECTED",
"ssid": "XXXXXXXXXX",
"rssi": -79,
"bssid": "XX:XX:XX:XX:XX:XX"
},
"evse": {
"temp": 40,
"temp_max": 65,
"connected": true,
"access": 1,
"mode": 2,
"loadbl": 1,
"pwm": 264,
"custombutton": false,
"solar_stop_timer": 0,
"state": "Charging",
"state_id": 2,
"error": "None",
"error_id": 0,
"rfidreader": "Disabled",
"nrofphases": 1,
"rfid": "Not Installed"
},
"settings": {
"charge_current": 155,
"override_current": 0,
"current_min": 6,
"current_max": 16,
"current_main": 25,
"current_max_circuit": 160,
"current_max_sum_mains": 600,
"max_sum_mains_time": 0,
"solar_max_import": 2,
"solar_start_current": 3,
"solar_stop_time": 10,
"enable_C2": "Auto",
"mains_meter": "Sensorbox",
"starttime": 0,
"stoptime": 0,
"repeat": 0,
"lcdlock": 1,
"lock": 0,
"cablelock": 0
},
"mqtt": {
"host": "10.12.40.32",
"port": 1883,
"topic_prefix": "SmartEVSE-15494",
"username": "",
"password_set": false,
"status": "Connected"
},
"ocpp": {
"mode": "Disabled",
"backend_url": "",
"cb_id": "",
"auth_key": "",
"auto_auth": "Disabled",
"auto_auth_idtag": "",
"status": "Disconnected"
},
"home_battery": {
"current": 0,
"last_update": 0
},
"ev_meter": {
"description": "Eastron3P",
"address": 101,
"import_active_power": 3.4,
"total_kwh": 4216.6,
"charged_kwh": 1.7,
"currents": {
"TOTAL": 150,
"L1": 150,
"L2": 0,
"L3": 0
},
"import_active_energy": 4216.6,
"export_active_energy": 0
},
"mains_meter": {
"import_active_energy": 0,
"export_active_energy": 0
},
"phase_currents": {
"TOTAL": 16,
"L1": 102,
"L2": -43,
"L3": -43,
"last_data_update": 1758359603,
"original_data": {
"TOTAL": 16,
"L1": 102,
"L2": -43,
"L3": -43
}
},
"backlight": {
"timer": 120,
"status": "ON"
},
"color": {
"off": {
"R": 0,
"G": 0,
"B": 0
},
"normal": {
"R": 0,
"G": 255,
"B": 0
},
"smart": {
"R": 0,
"G": 255,
"B": 0
},
"solar": {
"R": 255,
"G": 170,
"B": 0
},
"custom": {
"R": 0,
"G": 0,
"B": 255
}
}
}
Upload a debug log Flash the debug version of the firmware (see https://github.com/dingo35/SmartEVSE-3.5/blob/master/SmartEVSE-3/HowToFlash.txt), telnet to your device, capture the debug log, cut it so that it shows JUST BEFORE and JUST AFTER the problem arises, and upload it here.
To Reproduce Steps to reproduce the behavior:
- Both master and slave are in solar mode
- problem is always there
Expected behavior HomeBattery is updated
Screenshots Only add screenshots if it adds any information, e.g. when you are reporting a problem on the webserver screen.
I was setting this up from my Victron > MQTT > SmartEVSE and also had problems when I followed the instructions. It seems you need to do it a little different.
Instead of: SmartEVSE-{serial}/Set/HomeBatteryCurrent I had to use: SmartEVSE/{serial}/Set/HomeBatteryCurrent
But I do have another problem with the home-battery value, it seems that a push of the smart-meter L1/L2/L3 values resets the home-battery value (even before the 10 sec timeout). I tried this with MQTT and REST, both seem to have the same outcome: the smart-meter update resets the home-battery value.
Hi Alex,
I tried your suggestion and this does not work. Additionally I can confirm that the SmartEVSE itself is indeed posting data to the MQTT broker itself on the correct topics and my messages are indeed processed in the same topic:
SmartEVSE-15494/connected online
SmartEVSE-15494/Mode Solar
SmartEVSE-15494/MaxCurrent 160
SmartEVSE-15494/ChargeCurrent 160
SmartEVSE-15494/ChargeCurrentOverride 0
SmartEVSE-15494/NrOfPhases 3
SmartEVSE-15494/Access Allow
SmartEVSE-15494/RFID Not Installed
SmartEVSE-15494/State Ready to Charge
SmartEVSE-15494/Error None
SmartEVSE-15494/EVPlugState Disconnected
SmartEVSE-15494/WiFiSSID XXXXXXXXXXX
SmartEVSE-15494/WiFiBSSID XX:XX:XX:XX:XX:XX
SmartEVSE-15494/EVEnergyCharged 30277
SmartEVSE-15494/OCPP Disabled
SmartEVSE-15494/LEDColorOff 0,0,0
SmartEVSE-15494/LEDColorNormal 0,255,0
SmartEVSE-15494/LEDColorSmart 0,255,0
SmartEVSE-15494/LEDColorSolar 255,170,0
SmartEVSE-15494/LEDColorCustom 0,0,255
SmartEVSE-15494/ESPUptime 2226160
SmartEVSE-15494/WiFiRSSI -74
**SmartEVSE-15494/Set/HomeBatteryCurrent 71**
SmartEVSE-15494/MainsCurrentL1 47
SmartEVSE-15494/MainsCurrentL2 -29
SmartEVSE-15494/MainsCurrentL3 -29
SmartEVSE-15494/MainsImportActiveEnergy 0
SmartEVSE-15494/MainsExportActiveEnergy 0
SmartEVSE-15494/EVCurrentL1 0
SmartEVSE-15494/EVCurrentL2 0
SmartEVSE-15494/EVCurrentL3 0
SmartEVSE-15494/EVImportActiveEnergy 4248260
SmartEVSE-15494/EVExportActiveEnergy 0
SmartEVSE-15494/ESPTemp 25
SmartEVSE-15494/Mode Solar
SmartEVSE-15494/MaxCurrent 160
SmartEVSE-15494/CustomButton Off
SmartEVSE-15494/ChargeCurrent 160
SmartEVSE-15494/ChargeCurrentOverride 0
SmartEVSE-15494/NrOfPhases 3
SmartEVSE-15494/Access Allow
SmartEVSE-15494/RFID Not Installed
SmartEVSE-15494/State Ready to Charge
SmartEVSE-15494/Error None
SmartEVSE-15494/EVPlugState Disconnected
SmartEVSE-15494/WiFiSSID XXXXXXXXXXX
SmartEVSE-15494/WiFiBSSID XX:XX:XX:XX:XX:XX
SmartEVSE-15494/EVChargePower 0
SmartEVSE-15494/EVEnergyCharged 30277
SmartEVSE-15494/EVTotalEnergyCharged 4248260
SmartEVSE-15494/HomeBatteryCurrent 71
SmartEVSE-15494/OCPP Disabled
SmartEVSE-15494/OCPPConnection Disconnected
SmartEVSE-15494/LEDColorOff 0,0,0
SmartEVSE-15494/LEDColorNormal 0,255,0
SmartEVSE-15494/LEDColorSmart 0,255,0
SmartEVSE-15494/LEDColorSolar 255,170,0
SmartEVSE-15494/LEDColorCustom 0,0,255
Any more information I can provide to get this going?
Sorry for not replying any sooner, will look into it asap.
FYI, I'm using v.3.9.2 and have just integrated my home battery into smartEVSE through MQTT. For me this is working.
This is how my webpage looks like:
Purpose is to give priority to the home battery charging so I only transmit negative currents (discharging home battery) to the smartEVSE. There's some sun now so that's why it's currently marked as idle with also 0 current from the grid.
I had an issue at first when I sent decimal values. The transmitted data on SmartEVSE/Set/HomeBatteryCurrent needs to be an integer.
Here is my python script that forwards the current from my Deye modbus integration to the smartEVSE topic for your reference:
#!/usr/bin/env python3
"""
MQTT Forwarder Script
Listens to inverter/sensor/sun3p-battery_output_power topic,
transforms the value by dividing by -230,
and publishes to SmartEVSE/Set/HomeBatteryCurrent topic.
"""
import json
import logging
import os
import signal
import sys
import time
from typing import Optional
import paho.mqtt.client as mqtt
import yaml
class MQTTForwarder:
def __init__(self, config_path: str = "config.yml"):
"""Initialize the MQTT forwarder with configuration."""
self.config = self._load_config(config_path)
self.client = None
self.running = False
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
self.logger = logging.getLogger(__name__)
# Topics
self.source_topic = "inverter/sensor/sun3p-battery_output_power/state"
self.target_topic = "SmartEVSE/Set/HomeBatteryCurrent"
# Transformation factor (need to publish in deci-Ampères)
self.divisor = -23
def _load_config(self, config_path: str) -> dict:
"""Load configuration from YAML file or environment variables."""
config = {
'mqtt': {
'broker': os.getenv('MQTT_BROKER', '192.168.2.9'),
'port': int(os.getenv('MQTT_PORT', 1883)),
'username': os.getenv('MQTT_USERNAME'),
'password': os.getenv('MQTT_PASSWORD'),
'keepalive': int(os.getenv('MQTT_KEEPALIVE', 60)),
'client_id': os.getenv('MQTT_CLIENT_ID', 'mqtt-forwarder')
}
}
# Try to load from config file if it exists
if os.path.exists(config_path):
try:
with open(config_path, 'r') as f:
file_config = yaml.safe_load(f)
if file_config:
config.update(file_config)
except Exception as e:
self.logger.warning(f"Could not load config file {config_path}: {e}")
return config
def on_connect(self, client, userdata, flags, rc):
"""Callback for when the client receives a CONNACK response."""
if rc == 0:
self.logger.info("Connected to MQTT broker successfully")
# Subscribe to the source topic
client.subscribe(self.source_topic)
self.logger.info(f"Subscribed to topic: {self.source_topic}")
else:
self.logger.error(f"Failed to connect to MQTT broker. Return code: {rc}")
def on_disconnect(self, client, userdata, rc):
"""Callback for when the client disconnects."""
if rc != 0:
self.logger.warning("Unexpected disconnection from MQTT broker")
else:
self.logger.info("Disconnected from MQTT broker")
def on_message(self, client, userdata, msg):
"""Callback for when a message is received."""
try:
topic = msg.topic
payload = msg.payload.decode('utf-8')
self.logger.info(f"Received message on {topic}: {payload}")
# Only process messages from our source topic
if topic == self.source_topic:
self.process_battery_power_message(payload)
except Exception as e:
self.logger.error(f"Error processing message: {e}")
def process_battery_power_message(self, payload: str):
"""Process the battery power message and forward transformed value."""
try:
# Try to parse the payload as a number
try:
power_value = float(payload)
except ValueError:
# If direct conversion fails, try to parse as JSON
try:
data = json.loads(payload)
if isinstance(data, dict) and 'value' in data:
power_value = float(data['value'])
else:
power_value = float(data)
except (json.JSONDecodeError, KeyError, TypeError):
self.logger.error(f"Could not parse power value from payload: {payload}")
return
# Transform the value: divide by -230
# Only forward negative values, meaning the battery is discharging
transformed_value = min(power_value / self.divisor, 0)
self.logger.info(f"Transforming {power_value} -> {transformed_value}")
# Publish the transformed value
self.publish_transformed_value(transformed_value)
except Exception as e:
self.logger.error(f"Error processing battery power message: {e}")
def publish_transformed_value(self, value: float):
"""Publish the transformed value to the target topic."""
try:
# Format the value to 0 decimal places
formatted_value = f"{value:.0f}"
result = self.client.publish(self.target_topic, formatted_value)
if result.rc == mqtt.MQTT_ERR_SUCCESS:
self.logger.info(f"Published {formatted_value} to {self.target_topic}")
else:
self.logger.error(f"Failed to publish message. Return code: {result.rc}")
except Exception as e:
self.logger.error(f"Error publishing transformed value: {e}")
def setup_mqtt_client(self):
"""Set up and configure the MQTT client."""
self.client = mqtt.Client(client_id=self.config['mqtt']['client_id'])
# Set callbacks
self.client.on_connect = self.on_connect
self.client.on_disconnect = self.on_disconnect
self.client.on_message = self.on_message
# Set authentication if provided
if self.config['mqtt'].get('username') and self.config['mqtt'].get('password'):
self.client.username_pw_set(
self.config['mqtt']['username'],
self.config['mqtt']['password']
)
self.logger.info("MQTT authentication configured")
def connect_to_broker(self):
"""Connect to the MQTT broker."""
try:
broker = self.config['mqtt']['broker']
port = self.config['mqtt']['port']
keepalive = self.config['mqtt']['keepalive']
self.logger.info(f"Connecting to MQTT broker at {broker}:{port}")
self.client.connect(broker, port, keepalive)
except Exception as e:
self.logger.error(f"Failed to connect to MQTT broker: {e}")
raise
def signal_handler(self, signum, frame):
"""Handle shutdown signals gracefully."""
self.logger.info(f"Received signal {signum}, shutting down...")
self.running = False
if self.client:
self.client.disconnect()
def run(self):
"""Main run loop."""
# Set up signal handlers for graceful shutdown
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
try:
# Set up MQTT client
self.setup_mqtt_client()
# Connect to broker
self.connect_to_broker()
# Start the network loop
self.client.loop_start()
self.running = True
self.logger.info("MQTT Forwarder started. Press Ctrl+C to stop.")
# Keep the main thread alive
while self.running:
time.sleep(1)
except KeyboardInterrupt:
self.logger.info("Received keyboard interrupt")
except Exception as e:
self.logger.error(f"Unexpected error: {e}")
finally:
self.cleanup()
def cleanup(self):
"""Clean up resources."""
self.logger.info("Cleaning up...")
if self.client:
self.client.loop_stop()
self.client.disconnect()
def main():
"""Main entry point."""
forwarder = MQTTForwarder()
forwarder.run()
if __name__ == "__main__":
main()