Heltec CubeCell HTTC AB-02 LoRaWan mit TTN verbinden

Hallo,

Ich möchte mir eine Wetterstation mit dem o.g. Board, einem BME280 und einem Solarpanel aufbauen.
Das Board kommt mit einer eigenen Bordverwalter-URL (im Gegensatz zu den ESP32 Heltec LoRa Bords) für die Arduino IDE und eigenen Bibliotheken. Hier das einzige LoRa-Beispiel "SendReceive", welches unter LoRaWanMinimal in den Beispielscripten auftaucht:


/**
 * This is an example of joining, sending and receiving data via LoRaWAN using a more minimal interface.
 * 
 * The example is configured for OTAA, set your keys into the variables below.
 * 
 * The example will upload a counter value periodically, and will print any downlink messages.
 * 
 * please disable AT_SUPPORT in tools menu
 *
 * David Brodrick.
 */
#include "LoRaWanMinimal_APP.h"
#include "Arduino.h"

/*
 * set LoraWan_RGB to Active,the RGB active in loraWan
 * RGB red means sending;
 * RGB purple means joined done;
 * RGB blue means RxWindow1;
 * RGB yellow means RxWindow2;
 * RGB green means received done;
 */

//Set these OTAA parameters to match your app/node in TTN
static uint8_t devEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static uint8_t appKey[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

uint16_t userChannelsMask[6]={ 0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000 };

static uint8_t counter=0;

///////////////////////////////////////////////////
//Some utilities for going into low power mode
TimerEvent_t sleepTimer;
//Records whether our sleep/low power timer expired
bool sleepTimerExpired;

static void wakeUp()
{
  sleepTimerExpired=true;
}

static void lowPowerSleep(uint32_t sleeptime)
{
  sleepTimerExpired=false;
  TimerInit( &sleepTimer, &wakeUp );
  TimerSetValue( &sleepTimer, sleeptime );
  TimerStart( &sleepTimer );
  //Low power handler also gets interrupted by other timers
  //So wait until our timer had expired
  while (!sleepTimerExpired) lowPowerHandler();
  TimerStop( &sleepTimer );
}

///////////////////////////////////////////////////
void setup() {
	Serial.begin(115200);

  if (ACTIVE_REGION==LORAMAC_REGION_AU915) {
    //TTN uses sub-band 2 in AU915
    LoRaWAN.setSubBand2();
  }
 
  LoRaWAN.begin(LORAWAN_CLASS, ACTIVE_REGION);
  
  //Enable ADR
  LoRaWAN.setAdaptiveDR(true);

  while (1) {
    Serial.print("Joining... ");
    LoRaWAN.joinOTAA(appEui, appKey, devEui);
    if (!LoRaWAN.isJoined()) {
      //In this example we just loop until we're joined, but you could
      //also go and start doing other things and try again later
      Serial.println("JOIN FAILED! Sleeping for 30 seconds");
      lowPowerSleep(30000);
    } else {
      Serial.println("JOINED");
      break;
    }
  }
}

///////////////////////////////////////////////////
void loop()
{
  //Counter is just some dummy data we send for the example
  counter++; 
  
  //In this demo we use a timer to go into low power mode to kill some time.
  //You might be collecting data or doing something more interesting instead.
  lowPowerSleep(15000);  

  //Now send the data. The parameters are "data size, data pointer, port, request ack"
  Serial.printf("\nSending packet with counter=%d\n", counter);
  //Here we send confirmed packed (ACK requested) only for the first five (remember there is a fair use policy)
  bool requestack=counter<5?true:false;
  if (LoRaWAN.send(1, &counter, 1, requestack)) {
    Serial.println("Send OK");
  } else {
    Serial.println("Send FAILED");
  }
}

///////////////////////////////////////////////////
//Example of handling downlink data
void downLinkDataHandle(McpsIndication_t *mcpsIndication)
{
  Serial.printf("Received downlink: %s, RXSIZE %d, PORT %d, DATA: ",mcpsIndication->RxSlot?"RXWIN2":"RXWIN1",mcpsIndication->BufferSize,mcpsIndication->Port);
  for(uint8_t i=0;i<mcpsIndication->BufferSize;i++) {
    Serial.printf("%02X",mcpsIndication->Buffer[i]);
  }
  Serial.println();
}

Wenn ich meine TTN Keys eintrage, kann ich eine Verbindung herstellen, aber es wird keine Payload übertragen (dabei benutzte ich den Default Payload Formatter von TTN).

Nun habe ich das Script folgendermaßen angepasst, damit ich Werte für Temperatur und Feuchtigkeit übertragen kann:


/**
 * This is an example of joining, sending and receiving data via LoRaWAN using a more minimal interface.
 * 
 * The example is configured for OTAA, set your keys into the variables below.
 * 
 * The example will upload a counter value periodically, and will print any downlink messages.
 * 
 * please disable AT_SUPPORT in tools menu
 *
 * David Brodrick.
 */
#include "LoRaWanMinimal_APP.h"
#include "Arduino.h"

/*
 * set LoraWan_RGB to Active,the RGB active in loraWan
 * RGB red means sending;
 * RGB purple means joined done;
 * RGB blue means RxWindow1;
 * RGB yellow means RxWindow2;
 * RGB green means received done;
 */

//Set these OTAA parameters to match your app/node in TTN
uint8_t devEui[] = {0x70, 0xB3, 0xD5, ...};
uint8_t appEui[] = {0x49, 0x85, 0x55, ...};
uint8_t appKey[] = {0x9E, 0x92, 0x86, ...};

uint16_t userChannelsMask[6] = {0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};

static uint8_t counter = 0;

// New: declare appData array
uint8_t appData[4];

///////////////////////////////////////////////////
//Some utilities for going into low power mode
TimerEvent_t sleepTimer;
//Records whether our sleep/low power timer expired
bool sleepTimerExpired;

static void wakeUp()
{
  sleepTimerExpired = true;
}

static void lowPowerSleep(uint32_t sleeptime)
{
  sleepTimerExpired = false;
  TimerInit(&sleepTimer, &wakeUp);
  TimerSetValue(&sleepTimer, sleeptime);
  TimerStart(&sleepTimer);
  //Low power handler also gets interrupted by other timers
  //So wait until our timer had expired
  while (!sleepTimerExpired) lowPowerHandler();
  TimerStop(&sleepTimer);
}

///////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);

  if (ACTIVE_REGION == LORAMAC_REGION_AU915) {
    //TTN uses sub-band 2 in AU915
    LoRaWAN.setSubBand2();
  }
 
  LoRaWAN.begin(LORAWAN_CLASS, ACTIVE_REGION);
  
  //Enable ADR
  LoRaWAN.setAdaptiveDR(true);

  while (1) {
    Serial.print("Joining... ");
    LoRaWAN.joinOTAA(appEui, appKey, devEui);
    if (!LoRaWAN.isJoined()) {
      //In this example we just loop until we're joined, but you could
      //also go and start doing other things and try again later
      Serial.println("JOIN FAILED! Sleeping for 30 seconds");
      lowPowerSleep(30000);
    } else {
      Serial.println("JOINED");
      break;
    }
  }
}

