Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
|
Electronics
Mechanics
All together
Tune it up!
Read more- 90uA during deep-sleep- 30mA during measurement and send
Solar Charger
Preparing base PCB
Done:
The Case
Arduino Code
Arduinosends data every 15 min (900.000 millis)
replace "YOUR xxx from TTN CONSOLE" with your TTN device setting
replace "YOUR xxx from TTN CONSOLE" with your TTN device setting
#include <lmic.h>
#include <hal/hal.h>
#include <bsec.h>
#include <Wire.h>
#include <Ticker.h>
#include <ESP8266WiFi.h>
#define fuel_on 1
#ifdef fuel_on
#include "MAX17043.h"
#endif
int fuel = 0 ;
int battery = 0 ;
// LoraWAN Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
// (c) 2018 Terry Moore, MCCI
// https://github.com/mcci-catena/arduino-lmic
// -------- LoRa PinMapping FeatherWing Octopus
const lmic_pinmap lmic_pins = {
.nss = 2, // Connected to pin D
.rxtx = LMIC_UNUSED_PIN, // For placeholder only, Do not connected on RFM92/RFM95
.rst = LMIC_UNUSED_PIN, // Needed on RFM92/RFM95? (probably not) D0/GPIO16
.dio = {
15, 15, LMIC_UNUSED_PIN }
};
void os_getArtEui (u1_t* buf) {
}
void os_getDevEui (u1_t* buf) {
}
void os_getDevKey (u1_t* buf) {
}
// bach-03-001-abp // fuel on
static const u4_t DEVADDR = YOUR DEV ADDR FROM TTN CONSOLE;
static const u1_t PROGMEM APPSKEY[16]={
YOUR APP KEY FROM TTN CONSOLE };
static const u1_t PROGMEM NWKSKEY[16]={
YOUR NETWORK KEY FROM TTN CONSOLE };
volatile int LoRaWAN_Tx_Ready = 0; // Merker für ACK
int LoRaWAN_Rx_Payload = 0 ;
// -------- LoRa Event
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"));
LoRaWAN_Rx_Payload = 0;
for (int i = 0;i<LMIC.dataLen;i++) {
Serial.println(LMIC.frame[i+ LMIC.dataBeg],HEX);
LoRaWAN_Rx_Payload = 256*LoRaWAN_Rx_Payload+LMIC.frame[i+ LMIC.dataBeg];
}
}
LoRaWAN_Tx_Ready = 1;
// 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;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
case EV_JOIN_TXCOMPLETE:
Serial.println(F("EV_JOIN_TXCOMPLETE"));
break;
default:
Serial.println(F("Unknown event"));
break;
}
}
/*
Bosch BSEC Lib, https://github.com/BoschSensortec/BSEC-Arduino-library
The BSEC software is only available for download or use after accepting the software license agreement.
By using this library, you have agreed to the terms of the license agreement:
https://ae-bst.resource.bosch.com/media/_tech/media/bsec/2017-07-17_ClickThrough_License_Terms_Environmentalib_SW_CLEAN.pdf */
Bsec iaqSensor; // Create an object of the class Bsec
Ticker Bsec_Ticker; // schedule cyclic update via Ticker
// ------------------------ Helper functions Bosch Bsec - Lib
void checkIaqSensorStatus(void)
{
String output;
if (iaqSensor.status != BSEC_OK) {
if (iaqSensor.status < BSEC_OK) {
output = "BSEC error code : " + String(iaqSensor.status);
for (;;) {
Serial.println(output);
delay(500);
} // Halt in case of failure
}
else {
output = "BSEC warning code : " + String(iaqSensor.status);
Serial.println(output);
}
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme680Status < BME680_OK) {
output = "BME680 error code : " + String(iaqSensor.bme680Status);
for (;;){
Serial.println(output);
delay(500);
} // Halt in case of failure
}
else {
output = "BME680 warning code : " + String(iaqSensor.bme680Status);
Serial.println(output);
}
}
}
// Housekeeping: scheduled update using ticker-lib
void iaqSensor_Housekeeping(){ // get new data
iaqSensor.run();
}
extern "C" { // zur Nutzung der speziellen ESP-Befehle wie Deep Sleep
#include "user_interface.h"
}
void setup(){ // Einmalige Initialisierung
pinMode( 0 , OUTPUT);
Serial.begin(115200);
// -- Initialisiere LoraWAN
os_init(); // LMIC LoraWAN
LMIC_reset(); // Reset the MAC state
LMIC.txpow = 27; // Maximum TX power
LMIC.datarate=DR_SF12; // Long Range
LMIC.rps = updr2rps(LMIC.datarate);
// Set static session parameters. Instead of dynamically establishing a session
// by joining the network, precomputed session parameters are be provided.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession (0x13, DEVADDR, nwkskey, appskey);
// Set up the channels used by the Things Network, which corresponds
// to the defaults of most gateways. Without this, only three base
// channels from the LoRaWAN specification are used
LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band
LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band
LMIC_setLinkCheckMode(0); // Disable link check validation
LMIC.dn2Dr = DR_SF9; // TTN uses SF9 for its RX2 window.
LMIC_setDrTxpow(DR_SF7,14); // Set data rate and transmit power for uplink
Wire.begin(); // ---- Initialisiere den I2C-Bus
#ifdef fuel_on
FuelGauge.begin();
#endif
iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire);
String output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix);
Serial.println(output);
checkIaqSensorStatus();
bsec_virtual_sensor_t sensorList[10] = {
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
};
iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
checkIaqSensorStatus();
iaqSensor_Housekeeping();
Bsec_Ticker.attach_ms(2000, iaqSensor_Housekeeping);
digitalWrite( 0 , LOW );
#ifdef fuel_on
FuelGauge.quickstart();
#endif
delay( 10000 );
fuel = 0 ;
battery = 0 ;
#ifdef fuel_on
Serial.print("Version: "); Serial.println(FuelGauge.version());
Serial.print("ADC: "); Serial.println(FuelGauge.adc());
Serial.print("Voltage: "); Serial.print(FuelGauge.voltage()); Serial.println(" v");
Serial.print("Percent: "); Serial.print(FuelGauge.percent()); Serial.println("%");
Serial.print("Is Sleeping: "); Serial.println(FuelGauge.isSleeping() ? "Yes" : "No");
Serial.print("Alert: "); Serial.println(FuelGauge.alertIsActive() ? "Yes" : "No");
Serial.print("Threshold: "); Serial.println(FuelGauge.getThreshold());
Serial.print("Compensation: 0x"); Serial.println(FuelGauge.compensation(), HEX);
// FuelGauge.sleep();
// FuelGauge.quickstart();
// FuelGauge.wake();
fuel = FuelGauge.percent();
battery = FuelGauge.voltage();
#endif
{ //Block------------------------------ sende Daten an TTN
int port = 10;
static uint8_t mydata[18];
int wert=round(analogRead(0)*1000);
mydata[0] = wert >> 16;
mydata[1] = wert >> 8;
mydata[2] = wert ;
wert=round(iaqSensor.temperature*1000);
mydata[3] = wert >> 16;
mydata[4] = wert >> 8;
mydata[5] = wert ;
wert=round(iaqSensor.humidity*1000);
mydata[6] = wert >> 16;
mydata[7] = wert >> 8;
mydata[8] = wert ;
wert=round((iaqSensor.pressure/100.)*1000);
mydata[9] = wert >> 16;
mydata[10] = wert >> 8;
mydata[11] = wert ;
wert=round(battery*1000);
mydata[12] = wert >> 16;
mydata[13] = wert >> 8;
mydata[14] = wert ;
wert=round(fuel*1000);
mydata[15] = wert >> 16;
mydata[16] = wert >> 8;
mydata[17] = wert ;
// Check if there is not a current TX/RX job running
//if (LMIC.opmode & OP_TXRXPEND) {
if (LMIC.opmode & (1 << 7)) {
Serial.println(F("OP_TXRXPEND, not sending"));
}
else {
// Prepare upstream data transmission at the next possible time.
LoRaWAN_Tx_Ready = 0; // Merker für ACK
LMIC_setTxData2(port, mydata, sizeof(mydata), 0); // Sende
Serial.println(F("Packet queued"));
while(LoRaWAN_Tx_Ready==0) {
yield();
os_runloop_once();
}; // Warte bis gesendet
}
} // Blockende
delay( 500 );
WiFi.disconnect( true );
delay(2); // Wifi Off
ESP.deepSleep( (long)900000*1000UL,WAKE_RF_DISABLED);//Tiefschlaf, danach Reset und von vorn
}
void loop() { // Kontinuierliche Wiederholung
}
Comments