Compare commits
No commits in common. "e9067dd4a3579155a1fd40536d357e820393dddb" and "108a0f911c342667d26ca7ae49118c9898b354a9" have entirely different histories.
e9067dd4a3
...
108a0f911c
14 changed files with 150 additions and 329 deletions
30
README.md
30
README.md
|
@ -16,36 +16,6 @@ Before programming a node, copy src/config.h.example to src/config.h and set the
|
||||||
|
|
||||||
Programming is done using a [MicroUPDI Programmer](https://github.com/MCUdude/microUPDI), settings in platformio.ini are set to use it. For other pogrammer options see the PlatformIO Documentation
|
Programming is done using a [MicroUPDI Programmer](https://github.com/MCUdude/microUPDI), settings in platformio.ini are set to use it. For other pogrammer options see the PlatformIO Documentation
|
||||||
|
|
||||||
## Multisensor Mode
|
|
||||||
|
|
||||||
The Firmware can be configured for multiple sensors at once (see comments in config.h.example). In this case the default payload decoder from the website will not be able to correctly determine the used sensors. You **must** define a specific decoder in this case. In the TTN v3 Stack a decoder can be set per device. Use the following as an example, and uncomment the parts for each enabled sensor, then make sure the placeholder for the byte index (**ii**)
|
|
||||||
is filled in ascending order, starting with the first enabled sensor from left to right, beginning with 1
|
|
||||||
|
|
||||||
function decodeUplink(input) {
|
|
||||||
var decoded = {};
|
|
||||||
// Battery Voltage, always enabled
|
|
||||||
decoded.v = (input.bytes[0] * 20) / 1000.0;
|
|
||||||
|
|
||||||
// CO2-Sensor (SG112A, MH-Z19C, Sensair S8)
|
|
||||||
// decoded.ppm = ((input.bytes[ii]) | (input.bytes[ii] << 8 ));
|
|
||||||
|
|
||||||
// Temperature and Humidity (BME280 / SHT21)
|
|
||||||
// decoded.t = ((input.bytes[ii]) | (input.bytes[ii] << 8 ) | (input.bytes[ii] << 16 ) | (input.bytes[ii] << 24)) / 100.0;
|
|
||||||
// decoded.h = ((input.bytes[ii]) | (input.bytes[ii] << 8 ) | (input.bytes[ii] << 16 ) | (input.bytes[ii] << 24)) / 100.0;
|
|
||||||
|
|
||||||
// Atmospheric Pressure (BME280)
|
|
||||||
// decoded.p = ((input.bytes[ii]) | (input.bytes[ii] << 8 ) | (input.bytes[ii] << 16 ) | (input.bytes[ii] << 24)) / 100.0;
|
|
||||||
|
|
||||||
// Leave this part as is
|
|
||||||
return {
|
|
||||||
data: decoded,
|
|
||||||
warnings: [],
|
|
||||||
errors: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Please be also aware, that not all sensor combinations are valid. Some might use the same interface and interfere with each others readings. Also keep in mind that RAM- and Flash-Space are limited, which might lead to crashes or the code not compiling/flashing correctly if to many sensors are enabled at the same time.
|
|
||||||
|
|
||||||
## Configuring via Downlink
|
## Configuring via Downlink
|
||||||
|
|
||||||
It is possible to change the sending interval via Downlink-Packets at runtime. The time between Transmits is specified in minutes (or more exactly, 64 Second intervals) and has to be sent as a 2 byte value, which will be interpreted as an uint. so for example 0x0001 means 1 Minute, 0x0002 means 2 Minutes and so on. Sending 0xFFFF resets the value to the compiled in default.
|
It is possible to change the sending interval via Downlink-Packets at runtime. The time between Transmits is specified in minutes (or more exactly, 64 Second intervals) and has to be sent as a 2 byte value, which will be interpreted as an uint. so for example 0x0001 means 1 Minute, 0x0002 means 2 Minutes and so on. Sending 0xFFFF resets the value to the compiled in default.
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
attsensor.h - Define the Base Sensor Interface Class
|
|
||||||
Copyright (c) 2020-2021, Stefan Brand
|
|
||||||
All rights reserved.
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
#ifndef ATTSENSOR_H
|
|
||||||
#define ATTSENSOR_H
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
class AttSensor {
|
|
||||||
public:
|
|
||||||
// Put the Data into the Payload Array starting at <startbyte>
|
|
||||||
// Return the next startbyte when done
|
|
||||||
virtual uint8_t getSensorData(char *payload, uint8_t startbyte) = 0;
|
|
||||||
|
|
||||||
// Called in Setup, Do any Necessary Initialization
|
|
||||||
virtual void initialize(void) = 0;
|
|
||||||
|
|
||||||
// Return the number of Bytes added to the Payload
|
|
||||||
virtual uint8_t numBytes(void) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include "BME280.h"
|
#include "BME280.h"
|
||||||
|
|
||||||
|
@ -77,10 +78,10 @@ int32_t BME280::compensate_h(int32_t adc_H)
|
||||||
return (uint32_t)((v_x1_u32r>>12)/10);
|
return (uint32_t)((v_x1_u32r>>12)/10);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t BME280::getSensorData(char *payload, uint8_t startbyte) {
|
void BME280::getSensorData(lora_data &loradata) {
|
||||||
|
|
||||||
int32_t UP, UT, UH;
|
int32_t UP, UT, UH;
|
||||||
int32_t rawP, rawT, value;
|
int32_t rawP, rawT;
|
||||||
|
|
||||||
// Trigger Measurement
|
// Trigger Measurement
|
||||||
// Set Sensor Config
|
// Set Sensor Config
|
||||||
|
@ -104,28 +105,10 @@ uint8_t BME280::getSensorData(char *payload, uint8_t startbyte) {
|
||||||
// Read Humidity
|
// Read Humidity
|
||||||
UH = read16(0xFD);
|
UH = read16(0xFD);
|
||||||
|
|
||||||
|
// Compensate Values and Return
|
||||||
// Temperature
|
loradata.temperature = compensate_t(UT);
|
||||||
value = compensate_t(UT);
|
loradata.pressure = compensate_p(UP);
|
||||||
payload[startbyte] = (value) & 0XFF;
|
loradata.humidity = compensate_h(UH);
|
||||||
payload[startbyte+1] = (value >> 8) & 0XFF;
|
|
||||||
payload[startbyte+2] = (value >> 16) & 0XFF;
|
|
||||||
payload[startbyte+3] = (value >> 24) & 0XFF;
|
|
||||||
|
|
||||||
// Humidity
|
|
||||||
value = compensate_h(UH);
|
|
||||||
payload[startbyte+4] = (value) & 0XFF;
|
|
||||||
payload[startbyte+5] = (value >> 8) & 0XFF;
|
|
||||||
payload[startbyte+6] = (value >> 16) & 0XFF;
|
|
||||||
payload[startbyte+7] = (value >> 24) & 0XFF;
|
|
||||||
|
|
||||||
// Pressure
|
|
||||||
value = compensate_p(UP);
|
|
||||||
payload[startbyte+8] = (value) & 0XFF;
|
|
||||||
payload[startbyte+9] = (value >> 8) & 0XFF;
|
|
||||||
payload[startbyte+10] = (value >> 16) & 0XFF;
|
|
||||||
payload[startbyte+11] = (value >> 24) & 0XFF;
|
|
||||||
return startbyte+12;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t BME280::read8(uint8_t addr) {
|
uint8_t BME280::read8(uint8_t addr) {
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
#ifndef BME280_H
|
#ifndef BME280_H
|
||||||
#define BME280_H
|
#define BME280_H
|
||||||
|
|
||||||
#include "../../include/attsensor.h"
|
#include <stdint.h>
|
||||||
|
|
||||||
#define BME280_I2CADDR 0x76
|
#define BME280_I2CADDR 0x76
|
||||||
|
|
||||||
class BME280 : public AttSensor {
|
struct lora_data {
|
||||||
|
uint8_t bat;
|
||||||
|
int32_t temperature;
|
||||||
|
int32_t humidity;
|
||||||
|
int32_t pressure;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
class BME280
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
// Variables for Calibration Values
|
// Variables for Calibration Values
|
||||||
uint8_t dig_H1, dig_H3;
|
uint8_t dig_H1, dig_H3;
|
||||||
|
@ -28,12 +36,13 @@ private:
|
||||||
int16_t readS16(uint8_t addr);
|
int16_t readS16(uint8_t addr);
|
||||||
int16_t readS16_LE(uint8_t addr);
|
int16_t readS16_LE(uint8_t addr);
|
||||||
void write8(uint8_t addr, uint8_t data);
|
void write8(uint8_t addr, uint8_t data);
|
||||||
void getCalData(void);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BME280(void);
|
BME280(void);
|
||||||
uint8_t getSensorData(char *payload, uint8_t startbyte);
|
|
||||||
void initialize(void) {getCalData();};
|
// Get Calibration Data from Sensor
|
||||||
uint8_t numBytes(void) {return 12;};
|
void getCalData(void);
|
||||||
|
// Read Pressure From Sensor
|
||||||
|
void getSensorData(lora_data &loradata);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,23 +41,19 @@ void MHZ19C::initialize(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t MHZ19C::getSensorData(char * payload, uint8_t startbyte) {
|
void MHZ19C::getSensorData(lora_data &loradata) {
|
||||||
write(MHZ19C_CMD_GET_PPM, 0x00);
|
write(MHZ19C_CMD_GET_PPM, 0x00);
|
||||||
delay(50);
|
delay(50);
|
||||||
uint8_t readBytes = read();
|
uint8_t readBytes = read();
|
||||||
|
|
||||||
payload[startbyte] = 0x00;
|
loradata.ppm = 0;
|
||||||
payload[startbyte+1] = 0x00;
|
|
||||||
if (readBytes > 0) {
|
if (readBytes > 0) {
|
||||||
switch(buffer[1]) {
|
switch(buffer[1]) {
|
||||||
case 0x86:
|
case 0x86:
|
||||||
uint16_t value = (buffer[2]*256) + buffer[3];
|
loradata.ppm = (buffer[2]*256) + buffer[3];
|
||||||
payload[startbyte] = (value) & 0xFF;
|
|
||||||
payload[startbyte+1] = (value >> 8) & 0xFF;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return startbyte+2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn Self Calibration Routine On or Off
|
// Turn Self Calibration Routine On or Off
|
||||||
|
|
|
@ -27,7 +27,11 @@
|
||||||
#ifndef MHZ19C_H
|
#ifndef MHZ19C_H
|
||||||
#define MHZ19C_H
|
#define MHZ19C_H
|
||||||
|
|
||||||
#include "../../include/attsensor.h"
|
// Data Structure for the LoRa Packet
|
||||||
|
struct lora_data {
|
||||||
|
uint8_t bat;
|
||||||
|
int16_t ppm;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
#define MHZ19C_READ_TIMEOUT 500 // Timeout for Serial Communication
|
#define MHZ19C_READ_TIMEOUT 500 // Timeout for Serial Communication
|
||||||
#define MHZ19C_SER_BUF_LEN 9 // Length of the Internal Serial Message Buffer
|
#define MHZ19C_SER_BUF_LEN 9 // Length of the Internal Serial Message Buffer
|
||||||
|
@ -35,7 +39,7 @@
|
||||||
#define MHZ19C_CMD_SET_AUTOCAL 0x79 // Turn Self Calibration on/off
|
#define MHZ19C_CMD_SET_AUTOCAL 0x79 // Turn Self Calibration on/off
|
||||||
#define MHZ19C_CMD_GET_PPM 0x86 // Get Current PPM Reading
|
#define MHZ19C_CMD_GET_PPM 0x86 // Get Current PPM Reading
|
||||||
|
|
||||||
class MHZ19C : public AttSensor {
|
class MHZ19C {
|
||||||
private:
|
private:
|
||||||
uint8_t buffer[MHZ19C_SER_BUF_LEN];
|
uint8_t buffer[MHZ19C_SER_BUF_LEN];
|
||||||
|
|
||||||
|
@ -47,9 +51,8 @@ class MHZ19C : public AttSensor {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MHZ19C(void);
|
MHZ19C(void);
|
||||||
void initialize(void);
|
void MHZ19C::initialize(void);
|
||||||
uint8_t numBytes(void) {return 2;};
|
void getSensorData(lora_data &loradata);
|
||||||
uint8_t getSensorData(char *payload, uint8_t startbyte);
|
|
||||||
void setSelfCalibration(bool state);
|
void setSelfCalibration(bool state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ SENSAIRS8::SENSAIRS8(void) {
|
||||||
Serial.setTimeout(READ_TIMEOUT);
|
Serial.setTimeout(READ_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SENSAIRS8::getSensorData(char *payload, uint8_t startbyte) {
|
void SENSAIRS8::getSensorData(lora_data &loradata) {
|
||||||
uint8_t _cmd[7] = {0xFE, 0x44, 0x00, 0x08, 0x02, 0x9F, 0x25};
|
uint8_t _cmd[7] = {0xFE, 0x44, 0x00, 0x08, 0x02, 0x9F, 0x25};
|
||||||
while (Serial.available() > 0) Serial.read();
|
while (Serial.available() > 0) Serial.read();
|
||||||
Serial.write(_cmd, 7);
|
Serial.write(_cmd, 7);
|
||||||
|
@ -41,14 +41,9 @@ uint8_t SENSAIRS8::getSensorData(char *payload, uint8_t startbyte) {
|
||||||
delay(1000);
|
delay(1000);
|
||||||
uint8_t readBytes = read();
|
uint8_t readBytes = read();
|
||||||
|
|
||||||
payload[startbyte] = 0x00;
|
|
||||||
payload[startbyte+1] = 0x00;
|
|
||||||
if (readBytes > 0) {
|
if (readBytes > 0) {
|
||||||
uint16_t value = (buffer[3]*256) + buffer[4];
|
loradata.ppm = (buffer[3]*256) + buffer[4];
|
||||||
payload[startbyte] = (value) & 0xFF;
|
|
||||||
payload[startbyte+1] = (value >> 8) & 0xFF;
|
|
||||||
}
|
}
|
||||||
return startbyte+2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a Sensor Response
|
// Read a Sensor Response
|
||||||
|
|
|
@ -27,12 +27,16 @@
|
||||||
#ifndef SENSAIRS8_H
|
#ifndef SENSAIRS8_H
|
||||||
#define SENSAIRS8_H
|
#define SENSAIRS8_H
|
||||||
|
|
||||||
#include "../../include/attsensor.h"
|
// Data Structure for the LoRa Packet
|
||||||
|
struct lora_data {
|
||||||
|
uint8_t bat;
|
||||||
|
int16_t ppm;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
#define READ_TIMEOUT 500 // Timeout for Serial Communication
|
#define READ_TIMEOUT 500 // Timeout for Serial Communication
|
||||||
#define SER_BUF_LEN 7 // Length of the Internal Serial Message Buffer
|
#define SER_BUF_LEN 7 // Length of the Internal Serial Message Buffer
|
||||||
|
|
||||||
class SENSAIRS8 : public AttSensor {
|
class SENSAIRS8 {
|
||||||
private:
|
private:
|
||||||
uint8_t buffer[SER_BUF_LEN];
|
uint8_t buffer[SER_BUF_LEN];
|
||||||
|
|
||||||
|
@ -42,9 +46,7 @@ class SENSAIRS8 : public AttSensor {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SENSAIRS8(void);
|
SENSAIRS8(void);
|
||||||
uint8_t getSensorData(char *payload, uint8_t startbyte);
|
void getSensorData(lora_data &loradata);
|
||||||
void initialize(void) {};
|
|
||||||
uint8_t numBytes(void) {return 2;};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -33,24 +33,18 @@ SG112A::SG112A(void) {
|
||||||
Serial.setTimeout(READ_TIMEOUT);
|
Serial.setTimeout(READ_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SG112A::getSensorData(lora_data &loradata) {
|
||||||
uint8_t SG112A::getSensorData(char *payload, uint8_t startbyte) {
|
|
||||||
write(CMD_GET_PPM);
|
write(CMD_GET_PPM);
|
||||||
delay(50);
|
delay(50);
|
||||||
uint8_t readBytes = read();
|
uint8_t readBytes = read();
|
||||||
|
|
||||||
payload[startbyte] = 0x00;
|
|
||||||
payload[startbyte+1] = 0x00;
|
|
||||||
if (readBytes > 0) {
|
if (readBytes > 0) {
|
||||||
switch(buffer[2]) {
|
switch(buffer[2]) {
|
||||||
case 0x15:
|
case 0x15:
|
||||||
uint16_t value = (buffer[5]*256) + buffer[4];
|
loradata.ppm = (buffer[5]*256) + buffer[4];
|
||||||
payload[startbyte] = (value) & 0xFF;
|
|
||||||
payload[startbyte+1] = (value >> 8) & 0xFF;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return startbyte+2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a Command to the Sensor
|
// Write a Command to the Sensor
|
||||||
|
|
|
@ -27,7 +27,11 @@
|
||||||
#ifndef SG112A_H
|
#ifndef SG112A_H
|
||||||
#define SG112A_H
|
#define SG112A_H
|
||||||
|
|
||||||
#include "../../include/attsensor.h"
|
// Data Structure for the LoRa Packet
|
||||||
|
struct lora_data {
|
||||||
|
uint8_t bat;
|
||||||
|
int16_t ppm;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
#define READ_TIMEOUT 500 // Timeout for Serial Communication
|
#define READ_TIMEOUT 500 // Timeout for Serial Communication
|
||||||
#define SER_BUF_LEN 16 // Length of the Internal Serial Message Buffer
|
#define SER_BUF_LEN 16 // Length of the Internal Serial Message Buffer
|
||||||
|
@ -36,7 +40,7 @@
|
||||||
#define CMD_GET_SER 0x12 // Get Sensor Serial
|
#define CMD_GET_SER 0x12 // Get Sensor Serial
|
||||||
#define CMD_GET_PPM 0x14 // Get Current PPM Reading
|
#define CMD_GET_PPM 0x14 // Get Current PPM Reading
|
||||||
|
|
||||||
class SG112A : public AttSensor {
|
class SG112A {
|
||||||
private:
|
private:
|
||||||
uint8_t buffer[SER_BUF_LEN];
|
uint8_t buffer[SER_BUF_LEN];
|
||||||
|
|
||||||
|
@ -48,9 +52,7 @@ class SG112A : public AttSensor {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SG112A(void);
|
SG112A(void);
|
||||||
uint8_t getSensorData(char *payload, uint8_t startbyte);
|
void getSensorData(lora_data &loradata);
|
||||||
void initialize(void) {};
|
|
||||||
uint8_t numBytes(void) {return 2;};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -52,20 +52,7 @@ uint16_t SHT21::sensorRead(uint8_t command) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SHT21::getSensorData(char *payload, uint8_t startbyte) {
|
void SHT21::getSensorData(lora_data &loradata) {
|
||||||
// Temperature
|
loradata.temperature = (int32_t)((-46.85 + 175.72 / 65536.0 * (float)(sensorRead(SHT21_TEMPHOLD)))*100);
|
||||||
int32_t value = (int32_t)((-46.85 + 175.72 / 65536.0 * (float)(sensorRead(SHT21_TEMPHOLD)))*100);
|
loradata.humidity = (int32_t)((-6.0 + 125.0 / 65536.0 * (float)(sensorRead(SHT21_HUMIHOLD)))*100);
|
||||||
payload[startbyte] = (value) & 0XFF;
|
|
||||||
payload[startbyte+1] = (value >> 8) & 0XFF;
|
|
||||||
payload[startbyte+2] = (value >> 16) & 0XFF;
|
|
||||||
payload[startbyte+3] = (value >> 24) & 0XFF;
|
|
||||||
|
|
||||||
// Humidity
|
|
||||||
value = (int32_t)((-6.0 + 125.0 / 65536.0 * (float)(sensorRead(SHT21_HUMIHOLD)))*100);
|
|
||||||
payload[startbyte+4] = (value) & 0XFF;
|
|
||||||
payload[startbyte+5] = (value >> 8) & 0XFF;
|
|
||||||
payload[startbyte+6] = (value >> 16) & 0XFF;
|
|
||||||
payload[startbyte+7] = (value >> 24) & 0XFF;
|
|
||||||
|
|
||||||
return startbyte+8;
|
|
||||||
}
|
}
|
|
@ -27,7 +27,7 @@
|
||||||
#ifndef SHT21_H
|
#ifndef SHT21_H
|
||||||
#define SHT21_H
|
#define SHT21_H
|
||||||
|
|
||||||
#include "../../include/attsensor.h"
|
#include <inttypes.h>
|
||||||
|
|
||||||
#define SHT21_I2CADDR 0x40
|
#define SHT21_I2CADDR 0x40
|
||||||
|
|
||||||
|
@ -37,15 +37,20 @@
|
||||||
#define SHT21_HUMINOHOLD 0xF5
|
#define SHT21_HUMINOHOLD 0xF5
|
||||||
#define SHT21_SOFTRESET 0xFE
|
#define SHT21_SOFTRESET 0xFE
|
||||||
|
|
||||||
class SHT21 : public AttSensor {
|
struct lora_data {
|
||||||
|
uint8_t bat;
|
||||||
|
int32_t temperature;
|
||||||
|
int32_t humidity;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
class SHT21
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
uint16_t sensorRead(uint8_t command);
|
uint16_t sensorRead(uint8_t command);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SHT21(void);
|
SHT21(void);
|
||||||
uint8_t getSensorData(char *payload, uint8_t startbyte);
|
void getSensorData(lora_data &loradata);
|
||||||
void initialize(void) {};
|
|
||||||
uint8_t numBytes(void) {return 8;};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,80 +1,48 @@
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
// ALL EDITS BELOW THIS LINE!
|
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
// ATTNode v3 Onboard LED is on PIN_PA7
|
||||||
* Use a Single Color LED for Status Signaling
|
|
||||||
* At Startup the LED will blink twice to signal a sucessfull OTAA Join
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
#define LED_PIN PIN_PA7
|
#define LED_PIN PIN_PA7
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
// Enable WS2812B RGB LED Support for the CO2 Addon Board
|
||||||
* Enable WS2812B RGB LED Support for the CO2 Addon Board
|
// * First LED shows CO2-Level (green: <1000, yellow: 1000-1800, red: >=1800)
|
||||||
* * First LED shows CO2-Level (green: <1000, yellow: 1000-1800, red: >=1800)
|
// * Second LED shows LoRa Status (yellow: Joining, green 1s: Joined, green 100ms: Sending, blue 250ms: Received Downlink)
|
||||||
* * Second LED shows LoRa Status (yellow: Joining, green 1s: Joined, green 100ms: Sending, blue 250ms: Received Downlink)
|
// WS2812B_BRIGHT can be set to the desired brightness value for the LEDs (0=off, 255=brightest)
|
||||||
* WS2812B_BRIGHT can be set to the desired brightness value for the LEDs (0=off, 255=brightest)
|
// Uncomment the 3 following lines to get the default behaviour
|
||||||
* Uncomment the 3 following lines to get the default behaviour
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
// #define WS2812B_PIN PIN_PC1
|
// #define WS2812B_PIN PIN_PC1
|
||||||
// #define WS2812B_NUM 2
|
// #define WS2812B_NUM 2
|
||||||
// #define WS2812B_BRIGHT 32
|
// #define WS2812B_BRIGHT 32
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
// Enable Sending on Button Press, as well as Calibration by Pressing Button for 4s with MH-Z19C Addon
|
||||||
* Enable Sending on Button Press, as well as CO2 Background Level Calibration by Pressing Button for 4s with MH-Z19C Addon
|
// The Button has to be connected to a pin that is capable of Fully Asynchronus Interrupts.
|
||||||
* The Button has to be connected to a pin that is capable of Fully Asynchronus Interrupts.
|
// For The ATTNode this means Pin PC2 if you don't want to block any other Interfaces
|
||||||
* For The ATTNode this means Pin PC2 if you don't want to block any other Interfaces
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
// #define BTN_PIN PIN_PC2
|
// #define BTN_PIN PIN_PC2
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
// Enable Serial Debugging. Parameters for the Serial Port are 115200
|
||||||
* Enable Serial Debugging. Parameters for the Serial Port are 115200 Baud 8n1
|
// Please be aware that the SG112A/B CO2 Sensor uses the HW-UART, so
|
||||||
* By default the Firmware will output some messages about LoRa-Status and indicate sending
|
// Serial Debug Output is not available with this Sensor.
|
||||||
* The Macros DEBUG_PRINT() and DEBUG_PRINTLN() can be used to produce debug output depending on this define
|
|
||||||
* Please be aware that this will not work when a Serial Sensor like the SG112A/MH-Z19C or Sensair S8 ist used
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
|
|
||||||
|
// Define which Sensor is installed
|
||||||
/**************************************************************************************************************************
|
|
||||||
* Number of active Sensors (used as long as HAS_NO_SENSOR is not enabled)
|
|
||||||
* Set to the correct number of enabled sensors below
|
|
||||||
* Not doing so will lead to unpredictable results or not work at all
|
|
||||||
* The default payload decoder will NOT WORK if more than one sensor is enabled, so you MUST define a specific
|
|
||||||
* decoder for this case. See the README.md for details
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
#define NUM_SENSORS 1
|
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
|
||||||
* Define which Sensors are installed
|
|
||||||
* Not all sensors can be used at the same time
|
|
||||||
* For example you can only have one sensor using serial UART
|
|
||||||
* If HAS_NO_SENSOR is selected all other activated sensor will be ignored
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
#define HAS_NO_SENSOR
|
#define HAS_NO_SENSOR
|
||||||
// #define HAS_MHZ19C
|
|
||||||
// #define HAS_SG112A
|
|
||||||
// #define HAS_SENSAIRS8
|
|
||||||
// #define HAS_BME280
|
// #define HAS_BME280
|
||||||
// #define HAS_SHT21
|
// #define HAS_SHT21
|
||||||
|
// #define HAS_SG112A
|
||||||
|
// #define HAS_MHZ19C
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
|
||||||
* How many minutes to sleep between Measuring/Sending
|
// How many minutes to sleep between Measuring/Sending
|
||||||
* Since this is a 2-byte value internally, intervals between 1 and 65536 are possible
|
// Since this is a 2-byte value internally, intervals between 1 and 65536 are possible
|
||||||
* This is the default interval to use, which can be overwritten via DownLink. If an interval
|
// This is the default interval to use, which can be overwritten via DownLink. If an interval
|
||||||
* is set via DownLink it will be saved in EEPROM and the time specified here will no longer be used.
|
// is set via DownLink it will be saved in EEPROM and the time specified here will no longer be used.
|
||||||
* Actual sleep Time is sleep_time*2*32 seconds due to the 32s sleep intervals of the ATTiny3216
|
// Actual Sleep Time is SLEEP_TIME*2*32 Seconds due to the 32s sleep intervals of the ATTiny3216
|
||||||
*************************************************************************************************************************/
|
|
||||||
uint16_t sleep_time = 10;
|
uint16_t sleep_time = 10;
|
||||||
|
|
||||||
/**************************************************************************************************************************
|
// Keys for OTAA Mode
|
||||||
* LoRa Keys for OTAA Mode
|
// APPEUI and DEVEUI from TTN, LSB!
|
||||||
* Please make sure to use the correct byte order when copying these from the TTN-Console!
|
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
* APPEUI and DEVEUI need to be inserted in LSB order
|
static const u1_t PROGMEM DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
* APPKEY needs to be inserted in MSB order
|
// APPKey from TTN, MSB!
|
||||||
* in some cases there is no APPEUI, for example when using Chirpstack. leave it set to all 0x00 in these cases
|
|
||||||
*************************************************************************************************************************/
|
|
||||||
static const u1_t PROGMEM APPEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
static const u1_t PROGMEM DEVEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
static const u1_t PROGMEM APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
static const u1_t PROGMEM APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
// ALL EDITS ABOVE THIS LINE!
|
// ALL EDITS ABOVE THIS LINE!
|
||||||
|
|
165
src/main.cpp
165
src/main.cpp
|
@ -11,31 +11,10 @@
|
||||||
// Keep Track of used EEPROM Addresses
|
// Keep Track of used EEPROM Addresses
|
||||||
#define ADDR_SLP 0 // Sleep Interval, 2 Bytes
|
#define ADDR_SLP 0 // Sleep Interval, 2 Bytes
|
||||||
|
|
||||||
// Include Config and Helpers
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "attsensor.h"
|
|
||||||
|
|
||||||
// Include All Sensors Activated in config.h
|
// define the blink function and BLINK_LED Macro depending
|
||||||
#ifndef HAS_NO_SENSOR
|
|
||||||
#ifdef HAS_MHZ19C
|
|
||||||
#include <MHZ19C.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SG112A
|
|
||||||
#include <SG112A.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SENSAIRS8
|
|
||||||
#include <SENSAIRS8.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_BME280
|
|
||||||
#include <BME280.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SHT21
|
|
||||||
#include <SHT21.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Define the blink function and BLINK_LED Macro depending
|
|
||||||
// on the definition of LED_PIN
|
// on the definition of LED_PIN
|
||||||
#ifdef LED_PIN
|
#ifdef LED_PIN
|
||||||
void blink(uint8_t num) {
|
void blink(uint8_t num) {
|
||||||
|
@ -65,14 +44,31 @@ void blink(uint8_t num) {
|
||||||
#define WS2812B_BLINK(led,r,g,b,ms)
|
#define WS2812B_BLINK(led,r,g,b,ms)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create Array for the Sensor Objects
|
// Create the Sensor Objects
|
||||||
#ifndef HAS_NO_SENSORS
|
#if defined HAS_NO_SENSOR
|
||||||
AttSensor* sensors[NUM_SENSORS];
|
struct lora_data {
|
||||||
|
uint8_t bat;
|
||||||
|
} __attribute ((packed));
|
||||||
|
#elif defined HAS_MHZ19C
|
||||||
|
#include <MHZ19C.h>
|
||||||
|
MHZ19C sensor;
|
||||||
|
#elif defined HAS_SG112A
|
||||||
|
#include <SG112A.h>
|
||||||
|
SG112A sensor;
|
||||||
|
#elif defined HAS_SENSAIRS8
|
||||||
|
#include <SENSAIRS8.h>
|
||||||
|
SENSAIRS8 sensor;
|
||||||
|
#elif defined HAS_BME280
|
||||||
|
#include <BME280.h>
|
||||||
|
BME280 sensor;
|
||||||
|
#elif defined HAS_SHT21
|
||||||
|
#include <SHT21.h>
|
||||||
|
SHT21 sensor;
|
||||||
|
#elif defined HAS_SG112A
|
||||||
|
#include <SG112A.h>
|
||||||
|
SG112A sensor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Track Length of Payload (Depends on Active Sensors)
|
|
||||||
int payloadBytes = 1;
|
|
||||||
|
|
||||||
// Define some LMIC Callbacks and Variables
|
// Define some LMIC Callbacks and Variables
|
||||||
void os_getArtEui (u1_t* buf) {
|
void os_getArtEui (u1_t* buf) {
|
||||||
memcpy_P(buf, APPEUI, 8);
|
memcpy_P(buf, APPEUI, 8);
|
||||||
|
@ -101,7 +97,6 @@ const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2
|
||||||
const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB3, PIN_PB2, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0};
|
const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB3, PIN_PB2, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Helper variables and Interrupt Routine for Button
|
|
||||||
#ifdef BTN_PIN
|
#ifdef BTN_PIN
|
||||||
volatile bool btn_pressed = 0;
|
volatile bool btn_pressed = 0;
|
||||||
volatile unsigned long btn_millis = 0;
|
volatile unsigned long btn_millis = 0;
|
||||||
|
@ -114,19 +109,19 @@ void btn_press() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Interrupt Routine for Sleep
|
// ISR Routine for Sleep
|
||||||
ISR(RTC_PIT_vect)
|
ISR(RTC_PIT_vect)
|
||||||
{
|
{
|
||||||
/* Clear interrupt flag by writing '1' (required) */
|
/* Clear interrupt flag by writing '1' (required) */
|
||||||
RTC.PITINTFLAGS = RTC_PI_bm;
|
RTC.PITINTFLAGS = RTC_PI_bm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep Routine, Sleep for 32 Seconds
|
// Sleep Routine
|
||||||
void sleep_32s() {
|
void sleep_32s() {
|
||||||
cli();
|
cli();
|
||||||
while (RTC.PITSTATUS > 0) {}
|
while (RTC.PITSTATUS > 0) {}
|
||||||
RTC.PITINTCTRL = RTC_PI_bm;
|
RTC.PITINTCTRL = RTC_PI_bm;
|
||||||
// 32 Seconds
|
// 32 Sekunden
|
||||||
RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm;
|
RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc | RTC_PITEN_bm;
|
||||||
while (RTC.PITSTATUS & RTC_CTRLBUSY_bm) {}
|
while (RTC.PITSTATUS & RTC_CTRLBUSY_bm) {}
|
||||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||||
|
@ -164,7 +159,6 @@ void onEvent(ev_t ev) {
|
||||||
// Got to sleep for specified Time
|
// Got to sleep for specified Time
|
||||||
DEBUG_PRINTLN("Going to Sleep");
|
DEBUG_PRINTLN("Going to Sleep");
|
||||||
for (uint16_t i = 0; i < sleep_time*2; i++) {
|
for (uint16_t i = 0; i < sleep_time*2; i++) {
|
||||||
// Cancel sleep Cycle if Button was Pressed
|
|
||||||
#ifdef BTN_PIN
|
#ifdef BTN_PIN
|
||||||
if (btn_pressed) {
|
if (btn_pressed) {
|
||||||
i = sleep_time*2;
|
i = sleep_time*2;
|
||||||
|
@ -200,65 +194,55 @@ uint16_t readSupplyVoltage() { //returns value in millivolts to avoid floating p
|
||||||
|
|
||||||
// Read Sensors and Send Data
|
// Read Sensors and Send Data
|
||||||
void do_send(osjob_t* j) {
|
void do_send(osjob_t* j) {
|
||||||
// Array of Bytes for the Payload
|
// Prepare LoRa Data Packet
|
||||||
// Length is defined by the Enabled Sensors
|
// The struct is defined in the sensor class (or above for use without a sensor)
|
||||||
char payload[payloadBytes];
|
lora_data data;
|
||||||
|
|
||||||
if (LMIC.opmode & OP_TXRXPEND) {
|
if (LMIC.opmode & OP_TXRXPEND) {
|
||||||
// Wayt if LMIC is busy
|
|
||||||
delay(1);
|
delay(1);
|
||||||
} else {
|
} else {
|
||||||
// Track Current Position in Payload Array
|
|
||||||
uint8_t curByte = 0;
|
|
||||||
|
|
||||||
// Add Battery Voltage (0.2V Accuracy stored in 1 byte)
|
// Add Battery Voltage (0.2V Accuracy stored in 1 byte)
|
||||||
uint32_t batv = readSupplyVoltage();
|
uint32_t batv = readSupplyVoltage();
|
||||||
payload[curByte] = (uint8_t)(batv / 20);
|
data.bat = (uint8_t)(batv / 20);
|
||||||
if (batv % 20 > 9)
|
if (batv % 20 > 9)
|
||||||
payload[curByte] += 1;
|
data.bat += 1;
|
||||||
curByte++;
|
|
||||||
|
|
||||||
|
// Get Sensor Readings Into Data Paket
|
||||||
#ifndef HAS_NO_SENSOR
|
#ifndef HAS_NO_SENSOR
|
||||||
// Put Sensor Readings into the Payload Array
|
sensor.getSensorData(data);
|
||||||
for (int i=0; i < NUM_SENSORS; i++)
|
|
||||||
curByte = sensors[i]->getSensorData(payload, curByte);
|
// Queue Packet for Sending
|
||||||
|
DEBUG_PRINTLN("LoRa-Packet Queued");
|
||||||
|
LMIC_setTxData2(1, (unsigned char *)&data, sizeof(data), 0);
|
||||||
|
|
||||||
|
#if defined WS2812B_PIN && (defined HAS_SG112A || defined HAS_MHZ19C)
|
||||||
|
|
||||||
// If CO2 Addon Boards with RGB-LEDS is installed, set LED according to the current CO2 Reading
|
|
||||||
#if defined WS2812B_PIN && (defined HAS_SG112A || defined HAS_MHZ19C || defined HAS_SENSAIRS8)
|
|
||||||
// CO2 PPM Levels and LED Colors
|
// CO2 PPM Levels and LED Colors
|
||||||
// < 1000 ppm green
|
// < 1000 ppm green
|
||||||
// < 1800 ppm yellow
|
// < 1800 ppm yellow
|
||||||
// > 1000 ppm red
|
// > 1000 ppm red
|
||||||
|
|
||||||
// Get PPM from Payload:
|
if (data.ppm > 0 && data.ppm <= 1000) {
|
||||||
uint16_t ppm = word(payload[2], payload[1]);
|
|
||||||
|
|
||||||
// Set WS2812B-LED accodring to PPM Value
|
|
||||||
if (ppm > 0 && ppm <= 1000) {
|
|
||||||
WS2812B_SETLED(0,0,127,0);
|
WS2812B_SETLED(0,0,127,0);
|
||||||
} else if (ppm > 1000 && ppm <= 1800) {
|
} else if (data.ppm > 1000 && data.ppm <= 1800) {
|
||||||
WS2812B_SETLED(0,127,127,0);
|
WS2812B_SETLED(0,127,127,0);
|
||||||
} else if (ppm > 1800) {
|
} else if (data.ppm > 1800) {
|
||||||
WS2812B_SETLED(0,127,0,0);
|
WS2812B_SETLED(0,127,0,0);
|
||||||
} else {
|
} else {
|
||||||
WS2812B_SETLED(0,0,0,0);
|
WS2812B_SETLED(0,0,0,0);
|
||||||
}
|
}
|
||||||
#endif // WS2812B
|
#endif // WS2812B
|
||||||
#endif // HAS_NO_SENSOR
|
#endif // #infdef HAS_NO_SENSOR
|
||||||
|
|
||||||
|
|
||||||
// Queue Packet for Sending
|
|
||||||
DEBUG_PRINTLN("LoRa-Packet Queued");
|
|
||||||
LMIC_setTxData2(1, payload, sizeof(payload), 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
// Initialize Serial if Debug is enabled
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialize SPI and I2C
|
// Initialize SPI and I2C
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
|
@ -267,67 +251,36 @@ void setup()
|
||||||
for (int i = 0; i < (sizeof(disabledPins) / sizeof(disabledPins[0])) - 1; i++)
|
for (int i = 0; i < (sizeof(disabledPins) / sizeof(disabledPins[0])) - 1; i++)
|
||||||
pinMode(disabledPins[i], INPUT_PULLUP);
|
pinMode(disabledPins[i], INPUT_PULLUP);
|
||||||
|
|
||||||
// Setup WS2812B LEDs
|
|
||||||
#ifdef WS2812B_PIN
|
#ifdef WS2812B_PIN
|
||||||
pinMode(WS2812B_PIN, OUTPUT);
|
pinMode(WS2812B_PIN, OUTPUT);
|
||||||
leds.setBrightness(WS2812B_BRIGHT);
|
leds.setBrightness(WS2812B_BRIGHT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setup Button Interrupt
|
|
||||||
#ifdef BTN_PIN
|
#ifdef BTN_PIN
|
||||||
pinMode(BTN_PIN, INPUT_PULLUP);
|
pinMode(BTN_PIN, INPUT_PULLUP);
|
||||||
attachInterrupt(digitalPinToInterrupt(BTN_PIN), btn_press, FALLING);
|
attachInterrupt(digitalPinToInterrupt(BTN_PIN), btn_press, FALLING);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setup all Sensors and Calculate the Payload Length
|
// Set RTC
|
||||||
// Order of the Sensors here is Order in the Payload
|
|
||||||
#ifndef HAS_NO_SENSOR
|
|
||||||
uint8_t i = 0;
|
|
||||||
#ifdef HAS_MHZ19C
|
|
||||||
sensors[i] = new MHZ19C();
|
|
||||||
payloadBytes += sensors[i]->numBytes();
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SG112A
|
|
||||||
sensors[i] = new SG112A();
|
|
||||||
payloadBytes += sensors[i]->numBytes();
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SENSAIRS8
|
|
||||||
sensors[i] = new SENSAIRS8();
|
|
||||||
payloadBytes += sensors[i]->numBytes();
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_BME280
|
|
||||||
sensors[i] = new BME280();
|
|
||||||
payloadBytes += sensors[i]->numBytes();
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SHT21
|
|
||||||
sensors[i] = new SHT21();
|
|
||||||
payloadBytes += sensors[i]->numBytes();
|
|
||||||
i++;
|
|
||||||
#endif
|
|
||||||
#endif // HAS_NO_SENSOR
|
|
||||||
|
|
||||||
// Initialize all Sensors
|
|
||||||
#ifndef HAS_NO_SENSOR
|
|
||||||
for (i = 0; i < NUM_SENSORS; i++)
|
|
||||||
sensors[i]->initialize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Setup RTC
|
|
||||||
while (RTC.STATUS > 0) {}
|
while (RTC.STATUS > 0) {}
|
||||||
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;
|
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;
|
||||||
while (RTC.PITSTATUS > 0) {}
|
while (RTC.PITSTATUS > 0) {}
|
||||||
|
|
||||||
|
// Initialize Sensor(s)
|
||||||
|
#ifdef HAS_BME280
|
||||||
|
sensor.getCalData();
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_MHZ19C
|
||||||
|
sensor.initialize();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Setup LMIC
|
// Setup LMIC
|
||||||
DEBUG_PRINT("Initializing LMIC...")
|
DEBUG_PRINT("Initializing LMIC...")
|
||||||
os_init();
|
os_init();
|
||||||
LMIC_reset(); // Reset LMIC state and cancel all queued transmissions
|
LMIC_reset(); // Reset LMIC state and cancel all queued transmissions
|
||||||
LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100); // Compensate for Clock Skew
|
LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100); // Compensate for Clock Skew
|
||||||
LMIC.dn2Dr = DR_SF9; // Downlink Band
|
LMIC.dn2Dr = DR_SF9; // Downlink Band
|
||||||
LMIC_setDrTxpow(DR_SF7, 14); // Default to SF7
|
LMIC_setDrTxpow(DR_SF7, 14); // Default to SF7
|
||||||
DEBUG_PRINTLN("Done");
|
DEBUG_PRINTLN("Done");
|
||||||
|
|
||||||
// Check if Sending Interval is set in EEPROM
|
// Check if Sending Interval is set in EEPROM
|
||||||
|
@ -342,15 +295,13 @@ void setup()
|
||||||
|
|
||||||
DEBUG_PRINTLN("Setup Finished");
|
DEBUG_PRINTLN("Setup Finished");
|
||||||
|
|
||||||
// Set WS2812B to Yellow for "Joining" (if enabled)
|
|
||||||
WS2812B_SETLED(1,127,127,0);
|
|
||||||
// Schedule First Send (Triggers OTAA Join as well)
|
// Schedule First Send (Triggers OTAA Join as well)
|
||||||
|
WS2812B_SETLED(1,127,127,0);
|
||||||
do_send(&sendjob);
|
do_send(&sendjob);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// Handle long Button Press for Calibration with MH-Z19C Sensor
|
|
||||||
#if defined HAS_MHZ19C && defined BTN_PIN
|
#if defined HAS_MHZ19C && defined BTN_PIN
|
||||||
if (digitalRead(BTN_PIN) == LOW) {
|
if (digitalRead(BTN_PIN) == LOW) {
|
||||||
// Press Button longer than 4 Seconds -> Start MH-Z19C Calibration Routine
|
// Press Button longer than 4 Seconds -> Start MH-Z19C Calibration Routine
|
||||||
|
|
Loading…
Reference in a new issue