Using Slimmelezer+ to read data from energy meter Aidon 6534 with communication module 6442SE (swedish branschrekommendation)

This worked perfectly. Thank you. Don’t know why but I did not get the solution in the first post to work.

However I have a question. What resolution do you get on the current reading. I only get 1 decimal. I think that is abot low.

Tack / micke

Editing this to answer what i found out by digging some more

Struggling with this issue as well.
Tried to follow your solution, but I don’t know how.

How do you adopt to ESP Home after installing firmware?

Ended up using Home Assistant add-on to be able to edit ESPHome devices

How do you access config/esphome ?

After installing ESPHome add-on, the config/esphome is accessible trough any file editor withing Home Assistant.

How do you access ESP Home to paste the p1reader.yaml file?

trough the ESPHome add-on. Choosing “Edit” on the one you need to change the YAML file on.

How do you install & run?

“Install” button available inside the “Edit” function in the ESPHome add-on

Feel like all these questions are linked together. Can you help me in the right direction on how to proceed?

I did the changes that you did, but I still cant get it to show any data. All fields are NA.

The reader I have is Aidon 6483 SE. Don’t know if there is any difference between the one you have and mine…

Micke,

I have 3 decimals.

You are correct with your own answers. Sorry for missing these details in my write-up.
My first hint would be:
power / wiring
The HAN port of my Aidon unit was disabled by default. I had to ask TV to enable this function for me.
Therefore, do you see your Slimmelezer “online” when it is connected to the Aidon reader?
Can you read the log wirelessly?

Recently order an slimmelezer+ and got it working with my aidon 6534, aidon 6442 S yesterday.
It’s a smaller power grid and they are running the binary version of the specification.

Used:

p1reader.yaml

esphome:
  name: slimmelezer-se
  platform: ESP8266
  board: d1_mini
  includes:
    - p1reader.h


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "slimmelezer-se"

captive_portal:

# Enable logging
logger:
  level: DEBUG
  baud_rate: 0 # disable logging over uart
  
# Enable Home Assistant API
api:

ota:

web_server:
  port: 80

uart:
  id: uart_bus
  rx_pin: D7
  baud_rate: 115200
  
sensor:
- platform: custom
  lambda: |-
    auto meter_sensor = new P1Reader(id(uart_bus), true);
    App.register_component(meter_sensor);
    return {
      meter_sensor->cumulativeActiveImport,
      meter_sensor->cumulativeActiveExport,
      meter_sensor->cumulativeReactiveImport,
      meter_sensor->cumulativeReactiveExport,
      meter_sensor->momentaryActiveImport,
      meter_sensor->momentaryActiveExport,
      meter_sensor->momentaryReactiveImport,
      meter_sensor->momentaryReactiveExport,
      meter_sensor->momentaryActiveImportL1,
      meter_sensor->momentaryActiveExportL1,
      meter_sensor->momentaryActiveImportL2,
      meter_sensor->momentaryActiveExportL2,
      meter_sensor->momentaryActiveImportL3,
      meter_sensor->momentaryActiveExportL3,
      meter_sensor->momentaryReactiveImportL1,
      meter_sensor->momentaryReactiveExportL1,
      meter_sensor->momentaryReactiveImportL2,
      meter_sensor->momentaryReactiveExportL2,
      meter_sensor->momentaryReactiveImportL3,
      meter_sensor->momentaryReactiveExportL3,
      meter_sensor->voltageL1,
      meter_sensor->voltageL2,
      meter_sensor->voltageL3,
      meter_sensor->currentL1,
      meter_sensor->currentL2,
      meter_sensor->currentL3
    };
  sensors:
  - name: "Cumulative Active Import"
    unit_of_measurement: kWh
    accuracy_decimals: 3
    state_class: "total_increasing"
    device_class: "energy"
  - name: "Cumulative Active Export"
    unit_of_measurement: kWh
    accuracy_decimals: 3
    state_class: "total_increasing"
    device_class: "energy"
  - name: "Cumulative Reactive Import"
    unit_of_measurement: kvarh
    accuracy_decimals: 3
  - name: "Cumulative Reactive Export"
    unit_of_measurement: kvarh
    accuracy_decimals: 3
  - name: "Momentary Active Import"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Active Export"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Reactive Import"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Reactive Export"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Active Import Phase 1"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Active Export Phase 1"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Active Import Phase 2"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Active Export Phase 2"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Active Import Phase 3"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Active Export Phase 3"
    unit_of_measurement: kW
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "power"
  - name: "Momentary Reactive Import Phase 1"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Reactive Export Phase 1"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Reactive Import Phase 2"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Reactive Export Phase 2"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Reactive Import Phase 3"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Momentary Reactive Export Phase 3"
    unit_of_measurement: kvar
    accuracy_decimals: 3
  - name: "Voltage Phase 1"
    unit_of_measurement: V
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "voltage"
  - name: "Voltage Phase 2"
    unit_of_measurement: V
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "voltage"
  - name: "Voltage Phase 3"
    unit_of_measurement: V
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "voltage"
  - name: "Current Phase 1"
    unit_of_measurement: A
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "current"
  - name: "Current Phase 2"
    unit_of_measurement: A
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "current"
  - name: "Current Phase 3"
    unit_of_measurement: A
    accuracy_decimals: 3
    state_class: "measurement"
    device_class: "current"

p1reader.h

//-------------------------------------------------------------------------------------
// ESPHome P1 Electricity Meter custom sensor
// Copyright 2020 Pär Svanström
// 
// History
//  0.1.0 2020-11-05:   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"
#include <math.h>

#define BUF_SIZE 60

class ParsedMessage {
  public:
    double cumulativeActiveImport;
    double cumulativeActiveExport;

    double cumulativeReactiveImport;
    double cumulativeReactiveExport;

    double momentaryActiveImport;
    double momentaryActiveExport;

    double momentaryReactiveImport;
    double momentaryReactiveExport;

    double momentaryActiveImportL1;
    double momentaryActiveExportL1;

    double momentaryActiveImportL2;
    double momentaryActiveExportL2;

    double momentaryActiveImportL3;
    double momentaryActiveExportL3;

    double momentaryReactiveImportL1;
    double momentaryReactiveExportL1;

    double momentaryReactiveImportL2;
    double momentaryReactiveExportL2;

    double momentaryReactiveImportL3;
    double momentaryReactiveExportL3;

    double voltageL1;
    double voltageL2;
    double voltageL3;

    double currentL1;
    double currentL2;
    double currentL3;

    bool crcOk = false;
};

class P1Reader : public Component, public UARTDevice {
  const char* DELIMITERS = "()*:";
  const char* DATA_ID = "1-0";
  char buffer[BUF_SIZE];
  bool useHDLCReader = false;

  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 *momentaryReactiveImport = new Sensor();
    Sensor *momentaryReactiveExport = new Sensor();

    Sensor *momentaryActiveImportL1 = new Sensor();
    Sensor *momentaryActiveExportL1 = new Sensor();

    Sensor *momentaryActiveImportL2 = new Sensor();
    Sensor *momentaryActiveExportL2 = new Sensor();

    Sensor *momentaryActiveImportL3 = new Sensor();
    Sensor *momentaryActiveExportL3 = new Sensor();

    Sensor *momentaryReactiveImportL1 = new Sensor();
    Sensor *momentaryReactiveExportL1 = new Sensor();

    Sensor *momentaryReactiveImportL2 = new Sensor();
    Sensor *momentaryReactiveExportL2 = new Sensor();

