Victron - BMV700 and MPPT - Serial USB to MQTT (and file) - Needs Improvement - But works

For those integrating VE-DIRECT Victron USB Devices.

I have (with the help of others on the net and HA Community) a working system for reading a USB victron device plugged into a Linux machine and displaying in HA front end VIA MQTT.

The setup is rather convoluted and I’m sure could be streamlined by someone clever., I have just strung a few things together…

I have scripts run from systemd at boot which reload once an hour to purge the ever growing printed files.

#############################################
The BMV700 Battery Meter to MQTT files:
#############################################

These three files are located in folder /startup/bmv

1st script

“BMV-serial-run.sh”

is to initiate the USB VE-Direct cable to print data using a VE-Direct script (vedirect.py) to file “bmv700.txt”

File: BMV-serial-run.sh

#!/bin/sh
cd /startup/bmv ; 
python vedirect.py --port /dev/ttyUSB_BMV1 > bmv700.txt

This setup relies on you to reserve USB device IDs using /etc/udev/rules.d/ for the VE-Direct Serial devices.

File which does the clever serial printing:

vedirect.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os, serial, argparse

class vedirect:

    def __init__(self, serialport, timeout):
        self.serialport = serialport
        self.ser = serial.Serial(serialport, 19200, timeout=timeout)
        self.header1 = '\r'
        self.header2 = '\n'
        self.hexmarker = ':'
        self.delimiter = '\t'
        self.key = ''
        self.value = ''
        self.bytes_sum = 0;
        self.state = self.WAIT_HEADER
        self.dict = {}


    (HEX, WAIT_HEADER, IN_KEY, IN_VALUE, IN_CHECKSUM) = range(5)

    def input(self, byte):
        if byte == self.hexmarker and self.state != self.IN_CHECKSUM:
            self.state = self.HEX
            
        
        if self.state == self.WAIT_HEADER:
            self.bytes_sum += ord(byte)
            if byte == self.header1:
                self.state = self.WAIT_HEADER
            elif byte == self.header2:
                self.state = self.IN_KEY

            return None
        elif self.state == self.IN_KEY:
            self.bytes_sum += ord(byte)
            if byte == self.delimiter:
                if (self.key == 'Checksum'):
                    self.state = self.IN_CHECKSUM
                else:
                    self.state = self.IN_VALUE
            else:
                self.key += byte
            return None
        elif self.state == self.IN_VALUE:
            self.bytes_sum += ord(byte)
            if byte == self.header1:
                self.state = self.WAIT_HEADER
                self.dict[self.key] = self.value;
                self.key = '';
                self.value = '';
            else:
                self.value += byte
            return None
        elif self.state == self.IN_CHECKSUM:
            self.bytes_sum += ord(byte)
            self.key = ''
            self.value = ''
            self.state = self.WAIT_HEADER
            if (self.bytes_sum % 256 == 0):
                self.bytes_sum = 0
                return self.dict
            else:
                print 'Malformed packet'
                self.bytes_sum = 0
        elif self.state == self.HEX:
            self.bytes_sum = 0
            if byte == self.header2:
                self.state = self.WAIT_HEADER
        else:
            raise AssertionError()

    def read_data(self):
        while True:
            byte = self.ser.read(1)
            packet = self.input(byte)

    def read_data_single(self):
        while True:
            byte = self.ser.read(1)
            packet = self.input(byte)
            if (packet != None):
                return packet
            

    def read_data_callback(self, callbackFunction):
        while True:
            byte = self.ser.read(1)
            if byte:
                packet = self.input(byte)
                if (packet != None):
                    callbackFunction(packet)
            else:
                break


def print_data_callback(data):
    print data

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Process VE.Direct protocol')
    parser.add_argument('--port', help='Serial port')
    parser.add_argument('--timeout', help='Serial port read timeout', type=int, default='60')
    args = parser.parse_args()
    ve = vedirect(args.port, args.timeout)
    ve.read_data_callback(print_data_callback)
    #print(ve.read_data_single())
    

Below, with the help of user DAP35

I use these two files to print the VE-DIRECT BMV700 Battery meter FILE info to MQTT.

bmv-to-mqtt.py

#!/usr/bin/python
import json
import paho.mqtt.client as mqtt
import time
import os
broker_url = "192.168.1.4"
broker_port = 1883
delay = 10
mq_client = "bmv700host"
mq_user = "YOUR_MQTT_USER"
mq_pw = "YOUR_MQTT_PASSWORD"
topic1 = "bmv700/SOC"
topic2 = "bmv700/TTG_MINS"
topic3 = "bmv700/AMNT_CHARGE_ENERGY_KWH"
topic4 = "bmv700/BAT_CURR_mA"
topic5 = "bmv700/CONS_ENERGY_mAH"
topic6 = "bmv700/AMNT_DISCHARGE_ENERGY_KWH"
topic7 = "bmv700/CURRENT_BATT_VOLTS_mV"
topic8 = "bmv700/MAX_BATT_VOLTS_mV"
topic9 = "bmv700/SEC_SINCE_LAST_F_CHARGE"
topic10 = "bmv700/LAST_DISCHARGE_mAH"
topic11 = "bmv700/DEEPEST_DISCHARGE_mAH"
topic12 = "bmv700/TOTAL_AH_DRAWN_mAH"
topic13 = "bmv700/MIN_BATT_VOLTS_mV"
topic14 = "bmv700/FULL_DISCHARGES"
status = "bmv700/connection_status"
lwm = "offline"
#
client = mqtt.Client(mq_client)
client.will_set(status, lwm, qos=1, retain=True)
client.username_pw_set(mq_user, password=mq_pw)
client.connect(broker_url, broker_port)
client.publish(topic=status, payload="online", qos=1, retain=True)
#
client.loop_start()
rc=1
while rc > 0:
        #### Edit path to grab.sh to match your environment ####
        os.popen('/startup/bmv/grab.sh')
        with open('bmv700Parsed1.txt', 'r') as sensordata:
            data=sensordata.read()
        obj = json.loads(data)
        SOC = int(obj['SOC'])
        TTG = int(obj['TTG'])
        H18 = int(obj['H18'])
        I = int(obj['I'])
        CE = int(obj['CE'])
        H17 = int(obj['H17'])
        V = int(obj['V'])
        H8 = int(obj['H8'])
        H9 = int(obj['H9'])
        H2 = int(obj['H2'])
        H1 = int(obj['H1'])
        H6 = int(obj['H6'])
        H7 = int(obj['H7'])
        H5 = int(obj['H5'])
        client.publish(topic=topic1, payload=SOC, qos=1, retain=True)
        client.publish(topic=topic2, payload=TTG, qos=1, retain=True)
        client.publish(topic=topic3, payload=H18, qos=1, retain=True)
        client.publish(topic=topic4, payload=I, qos=1, retain=True)
        client.publish(topic=topic5, payload=CE, qos=1, retain=True)
        client.publish(topic=topic6, payload=H17, qos=1, retain=True)
        client.publish(topic=topic7, payload=V, qos=1, retain=True)
        client.publish(topic=topic8, payload=H8, qos=1, retain=True)
        client.publish(topic=topic9, payload=H9, qos=1, retain=True)
        client.publish(topic=topic10, payload=H2, qos=1, retain=True)
        client.publish(topic=topic11, payload=H1, qos=1, retain=True)
        client.publish(topic=topic12, payload=H6, qos=1, retain=True)
        client.publish(topic=topic13, payload=H7, qos=1, retain=True)
        client.publish(topic=topic14, payload=H5, qos=1, retain=True)
        print("Parsing data", SOC, TTG, H18, I, CE, H17, V, H8, H9, H2, H1, H6, H7, H5)
        time.sleep(delay)

Which uses grab.sh to parse and publish to MQTT.

grab.sh

#!/bin/sh
tail -2 bmv700.txt | head -1 | sed s/\'/\"/g > bmv700Parsed1.txt

####################################################
After that we have the VE-Direct MPPT (Solar controller setup)
####################################################

3 Files located in folder: /startup/mppt

