Makerfabs / Lora-Soil-Moisture-Sensor

Lora Soil Moisture Sensor
50 stars 23 forks source link

Watchdog wakes up directly #3

Open littlejogi opened 2 years ago

littlejogi commented 2 years ago

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.

littlejogi commented 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;
  }
}