Convert to Cayenne LPP


#1

Hi,

I have some problems converting this code. Can someone assist with converting this code to Cayenne?

#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include "tinySPI.h"
#include "BME280Spi.h"
#include "LoRaWAN.h"
#include "secconfig.h" // remember to rename secconfig_example.h to secconfig.h and to modify this file


// RFM95W
#define DIO0 10
#define NSS  9
RFM95 rfm(DIO0, NSS);

// define LoRaWAN layer
LoRaWAN lora = LoRaWAN(rfm);
// frame counter for lora
unsigned int Frame_Counter_Tx = 0x0000;

// BME280 SPI Chipselect pin
#define BME_CS 7
// Default : forced mode, standby time = 1000 ms
//Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off
BME280Spi::Settings settings(BME_CS);
BME280Spi bme(settings);

// the things network stuff
// get them from the device overview page! uncomment and put this information here, remove the #include secconfig.h
// due to security reasons this information from the author is put in secconfig.h

// TTN, msb left
// unsigned char NwkSkey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// unsigned char AppSkey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// unsigned char DevAddr[4] = { 0x00, 0x00, 0x00, 0x00 };

// sleep cycles that will be counted, start with more than sleep_total to start after 8 seconds with first broadcast.
volatile int sleep_count = 38;

// set sleep time between broadcasts. The processor awakes after 8 seconds deep-sleep_mode,
// increase and checks the counter and sleep again until sleep_total is reached.
// 5min * 60s = 300/8 = 37,5 = 38.
// 17 seconds longer than 5 minutes with 37, so 35 is more apropriate
const int sleep_total = 35; // was 35

// all functions declared
ISR(WDT_vect);
void readData(float &temp, float &hum, float &press);
uint16_t vccVoltage();
void setUnusedPins();
void goToSleep();
void watchdogSetup();


void setup()
{
  // define unused pins
  setUnusedPins();

  //Initialize RFM module
  rfm.init();

  lora.setKeys(NwkSkey, AppSkey, DevAddr);

  // for BME sensor
  while(!bme.begin())
  {
     // Serial.println("Could not find BME280 sensor!");
     delay(200);
  }

}

void loop()
{

  // goToSleep for all devices...
  // The watchdog timer will reset.
  goToSleep();

  // use this for non-sleep testing:
  //delay(8000);
  //sleep_count++;

  // do action if sleep_total is reached
  if (sleep_count >= sleep_total)
  {
    uint16_t tempInt;
    uint16_t humInt;

    // define bytebuffer
    uint8_t Data_Length = 0x06;
	  uint8_t Data[Data_Length];

    float temp, hum, press;
    // read data from sensor
    readData(temp, hum, press);
    // from float to uint16_t
    tempInt = temp * 100;
    humInt = hum * 100;

    // read vcc voltage (mv)
    uint16_t vcc = vccVoltage();
    Data[0] = (vcc >> 8) & 0xff;
    Data[1] = (vcc & 0xff);

    // move into bytebuffer
    Data[2] = (tempInt >> 8) & 0xff;
    Data[3] = tempInt & 0xff;

    Data[4] = (humInt >> 8) & 0xff;
    Data[5] = humInt & 0xff;

    lora.Send_Data(Data, Data_Length, Frame_Counter_Tx);

    Frame_Counter_Tx++;

    // reset sleep count
    sleep_count = 0;

  }

}


/*
  set unused pins so no undefined situation takes place
*/
void setUnusedPins()
{
  // 0, 1, 2, 3, 8
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
}

/**
 read temperature from BME sensor
*/
void readData(float &temp, float &hum, float &press)
{
  // set units sensor
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_Pa);
  // read sensor (SPI interface)
  bme.read(press, temp, hum, tempUnit, presUnit);

}

