Merge Help: Door+ BME280



  • Hello,
    I have been struggling with this for a few days now. I have tried various permutations and combinations and the sketch does not work.
    Individually both Door Sensor and BME280 work just fine but once I merge them into one sketch the node hangs.

    Do I need to do anything different here?

    
    
    //#define MY_DEBUG
    #define REED_PIN 6
    #define MY_NODE_ID 2 //change everytime
    #define MY_PASSIVE_NODE
    #define MY_RADIO_NRF5_ESB
    #define MY_PARENT_NODE_ID 0
    #define MY_PARENT_NODE_IS_STATIC
    #define MY_TRANSPORT_WAIT_READY_MS 10000   // Try connecting for 10 seconds. Otherwise just continue.
    #define MY_SPLASH_SCREEN_DISABLED                   // Saves a little memory.
    
    
    
    #define IS_NRF51  //true iff the target is an nRF51.  If an nRF52, then comment this line out!
    #define SKETCH_NAME "Hobby Room Door Sensor"
    #define SKETCH_VERSION "v1"
    #define DOOR_CHILD_ID 0
    #define VOLT_CHILD_ID 10
    #define TEMP_CHILD_ID 1
    #define BARO_CHILD_ID 2
    #define HUM_CHILD_ID 3
    /* End NodeID definitions */
    
    /* Sketch specific libraries*/
    #include <SPI.h>                                  // A communication backbone, the Serial Peripheral Interface.
    #include <Wire.h>                                 // Enables the Wire communication protocol.
    #include <MySensors.h>                            // The MySensors library. Hurray!
    #include <Adafruit_BME280.h>                 
    
    
    
    
    
    /* door sensor variables */
    
    volatile bool door_tripped = false;
    bool magnet_detected= false;
    float batteryVoltage = 0;
    bool oldValueDoor = -1;
    /* door sensor variables */
    
    
    /* Sleep variables */
    #define SHORT_WAIT 50
    uint32_t SLEEP_TIME = 60000 *15; //60000 ms = 1 minute * number of minutes
    /* Sleep variables */
    
    /* BME 280 */
    
    Adafruit_BME280 bme; // use I2C interface
    //#define BME280_ADDRESS_ALTERNATE
    Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
    Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
    Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
    /* BME 280 */
    
    
    
    
    MyMessage msgDoor(DOOR_CHILD_ID, V_TRIPPED); //TRIPPED --> Open, ARMED --> Closed
    MyMessage msgVoltage(VOLT_CHILD_ID, V_VOLTAGE);
    MyMessage msgTemperature(TEMP_CHILD_ID, V_TEMP);
    MyMessage msgHumidity(HUM_CHILD_ID, V_HUM);
    MyMessage msgPressure(BARO_CHILD_ID, V_PRESSURE);
    
    
    //void before()
    //{
    //  NRF_POWER->DCDCEN = 1;
    //  sleep(400);
    //}
    
    void setup() 
    {
      hwInit();
      Wire.begin();
      if (!bme.begin(0x76))
        {
      
          while(1) delay(10);
    
        }
      environment();
      
      hwPinMode(REED_PIN, INPUT_PULLUP);
      turnOffAdc();
      disableNfc();
      turnOffAdc();
      activateLpComp();
      mySleepPrepare();
    
      
    }
    
    void presentation()
    {
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
      wait(SHORT_WAIT);
      present(DOOR_CHILD_ID, S_DOOR, "Door Sensor", true);
      wait(SHORT_WAIT);
      present(VOLT_CHILD_ID, S_MULTIMETER,"Battery voltage", true);
      wait(SHORT_WAIT);
      present(HUM_CHILD_ID, S_HUM);
      wait(SHORT_WAIT);
      present(BARO_CHILD_ID, S_BARO);
      wait(SHORT_WAIT);
      present(TEMP_CHILD_ID, S_TEMP);
      
      
    
    
    }
    void loop() 
    {
      mySleep(SLEEP_TIME);
      if (door_tripped)
      {
      door();
    //  sleep(digitalPinToInterrupt(REED_PIN), CHANGE, SLEEP_TIME);
      wait(SHORT_WAIT);
      battery_report();
      }
      else
      {
        environment();
        wait(SHORT_WAIT);
      }
    
    
    }
    
    
    
    
    void door()
    {
      bool tripped = digitalRead(REED_PIN) == HIGH;
      if (tripped != oldValueDoor)
      {
        send(msgDoor.set(tripped ? "Open" : "Close"), true);
        oldValueDoor = tripped;
        
      }
    }
    
    
    
    
    
    void environment()
    {
      float pressure = bme.readPressure() /100.0f;
      bme.begin(0x76);
      sensors_event_t temp_event, pressure_event, humidity_event;
      bme_temp->getEvent(&temp_event);
      bme_pressure->getEvent(&pressure_event);
      bme_humidity->getEvent(&humidity_event);
    
      send(msgTemperature.set(temp_event.temperature, 1));
      send(msgHumidity.set(bme.readHumidity(), 1));
      send(msgPressure.set(pressure, 1));
    //  i2c_off();
    }
    
    
    
    
    void i2c_off() // Shut i2c down, powerconsumption rises up to 450uA instead of 11 ua  - https://github.com/sandeepmistry/arduino-nRF5/issues/291#issuecomment-407492282
    {
      NRF_TWI1->ENABLE=TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
    *(volatile uint32_t *)0x40004FFC = 0;
    *(volatile uint32_t *)0x40004FFC;
    *(volatile uint32_t *)0x40004FFC = 1;
    
    }
    
    void  battery_report()
    {
      batteryVoltage = ((float)hwCPUVoltage()) / 1000.0;
      send(msgVoltage.set(batteryVoltage, 2));
    }
    
    void mySleep(uint32_t ms) {
       mySleepPrepare();  //Take steps to reduce drains on battery current prior to sleeping
    //   sleep(ms);
    // sleep(digitalPinToInterrupt(REED_PIN), CHANGE, SLEEP_TIME);
    
    }
    
    
    void disableNfc() {  //only applied to nRF52
    
    #ifndef IS_NRF51
      //Make pins 9 and 10 usable as GPIO pins.
      NRF_NFCT->TASKS_DISABLE=1;  //disable NFC
      NRF_NVMC->CONFIG=1;  // Write enable the UICR
      NRF_UICR->NFCPINS=0; //Make pins 9 and 10 usable as GPIO pins.
      NRF_NVMC->CONFIG=0;  // Put the UICR back into read-only mode.
    #endif
    }
    
    
    void turnOffRadio() {
      NRF_RADIO->TASKS_DISABLE=1;
      while (!(NRF_RADIO->EVENTS_DISABLED)) {}  //until radio is confirmed disabled
    }
    
    void turnOffUarte0() {
    #ifndef IS_NRF51  
      NRF_UARTE0->TASKS_STOPRX = 1;
      NRF_UARTE0->TASKS_STOPTX = 1;
      NRF_UARTE0->TASKS_SUSPEND = 1;
      NRF_UARTE0->ENABLE=0;  //disable UART0
      while (NRF_UARTE0->ENABLE!=0) {};  //wait until UART0 is confirmed disabled.
    #endif
    
    #ifdef IS_NRF51
      NRF_UART0->TASKS_STOPRX = 1;
      NRF_UART0->TASKS_STOPTX = 1;
      NRF_UART0->TASKS_SUSPEND = 1;
      NRF_UART0->ENABLE=0;  //disable UART0
      while (NRF_UART0->ENABLE!=0) {};  //wait until UART0 is confirmed disabled.
    #endif
    }
    
    void turnOffAdc() {
    #ifndef IS_NRF51
      if (NRF_SAADC->ENABLE) { //if enabled, then disable the SAADC
        NRF_SAADC->TASKS_STOP=1;
        while (NRF_SAADC->EVENTS_STOPPED) {} //wait until stopping of SAADC is confirmed
        NRF_SAADC->ENABLE=0;  //disable the SAADC
        while (NRF_SAADC->ENABLE) {} //wait until the disable is confirmed
      }
    #endif
    }
    
    
    void turnOffHighFrequencyClock() {
        NRF_CLOCK->TASKS_HFCLKSTOP = 1;
        while ((NRF_CLOCK->HFCLKSTAT) & 0x0100) {}  //wait as long as HF clock is still running.
    }
    
    
    void mySleepPrepare()
    {
      turnOffHighFrequencyClock();
      turnOffRadio();
      turnOffUarte0();
    }
     
    
    void activateLpComp() {
      //NRF_LPCOMP->PSEL=1; // monitor AIN1 (pin P0.03 on nRF52832 test board).
      //while (!(NRF_LPCOMP->PSEL==1)) {} //wait until confirmed
      NRF_LPCOMP->PSEL=3; // monitor AIN3 (pin P0.02 on nRF51822 for coincell_multisensor_v10)
      while (!(NRF_LPCOMP->PSEL==3)) {} //wait until confirmed
      NRF_LPCOMP->REFSEL=1;  // choose 1/4 VDD as the reference voltage
      while (!(NRF_LPCOMP->REFSEL==1)) {} //wait until confirmed
      NRF_LPCOMP->ANADETECT=1;  //detect UP events.
      while (NRF_LPCOMP->ANADETECT!=1) {} //wait until confirmed
      NRF_LPCOMP->INTENSET=B0100;  //Enable interrupt for UP event
      while (!(NRF_LPCOMP->INTENSET==B0100)) {} //wait until confirmed
      NRF_LPCOMP->ENABLE=1;  //Enable LPCOMP
      while (!(NRF_LPCOMP->ENABLE==1)) {} //wait until confirmed
      NRF_LPCOMP->TASKS_START=1;  //start the LPCOMP
      while (!(NRF_LPCOMP->EVENTS_READY)) {}  //wait until ready
      
      NVIC_SetPriority(LPCOMP_IRQn, 15);
      NVIC_ClearPendingIRQ(LPCOMP_IRQn);
      NVIC_EnableIRQ(LPCOMP_IRQn);
    }
    
    void suspendLpComp() { //suspend getting more interrupts from LPCOMP before the first interrupt can be handled
      if ((NRF_LPCOMP->ENABLE) && (NRF_LPCOMP->EVENTS_READY)) {  //if LPCOMP is enabled
        NRF_LPCOMP->INTENCLR=B0100;  //disable interrupt from LPCOMP
        while (NRF_LPCOMP->INTENCLR==B0100) {} //wait until confirmed
      }
    }
    
    void resumeLpComp() { //suspend getting interrupts from LPCOMP
      NRF_LPCOMP->INTENSET=B0100;  //Enable interrupt for UP event
      while (!(NRF_LPCOMP->INTENSET==B0100)) {} //wait until confirmed
    }
    #if __CORTEX_M == 0x04
    #define NRF5_RESET_EVENT(event)                                                 \
            event = 0;                                                                   \
            (void)event
    #else
    #define NRF5_RESET_EVENT(event) event = 0
    #endif
    extern "C" { void LPCOMP_IRQHandler(void) {door_tripped=true; NRF5_RESET_EVENT(NRF_LPCOMP->EVENTS_UP); NRF_LPCOMP->EVENTS_UP=0; MY_HW_RTC->CC[0]=(MY_HW_RTC->COUNTER+2);}}
    


  • Hi,
    I had some progress with the sketch - and it works fine on the bench. On the bench, I report readings every 30 seconds but in deployment, its once in 10 minutes.

    So this is happening:

    The door sensor interrupt works fine. When the node wakes up after an interrupt, it gives BME readings and goes to sleep for 10 minutes and reports again. But after the first wake after sleep, it does not wake up any more until interrupt happens again.
    Could someone please see what mistake am I doing in this sketch

    //#define MY_DEBUG //Debug Disabled in production
    #define MY_RADIO_NRF5_ESB
    #define MY_NODE_ID 61
    #define SKETCH_NAME "Hobby Room Door Sensor"
    #define SKETCH_VERSION "V1"
    #define MY_SMART_SLEEP_WAIT_DURATION 500 //activate smart sleep
    #define MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS  10000 //wait for 10 seconds to reconnect in case of transport problems
    #define MY_TRANSPORT_WAIT_READY_MS 30000  //try connecting for 30 seconds
    //#define MY_PARENT_NODE_ID 0
    //#define MY_PARENT_NODE_IS_STATIC
    
    #define DIGITAL_INPUT_SENSOR 2       // The digital input you attached your Door/Window sensor.
    #define CHILD_ID_DOOR 1            // Id of the door/window sensor child.
    #define CHILD_ID_BATTERY 254
    #define CHILD_ID_TEMP 2
    #define CHILD_ID_HUMID 3
    #define CHILD_ID_BARO 4
    
    
    #include <MySensors.h>
    #include <SPI.h>
    #include <Adafruit_BME280.h>
    #include <Wire.h>
    
    #ifdef MY_DEBUG
    uint32_t SLEEP_TIME = 30000; // when debugging, sleep time is 30 seconds
    #endif
    #ifndef MY_DEBUG
    
      uint32_t SLEEP_TIME = 60000 * 10 ; // when deployed, sleep time is 10 minutes
    #endif
    
    #define SHORT_WAIT 1000
    
    Adafruit_BME280 bme; // use I2C interface
    Adafruit_Sensor *bme_temp = bme.getTemperatureSensor();
    Adafruit_Sensor *bme_pressure = bme.getPressureSensor();
    Adafruit_Sensor *bme_humidity = bme.getHumiditySensor();
    
    bool oldValueDoor = -1;
    float batteryVoltage = 0;
    
    // Initialize door/window message
    MyMessage msgDoor(CHILD_ID_DOOR, V_TRIPPED); //Door/Window.
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgHumid(CHILD_ID_HUMID, V_HUM);
    MyMessage msgPressure(CHILD_ID_BARO, V_PRESSURE);
    MyMessage msgBattery(CHILD_ID_BATTERY, V_VOLTAGE);
    
    void setup()
    {
    #ifdef MY_DEBUG
      {
        Serial.println("Setup started");
      }
    #endif
      pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);  // sets the door/window sensor digital pin as input
    
    
      Wire.begin();
      if (!bme.begin(0x76))
      {
        while (1) delay(100);
    
      }
    #ifdef MY_DEBUG
      {
        Serial.println("Setup done");
      }
    #endif
    }
    
    
    void presentation()
    {
    #ifdef MY_DEBUG
      {
        Serial.println("Presentation started");
      }
    #endif
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_DOOR, S_DOOR, "Hobby Room Door", true);
      wait(SHORT_WAIT);
      present(CHILD_ID_TEMP, S_TEMP, "Hobby Room Temperature", true);
      wait(SHORT_WAIT);
      present(CHILD_ID_HUMID, S_HUM, "Hobby Room Humidity", true);
      wait(SHORT_WAIT);
      present(CHILD_ID_BARO, S_BARO, "Hobby Room Pressure", true);
      wait(SHORT_WAIT);
      present(CHILD_ID_BATTERY, S_MULTIMETER, "Battery Voltage", true);
    #ifdef MY_DEBUG
      {
        Serial.println("Presentation done");
      }
    #endif
    }
    
    void loop()
    {
      //Read digital door/window value.
      bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
    
    
    
    #ifdef MY_DEBUG
      {
        Serial.println("Tripped value");
        Serial.print(tripped);
      }
    #endif
      if (tripped != oldValueDoor)
      {
    #ifdef MY_DEBUG
        {
          Serial.println("Tripped value in if statement");
          Serial.print(tripped);
          Serial.println("oldValueDoor ");
          Serial.print(oldValueDoor);
        }
    #endif
        wait(100);
        send(msgDoor.set(tripped ? "1" : "0"), true); // Send door/window tripped value to gw
        wait(100);
    #ifdef MY_DEBUG
        {
          Serial.println(" Messgae sent and now tripped value is ");
          Serial.print(tripped);
          Serial.println(" Messgae sent and now oldValueDoor value is ");
          Serial.print(oldValueDoor);
        }
    #endif
        oldValueDoor = tripped;
    #ifdef MY_DEBUG
        {
          Serial.println("oldValue is now equal to tripped, check it - tripped is  ");
          Serial.print(tripped);
          Serial.println("oldValue is now equal to tripped, check it - oldValueDoor is ");
          Serial.print(oldValueDoor);
        }
    #endif
        wait(100);
    #ifdef MY_DEBUG
        {
          Serial.println("Door message sent, exiting if");
          wait(100);
        }
    #endif
    
    
        
        batteryVoltage = ((float)hwCPUVoltage()) / 1000.0;
        wait(100);
        send(msgBattery.set(batteryVoltage, 2));
        wait(100);
        bool sendBatteryLevel(uint8_t level, bool echo);
    #ifdef MY_DEBUG
        {
          Serial.println("Battery reported");
        }
    #endif
        wait(100);
    
        float pressure = bme.readPressure() / 100.0F;
    #ifdef MY_DEBUG
        {
          Serial.println("Starting BME readings");
        }
    #endif
        bme.begin(0x76);
        sensors_event_t temp_event, pressure_event, humidity_event;
        bme_temp->getEvent(&temp_event);
        bme_pressure->getEvent(&pressure_event);
        bme_humidity->getEvent(&humidity_event);
    
        send(msgTemp.set(temp_event.temperature, 2));
        wait(100);
        send(msgHumid.set(bme.readHumidity(), 2));
        wait(100);
        send(msgPressure.set(pressure, 2));
        wait(100);
    #ifdef MY_DEBUG
        {
    
          Serial.println("BME done");
          Serial.println("waiting for interrupt");
        }
    #endif
    
        smartSleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME);
        sendHeartbeat();
     
    
    
      }
    }
    

    Should I be doing a Wire.end() before sleep and then Wire.begin() after waking up. But I think its not waking up from Sleep after the 19th minute from interrupt.

    Thank you


  • Hero Member

    @Puneit-Thukral I have a similar sensor ( PIR + BMP280 + other stuff). I don't use smartSleep ( Since this code is old, only sleep was available ) so I can't speak about the sleep part. Maybe you could try with regular sleep just to see if brings some diference...

    Regarding the BME280 (BMP in my case) , I didn't have to use the Wire.begin() / end(), and I use the same library as yours (Adafruit).

    Code is bellow, in case you want to compare yourself.

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * (adopted from 5in1 V2.1)
     * Version 3.0 - RV -  Shifted to BMP280 sensor, added pressure and water leakage (via ROPE  https://www.amazon.com/gp/product/B004FTFQ4W/ref=ppx_od_dt_b_asin_title_s01?ie=UTF8&psc=1 ) 
     * 
     * 
     * DESCRIPTION
     * BMP280 on std SDA/SDL pins  (Temp/Pressure) 
     * LDR on pin A1:  GND ---> 10k ---> A1 <-- LDR  <-- Vcc 
     * PIR on D3 and wakeup via interrupt (in case of PIR trigger) 
     * Smoke on D2 with interrupt wake up too. ( 4n25 4K7 on buzzer, 2M7 Pullup resistor recommended ) 
     * Water Sensing cable on A2:  GND --> 100k --> A2 <--  X--X <-- Vcc  
     * (https://www.amazon.com/gp/product/B004FTFQ4W/ref=ppx_od_dt_b_asin_title_s01?ie=UTF8&psc=1)
     * 
     * Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below)
     *
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    
    // Board type 
    #define DRAGON  // PRO_MINI //  DRAGON / SENSEBENDER
    
    // Define a static node address, AUTO or 1-255 fixed
    #define MY_NODE_ID 25 // AUTO 
    #define MY_PARENT_NODE_ID AUTO 
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24  // MY_RADIO_RFM69
    
    // Uncomment the line below, to transmit battery voltage as a normal sensor value
    #define BATT_SENSOR    199
    
    #define NAME "8in1 Sensor"
    #define RELEASE "3.3"
    
    // Pin definitions for sensors
    #define SDA_PIN        A5    // Just to document std IC2 interface 
    #define SCL_PIN        A4    // Just to document std IC2 interface 
    #define LDR_PIN        A1    //  Analog Light sensor (LDR)
    #define WATER_PIN      A2    //  Analog Water Leak sensor (rope)
    #define SMOKE_PIN      2     //  Digital Smoke sensor (0/1)
    #define PIR_PIN        3     //  PIR Sensor (0/1) 
    #define TRIGGER_PIN    4     //  Trigger for HC-SR04 sensor 
    #define ECHO_PIN       5     //  Echo for HC-SR04 sensor 
    
    #ifdef DRAGON
    //   #define SPIFLASH_PIN   8 
       #define LED_PIN        9  
       #define TEST_PIN       A0
       #define MY_RF24_CE_PIN  7  
       #define MY_RF24_CS_PIN  10 
    //   #define MY_SOFTSPI
    //   #define MY_SOFT_SPI_SCK_PIN     13
    //   #define MY_SOFT_SPI_MISO_PIN    12
    //   #define MY_SOFT_SPI_MOSI_PIN    11
    #endif
    
    #ifdef SENSEBENDER
       #define SPIFLASH_PIN   8 
       #define TEST_PIN       A0
       #define OTA_ENABLE     A1
       #define LED_PIN        A2
       #define ATSHA204_PIN   17 // A3
    #endif
    
    #ifdef PRO_MINI
      #define LED_PIN 8
    #endif
    
    // Includes ///////////////////////////////////////////
    #include <SPIMemory.h> 
    #include <SPI.h>
    #include <MySensors.h>
    //#include <Wire.h>
    //#include <EEPROM.h>  
    //#include <sha204_library.h>
    //#include <Adafruit_Sensor.h>
    #include <Adafruit_BMP280.h>
    
    /// Sketch parameters SETUP ////////////////////////////
    // Child sensor ID's
    #define CHILD_ID_TEMP  1
    #define CHILD_ID_HUM   2
    #define CHILD_ID_PRESS 3
    #define CHILD_ID_LIGHT 4
    #define CHILD_ID_PIR   5
    #define CHILD_ID_SMOKE 6
    #define CHILD_ID_WATER 7 
    #define CHILD_ID_TANK  8 
    
    // How many milli seconds should we wait for OTA?
    #define OTA_WAIT_PERIOD 500
    
    // How many milli seconds between each measurement
    #define MEASURE_INTERVAL 720000   // 12min 
    
    // How many wakeups to send battery level 
    #define BAT_INTERVAL     100      //  around 20 hours 
    
    // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller
    #define FORCE_TRANSMIT_INTERVAL 10 //  around 2 hours 
    
    // When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes.
    // Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement
    
    // HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with
    // TEMP_TRANSMIT_THRESHOLD for temperature threshold.
    #define HUMI_TRANSMIT_THRESHOLD 5
    #define TEMP_TRANSMIT_THRESHOLD 0.5
    #define LIGHT_TRANSMIT_THRESHOLD 5
    #define PRESS_TRANSMIT_THRESHOLD 50
    
    // Flash memory 
    #ifdef SPIFLASH_PIN 
    SPIFlash flash( SPIFLASH_PIN );
    #endif
    
    // ATSHA204
    #ifdef ATSHA204_PIN
    atsha204Class sha204( ATSHA204_PIN );
    #endif
    
    //Weather Sensor BMP280 on IC2 (Temp/Hum/Pressure):
    #ifdef SDA_PIN and SCL_PIN 
    Adafruit_BMP280 weather_sensor;
    #endif
    
    // Sensor messages
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgPressure(CHILD_ID_PRESS, V_PRESSURE ); 
    MyMessage msgLight(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
    MyMessage msgMotion(CHILD_ID_PIR, V_TRIPPED); 
    MyMessage msgSmoke(CHILD_ID_SMOKE, V_TRIPPED ); 
    MyMessage msgWater(CHILD_ID_WATER, V_TRIPPED ); 
    MyMessage msgDist(CHILD_ID_TANK, V_DISTANCE ); 
    
    #ifdef BATT_SENSOR
    MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE);
    #endif
    
    // Global settings
    int measureCount;
    int sendBattery;
    boolean isMetric = true;
    boolean highfreq = true;
    boolean transmission_occured = false;
    
    // Storage of old measurements
    float lastTemperature = -100;
    float lastHumidity = -100;
    float lastPressure = -100; 
    long lastBattery = -100;
    int lastPir = -1;  
    int lastLight = -100; 
    int lastSmoke = -1; 
    int lastWater = -1; 
    int lastDist = -1; 
    
    /****************************************************
     *
     * Setup code 
     *
     ****************************************************/
    void setup() {
    
      #ifdef LED_PIN 
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, HIGH);
      #endif
      
      Serial.begin( MY_BAUD_RATE );  // Default for MySensors is 115200 
    
    // Test Mode  //////////////////////////
      #ifdef TEST_PIN
      pinMode(TEST_PIN,INPUT_PULLUP);
      if (!digitalRead(TEST_PIN)) testMode();
      pinMode(TEST_PIN,INPUT); 
      #endif
    
    // Pin Mode Setup //////////////////////
      #ifdef BAT_PIN 
      pinMode(BAT_PIN , INPUT);  // Ext. Batery meter (1M / 470K resistors) 
      #endif 
      #ifdef SMOKE_PIN
      pinMode(SMOKE_PIN , INPUT ); 
      #endif
      #ifdef PIR_PIN
      pinMode(PIR_PIN , INPUT);   
      #endif 
      #ifdef TRIGGER_PIN
      pinMode(PIR_PIN , OUTPUT);   
      #endif 
      #ifdef ECHO_PIN
      pinMode(ECHO_PIN , INPUT);   
      #endif 
        
    // Startup Info 
      Serial.print("Board:");
      Serial.print( ARDUINO ); 
      Serial.print( "\t" ); 
      Serial.print( F_CPU / 1000000 ); 
    
      Serial.print(" Mhz\t"); 
      Serial.print( NAME );
      Serial.print(" "); 
      Serial.println( RELEASE );
     
      Serial.print("Nrf24 CE/CS:");
      Serial.print( MY_RF24_CE_PIN);  
      Serial.print("/"); 
      Serial.print( MY_RF24_CS_PIN ); 
    
      Serial.print("\tNODE ID:");
      Serial.print(hwReadConfig(EEPROM_NODE_ID_ADDRESS));
      
      isMetric = getControllerConfig().isMetric;
      Serial.print(F("\tisMetric:")); Serial.println(isMetric);
      
      #ifdef OTA_WAIT_PERIOD
      Serial.print("OTA FW Enabled"); 
      #endif
    
      // SPI Flash 
      #ifdef SPIFLASH_PIN
      SPI.begin(); 
      Serial.print(F("\tFlash:")); 
      if ( flash.begin() ) { 
        Serial.print( flash.getCapacity() / 8000 , 0 );
        Serial.print( "KB"); 
        flash.powerDown(); 
      } else Serial.print( flash.error(VERBOSE) ); 
    
      #endif
    
      // BMP280 init ////////////////////////
      #ifdef SDA_PIN and SCL_PIN
      Serial.print(F("\tBMP280:")); 
      if ( weather_sensor.begin() ) { 
        Serial.print(F("OK"));
        /* Default settings from datasheet. */
        weather_sensor.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                      Adafruit_BMP280::SAMPLING_X1,       /* Temp. oversampling */
                      Adafruit_BMP280::SAMPLING_X1,       /* Pressure oversampling */
                      Adafruit_BMP280::FILTER_OFF );      /* Filtering. */
    
      } else Serial.print(F("ERROR!")); 
      #endif
    
      // Force 1st transmission of all sensors
      measureCount = FORCE_TRANSMIT_INTERVAL;
      sendBattery = BAT_INTERVAL; 
      
      #ifdef LED_PIN 
      digitalWrite(LED_PIN, LOW);
      #endif
        
      Serial.println(F("\n///////////////////// ONLINE /////////////////////"));
      Serial.flush(); 
    
    }
    
    void presentation() { 
    
      sendSketchInfo( NAME , RELEASE);
      #ifdef SDA_PIN 
        present(CHILD_ID_TEMP,S_TEMP);
        present(CHILD_ID_HUM,S_HUM);
        present(CHILD_ID_PRESS, S_BARO ); 
      #endif
      #ifdef LDR_PIN
        present(CHILD_ID_LIGHT,S_LIGHT_LEVEL);
      #endif
      #ifdef PIR_PIN 
        present(CHILD_ID_PIR,S_MOTION); 
      #endif
      #ifdef SMOKE_PIN 
        present(CHILD_ID_SMOKE, S_SMOKE); 
      #endif 
      #ifdef WATER_PIN
        present(CHILD_ID_WATER, S_WATER_LEAK ); 
      #endif
      #ifdef TRIGER_PIN
        present(CHILD_ID_TANK, S_DISTANCE ); 
      #endif
      #ifdef BATT_SENSOR
        present(BATT_SENSOR, S_POWER);
      #endif
     
    }
    
    /***********************************************
     *
     *  Main loop function
     *
     ***********************************************/
    void loop() {
    
      #ifdef LED_PIN
      digitalWrite( LED_PIN , HIGH ); 
      #endif
      
      boolean forceTransmit = false;
      transmission_occured = false; 
      
      if ( ++measureCount > FORCE_TRANSMIT_INTERVAL ) { // force a transmission
        forceTransmit = true;
        Serial.print(F("[Force Transmission]"));  
        measureCount = 0;
      }
    
      // Light, PIR, Smoke, Water leak 
      sendLight(forceTransmit); 
      sendPir(forceTransmit); 
      sendSmoke(forceTransmit); 
      sendWater(forceTransmit);
      sendWeather(forceTransmit);  
      sendDistance(forceTransmit); 
      
      // Battery level report 
      if ( ++sendBattery > BAT_INTERVAL ) {
           sendBattLevel(true); 
           sendBattery = 0;
      }
    
      // Wait for FW update... 
      if (transmission_occured) {
          wait(OTA_WAIT_PERIOD);
          measureCount = 0; 
      }
    
      #ifdef LED_PIN
      digitalWrite( LED_PIN , LOW ); 
      #endif
    
      Serial.println(); 
    
      // Trick to avoid false triggering on PIR 
      sleep(1000); 
      
      // Sleep until interval or PIR or smoke trigger 
      if ( lastSmoke == 1 )  // In case of Smoke Alarm, don't sleep too much... 
          sleep( 45000 ); 
      else if ( lastPir == 1 )  // In case of Motion, stop PIR detecting for 1 complete cycle... 
          sleep( 0 , CHANGE , MEASURE_INTERVAL ); 
      else 
          sleep( 0 , CHANGE , 1 , CHANGE, MEASURE_INTERVAL); // Default: Wake up on any PIR and Smoke... 
    
      // To avoid false Smoke alarm
      wait(100); 
    
      // Wake
      Serial.print( millis() ); 
      Serial.print("[WAKE]"); 
    
    }
    
    /*********************************************
     *
     * Sends Motion status 
     *
     *********************************************/
    void sendDistance(bool force)
    {
    
    long duration;
    int distance;
    
       #ifdef TRIGER_PIN
       digitalWrite( TRIGER_PIN, LOW);
       delayMicroseconds(2);
       digitalWrite( TRIGER_PIN , HIGH);
       delayMicroseconds(10);
       digitalWrite( TRIGER_PIN , LOW);
       // Reads the echoPin, returns the sound wave travel time in microseconds
       duration = pulseIn( ECHO_PIN , HIGH);
       // Calculating the distance
       distance = duration * 0.034 / 2;
       if ( distance != lastDist || force ) { 
          Serial.print(" D:");Serial.print(distance);
          send(msgDist.set(distance));
          transmission_occured = true; 
          lastDist = distance; 
       }
       #endif 
       
    }
    
    /*********************************************
     *
     * Sends Motion status 
     *
     *********************************************/
    void sendPir(bool force)
    {
    
       #ifdef PIR_PIN
       int currPir = digitalRead( PIR_PIN ); 
       if ( lastPir != currPir || force ) { 
          Serial.print(" M:");Serial.print(currPir);
          send(msgMotion.set(currPir));
          transmission_occured = true; 
          lastPir = currPir; 
       }
       #endif 
       
    }
      
    /*********************************************
     *
     * Sends Smoke status 
     *
     *********************************************/
    void sendSmoke(bool force)
    {
    
       #ifdef SMOKE_PIN
       int currSmoke = !digitalRead( SMOKE_PIN ); // Low = Smoke Triggered 
       if ( lastSmoke != currSmoke || force ) { 
          Serial.print(" S:");Serial.print(currSmoke);
          send(msgSmoke.set(currSmoke));
          transmission_occured = true; 
          lastSmoke = currSmoke;    
       }
       #endif 
    }
    
    /*********************************************
     *
     * Sends Smoke status 
     *
     *********************************************/
    void sendWater(bool force)
    {
    
       #ifdef WATER_PIN 
       int currWater = ( analogRead( WATER_PIN ) > 500 ? 1 : 0 ) ;  
       //Serial.println( analogRead( WATER_PIN ) ); 
       if ( lastWater != currWater || force ) { 
          Serial.print(" W:");Serial.print(currWater);
          send(msgWater.set(currWater));
          transmission_occured = true; 
          lastWater = currWater;    
       }
       #endif
    }
    
    /*********************************************
     *
     * Sends Light Level based on LDR 
     *
     * Parameters
     * - force : Forces transmission of a value (even if it's the same as previous measurement)
     *
     *********************************************/
    void sendLight(bool force)
    {
      #ifdef LDR_PIN 
      int currLight = map( analogRead( LDR_PIN ) , 0, 1024 , 0 , 100 ); 
      int diffLight = abs( lastLight - currLight );  
      if (isnan(diffLight) || diffLight >= LIGHT_TRANSMIT_THRESHOLD || force )  {
        Serial.print(" L:");Serial.print(currLight);
        send(msgLight.set(currLight));
        lastLight = currLight; 
        transmission_occured = true; 
      }
      #endif 
    }
    
    /*********************************************
     *
     * Sends temperature and humidity from Si7021 sensor
     *
     * Parameters
     * - force : Forces transmission of a value (even if it's the same as previous measurement)
     *
     *********************************************/
    void sendWeather(bool force)
    {
      #ifdef SDA_PIN and SCL_PIN 
      bool tx = force;
      
      // Sensor reading 
      float temp = weather_sensor.readTemperature();  
      //float humd = "N/A" ;  // Hum is not supported on BMP280  (But it is in BME280) 
      float pres = weather_sensor.readPressure(); 
      
       // Temperature delta 
      float diffTemp = abs( lastTemperature - temp );
      if (diffTemp >= TEMP_TRANSMIT_THRESHOLD) tx = true;
    
      // Humidity delta
      //float diffHum = abs( lastHumidity - humd ); 
      //if ( isnan(diffHum) || diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true;
    
      // Pressure delta 
      float diffPress = abs( lastPressure - pres );
      if (diffPress >= PRESS_TRANSMIT_THRESHOLD) tx = true;
    
      if (tx) {
        
        measureCount = 0;
         
        Serial.print(" T:");Serial.print(temp,1);
        //Serial.print(" H:");Serial.print(humd,1);
        Serial.print(" P:");Serial.print(pres,1); 
        
        send(msgTemp.set(temp,1));
        //send(msgHum.set(humd,1));
        send(msgPressure.set(pres,1)); 
       
        lastTemperature = temp;
        //lastHumidity = humd;
        lastPressure = pres; 
        
        transmission_occured = true;
             
      } 
    
      // BUG? High consumption ... 
      //digitalWrite( SDA_PIN , LOW ); 
      //digitalWrite( SCL_PIN , LOW ); 
      
      #endif 
    }
    
    /********************************************
     *
     * Sends battery information (battery percentage)
     *
     * Parameters
     * - force : Forces transmission of a value
     *
     *******************************************/
    void sendBattLevel(bool force)
    {
    
      #ifdef BAT_PIN
      long vcc = ( analogRead( BAT_PIN ) * 3300.0 / 1024.0 ) * 3.13; 
      #else
      long vcc = readVcc(); 
      #endif 
       
      if ( abs( ( vcc - lastBattery ) ) > 100 || force) {
    
        lastBattery = vcc;
    
        #ifdef BATT_SENSOR
        float send_voltage = float(vcc)/1000.0f;
        send(msgBatt.set(send_voltage,3));
        #endif
    
        // Calculate percentage
        vcc = vcc - 1900; // subtract 1.9V from vcc, as this is the lowest voltage we will operate at 
        long percent = vcc / 13.0;
        //long percent = constrain( map( vcc, 4000 , 9000, 0, 100 ) , 0 , 100 );  
        Serial.print(" Batt%:"); Serial.print( percent ); 
        sendBatteryLevel(percent);
        transmission_occured = true; 
        
      }
      
    }
    
    /*******************************************
     *
     * Internal battery ADC measuring 
     *
     *******************************************/
    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__)
        ADcdMUX = _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
    }
    
    
    /****************************************************
     *
     * Verify all peripherals, and signal via the LED if any problems.
     *
     ****************************************************/
    void testMode()
    {
      uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
      uint8_t ret_code;
      boolean fail = false; 
    
      #ifdef LED_PIN 
      digitalWrite(LED_PIN, HIGH); // Turn on LED.
      #endif
      
      Serial.println(F(" - TestMode"));
      Serial.println(F("Testing peripherals!"));
      Serial.flush();
    
      #ifdef SDA_PIN 
      Serial.print(F(" IC2 weather sensor ")); 
      Serial.flush();
      if ( weather_sensor.begin() && weather_sensor.readPressure() &&  
           weather_sensor.readTemperature() > 900 ) 
      {
        Serial.println(F("ok!"));
      }
      else
      {
        Serial.println(F("failed!"));
        fail = true; 
      }
      Serial.flush();
      #endif
      
      #ifdef SPIFLASH_PIN
      Serial.print(F("-> Flash : "));
      Serial.flush();
      if (flash.begin())
      {
        Serial.println(F("ok!"));
      }
      else
      {
        Serial.println(F("failed!"));
        fail = true; 
      }
      Serial.flush();
      #endif 
      
      #ifdef ATSHA204_PIN
      Serial.print(F("-> SHA204 : "));
      ret_code = sha204.sha204c_wakeup(rx_buffer);
      Serial.flush();
      if (ret_code != SHA204_SUCCESS)
      {
        Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX);
      }
      Serial.flush();
      if (ret_code == SHA204_SUCCESS)
      {
        ret_code = sha204.getSerialNumber(rx_buffer);
        if (ret_code != SHA204_SUCCESS)
        {
          Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX);
          fail = true; 
        }
        else
        {
          Serial.print(F("Ok (serial : "));
          for (int i=0; i<9; i++)
          {
            if (rx_buffer[i] < 0x10) Serial.print('0'); // Because Serial.print does not 0-pad HEX
            Serial.print(rx_buffer[i], HEX);
          }
          Serial.println(")");
        }
    
      }
      Serial.flush();
      #endif 
      
      Serial.println(F("Test finished"));
      
      if ( !fail ) 
      {
        Serial.println(F("Selftest ok!"));
        while (1) // Blink OK pattern!
        {
          #ifdef LED_PIN 
          digitalWrite(LED_PIN, HIGH);
          delay(200);
          digitalWrite(LED_PIN, LOW);
          delay(200);
          #endif
        }
      }
      else 
      {
        Serial.println(F("----> Selftest failed!"));
        while (1) // Blink FAILED pattern! Rappidly blinking..
        {
        }
      }  
    }
    

Log in to reply
 

Suggested Topics

1
Online

11.2k
Users

11.1k
Topics

112.5k
Posts