Battery sensor (RAK5811) by hotspot red helium, rural.draft

Hello, I do not speak English very well and I am trying to spread this to the Spanish language, I intend to implement these sensors in rural areas of my country, for example the coastal areas of Tarapacá, I am not a company or anything similar, I am simply a person who like to share.

A few days ago I acquired the helium developer kit, I have a hotspot in my house and another section, which I intend to install with solar panels, with the idea of ​​knowing the battery voltage of the hotspot I decided to start this project to create a network for my city , I have managed to use the examples, but I still cannot put together the RAK5811 example to send data over the helium network, I wanted to know if you could help me finish this project, which I want to share with Spanish-speaking people, I know how to program Arduino but at a local, without communications and I wanted to know if you can help me put together this code that I am advancing. I leave you the information, and the idea.

I first made this voltage divider to lower the voltage a bit and add it to this module.

then try to use this code to guide me to transmit data over helium network.
Código Lorawan helium network

with this sample code in arduinoIDE /RAK Wisblock Examples/RAK4631/IO/RAK5811_0-5V

/**
 * @file RAK5811_0-5V.ino
 * @author rakwireless.com
 * @brief 0 to 5V analog input example.
 * @version 0.1
 * @date 2020-07-28
 * @copyright Copyright (c) 2020
 */
 
#include <Arduino.h>
#include <Adafruit_TinyUSB.h>

#define NO_OF_SAMPLES 32

void setup()
{
	time_t timeout = millis();
	Serial.begin(115200);
	while (!Serial)
	{
		if ((millis() - timeout) < 5000)
		{
			delay(100);
		}
		else
		{
			break;
		}
	}

	/* WisBLOCK 5811 Power On*/
	pinMode(WB_IO1, OUTPUT);
	digitalWrite(WB_IO1, HIGH);
	/* WisBLOCK 5811 Power On*/

	pinMode(WB_A1, INPUT_PULLDOWN);
	analogReference(AR_INTERNAL_3_0);
	analogOversampling(128);
}

void loop()
{
	int i;

	int mcu_ain_raw = 0;

	int depths; 									// variable to store the value of oil depths
	int average_raw;
	float mcu_ain_voltage;
	float voltage_sensor; 							// variable to store the value coming from the sensor

	for (i = 0; i < NO_OF_SAMPLES; i++)
	{
		mcu_ain_raw += analogRead(WB_A1);				// the input pin A1 for the potentiometer
	}
	average_raw = mcu_ain_raw / i;            // la media de 32 mediciones 

	mcu_ain_voltage = average_raw * 3.0 / 1024; 	//raef 3.0V / 10bit ADC

	voltage_sensor = mcu_ain_voltage / 0.6; 		//WisBlock RAK5811 (0 ~ 5V).   Input signal reduced to 6/10 and output

	depths = (voltage_sensor * 1000 - 574) * 2.5; 	//Convert to millivolt. 574mv is the default output from sensor

	Serial.printf("-------average_value------ = %d\n", average_raw);
	Serial.printf("-------voltage_sensor------ = %f\n", voltage_sensor);
	Serial.printf("-------depths------ = %d mm\n", depths);

	delay(2000);
}

I present my code with errors.

/**
   @file Environment_Monitoring.ino
   @author rakwireless.com
   @brief This sketch demonstrate how to get environment data from BME680
      and send the data to lora gateway.
   @version 0.1
   @date 2020-07-28
   @copyright Copyright (c) 2020
**/

#include <Arduino.h>
#include <LoRaWan-RAK4630.h> // Click to install library: http://librarymanager/ALL#SX126x-Arduino
#include <SPI.h>
#include <Adafruit_TinyUSB.h>
#include <Wire.h>

#include <U8g2lib.h>       // Click to install library: http://librarymanager/ALL#u8g2

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);

#define NO_OF_SAMPLES 32

// RAK4630 supply two LED
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif

#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif

bool doOTAA = true;   // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60                     /**< Maximum number of events in the scheduler queue. */
#define LORAWAN_DATERATE DR_3                   /*LoRaMac datarates definition, from DR_0 to DR_5*/
#define LORAWAN_TX_POWER TX_POWER_0                 /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/
#define JOINREQ_NBTRIALS 5                      /**< Number of trials for the join request. */
DeviceClass_t g_CurrentClass = CLASS_A;         /* class definition*/
LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_AU915;    /* Region:EU868*/
lmh_confirm g_CurrentConfirm = LMH_CONFIRMED_MSG;         /* confirm/unconfirm packet definition*/
uint8_t gAppPort = LORAWAN_APP_PORT;                /* data port*/

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
*/
static lmh_param_t g_lora_param_init = {LORAWAN_ADR_OFF, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF};

