spacemanspiff2007 / sml2mqtt

Sml to MQTT Bridge
GNU General Public License v3.0
25 stars 8 forks source link

sml2mqtt: no negative values for active power #6

Closed mrumpf closed 2 years ago

mrumpf commented 2 years ago

The active power value "01000f0700ff" pushed from sml2mqtt does not differentiate between sending energy to the grid or receiving energy from the grid. It seems as if this information is encoded in the status field of "0100020801ff" and "0100010801ff" where a value of "418" shows that energy is pushed to the grid, in which case the active power "01000f0700ff" value should be negative.

[2022-03-03 15:15:42,367] [sml.device.ttyUSB0     ] INFO     |             <SmlListEntry>
[2022-03-03 15:15:42,369] [sml.device.ttyUSB0     ] INFO     |                 obis           : 0100010800ff
[2022-03-03 15:15:42,370] [sml.device.ttyUSB0     ] INFO     |                 status         : 418
[2022-03-03 15:15:42,371] [sml.device.ttyUSB0     ] INFO     |                 val_time       : None
[2022-03-03 15:15:42,373] [sml.device.ttyUSB0     ] INFO     |                 unit           : 30
[2022-03-03 15:15:42,374] [sml.device.ttyUSB0     ] INFO     |                 scaler         : -1
[2022-03-03 15:15:42,375] [sml.device.ttyUSB0     ] INFO     |                 value          : 300371964
[2022-03-03 15:15:42,376] [sml.device.ttyUSB0     ] INFO     |                 value_signature: None
[2022-03-03 15:15:42,378] [sml.device.ttyUSB0     ] INFO     |                 -> 30037196.4Wh (Zählerstand Total)
[2022-03-03 15:15:42,379] [sml.device.ttyUSB0     ] INFO     |             <SmlListEntry>
[2022-03-03 15:15:42,380] [sml.device.ttyUSB0     ] INFO     |                 obis           : 0100020800ff
[2022-03-03 15:15:42,382] [sml.device.ttyUSB0     ] INFO     |                 status         : 418
[2022-03-03 15:15:42,383] [sml.device.ttyUSB0     ] INFO     |                 val_time       : None
[2022-03-03 15:15:42,384] [sml.device.ttyUSB0     ] INFO     |                 unit           : 30
[2022-03-03 15:15:42,386] [sml.device.ttyUSB0     ] INFO     |                 scaler         : -1
[2022-03-03 15:15:42,387] [sml.device.ttyUSB0     ] INFO     |                 value          : 691569621
[2022-03-03 15:15:42,389] [sml.device.ttyUSB0     ] INFO     |                 value_signature: None
[2022-03-03 15:15:42,390] [sml.device.ttyUSB0     ] INFO     |                 -> 69156962.1Wh

[2022-03-03 15:15:42,420] [sml.device.ttyUSB0     ] INFO     |             <SmlListEntry>
[2022-03-03 15:15:42,421] [sml.device.ttyUSB0     ] INFO     |                 obis           : 01000f0700ff
[2022-03-03 15:15:42,422] [sml.device.ttyUSB0     ] INFO     |                 status         : None
[2022-03-03 15:15:42,423] [sml.device.ttyUSB0     ] INFO     |                 val_time       : None
[2022-03-03 15:15:42,424] [sml.device.ttyUSB0     ] INFO     |                 unit           : 27
[2022-03-03 15:15:42,425] [sml.device.ttyUSB0     ] INFO     |                 scaler         : -1
[2022-03-03 15:15:42,426] [sml.device.ttyUSB0     ] INFO     |                 value          : 41890
[2022-03-03 15:15:42,427] [sml.device.ttyUSB0     ] INFO     |                 value_signature: None
[2022-03-03 15:15:42,428] [sml.device.ttyUSB0     ] INFO     |                 -> 4189.0W

The value 4189W is the current energy that is delivered to the grid and this value should be negative, i.e. -4189.0W.

After sundown the status value changed from 418 (0x01A2) to 386 (0x0182), which is Bit 5 that seems to be the direction indicator:

