Harun YenisanMehmet Emin Uğur
Published © MIT

Smart Building Occupancy and Environmental Control

Smart Building Occupancy and Environmental Control

IntermediateWork in progress24 hours43
Smart Building Occupancy and Environmental Control

Things used in this project

Hardware components

RAKwireless RAK19003
×1
RAKwireless RAK4631
×1
RAKwireless RAK12033
×1
RAKwireless RAK1906
×1
RAKwireless RAK12004
×1
RAKwireless RAK7268V2
×1
RAKwireless RAK13009
×1
RAKwireless RAK13010
×1

Software apps and online services

The Things Industries TheThingsNetwork
Home Assistant
Home Assistant
Grafana
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Multitool, Screwdriver
Multitool, Screwdriver

Story

Read more

Code

Smart Building Occupancy and Environmental Control

Arduino
Smart Building Occupancy and Environmental Control
#include <LoRaWan-RAK4631.h> // LoRaWAN library for RAK4631
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME680.h> // For RAK1906 (uses BME680 sensor)
#include <RAK12004_Light.h> // For RAK12004 (uses BH1750 light sensor)

// For RAK12033 Motion Sensor
// If RAK12033 is a PIR sensor (typically passive infrared motion sensor), a simple digital pin read is sufficient.
// If it's an accelerometer (like LIS3DH), you'll need to include its library.
#define MOTION_SENSOR_PIN WB_IO4 // Example GPIO pin connected to RAK12033 (assuming PIR sensor)

// LoRaWAN Join Settings
// You must obtain these values from your TheThingsNetwork (TTN) console.
String node_device_eui = "AC1F09FFFE0xxxx"; // <<< CHANGE THIS
String node_app_eui = "70B3D57ED000xxxx";   // <<< CHANGE THIS
String node_app_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // <<< CHANGE THIS

// LoRaWAN Application Port
#define LORAWAN_APP_PORT 1

// Data Transmission Interval (in seconds)
#define SEND_INTERVAL_SEC 60 // Interval for sending sensor data (1 minute)

// Relay Pin Definitions
#define RELAY_LIGHTS_PIN WB_IO3 // Relay pin for lighting control
#define RELAY_HVAC_PIN WB_IO5   // Relay pin for HVAC (Heating, Ventilation, Air Conditioning) control

// Sensor Objects
Adafruit_BME680 bme;         // RAK1906 (BME680) environmental sensor object
RAK12004_Light lightSensor;  // RAK12004 (BH1750) light sensor object

// Timer Variable
time_t lastSendTime = 0; // Last sensor data transmission time (millis())

void setup() {
  // Set internal LED as OUTPUT and turn it off initially
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW); 
  
  // Start serial communication (for debug messages)
  Serial.begin(115200);
  while (!Serial); // Wait for serial port to be ready
  Serial.println("Smart Building Control System Starting...");

  // Set relay pins as OUTPUT and keep them off initially
  pinMode(RELAY_LIGHTS_PIN, OUTPUT);
  digitalWrite(RELAY_LIGHTS_PIN, LOW);
  pinMode(RELAY_HVAC_PIN, OUTPUT);
  digitalWrite(RELAY_HVAC_PIN, LOW);

  // Set motion sensor pin as INPUT
  pinMode(MOTION_SENSOR_PIN, INPUT);

  // Start I2C communication (for BME680 and BH1750)
  Wire.begin();

  // Initialize RAK1906 (BME680) sensor
  if (!bme.begin(0x76)) { // I2C address can be 0x76 or 0x77
    Serial.println("RAK1906 BME680 not found, check connection!");
    while (1); 
  }
  // Sampling and heater settings for BME680
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setGasHeater(320, 150); // Heater for gas sensor (VOC)
  Serial.println("RAK1906 BME680 successfully initialized.");

  // Initialize RAK12004 (BH1750) light sensor
  if (!lightSensor.begin()) {
    Serial.println("RAK12004 not found, check connection!");
    while (1); 
  }
  Serial.println("RAK12004 successfully initialized.");

  // Initialize and configure LoRaWAN module
  api.lorawan.setMcuStatus(true);         // Set MCU status
  api.lorawan.setDeviceClass(CLASS_A);    // Set device class
  api.lorawan.setRegion(EU868);           // Set LoRaWAN region
  api.lorawan.setDevEui(node_device_eui); // Set Device EUI
  api.lorawan.setAppEui(node_app_eui);   // Set Application EUI
  api.lorawan.setAppKey(node_app_key);   // Set Application Key
  api.lorawan.setConfirm(true);          // Use confirmed messages?
  api.lorawan.setAdaptiveDr(true);       // Use Adaptive Data Rate (ADR)?
  
  Serial.println("Attempting to join LoRaWAN network...");
  api.lorawan.join(); // Start LoRaWAN network join process

  // Initialize timer
  lastSendTime = millis();
}

void loop() {
  // Check LoRaWAN network connection status
  if (api.lorawan.queryNetworkStatus() == LORAWAN_JOINED) {
    // Check if it's time to send data
    if (millis() - lastSendTime > (SEND_INTERVAL_SEC * 1000)) {
      sendSensorData();       // Send sensor data
      lastSendTime = millis(); // Reset timer
    }
  } else {
    // If not connected to LoRaWAN network, try to join again...
    Serial.println("Not connected to LoRaWAN network, trying to join again...");
    api.lorawan.join(); 
    delay(10000); // Wait 10 seconds before retrying
  }
}

// Function to read sensor data and send it via LoRaWAN
void sendSensorData() {
  Serial.println("Reading sensor data...");
  
  // Start BME680 (RAK1906) readings
  bme.performReading(); 
  float temperature = bme.temperature;
  float humidity = bme.humidity;
  float gas_resistance = bme.gas_resistance / 1000.0; // Convert Ohm to KOhms

  // RAK12004 light sensor readings
  float lightLux = lightSensor.getLux();
  
  // RAK12033 motion sensor reading
  int motionDetected = digitalRead(MOTION_SENSOR_PIN); // HIGH if motion detected, LOW if not

  // Print read data to Serial Monitor
  Serial.printf("Temperature: %.2f C, Humidity: %.2f %%RH, Gas: %.2f KOhms, Light: %.2f Lux, Motion: %s\n",
                temperature, humidity, gas_resistance, lightLux, motionDetected == HIGH ? "Detected" : "Not Detected");

  // Package data into LoRaWAN payload
  // Payload structure: Temperature (float), Humidity (float), Gas (float), Light (float), Motion (byte)
  uint8_t payload[17]; // 4 float * 4 bytes + 1 byte (motion) = 17 bytes
  memcpy(&payload[0], &temperature, sizeof(float)); // Temperature
  memcpy(&payload[4], &humidity, sizeof(float));    // Humidity
  memcpy(&payload[8], &gas_resistance, sizeof(float)); // Gas Resistance (Air Quality)
  memcpy(&payload[12], &lightLux, sizeof(float));    // Light (Lux)
  payload[16] = (uint8_t)motionDetected;            // Motion status (0 or 1)

  Serial.println("Sending LoRaWAN data...");
  // Send payload to LoRaWAN network. Use LORAWAN_APP_PORT and send as confirmed message (true).
  api.lorawan.send(sizeof(payload), payload, LORAWAN_APP_PORT, true); 
}

// Callback function to be called when a LoRaWAN downlink message is received
// Processes commands from Home Assistant or similar automation systems.
void OnRxData(lorawan_AppData_t* appData) {
  Serial.printf("LoRaWAN Downlink message received, Port: %d, Length: %d\n", appData->Port, appData->BuffSize);
  
  // Print received payload to serial monitor
  Serial.print("Payload (hex): ");
  for (int i = 0; i < appData->BuffSize; i++) {
    Serial.printf("%02X ", appData->Buffer[i]);
  }
  Serial.println();

  // Convert payload to String and interpret as command
  String command = "";
  for (int i = 0; i < appData->BuffSize; i++) {
    command += (char)appData->Buffer[i];
  }
  Serial.print("Received Command: ");
  Serial.println(command);

  // Control relays based on incoming commands (lighting or HVAC)
  if (command == "LIGHTS_ON") {
    digitalWrite(RELAY_LIGHTS_PIN, HIGH); // Turn on lights relay
    Serial.println("LIGHTS TURNED ON!");
  } else if (command == "LIGHTS_OFF") {
    digitalWrite(RELAY_LIGHTS_PIN, LOW);  // Turn off lights relay
    Serial.println("LIGHTS TURNED OFF!");
  } else if (command == "HVAC_ON") {
    digitalWrite(RELAY_HVAC_PIN, HIGH); // Turn on HVAC relay
    Serial.println("HVAC TURNED ON!");
  } else if (command == "HVAC_OFF") {
    digitalWrite(RELAY_HVAC_PIN, LOW);  // Turn off HVAC relay
    Serial.println("HVAC TURNED OFF!");
  } else {
    Serial.println("Unknown command.");
  }
}

// Mandatory callback function definitions for LoRaWAN library
void lorawan_rx_handler(lorawan_AppData_t* appData) {
  OnRxData(appData); // Call OnRxData function when data is received
}

void lorawan_has_joined_handler(void) {
  Serial.println("Successfully joined LoRaWAN network!");
  digitalWrite(LED_BUILTIN, HIGH); // Turn on internal LED after joining network
}

void lorawan_join_failed_handler(void) {
  Serial.println("LoRaWAN network join failed. Retrying...");
  digitalWrite(LED_BUILTIN, LOW); // Turn off internal LED if join fails
}

void lorawan_tx_handler(void) {
  Serial.println("LoRaWAN Tx Done!"); // Inform when data transmission is complete
}

Credits

Harun Yenisan
8 projects • 7 followers
Electronic engineer, working as an IT teacher at the Ministry of National Education.
Mehmet Emin Uğur
9 projects • 9 followers
Computer engineer, working as an IT teacher at the Ministry of National Education.

Comments