// Foward declaration
static void lorawan_has_joined_handler(void);
void lorawan_join_fail(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t g_lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,
                                        lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_fail
                                       };

//OTAA keys !!!! KEYS ARE MSB !!!!
uint8_t nodeDeviceEUI[8] = {0x60, 0x81, 0xF9, 0x97, 0x1E, 0x55, 0xD7, 0xED};
uint8_t nodeAppEUI[8] = {0x60, 0x81, 0xF9, 0x9F, 0xA6, 0x64, 0x09, 0x01};
uint8_t nodeAppKey[16] = {0xE2, 0x71, 0xF3, 0xE6, 0x8F, 0x8E, 0x42, 0xCC, 0x36, 0x2D, 0xFB, 0x40, 0xC6, 0x43, 0xCE, 0xE6};

// ABP keys
uint32_t nodeDevAddr = 0x260116F8;
uint8_t nodeNwsKey[16] = {0x7E, 0xAC, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23};
uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C};

// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 64                     /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 20000                        /**< Defines for user timer, the application data transmission interval. 20s, value in [ms]. */
static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];        //< Lora user application data buffer.
static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.

TimerEvent_t appTimer;
static uint32_t timers_init(void);
static uint32_t count = 0;
static uint32_t count_fail = 0;

void setup()
{
  // Initialize the built in LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Initialize Serial for debug output
  Serial.begin(115200);

  time_t serial_timeout = millis();
  // On nRF52840 the USB serial is not available immediately
  while (!Serial)
  {
    if ((millis() - serial_timeout) < 5000)
    {
      delay(100);
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    }
    else
    {
      break;
    }
  }

  delay(2000);
  Serial.println("=====================================");
  Serial.println("Welcome to RAK4630 LoRaWan!!!");
  if (doOTAA)
  {
  Serial.println("Type: OTAA");
  }
  else
  {
    Serial.println("Type: ABP");
  }

  switch (g_CurrentRegion)
  {
    case LORAMAC_REGION_AS923:
  Serial.println("Region: AS923");
      break;
    case LORAMAC_REGION_AU915:
  Serial.println("Region: AU915");
      break;
    case LORAMAC_REGION_CN470:
  Serial.println("Region: CN470");
      break;
    case LORAMAC_REGION_EU433:
  Serial.println("Region: EU433");
      break;
    case LORAMAC_REGION_IN865:
  Serial.println("Region: IN865");
      break;
    case LORAMAC_REGION_EU868:
  Serial.println("Region: EU868");
      break;
    case LORAMAC_REGION_KR920:
  Serial.println("Region: KR920");
      break;
    case LORAMAC_REGION_US915:
  Serial.println("Region: US915");
      break;
  }


  Serial.println("=====================================");

  // Initialize LoRa chip.
  lora_rak4630_init();

 RAK5811();

  u8g2.begin();

  //creat a user timer to send data to server period
  uint32_t err_code;

  err_code = timers_init();
  if (err_code != 0)
  {
    Serial.printf("timers_init failed - %d\n", err_code);
    return;
  }

  // Setup the EUIs and Keys
  if (doOTAA)
  {
  lmh_setDevEui(nodeDeviceEUI);
  lmh_setAppEui(nodeAppEUI);
  lmh_setAppKey(nodeAppKey);
  }
  else
  {
    lmh_setNwkSKey(nodeNwsKey);
    lmh_setAppSKey(nodeAppsKey);
    lmh_setDevAddr(nodeDevAddr);
  }

  // Initialize LoRaWan
  err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion);
  if (err_code != 0)
  {
    Serial.printf("lmh_init failed - %d\n", err_code);
    return;
  }

  /* WisBLOCK 5811 Power On*/
  pinMode(WB_IO1, OUTPUT);
  digitalWrite(WB_IO1, HIGH);
  /* WisBLOCK 5811 Power On*/

  pinMode(WB_A1, INPUT_PULLDOWN);
  analogReference(AR_INTERNAL_3_0);
  analogOversampling(128);


  lmh_join();
}

void loop()
{
  // Put your application tasks here, like reading of sensors,
  // Controlling actuators and/or other functions. 
}

/**@brief LoRa function for failed Join event
*/
void lorawan_join_fail(void)
{
  Serial.println("OTAA join failed!");
}

/**@brief LoRa function for handling HasJoined event.
*/
void lorawan_has_joined_handler(void)
{
  Serial.println("OTAA Mode, Network Joined!");
  u8g2.clearBuffer();         // clear the internal memory
  u8g2.setFont(u8g2_font_ncenB10_tr); // choose a suitable font

  u8g2.drawStr(20, 39, "Joined");
  u8g2.sendBuffer(); // transfer internal memory to the display
  //delay(2000);

  lmh_error_status ret = lmh_class_request(g_CurrentClass);
  if (ret == LMH_SUCCESS)
  {
    delay(1000);
    TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&appTimer);
  }
}

