Get consumption from Victron Modbus

Does anyone know whether it is possible to change the ESS state from, for example, “Optimised (with BatteryLife)” to “Keep Batteries Charged” using ModBus? Thanks for @ebendl HA code, I was able to implement a few things I needed, so I would like to continue using the ModBus service as far as possible…

Yes. Change whatever register corresponds with /Settings/CGwacs/BatteryLife/State, to:

1 = Optimised with battery life
9 = Keep Batteries Charged
10 = Optimised without battery life.

1 Like

Amazing! I saw that, but I wasn’t sure (because there were many other states in the description as well).

It’s three state machines cobbled together. States 1-8 are used by batterylife, state 9 is to keep charged, and state 10 and up is used by no-batterylife. If you set it to any number inside the range, the state machine will react within the next second and change it to what it should be.

1 Like

Hey, thanks for the example. Under which node would I place this snippet? Or do you have a link to a complete snippet? Thanks.

Hi Jarettj,

I should really put it up somewhere! Here’s the previous snippets again, with the “main” node for each:

#Modbus sensors for Victron sensors
sensor:
  - platform: modbus
    registers:
      - name: "Victron Battery" #Battery SOC
        hub: victron
        data_type: uint
        unit_of_measurement: "%"
        slave: 100
        register: 843
        scale: 1
      - name: "Victron Current Power Usage"
        hub: victron
        data_type: uint
        unit_of_measurement: "W"
        slave: 100
        register: 817
        scale: 1
      - name: "Victron Grid Power"
        hub: victron
        data_type: int
        unit_of_measurement: "W"
        slave: 100
        register: 820
        scale: 1
      - name: "Victron Battery Power"
        hub: victron
        data_type: int
        unit_of_measurement: "W"
        slave: 100
        register: 842
        scale: 1
      - name: "Victron Battery State"
        hub: victron
        data_type: uint
        slave: 100
        register: 844
        scale: 1
      - name: "Victron PV power"
        hub: victron
        data_type: uint
        unit_of_measurement: "W"
        slave: 100
        register: 850
        scale: 1
      - name: "Victron ESS BatteryLife state"
        hub: victron
        data_type: uint
        slave: 100
        register: 2900
        scale: 1
      - name: "Victron ESS Minimum SOC"
        hub: victron
        data_type: uint
        slave: 100
        register: 2901
        scale: 0.1
        #VEBus devices = Multiplus = UnitID 242 = Device Instance 261 
      - name: "Victron Grid voltage"
        hub: victron
        data_type: uint
        slave: 242
        register: 3
        scale: 0.1
        unit_of_measurement: "V"      
      - name: "Victron Essential usage"
        hub: victron
        data_type: int
        slave: 242
        register: 23
        scale: 10
        unit_of_measurement: "W"      
      - name: "Victron VEBus Input Power 1"
        hub: victron
        data_type: int
        slave: 242
        register: 12
        scale: 10
        unit_of_measurement: "W"      
      - name: "Victron VEBus State"
        hub: victron
        data_type: uint
        slave: 242
        register: 31
        scale: 1
      - name: "Victron VEBus Error"
        hub: victron
        data_type: uint
        slave: 242
        register: 32
        scale: 1
      - name: "Victron energy meter"
        hub: victron
        data_type: int
        slave: 30
        register: 2600
        unit_of_measurement: "W" 
      - name: "Victron Grid Setpoint"
        hub: victron
        data_type: int
        slave: 100
        register: 2700
        unit_of_measurement: "W" 
  - platform: template
    sensors:
    #Victron template sensors
          victron_non_essential_usage:
            friendly_name: 'None essential usage'
            value_template: >
                {{ (states("sensor.victron_energy_meter") | float - states("sensor.victron_vebus_input_power_1") | float ) | abs }}
            unit_of_measurement: 'W'
          victron_grid_usage:
            friendly_name: 'Grid usage'
            value_template: >
              {% if float(states("sensor.victron_grid_power")) > 0 %}
                {{ (states("sensor.victron_grid_power") | float | round (0) ) }}
              {% else %}
                0
              {% endif %}        
            unit_of_measurement: 'W'
      victron_batterylife_status:
        friendly_name: "BatteryLife Status"
        value_template: >-
          {% if is_state('sensor.victron_ess_batterylife_state', '0') %}
            Unused, BL disabled
          {% elif is_state('sensor.victron_ess_batterylife_state', '1') %}
            Restarting 
          {% elif is_state('sensor.victron_ess_batterylife_state', '2') %}
            Self-consumption
          {% elif is_state('sensor.victron_ess_batterylife_state', '3') %}
            Self-consumption
          {% elif is_state('sensor.victron_ess_batterylife_state', '4') %}
            Self-consumption
          {% elif is_state('sensor.victron_ess_batterylife_state', '5') %}
            Discharge disabled
          {% elif is_state('sensor.victron_ess_batterylife_state', '6') %}
            Force charge
          {% elif is_state('sensor.victron_ess_batterylife_state', '7') %}
            Sustain
          {% elif is_state('sensor.victron_ess_batterylife_state', '9') %}
            Keep batteries charged   
          {% elif is_state('sensor.victron_ess_batterylife_state', '10') %}
            BL Disabled
          {% elif is_state('sensor.victron_ess_batterylife_state', '11') %}
            BL Disabled (Low SoC) 
          {% else %}
            Unknown - {{ states("sensor.victron_ess_batterylife_state") }}
          {% endif %}
      victron_inverter_state:
        friendly_name: "Inverter State"
        value_template: >-
          {% if is_state('sensor.victron_vebus_state', '0') %}
            Off
          {% elif is_state('sensor.victron_vebus_state', '1') %}
            Low Power
          {% elif is_state('sensor.victron_vebus_state', '2') %}
            Fault
          {% elif is_state('sensor.victron_vebus_state', '3') %}
            Bulk
          {% elif is_state('sensor.victron_vebus_state', '4') %}
            Absorption
          {% elif is_state('sensor.victron_vebus_state', '5') %}
            Float
          {% elif is_state('sensor.victron_vebus_state', '6') %}
            Storage
          {% elif is_state('sensor.victron_vebus_state', '7') %}
            Equalize
          {% elif is_state('sensor.victron_vebus_state', '8') %}
            Passthru
          {% elif is_state('sensor.victron_vebus_state', '9') %}
            Inverting
          {% elif is_state('sensor.victron_vebus_state', '10') %}
            Power assist
          {% elif is_state('sensor.victron_vebus_state', '11') %}
            Power supply
          {% elif is_state('sensor.victron_vebus_state', '252') %}
            Bulk protection
          {% else %}
            Unknown - {{ states('sensor.victron_vebus_state') }}
          {% endif %}
      victron_inverter_error:
        friendly_name: "Inverter Error"
        value_template: >-
          {% if is_state('sensor.victron_vebus_error', '0') %}
            No error
          {% elif is_state('sensor.victron_vebus_error', '1') %}
            Device is switched off because one of the other phases in the system has switched off
          {% elif is_state('sensor.victron_vebus_error', '2') %}
            New and old types MK2 are mixed in the system
          {% elif is_state('sensor.victron_vebus_error', '3') %}
            Not all- or more than- the expected devices were found in the system
          {% elif is_state('sensor.victron_vebus_error', '4') %}
            No other device whatsoever detected
          {% elif is_state('sensor.victron_vebus_error', '5') %}
            Overvoltage on AC-ou
          {% elif is_state('sensor.victron_vebus_error', '6') %}
            Error in DDC Program
          {% elif is_state('sensor.victron_vebus_error', '7') %}
            VE.Bus BMS connected- which requires an Assistant- but no assistant found
          {% elif is_state('sensor.victron_vebus_error', '10') %}
            System time synchronisation problem occurred
          {% elif is_state('sensor.victron_vebus_error', '14') %}
            Device cannot transmit data
          {% elif is_state('sensor.victron_vebus_error', '16') %}
            Dongle missing
          {% elif is_state('sensor.victron_vebus_error', '17') %}
            One of the devices assumed master status because the original master failed
          {% elif is_state('sensor.victron_vebus_error', '18') %}
            AC Overvoltage on the output of a slave has occurred while aready switched off
          {% elif is_state('sensor.victron_vebus_error', '22') %}
            This device cannot function as a slave
          {% elif is_state('sensor.victron_vebus_error', '24') %}
            Switch-over system protection initiated
          {% elif is_state('sensor.victron_vebus_error', '25') %}
            Firmware incompatibility
          {% elif is_state('sensor.victron_vebus_error', '25') %}
            Internal error
          {% else %}
            Unknown - {{ states('sensor.victron_vebus_error') }}
          {% endif %}
