Resol VBUS data extraction KM2 Communication module

Hi all,

I managed to create a way to read vbus data directly from the KM2 module without any additional hardware or use of the json data server from Wipperman.

One can download the vbus data directly via a script from the KM2 (DeltaSol CS Plus) like so:

get_vbus_data:
  sequence:
  - service: downloader.download_file
    data:
      url: http://xxx.xxx.xxx.xxx/current/current_packets.vbus
      filename: vbus_data.hex
      overwrite: true
  mode: single
  icon: mdi:file-download

Within the current_packets.vbus is the raw data (hex) of the logger at the time of reading the file.

In the file are a lot of headers and other stuff but the data I needed is at specific bytenumbers within that file.

I.e. the tempature sensor 1 (heatpipes) can be decoded like so:

sensor:
# Read solarboilervalues from file
  - platform: command_line
    name: "SolarBoiler T1"
    unit_of_measurement: "°C" 
    scan_interval: 300  # run the command every 300 seconds
    command: "python3 /config/extract_solarboilerT1.py"

The script is:

import struct

# open the file, extract the number
f = open("downloads/vbus_data.hex","rb")
f.seek(40)
LSB = struct.unpack("B",f.read(1))[0]
MSB = struct.unpack("B",f.read(1))[0]
Temperature= ((MSB*256)+LSB)/10
print (Temperature)

This is my result in lovelace:

I hope this could be of some help to others with a KM2 module. The exact locations of the data can be different because of the solarboiler system you own.

4 Likes

Hi HappyBacon,
How did you connect to the vbus of the resol? I have exactly the same device and want to integrate it in my dash. Can you help me out a bit?

Love the effort which was put in here!

Tell me, how can I find the offset for the other temperature sensors and pump speed?
Is there a document with the details somewhere?

Then another question; how did you get this script into HomeAssistant? Was it via the standard configuration.yaml file? I see all my stuff has been moved somewhere; not sure where to find it now.

1 Like

Thanks! This was very useful :slight_smile:

I added the “get_vbus_data” code to scripts.yaml, installed the “downloader” (Downloader - Home Assistant) integration and added the following to automations.yaml to update the data every 5 minutes:

- id: '1659953025733'
  alias: Get Resol VBUS data / 5 min
  description: ''
  trigger:
  - platform: time_pattern
    minutes: /5
  action:
  - service: script.get_vbus_data
  mode: single

Now I just need to figure out which data corresponds with the temperature, I read the HEX data which looks as follows:

00000000: a544 0e00 0e00 6045 c87c 8201 0000 a566  .D....`E.|.....f
00000010: 8600 8600 6045 c87c 8201 0000 1000 6023  ....`E.|......`#
00000020: 1000 0001 6c00 0000 b97c a228 1102 f901  ....l....|.(....
00000030: fe01 b822 1f01 0f27 3204 0000 0000 0000  ..."...'2.......
00000040: 0000 0000 0000 0000 0f27 6400 6400 0000  .........'d.d...
00000050: 0000 0000 6400 0000 1c23 3b01 0000 0000  ....d....#;.....
00000060: b6c2 cc02 0000 0000 0000 0000 0000 0000  ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: b822 0000 a566 4a00 4a00 6045 c87c 8201  ."...fJ.J.`E.|..
000000a0: 0000 1500 6023 1000 0001 3000 0000 0401  ....`#....0.....
000000b0: 0000 1102 f901 fe01 b822 1f01 0f27 0000  ........."...'..
000000c0: f1d8 0108 0000 0000 6400 020a 0000 1102  ........d.......
000000d0: f901 0000 0000 010b 0000 0000 0000       ..............

I converted this to decimals using Excel:

42308	3584	3584	24645	51324	33281	0		42342
34304	34304	24645	51324	33281	0		4096	24611
4096	1		27648	0		47484	41512	4354	63745
65025	47138	7937	3879	12804	0		0		0
0		0		0		0		3879	25600	25600	0
0		0		25600	0		7203	15105	0		0
46786	52226	0		0		0		0		0		0
0		0		0		0		0		0		0		0
0		0		0		0		0		0		0		0
47138	0		42342	18944	18944	24645	51324	33281
0		5376	24611	4096	1		12288	0		1025
0		4354	63745	65025	47138	7937	3879	0
61912	264		0		0		25600	522		0		4354
63745	0		0		267		0		0		0		0

(edit: which turned out to be wrong and completely useless)

At the time of export I also had a look at the VBus data on resol.net:

I need some help with your Python script though, I see that you calculate temperature with the following calculation: Temperature= ((MSB*256)+LSB)/10 .

What are my next steps in figuring out which values to use as the current values are way off:
image

Any tips/help is much appriated!

Cheers,

Roy

Quick update: I found the following project which was really useful: resol-vbus-docs

I installed this package on my WSL2 Ubuntu 22.05 LTS instance and created the following code:

var inFilename = 'current_packets.vbus';

var vbus = require('../resol-vbus');
var fs = require('fs');

var inFile = fs.createReadStream(inFilename);

var inConv = new vbus.VBusRecordingConverter();
var spec = vbus.Specification.getDefaultSpecification();


inConv.on('header', function(header) {
	console.log('Header decoded: ' + header.timestamp + ' -> ' + header.getId());
});

inConv.on('headerSet', function(headerSet) {
    console.log('HeaderSet decoded: ' + headerSet.timestamp + ' -> ' + headerSet.getId() + "\n");
	
	packets = headerSet.getSortedHeaders();
	packetFields = spec.getPacketFieldsForHeaders(packets);
	
	packet = null;
	packetFields.forEach(function(packetField) {
		if (packet !== packetField.packet) {
			packet = packetField.packet;
			console.log(packetField.packetSpec.fullName);
		}
		console.log('    ' + packetField.id + '    ' + packetField.name + ' = ' + packetField.formatTextValue() );
	});
});


inFile.pipe(inConv);

Now simply running “node index.js” returns the following results:

Header decoded: Mon Aug 08 2022 11:39:34 GMT+0200 (Central European Summer Time) -> 00_0010_2360_10_0100
Header decoded: Mon Aug 08 2022 11:39:34 GMT+0200 (Central European Summer Time) -> 00_0015_2360_10_0100
HeaderSet decoded: Mon Aug 08 2022 11:39:34 GMT+0200 (Central European Summer Time) -> 00_0010_2360_10_0100,00_0015_2360_10_0100

HR Solar ADVANCED controller [Regler]
    00_0010_2360_10_0100_000_4_0    System date = 08/09/2022 11:41:39
    00_0010_2360_10_0100_004_2_0    Temperature sensor 1 = 53.8 °C
    00_0010_2360_10_0100_006_2_0    Temperature sensor 2 = 50.5 °C
    00_0010_2360_10_0100_008_2_0    Temperature sensor 3 = 51.0 °C
    etc...

You can find all the headers for the KM2 here: resol-vbus-docs

The big question is how to map those headers to actual values in the HEX file downloaded from http://x.x.x.x/current/current_packets.vbus :slight_smile:

The simple solution would be to install resol-vbus on Home-Assistant but that is not a very future-proof solution, I’d rather create a lightweight solution like the python code @happybacon created.

A more heavyweight solution would be to to create a docker instance for resol-vbus that simply calls http://x.x.x.x/current/current_packets.vbus and returns the decoded field in a nicely formatted JSON structure.

I wrote a quick script to locate the value I was looking for:

import struct
import os

file_name = "current_packets.vbus"

file_stats = os.stat(file_name)
print(f'File Size in Bytes is {file_stats.st_size}')

# open the file, extract the number
f = open(file_name,"rb")

for x in range(file_stats.st_size):
  f.seek(x)
  lsb = struct.unpack("B",f.read(1))[0]
  msb = struct.unpack("B",f.read(1))[0]

  calc = ((msb * 256) + lsb) / 10

#  print(f'{x} - msb:{msb}, lsb:{lsb}, calc:{calc}')

  if calc == 53.8:
    print(f'{x}: Found Temp1! {msb}, {lsb} calc={calc}')

  if calc == 50.5:
    print(f'{x}: Found Temp2! {msb}, {lsb} calc={calc}')

  if calc == 51.0:
    print(f'{x}: Found Temp3! {msb}, {lsb} calc={calc}')

When I ran this against the file I downloaded from the KM2 and decoded using resol-vbus I was able to determine the exact temperatures (T1=53.8, T2=50,5 and T3=51.0) I was looking for and thus find the locations of the values I need (44, 46 and 48):

File Size in Bytes is 222
44: Found Temp1! 2, 26 calc=53.8
46: Found Temp2! 1, 249 calc=50.5
48: Found Temp3! 1, 254 calc=51.0

Next I created a new Python script to extract these values from the downloaded file and present them in a neatly formatted JSON structure:

import struct
import os
import json

# define input file here
file_name = "downloads/vbus_data.hex"

def extract_dec_val(file_handle, position, factor):
    """This function extracts the decimal value from a file using position and factor, considering negative values in two's complement form."""
    file_handle.seek(position)

    # get least significant bit value
    lsb = struct.unpack("B", file_handle.read(1))[0]
    # get most significant bit value
    msb = struct.unpack("B", file_handle.read(1))[0]

    # combine MSB and LSB
    combined_value = (msb << 8) | lsb

    # handle two's complement for negative values
    if msb & 0x80:  # Check if the most significant bit is set (negative number)
        combined_value -= 0x10000  # Adjust for two's complement

    # calculate value and apply correction factor (1 or 10 in most cases)
    value = combined_value / factor

    return value

# open the file
file_handle = open(file_name,"rb")

# define locations of values in file and factor
temp_1 = extract_dec_val(file_handle,44,10)
temp_2 = extract_dec_val(file_handle,46,10)
temp_3 = extract_dec_val(file_handle,48,10)

# create return set
return_set = {
  'vbus':{
    'temp_1':temp_1,
    'temp_2':temp_2,
    'temp_3':temp_3,
  }
}

# output nicely formatted JSON string
output = json.dumps(return_set)
print(output)

For now I have added the following three entities to configuration.yaml:

  # Read solarboilervalues from file
  - platform: command_line
    name: "Solar Boiler T1"
    command: "python3 /config/extract_solarboiler.py"
    scan_interval: 60
    json_attributes:
      - vbus
    value_template: '{{ value_json.vbus.temp_1 }}'
    unit_of_measurement: "°C"
    
  - platform: command_line
    name: "Solar Boiler T2"
    command: "python3 /config/extract_solarboiler.py"
    scan_interval: 60
    json_attributes:
      - vbus
    value_template: '{{ value_json.vbus.temp_2 }}'
    unit_of_measurement: "°C"
    
  - platform: command_line
    name: "Solar Boiler T3"
    command: "python3 /config/extract_solarboiler.py"
    scan_interval: 60
    json_attributes:
      - vbus
    value_template: '{{ value_json.vbus.temp_3 }}'
    unit_of_measurement: "°C"

I kind of expected to be able to update 3 sensors using a single command, I did quite some digging but could not find this. When I add a “sensors” block in the YAML it breaks.

Any help on how to update multiple sensors using a single command would be greatly appreciated :slight_smile:

Anyway, the result looks quite good:

Another way can be to use Node-RED

Notes:

This is my FLOW:

[{"id":"9b5eca7e3760c8b4","type":"tab","label":"Flow 1","disabled":false,"info":"","env":[]},{"id":"d9e0ecd35bc89761","type":"inject","z":"9b5eca7e3760c8b4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":true,"onceDelay":0.1,"topic":"","payloadType":"date","x":190,"y":240,"wires":[["3725a46f5cccd3e7"]]},{"id":"3725a46f5cccd3e7","type":"http request","z":"9b5eca7e3760c8b4","name":"","method":"GET","ret":"bin","paytoqs":"ignore","url":"http://192.X.X.X/current/current_packets.vbus","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"credentials":{"user":"","password":""},"x":400,"y":240,"wires":[["5ed57a0832a3a694","b8a84047a0e84a54"]]},{"id":"5ed57a0832a3a694","type":"buffer-parser","z":"9b5eca7e3760c8b4","name":"","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"int16le","name":"S1","offset":40,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S2","offset":42,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S3","offset":44,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S4","offset":46,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S5","offset":48,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S6","offset":50,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S7","offset":52,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S8","offset":54,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int16le","name":"S9","offset":56,"length":1,"offsetbit":0,"scale":"0.1","mask":""},{"type":"int8","name":"R1","offset":80,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int8","name":"R2","offset":81,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int8","name":"R3","offset":82,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int8","name":"R4","offset":83,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int8","name":"R5","offset":84,"length":1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"return","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":620,"y":240,"wires":[["f1d05f798f491c0e"]]},{"id":"b8a84047a0e84a54","type":"debug","z":"9b5eca7e3760c8b4","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":630,"y":120,"wires":[]},{"id":"f1d05f798f491c0e","type":"debug","z":"9b5eca7e3760c8b4","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":870,"y":120,"wires":[]}]

I was looking for a km2 integration, this node red flow works perfectly.

I changed S9 to be an int8 and it gives the pump speed too.

Hy Whem,

thank you for your flow. Basically it works fine (I found temperature sensors,…), but I can’t find the offset and data-type for heat meter. Do you have an idea how I can find out the right offset and data-type?

BR
Phil

Hey guys - if anyone is interested, I used Resol KM2 module as a reason to learn python and write my first custom HA integration.

Have fun.

cheers
Martin

Hi Martin, I will try and check it out later this week!. I have both a KM2 and a DL2, so if I can assist you with that… tell me what you want :slight_smile:

Hi Joost

Thanks for reaching out that is so kind

I am pretty certain KM2 works out of the box.

For DL2 some changes are needed as explained here:

I am on holidays and need my big screen/keyboard/mouse so once back home will release an update with those changes.

If you could please download integration from HACS and test if it works for KM2.

Once new release is done then DL2 should hopefully work too.

Happy new year
Thanks
Martin