    Sensor *momentaryReactiveImportL3 = new Sensor();
    Sensor *momentaryReactiveExportL3 = 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) {}

    P1Reader(UARTComponent *parent, bool useHDLCReader) : UARTDevice(parent)
    {
      this->useHDLCReader = useHDLCReader;
    }

    void setup() override { }

    void loop() override
    {
      if (useHDLCReader) {
        readHDLCMessage();
      } else {
        readP1Message();
      }
    }

  private:
    uint16_t crc16_update(uint16_t crc, uint8_t a) {
      int i;
      crc ^= a;
      for (i = 0; i < 8; ++i) {
        if (crc & 1) {
            crc = (crc >> 1) ^ 0xA001;
        } else {
            crc = (crc >> 1);
        }
      }
      return crc;
    }

    void parseRow(ParsedMessage* parsed, char* obisCode, double 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, "3.8.0", 5) == 0) {
        parsed->cumulativeReactiveImport = value;

      } else if (strncmp(obisCode, "4.8.0", 5) == 0) {
        parsed->cumulativeReactiveExport = 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, "3.7.0", 5) == 0) {
        parsed->momentaryReactiveImport = value;

      } else if (strncmp(obisCode, "4.7.0", 5) == 0) {
        parsed->momentaryReactiveExport = value;

      } else if (strncmp(obisCode, "21.7.0", 6) == 0) {
        parsed->momentaryActiveImportL1 = value;

      } else if (strncmp(obisCode, "22.7.0", 6) == 0) {
        parsed->momentaryActiveExportL1 = value;

      } else if (strncmp(obisCode, "41.7.0", 6) == 0) {
        parsed->momentaryActiveImportL2 = value;

      } else if (strncmp(obisCode, "42.7.0", 6) == 0) {
        parsed->momentaryActiveExportL2 = value;

      } else if (strncmp(obisCode, "61.7.0", 6) == 0) {
        parsed->momentaryActiveImportL3 = value;

      } else if (strncmp(obisCode, "62.7.0", 6) == 0) {
        parsed->momentaryActiveExportL3 = value;

      } else if (strncmp(obisCode, "23.7.0", 6) == 0) {
        parsed->momentaryReactiveImportL1 = value;

      } else if (strncmp(obisCode, "24.7.0", 6) == 0) {
        parsed->momentaryReactiveExportL1 = value;

      } else if (strncmp(obisCode, "43.7.0", 6) == 0) {
        parsed->momentaryReactiveImportL2 = value;

      } else if (strncmp(obisCode, "44.7.0", 6) == 0) {
        parsed->momentaryReactiveExportL2 = value;

      } else if (strncmp(obisCode, "63.7.0", 6) == 0) {
        parsed->momentaryReactiveImportL3 = value;

      } else if (strncmp(obisCode, "64.7.0", 6) == 0) {
        parsed->momentaryReactiveExportL3 = 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) {
      cumulativeActiveImport->publish_state(parsed->cumulativeActiveImport);
      cumulativeActiveExport->publish_state(parsed->cumulativeActiveExport);

      cumulativeReactiveImport->publish_state(parsed->cumulativeReactiveImport);
      cumulativeReactiveExport->publish_state(parsed->cumulativeReactiveExport);

      momentaryActiveImport->publish_state(parsed->momentaryActiveImport);
      momentaryActiveExport->publish_state(parsed->momentaryActiveExport);

      momentaryReactiveImport->publish_state(parsed->momentaryReactiveImport);
      momentaryReactiveExport->publish_state(parsed->momentaryReactiveExport);

      momentaryActiveImportL1->publish_state(parsed->momentaryActiveImportL1);
      momentaryActiveExportL1->publish_state(parsed->momentaryActiveExportL1);

      momentaryActiveImportL2->publish_state(parsed->momentaryActiveImportL2);
      momentaryActiveExportL2->publish_state(parsed->momentaryActiveExportL2);

      momentaryActiveImportL3->publish_state(parsed->momentaryActiveImportL3);
      momentaryActiveExportL3->publish_state(parsed->momentaryActiveExportL3);

      momentaryReactiveImportL1->publish_state(parsed->momentaryReactiveImportL1);
      momentaryReactiveExportL1->publish_state(parsed->momentaryReactiveExportL1);

      momentaryReactiveImportL2->publish_state(parsed->momentaryReactiveImportL2);
      momentaryReactiveExportL2->publish_state(parsed->momentaryReactiveExportL2);

      momentaryReactiveImportL3->publish_state(parsed->momentaryReactiveImportL3);
      momentaryReactiveExportL3->publish_state(parsed->momentaryReactiveExportL3);

      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);
    }

    void readP1Message() {
      if (available()) {
        uint16_t crc = 0x0000;
        ParsedMessage parsed = ParsedMessage();
        bool telegramEnded = false;

        while (available()) {
          int len = Serial.readBytesUntil('\n', buffer, BUF_SIZE);

          if (len > 0) {
            ESP_LOGD("data", "%s", buffer);

            // put newline back as it is required for CRC calculation
            buffer[len] = '\n';
            buffer[len + 1] = '\0';

            // if we've reached the CRC checksum, calculate last CRC and compare
            if (buffer[0] == '!') {
              crc = crc16_update(crc, buffer[0]);
              int crcFromMsg = (int) strtol(&buffer[1], NULL, 16);
              parsed.crcOk = crc == crcFromMsg;
              ESP_LOGI("crc", "Telegram read. CRC: %04X = %04X. PASS = %s", crc, crcFromMsg, parsed.crcOk ? "YES": "NO");
              telegramEnded = true;

            // otherwise pass the row through the CRC calculation
            } else {
              for (int i = 0; i < len + 1; i++) {
                crc = crc16_update(crc, buffer[i]);
              }
            }

            // if this is a row containing information
            if (strchr(buffer, '(') != NULL) {
              char* dataId = strtok(buffer, DELIMITERS);
              char* obisCode = strtok(NULL, DELIMITERS);

              // ...and this row is a data row, then parse row
              if (strncmp(DATA_ID, dataId, strlen(DATA_ID)) == 0) {
                char* value = strtok(NULL, DELIMITERS);
                char* unit = strtok(NULL, DELIMITERS);
                parseRow(&parsed, obisCode, atof(value));
              }
            }
          }
          // clean buffer
          memset(buffer, 0, BUF_SIZE - 1);
        
          if (!telegramEnded && !available()) {
            // wait for more data
            delay(40);
          }
        }

        // if the CRC pass, publish sensor values
        if (parsed.crcOk) {
          publishSensors(&parsed);
        }
      }
    }

    bool readHDLCStruct(ParsedMessage* parsed) {
      if(Serial.readBytes(buffer, 3) != 3)
        return false;

      if(buffer[0] != 0x02) {
        return false;
      }

      char obis[7];

      uint8_t struct_len = buffer[1];
      //ESP_LOGD("hdlc", "Struct length is %d", struct_len);

      uint8_t tag = buffer[2];

      if(tag != 0x09) {
        ESP_LOGE("hdcl", "Unexpected tag %X in struct, bailing out", tag);
        return false;
      }
      
      uint8_t str_length = read();
      if(Serial.readBytes(buffer, str_length) != str_length) {
        ESP_LOGE("hdlc", "Unable to read %d bytes of OBIS code", str_length);
        return false;
      }
      buffer[str_length] = 0; // Null-terminate
      sprintf(obis, "%d.%d.%d", buffer[2], buffer[3], buffer[4]);

      tag = read();

      bool is_signed = false;
      uint32_t uvalue = 0;
      int32_t value = 0;
      if (tag == 0x09) {
        str_length = read();
        if(Serial.readBytes(buffer, str_length) != str_length) {
          ESP_LOGE("hdlc", "Unable to read %d bytes of string", str_length);
          return false;
        }

        buffer[str_length] = 0;
        //ESP_LOGD("hdlc", "Read string length %d", str_length);
      } else if(tag == 0x06) {
        Serial.readBytes(buffer, 4);
        //uvalue = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24;
        uvalue = buffer[3] | buffer[2] << 8 | buffer[1] << 16 | buffer[0] << 24;
        //ESP_LOGD("hdlc", "Value of uvalue is %u", uvalue);
      } else if (tag == 0x10) {
        Serial.readBytes(buffer, 2); 
        //value = buffer[0] | buffer[1] << 8; // 
        is_signed = true;
        value = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "(Signed) Value of value is %d", value);
      } else if (tag == 0x12) {
        Serial.readBytes(buffer, 2); 
        //uvalue = buffer[0] | buffer[1] << 8; // 
        uvalue = buffer[1] | buffer[0] << 8;
        //ESP_LOGD("hdlc", "(Unsigned) Value of uvalue is %u", uvalue);
      } else {
        ESP_LOGE("hdlc", "unknown tag %X", tag);
      }

      int8_t scaler;
      uint8_t unit;
      if(struct_len == 3) {
        Serial.readBytes(buffer, 6);
        scaler = buffer[3];
        unit = buffer[5];
        //ESP_LOGD("hdlc", "Scaler %u", scaler);
        //ESP_LOGD("hdlc", "Unit %d", buffer[5]);

      if(!is_signed)
        value = uvalue;

        double scaled_value = pow(10, scaler) * value;

        // Volt and Ampere are the only two units where p1reader.yaml doesn't specify 
        // we should report in 1/1000, all others should be divided.
        if(unit != 33 && unit != 35)
          scaled_value = scaled_value / 1000;

        parseRow(parsed, obis, scaled_value);
      }


      

      return true;
    }

    //   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;
        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 || buffer[0] != 0x40 || buffer[1] != 0x00 || buffer[2] != 0x00 || buffer[3] != 0x00)
          {
            ESP_LOGE("hdlc", "Expected 0x40 0x00 0x00 0x00, got %X %X %X %X - out of sync, returning.", buffer[0], buffer[1], buffer[2], buffer[3]);
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        }

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

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

        uint8_t array_length = read();
        ESP_LOGD("hdlc", "Array length is %d", array_length);

        for(int i=0;i<array_length;i++) {
          if(!readHDLCStruct(&parsed)) {
            parseHDLCState = OUTSIDE_FRAME;
            return;
          }
        }

        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;
          }
        }
      }
    }
};