MPPT-serial-run.sh

#!/bin/sh
cd /startup/mppt ; 
python vedirect.py --port /dev/ttyUSB_MPPT1 > mppt-log.txt

Which also references vedirect.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os, serial, argparse

class vedirect:

    def __init__(self, serialport, timeout):
        self.serialport = serialport
        self.ser = serial.Serial(serialport, 19200, timeout=timeout)
        self.header1 = '\r'
        self.header2 = '\n'
        self.hexmarker = ':'
        self.delimiter = '\t'
        self.key = ''
        self.value = ''
        self.bytes_sum = 0;
        self.state = self.WAIT_HEADER
        self.dict = {}


    (HEX, WAIT_HEADER, IN_KEY, IN_VALUE, IN_CHECKSUM) = range(5)

    def input(self, byte):
        if byte == self.hexmarker and self.state != self.IN_CHECKSUM:
            self.state = self.HEX
            
        
        if self.state == self.WAIT_HEADER:
            self.bytes_sum += ord(byte)
            if byte == self.header1:
                self.state = self.WAIT_HEADER
            elif byte == self.header2:
                self.state = self.IN_KEY

            return None
        elif self.state == self.IN_KEY:
            self.bytes_sum += ord(byte)
            if byte == self.delimiter:
                if (self.key == 'Checksum'):
                    self.state = self.IN_CHECKSUM
                else:
                    self.state = self.IN_VALUE
            else:
                self.key += byte
            return None
        elif self.state == self.IN_VALUE:
            self.bytes_sum += ord(byte)
            if byte == self.header1:
                self.state = self.WAIT_HEADER
                self.dict[self.key] = self.value;
                self.key = '';
                self.value = '';
            else:
                self.value += byte
            return None
        elif self.state == self.IN_CHECKSUM:
            self.bytes_sum += ord(byte)
            self.key = ''
            self.value = ''
            self.state = self.WAIT_HEADER
            if (self.bytes_sum % 256 == 0):
                self.bytes_sum = 0
                return self.dict
            else:
                print 'Malformed packet'
                self.bytes_sum = 0
        elif self.state == self.HEX:
            self.bytes_sum = 0
            if byte == self.header2:
                self.state = self.WAIT_HEADER
        else:
            raise AssertionError()

    def read_data(self):
        while True:
            byte = self.ser.read(1)
            packet = self.input(byte)

    def read_data_single(self):
        while True:
            byte = self.ser.read(1)
            packet = self.input(byte)
            if (packet != None):
                return packet
            

    def read_data_callback(self, callbackFunction):
        while True:
            byte = self.ser.read(1)
            if byte:
                packet = self.input(byte)
                if (packet != None):
                    callbackFunction(packet)
            else:
                break


def print_data_callback(data):
    print data

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Process VE.Direct protocol')
    parser.add_argument('--port', help='Serial port')
    parser.add_argument('--timeout', help='Serial port read timeout', type=int, default='60')
    args = parser.parse_args()
    ve = vedirect(args.port, args.timeout)
    ve.read_data_callback(print_data_callback)
    #print(ve.read_data_single())
    

Then these two files below print the VE-DIRECT BMV700 Battery meter FILE info to MQTT.

mppt-to-mqtt.py

