KeHoSoftware
Published © GPL3+

M5Stack COM. LoRaWAN Using Arduino IDE

M5Stack recently released an updated LoRaWAN module. This tutorial teaches you how to connect it to The Things Network using Arduino IDE.

AdvancedFull instructions provided3 hours4,733
M5Stack COM. LoRaWAN Using Arduino IDE

Things used in this project

Story

Read more

Schematics

M5Stack Core TTN SensorNode MOV Video

M5Stack Core with TTN connection and how to mount sensors with LEGO

Code

M5CORE1_TTN_V3_SensorNode_V1_08.ino

Arduino
main source code (2022 TTN V3 console)
/****************************************************************************
**                                                                         **
** Name:        M5CORE1_TTN_V3_SensorNode.ino                              **
** Author:      Achim Kern                                                 **
** Interpreter: Arduino IDE 1.8.19                                         **
** Licence:     Freeware                                                   **
** Function:    Main Program                                               **
**                                                                         **
** Notes:       based on idea from SEEED STUDIO and LCARS SmartHome        **
**                                                                         **
** History:                                                                **
**                                                                         **
** 1.00        - 24.01.2021 - initial release                              **
**                          - TTN joined                                   **
** 1.01        - 25.01.2021 - ENVII unit implemented                       **                
**                          - NeoPixel implemented                         **
**                          - battery level implemented                    **                          
**                          - TTN payload defined                          **                          
**                          - PIR Motion sensor - display on/off           **                          
**                          - sensor data on screen display                **
** 1.02        - 26.01.2021 - show jpg pictures on booting                 **                          
** 1.03        - 27.01.2021 - TTN access codes                             **
**                          - application name as const char*              **
** 1.04        - 20.03.2021 - device now running under TTN cconsole v3     **
**                          - TTN OTAA acount with *char predifined        **
** 1.05        - 02.01.2022 - new COM.X.LORAWAN Modul                      **                          
**                          - no SERIAL init (compiled with ESP32 system   **
**                          - motion now as TTN sensor node data entry     **                        
** 1.06        - 12.01.2022 - motion counter set to zero after upload      **                          
** 1.07        - 13.01.2022 - payload changed - smaller and neg. temp      ** 
**                          - TTN V3 Uplink decoder docu in source         **
** 1.08        - 02.02.2022 - ENVIII unit implemented                      **
**                          - m5stack variables                            **
**                          - room screen name                             **                                              
**                                                                         **
****************************************************************************/

/*
 * Application and Version
 */
   const char* application  = "M5CORE1_TTN_V3_SensorNode";
   const char* aktu_version = "1.08";
   const char* room_screen  = "M5CORE1-NODE3";

/*
 * M5 STACK TFT Display
 * 
 */
   // we need these libraries, defines, variables
   #include <M5Stack.h>
   // we use special fonts
   #include "Free_Fonts.h"
   // tft backlight - on/off button 1 - on/off after 1 minute
   bool tft_backlight = true; 
   // screen off counter 
   int tft_counter=0;
   // pictures on the sd card
   String iot_picture="";

/*
 * M5 STACK RGB NeoPixels
 * 
 */
   // we need these libraries, defines, variables   
   #include <Adafruit_NeoPixel.h>
   #define M5STACK_FIRE_NEO_NUM_LEDS 10
   #define M5STACK_FIRE_NEO_DATA_PIN 15
   Adafruit_NeoPixel pixels = Adafruit_NeoPixel(M5STACK_FIRE_NEO_NUM_LEDS, M5STACK_FIRE_NEO_DATA_PIN, NEO_GRB + NEO_KHZ800);   

/*
 * ENVII M5Stack Unit I2C Pressure & Temperature & Humidity Sensor
 * ---------------------------------------------------------------
 * ENV II is an environment sensor which can sense temperature, humidity and atmospheric pressure. 
 * It is built with SHT30 and BMP280 sensors and is programmed over I2C. 
 * SHT30 is a digital temperature and humidity sensor with high precision and low power consumption. 
 * BMP280 is an absolute barometric pressure sensor which is especially designed for mobile applications. 
 * It offers the highest flexibility to optimize the device regarding power consumption, resolution and filter performance.
 * 
 */
   // Enable/disable sensor measurements if you want to
   // #define ENABLE_SENSOR_ENVII
   // Sensors enabled, but not found in the hardware will be ignored
   #ifdef ENABLE_SENSOR_ENVII
     #include <M5Stack.h>
     #include <Wire.h>
     #include "Adafruit_Sensor.h"
     #include <Adafruit_BMP280.h>
     #include "SHT3X.h"
     SHT3X sht30;
     Adafruit_BMP280 bme;
     float env2_tmp = 0.0;
     float env2_hum = 0.0;
     float env2_pressure = 0.0;
     /*-----------------------------------------*/
     /* Function void sensor_env2()             */
     /*                                         */
     /* TASK    : read out env2 sensor data     */
     /* UPDATE  : 04.11.2020                    */
     /*-----------------------------------------*/   
     void sensor_env2(void)
     {
       // read the sensor
       env2_pressure = bme.readPressure();
       env2_pressure = env2_pressure/100;
       if(sht30.get()==0)
       {
         env2_tmp = sht30.cTemp-2;
         env2_hum = sht30.humidity+3;
       }   
     }     
   #endif

/*
 * ENVIII M5Stack Unit I2C Pressure & Temperature & Humidity Sensor
 * ---------------------------------------------------------------
 * ENV III is an environmental sensor that integrates SHT30 and QMP6988 internally to detect temperature, 
 * humidity, and atmospheric pressure data. SHT30 is a high-precision and low-power digital temperature 
 * and humidity sensor, and supports I2C interface (SHT30:0x44 , QMP6988:0x70).
 * QMP6988 is an absolute air pressure sensor specially designed for mobile applications, 
 * with high accuracy and stability, suitable for environmental data collection and detection types of projects.
 * 
 */
   // Enable/disable sensor measurements if you want to
   #define ENABLE_SENSOR_ENVIII
   // Sensors enabled, but not found in the hardware will be ignored
   #ifdef ENABLE_SENSOR_ENVIII
     #include <M5Stack.h>
     #include "UNIT_ENV.h"
     SHT3X sht30;
     QMP6988 qmp6988;
     float env3_tmp = 0.0;
     float env3_hum = 0.0;
     float env3_pressure = 0.0;
     /*-----------------------------------------*/
     /* Function void sensor_env3()             */
     /*                                         */
     /* TASK    : read out env3 sensor data     */
     /* UPDATE  : 02.02.2022                    */
     /*-----------------------------------------*/   
     void sensor_env3(void)
     {
       // read the sensor
       env3_pressure = qmp6988.calcPressure();
       env3_pressure = env3_pressure/100;
       if(sht30.get()==0)
       {
         env3_tmp = sht30.cTemp-2;
         env3_hum = sht30.humidity+3;
       }   
     }     
   #endif   

/*
 * GROVE UNIT PIR Motion Sensor
 * ----------------------------
 * This sensor allows you to sense motion, usually human movement in its range. Simply connect it and program it, 
 * when anyone moves in its detecting range, the sensor will output HIGH on its SIG pin.
 *
 */
   // Enable/disable sensor measurements if you want to
   #define ENABLE_SENSOR_PIR_MOTION
   // Sensors enabled, but not found in the hardware will be ignored
   #ifdef ENABLE_SENSOR_PIR_MOTION
     #define PIR_MOTION_SENSOR 36 
     bool MOTION=false;
     int MOTION_counter=0;
   #endif

/*
 * connected sensor data place holders
 */
   // m5stack-core-01
   #define M5STACK 0
   float m5stack_temp  = 0;
   float m5stack_humi  = 0;
   float m5stack_press = 0;
   int m5stack_bat     = 0;

/*   
 * TTN OTAA access data 
 */
   // (OTAA Mode)
   // we got this from the TTN console - so we have to set on our chip
   // TTN CONSOLE V3
   // Node xx
   char* DevEui="xxxxxxxxxxxxxx";
   
   // (OTAA Mode)
   // we got this from the TTN console - so we have to set on our chip
   // TTN CONSOLE V3
   char* AppEui="xxxxxxxxxxxxxx";   
   
   // (OTAA Mode)
   // we got this from the TTN console - so we have to set on our chip
   // TTN CONSOLE V3
   // Node xx
   char* AppKey="xxxxxxxxxxxxxx";
  
   // ttn counter send frequence
   int TTNCounter=0;
      
/*
 * Generally, you should use "unsigned long" for variables that hold time
 * The value will quickly become too large for an int to store
 */
   // this timer is used to update tft display and mqtt data send frequence
   unsigned long previousMillis = 0;
   // every 10 minutes
   // unsigned long interval = 600000;  
   // every 3 minutes
   // unsigned long interval = 180000;
   // every 30 seconds
   unsigned long interval = 30000;   
   unsigned long counter  = 0;

/*-------------------------------------------------------------------------------*/
/* Function void ATCommand(char cmd[],char date[], uint32_t timeout = 50)        */
/*                                                                               */
/* TASK    : send AT commands to the M5Stack COM.LoRaWAN Module                  */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void ATCommand(char cmd[],char date[], uint32_t timeout = 50)
{
  char buf[256] = {0};
  if(date == NULL)
  {
    sprintf(buf,"AT+%s",cmd);
  }
  else 
  {
    sprintf(buf,"AT+%s=%s",cmd,date); 
  }
  Serial2.write(buf);
  delay(200);
  ReceiveAT(timeout);
}

/*-------------------------------------------------------------------------------*/
/* Function bool ReceiveAT(uint32_t timeout)                                     */
/*                                                                               */
/* TASK    : receive AT msg's from the M5Stack COM.LoRaWAN Module                */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
bool ReceiveAT(uint32_t timeout)
{
  uint32_t nowtime = millis();
  while(millis() - nowtime < timeout){
    if (Serial2.available() !=0) {
      String str = Serial2.readString();
      if (str.indexOf("+OK") != -1 || str.indexOf("+ERROR") != -1) {
        Serial.println(str);
        return true;
      }else {
        Serial.println("[!] Syntax Error");
        break;
      }
    }
  }
  Serial.println("[!] Timeout");
  return false;
}