[2022-03-03 18:33:30,287] [sml.device.ttyUSB0     ] INFO     |             <SmlListEntry>
[2022-03-03 18:33:30,288] [sml.device.ttyUSB0     ] INFO     |                 obis           : 0100010800ff
[2022-03-03 18:33:30,289] [sml.device.ttyUSB0     ] INFO     |                 status         : 386
[2022-03-03 18:33:30,290] [sml.device.ttyUSB0     ] INFO     |                 val_time       : None
[2022-03-03 18:33:30,291] [sml.device.ttyUSB0     ] INFO     |                 unit           : 30
[2022-03-03 18:33:30,292] [sml.device.ttyUSB0     ] INFO     |                 scaler         : -1
[2022-03-03 18:33:30,293] [sml.device.ttyUSB0     ] INFO     |                 value          : 300377177
[2022-03-03 18:33:30,294] [sml.device.ttyUSB0     ] INFO     |                 value_signature: None
[2022-03-03 18:33:30,295] [sml.device.ttyUSB0     ] INFO     |                 -> 30037717.7Wh (Zählerstand Total)
[2022-03-03 18:33:30,296] [sml.device.ttyUSB0     ] INFO     |             <SmlListEntry>
[2022-03-03 18:33:30,297] [sml.device.ttyUSB0     ] INFO     |                 obis           : 0100020800ff
[2022-03-03 18:33:30,298] [sml.device.ttyUSB0     ] INFO     |                 status         : 386
[2022-03-03 18:33:30,299] [sml.device.ttyUSB0     ] INFO     |                 val_time       : None
[2022-03-03 18:33:30,300] [sml.device.ttyUSB0     ] INFO     |                 unit           : 30
[2022-03-03 18:33:30,301] [sml.device.ttyUSB0     ] INFO     |                 scaler         : -1
[2022-03-03 18:33:30,302] [sml.device.ttyUSB0     ] INFO     |                 value          : 691655821
[2022-03-03 18:33:30,303] [sml.device.ttyUSB0     ] INFO     |                 value_signature: None
[2022-03-03 18:33:30,304] [sml.device.ttyUSB0     ] INFO     |                 -> 69165582.1Wh

[2022-03-03 18:33:30,330] [sml.device.ttyUSB0     ] INFO     |             <SmlListEntry>
[2022-03-03 18:33:30,332] [sml.device.ttyUSB0     ] INFO     |                 obis           : 01000f0700ff
[2022-03-03 18:33:30,332] [sml.device.ttyUSB0     ] INFO     |                 status         : None
[2022-03-03 18:33:30,333] [sml.device.ttyUSB0     ] INFO     |                 val_time       : None
[2022-03-03 18:33:30,334] [sml.device.ttyUSB0     ] INFO     |                 unit           : 27
[2022-03-03 18:33:30,335] [sml.device.ttyUSB0     ] INFO     |                 scaler         : -1
[2022-03-03 18:33:30,336] [sml.device.ttyUSB0     ] INFO     |                 value          : 2649
[2022-03-03 18:33:30,337] [sml.device.ttyUSB0     ] INFO     |                 value_signature: None
[2022-03-03 18:33:30,338] [sml.device.ttyUSB0     ] INFO     |                 -> 264.9W

The issue is also described here for the Tasmota firmware project: https://github.com/arendst/Tasmota/issues/8001#issuecomment-604868066

This seems to be an issue only for some older energy meters, in my case an eHz-HW8..., which does not allow to enable extended frames. The option in the menu, after entering the meter PIN, is simply missing.

One idea to solve the issue is to not only write the values into the sml2mqtt/ tree, but also the status:

sml2mqtt/080c2aec2d4c7239/01000f0700ff/value=300377177
sml2mqtt/080c2aec2d4c7239/01000f0700ff/status=386

sml2mqtt/080c2aec2d4c7239/0100010800ff/value=691655821
sml2mqtt/080c2aec2d4c7239/0100010800ff/status=386

sml2mqtt/080c2aec2d4c7239/0100020800ff/value=2649
sml2mqtt/080c2aec2d4c7239/0100020800ff/status=None

Maybe even having an option "-x" (Extended) where all the data from the SML frames is dumped to MQTT?

With the extended information my script that reads the sml2mqtt values from MQTT and pushes them to the tree for my wallbox could do the necessary transformations.

spacemanspiff2007 commented 2 years ago

Wouldn't it be sufficient to just make the value negative if the 5th bit of the status is set? It's a bit ugly because the sign of the reported power depends on a field from the energy meter. 👎

mrumpf commented 2 years ago

Yes, it is not nice, but that is exactly what I implemented and it is working for me now: https://github.com/mrumpf/sml2mqtt/commit/6ffbd962c851013237e8dd158cfc70dfc037a0e2

spacemanspiff2007 commented 2 years ago

I'm currently working on a major update and I've already included the workaround as a config option. Over the course of the next two weeks everything should be good to be released.

spacemanspiff2007 commented 2 years ago

I'm hijacking this thread since this also solves the issue.

I've pushed a working version of 1.0 into this repository. This is a huge code change so I'm not ready to push it to pypi yet. However I'd like to get feedback as soon as possible. The configuration structure has completely changed so you have to recreate your config from scratch. I've created a dummy config in the readme which you can use or you can just rename your config file and sml2mqtt will create a new one.

The main difference is that you can now configure per value what will be reported and on which topic.

@mrumpf @nohn @HWiese1980 Would you be willing to test the new version and provide feedback? If you have any questions you can just ask them here. Hint: Start with the -a config switch so you see what will be published and how

nohn commented 2 years ago

@spacemanspiff2007 sure.

However: The Raspberry Pi running sml2mqtt is mounted in an electric cabinet (so due to the position of the SD card slot, there is no easy way for a backup/restore) and I'm not firm in the Python ecosystem.

Could you please provide a step by step guide how to install the 1.0 version from Github in parallel to the current one without touching the 0.6 at all, so I can switch back in case 1.0 doesn't work as expected?