///////////////////////////////////////////////////
void loop()
{
  //Counter is just some dummy data we send for the example
  counter++; 
  
  //In this demo we use a timer to go into low power mode to kill some time.
  //You might be collecting data or doing something more interesting instead.
  lowPowerSleep(15000);  

  //Now send the data. The parameters are "data size, data pointer, port, request ack"
  Serial.printf("\nSending packet with counter=%d\n", counter);

  //Here we send confirmed packed (ACK requested) only for the first five (remember there is a fair use policy)
  bool requestack = counter<5?true:false;

  prepareTxFrame();

  if (LoRaWAN.send(1, appData, 2, requestack)) {
    Serial.println("Send OK");
  } else {
    Serial.println("Send FAILED");
  }
}

///////////////////////////////////////////////////
//Example of handling downlink data
void downLinkDataHandle(McpsIndication_t *mcpsIndication)
{
  Serial.printf("Received downlink: %s, RXSIZE %d, PORT %d, DATA: ",mcpsIndication->RxSlot?"RXWIN2":"RXWIN1",mcpsIndication->BufferSize,mcpsIndication->Port);
  for(uint8_t i=0;i<mcpsIndication->BufferSize;i++) {
    Serial.printf("%02X",mcpsIndication->Buffer[i]);
  }
  Serial.println();
}

/* Prepares the payload of the frame */
static void prepareTxFrame()
{
  /*appData size is LORAWAN_APP_DATA_MAX_SIZE which is defined in "commissioning.h".
  *appDataSize max value is LORAWAN_APP_DATA_MAX_SIZE.
  *if enabled AT, don't modify LORAWAN_APP_DATA_MAX_SIZE, it may cause system hanging or failure.
  *if disabled AT, LORAWAN_APP_DATA_MAX_SIZE can be modified, the max value is reference to lorawan region and SF.
  *for example, if use REGION_CN470, 
  *the max value for different DR can be found in MaxPayloadOfDatarateCN470 refer to DataratesCN470 and BandwidthsCN470 in "RegionCN470.h".
  */
  float temperature = 20.30;  // Example
  float humidity = 65.2;    // Example

  int int_temp = temperature * 100; // Remove comma
  int int_hum = humidity * 10; // Remove comma
  
  appData[0] = int_temp >> 8;
  appData[1] = int_temp;
  appData[2] = int_hum >> 8;
  appData[3] = int_hum;
}

