I wanted to consolidate my experience of connection my Victron Grid Connected MultiPlus II (or any Victron inverter) into HA. I then extended that into EMHASS to allow manage of import/export.
My Hardware:
- Victron MulitPlus II 5.0 (x3)
- Victron SmartShunt (500A)
- Victron CerboGX (but you can use a GX MP, or Raspberri Pi)
- Victron Smart Meter to monitor AC loads. (not needed if your solar is Victron, or AC coupled on ACout, and your entire house load is also on ACout. If you have Solar or loads on ACin, you need the smart meter).
- 80kw of 3v LifePO4 Chinese Cells
- 5x Chinese BMSās
- HA (mine runs as HAos on a Virtual Machine on my NAS, but any HA install will do).
- Mosquitto Broker is installed on HA and operating.(add ons). (auto start, watchdog turned ON)
Assumptions:
-
Your Victron setup is working, connected on on the same ethernet as the HA
-
Your Victron Inverter/Shunt/etc are all connected to your GX Device (Victron setup outside scope of this guide)
-
Youāve assigned static IPās to your Victron GX device and HA
-
Constant internet connection is NOT required
-
You have installed the ESS Grid Assistant on your Victron Inverters, and ESS is available in your GX Device. This menu will show in your GX device.
-
If you have solar, your Victron GX device is aware of the Solar, and it shows on the GX device. (I have Fronius AC Coupled solar, the the GX device found it with no setup)
-
I am single phase. if your 3 phase, you will need to copy quite a few parameters or modify.
How this works:
The Victron gear is fully responsible for managing the load, solar, batteries and monitoring of AC state. The HA is simply a co-pilot of the Victron, leveraging the ESS Assistant on the Victron device, and just feeding instructions to it. We also capture the monitoring details for HA to record and render.
The communication layer between HA and Victron GX (which in turn talks to all the Victron gear, on the Victron Network) is via a method called MQTT, which is a very basic instructional set that HA does quite well. (additional ModBus reading: https://www.victronenergy.com/live/ccgx:modbustcp_faq)
There are 2 main parameters when using MQTT and Victron. The Device ID, which is literally the physical Victron Device, and the Address ID, which is a parameter that is read only or writeable, which is set by Victron.
Device IDās are assigned by the Victron GX device, and Address IDās are set by Victron. Full list of Victron Addresses available here by requesting the ModBus TCP List (delivered by email instantly).
In HA, the only variable we can play with and write back to Victron is the ESS Set Point. this is a number in watts. ie/ +5000 is pull 5000W from Grid. -5000 is Export 5000W from the Grid (solar first and then batteries).
That updates this value in Victron:
If ESS is enabled, you will have this menu in your GX Device.
Step 1: Enable MQTT on your Victron GX device.
Step 2: Indentify the Device IDās on your Victron Network
Step 3: Enable HomeAssistant to communicate with your Victron GX Device.
Add the following code to your Configuration.yaml on HA, update your Device IDās and IP, and reboot the entire HA device.
modbus:
- name: victron
type: tcp
host: 192.168.10.137 # use the IP address of your CCGX
port: 502
sensors:
- name: 'ESS Grid Target' #This is the value your Inverter will attempt to import/export to and from the grid AFTER it takes into account your load and solar. This is the only writeable value.
unit_of_measurement: "W"
slave: 100 #HUB - Slave is your device ID you found when looking in the Device List on the Victron GX.
address: 2700 #ESS Control Loop Set Point
data_type: uint16
scan_interval: 5
device_class: power
- name: 'Victron AC L1' #I am single phase, if your 3 phase, you will need to add this 3 times and update the addresses using the link above for the full address list
unit_of_measurement: "W"
slave: 100 #HUB
address: 817 #AC Consumption L1
data_type: uint16
scan_interval: 5
device_class: power
- name: 'Victron Grid Load'
unit_of_measurement: "W"
slave: 100 #HUB
address: 820 #GridL1 Net
data_type: int16
scan_interval: 5
device_class: power
- name: 'Victron Energy from Grid'
unit_of_measurement: "kWh"
slave: 30 #GRID METER NOTE THE DIFFERENT SLAVE ID
address: 2603 #Energy From Netowrk L1
data_type: uint16
scale: 0.01
precision: 1
scan_interval: 5
device_class: energy
state_class: total_increasing
- name: 'Victron Energy to Grid'
unit_of_measurement: "kWh"
slave: 30 #GRID METER
address: 2606 #L1 Energy to Network
data_type: uint16
scale: 0.01
precision: 1
scan_interval: 5
device_class: energy
state_class: total_increasing
- name: 'Victron Energy Meter Voltage'
unit_of_measurement: "V"
slave: 30 #GRID METER
address: 2616 #Grid Meter Voltage
data_type: uint16
scale: 0.1
precision: 1
scan_interval: 5
device_class: voltage
state_class: total_increasing
- name: 'Victron Energy Meter Amperage'
unit_of_measurement: "A"
slave: 30 #GRID METER
address: 2617 #Grid Meter Amps
data_type: int16
scale: 0.1
precision: 1
scan_interval: 5
device_class: current
state_class: total_increasing
- name: 'Victron Solar power'
unit_of_measurement: "W"
slave: 100 #HUB
address: 850
data_type: uint16
device_class: power
- name: 'Victron ESS Minimum SoC setpoint'
unit_of_measurement: "%"
data_type: uint16
slave: 100 #HUB
address: 2901
scan_interval: 5
scale: 0.1
- name: 'Victron Maximum System Grid Feed In'
unit_of_measurement: "W"
data_type: uint16
slave: 100 #HUB
address: 2706
scale: 0.01
device_class: power
# command_on: 4000
# command_off: 40
# verify_state: false
#Battery
- name: 'Victron Battery current'
unit_of_measurement: "A"
slave: 100 #HUB
address: 841
data_type: int16
scale: 0.1
precision: 0
device_class: current
- name: 'Victron Battery Power System'
unit_of_measurement: "W"
slave: 100 #HUB
address: 842
data_type: int16
scale: 1.0
precision: 0
device_class: power
- name: 'Victron Charge Power System'
unit_of_measurement: "W"
slave: 100 #HUB
address: 860
data_type: int16
scale: 10.0
precision: 0
device_class: power
- name: 'Victron Battery State of Charge System'
unit_of_measurement: "%"
slave: 100 #HUB
address: 843
data_type: uint16
scale: 1
precision: 0
- name: 'Victron Inverter AC IN L1 V'
unit_of_measurement: "V"
slave: 227
address: 3
data_type: uint16
scale: 0.1
precision: 1
device_class: voltage
- name: 'Victron Inverter AC IN L1 A'
unit_of_measurement: "A"
slave: 227
address: 6
data_type: uint16
scale: 0.1
precision: 1
device_class: current
- name: 'Victron Inverter Max Over V Feed In L1'
unit_of_measurement: "V"
slave: 227
address: 66
data_type: uint16
scale: 0.1
precision: 1
device_class: voltage
- name: 'Victron Battery Voltage'
unit_of_measurement: "V"
slave: 226
address: 259
data_type: uint16
scale: 0.01
precision: 1
device_class: voltage
- name: 'Victron Battery Amperage'
unit_of_measurement: "A"
slave: 226
address: 261
data_type: uint16
scale: 0.1
precision: 1
device_class: current
- name: 'Victron Battery Consumed Amphours'
unit_of_measurement: "A"
slave: 226
address: 265
data_type: uint16
scale: 0.1
precision: 1
device_class: current
- name: 'Victron Battery State Of Charge'
unit_of_measurement: "%"
slave: 226
address: 266
data_type: uint16
scale: 0.1
precision: 1
device_class: power
- name: 'Victron Battery Capacity'
unit_of_measurement: "A"
slave: 226
address: 309
data_type: uint16
scale: 0.1
precision: 1
device_class: current
Step 4: Check its connected.
At this point, you should be able to search under entities in HA for Victron, and a good old list of values and data should be coming in. Congrats. Youāve connected Victron and HA together. Now, lets get that Grid Set point sorted.
If at this point you dont have data coming in, STOP. You need to troubleshoot why.
Step 5: Lets setup a slider
The slider is my way of easily in the UI being able to update the ESS Grid Set Point. You can choose your own destiny, but this is how I did it.
In Configuration.Yaml, add the following and reboot the entire HA device.
input_number:
input_current_slider:
name: ESS Grid Target Value
min: -15000 #update this to your maximum inverter capacity
max: 15000 #update this to your maximum inverter capacity
step: 100 #this is the increment of the slider in watts. It can be as low as increments of 10.
We now have a slider, but we need to connect it to Victron.
Step 6: Automations to bring it together
We need to setup 3 automations to connect the Slider to Victron, and do some maths.
Automation 1: This automations sets your Input Slider in HA to the value in Victron. (in case you update it in the Victron UI)
alias: 990.3 Input Current Limiter - Updater
trigger:
- platform: state
entity_id: sensor.input_current_limit
action:
- service: input_number.set_value
target:
entity_id: input_number.input_current_slider
data:
value: "{{ states('sensor.input_current_limit') | int }}"
Automation 2: Send the Input Slider value to Victron if its below 0
We do some maths on this one, as Victron doesnāt expect negatives, its just reverse from 65536 and the victron works it out on the fly. 65536 = 0W, 65535 = -1W, 64536 = -1000W etc. (Dont even ask me how bloody long this took to work out)
alias: 990.1 ESS Grid Set Point - SEND NEGATIVE
description: ""
trigger:
- platform: state
entity_id: input_number.input_current_slider
condition:
- condition: numeric_state
entity_id: input_number.input_current_slider
below: "0"
action:
- service: modbus.write_register
data:
address: 2700
unit: 100
value: "{{ states('input_number.input_current_slider') | float + 65536 }}"
hub: victron
mode: single
Automation 3: Send the Input Slider value to Victron if its 0 or above
alias: 990.2 ESS Grid Set Point - SEND POSITIVE
description: ""
trigger:
- platform: state
entity_id: input_number.input_current_slider
condition:
- condition: numeric_state
entity_id: input_number.input_current_slider
above: "-0.01"
action:
- service: modbus.write_register
data:
address: 2700
unit: 100
value: "{{ states('input_number.input_current_slider') | float }}"
hub: victron
mode: single
OK, So at this point you have:
- Connected Victron to HA
- Enabled a UI Slider to manage and view the ESS Setting
- Setup automations to apply data changes in either device to and from each other
At this point you can start the fun of building dashboards and automations on the new data set your receiving.
For those playing in the EMHASS space. I dont want to get into setting up EMHASS, but my script for those playing at home is below. I call post_amber_forecast daily at 5.30am, and I can MPC every 5 mins. This works, but I`m still working on some of the parameters.
### EMHASS ADD ON SCRIPT in Configuration.yaml
shell_command:
dayahead_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{}' http://localhost:5000/action/dayahead-optim"
publish_data: "curl -i -H \"Content-Type: application/json\" -X POST -d '{}' http://localhost:5000/action/publish-data "
post_amber_forecast: "curl -i -H 'Content-Type: application/json' -X POST -d '{\"prod_price_forecast\":{{(
state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)
}},\"load_cost_forecast\":{{(
state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)
}}}' http://localhost:5000/action/dayahead-optim"
post_mpc_optim: "curl -i -H \"Content-Type: application/json\" -X POST -d '{\"load_cost_forecast\":{{(
([states('sensor.amber_general_price')|float(0)] +
state_attr('sensor.amber_general_forecast', 'forecasts') |map(attribute='per_kwh')|list)[:48])
}}, \"prod_price_forecast\":{{(
([states('sensor.amber_feed_in_price')|float(0)] +
state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list)[:48])
}}, \"prediction_horizon\":{{min(48,
(state_attr('sensor.amber_feed_in_forecast', 'forecasts')|map(attribute='per_kwh')|list|length)+1)
}},\"soc_init\":{{states('sensor.victron_battery_state_of_charge')|float(0)/100}},\"soc_final\":0.05,\"def_total_hours\":[8,3,2,2]}' http://localhost:5000/action/naive-mpc-optim"
If you get stuck, comment below. I set this up over a long period of time, so I may have forgot/missed something along the way.
So, a massive thank you to @markpurcell as well for his help with EMHASS.