8 min read

Boat energy management using Victron and Home Assistant

The most important systems on modern cruising boats are the ones which generate, store, and distribute energy throughout the vessel. When we took delivery of our boat we immediately added a solar arch, lithium batteries, and a 5kw inverter to create a powerful enough electrical system to live off full-time.

The core of the system is a Victron Cerbo GX running Venus OS, a Victron BMV712 to manage batteries, and a Victron MPPT to manage solar panels. By itself, the Cerbo is already a wonderful device with a touchscreen to see/manage all the systems on the boat; which can also be conveniently connected to the local network and accessed over any web browser if you're not near the device itself.

http://venus.local

Additionally, Victron has a managed cloud service called VRM which can access the system remotely - provided that the system is online.

Victron VRM dashboard

What I wanted, though, was to integrate all the boat's energy management into Home Assistant - in order to have full end-to-end monitoring, logging, and remote control of the systems to be able to achieve full automation.

Coming into marine systems from a tech background, the most frustrating thing by far is that the entire marine industry is hell-bent on taking open systems and protocols and finding new and creative ways to make them proprietary, closed, and patented once again. Victron is a shining exception to this trend, presumably because they aren't specifically a marine company.

Every traditional marine system I've worked on aboard our boat has been a pain to work with, while every Victron system is an absolute joy. The Cerbo GX is the main thing that makes everything else possible, and by far the most important component in our network.

Some background on marine networks

The backbone of most marine networks runs on a communication standard called NMEA2000, and generally speaking any components that supports this standard will be able to read data from each other. NMEA is how your chart plotter reads your fuel tank sensors, and how your VHF radio reads the GPS position from your chart plotter, and so on. Not every component runs on NMEA, but the ones that do are relatively easy to work with.

The Victron Cerbo GX connects directly to its own components to ingest data from batteries, solar panels, etc – but it can also connect to the boat's NMEA2K backbone, giving it access to all of the data there, too.

When connected to your local network, the Cerbo can make data available to external devices over a standardised protocol called Modbus, which is a "marine flavour" of a more low-level networking protocol called CANbus.

Finally, Home Assistant supports reading and writing data with a native Modbus integration, and that's how all our systems end up talking to each other.

🏗️
Note: This level of networking is not remotely my area of expertise, so consider this a pretty high-level/crude overview.

Setting up networking on the Cerbo GX

The first thing to do is to connect your Cerbo GX to your LAN / router. You can do this over WiFi, but I would always opt for a direct Ethernet connection wherever possible - because it uses less power, is more reliable, and has lower latency. The Cerbo must have a dedicated IP address, so make sure you assign one within your router's DHCP configuration. (Beyond the scope of this post)

The next step is enabling Modbus. Victron don't assume that everyone will want to use Modbus, so it isn't enabled by default. To broadcast Modbus data to your LAN, you need to enable the feature within the Venus control panel by going to the settings.

Settings → Services → Modbus TCP → Enable

Then you will want to go into the submenu, and make a note of all the Modbus services that are running - and their respective IDs. These will be used for connecting and configuring, later.

Settings → Services → Modbus → Available services

Setting up Modbus in Home Assistant

Home Assistant has a native Modbus integration which is broadly compatible with any device. However, as with many Home Assistant integrations, the docs leave a lot to be desired and the examples are few and far between.

Modbus
Instructions on how to integrate Modbus and platforms.

The way Modbus works is with predefined IDs which can be queried to retrieve known values in known formats. How do you know which ID, value and format to use? Typically manufacturers put together a Modbus downloadable register list of every available value, and that's exactly what Victron have done.

The latest version of this file is available as an Excel spreadsheet and is downloadable from Victron's website, here. But I've occasionally had trouble with the website in the past, so here's a backup of the latest version that I have downloaded, too:

Then, in Home Assistant, these IDs can be used to connect to Victron services. For example, the code below tells Home Assistant that we have a Modbus hub (the cerbo) living on a particular IP address, and within that hub is a sensor, on slave "223" (this is the number you find in the Cerbo settings, above) and address "266" (this is in the spreadsheet).