#Victron energy sensors (from instant W to energy)
  - platform: integration
    source: sensor.victron_pv_power
    name: 'Victron PV energy'
    unit_prefix: k
    round: 2

  - platform: integration
    source: sensor.victron_grid_power
    name: 'Victron Grid energy'
    unit_prefix: k
    round: 2

  - platform: integration
    source: sensor.victron_current_power_usage
    name: 'Victron total home energy'
    unit_prefix: k
    round: 2

utility_meter:
  victron_pv_energy_daily:
    source: sensor.victron_pv_energy
    cycle: daily
  victron_pv_energy_monthly:
    source: sensor.victron_pv_energy
    cycle: monthly
  victron_home_energy_monthly:
    source: sensor.victron_total_home_energy
    cycle: monthly
  victron_home_energy_daily:
    source: sensor.victron_total_home_energy
    cycle: daily
  victron_grid_energy_monthly:
    source: sensor.victron_grid_energy
    cycle: monthly
  victron_grid_energy_daily:
    source: sensor.victron_grid_energy
    cycle: daily
1 Like

Wow! Thanks for the quick response. Best place would be github.com. You can create a snippet for all to see and mod/comment/star/like etc. :smiley:

Might even evolve into a project :wink:

Cool dashboard @MongooseMan especially with the Rand savings addition

