Open littlejogi opened 2 years ago
Here is my "working" code (TTN and private Chirpstack):
/* Version sends to Chirpstack; TTN also works
based on https://github.com/Makerfabs/Lora-Soil-Moisture-Sensor/blob/master/
Chirpstack Decoder:
function Decode(fPort, bytes){
var data = {
battery:((bytes[0]) + (bytes[1]/100)),
temperature:((bytes[2]) + (bytes[3]/100)),
humidity:((bytes[4]) + (bytes[5]/100)),
moisture:((bytes[6])+ (bytes[7]<<8)),
};
return data;
}
*/
#include <lmic.h>
#include <hal/hal.h>
#include "I2C_AHT10.h"
#include <avr/wdt.h>
#include <avr/sleep.h>
#define M_MOSI 11
#define M_MISO 12
#define M_SCLK 13
#define M_CS 10
#define M_DIO0 2
#define M_DIO1 6
#define M_DIO2 7
#define M_DIO5 8
#define M_RST 9
#define DEBUG_OUT_ENABLE 0
//Set sleep time, when value is 1 almost sleep 20s,when value is 450, almost 1 hour.
#define SLEEP_CYCLE 104 // 8 ca. 64 Sek., 104 ca. 15 Min.
#define SENSOR_POWER_PIN 5
int ADC_O_1; // ADC Output First 8 bits
int ADC_O_2; // ADC Output Next 2 bits
AHT10 humiditySensor;
int sensorPin = A2; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
int sensorPowerCtrlPin = 5;
int PWM_OUT_PIN = 9;
int16_t packetnum = 0; // packet counter, we increment per xmission
float temperature = 0.0; //
float humidity = 0.0;
int batValue = 0; // the voltage of battery
int count = 0;
#define LMIC_DEBUG_LEVEL 2
static const PROGMEM u1_t NWKSKEY[16] = { /* tbd */};
static const u1_t PROGMEM APPSKEY[16] = { /* tbd */ };
static const u4_t DEVADDR = /* tbd */;
// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
static uint8_t mydata[] = {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static osjob_t sendjob;
// Pin mapping
const lmic_pinmap lmic_pins = {
.nss = M_CS,
.rxtx = LMIC_UNUSED_PIN,
.rst = M_RST,
.dio = {M_DIO0, M_DIO1, M_DIO2},
};
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
{
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
#if DEBUG_OUT_ENABLE
Serial.print(F("Packet queued"));
Serial.print(": (0) " + String(mydata[0]));
Serial.print(", (1) " + String(mydata[1]));
Serial.print(", (2) " + String(mydata[2]));
Serial.print(", (3) " + String(mydata[3]));
Serial.print(", (4) " + String(mydata[4]));
Serial.print(", (5) " + String(mydata[5]));
Serial.print(", (6) " + String(mydata[6]));
Serial.println(", (7) " + String(mydata[7]));
#endif
}
}
void readSensor()
{
sensorPowerOn();
digitalWrite(SENSOR_POWER_PIN, HIGH); // Sensor/RF95 power on
delay(100);
digitalWrite(SENSOR_POWER_PIN, HIGH); // Sensor/RF95 power on
pinMode(PWM_OUT_PIN, OUTPUT); //digitalWrite(PWM_OUT_PIN, LOW);
TCCR1A = bit(COM1A0); // toggle OC1A on Compare Match
TCCR1B = bit(WGM12) | bit(CS10); // CTC, scale to clock
OCR1A = 1; // compare A register value (5000 * clock speed / 1024).When OCR1A == 1, PWM is 2MHz
//ADC2 AVCC as reference voltage
ADMUX = _BV(REFS0) | _BV(MUX1);
ADCSRA = _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0);
delay(50);
for (int i = 0; i < 3; i++)
{
//start ADC conversion
ADCSRA |= (1 << ADSC);
delay(10);
if ((ADCSRA & 0x40) == 0)
{
ADC_O_1 = ADCL;
ADC_O_2 = ADCH;
sensorValue = (ADC_O_2 << 8) + ADC_O_1;
ADCSRA |= 0x40;
#if DEBUG_OUT_ENABLE
Serial.print("ADC:");
Serial.println(sensorValue);
#endif
AHT_init();
}
ADCSRA |= (1 << ADIF); //reset as required
delay(50);
}
#if DEBUG_OUT_ENABLE
Serial.print(F("Moisture ADC : "));
Serial.println(sensorValue);
#endif
delay(200);
// Read battery value
int ADC_O_1; // ADC Output First 8 bits
int ADC_O_2; // ADC Output Next 2 bits
//ADC3 internal 1.1V as ADC reference voltage
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX1) | _BV(MUX0);
delay(50);
for (int i = 0; i < 3; i++)
{
//start ADC conversion
ADCSRA |= (1 << ADSC);
delay(10);
if ((ADCSRA & 0x40) == 0)
{
ADC_O_1 = ADCL;
ADC_O_2 = ADCH;
batValue = (ADC_O_2 << 8) + ADC_O_1;
ADCSRA |= 0x40;
float bat = (float)batValue * 3.3;
bat = bat / 1024.0;
}
ADCSRA |= (1 << ADIF); //reset as required
delay(50);
}
float bat = (float)batValue * 3.3;
bat = bat / 1024.0;
#if DEBUG_OUT_ENABLE
Serial.print("BAT: ");
Serial.print(bat);
Serial.println("V");
// Read temperature and humidity
Serial.println("Humidity-Sensor available? " + String(humiditySensor.available() == true));
#endif
// if (humiditySensor.available() == true)
{
//Get the new temperature and humidity value
temperature = humiditySensor.getTemperature();
humidity = humiditySensor.getHumidity();
#if DEBUG_OUT_ENABLE
//Print the results
Serial.print("Temperature: ");
Serial.print(temperature, 2);
Serial.println(" C\t");
Serial.print("Humidity: ");
Serial.print(humidity, 2);
Serial.println("% RH");
#endif
}
// Check if any reads failed and exit early (to try again).
if (isnan(humidity) || isnan(temperature))
{
Serial.println(F("Failed to read from AHT sensor!"));
//return;
}
delay(100);
sensorPowerOff();
// calcuate values and prepare lora data
int bat1 = int(bat);
float bat2 = (bat - bat1) * 100;
int temp1 = int(temperature);
float temp2 = (temperature - temp1) * 100;
int hum1 = int(humidity);
float hum2 = (humidity - hum1) * 100;
mydata[0] = uint8_t(bat1);
mydata[1] = uint8_t((int)bat2);
mydata[2] = uint8_t(temp1);
mydata[3] = uint8_t((int)temp2);
mydata[4] = uint8_t(hum1);
mydata[5] = uint8_t((int)hum2);
mydata[6] = uint8_t(sensorValue );
mydata[7] = uint8_t((sensorValue & 0xff00) >> 8);
}
void sensorPowerOn(void)
{
digitalWrite(sensorPowerCtrlPin, HIGH); //Sensor power on
}
void sensorPowerOff(void)
{
digitalWrite(sensorPowerCtrlPin, LOW); //Sensor power off
}
ISR(WDT_vect)
{
#if DEBUG_OUT_ENABLE
Serial.print("[Watch dog]");
Serial.println(count);
#endif
delay(100);
count++;
//wdt_reset();
wdt_disable(); // disable watchdog
}
//Set low power mode and into sleep
void low_power_set()
{
all_pins_low();
delay(10);
// disable ADC
ADCSRA = 0;
sleep_enable();
watchdog_init();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
delay(10);
noInterrupts();
sleep_enable();
// turn off brown-out enable in software
MCUCR = bit(BODS) | bit(BODSE);
MCUCR = bit(BODS);
interrupts();
sleep_cpu();
sleep_disable();
}
//Enable watch dog
void watchdog_init()
{
// clear various "reset" flags
MCUSR = 0;
// allow changes, disable reset
WDTCSR = bit(WDCE) | bit(WDE);
WDTCSR = bit(WDIE) | bit(WDP3) | bit(WDP0); // set WDIE, and 8 seconds delay
wdt_reset(); // pat the dog
}
void all_pins_low()
{
pinMode(PWM_OUT_PIN, INPUT);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);
delay(50);
}
bool AHT_init()
{
bool ret = false;
Wire.begin();
if (humiditySensor.begin() == false)
{
#if DEBUG_OUT_ENABLE
Serial.println("AHT10 not detected. Please check wiring. Freezing.");
#endif
}
if (humiditySensor.available() == true)
{
temperature = humiditySensor.getTemperature();
humidity = humiditySensor.getHumidity();
ret = true;
}
if (isnan(humidity) || isnan(temperature))
{
#if DEBUG_OUT_ENABLE
Serial.println(F("Failed to read from AHT sensor!"));
#endif
}
return ret;
}
void setup() {
pinMode(sensorPowerCtrlPin, OUTPUT);
// set up Timer 1
pinMode(PWM_OUT_PIN, OUTPUT);
TCCR1A = bit(COM1A0); // toggle OC1A on Compare Match
TCCR1B = bit(WGM12) | bit(CS10); // CTC, scale to clock
OCR1A = 1;
Serial.begin(115200);
#if DEBUG_OUT_ENABLE
Serial.println(F("Starting"));
#endif
do_job();
low_power_set();
}
void initalize() {
// initialize every sending loop (lora)
sensorPowerOn();
Wire.begin(); //Join I2C bus
//Check if the AHT10 will acknowledge
if (humiditySensor.begin() == false)
{
Serial.println("AHT10 not detected. Please check wiring. Freezing.");
//while (1);
}
else
{
#if DEBUG_OUT_ENABLE
Serial.println("AHT10 acknowledged.");
#endif
}
readSensor();
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
// 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 (0x1, DEVADDR, nwkskey, appskey);
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_disableChannel(0); //Send only at channel 0
LMIC_disableChannel(1);
LMIC_disableChannel(2);
LMIC_disableChannel(3);
LMIC_disableChannel(4);
LMIC_disableChannel(5);
LMIC_disableChannel(6);
LMIC_disableChannel(7);
LMIC_disableChannel(8);
// Disable link check validation
LMIC_setLinkCheckMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
LMIC_setDrTxpow(DR_SF7, 14);
}
void do_job() {
initalize();
do_send(&sendjob);
}
void loop() {
wdt_disable();
if (count > SLEEP_CYCLE) //(7+1) x 8S 450
{
#if DEBUG_OUT_ENABLE
//code start
Serial.println("Code start>>");
#endif
do_job();
// all_pins_low();
#if DEBUG_OUT_ENABLE
//code end
Serial.println("Code end<<");
#endif
//count init
count = 0;
}
low_power_set();
}
void onEvent (ev_t ev) {
#if DEBUG_OUT_ENABLE
Serial.print(os_getTime());
Serial.print(": ");
#endif
switch (ev) {
case EV_SCAN_TIMEOUT:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_SCAN_TIMEOUT"));
#endif
break;
case EV_BEACON_FOUND:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_BEACON_FOUND"));
#endif
break;
case EV_BEACON_MISSED:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_BEACON_MISSED"));
#endif
break;
case EV_BEACON_TRACKED:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_BEACON_TRACKED"));
#endif
break;
case EV_JOINING:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_JOINING"));
#endif
break;
case EV_JOINED:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_JOINED"));
#endif
break;
case EV_RFU1:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_RFU1"));
#endif
break;
case EV_JOIN_FAILED:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_JOIN_FAILED"));
#endif
break;
case EV_REJOIN_FAILED:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_REJOIN_FAILED"));
#endif
break;
case EV_TXCOMPLETE:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
#endif
if (LMIC.txrxFlags & TXRX_ACK)
#if DEBUG_OUT_ENABLE
Serial.println(F("Received ack"));
#endif
if (LMIC.dataLen) {
#if DEBUG_OUT_ENABLE
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
#endif
}
// Schedule next transmission(
// Serial.println("Next run ... "+String( os_getTime() + sec2osticks(TX_INTERVAL)));
// os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_LOST_TSYNC"));
#endif
break;
case EV_RESET:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_RESET"));
#endif
break;
case EV_RXCOMPLETE:
// data received in ping slot
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_RXCOMPLETE"));
#endif
break;
case EV_LINK_DEAD:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_LINK_DEAD"));
#endif
break;
case EV_LINK_ALIVE:
#if DEBUG_OUT_ENABLE
Serial.println(F("EV_LINK_ALIVE"));
#endif
break;
default:
#if DEBUG_OUT_ENABLE
Serial.println(F("Unknown event"));
#endif
break;
}
}
I have a problem with the deep sleep watch dog of the v2.1. SLEEP_CYCLE is set to 105 (~15 Minutes). For some days it works perfect. But since last night it doesnt sleep anymore and send every 5-7 seconds. A reset brings no improvment.