Codeing Service

Does anyone provide a service that will write code for the Cubecell ?
I can’t get any of the examples to do what I need and need more documentation than I can find.
I do not care to post code to have my ignorance of coding ridiculed.
Thanks

We can help.
Please tell me what you would like archive with your cubecell

I have the HTCC-AB01 connected to an ultrasonic sensor HC-SR04.
I have code that will read the distance and send it to Heltec WiFi Kit 32 OLED. I then up load data by WiFi to Adafruit IO.
I. Would like the AB01 to transmit distance to the ESP32 then sleep for as long as possible like 2 hours. It will be on battery and solar panel, I would also like it to transmit battery voltage.
I can not get the low power code to work with the AB01 in this case.
I can get data and upload to Adafruit, but not at low power or sleeping.
Thanks

Hi,

Would you consider using LoRaWAN for this application - if so I have working code I can send to you?

Regards,

Justin

Did you ever get help if so i would love to see the script. I’m trying to do a similar thing.

Hi,

Firstly I should state that my coding isn’t great, but I am certainly willing to help. I have a couple of different sensor types and have a bit of a common library for the cubecell that I’m slowly building to support them. The following two files need to be put in a folder where all your libraries are:

Cubecell_Sensor_Boards.h

// Base variables and various functions for using Cubecell dev boards with HTCC-AB01 (CommonSensor_Cubecell)
// 08/08/2021 by Justin Wyatt <>
// Updates should always be available at <no online library currently avaiable>
//
// Changelog:
//    2021-08-08 - initial release - TankSensor board support
//    2021-08-14 - added support for SoilSensor board
//
/* ============================================
Cubecell Common Sensor Board code is placed under the MIT license
Copyright (c) 2021 Justin Wyatt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/
 
#ifndef CUBECELLSENSORBOARDS_H_
#define CUBECELLSENSORBOARDS_H_
#include "LoRaWan_APP.h"
#include "Arduino.h"
#include <Wire.h>
#include <Sodaq_SHT2x.h>
#include <ArduinoJson.h>
#include <AT24Cxx.h>
#include <ADC081C.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>

// Set the DEBUG level - 0 none, 1 info, 2 verbose
#define DEBUG 2
// Required for SHT
#define WATER_VAPOR 17.62f
#define BAROMETRIC_PRESSURE 243.5f
// Required for Ultrasonic sensor
#define trigPin GPIO1
#define echoPin GPIO2
#define tempPin GPIO1
#define soilPin GPIO2
#define lightPin GPIO3

// I2C Address of the EEPROM onboard is 0x50 and the EEPROM is 256kbytes
#define eep_i2c_address 0x50
// I2C Addresses of ADC081C are 0x51 and 0x52
#define adc1_i2c_address 0x51
#define adc2_i2c_address 0x52


struct Structured_Variables {
   uint8_t cfg_8bit[16];
   uint16_t cfg_16bit[8];
   uint32_t cfg_32bit[4];
};

static const char* const HEX_CHARS = "0123456789ABCDEF";

void setup_MPU6050(void);
uint8_t hexpairtouint8(char a, char b);
void i2cinit(void);
unsigned long pulselength(uint8_t pin, uint8_t state, unsigned long timeout = 1000000);
ssize_t to_hex(char* dest, size_t dest_size, const void* src, size_t src_size);



#endif

Cubecell_Sensor_Boards.cpp

// Base variables and various functions for using Cubecell dev boards with HTCC-AB01 (CommonSensor_Cubecell)
// 08/08/2021 by Justin Wyatt <>
// Updates should always be available at <no online library currently avaiable>
//
// Changelog:
//    2021-08-08 - initial release - TankSensor board support
//    2021-08-14 - added support for SoilSensor board
//
/* ============================================
Cubecell Common Sensor Board code is placed under the MIT license
Copyright (c) 2021 Justin Wyatt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/

#include "Cubecell_Sensor_Boards.h"

/*
 * When LoraWan_RGB is set to Active,the LED will show the following states:
 * RGB red - sending
 * RGB purple - join done
 * RGB blue - RxWindow1
 * RGB yellow - RxWindow2
 * RGB green - receive done
*/