/**@brief Function for handling LoRaWan received data from Gateway
   @param[in] app_data  Pointer to rx data
*/
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
                app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}

void lorawan_confirm_class_handler(DeviceClass_t Class)
{
  Serial.printf("switch to class %c done\n", "ABC"[Class]);
  // Informs the server that switch has occurred ASAP
  m_lora_app_data.buffsize = 0;
  m_lora_app_data.port = gAppPort;
  lmh_send(&m_lora_app_data, g_CurrentConfirm);
}

void send_lora_frame(void)
{
  if (lmh_join_status_get() != LMH_SET)
  {
    //Not joined, try again later
    return;
  }
  if (!RAK5811()) {
    return;
  }

  lmh_error_status error = lmh_send(&m_lora_app_data, g_CurrentConfirm);
  if (error == LMH_SUCCESS)
  {
    count++;
    Serial.printf("lmh_send ok count %d\n", count);
  }
  else
  {
    count_fail++;
    Serial.printf("lmh_send fail count %d\n", count_fail);
  }
}

/**@brief Function for handling user timerout event.
*/
void tx_lora_periodic_handler(void)
{
  TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
  TimerStart(&appTimer);
  Serial.println("Sending frame now...");
  send_lora_frame();
}

/**@brief Function for the Timer initialization.
   @details Initializes the timer module. This creates and starts application timers.
*/
uint32_t timers_init(void)
{
  TimerInit(&appTimer, tx_lora_periodic_handler);
  return 0;
}


String data = "";

void RAK5811()
{
  K = 3.57;
  char oled_data[32] = {0};
  Serial.print("result: ");
  uint32_t i = 0;
  memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE);
  m_lora_app_data.port = gAppPort;

  double v = volt;

  int i;
 
  int mcu_ain_raw = 0;

  int depths;                   // variable to store the value of oil depths
  int average_raw;
  float mcu_ain_voltage;
  float voltage_sensor;               // variable to store the value coming from the sensor
  float volt
  float v
  float K
  
  for (i = 0; i < NO_OF_SAMPLES; i++)
  {
    mcu_ain_raw += analogRead(WB_A1);       // the input pin A1 for the potentiometer
  }
  average_raw = mcu_ain_raw / i;            // la media de 32 mediciones 

  mcu_ain_voltage = average_raw * 3.0 / 1024;   //raef 3.0V / 10bit ADC

  voltage_sensor = mcu_ain_voltage / 0.6;     //WisBlock RAK5811 (0 ~ 5V).   Input signal reduced to 6/10 and output

  depths = (voltage_sensor * 1000 - 574) * 2.5;   //Convert to millivolt. 574mv is the default output from sensor

  Serial.printf("-------average_value------ = %d\n", average_raw);
  Serial.printf("-------voltage_sensor------ = %f\n", voltage_sensor);
  Serial.printf("-------depths------ = %d mm\n", depths);

  Volt = K * average_raw;
  
  delay(2000);


  data = "Voltaje Bateria:" + String(volt) + "|V| ";
  Serial.println(data);

  uint16_t v = volt * 100;                              

  //result: V=12.25V
  m_lora_app_data.buffer[i++] = 0x01;
  m_lora_app_data.buffer[i++] = (uint8_t)(v >> 8);
  m_lora_app_data.buffer[i++] = (uint8_t)v;

  m_lora_app_data.buffsize = i;
}
}

I am trying to understand all this, if someone can help me or guide me I would be very grateful. I also think that it could be useful for quite a few people to have this sensor to implement them in other areas to some google form or some other application.

I have the following errors:

I use google translator, sorry if I don’t understand correctly.
Saludos desde chile!!!
greetings from Chile.!!!

Welcome to the forum @yamilongiano

We have an example for the RAK5811 that includes the LoRaWAN/Helium connection. It is titled Water_Level_Monitoring. but you can use it for your application, just connect the battery voltage to the RAK5811 as shown in your diagram.

The example shows only the usage of A1 analog input. If you need the second analog input A0, you have to use analogRead(WB_IO4);, because that is the analog port used for A0.

1 Like

Thank you very much for the info friend, I will start working immediately.

Hello, I have managed to connect to the network and also sense a data, but the data does not upload to the helium console, for some reason it does not continue sending the data, and I cannot find the problem, could you guide me please, I think the error must be in the send_lora_frame, in the conversion of the data to the cloud. please.

