disk91 / WioLoRaWANFieldTester

85 stars 32 forks source link

ChirpStack #41

Open aruznieto opened 1 year ago

aruznieto commented 1 year ago

Hi, WioLoRaWANFieldTester can be configurated on ChirpStack and get GPS data on this software?

disk91 commented 1 year ago

You have in the developper documentation all the information about uplink & downlink payload to manage the computations in your backend connected to ChirpStack. I'm not against an integration with ChirpStack in my backend to make the computation but I do not have any ChripStack instances available for making test.

aruznieto commented 1 year ago

Ok, I will test it, and If it works, I'll let you know

aruznieto commented 1 year ago

Hi, it works perfectly on ChirpStack, and the Codec too (only needs change "Decoder" to "Decode").

I have a question, the device is programed to send Downlink Power to Gateaway at any time?

disk91 commented 1 year ago

good to know. downlink device RSSI is not sent to gateway, it's calculated by the device (if it is your question) uplink gateway RSSI is sent to server and returned to device I recommand to read the documentation where all of this has been detailed.

hallard commented 1 year ago

@aruznieto nice, so you've done all stuff only on chirpstack side, right? if so are you sending downlink? Would love to see your decoder/encoder shared :-)

aruznieto commented 1 year ago

Hi @hallard, I only the encoder (it's exactly the same that you can see in the DEVELOPMENT.md) removing const from maxHdop and minstats

  function Decode(fPort, bytes, variables) { 
    var decoded = {};
    // avoid sending Downlink ACK to integration (Cargo)
    if (fPort === 1) {
      var lonSign = (bytes[0]>>7) & 0x01 ? -1 : 1;
      var latSign = (bytes[0]>>6) & 0x01 ? -1 : 1;

      var encLat = ((bytes[0] & 0x3f)<<17)+
                   (bytes[1]<<9)+
                   (bytes[2]<<1)+
                   (bytes[3]>>7);

      var encLon = ((bytes[3] & 0x7f)<<16)+
                   (bytes[4]<<8)+
                   bytes[5];

      var hdop = bytes[8]/10;
      var sats = bytes[9];

      maxHdop = 2;
      minSats = 5;

      if ((hdop < maxHdop) && (sats >= minSats)) {
        // Send only acceptable quality of position to mappers
        decoded.latitude = latSign * (encLat * 108 + 53) / 10000000;
        decoded.longitude = lonSign * (encLon * 215 + 107) / 10000000;  
        decoded.altitude = ((bytes[6]<<8)+bytes[7])-1000;
        decoded.accuracy = (hdop*5+5)/10
        decoded.hdop = hdop;
        decoded.sats = sats;
      } else {
        decoded.error = "Need more GPS precision (hdop must be <"+maxHdop+
          " & sats must be >= "+minSats+") current hdop: "+hdop+" & sats:"+sats;
      }
      return decoded;
    }
      return null;
}

I do not send downlink data but if @disk91 or somebody could share Encoder code It I could test it on ChirpStack.

hallard commented 1 year ago

thanks, I was hoping you send downlink, I know @disk91 will integrate chirpstack in his backend soon

hallard commented 1 year ago

OMG just retrieved I had prepared this job in node red, with distance calculation and gateway counts

image

hallard commented 1 year ago

And here the function code with data from Chirpstack (so easily transposable to Chirpstack decoder), don't ask me where I found calculation distance function, don't remember, only I had to google, but looks like not so bad :-)

Now need to finish downlink stuff

function distance(lat1, lon1, lat2, lon2) {
    a1 = lat1 * Math.PI/180; // φ, λ in radians
    a2 = lat2 * Math.PI/180;
    d1 = (lat2-lat1) * Math.PI/180;
    d2 = (lon2-lon1) * Math.PI/180;

    a = Math.sin(d1/2) * Math.sin(d1/2) + 
        Math.cos(a1) * Math.cos(a2) * 
        Math.sin(d2/2) * Math.sin(d2/2);
    c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    return 6371e3 * c; // in metres
}

var b = msg.payload.data;
var data = {};
var txt = "";
var color = "red";

// Get gateways array
var gws = msg.payload.rxInfo;
var minrssi = -999;
var maxrssi = +999;

// Calculate min/max RSSI
for (i=0; i<gws.length; i++) {
    gw = gws[i];
    if (gw.rssi < maxrssi) { maxrssi = gw.rssi; }
    if (gw.rssi > minrssi) { minrssi = gw.rssi; }
} 

// Only port with data
if (msg.payload.fPort == 1) {

    var lonSign = (b[0]>>7) & 0x01 ? -1 : 1;
    var latSign = (b[0]>>6) & 0x01 ? -1 : 1;
    var encLat = ((b[0] & 0x3f)<<17)+(b[1]<<9)+(b[2]<<1)+(b[3]>>7);
    var encLon = ((b[3] & 0x7f)<<16)+(b[4]<<8)+b[5];
    var hdop = b[8]/10;
    var sats = b[9];
    const maxHdop = 2;
    const minSats = 5;
    data.accuracy = (hdop*5+5)/10
    data.hdop = hdop;
    data.sat = sats;
    data.minrssi = minrssi;
    data.maxrssi = maxrssi;
    data.hotspot = gws.length;

    txt = "Hdop="+hdop+"   Sat="+sats;
    // Send only acceptable quality of position to mappers
    if ((hdop < maxHdop) && (sats >= minSats)) {
        // Get gateways array
        var mindist = 9999;
        var maxdist = 0;
        // Get node position        
        data.lat = latSign * (encLat * 108 + 53 ) / 10000000;
        data.lon = lonSign * (encLon * 215 + 107) / 10000000;  
        data.alt = ((b[6]<<8)+b[7])-1000;

        // Calculate distance between GW and node
        for (i=0; i<gws.length; i++) {
            gwlat = gws[i].location.latitude;
            gwlon = gws[i].location.longitude;
            node.warn("gwlat=" + gwlat + "  gwlon=" + gwlon);

            dist = distance(data.lat,data.lon,gwlat, gwlon);
            node.warn("distance=" + dist);
            if (dist>maxdist) {maxdist=dist;}
            if (dist<mindist) {mindist=dist;}
        } 
        data.mindist = Number(mindist.toFixed(0));
        data.maxdist = Number(maxdist.toFixed(0));

        color ="green";
    }
    msg.payload = data;

} else if (msg.payload.fPort == 2) {
    txt = "Request downlink";
    color = "green";
    msg = null;
}

node.status({fill: color,text: txt});
return msg;
aruznieto commented 1 year ago

For the distance you are using "Harvesine Function", this it would be the Encoder function or you mix both?

hallard commented 1 year ago

For now only for decoding going to my dashboard, but will use these calculated data to send thru downlink according @disk91 documentation ASAP

aruznieto commented 1 year ago

Ah! Ok, I calculate the distance after with Python because I need to analyze other parameters too.

hallard commented 1 year ago

and here the working downlink (my node red specific but easy to adapt)

var data = Buffer.alloc(6);
data[0] = msg.fc & 0xFF; // Frame Counter
data[1] = msg.payload.minrssi + 200;
data[2] = msg.payload.maxrssi + 200;
data[3] = (msg.payload.maxdist/250).toFixed(0);
data[4] = (msg.payload.mindist/250).toFixed(0);
data[5] = msg.payload.hotspot;

var newMsg = {}
newMsg.payload = {
    "confirmed": false,
    "fPort": 2,
    "data": Buffer.from(data,'hex').toString('base64')
}

newMsg.topic = msg.topicbase + "/command/down"

return newMsg;

works like a charm, special mention to @disk91, I feel so stupid not seeing sequenceID, because it's just frame count.