Klar. Gerne. Danke.
const char CodeVersion[] = "CodeVersion v4.0 - 20200620";
#include <SenseBoxMCU.h>
#include <SPI.h>
#include <Wire.h>
#include <WiFiSSLClient.h>
#include <WiFi101.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_GFX.h>
#include <Adafruit_BME680.h>
#include <LoraMessage.h>
#include <lmic.h>
#include <hal/hal.h>
#include <UniversalTelegramBot.h>
// Debugging messages on Serial port
// Do not leave this enabled for long time use
// #define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define DEBUG(str) Serial.println(str)
#define DEBUG_ARGS(str,str1) Serial.println(str,str1)
#define DEBUG2(str) Serial.print(str)
#define DEBUG_WRITE(c) Serial.write(c)
#else
#define DEBUG(str)
#define DEBUG_ARGS(str,str1)
#define DEBUG2(str)
#define DEBUG_WRITE(c)
#endif
bool DEBUG_DATA;
const int ledPin = 7; //red LED onboard senseBoxMCU
/******** Timing ********/
// Intervall SDS/PM
const long pm_interval = 31000;
long pm_time_start = 0;
long pm_time_actual = 0;
// Intervall BME
const long bme_interval = 27000;
long bme_time_start = 0;
long bme_time_actual = 0;
// Intervall Light
const long li_interval = 25000;
long li_time_start = 0;
long li_time_actual = 0;
// Intervall CO2
const long co2_interval = 28000;
long co2_time_start = 0;
long co2_time_actual = 0;
// Intervall openSenseMap
const long osm_interval = 62000;
long osm_time_start = 0;
long osm_time_actual = 0;
// Intervall TelegramBot
const long tbot_interval = 85000;
long tbot_time_start = 0;
long tbot_time_actual = 0;
/******** Sensor Bibliothek ********/
float temperature; // Temperatur
float humidity; // Feuchtigkeit
float pressure, pressure_Pa; // Luftdruck in hPa
float voc; // Gas/Luftqualität
float est_altitude; // Höhe (ca.)
#define SEALEVELPRESSURE_HPA (1024)
/******** Adafruit BME680 Bibliothek ********/
Adafruit_BME680 bme680; // Zugriff ueber I2C
/******** Lichtintensität TSL45315 & UV-Strahlung VEML6070 ********/
//Makerblog_TSL45315 tsl = Makerblog_TSL45315(TSL45315_TIME_M4);
TSL45315 tsl;
unsigned long lux; // Lichtstärke
VEML6070 veml;
unsigned int uv;
byte uvindex;// UV-Index
/******** Adafruit Feinstaub SDS011 ********/
// Load SDS011 Sensor on Serial 1
SDS011 sds(Serial1);
float pm10, pm10_n, pm25, pm25_n;
/******** Seeed Studio Grove CO2 MH-Z16 ********/
// Load CO2 Sensor on Serial 2
#define GROVE_CO2 (Serial2)
const unsigned char cmd_get_sensor[] = {0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
unsigned char dataReceived[9];
uint8_t attempt = 0;
int temperature_co2;
unsigned int co2ppm;
// Helper function for co2 sensor
int dataReceive(void)
{
byte data[9];
int i = 0;
//transmit command data
for(i=0; i<sizeof(cmd_get_sensor); i++)
{
GROVE_CO2.write(cmd_get_sensor[i]);
}
delay(10);
//begin receiving data
if(GROVE_CO2.available())
{
while(GROVE_CO2.available())
{
for(int i=0;i<9; i++)
{
data[i] = GROVE_CO2.read();
}
}
}
delay(100);
if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]))) != data[8])
{
DEBUG("ERROR - GROVE_CO2 Check.value");
return false;
}
co2ppm = (int)data[2] * 256 + (int)data[3];
temperature_co2 = (int)data[4] - 40;
return co2ppm;
}
/******** WLAN WiFi-Bee WINC1500 am XBEE1 mit fester IP-Adresse ********/
char wifi_ssid[] = "xxxxx"; // network wifi_ssid (name)
char wifi_psk[] = "xxxxx"; // network psk-key
IPAddress myip(x,x,x,x);
IPAddress mydns(x,x,x,x);
IPAddress mygateway(x,x,x,x);
IPAddress mysubnet(255, 255, 255, 0);
/******** LoRaWAN LoRa-Bee RFM9X am XBEE2 ********/
// Schedule TX every this many seconds (might become longer due to duty cycle limitations)
const unsigned TX_INTERVAL = 65;
//OTAA
// 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] = { 0x00 ...};
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] = { 0x00 ...};
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.
static const u1_t PROGMEM APPKEY[16] = { 0x00 ...};
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY , 16);}
static uint8_t mydata[] = "Hi,Lora World!"; //for testing
static osjob_t sendjob;
// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = PIN_XB2_CS,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
.dio = {PIN_XB2_INT, PIN_XB2_INT, LMIC_UNUSED_PIN},
};
/******** OpenSenseMap ********/
WiFiClient client;
// address of the server to send to
const char server[] PROGMEM = "ingress.opensensemap.org";
// senseBox ID
const char SENSEBOX_ID[] PROGMEM = "xxxxxxxxxx";
// Number of sensors
// Change this number if you add or remove sensors do not forget to remove or add the sensors on opensensemap.org
static const uint8_t NUM_SENSORS = 10;
// sensor IDs
// Temperatur
const char TEMPERSENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// rel. Luftfeuchte
const char RELLUFSENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// Luftdruck
const char LUFTDRSENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// Beleuchtungsstärke
const char BELEUCSENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// UV-Intensität
const char UVINTESENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// UV-Index
const char UVINDESENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// PM10
const char PM10SENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// PM2.5
const char PM25SENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// VOC
const char VOCSENSOR_ID[] PROGMEM = "xxxxxxxxxx";
// CO2
const char CO2SENSOR_ID[] PROGMEM = "xxxxxxxxxx";
typedef struct measurement
{
const char *sensorId;
float value;
}
measurement;
measurement measurements[NUM_SENSORS];
uint8_t num_measurements = 0;
// buffer for sprintf
char buffer[1500];
/******** Telegram BOT ********/
#define BOTtoken "xxxxxxxxxx" // your Bot Token (Get from Botfather)
WiFiSSLClient BOTclient;
UniversalTelegramBot bot(BOTtoken, BOTclient);
int Bot_mtbs = 1000; // mean time between scan messages
long Bot_lasttime; // last time messages' scan has been done
bool Start = false;
/******** Pushover ********/
String po_token = "xxxxxxxxxx"; // Pushover Token
String po_user = "xxxxxxxxxx"; // Pushover User
String po_retry = "60"; //wie hauefig eine Nachricht vom Server geschickt wird
String po_expire = "3600";
String po_sound = "spacealarm"; //Sounds: pushover, bike, bugle, cashregister, classical, cosmic, falling, gamelan, incoming, intermission, magic, mechanical, pianobar, siren, spacealarm, tugboat, alien, climb, persistent, echo, updown, none
WiFiClient POclient;
/******** START serial debug ********/
void serial_debug(void)
{
Serial.print("Temperatur = ");
Serial.print(temperature);
Serial.println(" °C");
Serial.print("Feuchtigkeit = ");
Serial.print(humidity);
Serial.println(" %");
Serial.print("Luftdruck = ");
Serial.print(pressure);
Serial.println(" hPa");
Serial.print("Beleuchtungsstärke = ");
Serial.print(lux);
Serial.println(" lx");
Serial.print("UV-Intensität = ");
Serial.print(uv);
Serial.print(" μW/cm²");
Serial.print(" / UV-Index = ");
Serial.println(uvindex);
Serial.print("PM10 = ");
Serial.print(pm10);
Serial.print(" µg/m³");
Serial.print(" / normalized = ");
Serial.print(pm10_n);
Serial.println(" µg/m³");
Serial.print("PM2.5 = ");
Serial.print(pm25);
Serial.print(" µg/m³");
Serial.print(" / normalized = ");
Serial.print(pm25_n);
Serial.println(" µg/m³");
Serial.print("VOC = ");
Serial.print(voc);
Serial.println(" kOhm");
Serial.print("CO2 = ");
Serial.print(co2ppm);
Serial.println(" ppm");
Serial.print("Höhe (ca.) = ");
Serial.print(est_altitude);
Serial.println(" m");
Serial.println();
}
/******** END serial debug ********/
/******** START bme/bmp/hdc measurement ********/
void measure_bme(void)
{
DEBUG("[measure] bme");
// bme680 auslesen, Werte ermitteln und merken
bme680.setGasHeater(0, 0);
if ( bme680.performReading())
{
temperature = bme680.temperature - 1;
humidity = bme680.humidity;
pressure = bme680.pressure / 100.0;
pressure_Pa = bme680.pressure;
est_altitude = bme680.readAltitude(SEALEVELPRESSURE_HPA);
}
delay(500);
bme680.setGasHeater(320, 150); // 320*C for 150 ms
if ( bme680.performReading())
{
voc = bme680.gas_resistance / 1000.0;
}
delay(1000);
}
/******** END bme/bmp/hdc measurement ********/
/******** START tsl/veml (light) measure ********/
void measure_light(void)
{
DEBUG("[measure] light");
lux = tsl.getIlluminance();
uv = veml.getUvIntensity();
uvindex = 0.4 * (uv * 5.625) / 1000;
}
/******** END tsl/veml measure ********/
/******** START SDS011 (PM) measure ********/
void measure_pm(void)
{
DEBUG("[measure] pm");
uint8_t attempt_pmread = 0;
while (attempt_pmread < 5)
{
pm25 = sds.getPm25();
pm10 = sds.getPm10();
break;
attempt_pmread++;
}
pm25_n = pm25 / (1.0 + 0.48756 * pow((humidity / 100.0), 8.60068));
pm10_n = pm10 / (1.0 + 0.81559 * pow((humidity / 100.0), 5.83411));
}
/******** END sds measure ********/
/******** START measurement serial2 Grove CO2 ********/
void measure_co2(void)
{
DEBUG("[measure] co2");
uint8_t attempt_co2 = 0;
while (attempt_co2 < 5)
{
bool error_co2 = dataReceive();
if (error_co2 != 0) {
break;
}
attempt_co2++;
}
}
/******** START OpenSenseMap ********/
void addMeasurement(const char *sensorId, float value) {
measurements[num_measurements].sensorId = sensorId;
measurements[num_measurements].value = value;
num_measurements++;
}
void writeMeasurementsToClient() {
// iterate throug the measurements array
for (uint8_t i = 0; i < num_measurements; i++) {
sprintf_P(buffer, PSTR("%s,%9.2f\n"), measurements[i].sensorId,
measurements[i].value);
// transmit buffer to client
client.print(buffer);
DEBUG2(buffer);
}
// reset num_measurements
num_measurements = 0;
}
void submitValues() {
// close any connection before send a new request - free the socket on the WiFi shield
if (client.connected()) {
client.stop();
delay(1000);
}
bool connected = false;
char _server[strlen_P(server)];
strcpy_P(_server, server);
for (uint8_t timeout = 5; timeout != 0; timeout--) {
DEBUG("[oSM] connecting...");
connected = client.connect(_server, 80);
if (connected == true) {
DEBUG("[oSM] connection successful, transferring...");
DEBUG();
// construct the HTTP POST request:
sprintf_P(buffer,
PSTR("POST /boxes/%s/data HTTP/1.1\nHost: %s\nContent-Type: "
"text/csv\nConnection: close\nContent-Length: %i\n\n"),
SENSEBOX_ID, server, num_measurements * 35);
DEBUG(buffer);
// send the HTTP POST request:
client.print(buffer);
// send measurements
writeMeasurementsToClient();
// send empty line to end the request
client.println();
uint16_t timeout = 0;
// allow the response to be computed
while (timeout <= 5000) {
delay(10);
timeout = timeout + 10;
if (client.available()) {
break;
}
}
DEBUG();
while (client.available()) {
char c = client.read();
DEBUG_WRITE(c);
// if the server's disconnected, stop the client:
if (!client.connected()) {
DEBUG();
DEBUG("[oSM] disconnecting...");
client.stop();
break;
}
}
DEBUG();
DEBUG("[oSM] done");
DEBUG();
// reset number of measurements
num_measurements = 0;
break;
}
delay(2000);
}
if (connected == false) {
// Reset durchführen
DEBUG("ERROR - Connection oSM failed. Restarting System.");
senseBoxIO.powerNone(); // all ports off
delay(500);
noInterrupts();
NVIC_SystemReset();
while (1);
}
}
void senddataOSM(void)
{
addMeasurement(TEMPERSENSOR_ID, temperature);
addMeasurement(RELLUFSENSOR_ID, humidity);
addMeasurement(LUFTDRSENSOR_ID, pressure);
addMeasurement(BELEUCSENSOR_ID, lux);
addMeasurement(UVINTESENSOR_ID, uv);
addMeasurement(UVINDESENSOR_ID, uvindex);
addMeasurement(PM10SENSOR_ID, pm10);
addMeasurement(PM25SENSOR_ID, pm25);
addMeasurement(VOCSENSOR_ID, voc);
addMeasurement(CO2SENSOR_ID, co2ppm);
submitValues();
}
/******** END OpenSenseMap ********/
/******** START LoRa ********/
void onEvent(ev_t ev)
{
senseBoxIO.statusGreen();
DEBUG2(os_getTime());
DEBUG2(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
DEBUG("[LoRa] EV_SCAN_TIMEOUT");
break;
case EV_BEACON_FOUND:
DEBUG("[LoRa] EV_BEACON_FOUND");
break;
case EV_BEACON_MISSED:
DEBUG("[LoRa] EV_BEACON_MISSED");
break;
case EV_BEACON_TRACKED:
DEBUG("[LoRa] EV_BEACON_TRACKED");
break;
case EV_JOINING:
DEBUG("[LoRa] EV_JOINING");
break;
case EV_JOINED:
DEBUG("[LoRa] 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("[LoRa] EV_RFU1");
break;
case EV_JOIN_FAILED:
DEBUG("[LoRa] EV_JOIN_FAILED");
break;
case EV_REJOIN_FAILED:
DEBUG("[LoRa] EV_REJOIN_FAILED");
break;
case EV_TXCOMPLETE:
DEBUG("[LoRa] EV_TXCOMPLETE (includes waiting for RX windows)");
if (LMIC.txrxFlags & TXRX_ACK)
DEBUG("Received ack");
if (LMIC.dataLen)
{
DEBUG2("[LoRa] Received ");
DEBUG2(LMIC.dataLen);
DEBUG(" bytes of payload");
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
DEBUG("[LoRa] EV_LOST_TSYNC");
break;
case EV_RESET:
DEBUG("[LoRa] EV_RESET");
break;
case EV_RXCOMPLETE:
// data received in ping slot
DEBUG("[LoRa] EV_RXCOMPLETE");
break;
case EV_LINK_DEAD:
DEBUG("[LoRa] EV_LINK_DEAD");
break;
case EV_LINK_ALIVE:
DEBUG("[LoRa] EV_LINK_ALIVE");
break;
default:
DEBUG2("[LoRa] Unknown event");
DEBUG((unsigned) ev);
break;
}
senseBoxIO.statusNone();
}
void do_send(osjob_t* j)
{
senseBoxIO.statusRed();
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND)
{
DEBUG("[LoRa] OP_TXRXPEND, not sending");
} else {
DEBUG("[LoRa] Prepare Message");
LoraMessage message;
DEBUG2("[LoRa] Temperature): ");
DEBUG(temperature);
message.addUint16((temperature + 18) * 771);
delay(200);
DEBUG2("[LoRa] Humidity: ");
DEBUG(humidity);
message.addHumidity(humidity);
delay(200);
DEBUG2("[LoRa] Pressure: ");
DEBUG(pressure);
message.addUint16((pressure - 300) * 81.9187);
delay(200);
DEBUG2("[LoRa] Illuminance: ");
DEBUG(lux);
message.addUint8(lux);
message.addUint16(lux >> 8);
delay(200);
DEBUG2("[LoRa] UV: ");
DEBUG(uv);
message.addUint8(uv);
message.addUint16(uv >> 8);
DEBUG2("[LoRa] UV-Index: ");
DEBUG(uvindex);
message.addUint16(uvindex * 10);
delay(200);
DEBUG2("[LoRa] PM10: ");
DEBUG(pm10);
message.addUint16(pm10 * 10);
DEBUG2("[LoRa] PM2.5: ");
DEBUG(pm25);
message.addUint16(pm25 * 10);
delay(200);
DEBUG2("[LoRa] VOC: ");
DEBUG(voc);
message.addUint16(voc * 10);
delay(200);
DEBUG2("[LoRa] CO2 PPM: ");
DEBUG(co2ppm);
message.addUint16(co2ppm * 10);
delay(200);
// prepare upstream data transmission at the next possible time.
// transmit on port 1 (the first parameter); you can use any value from 1 to 223 (others are reserved).
// don't request an ack (the last parameter, if not zero, requests an ack from the network).
// Remember, acks consume a lot of network resources; don't ask for an ack unless you really need it.
LMIC_setTxData2(1, message.getBytes(), message.getLength(), 0);
// LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 1);
DEBUG("[LoRa] packet queued");DEBUG(" ");
}
// Next TX is scheduled after TX_COMPLETE event
senseBoxIO.statusNone();
}
/******** END LoRa ********/
/******** START Telegram BOT ********/
void handleNewMessages(int numNewMessages)
{
DEBUG2("handleNewMessages");
DEBUG(String(numNewMessages));
String response;
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
if (text == "/readTemp") {
response = "Temp ";
response += String(temperature);
response += " °C mit ";
response += String(humidity);
response += " % Luftfeuchtigkeit bei ";
response += String(pressure);
response += " hPa Luftdruck";
if (temperature > 26 && temperature <= 124) {
response += " \xF0\x9F\x94\xA5";
} else if (temperature < 6) {
response += " \xE2\x9D\x84";
} else if (temperature > 124) {
response = "ERROR reading sensor. Check if sensor is connected or replace cable/sensor.";
} else {
response += ".";
}
bot.sendMessage(chat_id, response, "");
}
if (text == "/readPM") {
response = "PM10 = ";
response += String(pm10);
response += " & PM2.5 = ";
response += String(pm25);
response += ".";
bot.sendMessage(chat_id, response, "");
}
if (text == "/readLight") {
response = "Beleuchtungsstärke = ";
response += String(lux);
response += " lx";
response += " & UV-Intensität = ";
response += String(uv);
response += " μW/cm²";
response += " & UV-Index = ";
response += String(uvindex);
if (uvindex >= 0 && uvindex < 3) {
response += " \xF0\x9F\x8C\x83 \xF0\x9F\x8C\x85 \xE2\x98\x81";
} else if (uvindex >= 3 && uvindex <= 5.5) {
response += " \xE2\x9B\x85";
} else if (uvindex >= 5.6 && uvindex <= 7.5) {
response += " \xE2\x98\x80";
} else if (uvindex >= 7.6 && uvindex <= 10.5) {
response += " \xE2\x98\x80 \xE2\x98\x80";
} else if (uvindex > 10.6) {
response += "\xE2\x98\x80 \xE2\x98\x80";
} else {
response += ".";
}
bot.sendMessage(chat_id, response, "");
}
if (text == "/readCO2") {
response = "CO² = ";
response += String(co2ppm);
response += " ppm";
response += ".";
bot.sendMessage(chat_id, response, "");
}
if (text == "/start") {
String from_name = bot.messages[i].from_name;
if (from_name == "") from_name = "Anonymous";
String welcome = "Welcome, " + from_name + "! This is your fancy senseBoxMCU bot \xF0\x9F\x91\xBD\n\n";
welcome = welcome + "Use /status to read HDC1080 sensor measurements.\n";
bot.sendMessage(chat_id, welcome, "Markdown");
String keyboardJson = "[[\"/readTemp\"],[\"/readLight\"],[\"/readPM\"],[\"/readCO2\"]]";
bot.sendMessageWithReplyKeyboard(chat_id, "Select a function from the keyboard", "", keyboardJson, true);
}
}
}
void senddataTGBot(void)
{
if (millis() > Bot_lasttime + Bot_mtbs) {
DEBUG();
DEBUG("[TBot] data to...");
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
DEBUG2("[TBot] got response ");
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
Bot_lasttime = millis();
}
}
/******** END Telegram BOT ********/
/******** START Pushover ********/
/*Prioritaeten: 0=Normal; 1=High (AudioVibration auch bei quiet hour); 2=Emergency (Meldung muss bestätigt werden, solange Sound/Vibration);
* -1=Low ; -2=Lowest, dabei length anpassen auf 114
*
*/
byte pushover(String pushovermessage, int po_prio) {
int length;
String Msg = pushovermessage;
length = 113 + Msg.length();
DEBUG("[pushover] sending message");
if (POclient.connect("api.pushover.net", 80)) {
POclient.println("POST /1/messages.json HTTP/1.1");
POclient.println("Host: api.pushover.net");
POclient.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
POclient.print("Content-Length: ");
POclient.print(length);
POclient.println("\r\n");
POclient.print("token="+po_token+"&user="+po_user+"&message="+Msg+"&priority="+po_prio+"&retry="+po_retry+"&expire="+po_expire);
/*POclient.print("&sound="+po_sound); //!length anpassen! +7+ */
/*POclient.print("&device="+po_device); //!length anpassen! +8+ */
while(POclient.connected())
{
while(POclient.available())
{
char ch = POclient.read();
Serial.write(ch);
}
}
POclient.stop();
DEBUG("[pushover] sending message done");
delay(200);
}
}
/******** END Pushover ********/
/******** START setup ********/
void setup()
{
DEBUG_DATA = false;
senseBoxIO.powerNone(); // all ports off
// ledPIN
pinMode(ledPin, OUTPUT); // initialize digital ledPin as an output.
delay(100);
digitalWrite(ledPin, LOW); // initialize pin as off
// Initialize serial and wait for port to open:
#ifdef ENABLE_DEBUG
Serial.begin(9600);
#endif
delay(2000);
Serial.println();
Serial.println(CodeVersion);
Serial.println();
Serial.println("[INIT] start...");
// Sensor initialization
Serial.print("[INIT] sensors");
delay(1000);
Serial.print(".");
// Wifi-Bee in XBEE1 Socket
senseBoxIO.powerXB1(false);
delay(250);
senseBoxIO.powerXB1(true);
Serial.print(".");
delay(2000);
Serial.print(".");
// RFM9X (LoRa-Bee) in XBEE2 Socket
senseBoxIO.powerXB2(false); // power off to reset RFM9X
delay(250);
senseBoxIO.powerXB2(true); // power on
pinMode(PIN_XB2_INT, INPUT_PULLDOWN); // pull-down because interrupt is high-active
Serial.print(".");
delay(2000);
Serial.print(".");
senseBoxIO.powerI2C(true);
delay(2000);
senseBoxIO.powerUART(true);
Serial.print(".");
delay(2000);
Serial.print(".");
// init TSL 0x38 Beleuchtungsstärke
tsl.begin();
delay(1000);
// init VEML 0x38+0x39 UV-Strahlung
veml.begin();
Serial.print(".");
delay(1000);
Serial.print(".");
// init BME680 (Umweltsensor) BME 0x76
bme680.begin(0x76);
// Initialisierung von Oversampling und Filter
bme680.setTemperatureOversampling(BME680_OS_8X);
bme680.setHumidityOversampling(BME680_OS_2X);
bme680.setPressureOversampling(BME680_OS_4X);
bme680.setIIRFilterSize(BME680_FILTER_SIZE_3);
delay(1000);
Serial.print(".");
bme680.setGasHeater(320, 150); // 320*C for 150 ms
if ( bme680.performReading())
{
voc = bme680.gas_resistance / 1000.0;
}
delay(1000);
Serial.print(".");
// init SDS011
Serial1.begin(9600);
delay(5000);
//damit keine Nullwerte
pm25 = sds.getPm25();
pm10 = sds.getPm10();
Serial.print(".");
delay(1000);
Serial.print(".");
// init Grove CO2 (MH-Z16)
GROVE_CO2.begin(9600); //= Serial2.begin(9600);
delay(5000);
measure_co2();
delay(2000);
Serial.println(".");
Serial.println("[INIT] sensors done");
// Messungen um nicht Werte=0
measure_bme();
measure_light();
measure_pm();
measure_co2();
delay(5000);
// attempt to connect to WiFi network
Serial.print("[INIT] WLAN");
Serial.print(".");
WiFi.begin(wifi_ssid, wifi_psk);
WiFi.config(myip, mydns, mygateway, mysubnet);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
}
Serial.println(); Serial.println("[INIT] WLAN done");
delay(2000);
// init LoRa-WAN
Serial.print("[INIT] LoRa-WAN");
// initialize LMIC - runtime env
Serial.print(".");
os_init();
Serial.print(".");
// Reset the MAC state. Session and pending data transfers will be discarded
LMIC_reset();
Serial.println(); Serial.println("[INIT] LoRa-WAN done");
delay(2000);
// pushover("sensebox#1 started",0);
// Start job (sending automatically starts OTAA too)
do_send(&sendjob);
}
/******** END setup ********/
/******** loop() ********/
void loop()
{
// Messwerte BME
bme_time_start = millis();
if (bme_time_start > bme_time_actual + bme_interval)
{
bme_time_actual = millis();
measure_bme();
}
// Messwerte Licht/UV
li_time_start = millis();
if (li_time_start > li_time_actual + li_interval)
{
li_time_actual = millis();
measure_light();
}
// Messwerte PM / Feinstaub
pm_time_start = millis();
if (pm_time_start > pm_time_actual + pm_interval)
{
pm_time_actual = millis();
measure_pm();
}
// Messwerte CO2
co2_time_start = millis();
if (co2_time_start > co2_time_actual + co2_interval)
{
co2_time_actual = millis();
measure_co2();
}
// Daten an serial
if (DEBUG_DATA) {
serial_debug();
}
// Daten an OpenSenseMap
osm_time_start = millis();
if (osm_time_start > osm_time_actual + osm_interval)
{
osm_time_actual = millis();
DEBUG();
DEBUG("Data to oSM...");
senddataOSM(); // Daten Block openSenseMap
}
// Daten an TheThingsNetwork TTN - execute scheduled jobs and events
os_runloop_once();
}