Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas meter value always '0' #51

Open
cjandrasits opened this issue Apr 26, 2020 · 44 comments
Open

Gas meter value always '0' #51

cjandrasits opened this issue Apr 26, 2020 · 44 comments

Comments

@cjandrasits
Copy link

Hi,

I am using the homeassistant integration with your dsmr_parser module.
My smartmeter is a version 5 smartmeter with standard settings (115200 8N1).

The readout with the parsed MBusObject always has value '0' for the HOURLY_GAS_METER_READING.
This readout is also used in the homeassistant integration.

When I look at the raw telegram_data of the TelegramObject I see that the gas meter reading is not 0 (truncated telegram with header and relevant line):

/ISK5\2M550T-1012

1-3:0.2.8(50)
[...]
0-2:24.2.1(200426223001S)(00246.138*m3)

So there seems to be a problem with the parsing :(

@ndokter
Copy link
Owner

ndokter commented Apr 27, 2020

Ah thats too bad. I dont actively work on this project, but could you post the full telegram here? Maybe i or someone else can look at it some time. Thanks!

@cjandrasits
Copy link
Author

Hi, thanks for your reply!

This is the full telegram:

/ISK5\2M550T-1012

1-3:0.2.8(50)
0-0:1.0.0(200426223325S)
0-0:96.1.1(4530303434303037333832323436303139)
1-0:1.8.1(002130.115*kWh)
1-0:1.8.2(000245.467*kWh)
1-0:2.8.1(000000.000*kWh)
1-0:2.8.2(000000.000*kWh)
0-0:96.14.0(0001)
1-0:1.7.0(00.111*kW)
1-0:2.7.0(00.000*kW)
0-0:96.7.21(00005)
0-0:96.7.9(00003)
1-0:99.97.0(1)(0-0:96.7.19)(190326095015W)(0000002014*s)
1-0:32.32.0(00001)
1-0:52.32.0(00001)
1-0:72.32.0(00192)
1-0:32.36.0(00001)
1-0:52.36.0(00001)
1-0:72.36.0(00001)
0-0:96.13.0()
1-0:32.7.0(229.9*V)
1-0:52.7.0(229.2*V)
1-0:72.7.0(222.9*V)
1-0:31.7.0(000*A)
1-0:51.7.0(000*A)
1-0:71.7.0(001*A)
1-0:21.7.0(00.056*kW)
1-0:41.7.0(00.000*kW)
1-0:61.7.0(00.055*kW)
1-0:22.7.0(00.000*kW)
1-0:42.7.0(00.000*kW)
1-0:62.7.0(00.000*kW)
0-1:24.1.0(003)
0-1:96.1.0()
0-1:24.2.1(700101010000W)(00000000)
0-2:24.1.0(003)
0-2:96.1.0(4730303339303031393336393930363139)
0-2:24.2.1(200426223001S)(00246.138*m3)
!56DD

Thanks!

@lowdef
Copy link
Contributor

lowdef commented May 3, 2020

I had a look, the problem seems to be the line:
0-1:24.2.1(700101010000W)(00000000)

This also matches the signature for HOURLY_GAS_METER_READING.

Like does the true entry for the gas meter:
0-2:24.2.1(200426223001S)(00246.138*m3)

I think this is a consequence of how the specification treats connected M-Bus devices:
https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf

Which uses 0-n:24.2.1.255 obis reference for any connected gas meter, water meter, temperature meter etc. Therefore from the signature alone one can not determine how to parse the value. (Currently the parser works on the assumption that the signatures are uniquely identifying certain information elements.)

Apparently the parser needs to know which device is which, this could maybe be done on the basis of the preceding DEVICE_TYPE value. But I could not at first glance determine the logic used here.

Note: The OBIS reference Channel number (n) will be defined by the installing order of the M-Bus devices. So for example a Gas meter can be installed on channel 1, 2, 3 or 4. For that reason the Device-Type is sent first to identify the medium on P1. A slave E-meter can also be
an M-Bus device.

The telegram you provided, shows that the DEVICE-TYPE for both connected devices is both 003.

0-1:24.1.0(003)
0-1:96.1.0()
0-1:24.2.1(700101010000W)(00000000)
0-2:24.1.0(003)
0-2:96.1.0(4730303339303031393336393930363139)
0-2:24.2.1(200426223001S)(00246.138*m3)

I do not have access to the EN 13757-3 specification which apparently specifies the codes, but I found this: http://read.pudn.com/downloads677/ebook/2739011/ocr%20pdf/3.pdf. See chapter "5.8 Device type identification".

Device Type 3 appears to be a gas meter. Which obviously is not correct for the entry "0-1:24.2.1(700101010000W)(00000000)".

Maybe this helps in finding a solution to the problem, some possible alternatives:

  1. If possible fix the erroneous Mbus setup. That would result in correct P1 telegrams.
  2. Filter the offending entries from the telegram, before presenting it to the parser.
  3. Bigger endeavour: improve the parsing of Mbus information to take into account Device Type and allow multiple entries for the same kind of information. But this will not help in case of faulty device type information in P1 telegrams.

Here is the raw dump of the code i used to analyse the issue:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun May  3 12:27:42 2020

@author: lowdef
"""

from dsmr_parser import telegram_specifications
from dsmr_parser.objects import Telegram
from dsmr_parser.parsers import TelegramParser
from dsmr_parser.parsers import MBusParser
from dsmr_parser.parsers import ValueParser
from dsmr_parser import obis_references
from dsmr_parser.value_types import timestamp
from decimal import Decimal



telegram_cjandrasits  = r"""/ISK5\2M550T-1012

1-3:0.2.8(50)
0-0:1.0.0(200426223325S)
0-0:96.1.1(4530303434303037333832323436303139)
1-0:1.8.1(002130.115*kWh)
1-0:1.8.2(000245.467*kWh)
1-0:2.8.1(000000.000*kWh)
1-0:2.8.2(000000.000*kWh)
0-0:96.14.0(0001)
1-0:1.7.0(00.111*kW)
1-0:2.7.0(00.000*kW)
0-0:96.7.21(00005)
0-0:96.7.9(00003)
1-0:99.97.0(1)(0-0:96.7.19)(190326095015W)(0000002014*s)
1-0:32.32.0(00001)
1-0:52.32.0(00001)
1-0:72.32.0(00192)
1-0:32.36.0(00001)
1-0:52.36.0(00001)
1-0:72.36.0(00001)
0-0:96.13.0()
1-0:32.7.0(229.9*V)
1-0:52.7.0(229.2*V)
1-0:72.7.0(222.9*V)
1-0:31.7.0(000*A)
1-0:51.7.0(000*A)
1-0:71.7.0(001*A)
1-0:21.7.0(00.056*kW)
1-0:41.7.0(00.000*kW)
1-0:61.7.0(00.055*kW)
1-0:22.7.0(00.000*kW)
1-0:42.7.0(00.000*kW)
1-0:62.7.0(00.000*kW)
0-1:24.1.0(003)
0-1:96.1.0()
0-1:24.2.1(700101010000W)(00000000)
0-2:24.1.0(003)
0-2:96.1.0(4730303339303031393336393930363139)
0-2:24.2.1(200426223001S)(00246.138*m3)
!56DD
"""

sample = telegram_cjandrasits.replace('\n', '\r\n')

parser = TelegramParser(telegram_specifications.V5)
telegram = Telegram(sample, parser, telegram_specifications.V5)

print(telegram)

print(obis_references.HOURLY_GAS_METER_READING)
# \d-\d:24\.2\.1.+?\r\n

print(telegram.HOURLY_GAS_METER_READING.values)

# matching is correct, both for working version and not working version
# working 0-1:24.2.1(200501130000S)(10618.003*m3)	
# https://pythex.org/?regex=%5Cd-%5Cd%3A24%5C.2%5C.1.%2B%3F&test_string=0-1%3A24.2.1(200501130000S)(10618.003*m3)&ignorecase=0&multiline=0&dotall=0&verbose=0
# not working 0-2:24.2.1(200426223001S)(00246.138*m3)
# https://pythex.org/?regex=%5Cd-%5Cd%3A24%5C.2%5C.1.%2B%3F&test_string=0-2%3A24.2.1(200426223001S)(00246.138*m3)&ignorecase=0&multiline=0&dotall=0&verbose=0

# so it must be in the parsing itself

#        obis.HOURLY_GAS_METER_READING: MBusParser(
#            ValueParser(timestamp),
#            ValueParser(Decimal)


#The MBusParser itself works correctly:
hgm1 = MBusParser(ValueParser(timestamp), ValueParser(Decimal)).parse(r"0-1:24.2.1(200501130000S)(10618.003*m3)\r\n")
print("reference")
print(hgm1.values)

print("gas meter line")
hgm2 = MBusParser(ValueParser(timestamp), ValueParser(Decimal)).parse(r"0-2:24.2.1(200426223001S)(00246.138*m3)\r\n")
print(hgm2.values)

print("offending line")
hgm3 = MBusParser(ValueParser(timestamp), ValueParser(Decimal)).parse(r"0-1:24.2.1(700101010000W)(00000000)\r\n")
print(hgm3.values)

# if we remove the offending line from the telegram
# 0-1:24.2.1(700101010000W)(00000000)
telegram_adapted = r"""/ISK5\2M550T-1012

1-3:0.2.8(50)
0-0:1.0.0(200426223325S)
0-0:96.1.1(4530303434303037333832323436303139)
1-0:1.8.1(002130.115*kWh)
1-0:1.8.2(000245.467*kWh)
1-0:2.8.1(000000.000*kWh)
1-0:2.8.2(000000.000*kWh)
0-0:96.14.0(0001)
1-0:1.7.0(00.111*kW)
1-0:2.7.0(00.000*kW)
0-0:96.7.21(00005)
0-0:96.7.9(00003)
1-0:99.97.0(1)(0-0:96.7.19)(190326095015W)(0000002014*s)
1-0:32.32.0(00001)
1-0:52.32.0(00001)
1-0:72.32.0(00192)
1-0:32.36.0(00001)
1-0:52.36.0(00001)
1-0:72.36.0(00001)
0-0:96.13.0()
1-0:32.7.0(229.9*V)
1-0:52.7.0(229.2*V)
1-0:72.7.0(222.9*V)
1-0:31.7.0(000*A)
1-0:51.7.0(000*A)
1-0:71.7.0(001*A)
1-0:21.7.0(00.056*kW)
1-0:41.7.0(00.000*kW)
1-0:61.7.0(00.055*kW)
1-0:22.7.0(00.000*kW)
1-0:42.7.0(00.000*kW)
1-0:62.7.0(00.000*kW)
0-1:24.1.0(003)
0-1:96.1.0()
0-2:24.1.0(003)
0-2:96.1.0(4730303339303031393336393930363139)
0-2:24.2.1(200426223001S)(00246.138*m3)
!56DD
"""

sample2 = telegram_adapted.replace('\n', '\r\n')
telegram_specification = telegram_specifications.V5
telegram_specification['checksum_support']=False

telegram2 = Telegram(sample2, parser, telegram_specification)
print("remove the offending line and switch of CRC check")
print(telegram2.HOURLY_GAS_METER_READING.values)

@Quarco
Copy link

Quarco commented Jun 1, 2020

I have exactly the same problem; in Domoticz there was an option to set an uservariable 'P1GasMeterChannel' to, in my case, 2. That worked like a charm for 2 years now.
But.. having installed Home Assistant right now, looking forward to connect the P1 cable into HA :-)

@cjandrasits
Copy link
Author

Hi,

thank you for taking the time to look into this in such great detail!
It really makes sense, and it also is now clear to me why other parsers have worked - it depends on the order and the way several values for the same signature are treated. In case of this implementation, all values are stored and the first one encountered used. In another implementation values are overwritten, so you get the last one. I guess noone expects two values for the same device type.
I think both can result in the wrong parsing...

I can not fix any Mbus-Setup, I actually bought a cable and just plugged it in the P1-Meter and this is what it is sending...
Thinking about your other ideas, I don't think filtering out the lines is a good idea if this version should be usable for everyone - I would need my own fork and building on top of that my own Dockerimage for Home Assistant with this version etc. etc.
Figuring out from the telegrams which device is which would be nice, but as you said the device type is the same for two different devices on two different channels.

That's why I really appreciate @Quarco's comment - in cases as ours we can set the channels ourselves. Also in my case the channel would be 2, I guess?

0-1:24.2.1(700101010000W)(00000000)   // offending line
0-2:24.2.1(200426223001S)(00246.138*m3)  // correct one that should be parsed

An explanation for that is also listed as a 'Known Issue' here:
https://www.domoticz.com/wiki/Dutch_DSMR_smart_meter_with_P1_port

@Quarco
Copy link

Quarco commented Jun 2, 2020

...As i don't see a solution in the very-near future i called my electicity company and explained the problem. They will now send an engineer to clear the meter/channels and install my gas meter to channel#1. (best of all: no charges. Thank you Liander!)

but.... a configuration/variable would be a much better solution of course.
My problem is a (previous) gas meter was already configured in my smartmeter, so there is a gasmeter-id on the first channel and the DSMR stops looking further after finding the first valid entry.

@gilgamezh
Copy link

hello! Any known workaround for this issue?
I have the same problem

0-1:24.1.0(003)
0-1:96.1.0()
0-1:24.2.1(700101010000W)(00000000)
0-2:24.1.0(003)
0-2:96.1.0(4730303634303032303231353334383230)
0-2:24.2.1(220213171504W)(01302.251*m3)
!6ADD

@subNiels
Copy link

subNiels commented Mar 7, 2022

I have had the same problem. I guess the issue lies within the parser.py

In the code below the parser looks for the first object (signature) hit.
HA-dsmr-parser

In the example of @gilgamezh there are two channels in use, only the first channel returns the value 0. In my case they network operator replaced the gas meter because it had some issues. And the new meter was connected to the second channel.

Below my part of the telegram data with two read outs of gas meters, 0-1 is the old meter and 0-2 is the new one:
0-1:96.1.0(4730303339303031383136333235303138)
0-1:24.2.1(220302095001W)(04225.102m3)
0-2:24.1.0(003)
0-2:96.1.0(4730303738353635363036323338303231)
0-2:24.2.1(220307203505W)(00023.565
m3)

As you can see in the telegram specification it is possible to have up to four gas meters connected to the energy meter.
obis gasdata

In my opinion it goes wrong in the parser code, because it doesn't read all lines in the telegram and matches those to the objects (signatures). But it does it the other-way around, try to find the first hit of an object. So when 0-1:24:2.1 is found it doesn't look further if there are more lines matching the signatures.

A quick solution if you only want to read out one gas reading is to change the signature in obis_references.py
HOURLY_GAS_METER_READING = r'\d-\d:24.2.1.+?\r\n', by changing the \d: to the corresponding 'channel' it will read out the right one.

So for me and for @gilgamezh this should be OURLY_GAS_METER_READING = r'\d-2:24.2.1.+?\r\n'

for me this works as a charm at the moment also in combination with home assistant.
The file I had to alter on my HA install was: ./usr/local/lib/python3.9/site-packages/dsmr_parser/obis_references.py
after that restart HA.

@ariekraakjr
Copy link

Same problem here.
0-1:24.1.0(003)
0-1:96.1.0(4730303332353631323638313931343136)
0-1:24.2.1(170113170000W)(00001.287m3)
0-2:24.1.0(003)
0-2:96.1.0(4730303332353631323638313932353136)
0-2:24.2.1(220920160000S)(07995.618
m3)
!EE02

Can't use the workaround like @subNiels because i use HA inside docker.

@subNiels
Copy link

subNiels commented Sep 23, 2022

Hi @ariekraakjr I also run HA inside a docker, I made a small script to run within docker to copy the adjusted file after an update of my container. Important are the steps to follow then:

  1. first disconnect the P1 reader,
  2. then update container
  3. then copy the file inside the container
  4. restart ha container
  5. connect P1 reader

I copied the adjusted obis_references file to the HA config folder, so after a update this files still exists. After logging in trough console I run the following command (i put this in a script as well) from the location where the adjusted obis_references.py file is located:
cp obis_references.py /usr/local/lib/python*/site-packages/dsmr_parser/obis_references.py

This will copy the adjusted obis_refference file to the file location of the used file by HA. After a restart of the container everting works well for me.

I hope this will help you.

@askmurphy
Copy link

Same problem here.

Can't use the workaround like @subNiels because i use HA inside docker.

It's possible, use portainer:
Portainer->Containers->homeassistant , open console, and edit the file with 'vi' :
cd /usr/local/lib/python3.10/site-packages/dsmr_parser
vi obis_references.py

Ofcourse this all is just a temporary workaround, dsrm_parser needs some improvement..

@askmurphy
Copy link

askmurphy commented Oct 11, 2022

Another telegram snippet with the same problem, two read outs of gas meters, 0-1 is the old meter and 0-2 is the new one:
0-1:96.1.0(4730303339303031383136333235303138)
0-1:24.2.1(220302095001W)(04225.102m3)
0-2:24.1.0(003)
0-2:96.1.0(4730303738353635363036323338303231)
0-2:24.2.1(220307203505W)(00023.565m3)

Months later, we got a new gasmeter. Now the telegram is changed again:
image

Now, 0-2 is the old meter and 0-3 is the new one...

Parser still reading the wrong data 😢

@ndokter
Copy link
Owner

ndokter commented Oct 11, 2022

I like the idea of a P1_METER_GAS_CHANNEL setting (that defaults to channel 1 i guess). Which in turn determines what HOURLY_GAS_METER_READING will return

The main question is when and where this setting can be set

@renskorswagen
Copy link

Same issue here...

@twangraus
Copy link

Has there been any progress on this?

@ndokter
Copy link
Owner

ndokter commented Jan 14, 2023

I was thinking that maybe we can do more with the Telegram object. Like indicating what the active gas meter reading is. Either by doing it intelligently or manual passing the channel number.

So to start i think i want the parser to return a Telegram object. We already had one, but it was wrapping the parser. I refactored that a bit:
#121

Then i'm thinking we can for now (optionally) pass the gas meter channel number via TelegramParser(.., gas_meter_channel=1). This thengets passed to the Telegram object which can use it to return the correct gas reading.

Anyone got thoughts on this?

@lowdef
Copy link
Contributor

lowdef commented Jan 14, 2023 via email

@ndokter
Copy link
Owner

ndokter commented Jan 14, 2023

Thanks. I've pushed some WIP. So if i'm on the same page:

  • the TelegramParser will now parse all lines matching the 'signature' (regex) and put these in a list
  • the DSMRObject will get a channel attribute and is responsible to figure out which channel it is on. All lines seem to have a channel if i'm looking at the x-x part?
  • the Telegram object currently has 2 ways to get the lines. These will perform the same behavior and return the first result:
    • telegram.HOURLY_GAS_METER_READING
    • telegram[obis.HOURLY_GAS_METER_READING]
  • the Telegram object gets a method which allows you to pass in the channel number. For example telegram.get(obis.HOURLY_GAS_METER_READING, channel=1)

@lowdef
Copy link
Contributor

lowdef commented Jan 15, 2023

Hi Nigel,

I read through the code changes. In general I like very much where it is going.

Some questions / remarks:

  • Isn't it so that the channel concept only is relevant for MBUS devices, so wouldn't it be better placed in the MBusObject?
  • If I would like to get all the values for a specific MBUS device, how would I go about and retrieve this in one go?
  • Would I be able to address the device based on device-type and channel? (The issue is everything is still line based, but MBUS devices are actually represented as multi-line entries.)

A little brainstorm how it could be:

DEVICE_TYPE_GAS_METER = 003

# Telegram new methods
def get_mbus_devices  --> return list of MBUSDeviceObject
def get_mbus_device(device_type, channel) --> MBUSDeviceObject containing a list of the relevant MBusObject

# then i can retrieve all values for the gas meter as
get_mbus_device(DEVICE_TYPE_GAS_METER)

# and if there is multiple of them
gas_meter_reading = get_mbus_device(DEVICE_TYPE_GAS_METER, channel)

# how it could be used
print(gas_meter_reading)  # print all values for the device
print(gas_meter_reading.DEVICE_TYPE)  # address specific values for the device
print(gas_meter_reading.EQUIPMENT_IDENTIFIER)  # address specific values for the device
print(gas_meter_reading.VALVE_POSITION)  # address specific values for the device
print(gas_meter_reading.GAS_METER_READING)  # address specific values for the device

BR,
Hans Erik

@ndokter
Copy link
Owner

ndokter commented Jan 15, 2023

My initial idea was the following
Example telegram:

0-0:17.0.0(999.9*kW)
1-0:31.4.0(999*A)
0-0:96.13.0()
0-1:24.1.0(003)
0-1:96.1.1(37464C4F32313139303333373333)
0-1:24.4.0(1)
0-1:24.2.3(200512134558S)(00112.384*m3)
0-2:24.1.0(007)
0-2:96.1.1(3853414731323334353637383930)
0-2:24.2.1(200512134558S)(00872.234*m3)

I noticed that all lines have an ID part before the :. So i thought i would add this for all objects, and use it like so:

parser = TelegramParser(telegram_specifications.V5, apply_checksum_validation=False)
result = parser.parse(test_telegram)

# Current behaviors. These will get the first reading so it stays backwards compatible
print('dict like: ', result[obis.HOURLY_GAS_METER_READING])
print('as attribute: ', result.HOURLY_GAS_METER_READING)

# The 'get' (not sure about name) also uses the obis regex, but optionally accepts the channel (the 2 in example: 0-2)
print('channel 2: ', result.get(obis.HOURLY_GAS_METER_READING, channel=2))
print('all channels: ', result.get(obis.HOURLY_GAS_METER_READING))  
dict like:  872.234	[m3] at 2020-05-12T13:45:58+02:00
as attribute:  872.234	[m3] at 2020-05-12T13:45:58+02:00

channel 2:  872.234	[m3] at 2020-05-12T13:45:58+02:00
# it actually fails here already because the obis regex is too specific now, so i get 1 instead of 2 objects:
all channels:  [<dsmr_parser.objects.MBusObject object at 0x7fa9aac03490>]  

So the idea was to group all of '0-n:24.2.x' and allow selecting using the 'n'. This seems more simple, but using the device lines seems more correct. So using your approach that would also mean that in general you would stop using HOURLY_GAS_METER_READING and GAS_METER_READING right?

Ill try to give your idea a go somewhere this week :)

Update: im looking into a new laptop after which i can continue developing

@lowdef
Copy link
Contributor

lowdef commented Jan 15, 2023

So the idea was to group all of '0-n:24.2.x' and allow selecting using the 'n'. This seems more simple, but using the device lines seems more correct.

How where you going to group them?

So using your approach that would also mean that in general you would stop using HOURLY_GAS_METER_READING and GAS_METER_READING right?

Maybe we would offer them still as to not break all existing usages, and say it is deprecated. Then in some future major release you could drop them? Not sure what is wisdom here.

@dupondje
Copy link
Collaborator

@ndokter : Or we could go the way like we did with the belgian meter. Just report type and values of all mbus devices connected, and let the software using the dmsr_parser then decide what to do with it.

Cause there might be situations where you have 2 gas meters connected for ex?

@dennissiemensma
Copy link
Contributor

dennissiemensma commented Jan 20, 2023 via email

@dupondje
Copy link
Collaborator

Ah see :)

Personally I would do the same like the Belgian DSMR meter. Just report the values/type of each mbus, and then let the application which uses dsmr_parser to decide what to do with it.

@ndokter
Copy link
Owner

ndokter commented Feb 8, 2023

Update: found out that water meters, gas meters and thermal/heat/cold meters all use the same OBIS id's. So im working on something that lowdef suggested. Something like Telegram.devices that returns MbusDevices that have attributes like device.DEVICE_TYPE.

I did push something earlier today when i was still thinking i could go for a more simple solution, but that doesn't work

@ndokter
Copy link
Owner

ndokter commented Feb 12, 2023

I currently have made the following changes:

  • added MbusDevice object which is similar to Telegram, but holds values from mbus devices based on the channel ID. Example records that would be added to a MbusDevice are:
    '0-1:24.1.0(003)\r\n'
    '0-1:96.1.0()\r\n'
    '0-1:24.2.1(700101010000W)(00000000)\r\n'
    '0-2:24.1.0(003)\r\n'
    '0-2:96.1.0(4730303339303031393336393930363139)\r\n'
    '0-2:24.2.1(200426223001S)(00246.138*m3)\r\n'

The 0-1 and 0-2 would be added to separate MbusDevice objects which have the attributes: DEVICE_TYPE, EQUIPMENT_IDENTIFIER_GAS and HOURLY_GAS_METER_READING

  • added Telegram.get_mbus_devices() which returns all MbusDevice objects sorted by channel ID (1 and 2 in previous example)
  • added Telegram.get_mbus_device_by_channel(channel_id) which is a helper to get a specific MbusDevice more easily
  • sort of removed the telegram dictionary approach and always return a Telegram object that is mostly compatible with the old approach
  • updated documentation a bit to reflect changes and tried to compact it a bit. Not sure if it's a direct improvement or not :)

If anyone has time, please let me know what you think

PR: #121

@dennissiemensma
Copy link
Contributor

I like the changes and it seems a good addition for clients having multiple mbus devices.

@dennissiemensma
Copy link
Contributor

However, please note that I do not directly use the latest (unaltered) version of DSMR-parser (or its low-level features) in DSMR-reader, so opinions of others should be taken more seriously for sure.

@lowdef
Copy link
Contributor

lowdef commented Feb 12, 2023

the telegram logic does not work and can be simplified i think. Have to admit that I do not understand the current get_mbus_devices code.

What shows me there is something wrong here, just using some arbitrary code without mbus devices:

PyDev console: starting.
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
runfile('/home/hanserik/projects/donderstraal/develop/issue92_Q3D_with_COM-1.py', wdir='/home/hanserik/projects/donderstraal/develop')
Q3D_EQUIPMENT_IDENTIFIER: 	 0272031312565	[None]
ELECTRICITY_IMPORTED_TOTAL: 	 52185.7825309	[kWh]
ELECTRICITY_EXPORTED_TOTAL: 	 19949.3221493	[kWh]
INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE: 	 747.85	[W]
INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE: 	 737.28	[W]
INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE: 	 639.73	[W]
CURRENT_ELECTRICITY_USAGE: 	 2124.86	[W]
Q3D_EQUIPMENT_STATE: 	 80	[None]
Q3D_EQUIPMENT_SERIALNUMBER: 	 1ESY1313002565	[None]
telegram.get_mbus_devices()
[]
telegram.get_mbus_device_by_channel(1)
<dsmr_parser.objects.MbusDevice object at 0x7f67f502d660>
telegram.get_mbus_devices()
[<dsmr_parser.objects.MbusDevice object at 0x7f67f502d660>]
telegram.get_mbus_device_by_channel(1)
<dsmr_parser.objects.MbusDevice object at 0x7f67f502d660>
telegram.get_mbus_devices()
[<dsmr_parser.objects.MbusDevice object at 0x7f67f502d660>]
telegram.get_mbus_device_by_channel(2)
<dsmr_parser.objects.MbusDevice object at 0x7f67f502dc30>
telegram.get_mbus_devices()
[<dsmr_parser.objects.MbusDevice object at 0x7f67f502d660>, <dsmr_parser.objects.MbusDevice object at 0x7f67f502dc30>]

get_mbus_devices() returns an empty list as expected.
Now I start asking for the mbus_device with channel_id 1, instead of some empty value I get actually an MBusDevice object!

Whats more executing again get_mbus_devices() , the list is no longer empty.
This means that the get_mbus_device_by_channel() method has an unwanted side effect. And the result is incorrect.

@ndokter
Copy link
Owner

ndokter commented Feb 12, 2023

Thank you @lowdef that is a serious bug! It was caused by incorrect use of 'defaultdict' by me. It would instantiate a new MbusDevice for channels that did not exist. I have pushed the fix.

The code currently groups all records that start with '0-<channel_id>' together in the MbusDevice object and exposes it via get_mbus_devices and get_mbus_device_by_channel. Do you mean by simplify, that you would merge them together?

@lowdef
Copy link
Contributor

lowdef commented Feb 12, 2023

No, I must admit that I do not understand code like:
[d[1] for d in sorted(self._mbus_devices.items(), key=lambda x: x[0])]

I wonder if this can be expressed in a more intuitive manner.

How does the sorting help? If there are for example channels 1 and 3, you would still always need to inspect the elements.

@ndokter
Copy link
Owner

ndokter commented Feb 12, 2023

I have added the channel ID to the MbusDevice itself and rewritten the sorting to be more intuitive:

    def get_mbus_devices(self):
        """
        Return MbusDevice objects which are used for water, heat and gas meters.
        """
        mbus_devices = self._mbus_channel_devices.values()
        mbus_devices = sorted(mbus_devices, key=attrgetter('channel_id'))

        return mbus_devices

The sorting might not be needed indeed. I thought it would be nice if you want to list them somewhere and the order would be 1, 2, 3 guaranteed

@lowdef
Copy link
Contributor

lowdef commented Feb 12, 2023

you are quick ;-)

What is nagging me: is there something against adding setattr(self, name, value) to the add method?
We can then drop __getattr__() and the code becomes more explicit and understandable.
The change was tried out in code mentioned in issue #122.

@ndokter
Copy link
Owner

ndokter commented Feb 12, 2023

Oh wow that actually makes a lot of sense! I will try to incorporate that change and your other changes about the str and json method missing a bit later this week.

Thanks a lot for your time and effort so far

@dupondje
Copy link
Collaborator

dupondje commented Feb 21, 2023

Somewhat late to the party :) But my comments:

print(mbus_device.EQUIPMENT_IDENTIFIER_GAS.value)  # '4730303339303031393336393930363139'
print(mbus_device.HOURLY_GAS_METER_READING.value)  # Decimal('246.138')

I think we should have something more generic here.
mbus_device.EQUIPMENT_IDENTIFIER
mbus_device.METER_READING

So this can be used for any kind of device.
Cause if there is a 'HOURLY_GAS_METER_READING', it doesn't mean there is a gas meter.

Can you also print the mbus_device channel-nr? mbus_device.CHANNEL_ID for example?

@ndokter
Copy link
Owner

ndokter commented Feb 22, 2023

@dupondje good point. Sounds like a good followup. It should probably be done using the DEVICE_ID (24.1.0), but i'm not sure how it works.

In the following telegram (dsmr v5) i see the gas meter as device type 007:

    '0-1:24.1.0(003)\r\n'
    '0-1:96.1.1(37464C4F32313139303333373333)\r\n'
    '0-1:24.4.0(1)\r\n'
    '0-1:24.2.3(200512134558S)(00112.384*m3)\r\n'
    '0-2:24.1.0(007)\r\n'
    '0-2:96.1.1(3853414731323334353637383930)\r\n'
    '0-2:24.2.1(200512134558S)(00872.234*m3)\r\n'

And in this one (dsmr v4) it's 003:

    '0-1:24.1.0(003)\r\n'
    '0-1:96.1.0(4819243993373755377509728609491464)\r\n'
    '0-1:24.2.1(161129200000W)(00981.443*m3)\r\n'

@dupondje
Copy link
Collaborator

@ndokter :

Device types are described here:
https://oms-group.org/fileadmin/files/download4all/specification/Vol2/4.1.2/OMS-Spec_Vol2_Primary_v412.pdf

Electricity meter 02h
Gas meter 03h
Heat meter 04h
Warm water meter (30°C ... 90°C) 06h
Water meter 07h

So a Gas meter is 003, a water meter is 007.

And in Belgium the gas meter value is on 24.2.3 because:
Note 2: Be aware that for the gas volume, another OBIS-code is published than the one listed in section 7
of DSMR P1. This is due to the fact that in Belgium the not-temperature corrected gas volume is used
while in the Netherlands, the temperature corrected gas volume is used.

@lowdef
Copy link
Contributor

lowdef commented Feb 22, 2023

It would be also nice to parse these device_types in to meaningful names as well... :-)

@fromNL
Copy link

fromNL commented Oct 28, 2023

I placed a thread here: home-assistant/core#101342
Possibly it should be posted here? dupondje asked me to go here.

It seems to me that the meter should work as expected.
Here is part of the data (which you call telegram):
0-1:24.1.0(003)
0-1:96.1.0(4730303930303034323238393738323233)
0-1:24.2.1(231003134001S)(00003.416*m3)
!75FF
The complete data is on the link above.

My gas meter is currently at 27 m3, so I have lost a lot of data by now.
In the above communication I found "0-1:24.1.0(003)", "a Gas meter is 003" see 2 messages above mine.

I am seeing no data at all, it is not getting extracted to H.A.

Recently I updated H.A. to a more current core version (2023.10.3), but I see no improvement.
When I did the integration in H.A. I had chosen version 5.
I also tried re-configuring the "Netbeheer Nederland" integration, but it won't let me do that (already installed it says). I do not want to remove it, as I would possibly loose all other data (electricity).

I do not know where, but I found somewhere that the current parser does not support DSMR 5.0 in my (newly placed) meter Landis+Gyr E360, and that it only went up to 4.2 (I can't find the page anymore).

I hope this message is placed correctly and that it may lead to an improvement in the H.A. integration of the gas values.

@dupondje
Copy link
Collaborator

@fromNL :

HOURLY_GAS_METER_READING = r'^\d-\d:24\.2\.1.+?\r\n'

Do you have any other 24.2.1 codes in your telegram? Otherwise the issue is something else.
24.2.1 should get parsed correctly on V4 or V5

@fromNL
Copy link

fromNL commented Oct 29, 2023

I do see 0-1:24.2.1 is present, and just only one time.
This means the script should extract the data? But I still have zero values for gas_meter_gas_consumption. It is 'enabled' and 'visible'.
If the data is there, it should get extracted. Isn't this strange?

I took these lines from the debug info, it should be the complete telegram.
Here it is:
/XMX5LGF0010460963654
1-3:0.2.8(50)
0-0:1.0.0(231003134353S)
0-0:96.1.1(4530303637303036303936333635343233)
1-0:1.8.1(000025.413kWh)
1-0:1.8.2(000008.808kWh)
1-0:2.8.1(000038.871kWh)
1-0:2.8.2(000030.975kWh)
0-0:96.14.0(0002)
1-0:1.7.0(00.000kW)
1-0:2.7.0(00.305kW)
0-0:96.7.21(00005)
0-0:96.7.9(00005)
1-0:99.97.0(3)(0-0:96.7.19)(000101000000W)(0000000226s)(000101000000W)(0000006783s)(000101000000W)(0000241161s)
1-0:32.32.0(00001)
1-0:52.32.0(00003)
1-0:72.32.0(00004)
1-0:32.36.0(00000)
1-0:52.36.0(00000)
1-0:72.36.0(00000)
0-0:96.13.0()
1-0:32.7.0(237.0
V)
1-0:52.7.0(236.2V)
1-0:72.7.0(235.5V)
1-0:31.7.0(000A)
1-0:51.7.0(001A)
1-0:71.7.0(000A)
1-0:21.7.0(00.050
kW)
1-0:41.7.0(00.000kW)
1-0:61.7.0(00.000kW)
1-0:22.7.0(00.000kW)
1-0:42.7.0(00.326kW)
1-0:62.7.0(00.028kW)
0-1:24.1.0(003)
0-1:96.1.0(4730303930303034323238393738323233)
0-1:24.2.1(231003134001S)(00003.416
m3)
!75FF

@dupondje
Copy link
Collaborator

@fromNL: Checked parsing of that telegram, and it seems to be correct.
The value is parsed like it should with V5:
'{"datetime": "2023-10-03T13:40:01+02:00", "value": 3.416, "unit": "m3"}'

So it's not a dsmr_parser issue.

@fromNL
Copy link

fromNL commented Oct 30, 2023

Thanks for checking. I thought the same to be honest, and you directed me to this project (ndokter/dsmr_parser).

Does this mean my previous thread at hassio was placed correct?
It is not working, and I did place debug info there. But I get no response.

@fromNL
Copy link

fromNL commented Oct 30, 2023

After a while, we found out I had integration 5B installed. As soon as I updated this to version 5 and restarted H.A. all was looking well. I did have one entity that I had to delete afterwards, but that was it. For me it is case closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests