Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

EDL21 Electricity meter 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.

Note
titleWarning

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.


Info
titleConsider using the latest firmware on your hardware

Top Features

(tick) LoRaWAN 1.0.x and 1.1 network servers supported

(tick) LoRaWAN time synchronisation

(tick) Configuration via USB or remotely via LoRaWAN downlink

(tick) Compatible with many electrical utility meters

(tick) Configure up to 25 Obis Codes to be read

(tick) RGB Status LED

(tick) Variant with external power-supply available on request

(tick) Separation of infrared readout head and LoRaWAN antenna possible

Compatible utility meters


Electricity meter

Manufacturer

More information

DTZ541-ZEBAHolleyExternal Link
LK13 seriesLogarexExternal Link
OpenWay® 3.HZiTronExternal Link
SGM-C4 seriesefrExternal Link
SGM-D seriesefrExternal Link
eHZ-K seriesEMHExternal Link
mMe4.0 seriesEMHExternal Link
ED300 seriesEMHExternal Link
eBZD seriesEMHExternal Link
ITZ seriesEMHExternal Link
E320Landis+GyrExternal Link


Info

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, XH battery connector, int. Ant.), Order number: 8000091
Lobaro EDL21 LoRaWAN Bridge Lobaro EDL21 LoRaWAN Bridge

Info
titleCustomization Options

The product variant shown above is the standard variant for use with a ER34614 3.6V D-cell Battery connected over a XH connector.

Other power supply options & housing are available on request

  • External antenna
  • 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", here you can see a configuration example.
  3. Register the device in your LoRaWAN network
  4. Connect ER34614 3.6V D-cell Battery via XH connector / 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

OTAAActivation: OTAA or ABPbooltrue= use OTAA, false= use ABP
DevEUIDevEUI used to identify the Devicebyte[8]e.g. 0123456789abcdef
JoinEUIUsed for OTAA (called AppEUI in v1.0)byte[8]e.g. 0123456789abcdef
AppKeyKey used for OTAA (v1.0 and v1.1)byte[16]
NwkKeyKey used for OTAA (v1.1 only)byte[16]
SFInitial / maximum Spreading Factorint7 - 12
ADRUse Adaptive Data Ratebooltrue= use ADR, false= don't
TimeSyncDays after which to sync timeintdays, 0=don't sync time
RndDelayRandom delay before sendingintmax seconds
RemoteConfNot supported by this firmwareboolfalse=deactivate
LostRebootDays without downlink before reboot (triggers downlinks)intdays, 0=don't reboot

Operation

Configuration values defining the behaviour of the device.

name

description

example value

ReadCronCron expression defining when to read0 0/15 * * * * for every 15 minutes
ObisCodeComma separated list of ObisCodes to select a subset of the available information1-0:1.7.255*255 = Leistung (Momentan)
PayloadFormatFormat used for data upload (include timestamps or not)1=no timestamp, 2=include timestamp


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/blue300ms eachinitial pattern after reset
red/green1sNEW in 0.3.2: single readout success/failure before OTAA join
redshort, blinkingtrying to receive meter optical data for the first time after OTAA join
green5 secondssuccessfully received meter optical data
blue5 secondsLoRaWAN network join
blueshortsending 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

ProductType nameLOB-S-EDL21-LWDescriptionElectricity meter over LoRaWAN BridgeRF tranceiverTypeSemtech SX1272Frequency863 MHz to 870 MHzMax. TX Powermax. +14 dBmTypical RF Range≤2kmIdeal RF Range≤10km (free line of sight)LoRa communicationProtocolClass A LoRaWAN 1.0.1 EU868Activation methodOver-the-air-activation (OTAA)
Activation by personalization (ABP)EncryptionAES128Environmental RequirementsOperating temperature-20°C – 55°CMax installation height2m

Standards
CE logoImage Removed Image Removed

Disposal / WEEE / Entsorgung

Information about the disposal of the Device.

Payload Format Status Packet (Port 1)

Once per day a status packet will be sent. It contains basic information about the device. The Battery Voltage is transmitted in 1/1000 V and the temperature in 1/10 °C. Both are in Big Endian byte order.

Version Major

Version Minor

Version Patch

Flags

Battery Voltage

Temperature

1 byte1 byte1 byte1 byte2 byte2byteunsignedunsignedunsignedunsignedunsignedsignedPayload Format Status Packet (Port 1)

Once per day a status packet will be sent. It contains basic information about the device. The Battery Voltage is transmitted in 1/1000 V and the temperature in 1/10 °C. Both are in Big Endian byte order.

Version Major

Version Minor

Version Patch

Flags

Battery Voltage

Temperature

1 byte1 byte1 byte1 byte2 byte2byte
unsignedunsignedunsignedunsignedunsignedsigned


