Closed drakesoft closed 1 year ago
same here
I have the same issue. I haven't verified this yet, but it seems fairly likely that this is related to the following change: https://github.com/esphome/esphome/commit/6089526975ee74b73d5b4975b7b481f37d50ac58
The meter model I am reading from is a "eBZD-W1E3-0L-HL0-D4-000001-F50/Q2". The value sent by the smart meter is 0xcad3a9 and gets converted to 18446744073709551616 (0x10000000000000000) in the SML sensor entry.
(0xca & 0x80) is true.
The issue probably appears because the only 3 bytes are transmitted when the number is small enough, so buffer.size() is 3. The issue neither appears for a smaller (0x69275d) number nor a bigger number (0x0133fb06)
Additional information:
[..]
[17:15:16][D][sensor:094]: 'Stromzähler Debug': Sending state 18446744073709551616.00000 with 0 decimals of accuracy
[..]
[17:15:16][D][sml:066]: OBIS info:
[17:15:16][D][sml:072]: (xx) 1-0:96.50.1 [xx]
[17:15:16][D][sml:072]: (xx) 1-0:96.1.0 [xx]
[17:15:16][D][sml:072]: (xx) 1-0:1.8.0 [0x0133fb06]
[17:15:16][D][sml:072]: (xx) 1-0:1.8.1 [0x69275d] <<--- this one is fine
[17:15:16][D][sml:072]: (xx) 1-0:1.8.2 [0xcad3a9] <<--- this is the measurement resulting in wrong values
[17:15:16][D][sml:072]: (xx) 1-0:2.8.0 [0x0aad] <<--- this one as well
[17:15:16][D][sml:072]: (xx) 1-0:16.7.0 [xx]
Hi fblaese, I can confirm your suspicion. The change https://github.com/esphome/esphome/commit/6089526975ee74b73d5b4975b7b481f37d50ac58 cause this issue. I just fixed it by removing the few lines of code.
@mulder-fbi @jesserockz
Is this extension of 24 bit signed integers part of the SML standard or is this a workaround for broken devices? Or is it my meter that is broken? Is there a way to differentiate between signed and unsigned values, so the extension is only applied to signed integers?
I have seen the 24 bit sigend integer behaviour with a DWS7612.2 smart meter. The protocol definition (unfortunately in german) I referenced when debugging the issue only talks about 8, 16, 32 and 64 bit integers (see 6.2.2). But it also allows for "full bytes with leading zeros or ones" to be omitted when the data is being transferred, if this does not change the value on the receiving side. So sending a 24 bit signed integer doesn't seem to violate the data type definition in general. 6.2.3. than goes on and allows omitting leading zeros for unsigned values. So from my point of view there is no way to implicitly derive the datatype on the receiving side. As far as I know the actual data type is not transmitted inside the message, so the only way to I could think of would be to add a signed/unsigned config flag in the yaml.
According to 6.2.3, leading-zero bytes can be ommited for unsigned data types without any restrictions, so the sent value is ambigous, sadly. The mentioned restriction only seems to apply for the signed data type.
I have found the following: "Aus der OBIS Kennzahl leitet sich implizit der konkrete Datentyp und der Wertebereich für das zu liefernde Ergebnis ab" (5.1.9) which means something like "The OBIS code implicitly defines the data type and its range". So it should be possible to derive the data type from the OBIS code. The full list of OBIS codes is defined in IEC 62056 and can be found here: https://www.promotic.eu/en/pmdoc/Subsystems/Comm/PmDrivers/IEC62056_OBIS.htm
I am not sure if vendor-specific extensions are allowed.
A manual flag for signed/unsigned extension might be a good first step to fix the regression, with proper handling of the OBIS codes (if possible) later on.
Actually, after skimming through the protocol definition a second time, it looks like it should be possible to derive the data type from the type-length (TL) field. A TL-value matching (0b01010000 & 0b01110000) should represent a signed integer while a TL-value matching (0b01100000 & 0b01110000) should represent an unsigend integer. (See 6.1 and 6.2f.)
It looks like the code already properly represents this as well. bytes_to_uint
is only called for unsigned integers. However, its code has been reused in the bytes_to_int
function.
The sign-extension should probably be placed in bytes_to_int
instead. I will do a PR with the required changes.
Ok, good catch. Thanks :)
I have made a PR, but I currently do not have a testing environment available. @drakesoft it would be great if you could test if the changes in https://github.com/esphome/esphome/pull/5544 fix the issue.
I have tested your changes (on ESP8266) and can confirm, that negative signed integers still work as expected. But I have no way to test the other failure mode reported here.
I have quickly set up a development and testing environment myself. It looks like my code does work as intended and does fix the issue of the original issue creator as well as maintaining correct sign extension for abbreviated transmissions.
I have therefore removed the draft tag from the PR.
@fblaese I tested the changes. Everything seems fine. :-) Great work. Thanks a lot
The problem
The reading 1-0:1.8.0 from meter marked with (x) is wrongly converted to a very very large number. Another meter with identical configuration does not show this issue. Maybe it has something to do with leading zeros? The meter with no issues shows leading zeros in hex value.
Which version of ESPHome has the issue?
2023.8.3
What type of installation are you using?
Home Assistant Add-on
Which version of Home Assistant has the issue?
No response
What platform are you using?
ESP32
Board
Lolin32-lite
Component causing the issue
sml
Example YAML snippet
Anything in the logs that might be useful for us?
Additional information