/**
 * @file Water_Level_Monitoring.ino
 * @author rakwireless.com
 * @brief This sketch demonstrate reading a water level sensor
 *    and send the data to lora gateway.
 * @version 0.1
 * @date 2020-07-28
 * @copyright Copyright (c) 2020
 */
#include <Arduino.h>

#include <LoRaWan-RAK4630.h> //Click here to get the library: http://librarymanager/All#SX126x

#include <SPI.h>

// Check if the board has an LED port defined
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif

#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif

bool doOTAA = true;   // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60                      /**< Maximum number of events in the scheduler queue. */

#define LORAWAN_DATERATE DR_0
#define LORAWAN_TX_POWER TX_POWER_0
#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */
DeviceClass_t g_CurrentClass = CLASS_A;
LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_AU915;    /* Region:EU868*/
lmh_confirm g_CurrentConfirm = LMH_UNCONFIRMED_MSG;
uint8_t g_AppPort = LORAWAN_APP_PORT;

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
*/
static lmh_param_t g_lora_param_init = {
  LORAWAN_ADR_ON,
  LORAWAN_DATERATE,
  LORAWAN_PUBLIC_NETWORK,
  JOINREQ_NBTRIALS,
  LORAWAN_TX_POWER,
  LORAWAN_DUTYCYCLE_OFF
};

// Foward declaration
static void lorawan_has_joined_handler(void);
static void lorawan_join_failed_handler(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t g_lora_callbacks = {
  BoardGetBatteryLevel,
  BoardGetUniqueId,
  BoardGetRandomSeed,
  lorawan_rx_handler,
  lorawan_has_joined_handler,
  lorawan_confirm_class_handler,
  lorawan_join_failed_handler
};

//OTAA keys !!! KEYS ARE MSB !!!
uint8_t nodeDeviceEUI[8] = {0x60, 0x82, 0xF9, 0xB5, 0x92, 0x83, 0x96, 0xF8};
uint8_t nodeAppEUI[8] = {0x60, 0x84, 0xF9, 0x9F, 0xA6, 0x64, 0x09, 0x01};
uint8_t nodeAppKey[16] = {0xCD, 0x03, 0xCB, 0xDB, 0x75, 0x7C, 0xB2, 0x07, 0x75, 0xB8, 0xEE, 0xC5, 0x93, 0xFE, 0xFD, 0xF9};

// ABP keys
uint32_t nodeDevAddr = 0x260116F8;
uint8_t nodeNwsKey[16] = {0x7E, 0x=0C, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23};
uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C};

// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 64                     /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 20000                        /**< Defines for user timer, the application data transmission interval. 20s, value in [ms]. */
static uint8_t g_m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];        //< Lora user application data buffer.
static lmh_app_data_t g_m_lora_app_data = {g_m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.

TimerEvent_t g_appTimer;
static uint32_t timers_init(void);

static uint32_t g_count = 0;
static uint32_t g_count_fail = 0;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  /*
     WisBLOCK 5811 Power On
  */
  pinMode(WB_IO1, OUTPUT);
  digitalWrite(WB_IO1, HIGH);

  pinMode(WB_A1, INPUT_PULLDOWN);
  analogReference(AR_INTERNAL_3_0);
  analogOversampling(128);

  // Initialize Serial for debug output
  time_t timeout = millis();
  Serial.begin(115200);
  while (!Serial)
  {
    if ((millis() - timeout) < 5000)
    {
      delay(100);
    }
    else
    {
      break;
    }
  }
  // Initialize LoRa chip.
  lora_rak4630_init();

  // Initialize LoRa chip.
  lora_rak4630_init();

  Serial.println("=====================================");
  Serial.println("Welcome to RAK4630 LoRaWan!!!");
  if (doOTAA)
  {
    Serial.println("Type: OTAA");
  }
  else
  {
    Serial.println("Type: ABP");
  }

  switch (g_CurrentRegion)
  {
    case LORAMAC_REGION_AS923:
      Serial.println("Region: AS923");
      break;
    case LORAMAC_REGION_AU915:
      Serial.println("Region: AU915");
      break;
    case LORAMAC_REGION_CN470:
      Serial.println("Region: CN470");
      break;
  case LORAMAC_REGION_CN779:
    Serial.println("Region: CN779");
    break;
    case LORAMAC_REGION_EU433:
      Serial.println("Region: EU433");
      break;
    case LORAMAC_REGION_IN865:
      Serial.println("Region: IN865");
      break;
    case LORAMAC_REGION_EU868:
      Serial.println("Region: EU868");
      break;
    case LORAMAC_REGION_KR920:
      Serial.println("Region: KR920");
      break;
    case LORAMAC_REGION_US915:
      Serial.println("Region: US915");
    break;
  case LORAMAC_REGION_RU864:
    Serial.println("Region: RU864");
    break;
  case LORAMAC_REGION_AS923_2:
    Serial.println("Region: AS923-2");
    break;
  case LORAMAC_REGION_AS923_3:
    Serial.println("Region: AS923-3");
    break;
  case LORAMAC_REGION_AS923_4:
    Serial.println("Region: AS923-4");
      break;
  }
  Serial.println("=====================================");
  //creat a user timer to send data to server period
  uint32_t err_code;
  err_code = timers_init();
  if (err_code != 0)
  {
    Serial.printf("timers_init failed - %d\n", err_code);
    return;
  }

  // Setup the EUIs and Keys
  if (doOTAA)
  {
    lmh_setDevEui(nodeDeviceEUI);
    lmh_setAppEui(nodeAppEUI);
    lmh_setAppKey(nodeAppKey);
  }
  else
  {
    lmh_setNwkSKey(nodeNwsKey);
    lmh_setAppSKey(nodeAppsKey);
    lmh_setDevAddr(nodeDevAddr);
  }

  // Initialize LoRaWan
  err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion);
  if (err_code != 0)
  {
    Serial.printf("lmh_init failed - %d\n", err_code);
    return;
  }

  // Start Join procedure
  lmh_join();
}