/* The following key definitions are here as the CubeCell libraries require them to be defined or the sketch won't compile
 * OTAA para*/
uint8_t devEui[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t appEui[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t appKey[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

/* ABP para*/
uint8_t nwkSKey[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ,0xFF };
uint8_t appSKey[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ,0xFF };
uint32_t devAddr =  ( uint32_t )0xFFFFFFFF;

/*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 = 60000;

/*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 times to try transmiting the frame, if the LoRaMAC layer did not
* receive an acknowledgment. The MAC performs a datarate adaptation,
* according to the LoRaWAN Specification V1.0.2, chapter 18.4, according
* to the following table:
*
* Transmission nb | Data Rate
* ----------------|-----------
* 1 (first)       | DR
* 2               | DR
* 3               | max(DR-1,0)
* 4               | max(DR-1,0)
* 5               | max(DR-2,0)
* 6               | max(DR-2,0)
* 7               | max(DR-3,0)
* 8               | max(DR-3,0)
*
* Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
* the datarate, in the case where the LoRaMAC layer did not receive an acknowledgment
* it is recommended to leave this at 3 or more and prefferably 6-8
*/
uint8_t confirmedNbTrials = 6;

// define MPU object for the MPU6050 onboard I2C addr 0x68 (uses 9250 library) - currently unused
// TODO add useful code to support the MPU6050 and measure vibration etc at the device
extern Adafruit_MPU6050 mpu;


void setup_MPU6050(void){
  i2cinit();
  if(mpu.begin()){
    mpu.setAccelerometerRange(MPU6050_RANGE_2_G);
    mpu.setGyroRange(MPU6050_RANGE_250_DEG);
    mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
    Serial.println("MPU6050 initialised");
    delay(100);
  }
  else {
    Serial.println("Unable to connect to MPU6050");
  }
}

// outrageously inefficient method of converting two chars (hex pair) into a single uint8_t (0-255) number.
uint8_t hexpairtouint8(char a, char b){
   int x = 0;
   int y = 0;
   switch(a){
      case '0': x = 0; break;
      case '1': x = 1; break;
      case '2': x = 2; break;
      case '3': x = 3; break;
      case '4': x = 4; break;
      case '5': x = 5; break;
      case '6': x = 6; break;
      case '7': x = 7; break;
      case '8': x = 8; break;
      case '9': x = 9; break;
      case 'a': x = 10; break;
      case 'b': x = 11; break;
      case 'c': x = 12; break;
      case 'd': x = 13; break;
      case 'e': x = 14; break;
      case 'f': x = 15; break;
      case 'A': x = 10; break;
      case 'B': x = 11; break;
      case 'C': x = 12; break;
      case 'D': x = 13; break;
      case 'E': x = 14; break;
      case 'F': x = 15; break;
   }
   switch(b){
      case '0': y = 0; break;
      case '1': y = 1; break;
      case '2': y = 2; break;
      case '3': y = 3; break;
      case '4': y = 4; break;
      case '5': y = 5; break;
      case '6': y = 6; break;
      case '7': y = 7; break;
      case '8': y = 8; break;
      case '9': y = 9; break;
      case 'a': y = 10; break;
      case 'b': y = 11; break;
      case 'c': y = 12; break;
      case 'd': y = 13; break;
      case 'e': y = 14; break;
      case 'f': y = 15; break;
      case 'A': y = 10; break;
      case 'B': y = 11; break;
      case 'C': y = 12; break;
      case 'D': y = 13; break;
      case 'E': y = 14; break;
      case 'F': y = 15; break;
   }
   return (uint8_t)((x << 4) | y);
}


// this function was written explicitly because there appears to be some sort of hanging of the I2C bus, especially after Vext has been turned off and then on again
// when the bus hangs it appears to read or write but does not actualy return correct results or write to the eeprom
// we repetitively check that the I2C clock is not 0 and if it is, reset the I2C bus - this appears to fix the I2C bus after one or two cycles
void i2cinit(void){
  Wire.begin();
  Wire.setClock(10000);
  if(DEBUG){
    Serial.print("I2C Clock ");
    Serial.println(Wire.getClock());
  }
  while (Wire.getClock() == 0){
    if(DEBUG){ 
      Serial.println("I2C problem - Resetting I2C bus");
    }
    Wire.end();
    delay(100);
    Wire.begin();
    Wire.setClock(10000);
    if(DEBUG){
      Serial.print("I2C Clock ");
      Serial.println(Wire.getClock());
    }
  }
}

// the pulsein() function works fine in in cubecell library as long as you don't need the timeout function (which appears to never return)
// this function replaces the pulsein() function, where a timeout is required. 
unsigned long pulselength(uint8_t pin, uint8_t state, unsigned long timeout)
{
    //Serial.println("PL");
    uint8_t stateMask = state;
    // keep initialization out of time critical area
    unsigned long width = 0;  
    // convert the timeout from microseconds to a number of times through
    // the initial loop; it takes 40 clock cycles per iteration.
    unsigned long numloops = 0;
    unsigned long maxloops = microsecondsToClockCycles(timeout) / 40;

    // wait for any previous pulse to end
    while (digitalRead(pin) == stateMask)
        if (numloops++ == maxloops)
            return timeout;

    // wait for the pulse to start
    while (digitalRead(pin) != stateMask)
        if (numloops++ == maxloops)
            return timeout;

    // wait for the pulse to stop
    while (digitalRead(pin) == stateMask) {
        if (numloops++ == maxloops)
            return timeout;
        width++;
    }
    // convert the reading to microseconds. The loop has been determined
    // to be 40 clock cycles long and have about 30 clocks between the edge
    // and the start of the loop. There will be some error introduced by
    // the interrupt handlers.
    return clockCyclesToMicroseconds(width * 40 + 30); 
}
 
// the to_hex function converts an arbitrary sized type to an appropriately sized char array. Requires the use of malloc or similar (inadvisable)
// TODO - rewrite using fixed length char array and define several functions to convert various types (or write as templated function.
ssize_t to_hex(char* dest, size_t dest_size, const void* src, size_t src_size) {
   if (dest == NULL)
      return src_size*2+1;
   if (dest_size < src_size*2+1)
      return -1;
   while (src_size--) {
      *(dest++) = HEX_CHARS[*((const uint8_t*)src) >> 4];
      *(dest++) = HEX_CHARS[*((const uint8_t*)src) & 0xF];
      src = (const uint8_t*)src + 1;
   }
   *dest = '\0';
   return src_size*2+1;
}

The tanksensor code (which uses an ultrasonic sensor to pick up the surface of the water.
LoRaWan_Tanksensor.ino

     // Ultrasonic Sensor for Tank Level Sensing using Cubecell dev board HTCC-AB01 (LoRaWAN_TankSensor_Cubecell)
     // 08/08/2021 by Justin Wyatt <>
     // Updates should always be available at <no online library currently avaiable>
     //
     // Changelog:
     //    2021-08-08 - added downlink handler (allowing remote configuration)
     //               - added EEPROM saved configuration, loaded at startup
     //               - added stub MPU6050 support
     //    2020-01-05 - initial release
     //
     // Requires: 
     //    - Ultrasonic Tank Sensor LoRaWAN board >=v0.0.1
     //    - Cubecell HTTC-AB01 connected to the above board
     //    - Cubecell Development Framework >=v1.2.0
     //    - Cubecell Sensor Board Common >=v0.0.2
     //    - Sodaq_SHT2X Library =v1.2.0
     //    - AT24CXX Library =v1.0.0
     //    - Adafruit MPU6050 Library =v2.0.5 and all prerequisite Adafruit libraries  
     /* ============================================
     LoRaWAN TankSensor Cubecell code is placed under the MIT license
     Copyright (c) 2021 Justin Wyatt
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"), to deal
     in the Software without restriction, including without limitation the rights
     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     copies of the Software, and to permit persons to whom the Software is
     furnished to do so, subject to the following conditions:
     The above copyright notice and this permission notice shall be included in
     all copies or substantial portions of the Software.
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     THE SOFTWARE.
     ===============================================
     */
 
     #include "Cubecell_Sensor_Boards.h"
 
     // define MPU object for the MPU6050 onboard I2C addr 0x68 (uses 9250 library) - currently unused
     // TODO add useful code to support the MPU6050 and measure vibration etc at the device
     Adafruit_MPU6050 mpu;
 
     // I2C Address of the EEPROM onboard is 0x50 and the EEPROM is 256kbytes
     #define i2c_address 0x50
     AT24Cxx eep(i2c_address, 256);
 
     // Define the struct to hold a local copy of variables copied from EEPROM
     struct Structured_Variables local_cfg;
 
     // Required for JSON serialisation - we use a JSON string as the payload for the TX packets - note that most
     // LoRaWAN networks will provide this string as BASE64 encoded ASCII at the other end and the string needs
     // to be decoded from BASE64 to JSON before further processing / decoding 
     const int capacity = JSON_OBJECT_SIZE(8);
     StaticJsonDocument<capacity> doc;
     // variable to hold the enabled measurements to be sent for TX (read from EEPROM address 24)
     uint8_t enabled = 255;
     // variable to hold the ultrasonic distance that equals "full tank" (read from EEPROM address 25 and multiplied by 2)
     uint16_t full;
     // variable to hold the ultrasonic distance that equals "empty tank" (read from EEPROM address 26 and multiplied by 2)
     uint16_t empty;
 
     /* Prepares the payload of the LoRaWAN frame
      * TODO - check data frame sizes and ensure that we handle long frames better.
     */
     static void prepareTxFrame( uint8_t port )
     {
       float duration;
       uint16_t distance;
       // Turn on power source for peripherals - SHT21, AT24C256, MPU6050, Ultrasonic Sensor, MAX3232 and associated supplies
       pinMode(Vext, OUTPUT);
       digitalWrite(Vext, LOW);
       // Sets the Ultrasonic trigPin as an Output
       pinMode(trigPin, OUTPUT);
       // Sets the Ultrasonic echoPin as an Input 
       pinMode(echoPin, INPUT); 
       // Initialise the I2C Bus
       i2cinit();
       // Clears the Ultrasonic trigPin
       digitalWrite(trigPin, LOW);
       delayMicroseconds(10);
       // Sets the Ultrasonic trigPin at HIGH state for 20 micro seconds then LOW state - triggers measurement
       digitalWrite(trigPin, HIGH);
       delayMicroseconds(20);
       digitalWrite(trigPin, LOW);
       // Reads the echoPin, returns the sound wave travel time in microseconds
       duration = pulseIn(echoPin, HIGH);
       // After sleeping we will get the wrong distance the first time, so we need to repeat the process now 
       // that the threshold level on the ultrasonic sensor has been set from the first pass
       delayMicroseconds(10);
       digitalWrite(trigPin, HIGH);
       delayMicroseconds(20);
       digitalWrite(trigPin, LOW);
       duration = pulseIn(echoPin, HIGH);
       // Calculate the distance from the pulse duration
       distance = (uint16_t)(duration*0.034/2);
       // If distance is smaller than 20cm or larger than 7m (optimistic) - set 0 as an error value
       if ((distance <= 20) or (distance > 700)){
         distance = 0;
       }
       // Get the humidity and temperature readings from the SHT21 sensor
       float humidity = SHT2x.GetHumidity();
       float temperature = SHT2x.GetTemperature();
       // Calculate the intermediate value 'gamma' - used for calculating dew point temp
       float gamma = log(humidity / 100) + WATER_VAPOR * temperature / (BAROMETRIC_PRESSURE + temperature);
       // Calculate dew point in deg Celsius
       float dewPoint = BAROMETRIC_PRESSURE * gamma / (WATER_VAPOR - gamma);
       // Clear and reset the I2C Bus
       Wire.end();
       // Turn off power source for peripherals - SHT21, AT24C256, MPU6050, Ultrasonic Sensor, MAX3232 and associated supplies
       // This lowers load on the battery for measurement of its voltage, and also saves power as we are removing load as soon as possible
       digitalWrite(Vext, HIGH);
       // Measure the battery voltage (this will show ~4.15V if on USB power and will give the battery voltage on battery power
       uint16_t batteryVoltage = getBatteryVoltage();
       // Prints the sensor values on the Serial Monitor
       if(DEBUG){
         Serial.print("Distance: ");
         Serial.println(distance);
         Serial.print("Humidity(%RH): ");
         Serial.print(humidity);
         Serial.print("     Temperature(C): ");
         Serial.println(temperature);
         Serial.print("     Dewpoint(C): ");
         Serial.println(dewPoint);
         Serial.print("BatteryVoltage:");
         Serial.println(batteryVoltage);
       }
       // We use a JSON string as the payload for the TX packets - note that most
       // LoRaWAN networks will provide this string as BASE64 encoded ASCII at the other end and the string needs
       // to be decoded from BASE64 to JSON before further processing / decoding
       // Clear the JSON string and then copy our measured values into the JSON string for sending to our application
       // Note that only the enabled values will be sent. The enabled variable can be set OTA on port 8 using the key "SUP"
       doc.clear();
       // Always include battery voltage in TX 
       doc["BAT"] = batteryVoltage;
       // If bit 7 of enabled is NOT set - send internal temp
       if(bitRead(enabled,7) == 0){
         doc["TMP"] = temperature;
       }
       // If bit 6 of enabled is NOT set - send internal humidity
       if(bitRead(enabled,6) == 0){
         doc["HUM"] = humidity;  
       }
       // If bit 5 of enabled is NOT set - send internal dewpoint
       if(bitRead(enabled,5) == 0){
         doc["DWP"] = dewPoint;  
       }
       // If bit 4 of enabled is NOT set - send ultrasonic distance measurement
       if(bitRead(enabled,4) == 0){
         doc["DUS"] = distance;
       }
       // If bit 3 of enabled is NOT set - send tank fill percentage
       // This measurement is based on the ultrasonic measurement and saved empty and fill values
       // empty and fill values can be set OTA on port 8 using the key "TKP" with sub keys "EMPTY" and "FULL" 
       if(bitRead(enabled,3) == 0){
         if (empty > full ){
           doc["TKP"] = ((100 * (empty - distance)) / (empty - full));
         }
         // just in case empty and full have been swapped 
         else if (empty < full ){
           doc["TKP"] = 100 * (full - distance) / (full - empty);
         }
         // We can't divide by zero so if empty and full are the same - set output to 0
         else {
           doc["TKP"] = 0;
         }
       }
       // If bit 2 of enabled is NOT set - RESERVED - do nothing
       if(bitRead(enabled,2) == 0){}
       // If bit 1 of enabled is NOT set - RESERVED - do nothing
       if(bitRead(enabled,1) == 0){}
       // If bit 0 of enabled is SET then send a string that contains the 3 letter codes and bit position supported by the device
       // also send the Chip ID - this is sent numerically, so needs to be converted to HEX to see the EUI48 string - can be used
       // to create a devEUI by padding with FEFF after the 6th HEX character - eg CAA2EDE32B4E becomes CAA2EDFEFFE32B4E 
       if(bitRead(enabled,0)== 1){
         doc["SUP"] = "TMP7HUM6DWP5DUS4TKP3";
         doc["CID"] = getID();
       }
       // Get the length of the JSON string we have created
       int len1 = measureJson(doc);
       // length of data sent by LoRaWAN MAC is 1 byte longer than the actual data so we need to add one and set the appDataSize variable for the MAC layer
       appDataSize = len1 + 1;//AppDataSize max value is 64 <TODO> check and work around data being too large
       // serialise the JSON string into the LoRaWAN appData variable for sending by the MAC Layer
       serializeJson(doc, appData, len1 + 1);
     }
 
 
     //downlink (RX) data handling function
     void downLinkDataHandle(McpsIndication_t *mcpsIndication)
     {
       // Print the received data frame parameters and data on the serial monitor
       Serial.printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n",mcpsIndication-RxSlot?"RXWIN2":"RXWIN1",mcpsIndication->BufferSize,mcpsIndication->Port);
       Serial.print("+REV DATA:");
       for(uint8_t i=0;i<mcpsIndication->BufferSize;i++)
       {
         Serial.printf("%02X",mcpsIndication->Buffer[i]);
       }
       Serial.println();
       // Print the char version of the data to the serial monitor
       if(DEBUG){
         for(uint8_t i=0;i<mcpsIndication->BufferSize;i++)
         {
           Serial.print((char)mcpsIndication->Buffer[i]);
         }
         Serial.println();
       }
       // Port 8 is used for configuration of the device - expects a propoerly formed JSON string as the data
       if(mcpsIndication->Port == 8){
         // Create a 100 byte JSON document holder on the stack and deserialise the received data from the buffer to the doc
         StaticJsonDocument<100> jsonparse;
         DeserializationError error = deserializeJson(jsonparse, mcpsIndication->Buffer);
         // If deserialisation fails (not properly formed, too long or corrupted) print an error message to serial monitor 
         if (error) {
           Serial.print(F("deserializeJson() failed: "));
           Serial.println(error.c_str());
           return;
         }
         // If we have a properly formed JSON string, then we can check for config commands
         // SUP changes the enabled variable - which sets which measurement data the node will transmit
         // To turn off all values except battery voltage and the supported type / chip ID send 255
         // To turn on all measurement values and turn off the reporting of supported types / chip ID send 0
         // Each measurement value can be individually turned on by setting its bit in enabled to 0 (except SUP / chip ID which must be set to 1)
         if(jsonparse.containsKey("SUP")){
           // Turn on external peripherals
           pinMode(Vext, OUTPUT);
           digitalWrite(Vext, LOW);
           delay(500);
           // Initialise I2C Bus
           i2cinit();
           delay(10);
           // Get the value of SUP and set the value of enabled
           enabled = jsonparse["SUP"];
           if(DEBUG == 2){
             Serial.println(enabled);
             Serial.print("I2C Clock ");
             Serial.println(Wire.getClock());
           }
           // Write the new value of enabled to EEPROM (addr 24)
           eep.update(24, enabled);
           delay(10);
           if(DEBUG == 2){
             Serial.println(eep.read(24));
             delay(100);
           }
           // Stop the I2C Bus
           Wire.end();
           delay(100);
           // Turn off power to external peripherals
           digitalWrite(Vext, HIGH);
           return;
         }
         // SLP changes the time the device sleeps between measurements - expects a float representing minutes
         if(jsonparse.containsKey("SLP")){
           // Turn on external peripherals
           pinMode(Vext, OUTPUT);
           digitalWrite(Vext, LOW);
           delay(500);
           // Initialise I2C Bus
           i2cinit();
           delay(10);
           // copy the value in seconds to a tmp variable
           float sleeptime = jsonparse["SLP"];
           if(DEBUG == 2){
             Serial.println(round((255-log(sleeptime))*23));
           }
           // Write an integer representing the duty cycle to EEPROM - note that the nearest integer is used, so only certain values
           // of duty cycle are actually available. Distance between available values increases logarithmically, so there is fine adjustment for minutes
           // up to a few hours and then moderate to very course adjustment for many hours to days. The equation for the stored value to minutes is:
           // <mins> = e^((255-<stored value>)/23)
           // when a value is sent the following equation is used to calculate the stored uint8:
           // <stored value> = 255-(ln(<mins>)*23)
           // note that the duty cycle is still slightly random as there is processing time and a random variable subtracted
           // from the duty cyle to minimise collisions over time between nodes
           eep.update(27, round(255-(log(sleeptime)*23)));
           delay(10);
           // calculate the new duty cycle from the written value 
           appTxDutyCycle = uint32_t(exp(((255 - eep.read(27))/23.0f))*1000*60);
           delay(10);
           // Stop the I2C Bus
           Wire.end();
           delay(100);
           // Turn off power to external peripherals
           digitalWrite(Vext, HIGH);
           return;
         }
         // TKP changes the stored empty and full values for the calculation of tank fill percentage
         // TKP expects the JSON string to contain 2 sub keys FULL and EMPTY. Note that because the 
         // ultrasonic sensor is measuring a distance from the top of the tank the value for FULL
         // should be less than the value for EMPTY
         if(jsonparse.containsKey("TKP")){
           // Turn on external peripherals
           pinMode(Vext, OUTPUT);
           digitalWrite(Vext, LOW);
           delay(500);
           // Initialise I2C Bus
           i2cinit();
           delay(10);
           // Set the full and empty variables directly
           full = jsonparse["TKP"]["FULL"];
           empty = jsonparse["TKP"]["EMPTY"];
           if(DEBUG == 2){
             Serial.print("I2C Clock ");
             Serial.println(Wire.getClock());
           }
           // Write the full value to EEPROM (addr 25)
           eep.update(25, full / 2);
           delay(10);
           if(DEBUG == 2){
             Serial.print(eep.read(25));
             delay(100);
           }
           // Write the empty value to EEPROM (addr 26)
           eep.update(26, empty / 2);
           delay(10);
           if(DEBUG == 2){
             Serial.println(eep.read(26));
             delay(100);
           }
           // Stop the I2C Bus
           Wire.end();
           delay(100);
           // Turn off external peripherals
           digitalWrite(Vext, HIGH);
           return;
         }
         // SET allows the devEUI and AppKey to be set remotely - note that this is dangerous and you will lose your device util
         // it is re-added to the network under the new devEUI and AppKey. In future this feature may be disabled or require also
         // sending a unique key that would be stored at the end of the EEPROM in each device. For now each device
         // will come with an unwritten EEPROM which means all addresses will be all Fs you can setup a "commissioning" 
         // device in the application and then remotely commission each device one by one using this feature - use with caution
         // expects 2 sub keys: "DEVEUI" (16 HEX chars) and "APPKEY" (32 HEX chars)
         if(jsonparse.containsKey("SET")){
           // Turn on external peripherals
           pinMode(Vext, OUTPUT);
           digitalWrite(Vext, LOW);
           delay(500);
           // Initialise the I2C Bus
           i2cinit();
           delay(100);
           // parse the JSON strings to local character arrays
           const char* deui = jsonparse["SET"]["DEVEUI"];
           const char* appk = jsonparse["SET"]["APPKEY"];
           // Print new devEUI to Serial Monitor
           Serial.print("New DevEUI: ");
           Serial.println(deui);
           Serial.print("Writing DevEUI to EEPROM");
           // step through each pair of HEX characters, convert them to a single uint8 and write to EEPROM (addr 0-7)
           for (int x = 0; x < 8; x++){
             char a = deui[2*x];
             char b = deui[(2*x)+1];
             eep.update(x, hexpairtouint8(a,b));
             // Also immediately update the devEUI and appEUI
             devEui[x] = hexpairtouint8(a,b);
             appEui[x] = devEui[x]; 
             delay(100);
             Serial.print(".");
             if(DEBUG == 2){
               Serial.print(eep.read(x));
               delay(100);
             }
           }
           Serial.println(" Complete");
           // Print new AppKey to Serial Monitor
           Serial.print("New AppKey: ");
           Serial.println(appk);
           Serial.println("Writing AppKey to EEPROM");
           // step through each pair of HEX characters, convert them to a single uint8 and write to EEPROM (addr 8-23)
           for (int x = 0; x < 16; x++){
             char a = appk[2*x];
             char b = appk[(2*x)+1];
             eep.update(x+8, hexpairtouint8(a,b));
             // Also immediately update the AppKey
             appKey[x] = hexpairtouint8(a,b);
             delay(100);
             Serial.print(".");
             if(DEBUG == 2){
               Serial.print(eep.read(x+8));
               delay(100);
             }
           }
           Serial.println(" Complete");
           delay(100);
           // Stop the I2C Bus
           Wire.end();
           delay(1000);
           // Turn off external peripherals
           digitalWrite(Vext, HIGH);
           Serial.println("Rebooting");
           delay(5000);
           // Reboot the device
           CySoftwareReset();
           return;
         }
       }
     }
 
     // Used to setup the device when it is powered up or reset
     void setup() {
       // Turn on external peripherals
       pinMode(Vext, OUTPUT);
       digitalWrite(Vext, LOW);
       delay(500);
       // Initialise the Serial port and set to 115200 baud
     	Serial.begin(115200);
       // Initialise the I2C Bus
       i2cinit();
       // Get the chip ID and write it to the serial monitor
       uint64_t chipID=getID();
       Serial.printf("ChipID:%04X%08X\r\n",(uint32_t)(chipID>>32),(uint32_t)chipID);
       // Read the devEUI / appEUI from EEPROM (addr 0-7) and put them in memory for use 
       for (int x = 0; x < 8; x++){
         devEui[x] = eep.read(x);
         appEui[x] = devEui[x];
         delay(20); 
       }
       // Read the appKey from EEPROM (addr 8-23) and put it in memory for use
       for (int x = 8; x < 24; x++){
         appKey[x-8] = eep.read(x);
         delay(20); 
       }
       // Read from EEPROM (addr 24) which measurements are enabled for output
       enabled = eep.read(24);
       delay(20);
       // Read from EEPROM (addr 25-26) the values for a full and empty tank
       full = (eep.read(25) * 2);
       delay(20);
       empty = (eep.read(26) * 2);
       delay(20);
       // Read from EEPROM (addr 27) the stored duty cylce for measurement and transmission
       appTxDutyCycle = uint32_t(exp(((255 - eep.read(27))/23.0f))*1000*60);
       Serial.print("Sleep time between cycles (ms) ");
       Serial.println(appTxDutyCycle);
       delay(20);
       // Setup the onboard MPU and take a reading
       setup_MPU6050();
       sensors_event_t a, g, temp;
       mpu.getEvent(&a, &g, &temp);
     #if(AT_SUPPORT)
     	enableAt();
     #endif
       // Set the device LoRaWAN state machine to the initialise state and run ifskipjoin to check if join
       // should be completed or not and change state if required
     	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;
     		}
     	}
     }

Como le hizo para que la librería de Adafruit_MPU6050.funcione para el cubecell, la he instalado pero me lanza un error diciendo que no existe

¿Puedes darme más información? ¿Cuál es el mensaje de error que recibe y en qué etapa de la instalación o compilación recibe el mensaje de error?

Algunas capturas de pantalla pueden ayudar

por ejemplo tengo la librería FHT y algunas mas de adafruit
pero solo ejecutando el programa sin tener nada de código sino que simplemente importo la librería me lanza error diciendo que no esta en el directorio algún otro archivo que necesito para ejecutarse.

image

estarán bien colocadas ahí las librerías?

El error que está recibiendo es que no puede encontrar “avr/progmem.h”. La biblioteca que está importando debe usar PROGMEM, que no está disponible en los dispositivos Heltec que no se basan en AVR. Deberá modificar la biblioteca o buscar otra biblioteca que no use PROGMEM