Dazu habe ich folgenden Payload Formatter hinterlegt:


function decodeUplink(input) {
  
  var temp = input.bytes[0] << 8 | input.bytes[1];
  var hum = input.bytes[2] << 8 | input.bytes[3];
  
  return {
    data: {
      temperature: temp/100,
      humidity: hum/10
    }
  };
}

Allerdings bekomme ich immer nur die folgende Ausgabe in den 'Live data':

{ humidity: 0, temperature: 17.2 } … also statt 62.5 und 20.30

Kann mir jemand sagen, wo mein Fehler liegt?

Vielen Dank!
Martin

bitte zeig mal zusammenpassend:

-die Daten aus temp und hum vom node
-die entschlüsselten RAW daten die beim decoder ankommen.
-die Werte die dein Decoder ermittelt

alle 3 Angaben!

edit:
setz mal klammern im decoder beim Zusammenbauen deiner Variablen.
Habs nur mal schnell in C++

void setup() {
  Serial.begin(115200);
  prepareTxFrame();
  decode();

}

void loop() {
  // put your main code here, to run repeatedly:

}


void prepareTxFrame()
{
  /*appData size is LORAWAN_APP_DATA_MAX_SIZE which is defined in "commissioning.h".
  *appDataSize max value is LORAWAN_APP_DATA_MAX_SIZE.
  *if enabled AT, don't modify LORAWAN_APP_DATA_MAX_SIZE, it may cause system hanging or failure.
  *if disabled AT, LORAWAN_APP_DATA_MAX_SIZE can be modified, the max value is reference to lorawan region and SF.
  *for example, if use REGION_CN470, 
  *the max value for different DR can be found in MaxPayloadOfDatarateCN470 refer to DataratesCN470 and BandwidthsCN470 in "RegionCN470.h".
  */
  float temperature = 20.30;  // Example
  float humidity = 65.2;    // Example

  int int_temp = temperature * 100; // Remove comma
  int int_hum = humidity * 10; // Remove comma
  
  byte appData[4];

  appData[0] = int_temp >> 8;
  appData[1] = int_temp;
  appData[2] = int_hum >> 8;
  appData[3] = int_hum;

  Serial.println(appData[0], HEX);
  Serial.println(appData[1], HEX);
  Serial.println(appData[2], HEX);
  Serial.println(appData[3], HEX);

}

void decode() {
  byte input[4];
  input[0]=0x07;
  input[1]=0xED;
  input[2]=0x02;
  input[3]=0x8c;

  int temp = (input[0] << 8) | input[1];
  int hum = (input[2] << 8) | input[3];
  
  Serial.println(temp/100.0);
  Serial.println(hum/10.0);
}

7
ED
2
8C

20.29
65.20

Hmm, ich dachte das steht alles bereits in dem Post ..

Also vor dem Decodieren int_temp = 20.30; int_hum = 65.2, das wird in int umgewandelt und in das array appData gepackt.

Danach wird es gesendet, payload Formatter siehe oben. In den Live data erscheint:
“humidity: 0, temperature: 17.2”

Wo kann ich sehen, wie die entschlüsselten RAW Daten aussehen?

Also decode() kennt die Arduino IDE nicht ..

nein das tut es nicht.

die Rawdaten siehst du in Applications > [dein vergebene Applikationsname] > Livedata

Sorry, das dauert bei mir immer ewig, bis ich was in TTN sehe, da ich keinen eigenen Gateway habe .. also wenn ich das richtig sehe steht da als RAW Data nur 07 oder 0x07

Übrigens war das oben ein Fehler, ich sehe bei der Temperatur nicht 17.2 sondern 17.92

Ich habe jetzt mal testweise das folgende Beispiel in mein Script übernommen und die Temperatur und Humidity Daten ausgeblendet:

uint8_t appData[2];
int var = 123450; // entspricht als Payload: 30 A2

appData[0] = var >> 8;
appData[1] = var;

und als Payload Formatter:

function decodeUplink(bytes, port) {
var decoded_var = bytes[0] << 8 | bytes[1];

return {
var: decoded_var
};
}

Als Raw Data kommt "E2" an.

Kann es sein, das Du übers Ziel schiesst?

Das passt nicht in 16 bit!

Ah ok, das war mir nicht klar. Also schlechtes Beispiel … Das zeigt, dass ich mich mit diesen Dingen eben nicht gut auskenne :slight_smile:

Ich habe mich auf diesen Beitrag bezogen:

https://www.aeq-web.com/so-funktioniert-die-lora-payload-encoder-decoder-ttn/

