Eastron SDM230-LoRa - LoRaWAN issues

Thank you @jpmeijers for opening this thread.

I have successfully linked the device Eastron SDM630-Lora to TTN.
The problem is that I am only getting 2 types of payloads. In the manual, it is written that the auto-upload parameters could be set (max 30.) … anyone have any idea how to configure it so we can get more readings out of the meter?

Datasheet (page 8 → 10) :
https://www.eastroneurope.com/images/uploads/products/protocol/Eastron_SDM630MCT-LoRaWAN_protocol_V1.0-combined_.pdf

1 Like

Hello is it possible to send me the W1 Tool ?

[See edit history for email address]

THX

Hi, has anyone managed to configure the Active Upload feature on Eastron LoRAWAN meters? The documentation mentions that parameters can be configured for these messages and lists a table of the available parameters but I can’t see any mention of how to use these parameters. All help appreciated. Thanks.

I am coding the decoder, without having the device yet for the customer. Would you mind sharing 1-2 sample payload and the expected result after decode ?

Hi, I have integrated the eastron 630 Lora into my network server and I can read some of the values ​​saved in the registers every 5 minutes. However I can’t figure out how to choose which logs to read, any downlinks I send seem to be ignored. I am attaching the payload I receive. That said, if you have an example uplink to send to the meter to choose which logs to read please share with me

** “data”: “AVVjOQEUAAAAAEJIAAA/gAAAty3dGQAAAAAR3g==” **

decoded (from Base64) as:
01 55 63 39 → serial number
01 → data format
14 → (20 since is HEX) how many bytes
00 00 00 00 → some data
42 48 00 00 → (50) i guess it’s the frequency Hz
3f 80 00 00 → (1) some data i don t know
b7 2d dd 19 ->(1.036*10^-5) some data i don t know
00 00 00 00->some data
11 de → CRC (i guess)

The funny part is that i recieve the same numbers if the meter is attached to the electric line or no.
So if you can share some help it would be appreciated
Thank you so much

Are you polling the Eastron, via a downlink, for data every 5 minutes ?

Not actively, I set the polling time on the eastron to 5 minutes and it spontaneously sends this packet. Seems blind to my downlinks. I also tried to send him the package they use in the manual as an example (encoded as ascii) but nothing, he never responds.

I’ve got one of these with version 2.03. There is my decoding script for Chirpstack 2.03:

// v3 to v4 compatibility wrapper
function decodeUplink(input) {
	return {
		data: Decode(input.fPort, input.bytes, input.variables)
	};
}

function intFromBytes( x ){
    var val = 0;
    for (var i = 0; i < x.length; ++i) {        
        val += x[i];        
        if (i < x.length-1) {
            val = val << 8;
        }
    }
    return val;
}

function bytesToFloat(bytes) {
  var bits = bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];
  var sign = (bits>>>31 === 0) ? 1.0 : -1.0;
  var e = bits>>>23 & 0xff;
  var m = (e === 0) ? (bits & 0x7fffff)<<1 : (bits & 0x7fffff) | 0x800000;
  var f = sign * m * Math.pow(2, e - 150);
  return parseFloat(f);
}

// Decode decodes an array of bytes into an object.
//  - fPort contains the LoRaWAN fPort number
//  - bytes is an array of bytes, e.g. [225, 230, 255, 0]
//  - variables contains the device variables e.g. {"calibration": "3.5"} (both the key / value are of type string)
// The function must return an object, e.g. {"temperature": 22.5}
function Decode(fPort, bytes, variables) {
      var decoded = {};

if ( bytes[4] == 01) {

  decoded.SERIAL_NO = intFromBytes(bytes.slice(0, 4));   // Serial number
  decoded.INSTANT_WATT = (bytesToFloat(bytes.slice(06, 10))); // Instant W read
  decoded.KWH = (bytesToFloat(bytes.slice(10, 14))); //  Total Kwh
  decoded.CURRENT = (bytesToFloat(bytes.slice(14, 18)));  // Always zero?
  decoded.KWH_2 = (bytesToFloat(bytes.slice(18, 22)));  /// Absolute Kwh
  decoded.KVArh_imp  = (bytesToFloat(bytes.slice(22, 26))); // KVArh Imported
  decoded.KVArh_exp = (bytesToFloat(bytes.slice(26, 30))); // kVArh Exported
  decoded.KVArh_tot = (bytesToFloat(bytes.slice(30, 34))); // KVArh Total
}


return decoded;
}

1 Like

Did you manage to make it work ?

Hi, I’m exactly having the same issue. Have you find a solution so far?

Hi did you manage to find the solution for this? I can’t get all the data from the meter nor mapping it. Kind regards

Try to read this thread, we got some solutions and explanations

I’ve managed to crack this.

First - word of warning - what I’m doing here is not suitable for TTN directly because my test SDM230-LoRaWAN is being very verbose but I’m using a private loRaWAN network server so it doesn’t matter quite so much.

Anyway:

I’ve got the SDM230 sending messages automatically and my network server is forwarding them as json over MQTT like this:

{
    "adr": true,
    "applicationID": "2",
    "applicationName": "appTest2",
    "data": "01569A8A060C000000003F820C4A3F820C4A585B",
    "data_encode": "hexstring",
    "devEUI": "8680000122450000",
    "deviceName": "meter1",
    "fCnt": 10,
    "fPort": 1,
    "rxInfo": [
        {
            "gatewayID": "ac1f09fffe080000",
            "location": {
                "altitude": 0,
                "latitude": 0.0,
                "longitude": 0.0
            },
            "loRaSNR": 14.8,
            "rssi": -25
        }
    ],
    "timestamp": 1681156445,
    "txInfo": {
        "dr": 6,
        "frequency": 868300000
    }
}

