Payload sparen im TTN

ttn logoWir sollen Geld sparen und jetzt auch noch Payload? Ja, bitte, denn durch weniger Payload, erzeugt ihr auch weniger Airtime. Damit ist bleibt mehr Platz für alle über. Andererseits könnt ich aber auch mehr Nachrichten übermitteln.

Aufgrund der Verschlüsselung im LoRaWAN, werden mindestens immer zwei Byte übertragen. Ausgehend von einem Overhead von 13 Byte, macht es also keinen unterschied ob ihr eine netto Payload von zwei oder drei Byte verschickt, da die Airtime für die gesamte Payload von 15 oder 16 Byte gleich bleibt.

Es gibt zu dem Thema schon mehrere Anleitung wie diese, aber es kann ja nicht genug geben.

 

Wir senden nur noch Bytes als Payload

Um Payload zu sparen, senden wir nur noch Bytes, dieses spart Platz und dank dem Payload Decoder im TTN, bekommen wir unsere Daten sogar sauber aus dem TTN Backend.

Ein Byte kann 256 Werte annehmen, von 0 bis 255. Wir werden jetzt mal 100 in ein Byte wandeln un versenden. Der Code in der Arduino IDE würe in etwa so aussehen. Die Integer Variable meinwert, wird in das Byte measurement umgewandelt.

Encode:

uint8_t measurement[1];

void do_send(osjob_t* j){
	int meinwert = 100;
	measurement[0] = meinwert;
	

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder in TTN, kann dieses wieder in unsere 100 umgewandelt werden. In dem Tab Data eurer Applikation würdet ihr dann measurement.wert = 100 sehen.

Decode:

function Decoder(b, port) {

  var meinwert = (b[0]);

  return {
    measurement: {
      wert: meinwert
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.wert;

Das war jetzt einfach, aber leider beschränken sich unsere Messwerte nicht auf den Bereich zwischen 0 und 255, also geht es weiter.

 

Feste Basis

Messungen des Luftdrucks sind eine gute Beispiel hierfür. An meinem Wohnort schwankt der Luftdruck maximal zwischen 950 und 1050 hPa. Die Werte liegen zwar über meinem Byte-Maximum von 255, schwanken aber nur um 100. Ich nehme also die 950 als minimalen Wert an und beziehe meine Messwerte darauf. Ich werde also von jeder Messung 950 abziehen und später wieder im TTN Decoder hinzurechnen. Somit habe ich wieder Werte zwischen 0 und 100, welche ich als ein Byte verschicken kann.

Encode:

uint8_t measurement[1];

void do_send(osjob_t* j){
	int luftdruck = druck;
	measurement[0] = luftdruck - 950;
	

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder in TTN, fügen wir wieder die fehlenden 950 hinzu.

Decode:

function Decoder(b, port) {

  var meinwert = b[0] + 950;

  return {
    measurement: {
      luftdruck: meinwert
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.luftdruck;

Ok, das ist auch nicht schwer. Jetzt haben wir aber auch nicht ganze Zahlen, so müssen wir also etwas tiefer in die mathematische Trickkiste greifen.

 

Runden

Als reales Beispiel nehmen wir hier mal die Luftfeuchtigkeit. Viele Fühler liefern Werte für die Luftfeuchtigkeit mit einer Nachkommastelle, diese benötigen wir aber generell nicht, es reichen Werte zwischen 0 und 100. Somit reicht es einfach den Messwert zu runden.

Encode:

uint8_t measurement[1];

void do_send(osjob_t* j){
	int hum = round(humidity);
	measurement[0] = hum;

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder bekommen wir wieder unseren Wert.

Decode:

function Decoder(b, port) {

  var meinwert = b[0] ;

  return {
    measurement: {
      hum: meinwert
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.hum;

 

Multiplizieren

Bei der Temperatur sieht es anders aus, hier interessieren die Messwerte mit einer Nachkommastelle schon. Hier multiplizieren wir, bei einer Nachkommastelle, mit 10, um eine ganze Zahl zu erhalten.

Encode:

uint8_t measurement[1];

void do_send(osjob_t* j){
	int temp = temperatur * 10;
	measurement[0] = temp;

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder in TTN dividieren wir wieder durch 10.

Decode:

function Decoder(b, port) {

  var meinwert = b[0]  / 10;

  return {
    measurement: {
      temp: meinwert
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.temp;

 

Jetzt mit zwei Bytes (Word)

Ok, das vorangegangene Beispiel war für die Temperatur nicht ganz korrekt, jetzt machen wir es richtig, damit wir auch größere Werte übermitteln können. Dazu wird der Wert auf zwei Bytes aufgeteilt. Gleichzeitig multiplizieren wir noch mit 10 um eine ganze Zahl zu bekommen. So erhalten wir 65536 mögliche positive Werte. Sollten negative Werte vorkommen, sind es 32768.

Encode:

uint8_t measurement[2];

void do_send(osjob_t* j){
	int temp = temperatur * 10;
	measurement[0] = temp >> 8;
        measurement[1] = temp & 0xFF;

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder in TTN, bekommen wir wieder unsere Temperatur.

Decode:

function Decoder(b, port) {

  var meinwert = ((bytes[1] << 8) | bytes[2]) / 10;

  return {
    measurement: {
      temp: meinwert
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.temp;

 

Mehrere Werte übermittlen

Nun wollen wir aber Temperatur und Luftdruck zusammen zu übermitteln.

Encode:

uint8_t measurement[3];

void do_send(osjob_t* j){
	int temp = temperatur * 10;
        int hum = round(humidity);
	measurement[0] = temp >> 8;
        measurement[1] = temp & 0xFF;
        measurement[2] = hum;

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder in TTN, trennen wir die Werte wieder.

Decode:

function Decoder(b, port) {

  var meinwert = ((bytes[1] << 8) | bytes[2]) / 10;
  var meinwert2 = bytes[3];

  return {
    measurement: {
      temp: meinwert,
      hum : meinwert2
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.temp;
	msg.payload_fields.measurement.hum;

 

Noch Größer

Ok, es geht natürlich noch mehr. Das beispiel hier stammt vom TTN Mapper, damit Koordinaten übermittelt werden können.

Encode:

uint8_t measurement[3];

void do_send(osjob_t* j){
	int32_t lat = flat * 10000;
	measurement[0] = lat;
        measurement[1] = lat >> 8;
        measurement[2] = lat >> 16;

    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {

        LMIC_setTxData2(1, (uint8_t*) measurement, sizeof(measurement), 0);
        Serial.println(F("Packet queued"));
    }

}

Über den Payload Decoder in TTN, fügen wir wieder die fehlenden 950 hinzu.

Decode:

function Decoder(b, port) {

  var meinwert = (b[0] | b[1]<<8 | b[2]<<16 | (b[2] & 0x80 ? 0xFF<<24 : 0)) / 10000;

  return {
    measurement: {
      lat: meinwert
    },
  };
}

In Node-RED würdet ihr mittels ttn uplink Node mittels folgender Funktion an eure Daten kommen.

Payload:

	msg.payload_fields.measurement.lat;

 

Damit sollten wir die meisten Fälle erschlagen haben und alles an Daten verschicken können, was wir so brauchen. Und auch hier gilt, viele Wege führen nach Rom.

Eine weitere Möglichkeit ist es das Cayenne LPP Format zu verwenden, dann seit ihr aber auch auf das Cayenne Dashboard angewiesen.

Schreibe einen Kommentar