Using Slimmelezer+ to read data from energy meter Iskra AM550 from Romande Energie (Switzerland)

I’ve recently configured a custom sensor to read DSMR P1 data from Romande Energie through SlimmeLezer+ device.

To do so, I’ve reused some C code from Forsbergs

Find below the edited C code and the associated ESPhome configuration file.

Hope this will be useful for HA Swiss community.

p1reader.h

//-------------------------------------------------------------------------------------
// ESPHome P1 Electricity Meter custom sensor
// Copyright 2022 Sylvain Baron
// 
// History
//  0.1.0 2022-09-01:   Initial release
//
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
// IN THE SOFTWARE.
//-------------------------------------------------------------------------------------

#include "esphome.h"

#define BUF_SIZE 60

class ParsedMessage {
  public:
    double cumulativeActiveImport;
    double cumulativeActiveExport;

    double momentaryActiveImport;
    double momentaryActiveExport;

    double cumulativeActiveImportTarif1;
    double cumulativeActiveImportTarif2;

    double cumulativeActiveExportTarif1;
    double cumulativeActiveExportTarif2;

    double voltageL1;
    double voltageL2;
    double voltageL3;

    double currentL1;
    double currentL2;
    double currentL3;
};

class P1Reader : public Component, public UARTDevice {
  char buffer[BUF_SIZE];

  const int8_t OUTSIDE_FRAME = 0;
  const int8_t FOUND_FRAME = 1;


  int8_t parseHDLCState = OUTSIDE_FRAME;

  public:
    Sensor *cumulativeActiveImport = new Sensor();
    Sensor *cumulativeActiveExport = new Sensor();

    Sensor *cumulativeReactiveImport = new Sensor();
    Sensor *cumulativeReactiveExport = new Sensor();

    Sensor *momentaryActiveImport = new Sensor();
    Sensor *momentaryActiveExport = new Sensor();

    Sensor *cumulativeActiveImportTarif1 = new Sensor();
    Sensor *cumulativeActiveImportTarif2 = new Sensor();

    Sensor *cumulativeActiveExportTarif1 = new Sensor();
    Sensor *cumulativeActiveExportTarif2 = new Sensor();

    Sensor *voltageL1 = new Sensor();
    Sensor *voltageL2 = new Sensor();
    Sensor *voltageL3 = new Sensor();

    Sensor *currentL1 = new Sensor();
    Sensor *currentL2 = new Sensor();
    Sensor *currentL3 = new Sensor();

    P1Reader(UARTComponent *parent) : UARTDevice(parent) {}

    void setup() override { }

    void loop() override {
      readHDLCMessage();
    }


  private:
    void parseRow(ParsedMessage* parsed, char* obisCode, double value) {
      ESP_LOGD("parseRow", "OBIS %s value %f", obisCode, value);
      if (strncmp(obisCode, "1.8.0", 5) == 0) {
        parsed->cumulativeActiveImport = value;
      }
      else if (strncmp(obisCode, "2.8.0", 5) == 0) {
        parsed->cumulativeActiveExport = value;
      }
      else if (strncmp(obisCode, "1.7.0", 5) == 0) {
        parsed->momentaryActiveImport = value;
      }
      else if (strncmp(obisCode, "2.7.0", 5) == 0) {
        parsed->momentaryActiveExport = value;
      }
      else if (strncmp(obisCode, "1.8.1", 5) == 0) {
        parsed->cumulativeActiveImportTarif1 = value;
      }
      else if (strncmp(obisCode, "1.8.2", 5) == 0) {
        parsed->cumulativeActiveImportTarif2 = value;
      }
        else if (strncmp(obisCode, "2.8.1", 5) == 0) {
        parsed->cumulativeActiveExportTarif1 = value;
      }
      else if (strncmp(obisCode, "2.8.2", 5) == 0) {
        parsed->cumulativeActiveExportTarif2 = value;
      }
      else if (strncmp(obisCode, "32.7.0", 6) == 0) {
        parsed->voltageL1 = value;
      }
      else if (strncmp(obisCode, "52.7.0", 6) == 0) {
        parsed->voltageL2 = value;
      }
      else if (strncmp(obisCode, "72.7.0", 6) == 0) {
        parsed->voltageL3 = value;
      }
      else if (strncmp(obisCode, "31.7.0", 6) == 0) {
        parsed->currentL1 = value;
      }
      else if (strncmp(obisCode, "51.7.0", 6) == 0) {
        parsed->currentL2 = value;
      }
      else if (strncmp(obisCode, "71.7.0", 6) == 0) {
        parsed->currentL3 = value;
      }
    }


    void publishSensors(ParsedMessage* parsed) {
      momentaryActiveImport->publish_state(parsed->momentaryActiveImport);
      momentaryActiveExport->publish_state(parsed->momentaryActiveExport);

      cumulativeActiveImport->publish_state(parsed->cumulativeActiveImport);
      cumulativeActiveExport->publish_state(parsed->cumulativeActiveExport);

      cumulativeActiveImportTarif1->publish_state(parsed->cumulativeActiveImportTarif1);
      cumulativeActiveImportTarif2->publish_state(parsed->cumulativeActiveImportTarif2);

      cumulativeActiveExportTarif1->publish_state(parsed->cumulativeActiveExportTarif1);
      cumulativeActiveExportTarif2->publish_state(parsed->cumulativeActiveExportTarif2);

      voltageL1->publish_state(parsed->voltageL1);
      voltageL2->publish_state(parsed->voltageL2);
      voltageL3->publish_state(parsed->voltageL3);

      currentL1->publish_state(parsed->currentL1);
      currentL2->publish_state(parsed->currentL2);
      currentL3->publish_state(parsed->currentL3);
    }

    /* Reads messages formatted according to "Branschrekommendation v1.2", which
       at the time of writing (20210207) is used by Tekniska Verken's Aidon 6442SE
       meters. This is a binary format, with a HDLC Frame. 

       This code is in no way a generic HDLC Frame parser, but it does the job
       of decoding this particular data stream.
    */
    void readHDLCMessage() {
      if (available()) 
      {
        uint8_t data = 0;
        uint16_t crc = 0x0000;
        uint32_t uvalue = 0;
        char obis[7];

        ParsedMessage parsed = ParsedMessage();

        while (parseHDLCState == OUTSIDE_FRAME) {
          data = read();
          if (data == 0x7e) {
            ESP_LOGD("hdlc", "Found start of frame");
            parseHDLCState = FOUND_FRAME;
            break;

            int8_t next = peek();

            //ESP_LOGD("hdlc", "Next is %d", next);

            if (next == 0x7e) {
              read(); // We were actually at the end flag, consume the start flag of the next frame.
            }
            else if (next == -1) {
              ESP_LOGE("hdlc", "No char available after flag, out of sync. Returning");
              parseHDLCState = OUTSIDE_FRAME;
              return;
            }
          }
        }

      if (parseHDLCState == FOUND_FRAME) 
      {
        // Read various static HDLC Frame information we don't care about
        int len = Serial.readBytes(buffer, 12);
        if (len != 12) {
          ESP_LOGE("hdlc", "Expected 12 bytes, got %d bytes - out of sync. Returning", len);
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }
        //ESP_LOGD("hdlc", "Got %d HDLC bytes, now reading 4 Invoke ID And Priority bytes", len);          
        len = Serial.readBytes(buffer, 4);
        if (len != 4) {
          ESP_LOGE("hdlc", "Expected 4 bytes - out of sync, returning.", buffer[0], buffer[1]);
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }

        data = read(); // Expect length of date time field, usually 0
        //ESP_LOGD("hdlc", "Length of date time field is %d", data);
        Serial.readBytes(buffer, data);

        data = read();      
        //ESP_LOGD("hdlc", "Expect 0x02 (Structure tag), got %02X", data);
        if (data != 0x02) {
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }

        data = read();
        if (data != 0x0F) {
          ESP_LOGE("hdlc", "Expected 15 bytes, got %d bytes - out of sync. Returning", data);
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }

        // read serial number (96.1.0)
        if (Serial.readBytes(buffer, 2) != 2) {
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }

        if (buffer[0] != 0x09) {
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }
        
        uint8_t str_length = buffer[1];
        if (Serial.readBytes(buffer, str_length) != str_length) {
          ESP_LOGE("hdlc", "Unable to read %d bytes of serial number", str_length);
          parseHDLCState = OUTSIDE_FRAME;
          return;
        }

        // read momentary Active Import (1.7.0)
        strncpy(obis, "1.7.0", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          } 
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue);

        // read momentary Active Export (2.7.0)
        strncpy(obis, "2.7.0", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue);

        // read Cumulative active import energy (1.8.0)
        strncpy(obis, "1.8.0", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 1000); // convert in kW

        // read Cumulative active export energy (2.8.0)
        strncpy(obis, "2.8.0", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 1000); // convert in kW

        // read phase voltage L1 (32.7.0)
        strncpy(obis, "32.7.0", 7);
        data = read();
          if (data != 0x12) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        Serial.readBytes(buffer, 2); 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 10); // convert to V

        // read phase voltage L2 (52.7.0)
        strncpy(obis, "52.7.0", 7);
        data = read();
          if (data != 0x12) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        Serial.readBytes(buffer, 2); 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 10); // convert to V

