Hardware components | ||||||
![]() |
| × | 1 | |||
![]() |
| × | 2 | |||
| × | 1 | ||||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
![]() |
| |||||
![]() |
|
In today’s article, we are going to build a Matrix LoRa MQTT Gateway with your Wio Terminal ! This project sets up Wio Terminal as a LoRa gateway, but also it acts as a own SensorNode via the MQTT protocol too.
To demonstrate the function and features of this gateway you can build a small SensorNode with a Seeed Xiao and some Grove actors and sensors.
The Wio Terminal is a SAMD51-based microcontroller with Wireless Connectivity supported by Realtek RTL8720DN that’s compatible with Arduino and MicroPython. It runs at 120MHz (Boost up to 200MHz), 4MB External Flash and 192KB RAM. It supports both Bluetooth and Wi-Fi providing backbone for IoT projects. The Wio Terminal itself is equipped with a 2.4” LCD Screen, onboard IMU(LIS3DHTR), Microphone, Buzzer, microSD card slot, Light sensor, and Infrared Emitter(IR 940nm). On top of that, it also has two multifunctional Grove ports for Grove Ecosystem and 40 Raspberry pi compatible pin GPIO for more add-ons. More info in SeeedStudio page.
LoRa is a Long-Range radio technology developed by Semtech.
Here is a definition from Semtech's LoRa FAQ:
LoRa (Long Range) is a modulation technique that provides significantly longer range than competing technologies. The modulation is based on spread-spectrum techniques and a variation of chirp spread spectrum (CSS) with integrated forward error correction (FEC). LoRa significantly improves the receiver sensitivity and as with other spread‐spectrum modulation techniques, uses the entire channel bandwidth to broadcast a signal, making it robust to channel noise and insensitive to frequency offsets caused from the use of low cost crystals. LoRa can demodulate signals 19.5dB below the noise floor while most frequency shift keying systems (FSK) need a signal power of 8-10dB above the noise floor to demodulate properly. The LoRa modulation is the physical layer (PHY), which can be utilized with different protocols and in different network architecture – Mesh, Star, point to point, etcetera.
You can read this article for more information.
Features of this projectWio Terminal acts as a LoRa MQTT Gateway and MQTT SensorNode. All messages received (JSON) via LoRa will be send to your MQTT broker. With tools like Node-Red, InfluxDB and Grafana - you can visualize, react, transform this data later.
The inbuild sensors - light and sound - and the external connected DHT11 are used to establish beside your gateway - a full functional MQTT SensorNode. With help of the sound sensor your are able to wake up the screen saver too.
The user programmable buttons are used as:
Button 1 > send sensor data to your MQTT broker
[>] Message:{"node": "LoRa_MQTT_Gateway","H":44,"T":22,"N":1,"L":0}
Button 2 > display SensorNode Data
Button 3 > screen saver on/off
You can configure all setups in config_lora.txt on your SD card.
We provide a UF2 file if you prefer easy flashing and no coding and compiling.
The XIAO SensorNode demonstrates the use case of your Wio Terminal.
Our Wio Terminal LoRa MQTT Gateway is very easy to set up.
The Seeed Studio Grove - LoRa Radio 868MHz connects to the left multi-function GROVE connector and the Seeed Studio Grove - DHT11 sensor to the right multi-function GROVE connector.
All done with the help of Serial Communication Interfaces (SERCOM) which allows the easy connection of the LoRa module to the left GROVE port. (i2c).
If you like - you can print a nice stand-up with the provided STL file.
For demonstration use - you can also easy build up an XIAO SensorNode.
Please connect the LoRa Radio to TX/RX D6 D7, the VOC eCO2 sensor and bme280 sensor to a I2C port, the chainable LED to D1 D2 and finally the pir sensor to D0.
The XIAO LoRa SensorNode looks then like this for example.
The Source Code of our Wio Terminal LoRa MQTT Gateway and the XIAO SensorNode is coded with the new Arduino 2.0 IDE - well documented - and shows DEBUG infos to every step we make.
https://docs.arduino.cc/software/ide-v2/tutorials/getting-started-ide-v2
lora_config.txt
WifiSSID=yourwifissid
WifiPASS=yourwifipassword
MQTTSERVER=ip
MQTTPORT=1883
MQTTUSER=user
MQTTPASSWORD=password
MQTTSUBSCRIBE=wio/terminal
MQTTPUBLISH=dragino
LORAFREQ=868
MICTRIGGER=320
Also you have to copy two JPG pictures - iot.jpg and matrix.jpg on your SD card.
Booting the systemFor easy use we provide also a UF2 file which you can easy drag and drop to your Wio Terminal in boot mode.
If you have flashed our software to your Wio Terminal you should see this:
Starting...
WioTerminal_05_LoRa_MQTT_Gateway Version 1.12
connected via LORA WIFI WLAN MQTT
[x] SD Card init OK
[?] Read configuration file from SD
[x] read out settings from file config_lora.txt
[?] WifiSSID: xxx
[?] WifiPASS: xxx
[?] MQTTSERVER: 192.168.178.xxx
[?] MQTTPORT: 1883
[?] MQTTUSER: admin
[?] MQTTPASSWORD: admin
[?] MQTTSUBSCRIBE: wio/terminal
[?] MQTTPUBLISH: dragino
[?] LORAFREQ: 868
[?] MICTRIGGER: 320
[x] Configuration file loaded
[x] load and display picture - iot.jpg
[x] load and display picture - matrix.jpg
[x] initialize inbuild sensors, joystick, buttons and buzzer
[x] initialize pinPeripheral SCL and SCA
[x] GROVE DHT Sensor connected
[?] GROVE DHT --> T:22 H:42
[?] RPC-System-Firmware-Version: 2.1.3
[?] Connecting to your Wi-Fi
[x] Wi-Fi connected
[x] IP: 192.168.178.xx
[?] Connecting to your MQTT Broker
[x] MQTT Broker connected
[?] LoRa RF95 server init
[>] Waiting until receiving LoRa or MQTT packet
[x] TFT display OFF
[>] got request: {"node": "Xiao_01_LoRa_Node","C":17,"bme280_pressure":1005,"bme280_humidity":43,"bme280_temperature":22,"SGP30_eCO2":623,"SGP30_VOC":492,"pir_motion":0}
[x] sending sensor data to mqtt broker
[x] Noise detected
[?] Span: 638
[x] noise-counter: 1
[x] TFT display ON
Enjoy your Matrix LoRa MQTT Gateway - greetings Achim Kern KeHoSoftware
/****************************************************************************
** **
** Name: WioTerminal_05_LoRaWan_MQTT_Gateway **
** Author: Achim Kern **
** Interpreter: Arduino IDE 2.0.4 MacOS **
** Licence: Freeware **
** Function: Main Program **
** **
** Notes: based on idea from SEEED STUDIO and LCARS SmartHome **
** **
** History: **
** **
** 1.00 - 01.11.2021 - initial release **
** - LoRa working **
** - MQTT secured server now working **
** 1.01 - 06.05.2022 - Grove LoRa modul to the left Grove port **
** - (I2C Grove) **
** - secure MQTT Broker on Synology NAS **
** - code optimized from GPS Tracker **
** 1.02 - 10.01.2023 - config_lora.txt on SD card **
** 1.03 - 11.01.2023 - LoRa frequency from SD card **
** 1.04 - 12.01.2023 - MATRIX Graphics and ShowMessages **
** 1.05 - 12.01.2023 - SERIALDEBUG **
** 1.06 - 12.01.2023 - Wio inbuild 3 buttons - TFT screen on /off **
** 1.07 - 13.01.2023 - TFT screen off after 60 secs **
** 1.08 - 13.01.2023 - DHT11 sensor - Wio Terminal SensorNode **
** 1.09 - 14.01.2023 - Wio inbuild sound mic sensor **
** 1.10 - 16.01.2023 - sound mic trigger on SD card **
** - Wio inbuild light sensor **
** 1.11 - 17.01.2023 - screen display connected sensors **
** 1.12 - 07.02.2023 - MQTT problem solving **
** - hackster.io version **
** **
****************************************************************************/
/*
* Application and Version
*/
const char* application = "WioTerminal_05_LoRa_MQTT_Gateway";
const char* aktu_version = "1.12";
/*
* DEBUG:
* If the following line is uncommented, messages are being printed out to the
* serial connection for debugging purposes. When using the Arduino Integrated
* Development Environment (Arduino IDE), these messages are displayed in the
* Serial Monitor selecting the proper port and a baudrate of 115200.
*
*/
#define SERIALDEBUG
#ifdef SERIALDEBUG
#define SERIALDEBUG_PRINT(...) Serial.print(__VA_ARGS__)
#define SERIALDEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
#define SERIALDEBUG_PRINT(...)
#define SERIALDEBUG_PRINTLN(...)
#endif
/*
* RF95, WiFi and MQTT libs
*
*/
// we need these libraries
#include <wiring_private.h>
#include "rpcWiFi.h"
#include "PubSubClient.h"
#include "ArduinoJson.h"
/*
* WiFi and MQTT clients
*
*/
WiFiClient mqttClient;
PubSubClient MQTT(mqttClient);
/*
* WIO Terminal TFT Display and SD card
*
*/
#include <SPI.h>
#include <Seeed_FS.h>
#include <SD/Seeed_SD.h>
#include <SDConfigFile.h>
File myFile;
int BUFSIZE;
const char CONFIG_FILE[] = "config_lora.txt";
boolean readConfiguration();
boolean didReadConfig;
// WIO Terminal SD Card
char* sd_ssid;
char* sd_password;
char* sd_mqttServer;
int sd_mqttPort;
char* sd_mqttUser;
char* sd_mqttPassword;
char* sd_TOPIC_SUBSCRIBE;
char* sd_TOPIC_PUBLISH;
int sd_lora_freq;
int sd_mic_trigger;
// Wio Terminal TFT display
#include "Free_Fonts.h"
#include <LGFX_TFT_eSPI.hpp>
static TFT_eSPI tft;
// pictures on the sd card
String iot_picture="";
// Control Pin of LCD
#define LCD_BACKLIGHT (72Ul)
bool tft_backlight = true;
// sleeping counter
int tft_counter = 0;
// sending counter
int MQTT_counter = 0;
// room or sensor display
int aktu_room = 1;
int max_room = 1;
/*
* LoRa Modul
* Grove LoRa module can be connected on the back (Hardware Serial is required to use the Grove LoRa module)
* Also with the help of Serial Communication Interfaces (SERCOM) you can easily connect the Grove LoRa module
* to the left Grove port. (i2c Grove) - actual used
*
*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#include <RH_RF95.h>
static Uart Serial3(&sercom3, PIN_WIRE_SCL, PIN_WIRE_SDA, SERCOM_RX_PAD_1, UART_TX_PAD_0);
RH_RF95 <Uart> rf95(Serial3);
#endif
/*
* Wio Terminal inbuild Buzzer
* ---------------------------
*/
// Wio Buzzer
// sig pin of the buzzer
#define BUZZER_PIN WIO_BUZZER
// the number of notes
int length = 15;
char notes[] = "ccggaagffeeddc ";
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;
/*
* Wio Terminal inbuild Sound Sensor
* ---------------------------------
*/
int mic_level = 0;
int mic_trigger = 300;
long int mic_counter = 0;
#define MicSamples (1024*2)
/*
* Wio Terminal inbuild Light Sensor
* ---------------------------------
*/
int light;
uint8_t light_percentage;
/*
* Wio Terminal inbuild LED
* ------------------------
*/
int led = 13;
/*
* GROVE DHT11 Sensor (blue)
* -------------------------
* This Temperature&Humidity sensor provides a pre-calibrated digital output.
* A unique capacitive sensor element measures relative humidity and the temperature
* is measured by a negative temperature coefficient (NTC) thermistor.
* It has excellent reliability and long term stability.
* Please note that this sensor will not work for temperatures below 0 degree.
*
*/
// Enable/disable sensor measurements if you want to
#define ENABLE_SENSOR_DHT
// Sensors enabled, but not found in the hardware will be ignored
#ifdef ENABLE_SENSOR_DHT
// we need library
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
// signal pin of your dht11 sensor
#define DHT_PIN 0
// type of sensor (dht11=blue, dht22=white)
#define DHTTYPE DHT11
// intialize sensor
DHT_Unified dht(DHT_PIN, DHTTYPE);
uint32_t delayMS;
int grove_dht_temp = 0;
int grove_dht_humi = 0;
/*-----------------------------------------*/
/* Function void sensor_dht() */
/* */
/* TASK : read out dht sensor data */
/* UPDATE : 28.08.2020 */
/*-----------------------------------------*/
void sensor_dht()
{
delay(delayMS);
// Get temperature event and print its value
sensors_event_t event;
dht.temperature().getEvent(&event);
if (isnan(event.temperature))
{
SERIALDEBUG_PRINTLN(F("[!] Error reading DHTxx temperature!"));
}
else
{
grove_dht_temp = event.temperature;
}
// Get humidity event and print its value.
dht.humidity().getEvent(&event);
if (isnan(event.relative_humidity))
{
SERIALDEBUG_PRINTLN(F("[!] Error reading DHTxx humidity!"));
}
else
{
grove_dht_humi= event.relative_humidity+18;
}
}
#endif
/*
* list of functions used
*
*/
/* 01 */ boolean readConfiguration();
/* 02 */ void init_wifi(void);
/* 03 */ void connect_wifi(void);
/* 04 */ void verify_wifi(void);
/* 05 */ void init_mqtt(void);
/* 06 */ void connect_mqtt(void);
/* 07 */ void verify_mqtt(void);
/* 08 */ void mqtt_callback(char* topic, byte* payload, unsigned int length);
/* 09 */ void ShowMessage(String msg, int Cursor);
/* 10 */ void LCD();
/* 11 */ void TransmitData();
/* 12 */ void tft_display_room_screen(String room_name, long int room_bg);
/* 13 */ void tft_display_status_bar(String room_name, long int room_bg);
/* 14 */ void tft_display_sensor_temperature(int temperature);
/* 15 */ void tft_display_sensor_humidity(int humidity);
/* 16 */ void tft_display_sensor_noise(int noise);
/* 17 */ void tft_display_sensor_lux(int lux);
/* 18 */ void tft_display_wioterminal(void);
/* 19 */ void tft_display_matrix(void);
void setup();
void loop();
/*
* 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 lorawan data send frequence
unsigned long previousMillis = 0;
// send every 10 minutes
// unsigned long interval = 600000;
// send every 3 minutes
// unsigned long interval = 180000;
// send every 30 seconds
unsigned long interval = 30000;
unsigned long counter = 0;
/*-------------------------------------------------------------------------------*/
/* (01) Function boolean readConfiguration() */
/* */
/* TASK : read your config.txt file from the SD Card */
/* UPDATE : 29.04.2022 */
/*-------------------------------------------------------------------------------*/
boolean readConfiguration()
{
const uint8_t CONFIG_LINE_LENGTH = 127;
SDConfigFile cfg;
// Open the configuration file.
if (!cfg.begin(CONFIG_FILE, CONFIG_LINE_LENGTH))
{
SERIALDEBUG_PRINT("[x] Failed to open configuration file: ");
SERIALDEBUG_PRINT(CONFIG_FILE);
SERIALDEBUG_PRINT(F("\n"));
return false;
}
SERIALDEBUG_PRINT("[x] read out settings from file ");
SERIALDEBUG_PRINT(CONFIG_FILE);
SERIALDEBUG_PRINT("\n\n");
// Read each setting from the file.
while (cfg.readNextSetting())
{
if (cfg.nameIs("WifiSSID"))
{
sd_ssid = cfg.copyValue();
SERIALDEBUG_PRINT("[?] WifiSSID: ");
SERIALDEBUG_PRINTLN(sd_ssid);
}
else if (cfg.nameIs("WifiPASS"))
{
sd_password = cfg.copyValue();
SERIALDEBUG_PRINT("[?] WifiPASS: ");
SERIALDEBUG_PRINTLN(sd_password);
}
else if (cfg.nameIs("MQTTSERVER"))
{
sd_mqttServer = cfg.copyValue();
SERIALDEBUG_PRINT("[?] MQTTSERVER: ");
SERIALDEBUG_PRINTLN(sd_mqttServer);
}
else if (cfg.nameIs("MQTTPORT"))
{
sd_mqttPort = cfg.getIntValue();
SERIALDEBUG_PRINT("[?] MQTTPORT: ");
SERIALDEBUG_PRINTLN(String(sd_mqttPort));
}
else if (cfg.nameIs("MQTTUSER"))
{
sd_mqttUser = cfg.copyValue();
SERIALDEBUG_PRINT("[?] MQTTUSER: ");
SERIALDEBUG_PRINTLN(sd_mqttUser);
}
else if (cfg.nameIs("MQTTPASSWORD"))
{
sd_mqttPassword = cfg.copyValue();
SERIALDEBUG_PRINT("[?] MQTTPASSWORD: ");
SERIALDEBUG_PRINTLN(sd_mqttPassword);
}
else if (cfg.nameIs("MQTTSUBSCRIBE"))
{
sd_TOPIC_SUBSCRIBE = cfg.copyValue();
SERIALDEBUG_PRINT("[?] MQTTSUBSCRIBE: ");
SERIALDEBUG_PRINTLN(sd_TOPIC_SUBSCRIBE);
}
else if (cfg.nameIs("MQTTPUBLISH"))
{
sd_TOPIC_PUBLISH = cfg.copyValue();
SERIALDEBUG_PRINT("[?] MQTTPUBLISH: ");
SERIALDEBUG_PRINTLN(sd_TOPIC_PUBLISH);
}
else if (cfg.nameIs("LORAFREQ"))
{
sd_lora_freq = cfg.getIntValue();
SERIALDEBUG_PRINT("[?] LORAFREQ: ");
SERIALDEBUG_PRINTLN(String(sd_lora_freq));
}
else if (cfg.nameIs("MICTRIGGER"))
{
sd_mic_trigger = cfg.getIntValue();
SERIALDEBUG_PRINT("[?] MICTRIGGER: ");
SERIALDEBUG_PRINTLN(String(sd_mic_trigger));
mic_trigger=sd_mic_trigger;
}
else
{
// report unrecognized names
SERIALDEBUG_PRINT("[?] Unknown name in config: ");
SERIALDEBUG_PRINTLN(cfg.getName());
}
}
// clean up
cfg.end();
SERIALDEBUG_PRINTLN("");
return true;
}
/*-------------------------------------------------------------------------------*/
/* (02) Function void init_wifi(void) */
/* */
/* TASK : do not provide a wifi hotspot */
/* UPDATE : 30.08.2020 */
/*-------------------------------------------------------------------------------*/
void init_wifi(void)
{
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(2000);
}
/*-------------------------------------------------------------------------------*/
/* (03) Function void connect_wifi(void) */
/* */
/* TASK : connect to your WiFi */
/* UPDATE : 30.08.2020 */
/*-------------------------------------------------------------------------------*/
void connect_wifi(void)
{
/* are we already connect to wifi */
if (WiFi.status() == WL_CONNECTED)
return;
SERIALDEBUG_PRINTLN("[?] Connecting to your Wi-Fi");
ShowMessage("Connecting to your Wi-Fi", 196);
delay(1000);
WiFi.begin(sd_ssid, sd_password);
while (WiFi.status() != WL_CONNECTED)
{
delay(100);
// Serial.print(".");
}
SERIALDEBUG_PRINTLN("[x] Wi-Fi connected");
SERIALDEBUG_PRINT("[x] IP: ");
SERIALDEBUG_PRINTLN(WiFi.localIP());
SERIALDEBUG_PRINTLN("");
ShowMessage("Wi-Fi connected", 196);
delay(1000);
}
/*-------------------------------------------------------------------------------*/
/* (04) Function void verify_wifi(void) */
/* */
/* TASK : check if WiFi connection is stable */
/* UPDATE : 30.08.2020 */
/*-------------------------------------------------------------------------------*/
void verify_wifi(void)
{
connect_wifi();
}
/*-------------------------------------------------------------------------------*/
/* (05) Function void init_mqtt(void) */
/* */
/* TASK : init your MQTT broker */
/* UPDATE : 30.08.2020 */
/*-------------------------------------------------------------------------------*/
void init_mqtt(void)
{
MQTT.setServer(sd_mqttServer, sd_mqttPort);
MQTT.setCallback(mqtt_callback);
}
/*-------------------------------------------------------------------------------*/
/* (06) Function void connect_mqtt(void) */
/* */
/* TASK : connect to your MQTT broker */
/* UPDATE : 30.08.2020 */
/*-------------------------------------------------------------------------------*/
void connect_mqtt(void)
{
while (!MQTT.connected())
{
SERIALDEBUG_PRINTLN("[?] Connecting to your MQTT Broker");
ShowMessage("Connecting to your MQTT Broker", 196);
delay(1000);
char *user = sd_mqttUser;
char *password = sd_mqttPassword;
if (MQTT.connect("LoRaMQTTGateway", user, password))
{
SERIALDEBUG_PRINTLN("[x] MQTT Broker connected");
SERIALDEBUG_PRINTLN("");
ShowMessage("MQTT Broker connected", 196);
delay(500);
MQTT.subscribe(sd_TOPIC_SUBSCRIBE);
}
else
{
SERIALDEBUG_PRINT("[!] MQTT failed with state ");
SERIALDEBUG_PRINTLN(String(MQTT.state()));
delay(2000);
}
}
}
/*-------------------------------------------------------------------------------*/
/* (07) Function void verify_mqtt(void) */
/* */
/* TASK : check if MQTT connection is stable */
/* UPDATE : 30.08.2020 */
/*-------------------------------------------------------------------------------*/
void verify_mqtt(void)
{
connect_mqtt();
}
/*------------------------------------------------------------------------------------*/
/* (08) Function void mqtt_callback(char* topic, byte* payload, unsigned int length) */
/* */
/* TASK : setup all needed requirements */
/* UPDATE : 30.08.2020 */
/*------------------------------------------------------------------------------------*/
void mqtt_callback(char* topic, byte* payload, unsigned int length)
{
SERIALDEBUG_PRINT("[>] Message arrived in topic: ");
SERIALDEBUG_PRINTLN(topic);
SERIALDEBUG_PRINT("[>] Message:");
for(int i = 0; i < length; i++)
{
SERIALDEBUG_PRINT(String((char)payload[i]));
}
SERIALDEBUG_PRINTLN("");
char p[length + 1];
memcpy(p, payload, length);
p[length] = NULL;
String message(p);
// Parse the command payload if json (V6)
StaticJsonDocument<200> doc;
#ifdef SERIALDEBUG
deserializeJson(doc, (char*)payload);
SERIALDEBUG_PRINT("[x] Command received:");
serializeJson(doc, Serial);
SERIALDEBUG_PRINTLN("");
#endif
if (aktu_room==1) { ShowMessage(p, 196); }
}
/*-------------------------------------------------------------------------------*/
/* (09) Function void ShowMessage(String msg, int Cursor) */
/* */
/* TASK : display a short message on the WioTerminal TFT screen */
/* UPDATE : 29.04.2022 */
/*-------------------------------------------------------------------------------*/
void ShowMessage(String msg, int Cursor)
{
tft.setTextColor(TFT_GREEN,TFT_BLACK);
tft.setCursor(0, Cursor);
tft.print(" ");
tft.print(" ");
tft.print(" ");
tft.setCursor((320 - tft.textWidth(msg))/2, Cursor);
tft.print(" ");
tft.print(msg);
}
/*-------------------------------------------------------------------------------*/
/* (10) Function void LCD() */
/* */
/* TASK : switch LCD on or off */
/* UPDATE : 14.10.2022 */
/*-------------------------------------------------------------------------------*/
void LCD()
{
tft_backlight = !tft_backlight;
// Turning off the LCD backlight
if (tft_backlight == false)
{ digitalWrite(LCD_BACKLIGHT, LOW);
tft.setBrightness(0);
SERIALDEBUG_PRINT("TFT display OFF\n\r");
}
// Turning on the LCD backlight
if (tft_backlight == true)
{
digitalWrite(LCD_BACKLIGHT, HIGH);
tft.setBrightness(255);
SERIALDEBUG_PRINT("TFT display ON\n\r"); }
}
/*-------------------------------------------------------------------------------*/
/* (11) Function void TransmitData() */
/* */
/* TASK : transmit your sensor data to TTN V3 console */
/* UPDATE : 14.10.2022 */
/*-------------------------------------------------------------------------------*/
void TransmitData()
{
// tft.fillScreen(TFT_BLACK);
SERIALDEBUG_PRINTLN(F("[x] load and display picture - iot.jpg"));
tft.drawJpgFile(SD, "iot.jpg");
delay(1000);
// read out all available sensors
SERIALDEBUG_PRINTLN(F(""));
SERIALDEBUG_PRINTLN(F("[x] read out all available sensors"));
// Get the Wio Terminal inbuild mic value
SERIALDEBUG_PRINT(F("[?] WIO MIC inbuild >>> NoiseCounter:"));
SERIALDEBUG_PRINTLN(String(mic_level));
// Get the Wio Terminal inbuild light value
light = analogRead(WIO_LIGHT);
SERIALDEBUG_PRINT(F("[?] WIO LIGHT inbuild >>> AnalogRead:"));
SERIALDEBUG_PRINT(String(light));
// Light (Illuminance) level/percentage in greenhouse
light_percentage = map(light, 0, 1024, 0, 100);
SERIALDEBUG_PRINT(F(" Percentage:"));
SERIALDEBUG_PRINT(light_percentage);
SERIALDEBUG_PRINT(F("%\n"));
// create json msg
char textA[150] = "{\"node\": \"LoRa_MQTT_Gateway\"";
// sensor data
char array_sensor[1];
#ifdef ENABLE_SENSOR_DHT
// read the dht sensor */
sensor_dht();
SERIALDEBUG_PRINT(F("[?] GROVE DHT >>> "));
SERIALDEBUG_PRINT(F("T:")); SERIALDEBUG_PRINT(grove_dht_temp);
SERIALDEBUG_PRINT(F(" H:")); SERIALDEBUG_PRINTLN(grove_dht_humi);
// sensor humidity
sprintf(array_sensor, "%d", grove_dht_humi);
strcat(textA,",\"H\":");
strcat(textA,array_sensor);
// sensor temperature
sprintf(array_sensor, "%d", grove_dht_temp);
strcat(textA,",\"T\":");
strcat(textA,array_sensor);
#endif
// sensor wio inbuild sound mic
sprintf(array_sensor, "%d", mic_level);
strcat(textA,",\"N\":");
strcat(textA,array_sensor);
// sensor wio inbuild light
sprintf(array_sensor, "%d", light_percentage);
strcat(textA,",\"L\":");
strcat(textA,array_sensor);
// json end
strcat(textA,"}");
// show and publish sensor msg
SERIALDEBUG_PRINT("[>] Message:");
SERIALDEBUG_PRINTLN((char*)textA);
ShowMessage(textA,196);
MQTT.publish(sd_TOPIC_PUBLISH,textA);
SERIALDEBUG_PRINTLN(F("[x] Uplink to your MQTT broker done\n"));
mic_level=0;
aktu_room=1;
tft_display_matrix();
}
/*------------------------------------------------------------------------------------*/
/* (12) Function void tft_display_room_screen(String room_name, long int room_bg) */
/* */
/* TASK : show tft display room screen */
/* UPDATE : 22.09.2020 */
/* 08.01.2021 - room_name pos -22 */
/*------------------------------------------------------------------------------------*/
void tft_display_room_screen(String room_name, long int room_bg)
{
tft.fillScreen(TFT_WHITE);
tft.fillRect(0,0,320,50,room_bg);
tft.setFreeFont(FMB18);
tft.setTextColor(TFT_WHITE);
tft.setCursor((320 - tft.textWidth(room_name)) / 2, 32-22);
tft.print(room_name);
// drawing verticle line
tft.drawFastVLine(150,50,190,TFT_DARKGREEN);
// drawing horizontal line
tft.drawFastHLine(0,140,320,TFT_DARKGREEN);
}
/*-------------------------------------------------------------------------------------*/
/* (13) Function void tft_display_status_bar(String room_name, long int room_bg) */
/* */
/* TASK : show tft display status bar */
/* UPDATE : 22.09.2020 */
/* 08.01.2021 - room_name pos -22 */
/*-------------------------------------------------------------------------------------*/
void tft_display_status_bar(String room_name, long int room_bg)
{
tft.fillRect(0,0,320,50,room_bg);
tft.setFreeFont(FMB18);
tft.setTextColor(TFT_WHITE);
tft.setCursor((320 - tft.textWidth(room_name)) / 2, 32-22);
tft.print(room_name);
}
/*-------------------------------------------------------------------------------*/
/* (14) Function void tft_display_sensor_temperature(int temperature) */
/* */
/* TASK : show tft display sensor temperature */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_temperature(int temperature)
{
// setting the temperature
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Temperature",15,65);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
tft.drawNumber(temperature,50,95);
//tft.drawNumber(21,50,95);
tft.setFreeFont(FMB12);
tft.drawString("C",100,95);
}
/*-------------------------------------------------------------------------------*/
/* (15) 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
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Humidity",30,160);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
tft.drawNumber(humidity,50,190);
tft.setFreeFont(FMB12);
tft.drawString("%",100,190);
}
/*-------------------------------------------------------------------------------*/
/* (16) Function void tft_display_sensor_noise(int noise) */
/* */
/* TASK : show tft display sensor noise */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_noise(int noise)
{
// setting the voc
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Sounds",200,65);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
//tft.drawNumber(noise,160,95);
tft.drawNumber(noise,200,95);
//tft.setFreeFont(FMB12);
//tft.drawString("sum",250,95);
}
/*-------------------------------------------------------------------------------*/
/* (17) Function void tft_display_sensor_lux(int lux) */
/* */
/* TASK : show tft display sensor lux */
/* UPDATE : 22.09.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_sensor_lux(int lux)
{
// setting the luminance lux
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB9);
tft.drawString("Luminance",185,160);
tft.setTextColor(TFT_BLACK);
tft.setFreeFont(FMB18);
tft.drawNumber(lux,200,190);
tft.setFreeFont(FMB12);
tft.drawString("%",250,190);
}
/*-------------------------------------------------------------------------------*/
/* (18) Function void tft_display_wioterminal(void) */
/* */
/* TASK : show tft display wioterminal (own connected sensors) */
/* UPDATE : 30.11.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_wioterminal(void)
{
// display wioterminal screen
tft_display_room_screen("WioTerminal 5", TFT_DARKGREEN);
// display temperature sensor
#ifdef ENABLE_SENSOR_DHT
// read the dht sensor
sensor_dht();
tft_display_sensor_temperature(grove_dht_temp);
// display humidity sensor
tft_display_sensor_humidity(grove_dht_humi);
#endif
// display noise sensor
tft_display_sensor_noise(mic_level);
// display light sensor
light = analogRead(WIO_LIGHT);
// Light (Illuminance) level/percentage in greenhouse
light_percentage = map(light, 0, 1024, 0, 100);
tft_display_sensor_lux(light_percentage);
}
/*-------------------------------------------------------------------------------*/
/* (19) Function void tft_display_matrix(void) */
/* */
/* TASK : show tft display matrix (lora and mqtt connected sensors) */
/* UPDATE : 30.11.2020 */
/*-------------------------------------------------------------------------------*/
void tft_display_matrix(void)
{
// display matrix screen
tft.fillScreen(TFT_BLACK);
SERIALDEBUG_PRINTLN(F("[x] load and display picture - matrix.jpg"));
tft.drawJpgFile(SD, "matrix.jpg");
tft.setTextColor(TFT_GREEN);
tft.setFreeFont(FMB12);
tft.setCursor((320 - tft.textWidth("LoRa MQTT GATEWAY"))/2, 3);
tft.print("LoRa MQTT GATEWAY");
tft.setTextFont(0);
ShowMessage("Waiting until receiving LoRa or MQTT packet...", 196);
delay(1000);
SERIALDEBUG_PRINTLN("[>] Waiting until receiving LoRa or MQTT packet");
SERIALDEBUG_PRINTLN("");
}
/*-------------------------------------------------------------------------------*/
/* Functions void SERCOM3_x_Handler() */
/* */
/* TASK : Serial COM Handler */
/* UPDATE : 29.04.2022 */
/*-------------------------------------------------------------------------------*/
void SERCOM3_0_Handler()
{
Serial3.IrqHandler();
}
void SERCOM3_1_Handler()
{
Serial3.IrqHandler();
}
void SERCOM3_2_Handler()
{
Serial3.IrqHandler();
}
void SERCOM3_3_Handler()
{
Serial3.IrqHandler();
}
/*-------------------------------------------------------------------------------*/
/* Function void setup() */
/* */
/* TASK : setup all needed requirements */
/* UPDATE : 28.08.2020 */
/*-------------------------------------------------------------------------------*/
void setup()
{
// Serial baud rate
#ifdef SERIALDEBUG
Serial.begin(9600);
#endif
// boot application
delay(3000);
SERIALDEBUG_PRINTLN(F(" "));
SERIALDEBUG_PRINTLN(F(" "));
SERIALDEBUG_PRINTLN(F("Starting..."));
SERIALDEBUG_PRINT(F(application)); SERIALDEBUG_PRINT(F(" Version ")); SERIALDEBUG_PRINTLN(F(aktu_version));
SERIALDEBUG_PRINTLN(F("connected via LORA WIFI WLAN MQTT"));
SERIALDEBUG_PRINTLN(F(" "));
// Display Setup
tft.begin();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
//Initialise SD card
if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI))
{
SERIALDEBUG_PRINTLN("[!] SD Card init failed!");
ShowMessage("SD Card init FAILED", 196);
while (1);
}
SERIALDEBUG_PRINTLN("[x] SD Card init OK");
ShowMessage("SD Card init OK", 196);
delay(1000);
// read config file from sd card
SERIALDEBUG_PRINT(F("[?] Read configuration file from SD\n"));
ShowMessage("Read configuration file from SD", 196);
delay(1000);
didReadConfig = readConfiguration();
if (!didReadConfig)
{
SERIALDEBUG_PRINT(F("[!] Read configuration file FAILED!\n"));
while (1);
}
else
{
SERIALDEBUG_PRINT(F("[x] Configuration file loaded\n\n"));
ShowMessage("Configuration file loaded", 196);
}
delay(1000);
// display IoT picture
SERIALDEBUG_PRINTLN(F("[x] load and display picture - iot.jpg"));
tft.drawJpgFile(SD, "iot.jpg");
delay(2000);
tft.fillScreen(TFT_BLACK);
SERIALDEBUG_PRINTLN(F("[x] load and display picture - matrix.jpg"));
tft.drawJpgFile(SD, "matrix.jpg");
tft.setTextColor(TFT_GREEN);
tft.setFreeFont(FMB12);
tft.setCursor((320 - tft.textWidth("LoRa MQTT GATEWAY"))/2, 3);
tft.print("LoRa MQTT GATEWAY");
tft.setTextColor(TFT_YELLOW);
tft.setTextFont(0);
ShowMessage("CREATING THE MATRIX", 196);
delay(1000);
// Wio Terminal inbuild sensors and actors
pinMode(WIO_LIGHT,INPUT);
pinMode(BUZZER_PIN,OUTPUT);
pinMode(WIO_MIC,INPUT);
// Wio Terminal Joystick
pinMode(WIO_5S_PRESS,INPUT_PULLUP);
pinMode(WIO_5S_UP,INPUT_PULLUP);
pinMode(WIO_5S_DOWN,INPUT_PULLUP);
pinMode(WIO_5S_LEFT,INPUT_PULLUP);
pinMode(WIO_5S_RIGHT,INPUT_PULLUP);
// 3 Wio Terminal buttons
pinMode(WIO_KEY_A, INPUT_PULLUP);
pinMode(WIO_KEY_B, INPUT_PULLUP);
pinMode(WIO_KEY_C, INPUT_PULLUP);
SERIALDEBUG_PRINTLN("[x] initialize inbuild sensors, joystick, buttons and buzzer");
// LoRa Serial
pinPeripheral(PIN_WIRE_SCL, PIO_SERCOM_ALT);
pinPeripheral(PIN_WIRE_SDA, PIO_SERCOM_ALT);
SERIALDEBUG_PRINTLN("[x] initialize pinPeripheral SCL and SCA");
SERIALDEBUG_PRINTLN("");
delay(100);
#ifdef ENABLE_SENSOR_DHT
// start the dht sensor
dht.begin();
SERIALDEBUG_PRINT(F("[x] GROVE DHT Sensor connected\n"));
// read the dht sensor */
sensor_dht();
SERIALDEBUG_PRINT(F("[?] GROVE DHT --> "));
SERIALDEBUG_PRINT(F("T:")); SERIALDEBUG_PRINT(grove_dht_temp);
SERIALDEBUG_PRINT(F(" H:")); SERIALDEBUG_PRINTLN(grove_dht_humi);
SERIALDEBUG_PRINTLN("");
#endif
// connect to WiFi
SERIALDEBUG_PRINT(F("[?] RPC-System-Firmware-Version: "));
SERIALDEBUG_PRINTLN(F(rpc_system_version()));
init_wifi();
connect_wifi();
// connect to MQTT Broker secured
init_mqtt();
connect_mqtt();
delay(2000);
SERIALDEBUG_PRINTLN("[?] LoRa RF95 server init");
ShowMessage("LoRa RF95 server init", 196);
pinMode(led, OUTPUT);
if (!rf95.init())
{
SERIALDEBUG_PRINTLN("[!] LoRa R95 server init failed");
while (1);
}
// Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
// The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
//rf95.setTxPower(13, false);
// rf95.setFrequency(868.0);
rf95.setFrequency(sd_lora_freq);
ShowMessage("Waiting until receiving LoRa or MQTT packet...", 196);
delay(1000);
SERIALDEBUG_PRINTLN("[>] Waiting until receiving LoRa or MQTT packet");
SERIALDEBUG_PRINTLN("");
}
/*-------------------------------------------------------------------------------*/
/* Function void loop() */
/* */
/* TASK : this runs forever */
/* UPDATE : 28.08.2020 */
/* 08.01.2021 - backlight on/off no only works via brightness change */
/*-------------------------------------------------------------------------------*/
void loop()
{
// check if all connections are stable
verify_wifi();
verify_mqtt();
MQTT.loop();
//first we check noise level on the WIO inbuild MIC
long signalAvg = 0, signalMax = 0, signalMin = 1024, t0 = millis();
for (int i = 0; i < MicSamples; i++)
{
int k = analogRead(WIO_MIC);
signalMin = min(signalMin, k);
signalMax = max(signalMax, k);
signalAvg += k;
}
signalAvg /= MicSamples;
// if ((signalMax - signalMin) > 75)
if ((signalMax - signalMin) > mic_trigger)
{
SERIALDEBUG_PRINTLN("[x] Noise detected");
SERIALDEBUG_PRINTLN("[?] Span: " + String(signalMax - signalMin));
mic_level=mic_level+1;
SERIALDEBUG_PRINTLN("[x] noise-counter: " + String(mic_level));
...
This file has been truncated, please download it to see its full contents.
// 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
/****************************************************************************
** **
** Name: Xiao_01_LoRa_Node **
** Author: Achim Kern **
** Interpreter: Arduino IDE 2.0.4 - MacOS **
** Licence: Freeware **
** Function: Main Program **
** **
** Notes: based on idea from SEEED STUDIO and LCARS SmartHome **
** **
** History: **
** **
** 1.00 - 15.12.2022 - initial release **
** - GROVE LoRa R95 implemented **
** - code clearing **
** - BME280 sensor included **
** 1.01 - 19.12.2022 - JSON msg **
** 1.02 - 21.12.2022 - SGP30 Sensor implemented **
** 1.03 - 01.02.2023 - Node >> WioTerminal LoRa MQTT Gateway **
** 1.04 - 03.02.2023 - sensor libraries changed **
** - function SendData() included **
** 1.05 - 04.02.2023 - PIR sensor included **
** - chainable LED **
** **
****************************************************************************/
/*
* Application and Version
*/
const char* application = "Xiao_LoRa_Node";
const char* aktu_version = "1.04";
/*
* DEBUG:
* If the following line is uncommented, messages are being printed out to the
* serial connection for debugging purposes. When using the Arduino Integrated
* Development Environment (Arduino IDE), these messages are displayed in the
* Serial Monitor selecting the proper port and a baudrate of 115200.
*
*/
#define SERIALDEBUG
#ifdef SERIALDEBUG
#define SERIALDEBUG_PRINT(...) Serial.print(__VA_ARGS__)
#define SERIALDEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
#define SERIALDEBUG_PRINT(...)
#define SERIALDEBUG_PRINTLN(...)
#endif
/*
* LoRa Radio
* ----------------
* We have integrated the grove connector to most boards produced by Seeed to make them become a system.
* This time, we combined Grove with LoRa to provide an ultra-long-range wireless module for you.
* The main functional module in Grove - LoRa Radio 433MHz is RFM98,
* which is a transceiver features the LoRa long range modem that provides ultra-long range spread spectrum communication
* and high interference immunity whilst mini-missing current consumption.
* The heart of Grove - LoRa Radio 433MHz is ATmega168, a widely used chip with very high-performance and low power consumption,
* especially suitable for this grove module.
* There we already integrated a simple wire antenna to receive signal, if the signal is too weak to receive, dont worry,
* the MHF connector next to the antenna is for adding a second antenna which has MHF interface to gain more signal.
* This is the 433MHz version, which can be used for 433MHz communication.
* You can also find the version for 868MHz at Grove - LoRa Radio 868MHz.
* https://wiki.seeedstudio.com/Grove_LoRa_Radio/
*
*
*/
// Enable/disable actor if you want to
#define ENABLE_ACTOR_RF95_GROVE_LORAWAN
// Actors enabled, but not found in the hardware will be ignored
#ifdef ENABLE_ACTOR_RF95_GROVE_LORAWAN
// rf95_client.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messageing client
// with the RH_RF95 class. RH_RF95 class does not provide for addressing or
// reliability, so you should only use RH_RF95 if you do not need the higher
// level messaging abilities.
// It is designed to work with the Dragino LG01 LoRa-MQTT Server Gateway
// system libraries we need //
// #include <SoftwareSerial.h>
#include <RH_RF95.h>
#ifdef __AVR__
#include <SoftwareSerial.h>
SoftwareSerial SSerial(7, 6); // RX, TX
#define COMSerial SSerial
#define ShowSerial Serial
// Singleton instance of the radio driver on D5 connected
RH_RF95<SoftwareSerial> rf95(COMSerial);
#endif
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define COMSerial Serial1
#define ShowSerial SerialUSB
RH_RF95<Uart> rf95(COMSerial);
#endif
#ifdef ARDUINO_ARCH_STM32F4
#define COMSerial Serial
#define ShowSerial SerialUSB
RH_RF95<HardwareSerial> rf95(COMSerial);
#endif
int msg_nr=0;
#endif
/*
* Barometer sensor (BME280)
* -------------------------
* This sensor is a breakout board for Bosch BMP280 high-precision, low-power combined humidity, pressure, and temperature sensor.
* This module can be used to measure temperature, atmospheric pressure and humidity accurately and fast.
* As the atmospheric pressure changes with altitude, it can also measure approximate altitude of a place.
* https://github.com/adafruit/Adafruit_BME280_Library
*
*/
// Enable/disable sensor measurements if you want to
#define ENABLE_SENSOR_BME280
// Sensors enabled, but not found in the hardware will be ignored
#ifdef ENABLE_SENSOR_BME280
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10
#define SEALEVELPRESSURE_HPA (1013.25)
// Create the BME280 object on I2C
Adafruit_BME280 bme;
// BME280_I2C bme; // I2C using default 0x77
// or BME280_I2C bme(0x76); // I2C using address 0x76
int bme280_temperature = 0;
int bme280_humidity = 0;
int bme280_pressure = 0;
int bme280_altitude = 0;
/*-----------------------------------------*/
/* Function void sensor_bme280() */
/* */
/* TASK : read out bme280 sensor data */
/* UPDATE : 20.05.2020 */
/*-----------------------------------------*/
void sensor_bme280()
{
// read the bme280 sensor
bme280_pressure = (bme.readPressure() / 100.0F);
bme280_humidity = bme.readHumidity();
bme280_temperature = bme.readTemperature();
}
#endif
/*
* VOC & eCO2 Gas sensor (SGP30)
* -----------------------------
* The VOC and eCO2 Gas Sensor(SGP30) is an air quality detection sensor.
* We provide TVOC(Total Volatile Organic Compounds) and CO2eq output for this module.
* The SGP30 is a digital multi-pixel gas sensor designed for easy integration into air purifier,
* demand-controlled ventilation, and IoT applications.
* Sensirions CMOSenstechnology offers a complete sensor system on a single chip featuring a digital I2C interface,
* a temperature controlled micro hotplate, and two preprocessed indoor air quality signals.
* As the first metal-oxide gas sensor featuring multiple sensing elements on one chip,
* the SGP30 provides more detailed information about the air quality.
* https://github.com/sparkfun/SparkFun_SGP30_Arduino_Library
*
*/
// Enable/disable sensor measurements if you want to
#define ENABLE_SENSOR_SGP30
// Sensors enabled, but not found in the hardware will be ignored
#ifdef ENABLE_SENSOR_SGP30
#include <Wire.h>
#include "SparkFun_SGP30_Arduino_Library.h"
// create an object of the SGP30 class
SGP30 sgp30_sensor;
int sgp30_voc = 0;
int sgp30_co2 = 0;
/*-----------------------------------------*/
/* Function void sensor_sgp30() */
/* */
/* TASK : read out air sensor data */
/* UPDATE : 14.10.2020 */
/*-----------------------------------------*/
void sensor_sgp30()
{
sgp30_sensor.measureAirQuality();
sgp30_voc = sgp30_sensor.TVOC;
sgp30_co2 = sgp30_sensor.CO2;
}
#endif
/*
* PIR motion sensor
* -----------------------------
* This sensor allows you to sense motion, usually human movement in its range.
* Simply connect it to your Xiao and program it,
* when anyone moves in its detecting range,
* the sensor will output HIGH on its SIG pin.
* https://wiki.seeedstudio.com/Grove-PIR_Motion_Sensor/
*
*/
// 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 2
#define PIR_MOTION_SENSOR A0
bool MOTION = false;
int motion_counter = 0;
#endif
/*
* Chainable LED
* -------------
* Grove - Chainable RGB LED is based on P9813 chip which is a full-color LED driver.
* It provides 3 constant-current drivers as well as modulated output of 256 shades of gray.
* It communicates with a MCU using 2-wire transmission (Data and Clock).
* This 2-wire transmission can be used to cascade additional Grove - Chainable RGB LED modules.
* The built-in clock regeneration enhances the transmission distance.
* This Grove module is suitable for any colorful LED based projects.
* https://wiki.seeedstudio.com/Grove-Chainable_RGB_LED/
* https://github.com/pjpmarques/ChainableLED
*
*/
// Enable/disable actors if you want to
#define ENABLE_ACTOR_RGB_LED
// Sensors enabled, but not found in the hardware will be ignored
#ifdef ENABLE_ACTOR_RGB_LED
#include <ChainableLED.h>
// defines the num of LEDs used, The undefined
// will be lost control.
#define NUM_LEDS 1
// defines the pin used
ChainableLED leds(1, 2, NUM_LEDS);
#endif
/*
* Led inbuild or external
*/
int LED=13;
/*
* 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 lorawan data send frequence
unsigned long previousMillis = 0;
// send every 10 minutes
unsigned long interval = 600000;
// send every 3 minutes
// unsigned long interval = 180000;
// send every 30 seconds
// unsigned long interval = 30000;
unsigned long counter = 0;
/*-------------------------------------------------------------------------------*/
/* Function void SendData() */
/* */
/* TASK : send sensor data to your WioTerminal LoRa MQTT Gateway */
/* UPDATE : 03.02.2023 */
/*-------------------------------------------------------------------------------*/
void SendData()
{
// sending the data to the WioTerminal LoRa MQTT Gateway
SERIALDEBUG_PRINTLN("[x] Sending to WioTerminal LoRa MQTT Gateway");
// turn the LED on
digitalWrite(LED_BUILTIN, HIGH);
// LED blue
leds.setColorRGB(0, 0, 0, 255);
// Send a message to rf95_server - some possibilities
// unsigned char buffer[10] = {46,21,humidity, temperature};
// rf95.send(buffer, sizeof(buffer));
// uint8_t data[] = "N:12,C:12,L:100,P:1030,T:20,V:416,B:97";
// rf95.send(data, sizeof(data));
// build the sensor message - format from LCARS SmartHome sensors
// the required sensor entries
// the name of our node - change the number for needed type
// unsigned char textA[80] = "N:32";
// unsigned char textA[80] = "{\"32_node\":32,\"t\":21}";
char textA[150] = "{\"node\": \"Xiao_01_LoRa_Node\"";
// sensor counter
char array_counter[1];
counter++;
sprintf(array_counter, "%d", counter);
strcat(textA,",\"C\":");
strcat(textA,array_counter);
// sensor data
char array_sensor[1];
#ifdef ENABLE_SENSOR_BME280
// read the Bosch bme280 sensor
sensor_bme280();
// sensor barometer pressure
sprintf(array_sensor, "%d", bme280_pressure);
strcat(textA,",\"bme280_pressure\":");
strcat(textA,array_sensor);
// sensor humidity
sprintf(array_sensor, "%d", bme280_humidity);
strcat(textA,",\"bme280_humidity\":");
strcat(textA,array_sensor);
// sensor temperature
sprintf(array_sensor, "%d", bme280_temperature);
strcat(textA,",\"bme280_temperature\":");
strcat(textA,array_sensor);
#endif
// read the sgp30 sensor */
#ifdef ENABLE_SENSOR_SGP30
sensor_sgp30();
// sensor scd30
sprintf(array_sensor, "%d", sgp30_co2);
strcat(textA,",\"SGP30_eCO2\":");
strcat(textA,array_sensor);
sprintf(array_sensor, "%d", sgp30_voc);
strcat(textA,",\"SGP30_VOC\":");
strcat(textA,array_sensor);
#endif
#ifdef ENABLE_SENSOR_PIR_MOTION
sprintf(array_sensor, "%d", motion_counter);
strcat(textA,",\"pir_motion\":");
strcat(textA,array_sensor);
#endif
// json end
strcat(textA,"}");
SERIALDEBUG_PRINTLN((char*)textA);
// convert the message (new since xiao)
String OutPut=textA;
int a = strlen(textA)+1;
uint8_t data[a];
OutPut.toCharArray((char *)data, sizeof(data));
rf95.send(data, sizeof(data));
rf95.waitPacketSent();
// Now wait for a reply
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (rf95.waitAvailableTimeout(3000))
{
// Should be a reply message for us now
if(rf95.recv(buf, &len))
{
SERIALDEBUG_PRINT("[x] we got a reply: ");
SERIALDEBUG_PRINTLN((char*)buf);
}
else
{
SERIALDEBUG_PRINTLN("[!] recv failed");
}
}
else
{
SERIALDEBUG_PRINTLN("[!] No reply, is your WioTerminal LoRa MQTT Gateway online?");
}
delay(1000);
// turn the LED off
digitalWrite(LED_BUILTIN, LOW);
// RGB LED green
leds.setColorRGB(0, 0, 255, 0);
// motion couter to zero
motion_counter=0;
}
/*-------------------------------------------------------------------------------*/
/* Function void setup() */
/* */
/* TASK : setup all needed requirements */
/* UPDATE : 03.12.2017 */
/*-------------------------------------------------------------------------------*/
void setup()
{
Serial.begin(9600);
// boot application
delay(3000);
SERIALDEBUG_PRINTLN(" ");
SERIALDEBUG_PRINTLN(" ");
SERIALDEBUG_PRINTLN("Starting...");
SERIALDEBUG_PRINT(application); SERIALDEBUG_PRINT(" Version "); SERIALDEBUG_PRINTLN(aktu_version);
SERIALDEBUG_PRINTLN("connected to WioTerminal LoRa MQTT Gateway");
SERIALDEBUG_PRINTLN(" ");
// LED inbuild
pinMode(LED_BUILTIN, OUTPUT);
#ifdef ENABLE_ACTOR_RF95_GROVE_LORAWAN
// start the LoRa client
if (!rf95.init())
{
SERIALDEBUG_PRINTLN("[!] LoRa radio hardware client init failed!");
while(1);
}
// Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
// The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
// rf95.setTxPower(13, false);
rf95.setFrequency(868.0);
SERIALDEBUG_PRINTLN("[x] LoRa radio hardware client detected");
#endif
#ifdef ENABLE_SENSOR_BME280
if (!bme.begin(0x76))
{
SERIALDEBUG_PRINTLN("[!] Could not find a valid BME280 environment sensor, check wiring!");
while (1);
}
SERIALDEBUG_PRINTLN("[x] BME280 environment sensor detected");
// read the Bosch bme280 sensor
sensor_bme280();
SERIALDEBUG_PRINT("[?] BME280 --> ");
SERIALDEBUG_PRINT("P:"); SERIALDEBUG_PRINT(bme280_pressure);
SERIALDEBUG_PRINT(" H:"); SERIALDEBUG_PRINT(bme280_humidity);
SERIALDEBUG_PRINT(" T:"); SERIALDEBUG_PRINTLN(bme280_temperature);
#endif
#ifdef ENABLE_SENSOR_SGP30
Wire.begin();
if(sgp30_sensor.begin() == false)
{
SERIALDEBUG_PRINTLN("[!] SGP30 sensor initialisation failed!");
while (true); // Drop into endless loop requiring restart
}
sgp30_sensor.initAirQuality();
delay(1000);
SERIALDEBUG_PRINTLN("[x] SGP30 eCO2&VOC sensor detected");
sensor_sgp30();
SERIALDEBUG_PRINT("[?] SGP30 eCO2&VOC --> ");
SERIALDEBUG_PRINT("SGP30-eCO2:"); SERIALDEBUG_PRINT(sgp30_co2);
SERIALDEBUG_PRINT(" SGP30-VOC:"); SERIALDEBUG_PRINTLN(sgp30_voc);
#endif
#ifdef ENABLE_SENSOR_PIR_MOTION
// init Unit PIR
pinMode(PIR_MOTION_SENSOR, INPUT);
SERIALDEBUG_PRINTLN("[x] Initializing PIR Unit");
#endif
#ifdef ENABLE_ACTOR_RGB_LED
// RGB LED
leds.init();
SERIALDEBUG_PRINTLN("[x] Initializing RGB LED Unit");
leds.setColorRGB(0, 0, 255, 0);
#endif
// send first data to your WioTerminal LoRa MQTT Gateway - then every 10 minutes
SERIALDEBUG_PRINTLN(" ");
SERIALDEBUG_PRINTLN("[>] sending first sensor json data msg to your WioTerminal LoRa MQTT Gateway");
SERIALDEBUG_PRINTLN(" ");
SendData();
// now we wait until we have a trigger (motion) or time frame 10 minutes
SERIALDEBUG_PRINTLN(" ");
SERIALDEBUG_PRINTLN("[x] wait for trigger or time frame 10 minutes");
SERIALDEBUG_PRINTLN(" ");
}
/*-------------------------------------------------------------------------------*/
/* Function void loop() */
/* */
/* TASK : this runs forever */
/* UPDATE : 28.05.2020 */
/*-------------------------------------------------------------------------------*/
void loop()
{
#ifdef ENABLE_SENSOR_SGP30
// we have to read every one second to get a good baseline
sensor_sgp30();
delay(1000);
#endif
#ifdef ENABLE_SENSOR_PIR_MOTION
int sensorValue = digitalRead(PIR_MOTION_SENSOR);
// if the sensor value is HIGH we have an intruder ?
if(sensorValue == HIGH)
{
if (MOTION == false)
{
MOTION=true;
SERIALDEBUG_PRINTLN("[x] PIR MOTION detected ...");
// inbuild LED
digitalWrite(LED_BUILTIN, HIGH);
// RGB LED red
leds.setColorRGB(0, 255, 0, 0);
motion_counter++;
}
}
// if the sensor value is HIGH we have an intruder ?
if(sensorValue == LOW)
{
MOTION=false;
// LED OFF
digitalWrite(LED_BUILTIN, LOW);
leds.setColorRGB(0, 0, 255, 0);
}
#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();
// sending the data to the WioTerminal LoRa MQTT Gateway
SendData();
}
}
Comments