/*-------------------------------------------------------------------------------*/
/* Function void rgb_neopixel(String color)                                      */
/*                                                                               */
/* TASK    : show rgb neopixels (co2 ampel)                                      */
/* UPDATE  : 07.10.2020                                                          */
/*-------------------------------------------------------------------------------*/
void rgb_neopixel(int r,int g,int b)  
{
  // right side
  if (tft_backlight == true)
  {
    pixels.setPixelColor(0, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(1, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(2, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(3, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(4, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    // left side
    pixels.setPixelColor(5, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(6, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(7, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(8, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(9, pixels.Color(r,g,b));
    pixels.show(); delay(200);
  }  
}

/*-------------------------------------------------------------------------------*/
/* Function void rgb_neopixel_on(String color)                                   */
/*                                                                               */
/* TASK    : show rgb neopixels immediately                                      */
/* UPDATE  : 07.10.2020                                                          */
/*-------------------------------------------------------------------------------*/
void rgb_neopixel_on(int r,int g,int b)  
{
  // right side
  pixels.setPixelColor(0, pixels.Color(r,g,b));
  pixels.setPixelColor(1, pixels.Color(r,g,b));
  pixels.setPixelColor(2, pixels.Color(r,g,b));
  pixels.setPixelColor(3, pixels.Color(r,g,b));
  pixels.setPixelColor(4, pixels.Color(r,g,b));
  // left side
  pixels.setPixelColor(5, pixels.Color(r,g,b));
  pixels.setPixelColor(6, pixels.Color(r,g,b));
  pixels.setPixelColor(7, pixels.Color(r,g,b));
  pixels.setPixelColor(8, pixels.Color(r,g,b));
  pixels.setPixelColor(9, pixels.Color(r,g,b));
  pixels.show(); 
}

/*-------------------------------------------------------------------------------*/
/* Function void rgb_neopixel_off()                                              */
/*                                                                               */
/* TASK    : rgb neopixels off                                                   */
/* UPDATE  : 18.11.2020                                                          */
/*-------------------------------------------------------------------------------*/
void rgb_neopixel_off()  
{
  // right side
  pixels.setPixelColor(0, pixels.Color(0,0,0));
  pixels.setPixelColor(1, pixels.Color(0,0,0));
  pixels.setPixelColor(2, pixels.Color(0,0,0));
  pixels.setPixelColor(3, pixels.Color(0,0,0));
  pixels.setPixelColor(4, pixels.Color(0,0,0));
  // left side
  pixels.setPixelColor(5, pixels.Color(0,0,0));
  pixels.setPixelColor(6, pixels.Color(0,0,0));
  pixels.setPixelColor(7, pixels.Color(0,0,0));
  pixels.setPixelColor(8, pixels.Color(0,0,0));
  pixels.setPixelColor(9, pixels.Color(0,0,0));
  pixels.show(); 
}

/*-------------------------------------------------------------------------------*/
/* Function void array_to_string(byte array[], unsigned int len, char buffer[])  */
/*                                                                               */
/* TASK    : build string out of payload data                                    */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void array_to_string(byte array[], unsigned int len, char buffer[])
{
  for (unsigned int i = 0; i < len; i++)
  {
    byte nib1 = (array[i] >> 4) & 0x0F;
    byte nib2 = (array[i] >> 0) & 0x0F;
    buffer[i*2+0] = nib1  < 0xA ? '0' + nib1  : 'A' + nib1  - 0xA;
    buffer[i*2+1] = nib2  < 0xA ? '0' + nib2  : 'A' + nib2  - 0xA;
  }
  buffer[len*2] = '\0';
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_room_screen(String room_name, long int room_bg)     */
/*                                                                               */
/* TASK    : show tft display room screen                                        */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_room_screen(String room_name, long int room_bg) 
{
  M5.Lcd.fillScreen(TFT_WHITE);
  M5.Lcd.fillRect(0,0,320,50,room_bg);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setTextColor(TFT_WHITE);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth(room_name)) / 2, 32);
  M5.Lcd.print(room_name); 
  // drawing verticle line
  M5.Lcd.drawFastVLine(150,50,190,TFT_DARKGREEN);
  // drawing horizontal line
  M5.Lcd.drawFastHLine(0,140,320,TFT_DARKGREEN);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_status_bar(String room_name, long int room_bg)      */
/*                                                                               */
/* TASK    : show tft display status bar                                         */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_status_bar(String room_name, long int room_bg) 
{
  M5.Lcd.fillRect(0,0,320,50,room_bg);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setTextColor(TFT_WHITE);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth(room_name)) / 2, 32);
  M5.Lcd.print(room_name); 
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_temperature(void)                            */
/*                                                                               */
/* TASK    : show tft display sensor temperature                                 */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_temperature(int temperature) 
{
  // setting the temperature
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Temperature",15,65);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(temperature,50,95);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("C",100,95);  
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_temperature(void)                            */
/*                                                                               */
/* TASK    : show tft display update temperature                                 */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_temperature(int temperature) 
{
  // setting the temperature
  M5.Lcd.fillRect(50,95,50,30,WHITE);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(temperature,50,95);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_humidity(int humidity)                       */
/*                                                                               */
/* TASK    : show tft display sensor humidity                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_humidity(int humidity) 
{
  // setting the humidity
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Humidity",30,160);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(humidity,50,190);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("%",100,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_humidity(void)                               */
/*                                                                               */
/* TASK    : show tft display update humidity                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_humidity(int humidity) 
{
  // setting the humidity
  M5.Lcd.fillRect(50,190,50,30,TFT_WHITE);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(humidity,50,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_pressure(int pressure)                       */
/*                                                                               */
/* TASK    : show tft display sensor pressure                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_pressure(int pressure) 
{
  // setting the pressure
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Pressure",190,65);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(pressure,160,95);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("mBar",250,95);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_pressure(void)                               */
/*                                                                               */
/* TASK    : show tft display update pressure                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_pressure(int pressure) 
{
  // setting the pressure
  M5.Lcd.fillRect(160,95,85,30,TFT_WHITE);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(pressure,160,95);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_battery(int battery)                         */
/*                                                                               */
/* TASK    : show tft display sensor battery                                     */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_battery(int battery) 
{ 
  // setting the battery power
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Battery",200,160);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(battery,200,190);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("%",280,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_battery(int battery)                         */
/*                                                                               */
/* TASK    : show tft display update heating                                     */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_battery(int battery) 
{
  // setting the battery
  M5.Lcd.fillRect(160,190,105,30,TFT_WHITE);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(battery,200,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_m5stack(void)                                       */
/*                                                                               */
/* TASK    : show tft display m5stack (this m5stack)                             */
/* UPDATE  : 10.12.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_m5stack(void) 
{
  // display room screen
  tft_display_room_screen(room_screen,BLUE); 
  // display temperature sensor
  tft_display_sensor_temperature(m5stack_temp);
  // display humidity sensor
  tft_display_sensor_humidity(m5stack_humi); 
  // display pressure sensor
  tft_display_sensor_pressure(m5stack_press); 
  // display battery sensor
  tft_display_sensor_battery(m5stack_bat);
}

/*-------------------------------------------------------------------------------*/
/* Function void send_to_TTN(void)                                               */
/*                                                                               */
/* TASK    : send sensor data to TTN                                             */
/* UPDATE  : 25.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void send_to_TTN(void) 
{  
  // show picture
  iot_picture="/ttn.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
  
  // neopixels red
  rgb_neopixel(255,0,0);

  // activate communication
  Serial.println(F("[!] LoraSet=?")); 
  ATCommand("LoraSet", "?");
  delay(500);
  
  Serial.println(F(" "));
  Serial.print(F(application)); Serial.print(F(" Version ")); Serial.println(F(aktu_version));
  Serial.println(F(" "));

  // check if we can access battery functions
  if(!M5.Power.canControl())
  {
    Serial.println(F("[!] No communication with IP5306 chip"));
  }

  // actual battery level
  uint8_t bat = M5.Power.getBatteryLevel();
  Serial.print(F("[?] M5STACK BATT LEVEL  --> "));
  Serial.print(bat);
  Serial.println(F(" %"));
  m5stack_bat=bat;
  int32_t battery_int = bat * 100; 
    
  #ifdef ENABLE_SENSOR_ENVII     
    sensor_env2();
    m5stack_temp=env2_tmp;
    m5stack_humi=env2_hum;
    m5stack_press=env2_pressure;
    Serial.print(F("[?] M5STACK UNIT ENVII  --> "));
    Serial.print("ENVII-P:"); Serial.print(env2_pressure); 
    Serial.print("  ENVII-T:"); Serial.print(env2_tmp);  
    Serial.print("  ENVII-H:"); Serial.println(env2_hum);                 
  #endif

  #ifdef ENABLE_SENSOR_ENVIII     
    sensor_env3();
    m5stack_temp=env3_tmp;
    m5stack_humi=env3_hum;
    m5stack_press=env3_pressure;
    Serial.print(F("[?] M5STACK UNIT ENVIII --> "));
    Serial.print("ENVIII-P:"); Serial.print(env3_pressure); 
    Serial.print("  ENVIII-T:"); Serial.print(env3_tmp);  
    Serial.print("  ENVIII-H:"); Serial.println(env3_hum);                 
  #endif  

  /* TTN V3 payload Uplink decoder
   *
   * 
   
   function Decoder(bytes, port) 
   {
      var tmp     = (bytes[0]<<8 | bytes[1]);
      var pre     = (bytes[2]<<8 | bytes[3]);
      var hum     = (bytes[4]);
      var battery = (bytes[5]);
      var motion  = (bytes[6]);
  
      var decoded = {};
      decoded.temp     = (tmp-5000)/100;
      decoded.pressure = pre/10;
      decoded.hum      = hum/2;
      decoded.battery  = battery;
      decoded.motion   = motion;
 
      return decoded;
    }

  *
  *
  */
 

  /* new payload - smaller - and better data */

  int  tmp = ((int)(m5stack_temp * 100))+5000;
  int  pre = (int)(m5stack_press * 10);
  byte hum = (int)(m5stack_humi * 2);

  byte payload[7];

  payload[0] = tmp >> 8;
  payload[1] = tmp;
  
  payload[2] = pre >> 8;
  payload[3] = pre;
  
  payload[4] = hum;
  
  payload[5] = bat;
  payload[6] = MOTION_counter;

  Serial.print(F("[x] actual TTN payload  --> "));
  char str[32] = "";
  array_to_string(payload, 7, str);
  Serial.println(str);

  // now send all to TTN
  ATCommand("SendHex", str); 
  // neopixels now off
  rgb_neopixel_off();
  // motion counter reset
  MOTION_counter=0;  
  // display sensor data
  tft_display_m5stack();       
}

/*-------------------------------------------------------------------------------*/
/* Function void setup()                                                         */
/*                                                                               */
/* TASK    : setup all needed requirements                                       */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void setup() 
{
  // initialize the M5Stack object
  M5.begin();

  /*
    Power chip connected to gpio21, gpio22, I2C device
    Set battery charging voltage and current
    If used battery, please call this function in your project
  */
  M5.Power.begin();

  // open serial monitor
  // Serial.begin(115200);
  
  // activate the NeoPixels
  pixels.begin();
  rgb_neopixel(0,0,0);

  // boot application
  delay(3000);
  Serial.println(F(" "));
  Serial.println(F(" "));
  Serial.println(F("Starting..."));
  Serial.print(F(application)); Serial.print(F(" Version ")); Serial.println(F(aktu_version));
  Serial.println(F("connected via TTN Stuttgart"));
  Serial.println(F(" ")); 

  M5.Lcd.fillScreen(TFT_RED);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.setTextColor(TFT_WHITE);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth(room_screen)) / 2, 100);
  M5.Lcd.print(room_screen);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("TTN-V3 SensorNode")) / 2, 120);
  M5.Lcd.print("TTN-V3 SensorNode");
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("Version x.xx")) / 2, 140);
  M5.Lcd.print("Version ");
  M5.Lcd.print(aktu_version);
  delay(6000);

  // SD card
  M5.Lcd.fillScreen(TFT_NAVY);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.setTextColor(TFT_YELLOW);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("SD card initialize..")) / 2, 120);
  M5.Lcd.print("SD card initialize..");
  delay(2000);
  // check if we have a sd card inserted
  if (!SD.begin()) 
  {
    Serial.println("[!] SD Card failed, or not present");
    while (1);
  }
  Serial.println("[x] SD Card initialized");

  // Lcd display 
  M5.Lcd.setBrightness(255); 

  // show iot picture
  iot_picture="/iot.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
  delay(2000);

  // activate the FIRE NeoPixels blue
  rgb_neopixel(0,0,255);

  // actual battery level
  uint8_t bat = M5.Power.getBatteryLevel();
  Serial.print(F("[?] M5STACK BATT LEVEL  --> "));
  Serial.print(bat);
  Serial.println(F(" %"));
  m5stack_bat=bat;  

  #ifdef ENABLE_SENSOR_ENVII
    // show picture
    iot_picture="/unit_env2.jpg";
    M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
    delay(2000);  
    Wire.begin();
    while (!bme.begin(0x76))
    {
      Serial.println(F("[!] Could not find a valid BMP280 sensor, check wiring!"));
    }
    Serial.println(F("[x] M5STACK UNIT ENVII Sensor detected"));
    // read the env2 sensor */
    sensor_env2();
    m5stack_temp=env2_tmp;
    m5stack_humi=env2_hum;
    m5stack_press=env2_pressure;
    Serial.print(F("[?] M5STACK UNIT ENVII  --> "));
    Serial.print("ENVII-P:"); Serial.print(env2_pressure); 
    Serial.print("  ENVII-T:"); Serial.print(env2_tmp);  
    Serial.print("  ENVII-H:"); Serial.println(env2_hum);  
  #endif

  #ifdef ENABLE_SENSOR_ENVIII
    // show picture
    iot_picture="/unit_env3.jpg";
    M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
    delay(2000);  
    Wire.begin();
    qmp6988.init();
    Serial.println(F("[x] M5STACK UNIT ENVIII Sensor detected"));
    // read the env3 sensor */
    sensor_env3();
    m5stack_temp=env3_tmp;
    m5stack_humi=env3_hum;
    m5stack_press=env3_pressure;
    Serial.print(F("[?] M5STACK UNIT ENVIII --> "));
    Serial.print("ENVIII-P:"); Serial.print(env3_pressure); 
    Serial.print("  ENVIII-T:"); Serial.print(env3_tmp);  
    Serial.print("  ENVIII-H:"); Serial.println(env3_hum);  
  #endif  

  #ifdef ENABLE_SENSOR_PIR_MOTION
    // show picture
    iot_picture="/unit_pir.jpg";
    M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
    delay(2000);   
    pinMode(PIR_MOTION_SENSOR, INPUT);
    Serial.println(F("[x] M5STACK UNIT PIR Motion Sensor detected"));
  #endif   
    
  // now connect to the M%Stack COM.LoRaWAN module
  // TX 0/3/17
  // RX 5/15/16
  // Before you connect the module to your M5Stack device, make sure you set the TXD/RXD dip switches correctly. 
  // If you use the grey or basic and have nothing else connected, the default UART pin configuration 16/17 is fine. 
  // For the Fire you should use 13/5, as all other settings can interfere with internals of the Fire.
  //   
  // Serial2.begin(115200, SERIAL_8N1, 15, 13);
  Serial2.begin(115200, SERIAL_8N1, 16, 17);
  // show picture
  iot_picture="/comx_lorawan.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());

  // first run - we have to get and programm some parameters 
  
  ATCommand("LORAWAN", "?");
  delay(500);
  ATCommand("LORAWAN", "1");
  delay(500);

  // your TTN access data
  ATCommand("DevEui", DevEui);
  delay(500);
  // always the same for all devices
  ATCommand("AppEui", AppEui);
  delay(500);
  ATCommand("AppKey", AppKey);
  delay(500);

  Serial.println("Join=1");
  ATCommand("Join", "1");
  // show picture
  iot_picture="/ttn.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
  delay(2000);   
 
  // neopixels now off
  rgb_neopixel_off();

  // display sensor data
  tft_display_m5stack();   
}

/*-------------------------------------------------------------------------------*/
/* Function void loop()                                                          */
/*                                                                               */
/* TASK    : this runs forever                                                   */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void loop()
{ 
  // check if some one has pressed a button
  if (M5.BtnA.wasPressed()) 
  {
    Serial.println("[x] Button A was pressed - Display ON/OFF");
    tft_backlight = !tft_backlight;   
    // Turning off the LCD backlight
    if (tft_backlight == false) { rgb_neopixel_off(); M5.Lcd.sleep();  M5.Lcd.setBrightness(0); }
    // Turning on the LCD backlight
    if (tft_backlight == true)  { M5.Lcd.wakeup(); M5.Lcd.setBrightness(255); }
    delay(200);
  }

  // check if some one has pressed a button
  if (M5.BtnB.wasPressed()) 
  {
    Serial.println("[x] Button B was pressed."); 
    delay(200);  
  }

  // check if some one has pressed a button
  if (M5.BtnC.wasPressed()) 
  {
    Serial.println("[x] Button C was pressed - Send to TTN");
    // Turning on the LCD backlight
    tft_backlight = true;
    if (tft_backlight == true)  { M5.Lcd.wakeup(); M5.Lcd.setBrightness(255); }
    delay(200);     
    send_to_TTN();   
    delay(200);   
  }

  /*
   * If we have an enabled PIR Motion Sensor we will send immediately
   * a message to the LoRaWan Gateway if we have detected an intruder
   */ 
  #ifdef ENABLE_SENSOR_PIR_MOTION
    // read the motion sensor
    // only if display is dark
    if (tft_backlight == false)
    {
      int sensorValue = digitalRead(PIR_MOTION_SENSOR);
      // if the sensor value is HIGH we have an intruder ?
      if(sensorValue == HIGH)       
      { 
        if (MOTION == false)
        {
          // digitalWrite(LED, HIGH);
          MOTION=true;
          Serial.println("[x] PIR MOTION detected ..."); 
          // M5.Speaker.tone(661, 20);
          MOTION_counter=MOTION_counter+1;
          tft_backlight = true;  
          if (tft_backlight == true)  { tft_counter=0; M5.Lcd.wakeup(); M5.Lcd.setBrightness(255); }        
        }     
      }
      // if the sensor value is HIGH we have an intruder ?
      if(sensorValue == LOW)       
      { 
        // digitalWrite(LED, LOW);
        MOTION=false;   
      }
    }     
  #endif
  
  /* 
   * It is checked whether the time for the transmission interval has already expired
   * If the time difference between the last save and the current time is greater
   * as the interval, the following function is executed.
  */
  if (millis() - previousMillis > interval)
  {
    // correct timer
    previousMillis = millis();

    
    // shall we now publish (10 minutes)
    TTNCounter++;
    if (TTNCounter==20)
    {
      send_to_TTN();
      TTNCounter=0; 
    }
    
    // tft got to sleep after 1 minute
    tft_counter++;
    if (tft_counter==3) 
    {
      if (tft_backlight == true) { tft_backlight=false; }   
      // Turning off the LCD backlight
      if (tft_backlight == false) 
      {
        rgb_neopixel_off(); 
        M5.Lcd.sleep();  M5.Lcd.setBrightness(0);
        Serial.println(F("[x] sleeping mode ... "));
      }
      tft_counter=0;     
    }   
  }

  delay(100);  
  M5.update();
}

M5Stack_CORE_TTN_SensorNode_V1_03.ino

Arduino
main source code (2021 TTN V2 console)
/****************************************************************************
**                                                                         **
** Name:        M5_Stack_CORE_TTN_SensorNode.ino                           **
** Author:      Achim Kern                                                 **
** Interpreter: Arduino IDE 1.8.13                                         **
** Licence:     Freeware                                                   **
** Function:    Main Program                                               **
**                                                                         **
** Notes:       based on idea from SEEED STUDIO and LCARS SmartHome        **
**                                                                         **
** History:                                                                **
**                                                                         **
** 1.00        - 24.01.2021 - initial release                              **
**                          - TTN joined                                   **
** 1.01        - 25.01.2021 - ENVII unit implemented                       **                
**                          - NeoPixel implemented                         **
**                          - battery level implemented                    **                          
**                          - TTN payload defined                          **                          
**                          - PIR Motion sensor - display on/off           **                          
**                          - sensor data on screen display                **
** 1.02        - 26.01.2020 - show jpg pictures on booting                 **                          
** 1.03        - 27.01.2021 - TTN access codes                             **
**                                                                         **
*****************************************************************************

/*
 * Application and Version
 */
   const char* application  = "M5STACK_CORE_TTN_SensorNode";
   const char* aktu_version = "1.03";

/*
 * M5 STACK TFT Display
 * 
 */
   // we need these libraries, defines, variables
   #include <M5Stack.h>
   // we use special fonts
   #include "Free_Fonts.h"
   // tft backlight - on/off button 1 - on/off after 1 minute
   bool tft_backlight = true; 
   // screen off counter 
   int tft_counter=0;
   // pictures on the sd card
   String iot_picture="";

/*
 * M5 STACK RGB NeoPixels
 * 
 */
   // we need these libraries, defines, variables   
   #include <Adafruit_NeoPixel.h>
   #define M5STACK_FIRE_NEO_NUM_LEDS 10
   #define M5STACK_FIRE_NEO_DATA_PIN 15
   Adafruit_NeoPixel pixels = Adafruit_NeoPixel(M5STACK_FIRE_NEO_NUM_LEDS, M5STACK_FIRE_NEO_DATA_PIN, NEO_GRB + NEO_KHZ800);   

 /*
 * ENVII M5Stack Unit I2C Pressure & Temperature & Humidity Sensor
 * ---------------------------------------------------------------
 * ENV II is an environment sensor which can sense temperature, humidity and atmospheric pressure. 
 * It is built with SHT30 and BMP280 sensors and is programmed over I2C. 
 * SHT30 is a digital temperature and humidity sensor with high precision and low power consumption. 
 * BMP280 is an absolute barometric pressure sensor which is especially designed for mobile applications. 
 * It offers the highest flexibility to optimize the device regarding power consumption, resolution and filter performance.
 * 
 */
   // Enable/disable sensor measurements if you want to
   #define ENABLE_SENSOR_ENVII
   // Sensors enabled, but not found in the hardware will be ignored
   #ifdef ENABLE_SENSOR_ENVII
     #include <M5Stack.h>
     #include <Wire.h>
     #include "Adafruit_Sensor.h"
     #include <Adafruit_BMP280.h>
     #include "SHT3X.h"
     SHT3X sht30;
     Adafruit_BMP280 bme;
     float env2_tmp = 0.0;
     float env2_hum = 0.0;
     float env2_pressure = 0.0;
     /*-----------------------------------------*/
     /* Function void sensor_env2()             */
     /*                                         */
     /* TASK    : read out env2 sensor data     */
     /* UPDATE  : 04.11.2020                    */
     /*-----------------------------------------*/   
     void sensor_env2(void)
     {
       // read the sensor
       env2_pressure = bme.readPressure();
       env2_pressure = env2_pressure/100;
       if(sht30.get()==0)
       {
         env2_tmp = sht30.cTemp-1;
         env2_hum = sht30.humidity+5;
       }   
     }     
   #endif

/*
 * GROVE UNIT PIR Motion Sensor
 * ----------------------------
 * This sensor allows you to sense motion, usually human movement in its range. Simply connect it and program it, 
 * when anyone moves in its detecting range, the sensor will output HIGH on its SIG pin.
 *
 */
   // Enable/disable sensor measurements if you want to
   #define ENABLE_SENSOR_PIR_MOTION
   // Sensors enabled, but not found in the hardware will be ignored
   #ifdef ENABLE_SENSOR_PIR_MOTION
     #define PIR_MOTION_SENSOR 36 
     bool MOTION=false;
   #endif

/*
 * connected sensor data place holders
 */
   // m5stack-core-01
   #define M5STACK 0
   int m5stack_temp  = 0;
   int m5stack_humi  = 0;
   int m5stack_press = 0;
   int m5stack_bat   = 0;

/*   
 * TTN OTAA access data 
 * we must use this in the setup() 
 */
  // DevEui=XXXXXXXXXXXXXXXX(For OTAA Mode)
  // DevEui="XXXXXXXXXXXXXXXX";
   
  // AppEui=XXXXXXXXXXXXXXXX(For OTAA Mode)
  // always the same if equal devices
  // AppEui = "XXXXXXXXXXXXXXXX";
   
  // AppKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX(For OTAA Mode)
  // AppKey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 
   
   // ttn counter send frequence - used in loop()
   int TTNCounter=0;
      
/*
 * Generally, you should use "unsigned long" for variables that hold time
 * The value will quickly become too large for an int to store
 */
   // this timer is used to update tft display and mqtt data send frequence
   unsigned long previousMillis = 0;
   // every 10 minutes
   // unsigned long interval = 600000;  
   // every 3 minutes
   // unsigned long interval = 180000;
   // every 30 seconds
   unsigned long interval = 30000;   
   unsigned long counter  = 0;

/*-------------------------------------------------------------------------------*/
/* Function void ATCommand(char cmd[],char date[], uint32_t timeout = 50)        */
/*                                                                               */
/* TASK    : send AT commands to the M5Stack COM.LoRaWAN Module                  */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void ATCommand(char cmd[],char date[], uint32_t timeout = 50)
{
  char buf[256] = {0};
  if(date == NULL)
  {
    sprintf(buf,"AT+%s",cmd);
  }
  else 
  {
    sprintf(buf,"AT+%s=%s",cmd,date); 
  }
  Serial2.write(buf);
  delay(200);
  ReceiveAT(timeout);
}

/*-------------------------------------------------------------------------------*/
/* Function bool ReceiveAT(uint32_t timeout)                                     */
/*                                                                               */
/* TASK    : receive AT msg's from the M5Stack COM.LoRaWAN Module                */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
bool ReceiveAT(uint32_t timeout)
{
  uint32_t nowtime = millis();
  while(millis() - nowtime < timeout){
    if (Serial2.available() !=0) {
      String str = Serial2.readString();
      if (str.indexOf("+OK") != -1 || str.indexOf("+ERROR") != -1) {
        Serial.println(str);
        return true;
      }else {
        Serial.println("[!] Syntax Error");
        break;
      }
    }
  }
  Serial.println("[!] Timeout");
  return false;
}

/*-------------------------------------------------------------------------------*/
/* Function void rgb_neopixel(String color)                                      */
/*                                                                               */
/* TASK    : show rgb neopixels (co2 ampel)                                      */
/* UPDATE  : 07.10.2020                                                          */
/*-------------------------------------------------------------------------------*/
void rgb_neopixel(int r,int g,int b)  
{
  // right side
  if (tft_backlight == true)
  {
    pixels.setPixelColor(0, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(1, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(2, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(3, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(4, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    // left side
    pixels.setPixelColor(5, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(6, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(7, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(8, pixels.Color(r,g,b));
    pixels.show(); delay(200);
    pixels.setPixelColor(9, pixels.Color(r,g,b));
    pixels.show(); delay(200);
  }  
}

/*-------------------------------------------------------------------------------*/
/* Function void rgb_neopixel_on(String color)                                   */
/*                                                                               */
/* TASK    : show rgb neopixels immediately                                      */
/* UPDATE  : 07.10.2020                                                          */
/*-------------------------------------------------------------------------------*/
void rgb_neopixel_on(int r,int g,int b)  
{
  // right side
  pixels.setPixelColor(0, pixels.Color(r,g,b));
  pixels.setPixelColor(1, pixels.Color(r,g,b));
  pixels.setPixelColor(2, pixels.Color(r,g,b));
  pixels.setPixelColor(3, pixels.Color(r,g,b));
  pixels.setPixelColor(4, pixels.Color(r,g,b));
  // left side
  pixels.setPixelColor(5, pixels.Color(r,g,b));
  pixels.setPixelColor(6, pixels.Color(r,g,b));
  pixels.setPixelColor(7, pixels.Color(r,g,b));
  pixels.setPixelColor(8, pixels.Color(r,g,b));
  pixels.setPixelColor(9, pixels.Color(r,g,b));
  pixels.show(); 
}

/*-------------------------------------------------------------------------------*/
/* Function void rgb_neopixel_off()                                              */
/*                                                                               */
/* TASK    : rgb neopixels off                                                   */
/* UPDATE  : 18.11.2020                                                          */
/*-------------------------------------------------------------------------------*/
void rgb_neopixel_off()  
{
  // right side
  pixels.setPixelColor(0, pixels.Color(0,0,0));
  pixels.setPixelColor(1, pixels.Color(0,0,0));
  pixels.setPixelColor(2, pixels.Color(0,0,0));
  pixels.setPixelColor(3, pixels.Color(0,0,0));
  pixels.setPixelColor(4, pixels.Color(0,0,0));
  // left side
  pixels.setPixelColor(5, pixels.Color(0,0,0));
  pixels.setPixelColor(6, pixels.Color(0,0,0));
  pixels.setPixelColor(7, pixels.Color(0,0,0));
  pixels.setPixelColor(8, pixels.Color(0,0,0));
  pixels.setPixelColor(9, pixels.Color(0,0,0));
  pixels.show(); 
}

/*-------------------------------------------------------------------------------*/
/* Function void array_to_string(byte array[], unsigned int len, char buffer[])  */
/*                                                                               */
/* TASK    : build string out of payload data                                    */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void array_to_string(byte array[], unsigned int len, char buffer[])
{
  for (unsigned int i = 0; i < len; i++)
  {
    byte nib1 = (array[i] >> 4) & 0x0F;
    byte nib2 = (array[i] >> 0) & 0x0F;
    buffer[i*2+0] = nib1  < 0xA ? '0' + nib1  : 'A' + nib1  - 0xA;
    buffer[i*2+1] = nib2  < 0xA ? '0' + nib2  : 'A' + nib2  - 0xA;
  }
  buffer[len*2] = '\0';
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_room_screen(String room_name, long int room_bg)     */
/*                                                                               */
/* TASK    : show tft display room screen                                        */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_room_screen(String room_name, long int room_bg) 
{
  M5.Lcd.fillScreen(TFT_WHITE);
  M5.Lcd.fillRect(0,0,320,50,room_bg);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setTextColor(TFT_WHITE);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth(room_name)) / 2, 32);
  M5.Lcd.print(room_name); 
  // drawing verticle line
  M5.Lcd.drawFastVLine(150,50,190,TFT_DARKGREEN);
  // drawing horizontal line
  M5.Lcd.drawFastHLine(0,140,320,TFT_DARKGREEN);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_status_bar(String room_name, long int room_bg)      */
/*                                                                               */
/* TASK    : show tft display status bar                                         */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_status_bar(String room_name, long int room_bg) 
{
  M5.Lcd.fillRect(0,0,320,50,room_bg);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.setTextColor(TFT_WHITE);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth(room_name)) / 2, 32);
  M5.Lcd.print(room_name); 
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_temperature(void)                            */
/*                                                                               */
/* TASK    : show tft display sensor temperature                                 */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_temperature(int temperature) 
{
  // setting the temperature
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Temperature",15,65);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(temperature,50,95);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("C",100,95);  
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_temperature(void)                            */
/*                                                                               */
/* TASK    : show tft display update temperature                                 */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_temperature(int temperature) 
{
  // setting the temperature
  M5.Lcd.fillRect(50,95,50,30,WHITE);
  M5.Lcd.setTextColor(BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(temperature,50,95);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_humidity(int humidity)                       */
/*                                                                               */
/* TASK    : show tft display sensor humidity                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_humidity(int humidity) 
{
  // setting the humidity
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Humidity",30,160);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(humidity,50,190);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("%",100,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_humidity(void)                               */
/*                                                                               */
/* TASK    : show tft display update humidity                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_humidity(int humidity) 
{
  // setting the humidity
  M5.Lcd.fillRect(50,190,50,30,TFT_WHITE);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(humidity,50,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_pressure(int pressure)                       */
/*                                                                               */
/* TASK    : show tft display sensor pressure                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_pressure(int pressure) 
{
  // setting the pressure
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Pressure",190,65);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(pressure,160,95);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("mBar",250,95);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_pressure(void)                               */
/*                                                                               */
/* TASK    : show tft display update pressure                                    */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_pressure(int pressure) 
{
  // setting the pressure
  M5.Lcd.fillRect(160,95,85,30,TFT_WHITE);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(pressure,160,95);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_sensor_battery(int battery)                         */
/*                                                                               */
/* TASK    : show tft display sensor battery                                     */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_battery(int battery) 
{ 
  // setting the battery power
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB9);
  M5.Lcd.drawString("Battery",200,160);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(battery,200,190);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.drawString("%",280,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_update_battery(int battery)                         */
/*                                                                               */
/* TASK    : show tft display update heating                                     */
/* UPDATE  : 22.09.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_update_battery(int battery) 
{
  // setting the battery
  M5.Lcd.fillRect(160,190,105,30,TFT_WHITE);
  M5.Lcd.setTextColor(TFT_BLACK);
  M5.Lcd.setFreeFont(FMB18);
  M5.Lcd.drawNumber(battery,200,190);
}

/*-------------------------------------------------------------------------------*/
/* Function void tft_display_m5stack(void)                                       */
/*                                                                               */
/* TASK    : show tft display m5stack (this m5stack)                             */
/* UPDATE  : 10.12.2020                                                          */
/*-------------------------------------------------------------------------------*/
void tft_display_m5stack(void) 
{
  // display room screen
  tft_display_room_screen("M5STACK-CORE-2",BLUE); 
  // display temperature sensor
  tft_display_sensor_temperature(m5stack_temp);
  // display humidity sensor
  tft_display_sensor_humidity(m5stack_humi); 
  // display pressure sensor
  tft_display_sensor_pressure(m5stack_press); 
  // display battery sensor
  tft_display_sensor_battery(m5stack_bat);
}

/*-------------------------------------------------------------------------------*/
/* Function void send_to_TTN(void)                                               */
/*                                                                               */
/* TASK    : send sensor data to TTN                                             */
/* UPDATE  : 25.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void send_to_TTN(void) 
{  
  // show picture
  iot_picture="/ttn.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
  
  // neopixels red
  rgb_neopixel(255,0,0);

  // activate communication
  Serial.println("LoraSet=?");  
  ATCommand("LoraSet", "?");
  delay(500);
  
  Serial.println(F(" "));
  Serial.print(F(application)); Serial.print(F(" Version ")); Serial.println(F(aktu_version));
  Serial.println(F(" "));

  // check if we can access battery functions
  if(!M5.Power.canControl())
  {
    Serial.println(F("[!] No communication with IP5306 chip"));
  }

  // actual battery level
  uint8_t bat = M5.Power.getBatteryLevel();
  Serial.print(F("[?] M5STACK BATTERY LEVEL --> "));
  Serial.print(bat);
  Serial.println(F(" %"));
  m5stack_bat=bat;
  int32_t battery_int = bat * 100; 
    
  #ifdef ENABLE_SENSOR_ENVII     
    sensor_env2();
    m5stack_temp=env2_tmp;
    m5stack_humi=env2_hum;
    m5stack_press=env2_pressure;
    Serial.print(F("[?] M5STACK Unit ENVII --> "));
    Serial.print("ENVII-P:"); Serial.print(env2_pressure); 
    Serial.print("  ENVII-T:"); Serial.print(env2_tmp);  
    Serial.print("  ENVII-H:"); Serial.println(env2_hum);                 
  #endif

  // now we create the payload and send it to the TTN
  int32_t temp_int      = env2_tmp * 100;
  int32_t pressure_int  = env2_pressure * 100;
  int32_t hum_int       = env2_hum * 100;

  byte payload[12];
  payload[0] = temp_int;
  payload[1] = temp_int >> 8;
  payload[2] = temp_int >> 16;

  payload[3] = hum_int;
  payload[4] = hum_int >> 8;
  payload[5] = hum_int >> 16;

  payload[6] = pressure_int;
  payload[7] = pressure_int >> 8;
  payload[8] = pressure_int >> 16;
    
  payload[9]  = battery_int;
  payload[10] = battery_int >> 8;
  payload[11] = battery_int >> 16;

  Serial.print(F("[x] actual TTN payload --> "));
  char str[32] = "";
  array_to_string(payload, 12, str);
  Serial.println(str);

  // now send all to TTN
  ATCommand("SendHex", str); 
  // neopixels now off
  rgb_neopixel_off();
  // display sensor data
  tft_display_m5stack();       
}

/*-------------------------------------------------------------------------------*/
/* Function void setup()                                                         */
/*                                                                               */
/* TASK    : setup all needed requirements                                       */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void setup() 
{
  // initialize the M5Stack object
  M5.begin();

  /*
    Power chip connected to gpio21, gpio22, I2C device
    Set battery charging voltage and current
    If used battery, please call this function in your project
  */
  M5.Power.begin();

  // open serial monitor
  Serial.begin(115200);
  
  // activate the NeoPixels
  pixels.begin();
  rgb_neopixel(0,0,0);

  // boot application
  delay(3000);
  Serial.println(F(" "));
  Serial.println(F(" "));
  Serial.println(F("Starting..."));
  Serial.print(F(application)); Serial.print(F(" Version ")); Serial.println(F(aktu_version));
  Serial.println(F("connected via TTN Stuttgart"));
  Serial.println(F(" ")); 

  M5.Lcd.fillScreen(TFT_RED);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.setTextColor(TFT_WHITE);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("M5Stack CORE")) / 2, 100);
  M5.Lcd.print("M5Stack CORE");
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("TTN SensorNode")) / 2, 120);
  M5.Lcd.print("TTN SensorNode");
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("Version x.xx")) / 2, 140);
  M5.Lcd.print("Version ");
  M5.Lcd.print(aktu_version);
  delay(6000);

  // SD card
  M5.Lcd.fillScreen(TFT_NAVY);
  M5.Lcd.setFreeFont(FMB12);
  M5.Lcd.setTextColor(TFT_YELLOW);
  M5.Lcd.setCursor((320 - M5.Lcd.textWidth("SD card initialize..")) / 2, 120);
  M5.Lcd.print("SD card initialize..");
  delay(2000);
  // check if we have a sd card inserted
  if (!SD.begin()) 
  {
    Serial.println("[!] SD Card failed, or not present");
    while (1);
  }
  Serial.println("[x] SD Card initialized.");

  // Lcd display 
  M5.Lcd.setBrightness(255); 

  // show iot picture
  iot_picture="/iot.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
  delay(2000);

  // activate the FIRE NeoPixels blue
  rgb_neopixel(0,0,255);

  // actual battery level
  uint8_t bat = M5.Power.getBatteryLevel();
  Serial.print(F("[?] M5STACK BATTERY LEVEL --> "));
  Serial.print(bat);
  Serial.println(F(" %"));
  m5stack_bat=bat;  

  #ifdef ENABLE_SENSOR_ENVII
    // show picture
    iot_picture="/unit_env2.jpg";
    M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
    delay(2000);  
    Wire.begin();
    while (!bme.begin(0x76))
    {
      Serial.println(F("[!] Could not find a valid BMP280 sensor, check wiring!"));
    }
    Serial.println(F("[x] GROVE ENVII Sensor detected"));
    // read the env2 sensor */
    sensor_env2();
    m5stack_temp=env2_tmp;
    m5stack_humi=env2_hum;
    m5stack_press=env2_pressure;
    Serial.print(F("[?] M5STACK UNIT ENVII --> "));
    Serial.print("ENVII-P:"); Serial.print(env2_pressure); 
    Serial.print("  ENVII-T:"); Serial.print(env2_tmp);  
    Serial.print("  ENVII-H:"); Serial.println(env2_hum);  
  #endif

  #ifdef ENABLE_SENSOR_PIR_MOTION
    // show picture
    iot_picture="/unit_pir.jpg";
    M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
    delay(2000);   
    pinMode(PIR_MOTION_SENSOR, INPUT);
    Serial.println(F("[x] GROVE PIR Motion Sensor detected"));
  #endif   
    
  // now connect to the M%Stack COM.LoRaWAN module
  // TX 0/3/17
  // RX 5/15/16
  // Before you connect the module to your M5Stack device, make sure you set the TXD/RXD dip switches correctly. 
  // If you use the grey or basic and have nothing else connected, the default UART pin configuration 16/17 is fine. 
  // For the Fire you should use 13/5, as all other settings can interfere with internals of the Fire.
  //   
  // Serial2.begin(115200, SERIAL_8N1, 15, 13);
  Serial2.begin(115200, SERIAL_8N1, 16, 17);
  // show picture
  iot_picture="/comx_lorawan.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());

  // we have to get and set some parameters 
  // first order does not work - waking module 
  ATCommand("LORAWAN", "?");
  delay(500);

  // setting LoRaWan Mode
  ATCommand("LORAWAN", "1");
  delay(500);

  // DevEui=XXXXXXXXXXXXXXXX(For OTAA Mode)
  // DevEui="XXXXXXXXXXXXXXXX";
   
  // AppEui=XXXXXXXXXXXXXXXX(For OTAA Mode)
  // always the same if equal devices
  // AppEui = "XXXXXXXXXXXXXXXX";
   
  // AppKey=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX(For OTAA Mode)
  // AppKey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";  

  // your TTN access data
  ATCommand("DevEui", "XXXXXXXXXXXXXXXX");
  delay(500);
  ATCommand("AppEui", "XXXXXXXXXXXXXXXX");
  delay(500);
  ATCommand("AppKey", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
  delay(500);

  // we join the TTN network
  ATCommand("Join", "1");
  
  // show picture
  iot_picture="/ttn.jpg";
  M5.Lcd.drawJpgFile(SD, iot_picture.c_str());
  delay(2000);   
 
  // neopixels now off
  rgb_neopixel_off();

  // display sensor data
  tft_display_m5stack();   
}

/*-------------------------------------------------------------------------------*/
/* Function void loop()                                                          */
/*                                                                               */
/* TASK    : this runs forever                                                   */
/* UPDATE  : 24.01.2021                                                          */
/*-------------------------------------------------------------------------------*/
void loop()
{ 
  // check if some one has pressed a button
  if (M5.BtnA.wasPressed()) 
  {
    Serial.println("[x] Button A was pressed - Display ON/OFF");
    tft_backlight = !tft_backlight;   
    // Turning off the LCD backlight
    if (tft_backlight == false) { rgb_neopixel_off(); M5.Lcd.sleep();  M5.Lcd.setBrightness(0); }
    // Turning on the LCD backlight
    if (tft_backlight == true)  { M5.Lcd.wakeup(); M5.Lcd.setBrightness(255); }
    delay(200);
  }

  // check if some one has pressed a button
  if (M5.BtnB.wasPressed()) 
  {
    Serial.println("[x] Button B was pressed."); 
    delay(200);  
  }

  // check if some one has pressed a button
  if (M5.BtnC.wasPressed()) 
  {
    Serial.println("[x] Button C was pressed - Send to TTN");
    send_to_TTN();   
    delay(200);   
  }

  /*
   * If we have an enabled PIR Motion Sensor we will send immediately
   * a message to the LoRaWan Gateway if we have detected an intruder
   */ 
  #ifdef ENABLE_SENSOR_PIR_MOTION
    // read the motion sensor
    // only if display is dark
    if (tft_backlight == false)
    {
      int sensorValue = digitalRead(PIR_MOTION_SENSOR);
      // if the sensor value is HIGH we have an intruder ?
      if(sensorValue == HIGH)       
      { 
        if (MOTION == false)
        {
          // digitalWrite(LED, HIGH);
          MOTION=true;
          Serial.println("[x] PIR MOTION detected ..."); 
          // M5.Speaker.tone(661, 20);
          tft_backlight = true;  
          if (tft_backlight == true)  { tft_counter=0; M5.Lcd.wakeup(); M5.Lcd.setBrightness(255); }        
        }     
      }
      // if the sensor value is HIGH we have an intruder ?
      if(sensorValue == LOW)       
      { 
        // digitalWrite(LED, LOW);
        MOTION=false;   
      }
    }     
  #endif
  
  /* 
   * It is checked whether the time for the transmission interval has already expired
   * If the time difference between the last save and the current time is greater
   * as the interval, the following function is executed.
  */
  if (millis() - previousMillis > interval)
  {
    // correct timer
    previousMillis = millis();

    
    // shall we now publish (10 minutes)
    TTNCounter++;
    if (TTNCounter==20)
    {
      send_to_TTN();
      TTNCounter=0; 
    }
    
    // tft got to sleep after 1 minute
    tft_counter++;
    if (tft_counter==3) 
    {
      if (tft_backlight == true) { tft_backlight=false; }   
      // Turning off the LCD backlight
      if (tft_backlight == false) 
      {
        rgb_neopixel_off(); 
        M5.Lcd.sleep();  M5.Lcd.setBrightness(0);
        Serial.println(F("[x] sleeping mode ... "));
      }
      tft_counter=0;     
    }   
  }

  delay(100);  
  M5.update();
}

UNIT_ENV.h

Arduino
all sensor units env_x
#ifndef _UNIT_ENV_H_
#define _UNIT_ENV_H_

#include "QMP6988.h"
#include "SHT3X.h"
#include "DHT12.h"

#endif

SHT3X.cpp

Arduino
sensor unit ENVII and ENVIII
#include "SHT3X.h"

/* Motor()

*/
SHT3X::SHT3X(uint8_t address)
{
  Wire.begin();
  _address=address;
}



byte SHT3X::get()
{
  unsigned int data[6];

  // Start I2C Transmission
  Wire.beginTransmission(_address);
  // Send measurement command
  Wire.write(0x2C);
  Wire.write(0x06);
  // Stop I2C transmission
  if (Wire.endTransmission()!=0) 
    return 1;  

  delay(500);

  // Request 6 bytes of data
  Wire.requestFrom(_address, 6);

  // Read 6 bytes of data
  // cTemp msb, cTemp lsb, cTemp crc, humidity msb, humidity lsb, humidity crc
  for (int i=0;i<6;i++) {
    data[i]=Wire.read();
  };
  
  delay(50);
  
  if (Wire.available()!=0) 
    return 2;

  // Convert the data
  cTemp = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
  fTemp = (cTemp * 1.8) + 32;
  humidity = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0);

  return 0;
}

SHT3X.h

Arduino
header sensor unit ENVII and ENVIII
#ifndef __SHT3X_H
#define __SHT3X_H


#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include "Wire.h"

class SHT3X{
public:
  SHT3X(uint8_t address=0x44);
  byte get(void);
  float cTemp=0;
  float fTemp=0;
  float humidity=0;

private:
  uint8_t _address;

};


#endif

QMP6988.cpp

Arduino
sensor unit ENVIII (presssure)
#include <math.h>
#include "stdint.h"
#include "stdio.h"
#include "QMP6988.h"

// DISABLE LOG
#define QMP6988_LOG(format...)	
#define QMP6988_ERR(format...)		

// ENABLE LOG
// #define QMP6988_LOG Serial.printf
// #define QMP6988_ERR Serial.printf	

void QMP6988::delayMS(unsigned int ms)
{
  delay(ms);
}

uint8_t QMP6988::writeReg(uint8_t slave, uint8_t reg_add,uint8_t reg_dat)
{
  device_wire->beginTransmission(slave);
  device_wire->write(reg_add);
  device_wire->write(reg_dat);
  device_wire->endTransmission();
  return 1;
}

uint8_t QMP6988::readData(uint16_t slave, uint8_t reg_add, unsigned char* Read, uint8_t num)
{
  device_wire->beginTransmission(slave);
  device_wire->write(reg_add);
  device_wire->endTransmission();
  device_wire->requestFrom(slave, num);
  for (int i = 0; i < num; i++) {
    *(Read + i) = device_wire->read();
  }
  return 1;
}

uint8_t QMP6988::deviceCheck()
{
  uint8_t slave_addr_list[2] = {QMP6988_SLAVE_ADDRESS_L, QMP6988_SLAVE_ADDRESS_H};
  uint8_t ret = 0;
  uint8_t i;

  for(i=0; i<2; i++)
  {
    slave_addr = slave_addr_list[i];
    ret = readData(slave_addr, QMP6988_CHIP_ID_REG, &(qmp6988.chip_id), 1);
    if(ret == 0){
      QMP6988_LOG("%s: read 0xD1 failed\r\n",__func__);
      continue;
    }
    QMP6988_LOG("qmp6988 read chip id = 0x%x\r\n", qmp6988.chip_id);
    if(qmp6988.chip_id == QMP6988_CHIP_ID)
    {
      return 1;
    }
  }

  return 0;
}

int QMP6988::getCalibrationData()
{
  int status = 0;
  //BITFIELDS temp_COE;
  uint8_t a_data_uint8_tr[QMP6988_CALIBRATION_DATA_LENGTH] = {0};
  int len;

  for(len = 0; len < QMP6988_CALIBRATION_DATA_LENGTH; len += 1)
  {
    status = readData(slave_addr,QMP6988_CALIBRATION_DATA_START+len,&a_data_uint8_tr[len],1);
    if (status == 0)
    {
      QMP6988_LOG("qmp6988 read 0xA0 error!");
      return status;
    }
  }

  qmp6988.qmp6988_cali.COE_a0 = (QMP6988_S32_t)(((a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) \
              | (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) \
              | (a_data_uint8_tr[24] & 0x0f))<<12);
  qmp6988.qmp6988_cali.COE_a0 = qmp6988.qmp6988_cali.COE_a0>>12;
  
  qmp6988.qmp6988_cali.COE_a1 = (QMP6988_S16_t)(((a_data_uint8_tr[20]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]);
  qmp6988.qmp6988_cali.COE_a2 = (QMP6988_S16_t)(((a_data_uint8_tr[22]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]);
  
  qmp6988.qmp6988_cali.COE_b00 = (QMP6988_S32_t)(((a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) \
              | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) \
              | ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION))<<12);
  qmp6988.qmp6988_cali.COE_b00 = qmp6988.qmp6988_cali.COE_b00>>12;

  qmp6988.qmp6988_cali.COE_bt1 = (QMP6988_S16_t)(((a_data_uint8_tr[2]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]);
  qmp6988.qmp6988_cali.COE_bt2 = (QMP6988_S16_t)(((a_data_uint8_tr[4]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]);
  qmp6988.qmp6988_cali.COE_bp1 = (QMP6988_S16_t)(((a_data_uint8_tr[6]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]);
  qmp6988.qmp6988_cali.COE_b11 = (QMP6988_S16_t)(((a_data_uint8_tr[8]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]);
  qmp6988.qmp6988_cali.COE_bp2 = (QMP6988_S16_t)(((a_data_uint8_tr[10]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]);
  qmp6988.qmp6988_cali.COE_b12 = (QMP6988_S16_t)(((a_data_uint8_tr[12]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]);		
  qmp6988.qmp6988_cali.COE_b21 = (QMP6988_S16_t)(((a_data_uint8_tr[14]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]);
  qmp6988.qmp6988_cali.COE_bp3 = (QMP6988_S16_t)(((a_data_uint8_tr[16]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]);			

  QMP6988_LOG("<-----------calibration data-------------->\r\n");
  QMP6988_LOG("COE_a0[%d]	COE_a1[%d]	COE_a2[%d]	COE_b00[%d]\r\n",
      qmp6988.qmp6988_cali.COE_a0,qmp6988.qmp6988_cali.COE_a1,qmp6988.qmp6988_cali.COE_a2,qmp6988.qmp6988_cali.COE_b00);
  QMP6988_LOG("COE_bt1[%d]	COE_bt2[%d]	COE_bp1[%d]	COE_b11[%d]\r\n",
      qmp6988.qmp6988_cali.COE_bt1,qmp6988.qmp6988_cali.COE_bt2,qmp6988.qmp6988_cali.COE_bp1,qmp6988.qmp6988_cali.COE_b11);
  QMP6988_LOG("COE_bp2[%d]	COE_b12[%d]	COE_b21[%d]	COE_bp3[%d]\r\n",
      qmp6988.qmp6988_cali.COE_bp2,qmp6988.qmp6988_cali.COE_b12,qmp6988.qmp6988_cali.COE_b21,qmp6988.qmp6988_cali.COE_bp3);
  QMP6988_LOG("<-----------calibration data-------------->\r\n");

  qmp6988.ik.a0 = qmp6988.qmp6988_cali.COE_a0; // 20Q4
  qmp6988.ik.b00 = qmp6988.qmp6988_cali.COE_b00; // 20Q4

  qmp6988.ik.a1 = 3608L * (QMP6988_S32_t)qmp6988.qmp6988_cali.COE_a1 - 1731677965L; // 31Q23
  qmp6988.ik.a2 = 16889L * (QMP6988_S32_t) qmp6988.qmp6988_cali.COE_a2 - 87619360L; // 30Q47

  qmp6988.ik.bt1 = 2982L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_bt1 + 107370906L; // 28Q15
  qmp6988.ik.bt2 = 329854L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_bt2 + 108083093L; // 34Q38
  qmp6988.ik.bp1 = 19923L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_bp1 + 1133836764L; // 31Q20
  qmp6988.ik.b11 = 2406L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_b11+ 118215883L; // 28Q34
  qmp6988.ik.bp2 = 3079L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_bp2 - 181579595L; // 29Q43
  qmp6988.ik.b12 = 6846L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_b12 + 85590281L; // 29Q53
  qmp6988.ik.b21 = 13836L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_b21 + 79333336L; // 29Q60
  qmp6988.ik.bp3 = 2915L * (QMP6988_S64_t)qmp6988.qmp6988_cali.COE_bp3 + 157155561L; // 28Q65
  QMP6988_LOG("<----------- int calibration data -------------->\r\n");
  QMP6988_LOG("a0[%d]	a1[%d] a2[%d] b00[%d]\r\n",qmp6988.ik.a0,qmp6988.ik.a1,qmp6988.ik.a2,qmp6988.ik.b00);
  QMP6988_LOG("bt1[%lld]	bt2[%lld]	bp1[%lld]	b11[%lld]\r\n",qmp6988.ik.bt1,qmp6988.ik.bt2,qmp6988.ik.bp1,qmp6988.ik.b11);
  QMP6988_LOG("bp2[%lld]	b12[%lld]	b21[%lld]	bp3[%lld]\r\n",qmp6988.ik.bp2,qmp6988.ik.b12,qmp6988.ik.b21,qmp6988.ik.bp3);
  QMP6988_LOG("<----------- int calibration data -------------->\r\n");
  return 1;
}

QMP6988_S16_t QMP6988::convTx02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dt) 
{
  QMP6988_S16_t ret;
  QMP6988_S64_t wk1, wk2;

  // wk1: 60Q4 // bit size
  wk1 = ((QMP6988_S64_t)ik->a1 * (QMP6988_S64_t)dt); // 31Q23+24-1=54 (54Q23)
  wk2 = ((QMP6988_S64_t)ik->a2 * (QMP6988_S64_t)dt) >> 14; // 30Q47+24-1=53 (39Q33)
  wk2 = (wk2 * (QMP6988_S64_t)dt) >> 10; // 39Q33+24-1=62 (52Q23)
  wk2 = ((wk1 + wk2) / 32767) >> 19; // 54,52->55Q23 (20Q04)
  ret = (QMP6988_S16_t)((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0
  return ret;
}

QMP6988_S32_t QMP6988::getPressure02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dp, QMP6988_S16_t tx)
{
  QMP6988_S32_t ret;
  QMP6988_S64_t wk1, wk2, wk3;

  // wk1 = 48Q16 // bit size
  wk1 = ((QMP6988_S64_t)ik->bt1 * (QMP6988_S64_t)tx); // 28Q15+16-1=43 (43Q15)
  wk2 = ((QMP6988_S64_t)ik->bp1 * (QMP6988_S64_t)dp) >> 5; // 31Q20+24-1=54 (49Q15)
  wk1 += wk2; // 43,49->50Q15
  wk2 = ((QMP6988_S64_t)ik->bt2 * (QMP6988_S64_t)tx) >> 1; // 34Q38+16-1=49 (48Q37)
  wk2 = (wk2 * (QMP6988_S64_t)tx) >> 8; // 48Q37+16-1=63 (55Q29)
  wk3 = wk2; // 55Q29
  wk2 = ((QMP6988_S64_t)ik->b11 * (QMP6988_S64_t)tx) >> 4; // 28Q34+16-1=43 (39Q30)
  wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29)
  wk3 += wk2; // 55,61->62Q29
  wk2 = ((QMP6988_S64_t)ik->bp2 * (QMP6988_S64_t)dp) >> 13; // 29Q43+24-1=52 (39Q30)
  wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q30+24-1=62 (61Q29)
  wk3 += wk2; // 62,61->63Q29
  wk1 += wk3 >> 14; // Q29 >> 14 -> Q15
  wk2 = ((QMP6988_S64_t)ik->b12 * (QMP6988_S64_t)tx); // 29Q53+16-1=45 (45Q53)
  wk2 = (wk2 * (QMP6988_S64_t)tx) >> 22; // 45Q53+16-1=61 (39Q31)
  wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q31+24-1=62 (61Q30)
  wk3 = wk2; // 61Q30
  wk2 = ((QMP6988_S64_t)ik->b21 * (QMP6988_S64_t)tx) >> 6; // 29Q60+16-1=45 (39Q54)
  wk2 = (wk2 * (QMP6988_S64_t)dp) >> 23; // 39Q54+24-1=62 (39Q31)
  wk2 = (wk2 * (QMP6988_S64_t)dp) >> 1; // 39Q31+24-1=62 (61Q20)
  wk3 += wk2; // 61,61->62Q30
  wk2 = ((QMP6988_S64_t)ik->bp3 * (QMP6988_S64_t)dp) >> 12; // 28Q65+24-1=51 (39Q53)
  wk2 = (wk2 * (QMP6988_S64_t)dp) >> 23; // 39Q53+24-1=62 (39Q30)
  wk2 = (wk2 * (QMP6988_S64_t)dp); // 39Q30+24-1=62 (62Q30)
  wk3 += wk2; // 62,62->63Q30
  wk1 += wk3 >> 15; // Q30 >> 15 = Q15
  wk1 /= 32767L;
  wk1 >>= 11; // Q15 >> 7 = Q4
  wk1 += ik->b00; // Q4 + 20Q4
  //wk1 >>= 4; // 28Q4 -> 24Q0
  ret = (QMP6988_S32_t)wk1;
  return ret;
}

void QMP6988::softwareReset()
{
  uint8_t ret = 0; 

  ret = writeReg(slave_addr, QMP6988_RESET_REG, 0xe6);
  if(ret == 0)
  {
    QMP6988_LOG("softwareReset fail!!! \r\n");
  }
  delayMS(20);
  ret = writeReg(slave_addr, QMP6988_RESET_REG, 0x00);
}

void QMP6988::setpPowermode(int power_mode)
{
  uint8_t data;

  QMP6988_LOG("qmp_set_powermode %d \r\n", power_mode);

  qmp6988.power_mode = power_mode;
  readData(slave_addr, QMP6988_CTRLMEAS_REG, &data, 1);
  data = data&0xfc;
  if(power_mode == QMP6988_SLEEP_MODE)
  {
    data |= 0x00;
  }
  else if(power_mode == QMP6988_FORCED_MODE)
  {
    data |= 0x01;
  }
  else if(power_mode == QMP6988_NORMAL_MODE)
  {
    data |= 0x03;
  }
  writeReg(slave_addr, QMP6988_CTRLMEAS_REG, data);

  QMP6988_LOG("qmp_set_powermode 0xf4=0x%x \r\n", data);
  
  delayMS(20);
}

void QMP6988::setFilter(unsigned char filter)
{	
  uint8_t data;

  data = (filter&0x03);
  writeReg(slave_addr, QMP6988_CONFIG_REG, data);

  delayMS(20);
}

void QMP6988::setOversamplingP(unsigned char oversampling_p)
{
  uint8_t data;

  readData(slave_addr, QMP6988_CTRLMEAS_REG, &data, 1);
  data &= 0xe3;
  data |= (oversampling_p << 2);
  writeReg(slave_addr, QMP6988_CTRLMEAS_REG, data);
  delayMS(20);
}

void QMP6988::setOversamplingT(unsigned char oversampling_t)
{
  uint8_t data;

  readData(slave_addr, QMP6988_CTRLMEAS_REG, &data, 1);
  data &= 0x1f;
  data |= (oversampling_t<<5);
  writeReg(slave_addr, QMP6988_CTRLMEAS_REG, data);
  delayMS(20);
}

float QMP6988::calcAltitude(float pressure, float temp)
{
  float altitude;

  altitude = (pow((101325/pressure),1/5.257)-1)*(temp+273.15)/0.0065;
  QMP6988_LOG("altitude = %f\r\n" ,altitude);
  return altitude;
}

float QMP6988::calcPressure()
{
  uint8_t err = 0;
  QMP6988_U32_t P_read, T_read;
  QMP6988_S32_t P_raw, T_raw;
  uint8_t a_data_uint8_tr[6] = {0};
  QMP6988_S32_t T_int, P_int;

  // press
  err = readData(slave_addr, QMP6988_PRESSURE_MSB_REG, a_data_uint8_tr, 6);
  if(err == 0)
  {
    QMP6988_LOG("qmp6988 read press raw error! \r\n");
    return 0.0f;
  }
  P_read = (QMP6988_U32_t)(
  (((QMP6988_U32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) |
  (((QMP6988_U16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2]));
  P_raw = (QMP6988_S32_t)(P_read - SUBTRACTOR);

  T_read = (QMP6988_U32_t)(
  (((QMP6988_U32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) |
  (((QMP6988_U16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5]));
  T_raw = (QMP6988_S32_t)(T_read - SUBTRACTOR);

  T_int = convTx02e(&(qmp6988.ik), T_raw);
  P_int = getPressure02e(&(qmp6988.ik), P_raw, T_int);
  qmp6988.temperature = (float)T_int / 256.0f;
  qmp6988.pressure = (float)P_int/16.0f;

  return qmp6988.pressure;
}

uint8_t QMP6988::init(uint8_t slave_addr_in, TwoWire* wire_in)
{
  device_wire = wire_in;
  uint8_t ret;
  slave_addr = slave_addr_in;
  ret = deviceCheck();
  if(ret == 0) {
    return 0;
  }
  softwareReset();
  getCalibrationData();
  setpPowermode(QMP6988_NORMAL_MODE);
  setFilter(QMP6988_FILTERCOEFF_4);
  setOversamplingP(QMP6988_OVERSAMPLING_8X);
  setOversamplingT(QMP6988_OVERSAMPLING_1X);
  return 1;
}

QMP6988.h

Arduino
header sensor unit ENVIII
#ifndef __QMP6988_H
#define __QMP6988_H

#include "Arduino.h"
#include "Wire.h"

#define QMP6988_SLAVE_ADDRESS_L  (0x70)
#define QMP6988_SLAVE_ADDRESS_H  (0x56)

#define QMP6988_U16_t unsigned short
#define QMP6988_S16_t short
#define QMP6988_U32_t unsigned int
#define QMP6988_S32_t int
#define QMP6988_U64_t unsigned long long
#define QMP6988_S64_t long long

#define QMP6988_CHIP_ID							0x5C

#define QMP6988_CHIP_ID_REG					0xD1
#define QMP6988_RESET_REG						0xE0  /* Device reset register */
#define QMP6988_DEVICE_STAT_REG			0xF3  /* Device state register */
#define QMP6988_CTRLMEAS_REG				0xF4  /* Measurement Condition Control Register */
/* data */
#define QMP6988_PRESSURE_MSB_REG    0xF7  /* Pressure MSB Register */
#define QMP6988_TEMPERATURE_MSB_REG 0xFA  /* Temperature MSB Reg */

/* compensation calculation */
#define QMP6988_CALIBRATION_DATA_START    0xA0 /* QMP6988 compensation coefficients */
#define QMP6988_CALIBRATION_DATA_LENGTH		25

#define SHIFT_RIGHT_4_POSITION 		4
#define SHIFT_LEFT_2_POSITION			2
#define SHIFT_LEFT_4_POSITION			4
#define SHIFT_LEFT_5_POSITION			5
#define SHIFT_LEFT_8_POSITION			8
#define SHIFT_LEFT_12_POSITION		12
#define SHIFT_LEFT_16_POSITION		16

/* power mode */
#define QMP6988_SLEEP_MODE                0x00
#define QMP6988_FORCED_MODE               0x01
#define QMP6988_NORMAL_MODE               0x03

#define QMP6988_CTRLMEAS_REG_MODE__POS		0
#define QMP6988_CTRLMEAS_REG_MODE__MSK		0x03
#define QMP6988_CTRLMEAS_REG_MODE__LEN		2

/* oversampling */
#define QMP6988_OVERSAMPLING_SKIPPED        0x00
#define QMP6988_OVERSAMPLING_1X             0x01
#define QMP6988_OVERSAMPLING_2X             0x02
#define QMP6988_OVERSAMPLING_4X             0x03
#define QMP6988_OVERSAMPLING_8X             0x04
#define QMP6988_OVERSAMPLING_16X            0x05
#define QMP6988_OVERSAMPLING_32X            0x06
#define QMP6988_OVERSAMPLING_64X            0x07

#define QMP6988_CTRLMEAS_REG_OSRST__POS     5
#define QMP6988_CTRLMEAS_REG_OSRST__MSK     0xE0
#define QMP6988_CTRLMEAS_REG_OSRST__LEN     3

#define QMP6988_CTRLMEAS_REG_OSRSP__POS     2
#define QMP6988_CTRLMEAS_REG_OSRSP__MSK     0x1C
#define QMP6988_CTRLMEAS_REG_OSRSP__LEN     3

/* filter */
#define QMP6988_FILTERCOEFF_OFF		0x00
#define QMP6988_FILTERCOEFF_2			0x01
#define QMP6988_FILTERCOEFF_4			0x02
#define QMP6988_FILTERCOEFF_8			0x03
#define QMP6988_FILTERCOEFF_16		0x04
#define QMP6988_FILTERCOEFF_32		0x05

#define QMP6988_CONFIG_REG                0xF1  /*IIR filter co-efficient setting Register*/
#define QMP6988_CONFIG_REG_FILTER__POS		0
#define QMP6988_CONFIG_REG_FILTER__MSK		0x07
#define QMP6988_CONFIG_REG_FILTER__LEN		3

#define SUBTRACTOR 8388608

typedef struct _qmp6988_cali_data {
  QMP6988_S32_t COE_a0;
  QMP6988_S16_t COE_a1;
  QMP6988_S16_t COE_a2;
  QMP6988_S32_t COE_b00;
  QMP6988_S16_t COE_bt1;
  QMP6988_S16_t COE_bt2;
  QMP6988_S16_t COE_bp1;
  QMP6988_S16_t COE_b11;
  QMP6988_S16_t COE_bp2;
  QMP6988_S16_t COE_b12;
  QMP6988_S16_t COE_b21;
  QMP6988_S16_t COE_bp3;
} qmp6988_cali_data_t;

typedef struct _qmp6988_fk_data {
  float a0, b00;
  float a1, a2, bt1, bt2, bp1, b11, bp2, b12, b21, bp3;
} qmp6988_fk_data_t;

typedef struct _qmp6988_ik_data {
  QMP6988_S32_t a0, b00;
  QMP6988_S32_t a1, a2;
  QMP6988_S64_t bt1, bt2, bp1, b11, bp2, b12, b21, bp3;
} qmp6988_ik_data_t;

typedef struct _qmp6988_data {
  uint8_t slave;
  uint8_t chip_id;
  uint8_t power_mode;
  float temperature;
  float pressure;
  float altitude;
  qmp6988_cali_data_t qmp6988_cali;
  qmp6988_ik_data_t ik;
} qmp6988_data_t;

class QMP6988 
{
private:
  qmp6988_data_t qmp6988;
  uint8_t slave_addr;
  TwoWire* device_wire;
  void delayMS(unsigned int ms);

  // read calibration data from otp
  int getCalibrationData();
  QMP6988_S32_t getPressure02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dp, QMP6988_S16_t tx);
  QMP6988_S16_t convTx02e(qmp6988_ik_data_t *ik, QMP6988_S32_t dt);

  void softwareReset();

public:
  uint8_t init(uint8_t slave_addr=0x56, TwoWire* wire_in=&Wire);
  uint8_t deviceCheck();

  float calcAltitude(float pressure, float temp);
  float calcPressure();

  void setpPowermode(int power_mode);
  void setFilter(unsigned char filter);
  void setOversamplingP(unsigned char oversampling_p);
  void setOversamplingT(unsigned char oversampling_t);

  uint8_t writeReg(uint8_t slave, uint8_t reg_add,uint8_t reg_dat);
  uint8_t readData(uint16_t slave, uint8_t reg_add, unsigned char* Read, uint8_t num);
};

#endif

sd.zip

Arduino
jpg pictures sd card (new with ENVIII unit)
No preview (download only).

Adafruit_Sensor.h

Arduino
Adafruit Sensors
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software< /span>
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
 * extended sensor support to include color, voltage and current */
 
#ifndef _ADAFRUIT_SENSOR_H
#define _ADAFRUIT_SENSOR_H

#ifndef ARDUINO
 #include <stdint.h>
#elif ARDUINO >= 100
 #include "Arduino.h"
 #include "Print.h"
#else
 #include "WProgram.h"
#endif

/* Intentionally modeled after sensors.h in the Android API:
 * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */

/* Constants */
#define SENSORS_GRAVITY_EARTH             (9.80665F)              /**< Earth's gravity in m/s^2 */
#define SENSORS_GRAVITY_MOON              (1.6F)                  /**< The moon's gravity in m/s^2 */
#define SENSORS_GRAVITY_SUN               (275.0F)                /**< The sun's gravity in m/s^2 */
#define SENSORS_GRAVITY_STANDARD          (SENSORS_GRAVITY_EARTH)
#define SENSORS_MAGFIELD_EARTH_MAX        (60.0F)                 /**< Maximum magnetic field on Earth's surface */
#define SENSORS_MAGFIELD_EARTH_MIN        (30.0F)                 /**< Minimum magnetic field on Earth's surface */
#define SENSORS_PRESSURE_SEALEVELHPA      (1013.25F)              /**< Average sea level pressure is 1013.25 hPa */
#define SENSORS_DPS_TO_RADS               (0.017453293F)          /**< Degrees/s to rad/s multiplier */
#define SENSORS_GAUSS_TO_MICROTESLA       (100)                   /**< Gauss to micro-Tesla multiplier */

/** Sensor types */
typedef enum
{
  SENSOR_TYPE_ACCELEROMETER         = (1),   /**< Gravity + linear acceleration */
  SENSOR_TYPE_MAGNETIC_FIELD        = (2),
  SENSOR_TYPE_ORIENTATION           = (3),
  SENSOR_TYPE_GYROSCOPE             = (4),
  SENSOR_TYPE_LIGHT                 = (5),
  SENSOR_TYPE_PRESSURE              = (6),
  SENSOR_TYPE_PROXIMITY             = (8),
  SENSOR_TYPE_GRAVITY               = (9),
  SENSOR_TYPE_LINEAR_ACCELERATION   = (10),  /**< Acceleration not including gravity */
  SENSOR_TYPE_ROTATION_VECTOR       = (11),
  SENSOR_TYPE_RELATIVE_HUMIDITY     = (12),
  SENSOR_TYPE_AMBIENT_TEMPERATURE   = (13),
  SENSOR_TYPE_VOLTAGE               = (15),
  SENSOR_TYPE_CURRENT               = (16),
  SENSOR_TYPE_COLOR                 = (17)
} sensors_type_t;

/** struct sensors_vec_s is used to return a vector in a common format. */
typedef struct {
    union {
        float v[3];
        struct {
            float x;
            float y;
            float z;
        };
        /* Orientation sensors */
        struct {
            float roll;    /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90<=roll<=90 */
            float pitch;   /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180<=pitch<=180) */
            float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359 */
        };
    };
    int8_t status;
    uint8_t reserved[3];
} sensors_vec_t;

/** struct sensors_color_s is used to return color data in a common format. */
typedef struct {
    union {
        float c[3];
        /* RGB color space */
        struct {
            float r;       /**< Red component */
            float g;       /**< Green component */
            float b;       /**< Blue component */
        };
    };
    uint32_t rgba;         /**< 24-bit RGBA value */
} sensors_color_t;

/* Sensor event (36 bytes) */
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
typedef struct
{
    int32_t version;                          /**< must be sizeof(struct sensors_event_t) */
    int32_t sensor_id;                        /**< unique sensor identifier */
    int32_t type;                             /**< sensor type */
    int32_t reserved0;                        /**< reserved */
    int32_t timestamp;                        /**< time is in milliseconds */
    union
    {
        float           data[4];
        sensors_vec_t   acceleration;         /**< acceleration values are in meter per second per second (m/s^2) */
        sensors_vec_t   magnetic;             /**< magnetic vector values are in micro-Tesla (uT) */
        sensors_vec_t   orientation;          /**< orientation values are in degrees */
        sensors_vec_t   gyro;                 /**< gyroscope values are in rad/s */
        float           temperature;          /**< temperature is in degrees centigrade (Celsius) */
        float           distance;             /**< distance in centimeters */
        float           light;                /**< light in SI lux units */
        float           pressure;             /**< pressure in hectopascal (hPa) */
        float           relative_humidity;    /**< relative humidity in percent */
        float           current;              /**< current in milliamps (mA) */
        float           voltage;              /**< voltage in volts (V) */
        sensors_color_t color;                /**< color in RGB component values */
    };
} sensors_event_t;

/* Sensor details (40 bytes) */
/** struct sensor_s is used to describe basic information about a specific sensor. */
typedef struct
{
    char     name[12];                        /**< sensor name */
    int32_t  version;                         /**< version of the hardware + driver */
    int32_t  sensor_id;                       /**< unique sensor identifier */
    int32_t  type;                            /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
    float    max_value;                       /**< maximum value of this sensor's value in SI units */
    float    min_value;                       /**< minimum value of this sensor's value in SI units */
    float    resolution;                      /**< smallest difference between two values reported by this sensor */
    int32_t  min_delay;                       /**< min delay in microseconds between events. zero = not a constant rate */
} sensor_t;

class Adafruit_Sensor {
 public:
  // Constructor(s)
  Adafruit_Sensor() {}
  virtual ~Adafruit_Sensor() {}

  // These must be defined by the subclass
  virtual void enableAutoRange(bool enabled) { (void)enabled; /* suppress unused warning */ };
  virtual bool getEvent(sensors_event_t*) = 0;
  virtual void getSensor(sensor_t*) = 0;
  
 private:
  bool _autoRange;
};

#endif

Free_Fonts.h

Arduino
Free Fonts
// Attach this header file to your sketch to use the GFX Free Fonts. You can write
// sketches without it, but it makes referencing them easier.

// This calls up ALL the fonts but they only get loaded if you actually
// use them in your sketch.
//
// No changes are needed to this header file unless new fonts are added to the
// library "Fonts/GFXFF" folder.
//
// To save a lot of typing long names, each font can easily be referenced in the
// sketch in three ways, either with:
//
//    1. Font file name with the & in front such as &FreeSansBoldOblique24pt7b
//       an example being:
//
//       tft.setFreeFont(&FreeSansBoldOblique24pt7b);
//
//    2. FF# where # is a number determined by looking at the list below
//       an example being:
//
//       tft.setFreeFont(FF32);
//
//    3. An abbreviation of the file name. Look at the list below to see
//       the abbreviations used, for example:
//
//       tft.setFreeFont(FSSBO24)
//
//       Where the letters mean:
//       F = Free font
//       M = Mono
//      SS = Sans Serif (double S to distinguish is form serif fonts)
//       S = Serif
//       B = Bold
//       O = Oblique (letter O not zero)
//       I = Italic
//       # =  point size, either 9, 12, 18 or 24
//
//  Setting the font to NULL will select the GLCD font:
//
//      tft.setFreeFont(NULL); // Set font to GLCD

#define LOAD_GFXFF

#ifdef LOAD_GFXFF // Only include the fonts if LOAD_GFXFF is defined in User_Setup.h

    // Use these when printing or drawing text in GLCD and high rendering speed fonts
    #define GFXFF 1
    #define GLCD  0
    #define FONT2 2
    #define FONT4 4
    #define FONT6 6
    #define FONT7 7
    #define FONT8 8

    // Use the following when calling setFont()
    //
    // Reserved for GLCD font  // FF0
    //

    #define TT1 &TomThumb

    #define FM9 &FreeMono9pt7b
    #define FM12 &FreeMono12pt7b
    #define FM18 &FreeMono18pt7b
    #define FM24 &FreeMono24pt7b

    #define FMB9 &FreeMonoBold9pt7b
    #define FMB12 &FreeMonoBold12pt7b
    #define FMB18 &FreeMonoBold18pt7b
    #define FMB24 &FreeMonoBold24pt7b

    #define FMO9 &FreeMonoOblique9pt7b
    #define FMO12 &FreeMonoOblique12pt7b
    #define FMO18 &FreeMonoOblique18pt7b
    #define FMO24 &FreeMonoOblique24pt7b

    #define FMBO9 &FreeMonoBoldOblique9pt7b
    #define FMBO12 &FreeMonoBoldOblique12pt7b
    #define FMBO18 &FreeMonoBoldOblique18pt7b
    #define FMBO24 &FreeMonoBoldOblique24pt7b

    #define FSS9 &FreeSans9pt7b
    #define FSS12 &FreeSans12pt7b
    #define FSS18 &FreeSans18pt7b
    #define FSS24 &FreeSans24pt7b

    #define FSSB9 &FreeSansBold9pt7b
    #define FSSB12 &FreeSansBold12pt7b
    #define FSSB18 &FreeSansBold18pt7b
    #define FSSB24 &FreeSansBold24pt7b

    #define FSSO9 &FreeSansOblique9pt7b
    #define FSSO12 &FreeSansOblique12pt7b
    #define FSSO18 &FreeSansOblique18pt7b
    #define FSSO24 &FreeSansOblique24pt7b

    #define FSSBO9 &FreeSansBoldOblique9pt7b
    #define FSSBO12 &FreeSansBoldOblique12pt7b
    #define FSSBO18 &FreeSansBoldOblique18pt7b
    #define FSSBO24 &FreeSansBoldOblique24pt7b

    #define FS9 &FreeSerif9pt7b
    #define FS12 &FreeSerif12pt7b
    #define FS18 &FreeSerif18pt7b
    #define FS24 &FreeSerif24pt7b

    #define FSI9 &FreeSerifItalic9pt7b
    #define FSI12 &FreeSerifItalic12pt7b
    #define FSI19 &FreeSerifItalic18pt7b
    #define FSI24 &FreeSerifItalic24pt7b

    #define FSB9 &FreeSerifBold9pt7b
    #define FSB12 &FreeSerifBold12pt7b
    #define FSB18 &FreeSerifBold18pt7b
    #define FSB24 &FreeSerifBold24pt7b

    #define FSBI9 &FreeSerifBoldItalic9pt7b
    #define FSBI12 &FreeSerifBoldItalic12pt7b
    #define FSBI18 &FreeSerifBoldItalic18pt7b
    #define FSBI24 &FreeSerifBoldItalic24pt7b

    #define FF0 NULL //ff0 reserved for GLCD
    #define FF1 &FreeMono9pt7b
    #define FF2 &FreeMono12pt7b
    #define FF3 &FreeMono18pt7b
    #define FF4 &FreeMono24pt7b

    #define FF5 &FreeMonoBold9pt7b
    #define FF6 &FreeMonoBold12pt7b
    #define FF7 &FreeMonoBold18pt7b
    #define FF8 &FreeMonoBold24pt7b

    #define FF9 &FreeMonoOblique9pt7b
    #define FF10 &FreeMonoOblique12pt7b
    #define FF11 &FreeMonoOblique18pt7b
    #define FF12 &FreeMonoOblique24pt7b

    #define FF13 &FreeMonoBoldOblique9pt7b
    #define FF14 &FreeMonoBoldOblique12pt7b
    #define FF15 &FreeMonoBoldOblique18pt7b
    #define FF16 &FreeMonoBoldOblique24pt7b

    #define FF17 &FreeSans9pt7b
    #define FF18 &FreeSans12pt7b
    #define FF19 &FreeSans18pt7b
    #define FF20 &FreeSans24pt7b

    #define FF21 &FreeSansBold9pt7b
    #define FF22 &FreeSansBold12pt7b
    #define FF23 &FreeSansBold18pt7b
    #define FF24 &FreeSansBold24pt7b

    #define FF25 &FreeSansOblique9pt7b
    #define FF26 &FreeSansOblique12pt7b
    #define FF27 &FreeSansOblique18pt7b
    #define FF28 &FreeSansOblique24pt7b

    #define FF29 &FreeSansBoldOblique9pt7b
    #define FF30 &FreeSansBoldOblique12pt7b
    #define FF31 &FreeSansBoldOblique18pt7b
    #define FF32 &FreeSansBoldOblique24pt7b

    #define FF33 &FreeSerif9pt7b
    #define FF34 &FreeSerif12pt7b
    #define FF35 &FreeSerif18pt7b
    #define FF36 &FreeSerif24pt7b

    #define FF37 &FreeSerifItalic9pt7b
    #define FF38 &FreeSerifItalic12pt7b
    #define FF39 &FreeSerifItalic18pt7b
    #define FF40 &FreeSerifItalic24pt7b

    #define FF41 &FreeSerifBold9pt7b
    #define FF42 &FreeSerifBold12pt7b
    #define FF43 &FreeSerifBold18pt7b
    #define FF44 &FreeSerifBold24pt7b

    #define FF45 &FreeSerifBoldItalic9pt7b
    #define FF46 &FreeSerifBoldItalic12pt7b
    #define FF47 &FreeSerifBoldItalic18pt7b
    #define FF48 &FreeSerifBoldItalic24pt7b

    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Now we define "s"tring versions for easy printing of the font name so:
    //   tft.println(sFF5);
    // will print
    //   Mono bold 9
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    #define sFF0 "GLCD"
    #define sTT1 "Tom Thumb"
    #define sFF1 "Mono 9"
    #define sFF2 "Mono 12"
    #define sFF3 "Mono 18"
    #define sFF4 "Mono 24"

    #define sFF5 "Mono bold 9"
    #define sFF6 "Mono bold 12"
    #define sFF7 "Mono bold 18"
    #define sFF8 "Mono bold 24"

    #define sFF9 "Mono oblique 9"
    #define sFF10 "Mono oblique 12"
    #define sFF11 "Mono oblique 18"
    #define sFF12 "Mono oblique 24"

    #define sFF13 "Mono bold oblique 9"
    #define sFF14 "Mono bold oblique 12"
    #define sFF15 "Mono bold oblique 18"
    #define sFF16 "Mono bold oblique 24" // Full text line is too big for 480 pixel wide screen

    #define sFF17 "Sans 9"
    #define sFF18 "Sans 12"
    #define sFF19 "Sans 18"
    #define sFF20 "Sans 24"

    #define sFF21 "Sans bold 9"
    #define sFF22 "Sans bold 12"
    #define sFF23 "Sans bold 18"
    #define sFF24 "Sans bold 24"

    #define sFF25 "Sans oblique 9"
    #define sFF26 "Sans oblique 12"
    #define sFF27 "Sans oblique 18"
    #define sFF28 "Sans oblique 24"

    #define sFF29 "Sans bold oblique 9"
    #define sFF30 "Sans bold oblique 12"
    #define sFF31 "Sans bold oblique 18"
    #define sFF32 "Sans bold oblique 24"

    #define sFF33 "Serif 9"
    #define sFF34 "Serif 12"
    #define sFF35 "Serif 18"
    #define sFF36 "Serif 24"

    #define sFF37 "Serif italic 9"
    #define sFF38 "Serif italic 12"
    #define sFF39 "Serif italic 18"
    #define sFF40 "Serif italic 24"

    #define sFF41 "Serif bold 9"
    #define sFF42 "Serif bold 12"
    #define sFF43 "Serif bold 18"
    #define sFF44 "Serif bold 24"

    #define sFF45 "Serif bold italic 9"
    #define sFF46 "Serif bold italic 12"
    #define sFF47 "Serif bold italic 18"
    #define sFF48 "Serif bold italic 24"

#else // LOAD_GFXFF not defined so setup defaults to prevent error messages

    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    // Free fonts are not loaded in User_Setup.h so we must define all as font 1
    // to prevent compile error messages
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    #define GFXFF 1
    #define GLCD  1
    #define FONT2 2
    #define FONT4 4
    #define FONT6 6
    #define FONT7 7
    #define FONT8 8

    #define FF0 1
    #define FF1 1
    #define FF2 1
    #define FF3 1
    #define FF4 1
    #define FF5 1
    #define FF6 1
    #define FF7 1
    #define FF8 1
    #define FF9 1
    #define FF10 1
    #define FF11 1
    #define FF12 1
    #define FF13 1
    #define FF14 1
    #define FF15 1
    #define FF16 1
    #define FF17 1
    #define FF18 1
    #define FF19 1
    #define FF20 1
    #define FF21 1
    #define FF22 1
    #define FF23 1
    #define FF24 1
    #define FF25 1
    #define FF26 1
    #define FF27 1
    #define FF28 1
    #define FF29 1
    #define FF30 1
    #define FF31 1
    #define FF32 1
    #define FF33 1
    #define FF34 1
    #define FF35 1
    #define FF36 1
    #define FF37 1
    #define FF38 1
    #define FF39 1
    #define FF40 1
    #define FF41 1
    #define FF42 1
    #define FF43 1
    #define FF44 1
    #define FF45 1
    #define FF46 1
    #define FF47 1
    #define FF48 1

    #define FM9  1
    #define FM12 1
    #define FM18 1
    #define FM24 1

    #define FMB9  1
    #define FMB12 1
    #define FMB18 1
    #define FMB24 1

    #define FMO9  1
    #define FMO12 1
    #define FMO18 1
    #define FMO24 1

    #define FMBO9  1
    #define FMBO12 1
    #define FMBO18 1
    #define FMBO24 1

    #define FSS9  1
    #define FSS12 1
    #define FSS18 1
    #define FSS24 1

    #define FSSB9  1
    #define FSSB12 1
    #define FSSB18 1
    #define FSSB24 1

    #define FSSO9  1
    #define FSSO12 1
    #define FSSO18 1
    #define FSSO24 1

    #define FSSBO9  1
    #define FSSBO12 1
    #define FSSBO18 1
    #define FSSBO24 1

    #define FS9  1
    #define FS12 1
    #define FS18 1
    #define FS24 1

    #define FSI9  1
    #define FSI12 1
    #define FSI19 1
    #define FSI24 1

    #define FSB9  1
    #define FSB12 1
    #define FSB18 1
    #define FSB24 1

    #define FSBI9  1
    #define FSBI12 1
    #define FSBI18 1
    #define FSBI24 1

#endif // LOAD_GFXFF

DHT12.cpp

Arduino
sensor unit ENVI
/*
	DHT12.cpp - Library for DHT12 sensor.
	v0.0.1 Beta
	Created by Bobadas, July 30,2016.
	Released into the public domain.
*/
#include "DHT12.h"

DHT12::DHT12(uint8_t scale,uint8_t id)
{
	if (id==0 || id>126) _id=0x5c;
	else _id=id;
	if (scale==0 || scale>3) _scale=CELSIUS;
	else _scale=scale;
}

uint8_t DHT12::read()
{
	Wire.beginTransmission(_id);
	Wire.write(0);
	if (Wire.endTransmission()!=0) return 1;  
	Wire.requestFrom(_id, (uint8_t)5);
	for (int i=0;i<5;i++) {
		datos[i]=Wire.read();
	};
	delay(50);
	if (Wire.available()!=0) return 2;
	if (datos[4]!=(datos[0]+datos[1]+datos[2]+datos[3])) return 3;
	return 0;
}

float DHT12::readTemperature(uint8_t scale)
{
	float resultado=0;
	uint8_t error=read();
	if (error!=0) return (float)error/100;
	if (scale==0) scale=_scale;
	switch(scale) {
		case CELSIUS:
			resultado=(datos[2]+(float)datos[3]/10);
			break;
		case FAHRENHEIT:
			resultado=((datos[2]+(float)datos[3]/10)*1.8+32);
			break;
		case KELVIN:
			resultado=(datos[2]+(float)datos[3]/10)+273.15;
			break;
	};
	return resultado;
}

float DHT12::readHumidity()
{
	float resultado;
	uint8_t error=read();
	if (error!=0) return (float)error/100;
	resultado=(datos[0]+(float)datos[1]/10);
	return resultado;
}

DHT12.h

Arduino
header sensor unit ENVI
/*
	DHT12.h - Library for DHT12 sensor.
	v0.0.1 Beta
	Created by Bobadas, July 30,2016.
	Released into the public domain.
*/
#ifndef DHT12_h 
#define DHT12_h 
#include "Arduino.h"
#include "Wire.h"

#define CELSIUS		1
#define KELVIN		2
#define FAHRENHEIT	3

class DHT12
{
	public:
		DHT12(uint8_t scale=0,uint8_t id=0);
		float readTemperature(uint8_t scale=0);
		float readHumidity();
	private:
		uint8_t read();
		uint8_t datos[5];
		uint8_t _id;
		uint8_t _scale;
};

#endif

Credits

KeHoSoftware

KeHoSoftware

2 projects • 6 followers

Comments