#!/usr/bin/python3
import json
import paho.mqtt.client as mqtt
import time
import os
broker_url = "192.168.1.4"
broker_port = 1883
delay = 10
mq_client = "victronhost"
mq_user = "YOUR_MQTT_USER"
mq_pw = "YOUR_MQTT_PASS"
topic1 = "victron/YIELD_TOTAL_mAH"
topic2 = "victron/PANEL_VOLTS_mV"
topic3 = "victron/SOLAR_AMPS_mA"
topic4 = "victron/MAX_POWER_TODAY_WATTS"
topic5 = "victron/YIELD_TODAY_KWH"
topic6 = "victron/AMAX_POWER_YESTRD_WATTS"
topic7 = "victron/BATT_VOLTS_mV"
topic8 = "victron/YIELD_YESTRD_KWH"
status = "victron/connection_status"
lwm = "offline"
#
client = mqtt.Client(mq_client)
client.will_set(status, lwm, qos=1, retain=True)
client.username_pw_set(mq_user, password=mq_pw)
client.connect(broker_url, broker_port)
client.publish(topic=status, payload="online", qos=0, retain=False)
#
client.loop_start()
rc=1
while rc > 0:
        #### Edit path to grab.sh to match your environment ####
        os.popen('/startup/mppt/mppt-grab.sh')
        with open('mppt-log-parsed1.txt', 'r') as sensordata:
            data=sensordata.read()
        obj = json.loads(data)
        H19 = int(obj['H19'])
        VPV = int(obj['VPV'])
        I = int(obj['I'])
        H21 = int(obj['H21'])
        H20 = int(obj['H20'])
        H23 = int(obj['H23'])
        V = int(obj['V'])
        H22 = int(obj['H22'])
        client.publish(topic=topic1, payload=H19, qos=0, retain=False)
        client.publish(topic=topic2, payload=VPV, qos=0, retain=False)
        client.publish(topic=topic3, payload=I, qos=0, retain=False)
        client.publish(topic=topic4, payload=H21, qos=0, retain=False)
        client.publish(topic=topic5, payload=H20, qos=0, retain=False)
        client.publish(topic=topic6, payload=H23, qos=0, retain=False)
        client.publish(topic=topic7, payload=V, qos=0, retain=False)
        client.publish(topic=topic8, payload=H22, qos=0, retain=False)
        print("Parsing data", H19, VPV, I, H21, H20, H23, V, H22)
        time.sleep(delay)

And the grab script referenced in the file above to parse printed file:

mppt-grab.sh

#!/bin/sh
tail -2 mppt-log.txt | head -1 | sed s/\'/\"/g > mppt-log-parsed1.txt

To a proper coder this is probably rather basic! BUT its been working for months on end.

It will hopefully help some people get started!

If someone can consolidate and improve the process. That’d also be useful for others…

3 Likes

Nice work :+1:
I created custom component for Esphome now supported mppt chargers via ve.direct port in next weak planing add support for smartshunt(now testing)

Mppt (done)

Smartshunt (testing)

For any questions

  • discord my nick Kindr007CZ#1242
  • my GitHub
1 Like

Like the look of that!
If my Victron USB serial stops working, I will give that a go… Actually have an old BMV meter I could give it a go on. Thanks for the link!

Am no longer using the script above.
Just using Node-Red serial reader node and printing that to MQTT.

Looks amazing!

Hi all,

The available numeric sensors are:

* max_power_yesterday
* max_power_today
* yield_total
* yield_yesterday
* yield_today
* panel_voltage
* panel_power
* battery_current
* day_number
* charging_mode_id
* error_code
* tracking_mode_id
* load_current
* ac_out_voltage
* ac_out_current
* battery_voltage
* device_mode_id
* warning_code

The available text sensors are:

* charging_mode
* error
* tracking_mode
* firmware_version 
* device_type
* device_mode
* warning

Binary sensors:

* load_state
* relay_state

The available numeric sensors are:

* instanteneous_power
* time_to_go
* state_of_charge
* consumed_amp_hours
* min_battery_voltage
* max_battery_voltage
* amount_of_charged
* bmv_alarm_text
* bmv_text
* last_full_charge
* deepest_discharge
* last_discharge
* discharged_energy
* number_of_full_dis

Contact me by telegram for questions

Have you looked at this Github project? https://github.com/diebietse/invertergui

Seems like it would interface with the VE.Bus and relay the information you want over MQTT.

great but the same is possible with esphome and my components :wink:

I love the idea of getting both Smart Solar and Shunt data into Home Assistant but I have no experience of ESP32. I can soler etc. but would like to know what I need to get this working. I’m sure other noobs would appreciate it too.

I’ve flashed up a NodeMCU with your integration… Great job! Saved me buying a victron serial lead. I actually hooked up an old BMV 600 monitor with the node. Am monitoring a wind turbine power creation with it.