Payload Format 0 (old, Port 2, without exponent)

This payload was used by previous versions of the firmware and is not supported in the current version.

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

OBISCode (hex)

length of value (n)

value

6 bytes1 byten 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)

length of value (n)

value

01 00 01 08 00 FE08FF 01 00 00 00 00 00 00
1-0:1.8.0*2548511

Entry 2:

OBISCode (hex)

length of value (n)

value

01 00 01 08 00 FE08FF 01 00 00 00 00 00 00
1-0:1.8.0*2548767

Payload Format 1 (new, Port 3, with exponent)

This Format is used, when the configuration parameter PayloadFormat is set to 1 (which is the default value)

Payload Format 0 (old, Port 2, without exponent)

This payload was used by previous versions of the firmware and is not supported in the current version.

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

OBISCode (hex)

length of value (n)

value

exponent

6 bytes1 byten bytes, LSB first1 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)

length of value (n)

value

exponent

01 00 01 08 00 FE08FF 01 00 00 00 00 00 00ff
1-0:1.8.0*2548511

Entry 2:

-1
Value = 511 * 10^-1 = 51.1


Entry 2:

OBISCode (hex)

length of value (n)

value

exponent

01 00 01 08 00 FE08FF 02 00 00 00 00 00 00FF 01 00 00 00 00 00 0002
1-0:1.8.0*2548767

Payload Format 1 (new, Port 3, with exponent)

This Format is used, when the configuration parameter PayloadFormat is set to 1 (which is the default value).

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

OBISCode (hex)

length of value (n)

value

exponent

6 bytes1 byten bytes, LSB first1 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)

length of value (n)

value

exponent

01 00 01 08 00 FE08FF 01 00 00 00 00 00 00ff1-0:1.8.0*2548511-1Value = 511 * 10^-1 = 51.1

Entry 2:

OBISCode (hex)

length of value (n)

value

exponent

01 00 01 08 00 FE08FF 02 00 00 00 00 00 00021-0:1.8.0*25487672
2
Value = 767 * 10^2 = 76700


Multiple messages

The Bridge puts as many values in a single data message as possible (respecting the current Spreading Factor). When it cannot fit all values in a single message, it will send multiple data messages until all values are uploaded. It will never split a single value. Since every value is prefixed with the Obis code, the parser can easily assign values to Obis codes.

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.

Code Block
languagejs
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 signed(val, bits) {
    if ((val & 1 << (bits - 1)) > 0) { // value is negative (16bit 2's complement)
        var mask = Math.pow(2, bits) - 1;
Value = 767 * 10^2 = 76700

Multiple messages

The Bridge puts as many values in a single data message as possible (respecting the current Spreading Factor). When it cannot fit all values in a single message, it will send multiple data messages until all values are uploaded. It will never split a single value. Since every value is prefixed with the Obis code, the parser can easily assign values to Obis codes.

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.

Code Block
languagejs
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) {val = (~val & mask) + 1; // invert all bits & add 1 => now positive value
    var s = '';
 val = val byteArray.forEach(function (byte) {* -1;
    }
    s += ('0' + (byte & 0xFF).toString(16)).slice(-2);
    });
    return s;
}

function parse_int8return val;
}
function uint40_BE(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    varreturn t = bytes[0]; << 32 |
    if ((t &  bytes[1] << 7) > 0) { // temp is negative (16bit 2's complement)
        t = ((~t) & 0xff) + 1; // invert 16bits & add 1 => now positive value24 | bytes[2] << 16 | bytes[3] << 8 | bytes[4] << 0;
}
function uint16_BE(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    return bytes[0] << 8 t = t * -1;
    }
    return t;
}