        // read phase voltage L3 (72.7.0)
        strncpy(obis, "72.7.0", 7);
        data = read();
          if (data != 0x12) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        Serial.readBytes(buffer, 2); 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 10); // convert to V

        // read phase current L1 (31.7.0)
        strncpy(obis, "31.7.0", 7);
        data = read();
          if (data != 0x12) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        Serial.readBytes(buffer, 2); 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 10); // convert to A

        // read phase current L2 (51.7.0)
        strncpy(obis, "51.7.0", 7);
        data = read();
          if (data != 0x12) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        Serial.readBytes(buffer, 2); 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 10); // convert to A

        // read phase current L3 (71.7.0)
        strncpy(obis, "71.7.0", 7);
        data = read();
          if (data != 0x12) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        Serial.readBytes(buffer, 2); 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 10); // convert to A

        // read Cumulative active import energy tarif 1 (1.8.1)
        strncpy(obis, "1.8.1", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 1000); // convert in kW

        // read Cumulative active import energy tarif 2 (1.8.2)
        strncpy(obis, "1.8.2", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 1000); // convert in kW

        // read Cumulative active export energy tarif 1 (2.8.1)
        strncpy(obis, "2.8.1", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 1000); // convert in kW

        // read Cumulative active export energy tarif 2 (2.8.2)
        strncpy(obis, "2.8.2", 7);
        data = read();
          if (data != 0x06) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }  
        Serial.readBytes(buffer, 4);
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value for %s is %u", obis, uvalue);

        parseRow(&parsed, obis, uvalue / 1000); // convert in kW

        publishSensors(&parsed);

        while (true) 
        {
          data = read();
          //ESP_LOGD("hdlc", "Read char %02X", data);
          if (data == 0x7e) {
            ESP_LOGD("hdlc", "Found end of frame");
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        }
      }
    }
  }
};

p1reader.yaml

---
substitutions:
  device_name: p1reader
  device_description: "DIY P1 module to read your smart meter"
     
esphome:
  name: ${device_name}
  comment: "${device_description}"
  platform: ESP8266
#  esp8266_restore_from_flash: true
  board: d1_mini
  name_add_mac_suffix: false
  project:
    name: "Sylvain_hack.p1reader"
    version: "0.1"
  includes:
    - p1reader.h

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
 
# Optional manual IP
#  manual_ip:
#    static_ip: 192.168.50.132
#    gateway: 192.168.50.1
#    subnet: 255.255.255.0

# MAC Address: C8:C9:A3:7C:19:C7

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${device_name}
    ap_timeout: 15s
    password: !secret fallback_password
 
captive_portal:
 
# Enable logging
logger:
#  level: VERBOSE
  level: INFO
#  baud_rate: 0 # disable logging over uart
  baud_rate: 0
 
# Enable Home Assistant API
api:
  password: !secret hass_api_password
 
ota:
  password: !secret ota_password

#web_server:
#  port: 80
 
uart:
  id: uart_bus
  tx_pin: D8
  rx_pin: D7
  baud_rate: 115200
  rx_buffer_size: 256
  data_bits: 8
  parity: NONE
  stop_bits: 1