void loop()
{
  // Put your application tasks here, like reading of sensors,
  // Controlling actuators and/or other functions. 
}

/**@brief LoRa function for handling HasJoined event.
*/
void lorawan_has_joined_handler(void)
{
  if(doOTAA == true)
  {
    Serial.println("OTAA Mode, Network Joined!");
  }
  else
  {
    Serial.println("ABP Mode");
  }

  lmh_error_status ret = lmh_class_request(g_CurrentClass);
  if (ret == LMH_SUCCESS)
  {
    delay(1000);
    TimerSetValue(&g_appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&g_appTimer);
  }
}
/**@brief LoRa function for handling OTAA join failed
*/
static void lorawan_join_failed_handler(void)
{
  Serial.println("OTAA join failed!");
  Serial.println("Check your EUI's and Keys's!");
  Serial.println("Check if a Gateway is in range!");
}

/**@brief Function for handling LoRaWan received data from Gateway

   @param[in] app_data  Pointer to rx data
*/
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
          app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}

void lorawan_confirm_class_handler(DeviceClass_t Class)
{
  Serial.printf("switch to class %c done\n", "ABC"[Class]);
  // Informs the server that switch has occurred ASAP
  g_m_lora_app_data.buffsize = 0;
  g_m_lora_app_data.port = g_AppPort;
  lmh_send(&g_m_lora_app_data, g_CurrentConfirm);
}

int get_voltage_sensor(void)
{
  int i;

  int sensor_pin = WB_A1;   // select the input pin for the potentiometer
  int mcu_ain_raw = 0; // variable to store the value coming from the sensor

  int depths; // variable to store the value of oil depths
  int average_raw;
  float voltage_ain, voltage_sensor;

  for (i = 0; i < 5; i++)
  {
    mcu_ain_raw += analogRead(sensor_pin);
  }
  average_raw = mcu_ain_raw / i;

  voltage_ain = average_raw * 3.0 / 1024; //raef 3.0v / 10bit ADC

  voltage_sensor = voltage_ain / 0.6; //WisBlock RAK5811 (0 ~ 5V).   Input signal reduced to 6/10 and output

  depths = (voltage_sensor * 1000 - 574) * 2.5; //Convert to millivolt. 574mv is the default output from sensor

  Serial.printf("-------voltage_sensor------ = %f\n", voltage_sensor);
  return voltage_sensor;
}

void send_lora_frame(void)
{
  int voltage_sensor;

  if (lmh_join_status_get() != LMH_SET)
  {
    //Not joined, try again later
    return;
  }

  voltage_sensor = get_voltage_sensor(); //volt range: (0 ~  5V)

  uint32_t i = 0;

  g_m_lora_app_data.port = g_AppPort;
  g_m_lora_app_data.buffer[i++] = 0x07;
  g_m_lora_app_data.buffer[i++] = (voltage_sensor >> 8) & 0xFF;
  g_m_lora_app_data.buffer[i++] = voltage_sensor & 0xFF;
  g_m_lora_app_data.buffsize = i;

  lmh_error_status error = lmh_send(&g_m_lora_app_data, g_CurrentConfirm);
  if (error == LMH_SUCCESS)
  {
    g_count++;
    Serial.printf("lmh_send ok count %d\n", g_count);
  }
  else
  {
    g_count_fail++;
    Serial.printf("lmh_send fail count %d\n", g_count_fail);
  }
}

/**@brief Function for handling user timerout event.
*/
void tx_lora_periodic_handler(void)
{
  TimerSetValue(&g_appTimer, LORAWAN_APP_INTERVAL);
  TimerStart(&g_appTimer);
  Serial.println("Sending frame now...");
  send_lora_frame();
}

/**@brief Function for the Timer initialization.

   @details Initializes the timer module. This creates and starts application timers.
*/
uint32_t timers_init(void)
{
  TimerInit(&g_appTimer, tx_lora_periodic_handler);
  return 0;
}

data does not continue to arrive in the console, it only marks that it has managed to join.

Excuse me, I don’t handle much in communications and in Lorawan I’m starting.

I forgot to insert the serial monitor.

it only takes a measurement and then it does not continue measuring more data, nor does it send the data, since it is not seen in the console.

I don’t think the data is really sent, because there should be a log output which says
lmh_send ok count 1
or
lmh_send fail count 1

It looks like the application is crashing instead.

Let me setup a device and test your code.

1 Like

thank you very much very grateful. this reminds me of my first attempts at arduino :slight_smile:

There is an mistyped number in your nodeNwsKey.
Did it compile?

And

  // Initialize LoRa chip.
  lora_rak4630_init();

was called twice.

Another problem (which is in the example itself). The function to send a LoRaWAN packet is called from a timer interrupt and should not do lengthy operations, but return as fat as possible.

I changed the code a little bit, so that it works (it works at least for me)

#include <Arduino.h>
/**
 * @file Water_Level_Monitoring.ino
 * @author rakwireless.com
 * @brief This sketch demonstrate reading a water level sensor
 *    and send the data to lora gateway.
 * @version 0.1
 * @date 2020-07-28
 * @copyright Copyright (c) 2020
 */
#include <Arduino.h>

#include <LoRaWan-RAK4630.h> //Click here to get the library: http://librarymanager/All#SX126x

#include <SPI.h>

// Check if the board has an LED port defined
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif

#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif

bool doOTAA = true;												  // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60										  /**< Maximum number of events in the scheduler queue. */

#define LORAWAN_DATERATE DR_0
#define LORAWAN_TX_POWER TX_POWER_0
#define JOINREQ_NBTRIALS 3 /**< Number of trials for the join request. */
DeviceClass_t g_CurrentClass = CLASS_A;
LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_AU915; /* Region:EU868*/
lmh_confirm g_CurrentConfirm = LMH_UNCONFIRMED_MSG;
uint8_t g_AppPort = LORAWAN_APP_PORT;

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
 */
static lmh_param_t g_lora_param_init = {
	LORAWAN_ADR_ON,
	LORAWAN_DATERATE,
	LORAWAN_PUBLIC_NETWORK,
	JOINREQ_NBTRIALS,
	LORAWAN_TX_POWER,
	LORAWAN_DUTYCYCLE_OFF};

// Foward declaration
static void lorawan_has_joined_handler(void);
static void lorawan_join_failed_handler(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
 */
static lmh_callback_t g_lora_callbacks = {
	BoardGetBatteryLevel,
	BoardGetUniqueId,
	BoardGetRandomSeed,
	lorawan_rx_handler,
	lorawan_has_joined_handler,
	lorawan_confirm_class_handler,
	lorawan_join_failed_handler};

// OTAA keys !!! KEYS ARE MSB !!!
uint8_t nodeDeviceEUI[8] = {0x60, 0x82, 0xF9, 0xB5, 0x92, 0x83, 0x96, 0xF8};
uint8_t nodeAppEUI[8] = {0x60, 0x84, 0xF9, 0x9F, 0xA6, 0x64, 0x09, 0x01};
uint8_t nodeAppKey[16] = {0xCD, 0x03, 0xCB, 0xDB, 0x75, 0x7C, 0xB2, 0x07, 0x75, 0xB8, 0xEE, 0xC5, 0x93, 0xFE, 0xFD, 0xF9};

// ABP keys
uint32_t nodeDevAddr = 0x260116F8;
uint8_t nodeNwsKey[16] = {0x7E, 0x0C, 0xE2, 0x55, 0xB8, 0xA5, 0xE2, 0x69, 0x91, 0x51, 0x96, 0x06, 0x47, 0x56, 0x9D, 0x23};
uint8_t nodeAppsKey[16] = {0xFB, 0xAC, 0xB6, 0x47, 0xF3, 0x58, 0x45, 0xC7, 0x50, 0x7D, 0xBF, 0x16, 0x8B, 0xA8, 0xC1, 0x7C};

// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 64											  /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 20000												  /**< Defines for user timer, the application data transmission interval. 20s, value in [ms]. */
static uint8_t g_m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];			  //< Lora user application data buffer.
static lmh_app_data_t g_m_lora_app_data = {g_m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.

TimerEvent_t g_appTimer;
static uint32_t timers_init(void);

static uint32_t g_count = 0;
static uint32_t g_count_fail = 0;

void setup()
{
	pinMode(LED_BUILTIN, OUTPUT);
	digitalWrite(LED_BUILTIN, LOW);

	/*
	   WisBLOCK 5811 Power On
	*/
	pinMode(WB_IO1, OUTPUT);
	digitalWrite(WB_IO1, HIGH);

	pinMode(WB_A1, INPUT_PULLDOWN);
	analogReference(AR_INTERNAL_3_0);
	analogOversampling(128);

	// Initialize Serial for debug output
	time_t timeout = millis();
	Serial.begin(115200);
	while (!Serial)
	{
		if ((millis() - timeout) < 5000)
		{
			delay(100);
			digitalToggle(LED_GREEN);
		}
		else
		{
			break;
		}
	}

	digitalWrite(LED_GREEN, LOW);
	// Initialize LoRa chip.
	lora_rak4630_init();

	Serial.println("=====================================");
	Serial.println("Welcome to RAK4630 LoRaWan!!!");
	if (doOTAA)
	{
		Serial.println("Type: OTAA");
	}
	else
	{
		Serial.println("Type: ABP");
	}

	switch (g_CurrentRegion)
	{
	case LORAMAC_REGION_AS923:
		Serial.println("Region: AS923");
		break;
	case LORAMAC_REGION_AU915:
		Serial.println("Region: AU915");
		break;
	case LORAMAC_REGION_CN470:
		Serial.println("Region: CN470");
		break;
	case LORAMAC_REGION_CN779:
		Serial.println("Region: CN779");
		break;
	case LORAMAC_REGION_EU433:
		Serial.println("Region: EU433");
		break;
	case LORAMAC_REGION_IN865:
		Serial.println("Region: IN865");
		break;
	case LORAMAC_REGION_EU868:
		Serial.println("Region: EU868");
		break;
	case LORAMAC_REGION_KR920:
		Serial.println("Region: KR920");
		break;
	case LORAMAC_REGION_US915:
		Serial.println("Region: US915");
		break;
	case LORAMAC_REGION_RU864:
		Serial.println("Region: RU864");
		break;
	case LORAMAC_REGION_AS923_2:
		Serial.println("Region: AS923-2");
		break;
	case LORAMAC_REGION_AS923_3:
		Serial.println("Region: AS923-3");
		break;
	case LORAMAC_REGION_AS923_4:
		Serial.println("Region: AS923-4");
		break;
	}
	Serial.println("=====================================");
	// creat a user timer to send data to server period
	uint32_t err_code;
	err_code = timers_init();
	if (err_code != 0)
	{
		Serial.printf("timers_init failed - %d\n", err_code);
		return;
	}

	// Setup the EUIs and Keys
	if (doOTAA)
	{
		lmh_setDevEui(nodeDeviceEUI);
		lmh_setAppEui(nodeAppEUI);
		lmh_setAppKey(nodeAppKey);
	}
	else
	{
		lmh_setNwkSKey(nodeNwsKey);
		lmh_setAppSKey(nodeAppsKey);
		lmh_setDevAddr(nodeDevAddr);
	}

	// Initialize LoRaWan
	err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion);
	if (err_code != 0)
	{
		Serial.printf("lmh_init failed - %d\n", err_code);
		return;
	}

	// Start Join procedure
	lmh_join();
}

bool send_now = false;

void loop()
{
	// Put your application tasks here, like reading of sensors,
	// Controlling actuators and/or other functions.

	if (send_now)
	{
		digitalWrite(LED_GREEN, HIGH);
		send_now = false;
		send_lora_frame();
		digitalWrite(LED_GREEN, LOW);
	}
}

/**@brief LoRa function for handling HasJoined event.
 */
void lorawan_has_joined_handler(void)
{
	if (doOTAA == true)
	{
		Serial.println("OTAA Mode, Network Joined!");
	}
	else
	{
		Serial.println("ABP Mode");
	}

	lmh_error_status ret = lmh_class_request(g_CurrentClass);
	if (ret == LMH_SUCCESS)
	{
		delay(1000);
		TimerSetValue(&g_appTimer, LORAWAN_APP_INTERVAL);
		TimerStart(&g_appTimer);
	}
}
/**@brief LoRa function for handling OTAA join failed
 */
static void lorawan_join_failed_handler(void)
{
	Serial.println("OTAA join failed!");
	Serial.println("Check your EUI's and Keys's!");
	Serial.println("Check if a Gateway is in range!");
}

