Get consumption from Victron Modbus

Is it possible to get consumption from modbus?
ie, the bottom right value here:
image

I can’t find anything on the spreadsheet.

I see 2 similar questions on the Victron forum, without answers:


Wild guess, those values resides on VrM, and I don’t think they have a API you can use to get the value. The list is modbus registers that resides on the multi or other hardware components, so you can pull that.

I would suggest you bull your own accumulator in HA.

Unless @plonkster knows of a better way to get those values.

There is a component in the GX device called vrmlogger, and that has a kwhdeltas component that counts how much the energy counters change, and sends it up to vrm. VRM calculates the actual use.

This data is not available on modbus. But the energy counters themselves are. So you can build your own.

For some devices the energy counters just count upwards forever (like a car’s odo meter, resetting to zero after it maxes out). For others, it restarts at zero after a power cycle (the Multi is like this). So your code needs to be able to handle the situation where the new value is lower than the old one.

Usually the way you deal with this is to assume there was a restart at zero. Then, because you don’t know where the counter loops over, you essentially ignore the old counter and just assume the old reading was zero. Of course this is a little bit lossy (whatever was in the counter before the restart is lost now), but in practice it’s small enough that it bothers nobody.

1 Like

Thanks

For the energy counters, are you referring to this modbus register?

Its great knowing someone that knows… thanks.

1 Like

I use Home Assistant to grab the data from Modbus with these sensors:

#Modbus sensors for Victron sensors
  - 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" 

I calculate some of the other ones using template sensors:

  - 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 %}

And then finally I convert the instantaneous values (W) to kWh using the integration sensor:

#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

One thing to note is that the modbus sensors update only once every 30s. So the values won’t be as accurate as in VRM, but it works well enough.

End result:

image

Edit: Sorry, forgot to add: the monthly totals are done using the utility_meter component of Home Assistant:

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
4 Likes

I really like what you have done here, great job and thanks for sharing…

Pleasure! Happy to share other config on how to change grid-setpoint (which I use to “force charge” the batteries from the grid) and of course the Minimum SOC, but didn’t want to derail the thread here too much.

1 Like

Please share that too

Awesome, thanks!

Dashboard is coming together nicely…



image

3 Likes

Looking great @MongooseMan!!

Here’s the switch config for the “force charge”-- from user “Sinbad” on the Victron community:

Setting the grid target point on register 2700 will make the ESS system charge up the batteries with the difference between the grid target and the load. Dropping the target register down again returns to “normal” operation.

(Sinbad is also posting on MyBroadband under the same username, and have a number of posts of his setup around the forum).

switch:
    #Victron force charge
  - platform: modbus
    registers:
    - name: Force Charge
      hub: victron
      slave: 100
      register: 2700
      command_on: 5000
      command_off: 20
      verify_state: false

The minimum SOC of charge I set with the following automation, based on the value of the Input select :

automation:
- alias: Set Victron ESS Minimum SOC from input select
  trigger:
    platform: state
    entity_id: input_select.victron_ess_minimum_soc
  action:
    service: modbus.write_register
    data_template:
      unit: 100
      value: '{{ states(''input_select.victron_ess_minimum_soc'')|int * 10 }}'
      hub: victron
      address: 2901
   
  
- alias: Set input select from Victron ESS Minimum SOC
  trigger:
    platform: state
    entity_id: sensor.victron_ess_minimum_soc
  action:
    service: input_select.select_option
    data_template:
      entity_id: input_select.victron_ess_minimum_soc
      option: '{{ states(sensor.victron_ess_minimum_soc) }}'

The input select itself is just a list of values from 20 - 100 in increments of 5 (I don’t go lower than 20).

input_select:
  victron_ess_minimum_soc:
    name: Victron ESS Minimum SoC
    options:
      - 20
      - 25
      - 30
      - 35
      - 40
      - 45
      - 50
      - 55
      - 60
      - 65
      - 70
      - 75
      - 80
      - 85
      - 90
      - 95 
      - 100
4 Likes

Nice, that’s useful.

From what I can see, the “Force Charge” switch isn’t really needed (if you’re willing to change the Min Soc % up, and then down again once you’ve reached where you want to get to). Is that right?

@ebendl Wow, thank you so much for sharing this, it will help me immensely! Answers so many of the questions I had when it comes to how to implement automations and templating in HA!

Yep, that’s correct.

It was some of my first experiments with Home Assistant and Victron. I also played around with it in conjunction with my solar geyser’s element to basically run the geyser on a cloudy day but not use the batteries.

But in my mind, the min SOC approach is better since you still get to use all the PV you can and only use what is needed from the grid.

It’s still something that I’ll keep as a backup – much simpler for my wife to flip the switch and charge the batteries if I’m not home and she wants to make sure there’s power for whatever reason than to tell her to set minimum SOC levels etc.

Glad to help!

Another one that is extremely cool for use with Home Assistant and a PV system, is the Solcast sensor service and custom component somebody developed for HA. In the interest of not derailing this thread I posted a new topic here: Solcast and Home Assistant - IOT (The internet of things) - Energy Talk

1 Like

Will have a look, thanks. My next project (after I figured this one out) will be to integrate my DSC alarm system with HA. It seems to be possible…

Thanks for sharing @ebendl!

Do you know if it is possible to change the Multi’s charge current using modbus registers?

Not sure, unfortunately. Here’s a spreadsheet with all of the registers: Victron GX product range [Victron Energy]

You can change the total max charge current (register 2705, unit/slave id=0 or 100). But that will affect solar chargers too.

You can get even more creative. The entire thing is set up in /opt/victronenergy/dbus-modbustcp/attributes.csv. The dbus path you want to write (on vebus) is /Dc/0/MaxChargeCurrent.

Unfortunately, if you don’t have a managed battery (eg lead acid), then you will also be fighting systemcalc, which also wants to write that path… so more hackery would be required.