The remaining attributes tell Home Assistant what type of data it is, and what format to display it in within the UI.

# Victron
modbus:
  - name: cerbo
    host: 192.168.1.100
    type: tcp
    port: 502

    sensors:
        # BMV
      - name: "Victron Battery Level"
        data_type: uint
        unit_of_measurement: "%"
        slave: 223
        address: 266
        scale: 0.1
        device_class: battery
        state_class: measurement
configuration.yaml

Once the config file is saved and HA restarted, you'll have new entities available which can be used in Home Assistant to build UI, charts, automations and alerts as with any other smart-home devices.

The left side of the dashboard, below, shows most of the Modbus sensors I have coming into Home Assistant. All of this data is available locally, with no internet connection, across any device (laptop, phone, tablet) as well as remotely from any location around the world - as long as the boat does have an internet connection (The subject of a future post).

Getting the data into Home Assistant is just the first step, and one that mostly brings convenience. But once the data is there, you have access to perform actions on or with the data which start to make things interesting.

Some example ideas, some of which I'll cover in future posts:

  • When battery is below 50% and AC Load is above 2,000W for 10 minutes, tell Alexa to announce to the boat that battery drain is too high over the speaker.
  • When battery is has been at 100% for over 10 minutes, automatically turn on the water heater for 20 minutes to use up some spare energy.
  • When battery is below 25% send "Battery critical" push notification to all designated mobile devices and email addresses, and start shutting down power-hungry devices.
  • When water tanks are below 30% have Alexa suggest running watermaker
  • When water tanks go from below 90% to above 95%, have Alexa announce that the water tanks are full (so you remember to turn off the dock water or watermaker)
  • Automatically turn off the Victron Inverter between 2am and 9am every night (This saves 45Ah of battery, per night!) — or if nobody is aboard, keep it off.
  • If connected to shore-power or generator, automatically turn on AC or water heaters to use available energy.
  • If AC load is coming close to exceeding the rated wattage of inverter, shut down devices in a particular order to stay under the threshold. Eg. Maybe disable the outlets first, so the oven/kettle that just turned on is promptly cut off.

You can imagine / come-up-with your own variations of these, pretty easily. Having access to energy management data unlocks a huge number of valuable options for full-time boat life, and even just monitoring systems when not aboard.

Full config

Here's my full Modbus config file for working with our Victron systems, feel free to copy / learn from it. It will need some modifications to work with your own setup.