I presume you’re using tariffs in the HA utility meter…mind sharing your config

It’s a lot more manual than that :slight_smile:

I basically track monthly kWh (both solar and grid) and have a template sensor I use to convert those into a monthly cost (without solar) and a monthly cost (with solar) and therefore a saving (formulae below using CT tariffs).

monthly_solar_saving:
      friendly_name: "Monthly Solar Saving"
      value_template: >-
        {{ 
           (([states('sensor.solar_energy_monthly')|float * 0.98 + states('sensor.grid_energy_monthly')|float, 600000]|min * 2.11 / 1000)
         + ([states('sensor.solar_energy_monthly')|float * 0.98 + states('sensor.grid_energy_monthly')|float - 600000, 0]|max * 2.9 / 1000)
         - ([states('sensor.grid_energy_monthly')|float, 600000]|min * 2.11 / 1000)
         - ([states('sensor.grid_energy_monthly')|float - 600000, 0]|max * 2.9 / 1000))
        }}

I then do a monthly “true-up” using the VRM portal, and update the Total kWh and savings for each.
Another template sensor then uses that to calculate running total costs and savings

total_solar_saving_current:
      friendly_name: "Total Solar Saving"
      value_template: >-
        R {{ ((states('input_number.total_solar_saving')| float + states('sensor.monthly_solar_saving')| float)) | round(2) }}

It’s something I keep meaning to update (it’ll break the next time tariffs change, for example) but it’s working well enough for now.

It’s not a source of truth, VRM fulfills that purpose, but it is a nice headsup monitor of what’s going on, more or less.

Thanks, definitely quite a process you have there…might give it a bash also not looking for perfection just some ball park estimates will do.

Also stumbled upon the power-wheel-card on GitHub power-wheel-card/README.md at f3e34e1aa263bf48b40e5557528733e247528787 · gurbyz/power-wheel-card · GitHub

You can plug in tariffs e.t.c. it has a couple of views for power, energy and money you can configure but not 100% sure if it’s suited for non-net metering environments like we have in SA, also not particularly keen on the overall appearance and battery support is still in beta

@ebendl am i mistaking or the value you have are onlye for one phase from the Victron ?

Sorry for the late reply! Yes, I have a single-phase system…

Ok thx, i was hoping you had a solution how to see the total power usage from all phases coz that is not availble from modbus, i guess i have to calculate it myself.

@ebendl Did you integrate your Victron data into the new energy dashboard if so how ? Do you have the sensors you used for that ?

Hi @donnib - I started but still need to do the battery in/battery out sensors. Still my aim to do it somewhere over the weekend or so - will post when I have everything set up.

1 Like

So I did end up doing the Energy dashboard last night:

Doesn’t quite match what’s in VRM - at least in terms of consumption:

1 Like

I think the numbers don’t match cause HA adds any excess solar to consumption but ignores efficiency. 10kWh solar is 8.5kWh on the ac side.

You got some YAML examples? I know @Sarel.Wagner was looking to see how to add the battery.

These are the modbus sensors:

modbus:
  name: victron
  host: <IP>
  type: tcp
  port: 502
  switches:
    - name: Force Charge
      slave: 100
      address: 2700
      command_on: 5000
      command_off: 20
      verify: 
  sensors:
  - name: "Victron Current Power Usage"
    data_type: uint
    unit_of_measurement: "W"
    device_class: power
    slave: 100
    address: 817
    scale: 1
  - name: "Victron Grid Power"
    data_type: int
    unit_of_measurement: "W"
    device_class: power    
    slave: 100
    address: 820
    scale: 1
  - name: "Victron Battery Power"
    data_type: int
    unit_of_measurement: "W"
    device_class: power    
    slave: 100
    address: 842
    scale: 1
  - name: "Victron PV power"
    data_type: uint
    unit_of_measurement: "W"
    device_class: power    
    slave: 100
    address: 850
    scale: 1
  - name: "Victron Essential usage"
    data_type: int
    slave: 242
    address: 23
    scale: 10
    unit_of_measurement: "W"
    device_class: power    
  - name: "Victron VEBus Input Power 1"
    data_type: int
    slave: 242
    address: 12
    scale: 10
    unit_of_measurement: "W"
    device_class: power    

Then I split the battery power into two using a template sensor, and isolate the power coming in from the grid:

  - platform: template
    sensors:
      victron_battery_in:
        friendly_name: 'Victron battery in'
        value_template: >
          {% if float(states("sensor.victron_battery_power")) > 0 %}
            {{ (states("sensor.victron_battery_power") | float | round(0) ) }} 
          {% else %}
            0
          {% endif %}        
        unit_of_measurement: 'W'
        device_class: power
      victron_battery_out:
        friendly_name: 'Victron battery out'
        value_template: >
          {% if float(states("sensor.victron_battery_power")) < 0 %}
            {{ (states("sensor.victron_battery_power") | float | round(0) ) | abs }} 
          {% else %}
            0
          {% endif %}       
        unit_of_measurement: 'W'
        device_class: power
      victron_grid_usage:
        friendly_name: 'Grid usage'
        value_template: >
          {% if float(states("sensor.victron_grid_power")) > 0 %}
            {{ (states("sensor.victron_grid_power") | float | round (0) ) }}
          {% else %}
            0
          {% endif %}        
        unit_of_measurement: 'W'
        device_class: power

Do note the device_class:power – doing this makes sure that the integration sensor is set to device_class: energy which you need to be able to use them in the Energy settings.

Next I integrate the instantaneous power (W) usage into energy (kWh) using the integration sensors:

#Victron energy sensors (from instant W to energy)
  - platform: integration
    source: sensor.victron_pv_power
    name: 'Victron PV energy'
    unit_prefix: k
    round: 2

  - platform: integration
    source: sensor.victron_grid_power
    name: 'Victron Grid energy'
    unit_prefix: k
    round: 2

  - platform: integration
    source: sensor.victron_current_power_usage
    name: 'Victron total home energy'
    unit_prefix: k
    round: 2
    
  - platform: integration
    source: sensor.victron_battery_in
    name: 'Victron battery in energy'
    unit_prefix: k
    round: 2

  - platform: integration
    source: sensor.victron_battery_out
    name: 'Victron battery out energy'
    unit_prefix: k
    round: 2

This is what you get:

That being said, there’s still a big difference between VRM and what HA calculates, especially for the battery part.

image (if I take “consumed battery” - “battery in energy”, I get 0.51 kWh which is a far cry from 0.04kWh in VRM.

1 Like

VRM does a lot of fudging. Well, not VRM so much as vrmlogger. Every 15 minutes it gets a bunch of values from energy counters, and it has to decide how much of that PV went to loads, and how much went into the battery, and it may well decide that all of it went to loads, because for 5 minutes there was a big load, even though for the other 10 minutes there wasn’t a big load and most of it really went into the batteries (and was taken out again for said big load).

It is not perfect, but in general it is good enough.