Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
|
M5Stack recently released an updated LoRaWAN module using a heltec cubecell chip based on the ASR6501. This chip can be programmed using Arduino IDE with AT-commands. You can find a list of supported commands at M5Stacks documentation page: https://docs.m5stack.com/#/en/module/comx_lorawan
The module supports two different modes: LoRa (point to point) and LoRaWAN. This project is about using LoRaWAN to connect the module to The Things Network - TTN (https://www.thethingsnetwork.org/).
This tutorial is based on the good prework from Philip Stewart.
He has done first steps with UI-Flow.
NEW in 2022 - we have updated source to Version 1.8
which can handle UNIT ENVIII, motion counter, new optimized payload
and TTN V3.
COM.LoRaWAN is a LoRaWAN communication module in the M5Stack stackable module series, supporting node-to-node or LoRaWAN communication. The LoRaWAN module based on ASR6501 encapsulates the PSoC4000 and SX1262 chips, supports the 868MHz frequency band, is based on an ultra-low power design, and consumes very low current (3.5μA) in deep sleep mode. In order to facilitate the user to configure the pins, the DIP switch is used to set the hardware serial port pins.
The user only needs to switch the corresponding pins to ON as needed and specify the pins in the program. A DC power socket is designed under the module, which can be powered by an external power supply, and an external antenna can be used to obtain better signal quality. This module is especially suitable for remote low-power transmission application scenarios with ultra-low power consumption and ultra-small size as the core requirements. Since LoRa defines the lower physical layer, the upper networking layers were lacking.
LoRaWAN was developed to define the upper layers of the network. LoRaWAN is a media access control (MAC) layer protocol but acts mainly as a network layer protocol for managing communication between LPWAN gateways and end-node devices as a routing protocol, maintained by the LoRa Alliance.You can upgrade your work with a LoRa / LoRaWAN radio, so it can communicate over very long distances and extremely low power consuming.
COM LoRaWAN serial port settings baud rate: 115200, stop bit: 1, data bit: 8, parity bit: none, terminator: none
COM.LoRaWAN RXD/TXD can be connected to M5Stack's UART (TX(0/13/17)RX(5/15/16)) by setting the DIP switch. Since these GPIO in M5Stack Fire 16/17 are connected to PSRAM by default. It is recommended to use any set of UART pins in the remaining two groups.
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 M5Stack Fire you should use 13/5, as all other settings can interfere with internals of the Fire.
Our SensorNode will use two M5Stack sensor units.
We will send environment data to the TTN from an ENVII or ENVIII unit.
The PIR unit will recognize motions and steer on/off our TFT LCD display.
I mounted the 2 sensors behind the M5Stack with the provided LEGO parts like on the picture from the M5GO IoT StarterKit. Looks and works pretty well.
ENV II is an environmental sensor which can sense temperature, humidity and atmospheric pressure. It integrates the SHT30 and BMP280 sensors and is programmed over the I2C protocol.
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.
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.
PIR is a human body infrared unit. It belongs to the "passive pyroelectric infrared detector". It detects the infrared radiation emitted and reflected by the human body or object. When infrared is detected, the output level is high and it takes a while. Delay (high during the period and allow repeated triggers) until the trigger signal disappears (restores low).
This Unit communicates with the M5Core via the GROVE B.
Notice: This Unit has 2s delay time.
Configuration of TTNFollow the device registration tutorial from TTN's website
https://www.thethingsindustries.com/docs
to create an account and register an app as well as the device.
In your application check Integrations. Please add Data Storage.
Next you should edit Payload Format Uplink (decoder).
Payload used in Version 1.03 (2021 TTN V2 Console)
function Decoder(bytes, port)
{
var temp = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16)) / 100;
var hum = (bytes[3] + (bytes[4] << 8) + (bytes[5] << 16)) / 100;
var pressure = (bytes[6] + (bytes[7] << 8) + (bytes[8] << 16)) / 100;
var battery = (bytes[9] + (bytes[10] << 8) + (bytes[11] << 16)) / 100;
var decoded = {};
decoded.temp = temp;
decoded.pressure = pressure;
decoded.hum = hum;
decoded.battery = battery;
return decoded;
}
Payload used in Version 1.08 (2022 TTN V3 Console)
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;
}
From that registration process you should now have three settings necessary for joining the TTN network: Device EUI, App Key and App EUI. Our Arduino software will save them into the COM.LoRaWAN chip.
Arduino IDE (used 1.8.19)Our Arduino source includes 10+ code files.
- M5Stack_TTN_SensorNode.ino
- AdafruitSensor.h
- Free_Fonts.h
- SHT3x.cpp
- SHT3x.h
- QMP6988.cpp
- QMP6988.h
- UNIT_ENV.h
- DHT12.cpp (ENVI)
- DHT12.h. (ENVI)
If you not already have done - please install correct M5Stack board.
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json
Also you should have installed library
M5Stack, Adafruit Unified Sensor, Adafruit BMP280, Adafruit Neopixel,
LovyanGFX - hopefully i have listed all...
Please change / edit in our M5Stack_TTN_SensorNode.ino setup()
the TTN access data.
Version 1.03 (2021 TTN V2 console)
// your TTN access data
ATCommand("DevEui", "XXXXXXXXXXXXXXXX");
delay(500);
ATCommand("AppEui", "XXXXXXXXXXXXXXXX");
delay(500);
ATCommand("AppKey", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
delay(500);
Version 1.08 (2022 TTN V3 console)
/*
* 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="xxxxxxxxx";
// (OTAA Mode)
// we got this from the TTN console - so we have to set on our chip
// TTN CONSOLE V3
// Node xx
char* AppEui="xxxxxxxxx";
// (OTAA Mode)
// we got this from the TTN console - so we have to set on our chip
// TTN CONSOLE V3
// Node xx
char* AppKey="xxxxxxxx";
The Software will flash your access codes in the setup() function to your LoRaWAN modul. In the setup() and loop() we use JPG pictures to show on the screen what is going on. Please copy the provided files (inside SD.zip) on a max. 8GB SD card.
Now it is time to flash the code to your device. Please use at first time your serial monitor to check all runs fine. The Node will send data every 10 minutes to the TTN. You can press button C to sent manually a sequence.
Press button A to handle display ON/OFF.
After 1 minute the display will go to sleep.
Motion detected with the PIR sensor will wake up your display.
Congratulations - you have now a nice TTN SensorNode online.
Now it would be a next good step to visualize your data with GRAFANA.
But this is another great story so far.
/****************************************************************************
** **
** 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();
}
/****************************************************************************
** **
** 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();
}
#ifndef _UNIT_ENV_H_
#define _UNIT_ENV_H_
#include "QMP6988.h"
#include "SHT3X.h"
#include "DHT12.h"
#endif
#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;
}
#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
#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;
}
#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
/*
* 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
// 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 - 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 - 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
Comments