Open kolucciy opened 5 years ago
Is this over wired M-Bus or over an optical connection?
It is quite common for heat meters to only reply over opto after a preamble of some sort. Typical preambles are a series of "0x00" or "0x55" characters.
It's over an optical connection.
I will take a look and see if I can come up with something elegant.
@kolucciy any chance you are talking about a Landis gyr uh30 (T330) here (same prefix using optical mbus interface)? If so - did you succeed in reading it out? I am at the beginning of all the m-bus stuff atm and get responses already and try to figure out how to parse them in the best way.
In an old C code solution that I have, which was written to read data from M-Bus meter over the Optical interface, there is an opto_wake function. Using "8n1", it sends a bunch of 0x55 ('U') characters (01010101) where the count is based on the formula;
(ispeed / 10) * sleeptime
Where the speed is the baudrate and sleeptime is 2 seconds.
I can't recall what this code is based on. Probably something in a datasheet for one or more energy meters.
I don't think that any Opto wake solution should be part of the library. But it may be added the CLI tools.
There seems to be a difference between prefix (the leading 0x0 or 0x55 bytes) and the wakeup of the interface though.
For my heat meter the 210 0x0 bytes need to be prefixed to all m bus telegrams - but after some time of not using the optical interface it seems to go into a sleep mode where it does not respond to any telegrams.
It seems it is woken up by raising dtr and cts lines in a special manner but I have no idea how this would affect the ir interface at all (cause it has only tx and rx).
ATM I try to reverse engineer the wake up process from the manufacturer software - once woken up via original software the approach with the leading zeros works for me (until it goes to sleep again)
Hi @Memphiz,
That's what I ended up doing to read the meter for my HA setup.
Hope that helps
import meterbus
import serial
import logging
from homeassistant.const import ENERGY_KILO_WATT_HOUR
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the sensor platform."""
add_devices([T230Sensor()])
class T230Sensor(Entity):
"""Representation of a Sensor."""
def __init__(self):
"""Initialize the sensor."""
self._state = None
self.update()
@property
def name(self):
"""Return the name of the sensor."""
return 'ULTRAHEAT T230'
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return ENERGY_KILO_WATT_HOUR
def update(self):
"""Fetch new state data for the sensor.
This is the only method that should fetch new data for Home Assistant.
"""
ser = serial.Serial('/dev/ttyUSB0', 2400, 8, 'E', 1, 4)
try:
"""Ping... 5 times"""
connected = False
for i in range(0, 4):
ser.write(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x40\x00\x40\x16')
try:
frame = meterbus.load(meterbus.recv_frame(ser, 1))
if isinstance(frame, meterbus.TelegramACK):
connected = True
break
except meterbus.MBusFrameDecodeError:
pass
"""Read out"""
if connected:
ser.write(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x5b\x00\x5b\x16')
frame = meterbus.load(meterbus.recv_frame(ser))
#hass.components.mqtt.publish("t230_heating", frame.records[2].parsed_value/1000)
self._state = frame.records[2].parsed_value/1000
"""Read remaining frames"""
read_buffer = b''
chunk_size = 200
while True:
# Read in chunks. Each chunk will wait as long as specified by
# timeout. Increase chunk_size to fail quicker
byte_chunk = ser.read(size=chunk_size)
read_buffer += byte_chunk
if not len(byte_chunk) == chunk_size:
break
except meterbus.MBusFrameDecodeError as e:
_LOGGER.error("Could not fetch meter readings. Frame: %s", e.value)
ser.close()
Thx for sharing your code. I had something similar in place too. I think the retries made the difference - though those look like a workaround for doing something not as intended. It works ok as it seems. I have read for similar wake up procedures that there is a wait time after sending the zeros and before sending the first telegram (snd_nke in this code example). Not sure if that is the reason why it needs retries sometimes.
T230 and T330 share the init process in the "ultra assist" software as well so that's we it works here too I guess.
For pyMeterBus, to come back to topic, there should be no need to add anything for this. We can send the zeros first (only the zeros) and afterwards use the pyMeterBus APIs to send telegrams.
As I also think that this wakeup stuff is not mbus related but ZVEI (or how that optical interface is called) related.
Sorry for spamming this issue - but really glad for your replies - infinally can start optimizing my heating now that I have all the meter data inside fhem :)
It looks like my meter replies to the command only if its sent with a prefix of 210:
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x5b\x00\x5b\x16
instead of \x10\x5b\x00\x5b\x16 sent by:
meterbus.send_request_frame(ser, address)
Was wondering if there is a way to add this prefix? For now I run:
ser.write(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x5b\x00\x5b\x16')
frame = meterbus.load(meterbus.recv_frame(ser))
print(frame.to_JSON())