Thanks for the work you put into getting Victron to talk to ESP nodes.
Doubt I’ll buy another Victron Serial lead for future installs :ok_hand:

Here is a Python script that will publish Victron device data to MQTT:

Looks very interesting. Will take a look out of curiosity!

I’m using serial node in node red to listen to VE-Direct USB and publishing data to MQTT ATM which has been flawless and is pretty simple.

The ESP Node integration is great for those not wanting to buy a “Victron VE-Direct USB serial device” thanks again @KinDR.

A hurdle I’m looking to overcome is connecting a Smart Victron Bluetooth device to print to MQTT without having to flash a raspberry PI with their smart hub interface…

Hi,

Could you elaborate a little more please on how you accomplished this, I am trying to avoid running venus and Im trying to avoid using an ESP32… two reasons, 1) i bought this to make sure everything was isolated and clean signal etc from ve.direct, works perfectly with venus dupa.net (duppa.net) and 2) want to run a single device (ripi4) with everything i need and not hang additional devices off of it.

You say you are using node-red serial reader, is this a component of a typical node-red installation? I assume you just installed node-red on your ripi or other… is then as simple as adding a serial reader node and MQTT writer node and linking them together? do you have any advise, could you share any screenshots which would help me get this configured please? Im sure you must be doing some filtering or converting or something along the way?

can you get in into mainline esphome ? <3

Here’s a sample Node-Red flow I use. There may be errors in the formula conversions for kwh’s but I’m only needing SOC, voltages and charge current.
This flow uses a serial node linked to a victron USB serial cable plugged into the node red Mini PC.