function parse_int16| bytes[1] << 0;
}
function int40_BE(bytes, idx) {return signed(uint40_BE(bytes, idx), 40);}
function int16_BE(bytes, idx) {
    bytes = bytes.slice(return signed(uint16_BE(bytes, idx), 16);}
function int8(bytes, idx) {return signed(bytes[idx || 0], 8);}

function    var t = bytes[0] << 8 | bytes[1] << toNumber(bytes) {
    var res = 0;
    iffor ((tvar &i 1= <<0, 15)s >= 0; i < bytes.length; i++) {
  // temp is negative (16bit 2's complement)
        t = ((~t) & 0xffff) + 1; // invert 16bits & add 1 => now positive value res |= bytes[i] << s;
        ts += t * -18;
    }
    return tres;
}

function parse_uint16(bytes, idxreadVersion(bytes) {
    if (bytes.length<3) {
    bytes  = bytes.slice(idx || 0); return null;
    }
    varreturn t"v" =+ bytes[0] <<+ 8"." |+ bytes[1] << 0;
    return t+ "." + bytes[2];
}

function toNumberdecodeStatus(bytes) {
    var resdecoded = 0;{
    for (var i = 0, s = 0; i < bytes.length; i++) { "version":readVersion(bytes),
        res |= "flags": bytes[i] << s;3],
        s += 8;"vBat": uint16_BE(bytes, 4) / 1000,
        "temp": int16_BE(bytes, 6) / 10,
    };

    return resdecoded;
}

function readVersiondecodeSmlValuesV1(bytes) {
    if (bytes.length < 3) var decoded = {
        return null;values: [],
    };

    return "v" + bytes[0] + "." + bytes[1] + "." + bytes[2];
}

function decodeStatus(bytes) {
    var decoded = {
if (bytes.length === 1) {
        // No Data! Read error?
         "version": readVersion(bytes),return decoded;
    }

    "flags": bytes[3],
  var pos = 0;
    while  "vBat": parse_uint16(bytes, 4) / 1000,
(pos < bytes.length) {
        var name "temp": parse_int16= readName(bytes, 6pos);
 / 10,
    };


  pos += return decoded6;
}

function decodeSmlValuesV1(bytes) {
        var decodedlen = {bytes[pos];
        values: [],
    };
pos += 1;
    if (bytes.length === 1) {
var value =      // No Data! Read error?
readValue(len, bytes, pos);
        pos += return decodedlen;

    }

    var posval = 0;{
    while (pos < bytes.length) {
    nameHex: toHexString(name),
   var name = readName(bytes, pos);
     len: len,
  pos  += 6;
        var len = bytes[pos];
value: toNumber(value),
           pos += 1;valueHex: toHexString(value)
        var value = readValue(len, bytes, pos};

        decoded.values.push(val);
    }

    pos += len;return decoded;
}

function    decodeSmlValuesV2(bytes) {
    var valdecoded = {
            nameHexvalues: toHexString(name)[],
    };

    if (bytes.length ===  len: len,1) {
        // No Data!  value: toNumber(value),Read error?
        return decoded;
   valueHex: toHexString(value) }

    var pos =  }0;

    while (pos <  decoded.values.push(val);
bytes.length) {
     }

   var return decoded;
}

function decodeSmlValuesV2(bytes) {
name = readName(bytes, pos);
       var decodedpos += {6;
        values: [],var len = bytes[pos];
    };

    if (bytes.length === 1) {
pos += 1;
        var //value No Data! Read error?
= readValue(len, bytes, pos);
        pos return+= decodedlen;
    }

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

        decoded.values.push(val);
    val}

 = {
  return decoded;
}

function decodeSmlValuesV3(bytes) {
    // Like V2, but with 5B timestamp as nameHex: toHexString(name),prefix:
    var decoded = decodeSmlValuesV2(bytes.slice(5));
    decoded.time = int40_BE(bytes, 0) * len: len,
1000;
    return decoded;
}

function Decoder(bytes, port) {
    // Decode an uplink message from value: toNumber(value),a buffer
    // (array) of bytes to an object of fields.
    valueHex:switch toHexString(valueport), {
        case 1:
    };
        return }

decodeStatus(bytes);
         decoded.values.push(val);case 2:
    }

        return decodeddecodeSmlValuesV1(bytes);
}

// Test input (Port 3): 01 00 01 08case 003:
 FE 08 FF 01 00 00 00 00 00 00 FF
function Decoder return decodeSmlValuesV2(bytes, port) {;
    // Decode an uplink message from acase buffer
    // (array) of bytes to an object of fields.
4:
            switchreturn decodeSmlValuesV3(portbytes) {;
        case 1:
            return decodeStatus(bytes);}
}

Example parser result

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

{
  "values": [
    {
      "len": 8,
     case 2:"nameHex": "0100010800fe",
      "value": 51.1,
     return decodeSmlValuesV1(bytes);
        case 3:
            return decodeSmlValuesV2(bytes); "valueHex": "ff01000000000000"
    }
}

// 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

Code Block
languagejs
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"
    }
  ]
}
]
}

Appendices


Technical characteristics




Product
Type nameLOB-S-EDL21-LW
DescriptionElectricity meter over LoRaWAN Bridge
RF transceiver
TypeSemtech SX1272
Frequency863 MHz to 870 MHz
Max. TX Powermax. +14 dBm
Typical RF Range≤2km
Ideal RF Range≤10km (free line of sight)
LoRa communication
ProtocolClass A LoRaWAN 1.0.1 EU868
Activation methodOver-the-air-activation (OTAA)
Activation by personalization (ABP)
EncryptionAES128
Environmental Requirements
Operating temperature-20°C – 55°C
Max installation height2m

Standards
CE logoImage Added Image Added





Disposal / WEEE / Entsorgung


Information about the disposal of the Device.


CE Declaration of Conformity

CE Declaration of Conformity (pdf).



Table of Contents