To develop a wireless, low-power sensor system that would monitor indoor air quality, temperature, humidity and potential gas leaks in real time. The goal of the system is to provide data needed to optimize ventilation and heating, thereby saving energy and improving the health of residents (Green Deal).
Main functions:Environmental monitoring: Temperature (T), relative humidity (RH), barometric pressure (P).Air quality assessment (IAQ): Measurement of volatile organic compounds (VOC) and calculation of IAQ index (using BME680 BSEC algorithm).Gas leak/smoke detection: Emergency detection of flammable gases and smoke (MQ2).Data transmission: Data transmission via LoRaWAN network to the cloud platform.
Software and Components1. Programming EnvironmentIDE: Arduino IDE. Kernel Support: RAK4631 (nRF52) card support required.
2. Required LibrariesBME680 BSEC Library: Very important! Used for complex calculation of IAQ (Indoor Air Quality) index from BME680 resistance data. This provides much more stable and reliable air quality indicators than simple VOC measurement.
3. MQ2 Library: Designed to read RAK12004 sensor data and convert it to an approximate ppm value.
4. LoRaWAN Library: Designed to send data packets via LoRaWAN.
Data Transmission (LoRaWAN)Formation: Sensors read data (e.g. every 5-10 minutes). Data is packaged into an efficient byte array (small packets, optimizing power consumption).
Transmission: RAK4631 uses the LoRaWAN protocol (OTAA activation recommended) to send data to a LoRaWAN network server (e.g. The Things Network).
Sleep mode: Between transmissions, the RAK4631 enters a deep sleep mode to minimize power consumption (an essential step for low-power IoT projects).
Gateway: Setup and ConfigurationTo avoid damage to the gateway, make sure to connect the antenna before turning it on!
This step is thoroughly explained in the guide - IoT Education Kit - Setup the Gateway RAK7268V2 - that can be found on https://www.hackster.io/520073/iot-education-kit-setup-the-gateway-rak7268v2-6b222f
Hardware assemblyThe processor was installed and screwed onto the motherboard, so a sensor was installed in the expansion slot.
I. Arduino IDE Setup (RAK4631 Support)First, you need to make sure that the Arduino IDE recognizes your RAK4631 core:Install the Board Manager URL: Go to File -> Preferences. In the Additional Boards Manager URLs section, enter the following URL:
Install Boards: Go to Tools -> Board -> Boards Manager. Search for “RAK” and install “RAK nRF Boards”.
Select Board: Go to Tools -> Board and select “WisBlock Core RAK4631 Board”.
Installed libraries:WisBlock-API-V2 (RAKwireless)CayenneLPP (Electronic Cats)Adafruit BME680 (Adafruit)Adafruit Unified Sensor (Adafruit)Bosch BSEC Software LibraryCODE:
// 1. LOARAWAN IR BAZINĖS BIBLIOTEKOS
#include <WisBlock-API-V2.h>
#include <CayenneLPP.h>
#include <LoRaWan-Arduino.h>
#include <Wire.h>
// PRIVALOMA: Rankiniu būdu apibrėžiame TIK tas konstantes, kurios vis dar nerandamos
#define LMH_SUCCESS 0
#define LMH_APL_SET 1 // Prisijungimo sėkmė
// Minimali lmh_evt_t struktūra (paliekama, nes naudojama callback'uose)
typedef struct {
uint8_t type;
struct {
uint8_t join_result;
struct {
int16_t rssi;
int8_t snr;
} send_confirm;
} params;
} lmh_evt_t;
// Event konstantos
#define LMH_EVT_JOINED 0
#define LMH_EVT_SEND_CONFIRMED 1
#define LMH_EVT_SEND_UNCONFIRMED 2
// 2. JUTIKLIŲ BIBLIOTEKOS
#include <Adafruit_BME680.h>
#include <bsec.h>
// ---------------------- LOARAWAN NUSTATYMAI ----------------------
#define LORAWAN_APP_PORT 2
#define LORAWAN_SEND_CYCLE 300000
time_t next_send_time = 0;
bool is_joined = false;
// RAK LoRaWAN raktų konfigūracija
uint8_t nodeDeviceEUI[8] = {0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x05, 0x8C, 0x66};
uint8_t nodeAppEUI[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t nodeAppKey[16] = {0x33, 0xCC, 0x98, 0x22, 0xCD, 0xAB, 0x67, 0x00, 0x68, 0x27, 0x8F, 0xC3, 0x01, 0x33, 0x24, 0xEE};
// ---------------------- JUTIKLIŲ OBJEKTAI IR KINTAMIEJI ----------------------
Adafruit_BME680 bme680;
Bsec iaqSensor;
#define MQ2_I2C_ADDR 0x04
float mq2_raw_value = 0.0;
float temperature = 0.0;
float humidity = 0.0;
float pressure = 0.0;
float iaq = 0.0;
// ---------------------- TRŪKSTAMOS API FUNKCIJOS DEKLARAVIMAS ----------------------
void setup_app(void);
bool init_app(void); // PATAISYTA: pakeista iš 'void' į 'bool'
void app_event_handler(void);
void lora_data_handler(void);
// Kintamasis, kurio reikalauja BLE modulis (net jei nenaudojamas)
char g_ble_dev_name[10] = "IEEOKS_GW";
// ---------------------- SENOSIOS FUNKCIJOS DEKLARAVIMAS ----------------------
void getBME680Data(void);
void getMQ2Data(void);
void send_lora_data(void);
void user_init_lora(void);
void callback_lora_event(lmh_evt_t *evt);
// CALLBACK FUNKCIJŲ DEKLARAVIMAS
uint8_t join_callback(void);
void send_done_callback(uint8_t *evt);
uint32_t receive_data_callback(void);
void confirm_callback(lmh_app_data_t *app_data);
void tx_needed_callback(void);
// ---------------------- WISBLOCK API IMPLEMENTACIJA ----------------------
// 1. Kviečiama RAK setup() metu
void setup_app(void) {
// Čia atliekame Serijinės jungties ir I2C inicializavimą
Serial.begin(115200);
delay(1000);
Serial.println("IEEOKS sistema inicijuojama (setup_app).");
Wire.begin();
}
// 2. Kviečiama RAK setup() metu (tęsia inicijavimą)
bool init_app(void) { // PATAISYTA: pakeista iš 'void' į 'bool'
// Perkeliame jutiklių ir LoRaWAN inicializavimą
// BME680 / BSEC Inicializavimas
if (!bme680.begin(0x76, true)) {
Serial.println("BME680 nepavyko rasti!");
return false; // Grąžiname FALSE, jei jutiklis nerastas
}
iaqSensor.begin(0x76, Wire);
// LoRaWAN Inicializavimas
user_init_lora();
return true; // Grąžiname TRUE, jei pavyko
}
// 3. Kviečiama RAK loop() metu (tvarko ciklinį siuntimą)
void lora_data_handler(void) {
if (is_joined && millis() >= next_send_time) {
send_lora_data();
next_send_time = millis() + LORAWAN_SEND_CYCLE;
}
}
// 4. Kviečiama RAK loop() metu (tvarko įvykius)
void app_event_handler(void) {
// Galima palikti tuščią, jei viskas tvarkoma callback'uose
}
// ---------------------- SENOSIOS FUNKCIJOS KŪNAS ----------------------
// ... (Likęs kodas nesikeičia)
void getBME680Data(void) {
if (iaqSensor.run()) {
temperature = iaqSensor.temperature;
humidity = iaqSensor.humidity;
pressure = iaqSensor.pressure / 100.0;
iaq = iaqSensor.iaq;
}
}
void getMQ2Data(void) {
uint16_t raw_data;
Wire.beginTransmission(MQ2_I2C_ADDR);
Wire.write(0x00);
Wire.endTransmission(false);
if (Wire.requestFrom(MQ2_I2C_ADDR, 2) == 2) {
raw_data = Wire.read() << 8 | Wire.read();
mq2_raw_value = (float)raw_data;
} else {
mq2_raw_value = 0;
}
}
void send_lora_data() {
getBME680Data();
getMQ2Data();
CayenneLPP lpp(50);
lpp.addAnalogInput(0, iaq);
lpp.addTemperature(1, temperature);
lpp.addRelativeHumidity(2, humidity);
lpp.addBarometricPressure(3, pressure);
lpp.addAnalogInput(4, mq2_raw_value);
lmh_app_data_t app_data;
app_data.buffer = lpp.getBuffer();
app_data.buffsize = lpp.getSize();
app_data.port = LORAWAN_APP_PORT;
if (lmh_send(&app_data, LMH_UNCONFIRMED_MSG) == LMH_SUCCESS) {
Serial.printf("LoRaWAN paketas siunčiamas. Dydis: %d baitai.\n", app_data.buffsize);
} else {
Serial.println("Nepavyko išsiųsti paketo.");
}
}
void callback_lora_event(lmh_evt_t *evt) {
// ...
}
// Callback funkcijų realizacijos, atitinkančios naują API parašą
uint8_t join_callback(void) {
Serial.println("Prisijungimo kvietimas inicijuotas. API tvarko bandymą.");
return 0;
}
void send_done_callback(uint8_t *evt) {
Serial.println("Paketas išsiųstas (send_done_callback).");
}
uint32_t receive_data_callback(void) {
Serial.println("Gauti duomenys (receive_data_callback).");
return 0;
}
void confirm_callback(lmh_app_data_t *app_data) {
Serial.printf("Patvirtinimas gautas (Port: %d, confirm_callback).\n", app_data->port);
is_joined = true;
next_send_time = millis() + LORAWAN_SEND_CYCLE;
}
void tx_needed_callback(void) {
Serial.println("TX reikalingas (tx_needed_callback).");
}
// Globalus kintamasis, užpildytas su poziciniu inicializavimu
lmh_callback_t lora_callbacks = {
(uint8_t (*)())join_callback, // 1: uint8_t (*)(void)
(void (*)(uint8_t*))send_done_callback, // 2: void (*)(uint8_t*)
(uint32_t (*)())receive_data_callback, // 3: uint32_t (*)(void)
(void (*)(lmh_app_data_t*))confirm_callback, // 4: void (*)(lmh_app_data_t*)
tx_needed_callback // 5: void (*)(void)
};
void user_init_lora(void) {
// LoRaWAN Inicializavimas
lmh_param_t lora_config;
lora_config.adr_enable = true;
lora_config.tx_power = 14;
if (lmh_init(&lora_callbacks, lora_config, true, CLASS_A, LORAMAC_REGION_EU868, false) != LMH_SUCCESS) {
Serial.println("LMH inicializavimo klaida!");
return;
}
Serial.println("Pradedamas OTAA prisijungimas prie LoRaWAN...");
lmh_join();
}







_M6kErcYJ84.png?auto=compress%2Cformat&w=40&h=40&fit=fillmax&bg=fff&dpr=2)


Comments