-
-
Save felixerdy/a42dab711531a8ac587a96b5ab7b24cf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
senseBox:home - Citizen Sensingplatform | |
Version: lorav2.0.0 | |
Date: 2018-09-11 | |
Homepage: https://www.sensebox.de https://www.opensensemap.org | |
Author: Reedu GmbH & Co. KG | |
Note: Sketch for senseBox:home LoRa MCU Edition | |
Model: homeV2lora | |
Email: support@sensebox.de | |
Code is in the public domain. | |
https://github.com/sensebox/node-sketch-templater | |
*/ | |
#include <LoraMessage.h> | |
#include <lmic.h> | |
#include <hal/hal.h> | |
#include <SPI.h> | |
#include <senseBoxIO.h> | |
#include <SD.h> | |
#include <Wire.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
#include <Adafruit_Sensor.h> | |
#include <Adafruit_HDC1000.h> | |
#include <Adafruit_BMP280.h> | |
#include <Makerblog_TSL45315.h> | |
#include <VEML6070.h> | |
#include <SDS011-select-serial.h> | |
// Uncomment the next line to get debugging messages printed on the Serial port | |
// Do not leave this enabled for long time use | |
// #define ENABLE_DEBUG | |
#ifdef ENABLE_DEBUG | |
#define DEBUG(str) Serial.println(str) | |
#else | |
#define DEBUG(str) | |
#endif | |
// Connected sensors | |
// Temperatur | |
#define HDC1080_CONNECTED | |
// rel. Luftfeuchte | |
#define HDC1080_CONNECTED | |
// Luftdruck | |
#define BMP280_CONNECTED | |
// Beleuchtungsstärke | |
#define TSL45315_CONNECTED | |
// UV-Intensität | |
#define VEML6070_CONNECTED | |
// PM10 | |
#define SDS011_CONNECTED | |
// PM2.5 | |
#define SDS011_CONNECTED | |
// Bodenfeuchte 1 | |
#define SMT50_1_CONNECTED | |
// Bodentemperatur 1 | |
#define SMT50_1_CONNECTED | |
// Bodenfeuchte 2 | |
#define SMT50_2_CONNECTED | |
// Bodentemperatur 2 | |
#define SMT50_2_CONNECTED | |
// Ultraschall | |
#define ULTRASONIC_CONNECTED | |
// Display | |
#define DISPLAY_CONNECTED | |
// SD | |
#define SD_CONNECTED | |
// Number of serial port the SDS011 is connected to. Either Serial1 or Serial2 | |
#ifdef SDS011_CONNECTED | |
#define SDS_UART_PORT (Serial1) | |
#endif | |
//Load sensors / instances | |
#ifdef HDC1080_CONNECTED | |
Adafruit_HDC1000 HDC = Adafruit_HDC1000(); | |
float temperature = 0; | |
float humidity = 0; | |
#endif | |
#ifdef BMP280_CONNECTED | |
Adafruit_BMP280 BMP; | |
double pressure; | |
#endif | |
#ifdef TSL45315_CONNECTED | |
uint32_t lux; | |
Makerblog_TSL45315 TSL = Makerblog_TSL45315(TSL45315_TIME_M4); | |
#endif | |
#ifdef VEML6070_CONNECTED | |
VEML6070 VEML; | |
uint16_t uv; | |
#endif | |
#ifdef SDS011_CONNECTED | |
SDS011 SDS(SDS_UART_PORT); | |
float pm10 = 0; | |
float pm25 = 0; | |
#endif | |
#ifdef SMT50_1_CONNECTED | |
#define SOILTEMPPIN_1 3 | |
#define SOILMOISPIN_1 4 | |
float soilTemp1 = 0; | |
float soilMoist1 = 0; | |
#endif | |
#ifdef SMT50_2_CONNECTED | |
#define SOILTEMPPIN_2 5 | |
#define SOILMOISPIN_2 6 | |
float soilTemp2 = 0; | |
float soilMoist2 = 0; | |
#endif | |
#ifdef ULTRASONIC_CONNECTED | |
int trig = 1; // Trig-Pin des Sensors ist an Pin 1 angeschlossen. | |
int echo = 2; // Echo-Pin des Sensors ist an Pin 2 angeschlossen. | |
unsigned int time = 0; | |
unsigned int distance = 0; | |
#endif | |
#ifdef DISPLAY_CONNECTED | |
#define OLED_RESET 4 | |
Adafruit_SSD1306 display(OLED_RESET); | |
#endif | |
#ifdef SD_CONNECTED | |
File myFile; | |
String fileName = "data.csv"; | |
#endif | |
// This EUI must be in little-endian format, so least-significant-byte (lsb) | |
// first. When copying an EUI from ttnctl output, this means to reverse | |
// the bytes. | |
static const u1_t PROGMEM DEVEUI[8] = { ... }; | |
void os_getDevEui (u1_t* buf) { | |
memcpy_P(buf, DEVEUI, 8); | |
} | |
// This EUI must be in little-endian format, so least-significant-byte (lsb) | |
// first. When copying an EUI from ttnctl output, this means to reverse | |
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, | |
// 0x70. | |
static const u1_t PROGMEM APPEUI[8] = { ... }; | |
void os_getArtEui (u1_t* buf) { | |
memcpy_P(buf, APPEUI, 8); | |
} | |
// This key should be in big endian format (msb) (or, since it is not really a | |
// number but a block of memory, endianness does not really apply). In | |
// practice, a key taken from ttnctl can be copied as-is. | |
// The key shown here is the semtech default key. | |
static const u1_t PROGMEM APPKEY[16] = { ... }; | |
void os_getDevKey (u1_t* buf) { | |
memcpy_P(buf, APPKEY, 16); | |
} | |
static osjob_t sendjob; | |
// Schedule TX every this many seconds (might become longer due to duty | |
// cycle limitations). | |
const unsigned TX_INTERVAL = 60; | |
// Pin mapping | |
const lmic_pinmap lmic_pins = { | |
.nss = PIN_XB1_CS, | |
.rxtx = LMIC_UNUSED_PIN, | |
.rst = LMIC_UNUSED_PIN, | |
.dio = {PIN_XB1_INT, PIN_XB1_INT, LMIC_UNUSED_PIN}, | |
}; | |
void onEvent (ev_t ev) { | |
senseBoxIO.statusGreen(); | |
DEBUG(os_getTime()); | |
switch (ev) { | |
case EV_SCAN_TIMEOUT: | |
DEBUG(F("EV_SCAN_TIMEOUT")); | |
break; | |
case EV_BEACON_FOUND: | |
DEBUG(F("EV_BEACON_FOUND")); | |
break; | |
case EV_BEACON_MISSED: | |
DEBUG(F("EV_BEACON_MISSED")); | |
break; | |
case EV_BEACON_TRACKED: | |
DEBUG(F("EV_BEACON_TRACKED")); | |
break; | |
case EV_JOINING: | |
DEBUG(F("EV_JOINING")); | |
break; | |
case EV_JOINED: | |
DEBUG(F("EV_JOINED")); | |
// Disable link check validation (automatically enabled | |
// during join, but not supported by TTN at this time). | |
LMIC_setLinkCheckMode(0); | |
break; | |
case EV_RFU1: | |
DEBUG(F("EV_RFU1")); | |
break; | |
case EV_JOIN_FAILED: | |
DEBUG(F("EV_JOIN_FAILED")); | |
break; | |
case EV_REJOIN_FAILED: | |
DEBUG(F("EV_REJOIN_FAILED")); | |
break; | |
case EV_TXCOMPLETE: | |
DEBUG(F("EV_TXCOMPLETE (includes waiting for RX windows)")); | |
if (LMIC.txrxFlags & TXRX_ACK) | |
DEBUG(F("Received ack")); | |
if (LMIC.dataLen) { | |
DEBUG(F("Received ")); | |
DEBUG(LMIC.dataLen); | |
DEBUG(F(" bytes of payload")); | |
} | |
// Schedule next transmission | |
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); | |
break; | |
case EV_LOST_TSYNC: | |
DEBUG(F("EV_LOST_TSYNC")); | |
break; | |
case EV_RESET: | |
DEBUG(F("EV_RESET")); | |
break; | |
case EV_RXCOMPLETE: | |
// data received in ping slot | |
DEBUG(F("EV_RXCOMPLETE")); | |
break; | |
case EV_LINK_DEAD: | |
DEBUG(F("EV_LINK_DEAD")); | |
break; | |
case EV_LINK_ALIVE: | |
DEBUG(F("EV_LINK_ALIVE")); | |
break; | |
default: | |
DEBUG(F("Unknown event")); | |
break; | |
} | |
} | |
void do_send(osjob_t* j) { | |
// Check if there is not a current TX/RX job running | |
if (LMIC.opmode & OP_TXRXPEND) { | |
DEBUG(F("OP_TXRXPEND, not sending")); | |
} else { | |
LoraMessage message; | |
//-----Temperature-----// | |
//-----Humidity-----// | |
#ifdef HDC1080_CONNECTED | |
DEBUG(F("Temperature: ")); | |
temperature = HDC.readTemperature(); | |
DEBUG(temperature); | |
message.addUint16((temperature + 18) * 771); | |
delay(2000); | |
DEBUG(F("Humidity: ")); | |
humidity = HDC.readHumidity(); | |
DEBUG(humidity); | |
message.addHumidity(humidity); | |
delay(2000); | |
#endif | |
//-----Pressure-----// | |
#ifdef BMP280_CONNECTED | |
float altitude; | |
pressure = BMP.readPressure() / 100; | |
altitude = BMP.readAltitude(1013.25); //1013.25 = sea level pressure | |
DEBUG(F("Pressure: ")); | |
DEBUG(pressure); | |
message.addUint16((pressure - 300) * 81.9187); | |
delay(2000); | |
#endif | |
//-----Lux-----// | |
#ifdef TSL45315_CONNECTED | |
DEBUG(F("Illuminance: ")); | |
lux = TSL.readLux(); | |
DEBUG(lux); | |
message.addUint8(lux); | |
message.addUint16(lux >> 8); | |
delay(2000); | |
#endif | |
//-----UV intensity-----// | |
#ifdef VEML6070_CONNECTED | |
DEBUG(F("UV: ")); | |
uv = VEML.getUV(); | |
DEBUG(uv); | |
message.addUint8(uv); | |
message.addUint16(uv >> 8); | |
delay(2000); | |
#endif | |
//-----PM-----// | |
#ifdef SDS011_CONNECTED | |
uint8_t attempt = 0; | |
while (attempt < 5) { | |
bool error = SDS.read(&pm25, &pm10); | |
if (!error) { | |
DEBUG(F("PM10: ")); | |
DEBUG(pm10); | |
message.addUint16(pm10 * 10); | |
DEBUG(F("PM2.5: ")); | |
DEBUG(pm25); | |
message.addUint16(pm25 * 10); | |
break; | |
} | |
attempt++; | |
} | |
#endif | |
//-----Soil Temperature & Moisture-----// | |
#ifdef SMT50_1_CONNECTED | |
float voltage_1 = analogRead(SOILTEMPPIN_1) * (3.3 / 1024.0); | |
soilTemp1 = (voltage_1 - 0.5) * 100; | |
message.addUint16((soilTemp1 + 18) * 771); | |
voltage_1 = analogRead(SOILMOISPIN_1) * (3.3 / 1024.0); | |
soilMoist1 = (voltage_1 * 50) / 3; | |
message.addHumidity(soilMoist1); | |
#endif | |
//-----Soil Temperature & Moisture-----// | |
#ifdef SMT50_2_CONNECTED | |
float voltage_2 = analogRead(SOILTEMPPIN_2) * (3.3 / 1024.0); | |
soilTemp2 = (voltage_2 - 0.5) * 100; | |
message.addUint16((soilTemp2 + 18) * 771); | |
voltage_2 = analogRead(SOILMOISPIN_2) * (3.3 / 1024.0); | |
soilMoist2 = (voltage_2 * 50) / 3; | |
message.addHumidity(soilMoist2); | |
#endif | |
#ifdef ULTRASONIC_CONNECTED | |
digitalWrite(trig, HIGH); | |
delayMicroseconds(10); | |
digitalWrite(trig, LOW); | |
time = pulseIn(echo, HIGH); | |
distance = time / 58; | |
message.addUint8(distance); | |
message.addUint16(distance >> 8); | |
#endif | |
#ifdef SD_CONNECTED | |
// Datei öffnen mit Schreibzugriff | |
myFile = SD.open(fileName, FILE_WRITE); | |
myFile.print(temperature); | |
myFile.print(","); | |
myFile.print(humidity); | |
myFile.print(","); | |
myFile.print(pressure); | |
myFile.print(","); | |
myFile.print(lux); | |
myFile.print(","); | |
myFile.print(uv); | |
myFile.print(","); | |
myFile.print(pm10); | |
myFile.print(","); | |
myFile.print(pm25); | |
myFile.print(","); | |
myFile.print(soilTemp1); | |
myFile.print(","); | |
myFile.print(soilMoist1); | |
myFile.print(","); | |
myFile.print(soilTemp2); | |
myFile.print(","); | |
myFile.print(soilMoist2); | |
myFile.print(","); | |
myFile.println(distance); | |
// Nach benutzung wird die Datei wieder geschlossen | |
myFile.close(); | |
#endif | |
// Prepare upstream data transmission at the next possible time. | |
LMIC_setTxData2(1, message.getBytes(), message.getLength(), 0); | |
DEBUG(F("Packet queued")); | |
} | |
// Next TX is scheduled after TX_COMPLETE event. | |
} | |
void setup() { | |
#ifdef ENABLE_DEBUG | |
Serial.begin(9600); | |
#endif | |
delay(3000); | |
// RFM9X (LoRa-Bee) in XBEE1 Socket | |
senseBoxIO.powerXB1(false); // power off to reset RFM9X | |
delay(250); | |
senseBoxIO.powerXB1(true); // power on | |
// Sensor initialization | |
DEBUG(F("Initializing sensors...")); | |
#ifdef VEML6070_CONNECTED | |
VEML.begin(); | |
delay(500); | |
#endif | |
#ifdef HDC1080_CONNECTED | |
HDC.begin(); | |
#endif | |
#ifdef BMP280_CONNECTED | |
BMP.begin(0x76); | |
#endif | |
#ifdef TSL45315_CONNECTED | |
TSL.begin(); | |
#endif | |
#ifdef SDS011_CONNECTED | |
SDS_UART_PORT.begin(9600); | |
#endif | |
#ifdef ULTRASONIC_CONNECTED | |
pinMode(trig, OUTPUT); | |
pinMode(echo, INPUT); | |
#endif | |
#ifdef DISPLAY_CONNECTED | |
display.begin(SSD1306_SWITCHCAPVCC, 0x3D); | |
display.display(); | |
delay(100); | |
display.clearDisplay(); | |
#endif | |
#ifdef SD_CONNECTED | |
SD.begin(28); | |
myFile = SD.open(fileName, FILE_WRITE); | |
myFile.close(); | |
#endif | |
DEBUG(F("Sensor initializing done!")); | |
DEBUG(F("Starting loop in 3 seconds.")); | |
delay(3000); | |
// LMIC init | |
os_init(); | |
// Reset the MAC state. Session and pending data transfers will be discarded. | |
LMIC_reset(); | |
// Start job (sending automatically starts OTAA too) | |
do_send(&sendjob); | |
} | |
void loop() { | |
#ifdef DISPLAY_CONNECTED | |
printOnDisplay("Temperatur", String(temperature), "*C", "rel. Luftfeuchte", String(humidity), "%"); | |
long start = millis(); | |
while (millis() < start + 8000) {os_runloop_once();} | |
printOnDisplay("Luftdruck", String(pressure), "hPa", "", "", ""); | |
while (millis() < start + 16000) {os_runloop_once();} | |
printOnDisplay("Helligkeit", String(lux), "lx", "UV-Intensitaet", String(uv), "uW/cm2"); | |
while (millis() < start + 24000) {os_runloop_once();} | |
printOnDisplay("PM10", String(pm10), "ug/m3", "PM2.5", String(pm25), "ug/m3"); | |
while (millis() < start + 32000) {os_runloop_once();} | |
printOnDisplay("Bodenfeuchte", String(soilMoist1), "%", "Bodentemperatur", String(soilTemp1), "*C"); | |
while (millis() < start + 40000) {os_runloop_once();} | |
printOnDisplay("Bodenfeuchte 2", String(soilMoist2), "%", "Bodentemperatur 2", String(soilTemp2), "*C"); | |
while (millis() < start + 48000) {os_runloop_once();} | |
printOnDisplay("Distanz", String(distance), "cm", "", "", ""); | |
while (millis() < start + 56000) {os_runloop_once();} | |
#endif | |
os_runloop_once(); | |
} | |
void printOnDisplay(String title1, String measurement1, String unit1, String title2, String measurement2, String unit2) { | |
display.clearDisplay(); | |
display.setCursor(0, 0); | |
display.setTextSize(1); | |
display.setTextColor(WHITE, BLACK); | |
display.println(title1); | |
display.setCursor(0, 10); | |
display.setTextSize(2); | |
display.print(measurement1); | |
display.print(" "); | |
display.setTextSize(1); | |
display.println(unit1); | |
display.setCursor(0, 30); | |
display.setTextSize(1); | |
display.println(title2); | |
display.setCursor(0, 40); | |
display.setTextSize(2); | |
display.print(measurement2); | |
display.print(" "); | |
display.setTextSize(1); | |
display.println(unit2); | |
display.display(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment