Hacky integration for M-Bus

PS: On your specific question: The code from DLMS meter is very specific to a certain type of meters. I believe it will be not easy to adjust it to your own meter. Maybe my previous post gives you an idea about the problems.

I fully agree :wink:

Hi guys,

your wish is my command :slight_smile:

Here is a first draft of my blog post:

It should clarify many things already.

But now it time to watch some news and take some rest :slight_smile:

Regards,
Daniel

3 Likes

Hi Daniel and everyone,

I completed the full circuit and could get it to work by switching the FT232 board to 5V output. With 3.3V the output the serial rx line was just between 0.0035V when there was no communication and 0.6V when it was communicating. So I tried 5V and then the rx line was more in the useable range (it is a bit higher than 3.3V, i measured a bit more than 4V max, but the rx led was blinking.

With python I set the baudrate to 300, since I could receive consistent data with my previous adapter at this bitrate, set the parity bit to even and stopbit to one. But so far I couldn’t get anything meaningful. Maybe I’ll try to change the shunt resistor to 33Ohms… But I’m still optimistic to get it to work :slight_smile:

So thanks for all the support and I’ll report progress back here!

Andreas

PS: I like the blog post, it sums up all the important stuff!

Hi,
I want to read out a PolluCom E with optical adapter from Hihi IR ttl, the rx is on Pin 14 and tx on pin 16

ive installed the code from 1st post but get no data.

ive also found some code where others chan read this Device but I want it with HA and ESPHome,

can someone help me with this? maybe others found it helpful with this Devices

this is python code

#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
4
import serial, time
5
import meterbus
6
7
address = 0
8
port = '/dev/ttyUSB0'
9
wakeup = "\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55\x55"
10
11
# start communication with 8N1, DTR enabled
12
ser =  serial.Serial(port, 2400, 8, 'N', 1, 0.5)
13
ser.dsrdtr=True
14
15
# send wake up sequence
16
ser.write(wakeup)
17
time.sleep(0.130)
18
ser.read()
19
response = ser.readline()
20
21
# switch to 8E1
22
ser.parity = serial.PARITY_EVEN
23
24
# SND_NKE to reset the communication
25
meterbus.send_ping_frame(ser, address)
26
frame = meterbus.load(meterbus.recv_frame(ser, 1))
27
assert isinstance(frame, meterbus.TelegramACK)
28
29
# request data from meter
30
meterbus.send_request_frame(ser, address)
31
frame = meterbus.load(meterbus.recv_frame(ser, meterbus.FRAME_DATA_LENGTH))
32
assert isinstance(frame, meterbus.TelegramLong)
33
34
# print data, todo: save it to file
35
print(frame.to_JSON())

and this does the same in C

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>

char *buf;
char in[256] = "";
ssize_t ret_out;
int fd = open ("/dev/ttyUSB0", O_RDWR | O_NOCTTY );
set_interface_attribs (fd, B2400, 0);  // set speed to 2,400 bps, 8n1 (no parity)
set_blocking (fd, 0 );                // set no blocking
strcpy( in, "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU");
ret_out = write (fd, in, strlen(in));           // sent wakeup
usleep ((1000 + 25) * 100);             // sleep enough to transmit plus
buf = read_data( fd);
// Initialisiere MBus -> ACK mit 'E5'
in[0] = 0x10;
in[1] = 0x40; // Init MBus
in[2] = 0x00;
in[3] = 0x40; // Checksumme = in[1] + in [2]
in[4] = 0x16;
ret_out = write (fd, in, 5);           // sent
usleep ((1000 + 25) * 100);             // sleep enough to transmit plus
buf = read_data( fd);
if (buf[5] == 0xE5)
{ 
// Get Data from MBus
in[0] = 0x10;
in[1] = 0x5B;  // GetData
in[2] = 0x00;
in[3] = 0x5B;   // Checksumme = in[1] + in [2]
in[4] = 0x16;
ret_out = write (fd, in, 5);
usleep ((1000 + 25) * 100);             // sleep enough to transmit plus
buf = read_data( fd);
// Zaehlerstand
double waerme = ((double) toInt(&buf[26])) + (100.0 * (double) toInt(&buf[27])) + (1000.0 * (double) toInt(&buf[28])) + (10000.0 * (double) toInt(&buf[29]));
//aktuelle Leistung
double leistung = ((double) toInt(&buf[44])) + (100.0 * (double) toInt(&buf[45])) + (1000.0 * (double) toInt(&buf[46])) + (10000.0 * (double) toInt(&buf[47]));
}

int toInt( char *in ) {

char out[2];
int iOut = 0;
sprintf(out, "%02x", in[0]);
iOut = atoi(out);
return iOut;
}

Hi Aikawa24,

optical communication is very off-topic in this thread. This thread is about M-Bus. Please start another thread, if you want to get help.

Read the FAQ and please do not derail/hijack threads as stated in the Community Guidelines.

Regards,
Daniel

I really like, where this is going :slight_smile: Thanks for your effort @the78mole ! I wanted to get hold of the meter bus data on our flat for a long time, but there already is a master/gateway at work which I can not disable or alter (its a rented flat). So the mbus-sniffing-project should work well in this context.

Beginners-Question from my side concerning your discussion with @ajuch about the hardware: Wouldn’t it be sufficient to use a standard board like the Sparkfun INA219 or INA 169 to measure the currents instead of building a specific setup like you proposed? We are not really interested in the current value, but the INA169 converts it to an easily measurable Vout, we could maybe get this Vout directly into a GPIO from an ESP32? The INA169 has a bandwith of 440kHz, so this could work even if the mbus uses its maximum speed of 9600 baud. I did not yet draw a sketch for all this, just some toughts.

Hi AMTQ,

in my opinion, the INA-Solution is way too complex. Using a cheap, simple comparator is way easier. With a little more effort (low-pass filter + chicken feed), you could also find the inactive current to compare with and also allow for many more slaves. On the other side, with the potentiometer, you have a really simply way to adjust the comparision trigger level, even with more than 5 slaves.

Regards,
Daniel

Hi AMTQ and Daniel,

I would also like to add an ESP (8266 in my case, i have them lying around) and push the data to a MQTT broker, the circuit with the comparator is something I can conceptually understand, I learned how to measure current with a shunt resistor, although I don’t have the fundamental knowledge which resistors to use…

But however I didn’t yet get useful data out of it. I tried a lot of stuff, changed the shut resistor to 33Ohm, tried every baud rate supported by the meter (luckily only 300, 2400 and 9600 are supported by the meter). I tried both 3.3V and 5.0V mode of the FT232 board. And of course I changed the potentiometer while monitoring the serial output. But so far not the data I expected (I’m looking for 0x68 + L + L + 0x68 and 0x16 for the start end end of long frames). The system looks very stable, I’m capturing data since ~10days now without any issues. I also learned that the RX led on the FT232 board only blinks when the serial port is read, this confused me in the beginning, as I expected it to work all the time.

Maybe I have to redo everything more systematically, but I’m not sure what I can try to get it to work. I guess the best tool to help me would be a oscilloscope, but I don’t have one. I’m happy that there is more interest in that, I’d like to avoid using an IR reader on the meter (doesn’t look very stable to me, I’d have to press buttons on the meter after every power outage to start IR comm again). Maybe you have some suggestions for me, Daniel? I’d really like to get this to work and solder a beautiful PCB with a shiny ESP on top of it :slight_smile:

Thanks, Andreas

PS: I hope your heat pump project went well, Daniel.

PPS: I forgot to mention that I bought Estek LM393, not the TI ones. If they are worse, I’d order the ones from TI…

Hi Andreas,

regarding the heat pump, I’m knee deep in the mud :rofl: There is progress, but there is also some delay of delivery for some central little components (mostly valves).

LM393 should all be fine, if they are still comparators. The first thing I would do is taking a multimeter, measuring the voltage (DC) between ground and pin 3 of the comparator, to get knowledge about the inactive current/eqivalent voltage (note down this voltage). I would also have a look, how it changes, if data is transferred from slave to master. The latter in theory should be around half the value of the peaks, since the multimeter will average the lows and highs (in DC mode). Then I would measure the voltage from ground to pin 2 of the comparator. Adjust it, to be slightly above the previously measured voltage (around the DC voltage, you can measure during activity). If you did this, you should be able to watch a logic high (supply) during inactive periods and a voltage around half the supply when there is activity.

If you measure a negative voltage on pin 3, you could have miswired the shunt. Just reverse the connections from the M-Bus to the shunt.

Hope this helps :slight_smile:

Edit: Just read your post again… You already measured the inputs and outpus… 3.3V is really close to the limits of this comparator and 5V is much better. But when it is inactive, you should get the supply voltage level and not ground level. Try swapping the inputs (IN+ and IN-) of the comparator. And you could also lower the pull-up on the output, to get a more “crisp” signal. Could be that your converter has a quite low input impedance.

Regards,
Daniel

Oh my, I know it’s ages since I wrote my last comment, but I just logged in and saw you asked, so… :smiley:
Ultimately I did not find a working way to integrate mbus via an ESP, but I did integrated a wired mbus eventually.
I have used this mbus master:

And connected it to an rpi 1.

I’m using libmbus to poll the devices, xpath to get the data I need and mqtt to push it to Home Assistant.
I’ve set up it to just work with an intention to write a better code.
So one year later it’s still working great as it is and I forgot what I was about to :smiley:

2 Likes

Hi,

I got to this topic after many hours on Google.

I want to read the measurements of my water meter which is already connected to a mbus gateway used by the company that bills my water consumption (and the consumption of my neighbours). I assume that this mbus gateway is master and the my meter and my neighbors meters are slaves.

My question is, can I use a mbus-master USB ( https://de.aliexpress.com/item/32990900096.html?gatewayAdapt=glo2deu) to poll values from the meter considering that there is already a mbus master in the bus (gateway used by the billing company)? In other words, is is possible to have 2 masters on the same bus?

Hello, I do not think 2 masters will work. I accidentally ordered a USB MBus Slave that cannot use.
Maybe you are interested?

Hi soyxan,

unfortunately, M-Bus is really single master. It could even destroy one or both of it, if you connect them in parallel. But if you could use the sniffing-curcuit I proposed earlier, you could simply sniff the data, when the master asks the meter for data.

Hope that helps.

Regards,
Daniel

1 Like

Hello

I started reading the Apator MBus meter using the configuration and description from the website Taking Your M-Bus To The Next Level… MQTT – MolesBlog but I have a small problem because I get 2 errors that I can’t deal with .

pi@raspberrypi:~/bin $ read_send_meters_mqtt2.sh
Getting data from 0025244901061507… 2875 bytes sent
water/0025244901061507 -> "252449"
water/0025244901061507 -> "APA"
water/0025244901061507 -> "21"
water/0025244901061507 -> "88"
sed: -e expression #1, char 6: unknown option to `s'
sed: -e expression #1, char 7: unterminated `s' command
water/0025244901061507 –> {
  "MBusData": {
    "SlaveInformation": {
      "Id": "252449",
      "Manufacturer": "APA",
      "Version": "21",
      "ProductName": null,
      "Medium": "Water",
      "AccessNumber": "74",
      "Status": "88",
      "Signature": "0000"
    },
    "DataRecord": [
      {
        "_id": "0",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Fabrication number",
        "Value": "252449",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "1",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Time Point (time & date)",
        "Value": "2023-02-16T17:44:00",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "2",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Volume (m m^3)",
        "Value": "20",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "3",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Volume flow (m m^3/h)",
        "Value": "0",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "4",
        "Function": "Instantaneous value",
        "StorageNumber": "1",
        "Unit": "Volume (m m^3)",
        "Value": "53",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "5",
        "Function": "Instantaneous value",
        "StorageNumber": "1",
        "Unit": "Time Point (date)",
        "Value": "2023-02-01",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "6",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Operating time (days)",
        "Value": "1575",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "7",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Error flags",
        "Value": "262660",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "8",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Manufacturer specific",
        "Value": "263172",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "9",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Manufacturer specific",
        "Value": "0",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "10",
        "Function": "Instantaneous value",
        "StorageNumber": "0",
        "Unit": "Manufacturer specific",
        "Value": "-4980702",
        "Timestamp": "2023-02-16T16:44:41Z"
      },
      {
        "_id": "11",
        "Function": "Manufacturer specific",
        "Value": "00 05 15 39 FF 00 00 00 00 00",
        "Timestamp": "2023-02-16T16:44:41Z"
      }
    ]
  }
}
sed: -e expression #1, char 6: unknown option to `s'
sed: -e expression #1, char 7: unterminated `s' command
#!/bin/bash

# Code Basis stammt von https://the78mole.de/taking-your-m-bus-online-with-mqtt/

# Ich habe es nur ergänzt um alle Datenfelden flexibel zum MQTT Server zu übertragen

# Getestet nur mit einem Wärmezähler. Ich hoffe es felxibel genug auch für andere Geräte

ADDRESS_FILE=~/addresses.txt

BAUDRATE=2400

DEVICE=/dev/serial0

MQTT_HOST=19***********

MQTT_USER=mqttbroker

MQTT_PASS=**********

MQTT_TOPIC=water

#Basis Informationen

modbus_array[0]=.MBusData.SlaveInformation.Id

modbus_array[1]=.MBusData.SlaveInformation.Manufacturer

modbus_array[2]=.MBusData.SlaveInformation.Version

modbus_array[3]=.MBusData.SlaveInformation.Status

#———————————————————-

while read ameter

do

echo -n "Getting data from $ameter…"

# The sed is for replacing the @ with _ to be able to match on it in HASS templates

METER_DATA=$(mbus-serial-request-data-multi-reply -b $BAUDRATE $DEVICE $ameter | xq . | sed -e "s/@/_/")

/usr/bin/mosquitto_pub -h $MQTT_HOST -u $MQTT_USER -P $MQTT_PASS -t $MQTT_TOPIC/$ameter -m "${METER_DATA}"

BYTCNT=$(echo "$METER_DATA" | wc -c)

echo " $BYTCNT bytes sent"

# Basis Parameter auslesen

for Parameter in "${modbus_array[@]}"

do

ausgabe=$(echo $METER_DATA | jq "$Parameter" )

#Punkte in / konvertieren für mqtt

Parameter=$(echo $Parameter | sed -e  "s/.//g")

/usr/bin/mosquitto_pub -h $MQTT_HOST -u $MQTT_USER -P $MQTT_PASS -t $MQTT_TOPIC/$ameter$Parameter -m "$ausgabe"

#Ausgabe des MQTT Pfades und Wertes

echo "$MQTT_TOPIC/$ameter$Parameter -> $ausgabe"

done

#Schleife über alle Data Records

for row in $(echo $METER_DATA | jq '.MBusData.DataRecord | keys'); do

#Leere Datenfelder am Anfang und Ende abfangen

if [[ ${row} != "[" ]] && [[ ${row} != "]" ]]

then

#Das Komma am Ende entfernen

id=$(echo "${row}" | sed -e "s/,//")

#Einen Int Wert daraus machen

nummer=$(("$id"+0))

#Alle Keys (Datenpunkte) auslesen

for name in $(echo $METER_DATA | jq ".MBusData.DataRecord[$nummer] | keys"); do

#Leere Datenfelder am Anfang und Ende abfangen

if [[ ${name} != "[" ]] && [[ ${name} != "]" ]]

then

# Ein paar Sonderzeichen aus dem Pfad entfernen

pfad=".MBusData.DataRecord[$nummer].${name}"

pfad=$(echo $pfad | sed "s/,//g")

pfad=$(echo $pfad | sed "s/.//g")

#Den richtigen Wert aus dem json holen

wert=$(echo $METER_DATA | jq $pfad)

#Umformatieren für eine MQTT Pfad

pfad=$(echo $pfad | sed "s/.///g")

pfad=$(echo $pfad | sed "s/[/_/g")

pfad=$(echo $pfad | sed "s/]//g")

#Zum MQTT Server senden

/usr/bin/mosquitto_pub -h $MQTT_HOST -u $MQTT_USER -P $MQTT_PASS -t $MQTT_TOPIC/$ameter$pfad -m "$wert"

echo "$MQTT_TOPIC/$ameter$pfad –> $wert"

fi

done

fi

done

done < <(cat $ADDRESS_FILE)

HI dknt,
I bought the same mbus master, do you have a schema how you connected it?
what components did you use?
do you still use this integration?

my goal is to read data from two of these:

@dknt is probably not online anymore.

is anybody else able to help me with this m-bus master

I’m in the same dilemma, the building has both water and power meters connected to m-bus, and I would really like to be able to sniff that data.

Building this myself doesn’t feel like a viable solution, I’m really not that into electronics :slight_smile: There’s no simpler way, using fewer components? Some breakout board that does most of the heavy lifting? :slight_smile:

I was in the same situation and after some looking I solve my situation with https://github.com/wmbusmeters/wmbusmeters-ha-addon and cheap RTL2832U DVB-T antena.
All that was needed to enable the mbus on my meter from the operator site and copy the id and key.

But that’s just for the wireless variant, right? My meter is wired, so I think the sniffing way is the only way for me :confused:

Hi Oscar,

unfortunately I have some higher priority projects currently running. Otherwise, I would really integrate such a device to be connected between meter and master to sniff the data. I’ll get back to this, when I have a bit more time, hopefully in a few weeks.

Regards,
Daniel