I’m receiving this in node-red and processing the data elements thus:

// hex int to decimal int
function hexToDec(hexString){
  return parseInt(hexString, 16);
}

//https://gist.github.com/Jozo132/2c0fae763f5dc6635a6714bb741d152f
function HexToFloat32(str)  {
    var int = parseInt(str, 16);
    if (int > 0 || int < 0) {
        var sign = (int >>> 31) ? -1 : 1;
        var exp = (int >>> 23 & 0xff) - 127;
        var mantissa = ((int & 0x7fffff) + 0x800000).toString(2);
        var float32 = 0
        for (i = 0; i < mantissa.length; i += 1) { float32 += parseInt(mantissa[i]) ? Math.pow(2, exp) : 0; exp-- }
        return float32 * sign;
    } else return 0
}

//modified from https://www.thethingsnetwork.org/forum/t/eastron-sdm230-lora-lorawan-issues/45126/48?page=2
function decode(str) {
      var decoded = {};

    decoded.SERIAL_NO = hexToDec(str.slice(0, 8));
    decoded.MSG_TYP = hexToDec(str.slice(8,10)); //important, because vals are different for each typ
    //decoded.VAL_COUNT = hexToDec(str.slice(10,12))/4; //not using this - eastron SDM230 always sends 3 data items but maybe SDM630 sends more?
    decoded.VAL1 = HexToFloat32(str.slice(12,20));
    decoded.VAL2 = HexToFloat32(str.slice(20,28));
    decoded.VAL3 = HexToFloat32(str.slice(28,36));
return decoded;
}

The key to interpreting what each VAL is, depends on MSG_TYP. Note that I said ‘data elements’ above, because in my case, the meter is spitting out 6 different messages in sequence, and the order is the same as in table 1 of the published protocol document Eastron_SDM230-LoRaWAN_protocol_V1.0-combined.pdf which you can get off the Eastron-Europe website (after you log in to it).

So in my case, when MSG_TYP=5 then VAL1=Import kWh, VAL2=Export kWh and VAL3=Total kWh

Below Table 1 there’s a short paragraph which shows how the register in the SDM20 which determines what messages are sent, and in which order, is set. In my case, the register is obviously set as per Table 1 and I’m getting nearly all of what the meter is capable of sending out.

I don’t really need to collect all this stuff and it would be nice to be able to change it so I’m getting just 2 messages (ie 6 data items) but I don’t know how to do this.

Suggestions welcome!

Increase meter/gw seperation as

Is a very strong signal and a -25dbm RSSI there is high risk of either RF front end overloading/distorting, increased risk of channel bleed etc. risking missed messages, CRC errors, incorrect response channels etc. :wink: If debugging a system on the bench look to get RSSI in range -45 to -105, ideally -65 to -95 for good sweet spot operation and effective debug of potentia feild behaviour… (3-5m extra distance and pref an absorber in between - wall thicker window or whatever usually works)

Thanks. Node & collector were both in my office for testing. Collector is now deployed with outside antenna and I’m getting rssi in the region of -75.

Joining the club; to contribute and maybe avoid somebody some wasted hours: the European dealer of them, cThings have a very well documented wiki with examples:

The relevant bits, just to have them copied here:

It seems that you can send some payloads to the meter for configuring it to send more data registers, but the default is pretty good already, I would say.

1 Like

And here it is my final formatter code:

// v3 to v4 compatibility wrapper
function decodeUplink(input) {
	return {
		data: Decode(input.fPort, input.bytes, input.variables)
	};
}

function bytesToInt(bytes) {
    var val = 0;
    for (var i = 0; i < bytes.length; ++i) {        
        val += bytes[i];        
        if (i < bytes.length-1) {
            val = val << 8;
        }
    }
    return val;
}

function bytesToFloat(bytes) {
  var bits = bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3];
  var sign = (bits>>>31 === 0) ? 1.0 : -1.0;
  var e = bits>>>23 & 0xff;
  var m = (e === 0) ? (bits & 0x7fffff)<<1 : (bits & 0x7fffff) | 0x800000;
  var f = sign * m * Math.pow(2, e - 150);
  return parseFloat(f);
}

// Decode decodes an array of bytes into an object.
//  - fPort contains the LoRaWAN fPort number
//  - bytes is an array of bytes, e.g. [225, 230, 255, 0]
//  - variables contains the device variables e.g. {"calibration": "3.5"} (both the key / value are of type string)
// The function must return an object, e.g. {"temperature": 22.5}
function Decode(fPort, bytes, variables) {
  var decoded = {};

  if ( bytes[4] == 01) {
  
    decoded.SERIAL_NO = bytesToInt(bytes.slice(0, 4));   // Serial number

    decoded.TOTAL_KWH = (bytesToFloat(bytes.slice(06, 10))).toFixed(3);
    decoded.VOLTAGE = (bytesToFloat(bytes.slice(10, 14))).toFixed(2);
    decoded.CURRENT = (bytesToFloat(bytes.slice(14, 18))).toFixed(3);
    decoded.POWER_FACTOR = (bytesToFloat(bytes.slice(18, 22))).toFixed(0);
    decoded.FREQUENCY = (bytesToFloat(bytes.slice(22, 26))).toFixed();
  }
  
  
  return decoded;
}
1 Like