sensor:
- platform: custom
  lambda: |-
    auto meter_sensor = new P1Reader(id(uart_bus));
    App.register_component(meter_sensor);
    return {
      meter_sensor->momentaryActiveImport,
      meter_sensor->momentaryActiveExport,
      meter_sensor->cumulativeActiveImport,
      meter_sensor->cumulativeActiveExport,
      meter_sensor->cumulativeActiveImportTarif1,
      meter_sensor->cumulativeActiveImportTarif2,
      meter_sensor->cumulativeActiveExportTarif1,
      meter_sensor->cumulativeActiveExportTarif2,
      meter_sensor->voltageL1,
      meter_sensor->voltageL2,
      meter_sensor->voltageL3,
      meter_sensor->currentL1,
      meter_sensor->currentL2,
      meter_sensor->currentL3
    };

  sensors:
  - name: "Momentary Import"
    unit_of_measurement: W
    state_class: measurement
    device_class: power

  - name: "Momentary Export"
    unit_of_measurement: W
    state_class: measurement
    device_class: power

  - name: "Total Import"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

  - name: "Total Export"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

  - name: "Total Import T1"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

  - name: "Total Import T2"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

  - name: "Total Export T1"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

  - name: "Total Export T2"
    unit_of_measurement: kWh
    state_class: total_increasing
    device_class: energy

  - name: "Voltage Phase 1"
    unit_of_measurement: V
    accuracy_decimals: 1
    state_class: measurement
    device_class: voltage

  - name: "Voltage Phase 2"
    unit_of_measurement: V
    accuracy_decimals: 1
    state_class: measurement
    device_class: voltage

  - name: "Voltage Phase 3"
    unit_of_measurement: V
    accuracy_decimals: 1
    state_class: measurement
    device_class: voltage

  - name: "Current Phase 1"
    unit_of_measurement: A
    accuracy_decimals: 1
    state_class: measurement
    device_class: current

  - name: "Current Phase 2"
    unit_of_measurement: A
    accuracy_decimals: 1
    state_class: measurement
    device_class: current

  - name: "Current Phase 3"
    unit_of_measurement: A
    accuracy_decimals: 1
    state_class: measurement
    device_class: current
2 Likes

To reverse-engineer the HDLC frames, I’ve also used Gurux DLMS Translator using esp-link to read the raw data from the electricity meter.

Thanks @sybaron3 for posting your work here. I am currently trying to read an ISKRA AM550 from SIE SA (West of Lausanne) with a recently acquired SlimmeLezer. At this stage, I am unable to make it work even though I see the messages coming out from P1 both with an oscilloscope and an FTDI. However, I am unable to make sense of the frames I see and the Slimmelezer (default FW) is unable to decode them either.

Can you explain why the provided FW based on DSMR Component — ESPHome would not work as is?

1 Like

Hi jzuffere, did you had any luck since december ?
I also have an AM550 from SIE Lausanne and I only get binary data. I tried with the SlimmeLezer and with a direct serial connection to a computer. No luck atm.

Not yet, no. But still in contact with SIE on this topic. However, it looks like we’ll need to be patient as they are a bit underwater these times…

If you cannot wait, I suggest to take a look at the Shelly 3EM, a relatively low-cost alternative that interfaces very well to Home assistant, Solar Manager and alike.

By the way, I got a Slimmelezer working perfectly fine with an ENSOR meter provided by SEVJ at la Vallée de Joux.

1 Like

Hi Jeremie,
I added the ESPHome to home assistant and used the integration from Sylvain_Baron.p1reader to get it working on p1 port with slimmlezer device. it is working with esphome 2022.11.4 version as the new version of esphome has API key integrated, I have not spent time to figure that one out yet.
Let me know if you are interested to have the code.
you need to get the image file from slimmlezer website and load it with usb-c cable and esphome

@sybaron3 and anybody else in this topic. How does the AM550 communicates on the P1 port in Switzerland? Does it use DSMR as in the Nordic countries or is it DLMS to use a secure connection?
If it is DLMS, does it use any authentication or can you read basic data without that?

Thanks for the answers!

Hello,