[
    {
        "id": "c6d236677cff8ba5",
        "type": "tab",
        "label": "Flow 3",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "466da7f5b7c97d59",
        "type": "function",
        "z": "c6d236677cff8ba5",
        "name": "Extract Data BMV700",
        "func": "var data = msg.payload.split(\"\\t\");\nswitch(data[0]) {\n        case    'SOC':\n            SOC = parseFloat(data[1]/10).toFixed(1);\n            break;\n        case    'V':\n            Volts = parseFloat(data[1]/1000).toFixed(2);\n            break;\n        case    'I':\n            Amps = parseFloat(data[1]/1000).toFixed(2);\n            break;\n        case    'P':\n            Watts = parseInt(data[1]);\n            break;\n        case    'CE':\n            AhConsumed = parseInt(data[1]/1000);\n            break;\n        case    'H2':\n            LastDischarge = parseInt(data[1]/1000);\n            break;\n        case    'H6':\n            TotalAhDrawn = parseInt(data[1]/1000);\n            break;\n        case    'H7':\n            MinBattVolt = parseFloat(data[1]/1000).toFixed(2);\n            break;\n        case    'H8':\n            MaxBattVolt = parseFloat(data[1]/1000).toFixed(2);\n            break;\n        case    'H9':\n            SecsSinceFullCharge = parseInt(data[1]);\n            break;\n                }\nreturn [\n    {\n        payload: {\n                SOC: SOC,\n                Volts: Volts,\n                Amps: Amps,\n                Watts: Watts,\n                AhConsumed: AhConsumed,\n                LastDischarge: LastDischarge,\n                TotalAhDrawn: TotalAhDrawn,\n                MinBattVolt: MinBattVolt,\n                MaxBattVolt: MaxBattVolt,\n                SecsSinceFullCharge: SecsSinceFullCharge,\n                 }\n    }\n]",
        "outputs": 1,
        "noerr": 10,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 260,
        "wires": [
            [
                "9027609f9861c975"
            ]
        ]
    },
    {
        "id": "00921e4719b4386d",
        "type": "function",
        "z": "c6d236677cff8ba5",
        "name": "Extract Data MPPT",
        "func": "var data = msg.payload.split(\"\\t\");\nswitch(data[0]) {\n        case    'PPV':\n            PanelWatts = parseFloat(data[1]/1).toFixed(2);\n            break;\n        case    'VPV':\n            PanelVolts = parseFloat(data[1]/1000).toFixed(2);\n            break;\n        case    'I':\n            PanelAmps = parseFloat(data[1]/1000).toFixed(2);\n            break;\n        case    'H19':\n            YieldTotal = parseInt(data[1]/1).toFixed(2);\n            break;\n        case    'H21':\n            MaxWattsToday = parseInt(data[1]/1).toFixed(2);\n            break;\n        case    'H22':\n            YieldYesterday = parseInt(data[1]/1).toFixed(2);\n            break;\n        case    'H23':\n            MaxWattsYesterday = parseInt(data[1]/1).toFixed(2);\n            break;\n        case    'H20':\n            YieldToday = parseInt(data[1]/1).toFixed(2);\n            break;\n\n                }\nreturn [\n    {\n        payload: {\n                PanelWatts: PanelWatts,\n                PanelVolts: PanelVolts,\n                PanelAmps: PanelAmps,\n                YieldTotal: YieldTotal,\n                MaxWattsToday: MaxWattsToday,\n                YieldYesterday: YieldYesterday,\n                MaxWattsYesterday: MaxWattsYesterday,\n                YieldToday: YieldToday,\n                 }\n    }\n]",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 590,
        "y": 600,
        "wires": [
            [
                "fa4151983dab6ed7"
            ]
        ]
    },
    {
        "id": "2f953e9b1f05ad6b",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "SOC Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/SOC/%",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1250,
        "y": 80,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "d2210a8bb7d548ec",
        "type": "link out",
        "z": "c6d236677cff8ba5",
        "name": "Link out",
        "mode": "link",
        "links": [
            "a566578a.89a09"
        ],
        "x": 1575,
        "y": 220,
        "wires": []
    },
    {
        "id": "4faddd93bfe44410",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "Volts Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/CURRENT_BATT_VOLTS_mV/V",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1250,
        "y": 120,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "cee807b90ca6319d",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "Amps Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/BAT_CURR_mA/A",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1260,
        "y": 160,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "4fcc5849c46b564f",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "Watts Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/BAT_Watt",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1260,
        "y": 200,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "c3a2343e2b0da573",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "AhConsumed Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/CONS_ENERGY_mAH/A",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1280,
        "y": 240,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "260cdcfe4490b630",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "LastDischarge Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/LAST_DISCHARGE_mAH/A",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1280,
        "y": 280,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "f996078203a14489",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "TotalAhDrawn Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/TOTAL_AH_DRAWN_mAH/A",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1040,
        "y": 200,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "7dd9d3cd5c514965",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "MinBattVolt Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/MIN_BATT_VOLTS_mV/A",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1270,
        "y": 360,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "1ea78185a4ac3517",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "MaxBattVolt Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/MAX_BATT_VOLTS_mV/V",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1280,
        "y": 400,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "826aa75052802b2f",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": " SecsSinceFullCharge Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "bmv700/Time_Full_C/sec",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1300,
        "y": 440,
        "wires": [
            [
                "d2210a8bb7d548ec"
            ]
        ]
    },
    {
        "id": "d2b92dacc1ee30c4",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "PanelWatts Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/SOLAR_Watts",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1270,
        "y": 500,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "e6f2753c246ccfe8",
        "type": "link out",
        "z": "c6d236677cff8ba5",
        "name": "Link out",
        "mode": "link",
        "links": [],
        "x": 1675,
        "y": 620,
        "wires": []
    },
    {
        "id": "49cd97ee143734e0",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "Volts Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/SOLAR_Panel_Volts",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1250,
        "y": 540,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "2ba20926825ade82",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "Amps Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/SOLAR_AMPS_mA/A",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1300,
        "y": 580,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "e1ee289e1cdfb018",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "YieldTotal Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/YIELD_TOTAL_kWH",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1430,
        "y": 620,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "1d8d3dc66e0ba422",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "MaxWattsToday Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/MAX_POWER_TODAY_WATTS",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1290,
        "y": 660,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "cae1c44fa4cfa055",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "YieldToday Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/YIELD_TODAY_KWH",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1410,
        "y": 700,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "9c2745a89ba644c9",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.SOC",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 80,
        "wires": [
            [
                "2f953e9b1f05ad6b"
            ]
        ]
    },
    {
        "id": "1c918ca9875a57f3",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.Volts",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 120,
        "wires": [
            [
                "4faddd93bfe44410"
            ]
        ]
    },
    {
        "id": "8dc74b0754e005e5",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.Amps",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 160,
        "wires": [
            [
                "cee807b90ca6319d"
            ]
        ]
    },
    {
        "id": "1640861bf192ee66",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.Watts",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 200,
        "wires": [
            [
                "4fcc5849c46b564f"
            ]
        ]
    },
    {
        "id": "8cac6824acc632c7",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.AhConsumed",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 240,
        "wires": [
            [
                "c3a2343e2b0da573"
            ]
        ]
    },
    {
        "id": "e2737cd7b0900401",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.LastDischarge",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 280,
        "wires": [
            [
                "260cdcfe4490b630"
            ]
        ]
    },
    {
        "id": "e21875e73e55ce95",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.TotalAhDrawn",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 320,
        "wires": [
            [
                "f996078203a14489"
            ]
        ]
    },
    {
        "id": "c22ae9df74bb9246",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.MinBattVolt",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 360,
        "wires": [
            [
                "7dd9d3cd5c514965"
            ]
        ]
    },
    {
        "id": "67e05369b1841172",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.MaxBattVolt",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 400,
        "wires": [
            [
                "1ea78185a4ac3517"
            ]
        ]
    },
    {
        "id": "3daedffc2a6c11be",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.SecsSinceFullCharge",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 440,
        "wires": [
            [
                "826aa75052802b2f"
            ]
        ]
    },
    {
        "id": "4331f3847cc751dc",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.PanelWatts",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 500,
        "wires": [
            [
                "d2b92dacc1ee30c4"
            ]
        ]
    },
    {
        "id": "86872769c6bf73e0",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.PanelVolts",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 540,
        "wires": [
            [
                "49cd97ee143734e0"
            ]
        ]
    },
    {
        "id": "4e4e9186e6aca55b",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.PanelAmps",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 580,
        "wires": [
            [
                "2ba20926825ade82"
            ]
        ]
    },
    {
        "id": "3213c38bc6b6175d",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.YieldTotal",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 620,
        "wires": [
            [
                "32a03c27bd5c3e00"
            ]
        ]
    },
    {
        "id": "21c3c9f6bcab9595",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.MaxWattsToday",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 660,
        "wires": [
            [
                "1d8d3dc66e0ba422"
            ]
        ]
    },
    {
        "id": "59bb33bb6be23ada",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.YieldToday",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 700,
        "wires": [
            [
                "7ba719181c73a08d"
            ]
        ]
    },
    {
        "id": "9027609f9861c975",
        "type": "delay",
        "z": "c6d236677cff8ba5",
        "name": "",
        "pauseType": "queue",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "0.5",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "outputs": 1,
        "x": 810,
        "y": 260,
        "wires": [
            [
                "8cac6824acc632c7",
                "9c2745a89ba644c9",
                "1c918ca9875a57f3",
                "8dc74b0754e005e5",
                "1640861bf192ee66",
                "e2737cd7b0900401",
                "e21875e73e55ce95",
                "c22ae9df74bb9246",
                "67e05369b1841172",
                "3daedffc2a6c11be"
            ]
        ]
    },
    {
        "id": "fa4151983dab6ed7",
        "type": "delay",
        "z": "c6d236677cff8ba5",
        "name": "",
        "pauseType": "queue",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "0.5",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "outputs": 1,
        "x": 810,
        "y": 600,
        "wires": [
            [
                "4331f3847cc751dc",
                "86872769c6bf73e0",
                "4e4e9186e6aca55b",
                "3213c38bc6b6175d",
                "21c3c9f6bcab9595",
                "0e53f53f25e0a02a",
                "59bb33bb6be23ada",
                "4c448270b710c428"
            ]
        ]
    },
    {
        "id": "07ea74f3057248e0",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "YieldYesterday Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/YIELD_YESTERDAY_KWH",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1420,
        "y": 740,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "4c448270b710c428",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.YieldYesterday",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 740,
        "wires": [
            [
                "127ae2ba198e1cd9"
            ]
        ]
    },
    {
        "id": "18d092085af190fe",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "MaxWattsYesterday Publish",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "victron/MAX_POWER_YESTRD_WATTS",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1300,
        "y": 780,
        "wires": [
            [
                "e6f2753c246ccfe8"
            ]
        ]
    },
    {
        "id": "0e53f53f25e0a02a",
        "type": "change",
        "z": "c6d236677cff8ba5",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.MaxWattsYesterday",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 1060,
        "y": 780,
        "wires": [
            [
                "18d092085af190fe"
            ]
        ]
    },
    {
        "id": "127ae2ba198e1cd9",
        "type": "function",
        "z": "c6d236677cff8ba5",
        "name": "Convert",
        "func": "msg.payload = ((msg.payload)/100).toFixed(2);\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1240,
        "y": 740,
        "wires": [
            [
                "07ea74f3057248e0"
            ]
        ]
    },
    {
        "id": "7ba719181c73a08d",
        "type": "function",
        "z": "c6d236677cff8ba5",
        "name": "Convert",
        "func": "msg.payload = ((msg.payload)/100).toFixed(2);\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1240,
        "y": 700,
        "wires": [
            [
                "cae1c44fa4cfa055"
            ]
        ]
    },
    {
        "id": "32a03c27bd5c3e00",
        "type": "function",
        "z": "c6d236677cff8ba5",
        "name": "Convert",
        "func": "msg.payload = ((msg.payload)/100).toFixed(2);\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1240,
        "y": 620,
        "wires": [
            [
                "e1ee289e1cdfb018"
            ]
        ]
    },
    {
        "id": "e84c109a3d1f7380",
        "type": "comment",
        "z": "c6d236677cff8ba5",
        "name": "MQTT HA",
        "info": "",
        "x": 1800,
        "y": 220,
        "wires": []
    },
    {
        "id": "02f7d2e939b4c4e6",
        "type": "comment",
        "z": "c6d236677cff8ba5",
        "name": "MQTT HA",
        "info": "",
        "x": 1800,
        "y": 620,
        "wires": []
    },
    {
        "id": "2364cb8b9494e97b",
        "type": "serial in",
        "z": "c6d236677cff8ba5",
        "name": "Victron BMV",
        "serial": "cf639975.bcaca",
        "x": 390,
        "y": 260,
        "wires": [
            [
                "466da7f5b7c97d59"
            ]
        ]
    },
    {
        "id": "805fdec974a0d5d1",
        "type": "serial in",
        "z": "c6d236677cff8ba5",
        "name": "Victron MPPT",
        "serial": "b01297686e876e61",
        "x": 390,
        "y": 600,
        "wires": [
            [
                "00921e4719b4386d"
            ]
        ]
    },
    {
        "id": "cf639975.bcaca",
        "type": "serial-port",
        "serialport": "/dev/ttyUSB1",
        "serialbaud": "19200",
        "databits": "8",
        "parity": "none",
        "stopbits": "1",
        "waitfor": "",
        "dtr": "none",
        "rts": "none",
        "cts": "none",
        "dsr": "none",
        "newline": "\\n",
        "bin": "false",
        "out": "char",
        "addchar": "",
        "responsetimeout": "10000"
    },
    {
        "id": "b01297686e876e61",
        "type": "serial-port",
        "serialport": "/dev/ttyUSB_mppt",
        "serialbaud": "19200",
        "databits": "8",
        "parity": "none",
        "stopbits": "1",
        "waitfor": "",
        "dtr": "none",
        "rts": "none",
        "cts": "none",
        "dsr": "none",
        "newline": "\\n",
        "bin": "false",
        "out": "char",
        "addchar": "",
        "responsetimeout": "10000"
    }
]

Hope that gives you something to go on via the USB route. Tho I will myself, in future installs just use the ESP32 interface way suggested by @KinDR

Tho I am using the flow above to report for the last year (or so) to report a BMV battery monitor and MPPT Solar controller.