code in code tags posten!(!!!)

außerdem habe ich oben schon geschrieben du sollst Klammern setzen.

var decoded_var =( bytes[0] << 8) | bytes[1];

wobei ich behaupte dein neuer Decoder funktioniert nur im alten TTN V2.
In TTN V3 muss das so aufgebaut sein wie in deinem Start-Post.
input ist eine Struktur die u.a. bytes enthält. Daher der Zugriff über input.bytes.
Den Link den du gepostet hast ist vermutlich veraltert.

Nochmal zusammenfassend: das geschifftete Ergebnis in eine Klammer setzen.

Ok, danke

Ich habe ein anderes Script gefunden, welches funktioniert. Wie markiere ich einen anderen Beitrag als Lösung?

das solltest du unter jedem Beitrag sehen können:

einen kannst du als Solution markieren. Herzchen kannst mehrmals vergeben.
Wenn es eine ganz andere Lösung ist, poste einfach dein neues Script.

Obwohl sich am Encodieren und Decodieren der Payload nichts geändert hat, funktioniert dieses Script im Gegensatz zum ersten:

#include <LoRaWan_APP.h>
#include <Arduino.h>

/*
set LoraWan_RGB to Active, the RGB active in loraWan
RGB red means sending;
RGB purple means joined done;
RGB blue means RxWindow1;
RGB yellow means RxWindow2;
RGB green means received done;
*/

// OTAA parameters
uint8_t devEui[] = {0x70, 0xB3, ...};
uint8_t appEui[] = {0x49, 0x85, ...};
uint8_t appKey[] = {0x9E, 0x92, ...};

// ABP parameters
uint8_t nwkSKey[] = {};
uint8_t appSKey[] = {};
uint32_t devAddr = (uint32_t )0x26...;

// LoraWan channelsmask, default channels 0-7
uint16_t userChannelsMask[6] = {0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000};

// LoraWan region, select in arduino IDE tools
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;

// LoraWan Class, Class A and Class C are supported
DeviceClass_t loraWanClass = LORAWAN_CLASS;

// The application data transmission duty cycle. value in [ms].
uint32_t appTxDutyCycle = 15000;

// OTAA or ABP
bool overTheAirActivation = LORAWAN_NETMODE;

// ADR enable
bool loraWanAdr = LORAWAN_ADR;

// set LORAWAN_Net_Reserve ON, the node could save the network info to flash, when node reset not need to join again.
bool keepNet = LORAWAN_NET_RESERVE;

// Indicates if the node is sending confirmed or unconfirmed messages.
bool isTxConfirmed = LORAWAN_UPLINKMODE;

// Application port
uint8_t appPort = 2;

// Number of trials to transmit the frame, if the LoRaMAC layer did not receive an acknowledgment.
uint8_t confirmedNbTrials = 4;


void setup() {
  
  Serial.begin(115200);

  #if(AT_SUPPORT)
    enableAt();
  #endif

  deviceState = DEVICE_STATE_INIT;
  LoRaWAN.ifskipjoin();
}

void loop() {

  switch(deviceState) {

    case DEVICE_STATE_INIT: {
      #if(LORAWAN_DEVEUI_AUTO)
        LoRaWAN.generateDeveuiByChipID();
      #endif
      #if(AT_SUPPORT)
        getDevParam();
      #endif
      printDevParam();
      LoRaWAN.init(loraWanClass,loraWanRegion);
      deviceState = DEVICE_STATE_JOIN;
    break;
    }

    case DEVICE_STATE_JOIN: {
      LoRaWAN.join();
    break;
    }

    case DEVICE_STATE_SEND: {
      prepareTxFrame(appPort);
      LoRaWAN.send();
      deviceState = DEVICE_STATE_CYCLE;
    break;
    }

    case DEVICE_STATE_CYCLE: {
      // Schedule next packet transmission
      txDutyCycleTime = appTxDutyCycle + randr(0, APP_TX_DUTYCYCLE_RND);
      LoRaWAN.cycle(txDutyCycleTime);
      deviceState = DEVICE_STATE_SLEEP;
    break;
    }

    case DEVICE_STATE_SLEEP: {
      LoRaWAN.sleep();
    break;
    }

    default: {
      deviceState = DEVICE_STATE_INIT;
    break;
    }
  }
}

// Prepares the payload of the frame
static void prepareTxFrame(uint8_t port) {

  float temperature = 20.30;
  float humidity = 65.2;

  int int_temp = temperature * 100;
  int int_hum = humidity * 10; 

  appDataSize = 4;
  appData[0] = int_temp >> 8;
  appData[1] = int_temp;
  appData[2] = int_hum >> 8;
  appData[3] = int_hum;
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.