diff --git a/BME-280-LoraWAN-Node.png b/BME-280-LoraWAN-Node.png deleted file mode 100644 index 0ff2f5e..0000000 Binary files a/BME-280-LoraWAN-Node.png and /dev/null differ diff --git a/bme280-lorawan-sensor.ino b/bme280-lorawan-sensor.ino new file mode 100644 index 0000000..278049d --- /dev/null +++ b/bme280-lorawan-sensor.ino @@ -0,0 +1,235 @@ +/******************************************************************************* + Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman + Copyright (c) 2019 Severin Schols + + Permission is hereby granted, free of charge, to anyone + obtaining a copy of this document and accompanying files, + to do whatever they want with them without any restriction, + including, but not limited to, copying, modification and redistribution. + NO WARRANTY OF ANY KIND IS PROVIDED. + + This example reads a BME280 or BMP280 sensor and sends a valid LoRaWAN + packet with the readings alongside the current input voltage, using + frequency and encryption settings matching those of the The Things Network. + + This uses OTAA (Over-the-air activation), where where a DevEUI and + application key is configured, which are used in an over-the-air + activation procedure where a DevAddr and session keys are + assigned/generated for use with all further communication. + + Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in + g1, 0.1% in g2), but not the TTN fair usage policy (which is probably + violated by this sketch when left running for longer)! + + To use this sketch, first register your application and device with + the things network, to set or generate an AppEUI, DevEUI and AppKey. + Multiple devices can use the same AppEUI, but each device has its own + DevEUI and AppKey. + + Do not forget to define the radio type correctly in config.h. + + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "config.h" + +void os_getArtEui (u1_t* buf) { + memcpy_P(buf, APPEUI, 8); +} +void os_getDevEui (u1_t* buf) { + memcpy_P(buf, DEVEUI, 8); +} +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 = 30; + +const lmic_pinmap lmic_pins = { + .nss = 4, + .rxtx = LMIC_UNUSED_PIN, + .rst = LMIC_UNUSED_PIN, // hardwired to AtMega RESET + .dio = {12, 13, LMIC_UNUSED_PIN} // .dio = {4, 5, LMIC_UNUSED_PIN}, +}; + +CayenneLPP lpp(51); +BME280I2C bme; + + +// https://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ +long readVcc() { + // Read 1.1V reference against AVcc + // set the reference to Vcc and the measurement to the internal 1.1V reference +#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); +#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + ADMUX = _BV(MUX5) | _BV(MUX0); +#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + ADMUX = _BV(MUX3) | _BV(MUX2); +#else + ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); +#endif + + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Start conversion + while (bit_is_set(ADCSRA, ADSC)); // measuring + + uint8_t low = ADCL; // must read ADCL first - it then locks ADCH + uint8_t high = ADCH; // unlocks both + + long result = (high << 8) | low; + + result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 + return result; // Vcc in millivolts +} + +void onEvent (ev_t ev) { + Serial.print(os_getTime()); + Serial.print(": "); + switch (ev) { + case EV_SCAN_TIMEOUT: + Serial.println(F("EV_SCAN_TIMEOUT")); + break; + case EV_BEACON_FOUND: + Serial.println(F("EV_BEACON_FOUND")); + break; + case EV_BEACON_MISSED: + Serial.println(F("EV_BEACON_MISSED")); + break; + case EV_BEACON_TRACKED: + Serial.println(F("EV_BEACON_TRACKED")); + break; + case EV_JOINING: + Serial.println(F("EV_JOINING")); + break; + case EV_JOINED: + Serial.println(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: + Serial.println(F("EV_RFU1")); + break; + case EV_JOIN_FAILED: + Serial.println(F("EV_JOIN_FAILED")); + break; + case EV_REJOIN_FAILED: + Serial.println(F("EV_REJOIN_FAILED")); + break; + break; + case EV_TXCOMPLETE: + Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); + if (LMIC.txrxFlags & TXRX_ACK) + Serial.println(F("Received ack")); + if (LMIC.dataLen) { + Serial.println(F("Received ")); + Serial.println(LMIC.dataLen); + Serial.println(F(" bytes of payload")); + } + /*Serial.print(F("Frequency: ")); + Serial.println(LMIC.freq); + Serial.print(F("RSSI: ")); + Serial.println(LMIC.rssi); + Serial.print(F("SNR: ")); + Serial.println(LMIC.snr); + Serial.print(F("txpow: ")); + Serial.println(LMIC.txpow);*/ + Serial.print(F("adrTxPow: ")); + Serial.println(LMIC.adrTxPow); + Serial.print(F("txChnl: ")); + Serial.println(LMIC.txChnl); + Serial.println(); + // Schedule next transmission + os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); + break; + case EV_LOST_TSYNC: + Serial.println(F("EV_LOST_TSYNC")); + break; + case EV_RESET: + Serial.println(F("EV_RESET")); + break; + case EV_RXCOMPLETE: + // data received in ping slot + Serial.println(F("EV_RXCOMPLETE")); + break; + case EV_LINK_DEAD: + Serial.println(F("EV_LINK_DEAD")); + break; + case EV_LINK_ALIVE: + Serial.println(F("EV_LINK_ALIVE")); + break; + default: + Serial.println(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) { + Serial.println(F("OP_TXRXPEND, not sending")); + } else { + float temp(NAN), hum(NAN), pres(NAN), voltage(NAN); + + BME280::TempUnit tempUnit(BME280::TempUnit_Celcius); + BME280::PresUnit presUnit(BME280::PresUnit_hPa); + + // Read BME280/BMP280 sensor + bme.read(pres, temp, hum, tempUnit, presUnit); + + voltage = readVcc() / 1000.0 ; + + // Build CayenneLPP message + lpp.reset(); + lpp.addTemperature(1, temp); + lpp.addRelativeHumidity(2, hum); + lpp.addBarometricPressure(3, pres); + lpp.addAnalogInput(4, voltage); + + // Prepare upstream data transmission at the next possible time. + LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0); + + Serial.println(F("Packet queued")); + } + // Next TX is scheduled after TX_COMPLETE event. +} + +void setup() { + Serial.begin(9600); + Serial.println(F("Starting TTN Muc Sensor 4")); + + Wire.begin(); + + while (!bme.begin()) { + Serial.println("Could not find BME280 sensor!"); + delay(1000); + } + + // LMIC init + os_init(); + + // Reset the MAC state. Session and pending data transfers will be discarded. + LMIC_reset(); + + // Let LMIC compensate for +/- 1% clock error + LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); + + // Start job (sending automatically starts OTAA too) + do_send(&sendjob); +} + +void loop() { + os_runloop_once(); +} + diff --git a/lorawan-sensor.ino b/lorawan-sensor.ino deleted file mode 100644 index 628c87c..0000000 --- a/lorawan-sensor.ino +++ /dev/null @@ -1,223 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman - * - * Permission is hereby granted, free of charge, to anyone - * obtaining a copy of this document and accompanying files, - * to do whatever they want with them without any restriction, - * including, but not limited to, copying, modification and redistribution. - * NO WARRANTY OF ANY KIND IS PROVIDED. - * - * This example sends a valid LoRaWAN packet with payload "Hello, - * world!", using frequency and encryption settings matching those of - * the The Things Network. - * - * This uses OTAA (Over-the-air activation), where where a DevEUI and - * application key is configured, which are used in an over-the-air - * activation procedure where a DevAddr and session keys are - * assigned/generated for use with all further communication. - * - * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in - * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably - * violated by this sketch when left running for longer)! - * To use this sketch, first register your application and device with - * the things network, to set or generate an AppEUI, DevEUI and AppKey. - * Multiple devices can use the same AppEUI, but each device has its own - * DevEUI and AppKey. - * - * Do not forget to define the radio type correctly in config.h. - * - *******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include "config.h" - -void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);} -void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} -void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} - -static uint8_t mydata[] = "ping"; -static osjob_t sendjob; - -// Schedule TX every this many seconds (might become longer due to duty -// cycle limitations). -const unsigned TX_INTERVAL = 30; - -const lmic_pinmap lmic_pins = { - .nss = 10, - .rxtx = LMIC_UNUSED_PIN, - .rst = LMIC_UNUSED_PIN, // hardwired to AtMega RESET - .dio = {4,5,LMIC_UNUSED_PIN}// .dio = {4, 5, LMIC_UNUSED_PIN}, -}; - -CayenneLPP lpp(51); -BME280I2C bme; - -long readVcc() { - // Read 1.1V reference against AVcc - // set the reference to Vcc and the measurement to the internal 1.1V reference - #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); - #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) - ADMUX = _BV(MUX5) | _BV(MUX0); - #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) - ADMUX = _BV(MUX3) | _BV(MUX2); - #else - ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); - #endif - - delay(2); // Wait for Vref to settle - ADCSRA |= _BV(ADSC); // Start conversion - while (bit_is_set(ADCSRA,ADSC)); // measuring - - uint8_t low = ADCL; // must read ADCL first - it then locks ADCH - uint8_t high = ADCH; // unlocks both - - long result = (high<<8) | low; - - result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 - return result; // Vcc in millivolts -} - -void onEvent (ev_t ev) { - Serial.print(os_getTime()); - Serial.print(": "); - switch(ev) { - case EV_SCAN_TIMEOUT: - Serial.println(F("EV_SCAN_TIMEOUT")); - break; - case EV_BEACON_FOUND: - Serial.println(F("EV_BEACON_FOUND")); - break; - case EV_BEACON_MISSED: - Serial.println(F("EV_BEACON_MISSED")); - break; - case EV_BEACON_TRACKED: - Serial.println(F("EV_BEACON_TRACKED")); - break; - case EV_JOINING: - Serial.println(F("EV_JOINING")); - break; - case EV_JOINED: - Serial.println(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: - Serial.println(F("EV_RFU1")); - break; - case EV_JOIN_FAILED: - Serial.println(F("EV_JOIN_FAILED")); - break; - case EV_REJOIN_FAILED: - Serial.println(F("EV_REJOIN_FAILED")); - break; - break; - case EV_TXCOMPLETE: - Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); - if (LMIC.txrxFlags & TXRX_ACK) - Serial.println(F("Received ack")); - if (LMIC.dataLen) { - Serial.println(F("Received ")); - Serial.println(LMIC.dataLen); - Serial.println(F(" bytes of payload")); - } - /*Serial.print(F("Frequency: ")); - Serial.println(LMIC.freq); - Serial.print(F("RSSI: ")); - Serial.println(LMIC.rssi); - Serial.print(F("SNR: ")); - Serial.println(LMIC.snr); - Serial.print(F("txpow: ")); - Serial.println(LMIC.txpow);*/ - Serial.print(F("adrTxPow: ")); - Serial.println(LMIC.adrTxPow); - Serial.print(F("txChnl: ")); - Serial.println(LMIC.txChnl); - Serial.println(); - // Schedule next transmission - os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); - break; - case EV_LOST_TSYNC: - Serial.println(F("EV_LOST_TSYNC")); - break; - case EV_RESET: - Serial.println(F("EV_RESET")); - break; - case EV_RXCOMPLETE: - // data received in ping slot - Serial.println(F("EV_RXCOMPLETE")); - break; - case EV_LINK_DEAD: - Serial.println(F("EV_LINK_DEAD")); - break; - case EV_LINK_ALIVE: - Serial.println(F("EV_LINK_ALIVE")); - break; - default: - Serial.println(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) { - Serial.println(F("OP_TXRXPEND, not sending")); - } else { - float temp(NAN), hum(NAN), pres(NAN); - - BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); - BME280::PresUnit presUnit(BME280::PresUnit_hPa); - - bme.read(pres, temp, hum, tempUnit, presUnit); - - float voltage = readVcc() / 1000.0 ; - - lpp.reset(); - lpp.addTemperature(1, temp); - lpp.addRelativeHumidity(2, hum); - lpp.addBarometricPressure(3, pres); - lpp.addAnalogInput(4, voltage); - // Prepare upstream data transmission at the next possible time. - LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0); - Serial.println(F("Packet queued")); - } - // Next TX is scheduled after TX_COMPLETE event. -} - -void setup() { - Serial.begin(9600); - Serial.println(F("Starting TTN Muc Cayenne Sensor 1")); - - while(!bme.begin()) - { - Serial.println("Could not find BME280 sensor!"); - delay(1000); - } - - - - // LMIC init - os_init(); - - // Reset the MAC state. Session and pending data transfers will be discarded. - LMIC_reset(); - - // Let LMIC compensate for +/- 1% clock error - LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); - - // Start job (sending automatically starts OTAA too) - do_send(&sendjob); -} - -void loop() { - os_runloop_once(); -}