hmm, strange, it shows 3 decimals but the last 2 is 00 so i count that as 1.maybe i messed something when writing the firmware/yaml

/Micke

I also followed @peter.sv guide. I got it up and running, connected to my Aidon unit but I just get ‘Unknown’ on all readings. It doesn’t seem to update either. I have some questions still up in the air like is Baud Rate important? Because that is very specific to each unit it seems like from Aidon documentation. Not sure if this one is important thought.

If anyone has a solution to why it doesn’t seem to be able to read the values from my Aidon unit it would be much appreciated. I have the same unit as @thwedum .
Unit: Aidon 6483SE
Another weird thing I can’t get my head around is that in one place on the unit it says Aidon 6525 and in another place it says Aidon 6483SE.
Anyhow, any help would be greatly appreciated. I am using the code explained and edited by @peter.sv .
I do get wireless information from the Slimmelezer.

When I copy p1reader.h and use the p1reader.yaml then I get a compile error saying that:
error: ‘readBytesUntil’ was not declared in this scope
and
error: ‘readBytes’ was not declared in this scope; did you mean ‘read_byte’

Refering to the implementation of void P1Reader::readP1Message()

Any guess on what I’m doing wrong?

Sorry have not touched this since I got i working. And really i dont understand it well enough to know whats causing issues. Im just Lucky it worked for me😄

Sorry for the late reply.

You do change the logic when you make that change. I’m not sure what is the intention, but I think the intention would be this instead:
if (!(len == 4) || buffer[0] != 0x40 || buffer[1] != 0x00 || buffer[2] != 0x00 || buffer[3] != 0x00)

By adding Serial. before allt the ReadBytes and ReadBytesUntil I managed to compile. I still have no luck with receiving data from my Aidon meter. Will have to see if I find the schematic for SlimmeLeezer+ v1.1.

I managed to get my Slimmelezer+ v1.1 going with the help from this thread and this page: SlimmeLezer support [no issue] · Issue #45 · psvanstrom/esphome-p1reader · GitHub

Where Zuidwijk adds some info about the Slimmelezer+

I also had to tell my grid owner a second time to turn on the HAN port. First time wasn’t enough :slight_smile: