EDL21 Electricity meter LoRaWAN Bridge

Lobaro EDL21 LoRaWAN Bridge

The EDL21 over LoRaWAN bridge is a device that can be used to readout modern utility meters with standardized infrared "INFO" interface.

These type of meters are called in Germany to be "EDL21"-compatible - hence the name. The meter outputs over its infrared "INFO" interface a serial protocol conforming to the Smart Meter Language Protocol 1.04 (SML). This interface is intended to be used by end-users and not for billing purposes of the electricity supplier. The read information normally contains the current consumption values of the meter and gets interpreted and forwarded by the EDL21 bridge via a LoRaWAN network to web based applications interested in further processing this data.

Warning

Older meters with "infrared pulse" output are not compatible to the Lobaro EDL21 bridge. Please check our list of compatible meters to make sure it is equipped with the correct interface.

Consider using the latest firmware on your hardware

Top Features

  • LoRaWAN 1.0.x and 1.1 network servers supported
  • LoRaWAN Class A or Class C operation
  • LoRaWAN 1.1 time synchronisation
  • Configuration via USB or remotely via LoRaWAN downlink
  • Compatible with many electrical utility meters
  • RGB Status LED
  • Variants with external power-supply and D-cell batteries available on request
  • Separation of infrared readout head and LoRaWAN antenna possible

Compatible utility meters

Electricity meter Manufacturer More information
DTZ541-ZEBA Holley External Link
LK13 series Logarex External Link
OpenWay® 3.HZ iTron External Link
SGM-C4 series efr External Link
SGM-D series efr External Link
eHZ-K series EMH External Link
mMe4.0 series EMH External Link
ED300 series EMH External Link
eBZD series EMH External Link
ITZ series EMH External Link
E320 Landis+Gyr External Link

Alternative IEC 62056-21 protocol

On request we offer also the integration of electricity meters using the D0 interface conforming to IEC 62056-21. This interface is not compatible to the SML protocol. Please contact us if you need an offer for a custom firmware supporting your meter of interest.

Product variants

EDL21-LoRaWAN Bridge (universal head, AA, int. Ant.), Order number: 8000057
Lobaro EDL21 LoRaWAN Bridge

Customization Options

The product variant shown above is the standard variant in our compact housing and powered by two AA batteries.

Other power supply options & housing are available on request

  • External antenna
  • D-cell batteries
  • External power-supply
  • NB-IoT instead of LoRaWAN
  • Different infrared data formats other than SML

Contact us via support@lobaro.de if you need our offer for a special variant.

Quickstart

  1. Connect to the device with the Lobaro Tool using the Lobaro Config Adapter
  2. Under Configuration click "Reload Config" and change the fields ReadCron and ObisCode as you need followed by clicking on "Write to Device" click here for a configuration example
  3. Register the device in your LoRaWAN network
  4. Insert 2 batteries ('AA' size, 1.5V) / Connect external powersupply
  5. If not connected to anything the red LED will start blinking as long as no data is received, after 1 minute it will sleep for 15 seconds after every 5 retries
  6. Tighten the screws and install the bridge beside your electric meter
  7. Place the EDL21 opto head on the "Info" interface
  8. As soon as the EDL21 receives data its green LED will light up for 5 seconds, when connected to a LoRa Network its blue LED will light up for 5 seconds
  9. Check the sent data (port 3), if payload is zero the EDL21 was not able to read data, recheck proper alignment

Configuration

The configuration is done using Lobaro Maintenance Tool and the Lobaro USB PC adapter.

LoRaWAN

The connection to the LoRaWAN network is defined by multiple configuration parameters. This need to be set according to your LoRaWAN network and the way your device is supposed to be attached to it, or the device will not be able to send any data.

For a detailed introduction into how this values need to be configured, please refer to the chapter LoRaWAN configuration in our LoRaWAN background article.

Name Description Type Values
OTAA Activation: OTAA or ABP bool true= use OTAA, false= use ABP
DevEUI DevEUI used to identify the Device byte[8] e.g. 0123456789abcdef
JoinEUI Used for OTAA (called AppEUI in v1.0) byte[8] e.g. 0123456789abcdef
AppKey Key used for OTAA (v1.0 and v1.1) byte[16]
NwkKey Key used for OTAA (v1.1 only) byte[16]
SF Initial / maximum Spreading Factor int 7 - 12
ADR Use Adaptive Data Rate bool true= use ADR, false= don't
OpMode Operation Mode string A= Class A, C= Class C
TimeSync Days after which to sync time int days, 0=don't sync time
RndDelay Random delay before sending int max seconds
RemoteConf Not supported by this firmware bool false=deactivate
LostReboot Days without downlink before reboot int days, 0=don't reboot

Operation

Configuration values defining the behaviour of the device.

name description example value
ReadCron Cron expression defining when to read 0 0/15 * * * * for every 15 minutes
ObisCode Comma separated list of ObisCodes to select a subset of the available information 1-0:1.7.255*255 = Leistung (Momentan)

See also our Introduction to Cron expressions and our Introduction to Obis Codes.

LED blinking patterns

The following pattery are explained in the order in which they appear after initial power on / reset of the device.

color duration description
red/green/blue 300ms each initial pattern after reset
red/green 1s NEW in 0.3.2: single readout success/failure before OTAA join
red short, blinking trying to receive meter optical data for the first time after OTAA join
green 5 seconds successfully received meter optical data
blue 5 seconds LoRaWAN network join
blue short sending LoRaWAN data uplink
off - low-power mode until next sendout cycle

As you can see by this the device will start the LoRaWAN join only after receiving optical data at least once.

Appendices

Technical characteristics

Product
Type name EDL21-LoRaWAN
Description Electricity meter over LoRaWAN Bridge
RF tranceiver
Type Semtech SX1272
Frequency 863 MHz to 870 MHz
Max. TX Power max. +14 dBm
Typical RF Range ≤2km
Ideal RF Range ≤10km (free line of sight)
LoRa communication
Protocol Class A LoRaWAN 1.0.1 EU868
Activation method Over-the-air-activation (OTAA)
Activation by personalization (ABP)
Encryption AES128
Environmental Requirements
Operating temperature -20°C – 55°C
Max installation height 2m
Standards
CE logo

Disposal / WEEE / Entsorgung

Information about the disposal of the Device.

Payload Format (old, Port 2, without exponent)

The payload consists of multiple entries, one entry per OBIS code given in the configuration. Each entry follows the following structure:

OBISCode (hex) lenght of value (n) value
6 bytes 1 byte n bytes, LSB first

Example packet: 01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00 01 00 01 08 00 FE 08 FF 02 00 00 00 00 00 00

Entry 1:

OBISCode (hex) lenght of value (n) value
01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00
1-0:1.8.0*254 8 511

Entry 2:

OBISCode (hex) lenght of value (n) value
01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00
1-0:1.8.0*254 8 767

Payload Format (new, Port 3, with exponent)

The payload consists of multiple entries, one entry per OBIS code given in the configuration. Each entry follows the following structure:

OBISCode (hex) lenght of value (n) value exponent
6 bytes 1 byte n bytes, LSB first 1 byte (signed)

Example packet: 01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00 ff 01 00 01 08 00 FE 08 FF 02 00 00 00 00 00 00 02

Entry 1:

OBISCode (hex) lenght of value (n) value exponent
01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00 ff
1-0:1.8.0*254 8 511 -1
Value = 511 * 10^-1 = 51.1

Entry 2:

OBISCode (hex) lenght of value (n) value exponent
01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00 02
1-0:1.8.0*254 8 767 2
Value = 767 * 10^2 = 76700

Reference decoder

This is a decoder written in JavaScript that can be used to parse the device's LoRaWAN messages. It can be used as is in The Things Network.

function readName(bytes, i) {
    return bytes.slice(i, i + 6);
}

function readValue(len, bytes, i) {
    if (len <= 0) {
        return [];
    }
    return bytes.slice(i, i + len);
}

function toHexString(byteArray) {
    var s = '';
    byteArray.forEach(function (byte) {
        s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
    });
    return s;
}

function parse_int8(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    var t = bytes[0];
    if ((t & 1 << 7) > 0) { // temp is negative (16bit 2's complement)
        t = ((~t) & 0xff) + 1; // invert 16bits & add 1 => now positive value
        t = t * -1;
    }
    return t;
}

function parse_int16(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    var t = bytes[0] << 8 | bytes[1] << 0;
    if( (t & 1<<15) > 0){ // temp is negative (16bit 2's complement)
        t = ((~t)& 0xffff)+1; // invert 16bits & add 1 => now positive value
        t=t*-1;
    }
    return t;
}
function parse_uint16(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    var t = bytes[0] << 8 | bytes[1] << 0;
    return t;
}

function toNumber(bytes) {
    var res = 0;
    for (var i = 0, s = 0; i < bytes.length; i++) {
        res |= bytes[i] << s;
        s += 8;
    }
    return res;
}

function readVersion(bytes) {
    if (bytes.length<3) {
        return null;
    }
    return "v" + bytes[0] + "." + bytes[1] + "." + bytes[2];
}

function decodeStatus(bytes) {
    var decoded = {
        "version":readVersion(bytes),
        "flags": bytes[3],
        "vBat": parse_uint16(bytes, 4) / 1000,
        "temp": parse_int16(bytes, 6) / 10,
    };


    return decoded;
}

function decodeSmlValuesV1(bytes) {
    var decoded = {
        values: [],
    };

    if (bytes.length === 1) {
        // No Data! Read error?
        return decoded;
    }

    var pos = 0;
    while (pos < bytes.length) {
        var name = readName(bytes, pos);
        pos += 6;
        var len = bytes[pos];
        pos += 1;
        var value = readValue(len, bytes, pos);
        pos += len;

        var val = {
            nameHex: toHexString(name),
            len: len,
            value: toNumber(value),
            valueHex: toHexString(value)
        };

        decoded.values.push(val);
    }

    return decoded;
}

function decodeSmlValuesV2(bytes) {
    var decoded = {
        values: [],
    };

    if (bytes.length === 1) {
        // No Data! Read error?
        return decoded;
    }

    var pos = 0;
    while (pos < bytes.length) {
        var name = readName(bytes, pos);
        pos += 6;
        var len = bytes[pos];
        pos += 1;
        var value = readValue(len, bytes, pos);
        pos += len;
        if (len > 0) {
            var exponent = parse_int8(bytes, pos);
            pos += 1;
        }
        if (len > 0) {
            var val = {
                nameHex: toHexString(name),
                len: len,
                value: toNumber(value) * Math.pow(10, exponent),
                valueHex: toHexString(value),
            }
        } else {
            var val = {
                nameHex: toHexString(name),
                len: len,
                value: toNumber(value),
                valueHex: toHexString(value),
            }
        }

        decoded.values.push(val);
    }

    return decoded;
}

function Decoder(bytes, port) {
    // Decode an uplink message from a buffer
    // (array) of bytes to an object of fields.
    if (port === 1) {
        return decodeStatus(bytes);
    }
    if (port === 2) {
        return decodeSmlValuesV1(bytes);
    }
    if (port == 3) {
        return decodeSmlValuesV2(bytes);
    }
}

// Wrapper for niota.io
module.exports = function (payload, meta) {
    const port = meta.lora.fport;
    const buf = Buffer.from(payload, 'hex');

    return Decoder(buf, port);
}

Example parser result

Test input (Port 3): 01 00 01 08 00 FE 08 FF 01 00 00 00 00 00 00 FF

{
  "values": [
    {
      "len": 8,
      "nameHex": "0100010800fe",
      "value": 51.1,
      "valueHex": "ff01000000000000"
    }
  ]
}

CE Declaration of Conformity

CE Declaration of Conformity (pdf).