/**
  read voltage of the rail (Vcc)
  output mV (2 bytes)
*/
uint16_t vccVoltage()
{
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  // default ADMUX REFS1 and REFS0 = 0

  // #define _BV(bit) (1 << (bit))

  // 1.1V (I Ref)(2) 100001
  ADMUX = _BV(MUX5) | _BV(MUX0);

  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA,ADSC)); // measuring

  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  uint16_t result = (high<<8) | low;

  // result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  // number of steps = 1023??
  result = (1125300L / result) ; // Calculate Vcc (in mV);

  return result;
}


void watchdogSetup()
{
  // Table for clearing/setting bits
  //WDP3 - WDP2 - WPD1 - WDP0 - time
  // 0      0      0      0      16 ms
  // 0      0      0      1      32 ms
  // 0      0      1      0      64 ms
  // 0      0      1      1      0.125 s
  // 0      1      0      0      0.25 s
  // 0      1      0      1      0.5 s
  // 0      1      1      0      1.0 s
  // 0      1      1      1      2.0 s
  // 1      0      0      0      4.0 s
  // 1      0      0      1      8.0 s


  // Reset the watchdog reset flag
  bitClear(MCUSR, WDRF);
  // Start timed sequence
  bitSet(WDTCSR, WDCE); //Watchdog Change Enable to clear WD
  bitSet(WDTCSR, WDE); //Enable WD

  // Set new watchdog timeout value to 8 second
  bitSet(WDTCSR, WDP3);
  bitClear(WDTCSR, WDP2);
  bitClear(WDTCSR, WDP1);
  bitSet(WDTCSR, WDP0);
  // Enable interrupts instead of reset
  bitSet(WDTCSR, WDIE);
}

void goToSleep()
{
  //Disable ADC, saves ~230uA
  ADCSRA &= ~(1<<ADEN);
  watchdogSetup(); //enable watchDog
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  // sleep_mode does set and reset the SE bit. sleep_enable and sleep_disable are not usefull
  sleep_mode();
  //disable watchdog after sleep
  wdt_disable();
  // enable ADC
  ADCSRA |=  (1<<ADEN);
}


ISR(WDT_vect)
{
  sleep_count++; // keep track of how many sleep cycles have been completed.
}


/*
  Hardware setup
  Attiny84 using the Arduino pin numbers! PB0 = 0 etc.


  Atmel ATtiny84A PU
  RFM95W
  BME280

  Power: 3V3 - 470uF elco over power connectors, 100nF over power connector for interference suppression
  Connections:
  RFM95W   ATtiny84

  DIO0 -- PB0
  MISO -- MOSI
  MOSI -- MISO
  SCK  -- SCK
  NSS  -- PB1 (this is Chipselect)

  Bosch BME280 sensor used with tinySPI....
  BME280  ATtiny84
  SCL -- SCK
  SDA -- MISO
  SDO -- MOSI
  CSB -- PA7 (this is Chipselect)(Arduino pin 7)

#2

try using TTN arduino library https://github.com/TheThingsNetwork/arduino-device-lib/blob/master/examples/CayenneLPP/CayenneLPP.ino for cayenne LPP


#3

Thanks shramiksalgaonkar for the link, I also consulted: Cayenne Docs and finally I managed to change the code, which I will show below.

  main.cpp
  Main code where the control takes place
  Code converted to Cayenne Low Power Payload - Marco Rudolph
  @author  Leo Korbee (c), Leo.Korbee@xs4all.nl
  @website iot-lab.org
  @license Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
  Thanks to all the folks who contributed beforme me on this code.


  Hardware information at the end of this file.
  @version 2018-03-31

  @version 2018-06-21
  binary was broken on atmelavr platform 1.9.0 (7200 bytes hex file)
  modified platform.ini to force to platform 1.8.0 (7212 bytes hex file)

*/
#include <Arduino.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include "tinySPI.h"
#include "BME280Spi.h"
#include "LoRaWAN.h"
#include "secconfig.h" // remember to rename secconfig_example.h to secconfig.h and to modify this file
#include <CayenneLPP.h>

// RFM95W
#define DIO0 10
#define NSS 9
RFM95 rfm(DIO0, NSS);

// define LoRaWAN layer
LoRaWAN lora = LoRaWAN(rfm);
// frame counter for lora
unsigned int Frame_Counter_Tx = 0x0000;

// BME280 SPI Chipselect pin
#define BME_CS 7
// Default : forced mode, standby time = 1000 ms
//Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off
BME280Spi::Settings settings(BME_CS);
BME280Spi bme(settings);

// the things network stuff
// get them from the device overview page! uncomment and put this information here, remove the #include secconfig.h
// due to security reasons this information from the author is put in secconfig.h

// TTN, msb left
// unsigned char NwkSkey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// unsigned char AppSkey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// unsigned char DevAddr[4] = { 0x00, 0x00, 0x00, 0x00 };

// sleep cycles that will be counted, start with more than sleep_total to start after 8 seconds with first broadcast.
volatile int sleep_count = 38;
//Volatile int sleep_count = 448;

// set sleep time between broadcasts. The processor awakes after 8 seconds deep-sleep_mode,
// increase and checks the counter and sleep again until sleep_total is reached.
// 5min * 60s = 300/8 = 37,5 = 38.
// 17 seconds longer than 5 minutes with 37, so 35 is more apropriate
const int sleep_total = 35; // was 35

// 60min * 60s = 3600/8 = 450
//const int sleep_total = 450;

// all functions declared
ISR(WDT_vect);
void readData(float &temp, float &hum, float &press);
uint16_t vccVoltage();
void setUnusedPins();
void goToSleep();
void watchdogSetup();

void setup()
{
  // define unused pins
  setUnusedPins();

  //Initialize RFM module
  rfm.init();

  lora.setKeys(NwkSkey, AppSkey, DevAddr);

  // for BME sensor
  while (!bme.begin())
  {
    // Serial.println("Could not find BME280 sensor!");
    delay(200);
  }
}

void loop()
{

#define LPP_TEMPERATURE 103         // 0x67 - 103 - 2 bytes, 0.1°C signed
#define LPP_RELATIVE_HUMIDITY 104   // 1 byte, 0.5% unsigned
#define LPP_ANALOG_INPUT 2         // 2 bytes, 0.01 signed
//#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1 hPa Unsigned

  // goToSleep for all devices...
  // The watchdog timer will reset.
  goToSleep();

  // use this for non-sleep testing:
  //delay(8000);
  //sleep_count++;

  // do action if sleep_total is reached
  if (sleep_count >= sleep_total)
  {
    uint16_t tempInt;
    uint8_t humInt;
    //uint16_t baPress;


    // define bytebuffer
    uint8_t Data_Length = 0x0B;
    uint8_t Data[Data_Length];
    uint8_t cursor = 0;
    

    float temp, hum, press;
    // read data from sensor
    readData(temp, hum, press);
    // from float to uint16_t
    tempInt = temp * 10;
    humInt = hum * 2;
    //baPress = press * 10;


    // read vcc voltage (mv)
    uint16_t vcc = vccVoltage();
    Data[cursor++] = 0x02;
    Data[cursor++] = LPP_ANALOG_INPUT;
    Data[cursor++] = (vcc >> 8) & 0xff;
    Data[cursor++] = vcc & 0xff;

    // move into bytebuffer
    Data[cursor++] = 0x03;
    Data[cursor++] = LPP_TEMPERATURE;
    Data[cursor++] = (tempInt >> 8) & 0xff;
    Data[cursor++] = tempInt & 0xff;

    Data[cursor++] = 0x04;
    Data[cursor++] = LPP_RELATIVE_HUMIDITY;
    Data[cursor++] = humInt;

    //Data[cursor++] = 0x05;
    //Data[cursor++] = LPP_BAROMETRIC_PRESSURE;
    //Data[cursor++] = baPress >> 8;
    //Data[cursor++] = baPress;

        lora.Send_Data(Data, Data_Length, Frame_Counter_Tx);

    Frame_Counter_Tx++;

    // reset sleep count
    sleep_count = 0;
  }
}

/*
  set unused pins so no undefined situation takes place
*/
void setUnusedPins()
{
  // 0, 1, 2, 3, 8
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
}

/**
 read temperature from BME sensor
*/
void readData(float &temp, float &hum, float &press)
{
  // set units sensor
  BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
  BME280::PresUnit presUnit(BME280::PresUnit_Pa);
  // read sensor (SPI interface)
  bme.read(press, temp, hum, tempUnit, presUnit);
}

/**
  read voltage of the rail (Vcc)
  output mV (2 bytes)
*/
uint16_t vccVoltage()
{
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  // default ADMUX REFS1 and REFS0 = 0

  // #define _BV(bit) (1 << (bit))

  // 1.1V (I Ref)(2) 100001
  ADMUX = _BV(MUX5) | _BV(MUX0);

  delay(2);            // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC))
    ; // measuring

  uint8_t low = ADCL;  // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both

  uint16_t result = (high << 8) | low;

  // result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  // number of steps = 1023??
  result = (112530L / result); // Calculate Vcc (in mV);

  return result;
}

void watchdogSetup()
{
  // Table for clearing/setting bits
  //WDP3 - WDP2 - WPD1 - WDP0 - time
  // 0      0      0      0      16 ms
  // 0      0      0      1      32 ms
  // 0      0      1      0      64 ms
  // 0      0      1      1      0.125 s
  // 0      1      0      0      0.25 s
  // 0      1      0      1      0.5 s
  // 0      1      1      0      1.0 s
  // 0      1      1      1      2.0 s
  // 1      0      0      0      4.0 s
  // 1      0      0      1      8.0 s

  // Reset the watchdog reset flag
  bitClear(MCUSR, WDRF);
  // Start timed sequence
  bitSet(WDTCSR, WDCE); //Watchdog Change Enable to clear WD
  bitSet(WDTCSR, WDE);  //Enable WD

  // Set new watchdog timeout value to 8 second
  bitSet(WDTCSR, WDP3);
  bitClear(WDTCSR, WDP2);
  bitClear(WDTCSR, WDP1);
  bitSet(WDTCSR, WDP0);
  // Enable interrupts instead of reset
  bitSet(WDTCSR, WDIE);
}

void goToSleep()
{
  //Disable ADC, saves ~230uA
  ADCSRA &= ~(1 << ADEN);
  watchdogSetup(); //enable watchDog
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  // sleep_mode does set and reset the SE bit. sleep_enable and sleep_disable are not usefull
  sleep_mode();
  //disable watchdog after sleep
  wdt_disable();
  // enable ADC
  ADCSRA |= (1 << ADEN);
}

ISR(WDT_vect)
{
  sleep_count++; // keep track of how many sleep cycles have been completed.
}

/*
  Hardware setup
  Attiny84 using the Arduino pin numbers! PB0 = 0 etc.


  Atmel ATtiny84A PU
  RFM95W
  BME280

  Power: 3V3 - 470uF elco over power connectors, 100nF over power connector for interference suppression
  Connections:
  RFM95W   ATtiny84

  DIO0 -- PB0
  MISO -- MOSI
  MOSI -- MISO
  SCK  -- SCK
  NSS  -- PB1 (this is Chipselect)

  Bosch BME280 sensor used with tinySPI....
  BME280  ATtiny84
  SCL -- SCK
  SDA -- MISO
  SDO -- MOSI
  CSB -- PA7 (this is Chipselect)(Arduino pin 7)

For the battery voltage I used Data Type: Analog Output. Is there a way to assign another widget instead of the slider?


#4

try changing the data types https://mydevices.com/cayenne/docs_stage/lora/#lora-cayenne-low-power-payload-data-types


#5

Found it! I’ts “LPP_ANALOG_INPUT” instead of “LPP_ANALOG_OUTPUT”