/**@brief Function for handling LoRaWan received data from Gateway

   @param[in] app_data  Pointer to rx data
*/
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
	Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
				  app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}

void lorawan_confirm_class_handler(DeviceClass_t Class)
{
	Serial.printf("switch to class %c done\n", "ABC"[Class]);
	// Informs the server that switch has occurred ASAP
	g_m_lora_app_data.buffsize = 0;
	g_m_lora_app_data.port = g_AppPort;
	lmh_send(&g_m_lora_app_data, g_CurrentConfirm);
}

int get_voltage_sensor(void)
{
	int i;

	int sensor_pin = WB_A1; // select the input pin for the potentiometer
	int mcu_ain_raw = 0;	// variable to store the value coming from the sensor

	int depths; // variable to store the value of oil depths
	int average_raw;
	float voltage_ain, voltage_sensor;

	for (i = 0; i < 5; i++)
	{
		mcu_ain_raw += analogRead(sensor_pin);
	}
	average_raw = mcu_ain_raw / i;

	voltage_ain = average_raw * 3.0 / 1024; // raef 3.0v / 10bit ADC

	voltage_sensor = voltage_ain / 0.6; // WisBlock RAK5811 (0 ~ 5V).   Input signal reduced to 6/10 and output

	depths = (voltage_sensor * 1000 - 574) * 2.5; // Convert to millivolt. 574mv is the default output from sensor

	Serial.printf("-------voltage_sensor------ = %f\n", voltage_sensor);
	return voltage_sensor;
}

void send_lora_frame(void)
{
	int voltage_sensor;

	if (lmh_join_status_get() != LMH_SET)
	{
		// Not joined, try again later
		return;
	}

	voltage_sensor = get_voltage_sensor(); // volt range: (0 ~  5V)

	uint32_t i = 0;

	g_m_lora_app_data.port = g_AppPort;
	g_m_lora_app_data.buffer[i++] = 0x07;
	g_m_lora_app_data.buffer[i++] = (voltage_sensor >> 8) & 0xFF;
	g_m_lora_app_data.buffer[i++] = voltage_sensor & 0xFF;
	g_m_lora_app_data.buffsize = i;

	lmh_error_status error = lmh_send(&g_m_lora_app_data, g_CurrentConfirm);
	if (error == LMH_SUCCESS)
	{
		g_count++;
		Serial.printf("lmh_send ok count %d\n", g_count);
	}
	else
	{
		g_count_fail++;
		Serial.printf("lmh_send fail count %d\n", g_count_fail);
	}
}

/**@brief Function for handling user timerout event.
 */
void tx_lora_periodic_handler(void)
{
	TimerSetValue(&g_appTimer, LORAWAN_APP_INTERVAL);
	TimerStart(&g_appTimer);
	Serial.println("Sending frame now...");
	send_now = true;
	// send_lora_frame();
}

/**@brief Function for the Timer initialization.

   @details Initializes the timer module. This creates and starts application timers.
*/
uint32_t timers_init(void)
{
	TimerInit(&g_appTimer, tx_lora_periodic_handler);
	return 0;
}

Here is my log output:
image

1 Like

hello, thanks to you I have managed to send the data and transform it according to my needs, I am very grateful and I will document this project and see how to upload it, as I told you dear bee gee, I do not have much experience but I hope to share what I have achieved. greetings from Chile.

I changed the variables of the sensor and the coding, then I realized that the integration is divided by 100, so simply to not modify the code, multiply the value by the constant and by 100. This way, I rescue the decimals to be able to send it in int, without lose information, thanks for everything I will see how to share all this.

:clap::clap::clap:
Congratulations.
I wish you success with your project!

@mariahdz project is in Chile, close to you, maybe something RAK can promote.

1 Like

hello thanks for everything, the project works quite well, I’ll start working on the mobile application, I’m still learning, but very happy.

My intentions are totally educational, I just want to teach how to use the helium network with rak iot easy, I have the helium developer kit and I intend to upload all this information in Spanish to my channel, in this way bring this technology closer to more users in South America. an arm and thank you very much for your time.

If I may, I’ll upload the video right here when I finish recording tomorrow.

PS: I don’t know the language, I use a translator if it is not well understood, I apologize, we are in contact with more projects.

Extracted the code from the cited example and installed it for RAK19001/RAK11310:
RAK5811-NewTest.ino (1.6 KB)

(1) Grounding A1, I had expected to get 0 for average_raw. But am getting non-zero values. How does one get 0 when there is no input, or is that possible?

(2) When referring to A0, is it only necessary to change the value of sensor_pin to WB_IO4? Are any other changes needed?

I appreciate the community’s input on this matter.