I have an Iskra AM550 meter from Romande Energie.
On P1 port :
-Serial is 115200-8-n-1.
-Data format is hdlc.

I managed to read and get datas with this Python script :
https://github.com/Gurux/Gurux.DLMS.Python/tree/master/Gurux.DLMS.Push.Listener.Example.python

But it is pretty complex and I don’t understant everything. I wish I could decode it an easier way…
Receiving raw frame is easy. Decoding it to get values isn’t…

Any simple idea or format explanation ?

1 Like

The article in this comment summs it up:

Otherwise from a Github repo’s read me references in the comments of the aforementioned article (belongs to the author of the article).

Be warned that the DLMS protocol stack is created by a succession
of morons, doing one stupid thing after another for several decades.

This is DLMS Green book for reference:

And the Blue Book:

Hi Adam,
Could you explain in more details what you did to make it work ?
Should we flash the SlimmeLezer with a specific firmware (which one) ? Then use the P1read.yaml configuration ?
Thanks if you can provide some details if you succeeded to make it work !

Hi @sybaron3,
Could you provide more details how you made it work ? I am trying to use the SlimmeLezer+ to read data from ISKRA AM450 meter, but no luck so far…
Thanks if you can help !

@malonip, which country are you from? If from the EU then the DSO should provide you information how is the meter communicates. There is an EU directive (2019/944) which regulates what information should be provided to the end customer (Article 20). It should be implemented already in the local law as well.

Otherwise it depends on the meter’s firmware and settings how it communicates, what protocol does it use and what information does it provide in what frequency. Also, the P1 port should be activated as well to be able to use it. That should be activated either locally through the optical port by a service man or remotely by the DSO or on the DSO’s self service website if any. (Some DSOs allow these options through their metering and billing website.)
Also if encryption is used, you will need decipher key, if authentication is used (DLMS/COSEM), then you will need the username/password as well.
Most of the cases what I read about, the P1 port is either not encrypted, like in the Netherlands by the DSMR standard, or uses encryption (AES128) which can easily decrypted by the device with the decipher key. (Actually encryption is required by the EU directive for privacy reasons.)

Hi @GSzabados,
I am in Switzerland (French part).Our power company is Romande Energie/SIE. It seems that @sybaron3 and @asturges79 found a way to configure a Slimmelezer to work on the P1 port of the IKRA AM550 meter. It is why I was asking. Not sure they needed a decryption key at the end, but they may answer…
With the Slimmelezer out-of-the-box, the telegrams are not readable as is.

You can give a try to this old (and removed) project.

https://web.archive.org/web/20201121021717/https://github.com/saghonfly/shrdzm/releases

As I understand it can read the telegrams and display them as it is. Look at the picture.

@AdmiralStipe can confirm how it is working as he uses it with an Iskra AM550 in Slovenia.

And once you are sure what are the telegrams then you can update the p1meter description. My guess that is only the modification what @sybaron3 implemented. I couldn’t compare the original and his code as I am using my phone.

Thanks @GSzabados !

I am not skilled enough to analyze the telegrams and understand anything about them :wink:

Anyway, I’ve done the setup proposed by @sybaron3 with his p1reader.h code and p1reader.yaml configuration. Unfortunately, this doesn’t work and no valid frames can be captured by the Slimmelezer, see following screenshot:
image

Still stuck on the problem :cry:

The code is really specific there what it tries to read from the P1 port. You should first try to get a full message, then try to adjust the code according that.

By the regularity it seems to be the P1 port is outputting data. But I am a bit confused by some of the error messages. Especially the expected 12 bytes and received 16. When I looked at the code it seemed to me that is specifically reading 12 byte…

You’re right, the code is really specific… I will try to figure it out…

Hello
Someone managed to obtain usable data of the P1 port of a IKRA AM55 from the SIL?
Regards

Hello please find below the code for switzerland


substitutions:

device_name: slimmelezer

device_description: “DIY P1 module to read your smart meter”

esphome:

name: ${device_name}

comment: “${device_description}”

platform: ESP8266

esp8266_restore_from_flash: true

board: d1_mini

name_add_mac_suffix: false

project:

name: "Sylvain_hack.p1reader"

version: "0.1"

includes:

- p1reader.h