spacemanspiff2007 commented 2 years ago

Sure - I'll write it down, but it's untested. If something doesn't work just give me a heads up

This will install it into /opt/sml2mqtt_new so you can just delete the folder after testing. I think you have to stop the old version before starting the new one, otherwise you'll get a serial device error.

cd /opt/sml2mqtt_new
python3 -m venv venv
source venv/bin/activate

copy requirements_setup.txt from this repo into /opt/sml2mqtt_new folder

python -m pip install --upgrade -r requirements_setup.txt

copy src/sml2mqtt from this repo into /opt/sml2mqtt_new/sml2mqtt folder

run

python3 -m sml2mqtt -c /opt/sml2mqtt_new/config.yaml -a

to analyze the frame and create a new configuration. Play around with the configuration until everything is as you desire. It'll output directly to stdout.

then re run without the -a switch

nohn commented 2 years ago
$ python3 -m sml2mqtt -c /opt/sml2mqtt_new/config.yaml -a
Traceback (most recent call last):
  File "/usr/lib/python3.9/runpy.py", line 188, in _run_module_as_main
    mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
  File "/usr/lib/python3.9/runpy.py", line 147, in _get_module_details
    return _get_module_details(pkg_main_name, error)
  File "/usr/lib/python3.9/runpy.py", line 111, in _get_module_details
    __import__(pkg_name)
  File "/opt/sml2mqtt_new/sml2mqtt/__init__.py", line 7, in <module>
    from sml2mqtt.config import CONFIG
  File "/opt/sml2mqtt_new/sml2mqtt/config/__init__.py", line 1, in <module>
    from .config import CONFIG
  File "/opt/sml2mqtt_new/sml2mqtt/config/config.py", line 4, in <module>
    from easyconfig import AppConfigModel, ConfigModel
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/__init__.py", line 6, in <module>
    from easyconfig.models import AppConfigModel, ConfigModel, PathModel
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/models/__init__.py", line 2, in <module>
    from .config_model import ConfigModel
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/models/config_model.py", line 6, in <module>
    import easyconfig.config_obj
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/config_obj/__init__.py", line 1, in <module>
    from easyconfig.config_obj.config_obj import EasyConfigObj, PARENT_ROOT
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/config_obj/config_obj.py", line 9, in <module>
    from easyconfig.config_obj.model_access import ModelModelAccess, ModelModelTupleAccess, ModelValueAccess
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/config_obj/model_access/__init__.py", line 1, in <module>
    from .value_access import ModelValueAccess
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/config_obj/model_access/value_access.py", line 9, in <module>
    from easyconfig.yaml import CommentedMap
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/yaml/__init__.py", line 1, in <module>
    from easyconfig.yaml.yaml import CommentedMap, CommentedSeq, yaml_rt, yaml_safe
  File "/opt/sml2mqtt_new/venv/lib/python3.9/site-packages/easyconfig/yaml/yaml.py", line 1, in <module>
    import ruamel.yaml  # type: ignore
ModuleNotFoundError: No module named 'ruamel'
spacemanspiff2007 commented 2 years ago

Could you additionally run

python -m pip install --upgrade pydantic ruamel.yaml

Somehow the additional dependencies were not installed.

nohn commented 2 years ago

Seems to work. I'll however need to take some time to "Play around with the configuration until everything is as you desire."

To me it's a bit unclear what is a must and what is optional in the config. For example, do I need to replace DEVICE_ID_HEX with a real value, if so with which or will it work magically, if I leave it like that?

nohn commented 2 years ago

A config migration guide would be great, maybe even an automatic config migration tool. Especially for users upgrading through pip.

spacemanspiff2007 commented 2 years ago

I've provided a sample config in the readme where there are some more comments.

DEVICE_ID_HEX is the value that the device reports under 0100000009ff. It's also printed on your energy meter after "Server-ID". If you observe the -a output you'll see if a default configuration is created or the entries from the file are taken. You'll typically want to set the entry under mqtt so the topic is nice and readable.

Each device reports values. For each value you can set the topic. The key is the OBIS_HEX. You'll typically want to use Energie or Leistung there. Then you can run mathematical transformation (e.g. round values) and add some filters so you don't get an update of the value every second.

Under the device you can configure values and how they are reported. Typically you'll want to set at least the corresponding topic entry

My current configuration. I have to energy meters: one for light and one for heating. This is the light configuration.

I want the energy report on change or every hour. I want the power report on a 5% power change or every 2 mins (default from republish after)

AAAAAAAAAAAAAAAAAAAA:
  mqtt:
    topic: licht
  skip:
  - 0100010801ff
  values:
    0100010800ff:
      mqtt:
        topic: energie
      transformations:
      - round: 1
      filters:
      - every: 3600

    0100100700ff:
      mqtt:
        topic: leistung
      filters:
      - perc: 5
nohn commented 2 years ago

It seems to work as expected, I couldn't find any obvious problems. But I found the configuration in the old version to be cleaner / more intuitive.