# Victron
modbus:
  - name: cerbo
    host: 192.168.1.100
    type: tcp
    port: 502
    switches:
      - name: Inverter
        slave: 227
        address: 33
        command_on: 3
        command_off: 4
        verify:
          input_type: holding
          address: 33
          state_on: 3
          state_off: 4
    sensors:
      # SYSTEM
      - name: Inverter State
        slave: 227
        address: 33
        data_type: uint16
        scale: 1

      - name: "Victron Power Source"
        data_type: int16
        slave: 100
        address: 826
        scale: 1

      - name: "Victron Genset Load"
        data_type: int16
        unit_of_measurement: "W"
        slave: 100
        address: 823
        scale: 1
        device_class: power
        state_class: measurement

      - name: "Victron AC Consumption"
        data_type: uint16
        unit_of_measurement: "W"
        slave: 100
        address: 817
        scale: 1
        device_class: power
        state_class: measurement

      - name: "Victron DC Consumption"
        data_type: int16
        unit_of_measurement: "W"
        slave: 100
        address: 860
        scale: 1
        device_class: power
        state_class: measurement

      - name: "Victron Shore Power"
        data_type: int16
        unit_of_measurement: "W"
        slave: 100
        address: 820
        scale: 1
        device_class: power
        state_class: measurement

      - name: "Victron Home Battery voltage"
        data_type: uint16
        unit_of_measurement: "V"
        slave: 100
        address: 840
        scale: 0.1
        device_class: voltage
      - name: "Victron Home Battery Current"
        data_type: int16
        unit_of_measurement: "A"
        slave: 100
        address: 841
        scale: 0.1
        device_class: current
      - name: "Victron Home Battery Power"
        data_type: int16
        unit_of_measurement: "W"
        slave: 100
        address: 842
        scale: 1
        device_class: power
      - name: "Victron Home PV Power"
        data_type: uint16
        unit_of_measurement: "W"
        slave: 100
        address: 850
        scale: 1
        device_class: power

        # BMV
      - name: "Victron Home Battery SOC"
        data_type: uint16
        unit_of_measurement: "%"
        slave: 223
        address: 266
        scale: 0.1
        device_class: battery
        state_class: measurement
      - name: "Victron Home Time to go"
        data_type: uint16
        unit_of_measurement: "seconds"
        slave: 223
        address: 303
        scale: 100
      - name: "Victron Time since last full charge"
        data_type: uint16
        unit_of_measurement: "seconds"
        slave: 223
        address: 289
        scale: 0

        # MPPT Solar Arch
      - name: "Solar Voltage"
        data_type: uint16
        unit_of_measurement: "V"
        slave: 100
        address: 776
        scale: 0.01
        device_class: voltage
      - name: "Solar Current"
        data_type: int16
        unit_of_measurement: "A"
        slave: 100
        address: 777
        scale: 0.1
        device_class: current
      - name: "Solar Power"
        data_type: uint16
        unit_of_measurement: W
        slave: 100
        address: 789
        scale: 0.1
        device_class: power
        state_class: measurement
      - name: "Solar Operation mode"
        data_type: uint16
        slave: 100
        address: 791
        scale: 1
      - name: "Solar Yield today"
        data_type: uint16
        unit_of_measurement: "kW"
        slave: 100
        address: 784
        scale: 0.1
        precision: 3
        device_class: power
      - name: "Solar Max power today"
        data_type: uint16
        unit_of_measurement: "W"
        slave: 100
        address: 785
        scale: 1
        device_class: power
      - name: "Solar Yield yesterday"
        data_type: uint16
        unit_of_measurement: "W"
        slave: 100
        address: 786
        scale: 0.1
        precision: 3
        device_class: power
      - name: "Solar Max power yesterday"
        data_type: uint16
        unit_of_measurement: "W"
        slave: 100
        address: 787
        scale: 1
        device_class: power

        # Tanks
      - name: "Fuel Tank Port"
        data_type: uint16
        unit_of_measurement: "%"
        slave: 23
        address: 3004
        scale: 0.1
        device_class: humidity
      - name: "Fuel Tank Starboard"
        data_type: uint16
        unit_of_measurement: "%"
        slave: 22
        address: 3004
        scale: 0.1
        device_class: humidity
      - name: "Water Tank Aft"
        data_type: uint16
        unit_of_measurement: "%"
        slave: 20
        address: 3004
        scale: 0.1
        device_class: humidity
      - name: "Water Tank Fwd"
        data_type: uint16
        unit_of_measurement: "%"
        slave: 21
        address: 3004
        scale: 0.1
        device_class: humidity

        # GPS
      - name: "GPS Latitude"
        data_type: int32
        unit_of_measurement: "deg"
        slave: 100
        address: 2800
      - name: "GPS Longitude"
        data_type: int32
        unit_of_measurement: "deg"
        slave: 100
        address: 2802
      - name: "GPS Course"
        data_type: uint16
        unit_of_measurement: "deg"
        slave: 100
        address: 2804
        scale: 0.01
      - name: "GPS Speed"
        data_type: uint16
        unit_of_measurement: "m/s"
        slave: 100
        address: 2805
        scale: 0.01
      - name: "GPS Fix"
        data_type: uint16
        slave: 100
        address: 2806
      - name: "GPS Satellites"
        data_type: uint16
        slave: 100
        address: 2807
configuration.yaml