wifi:

ssid: !secret wifi_ssid

password: !secret wifi_password

MAC Address: C8:C9:A3:7C:19:C7

Enable fallback hotspot (captive portal) in case wifi connection fails

ap:

ssid: ${device_name}

ap_timeout: 15s

password: !secret fallback_password

captive_portal:

Enable logging

logger:

level: VERBOSE

level: INFO

baud_rate: 0 # disable logging over uart

baud_rate: 0

Enable Home Assistant API

api:

password: !secret hass_api_password

ota:

password: !secret ota_password

web_server:

port: 80

globals:

  • id: has_key

    type: bool

    restore_value: yes

    initial_value: “false”

  • id: stored_decryption_key

    type: char[32]

    restore_value: yes

dsmr:

id: dsmr_instance

For Luxembourg users set here your decryption key.

Enable this when using decryption for Luxembourg;

key looks like ‘00112233445566778899AABBCCDDEEFF’

#decryption_key: !secret decryption_key

Enable Home Assistant API

#api:

password: !secret hass_api_password

uart:

id: uart_bus

tx_pin: D8

rx_pin: D7

baud_rate: 115200

rx_buffer_size: 256

data_bits: 8

parity: NONE

stop_bits: 1

sensor:

  • platform: custom

    lambda: |-

    auto meter_sensor = new P1Reader(id(uart_bus));

    App.register_component(meter_sensor);

    return {

    meter_sensor->momentaryActiveImport,
    
    meter_sensor->momentaryActiveExport,
    
    meter_sensor->cumulativeActiveImport,
    
    meter_sensor->cumulativeActiveExport,
    
    meter_sensor->cumulativeActiveImportTarif1,
    
    meter_sensor->cumulativeActiveImportTarif2,
    
    meter_sensor->cumulativeActiveExportTarif1,
    
    meter_sensor->cumulativeActiveExportTarif2,
    
    meter_sensor->voltageL1,
    
    meter_sensor->voltageL2,
    
    meter_sensor->voltageL3,
    
    meter_sensor->currentL1,
    
    meter_sensor->currentL2,
    
    meter_sensor->currentL3
    

    };

    sensors:

    • name: “Momentary Import”

      unit_of_measurement: W

      state_class: measurement

      device_class: power

    • name: “Momentary Export”

      unit_of_measurement: W

      state_class: measurement

      device_class: power

    • name: “Total Import”

      unit_of_measurement: kWh

      state_class: total_increasing

      device_class: energy

    • name: “Total Export”

      unit_of_measurement: kWh

      state_class: total_increasing

      device_class: energy

    • name: “Total Import T1”

      unit_of_measurement: kWh

      state_class: total_increasing

      device_class: energy

    • name: “Total Import T2”

      unit_of_measurement: kWh

      state_class: total_increasing

      device_class: energy

    • name: “Total Export T1”

      unit_of_measurement: kWh

      state_class: total_increasing

      device_class: energy

    • name: “Total Export T2”

      unit_of_measurement: kWh

      state_class: total_increasing

      device_class: energy

    • name: “Voltage Phase 1”

      unit_of_measurement: V

      accuracy_decimals: 1

      state_class: measurement

      device_class: voltage

    • name: “Voltage Phase 2”

      unit_of_measurement: V

      accuracy_decimals: 1

      state_class: measurement

      device_class: voltage

    • name: “Voltage Phase 3”

      unit_of_measurement: V

      accuracy_decimals: 1

      state_class: measurement

      device_class: voltage

    • name: “Current Phase 1”

      unit_of_measurement: A

      accuracy_decimals: 1

      state_class: measurement

      device_class: current

    • name: “Current Phase 2”

      unit_of_measurement: A

      accuracy_decimals: 1

      state_class: measurement

      device_class: current

    • name: “Current Phase 3”

      unit_of_measurement: A

      accuracy_decimals: 1

      state_class: measurement

      device_class: current

text_sensor:

  • platform: wifi_info

    ip_address:

    name: “IP Address”

    ssid:

    name: “Wi-Fi SSID”

    bssid:

    name: “Wi-Fi BSSID”

  • platform: version

    name: “ESPHome Version”

    hide_timestamp: true