Low power temperature/humidity node with sonoff si7021



  • My little project:
    Temperature/humidity sensor with a sonoff si7021.

    You can find the sonoff si7021 sensors quite cheap on aliexpress (about 4,5€/piece).
    Pro's: has sensor and housing
    Con's: needs some tinkering to use it in low power application.

    The build:
    Arduino mini pro 8mhz 3.3v
    Sonoff si7021 sensor
    Lipo 3.7v battery
    nrf24l01+ radio

    I modded the arduino nano clone for low low power.

    First I tried with the one-wire protocol of the sonoff, but no luck in there.
    Next I soldered sda/scl lines directy and the sensor worked, but sleeping current was 1ma and way out of specs for the si7021 + mini pro.

    Next I modded the si7021sonoff si7021

    • I removed the transistor Q1
    • I remove capacitor C4
    • I cut all traces from the mcu

    After this the sleeping current is about 15 uA.

    The sketch sends temperature, humidity, batterylevel and batteryvoltage.

    My code:

    
    // Enable debug prints to serial monitor
    //#define MY_DEBUG 
     
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
     
    // Set LOW transmit power level as default, if you have an amplified NRF-module and
    // power your radio separately with a good regulator you can turn up PA level.
    // #define MY_RF24_PA_LEVEL RF24_PA_LOW
     
    #define MY_RF24_PA_LEVEL RF24_PA_HIGH
    //#define MY_DEBUG_VERBOSE_RF24
     
    // RF channel for the sensor net, 0-127
    #define RF24_CHANNEL     125
    //PiHome Node ID
    #define MY_NODE_ID 23
     
    //RF24_250KBPS for 250kbs, RF24_1MBPS for 1Mbps, or RF24_2MBPS for 2Mbps
    #define RF24_DATARATE      RF24_250KBPS
     
    #include <MySensors.h>  
    #include "Adafruit_Si7021.h"
    
    Adafruit_Si7021 sensor = Adafruit_Si7021();
     
    // Define sensor node childs
    
    #define CHILD_ID_TEMP 0
    #define CHILD_ID_HUM 1
    #define CHILD_ID_BATT 2
    #define CHILD_ID_BATT_VOLTAGE 3
     
    #define COMPARE_TEMP 1 // Send temperature only if changed? 1 = Yes 0 = No
    #define COMPARE_BVOLT 1 // Send battery voltage only if changed? 1 = Yes 0 = No
    #define         READ_SAMPLE_INTERVAL         (10)    //define how many samples you are going to take in normal operation
    #define         READ_SAMPLE_TIMES            (5)     //define the time interal(in milisecond) between each samples in 
    
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    
    static const uint64_t UPDATE_INTERVAL = 10000;
     
    unsigned long SLEEP_TIME = 56000; // Sleep time between reads (in milliseconds)
     
    // Battery related init
    int BATTERY_SENSE_PIN = A6;  // select the input pin for the battery sense point
    float oldBatteryV = 0;
    
     
    #define SKETCH_NAME "Temp_Humid_Bat_Uterum"      // Change to a fancy name you like
    #define SKETCH_VERSION "2.1"                    // Your version
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    //Definition messages
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgBattVolt(CHILD_ID_BATT_VOLTAGE, V_VOLTAGE);
    MyMessage msgBatt(CHILD_ID_BATT, V_VOLTAGE);
    
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    
    //Variables
    int chk;
    float hum;  //Stores humidity value
    float temp; //Stores temperature value
     
     
    void setup()  
    { 
      if (!sensor.begin()) {
        Serial.println("Did not find Si7021 sensor!");
        while (true);
      }
      
      // needed for battery soc
      // use the 1.1 V internal reference
      #if defined(__AVR_ATmega2560__)
          analogReference(INTERNAL1V1);
      #else
          analogReference(INTERNAL);
      #endif
      delay(2000);
      #ifdef MY_DEBUG 
        Serial.println("***Debug Activated***");
        Serial.print("Sleep_Time: ");
        Serial.print((SLEEP_TIME / 1000)/60);
        Serial.println(" min");    
      #else 
        Serial.println("***Debug Deactivated***");
        Serial.print("Sleep_Time: ");
        Serial.print((SLEEP_TIME / 1000)/60);
        Serial.println(" min");  
      #endif
    }
     
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Temperature Sensor", "1.34");
     
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
      present(CHILD_ID_BATT, S_POWER);
      present(CHILD_ID_BATT_VOLTAGE, S_MULTIMETER , "Battery ");
    
    }
     
    void loop()     
    {
      // disable ADC
      
      // get the battery Voltage
      int battSensorValue = analogRead(BATTERY_SENSE_PIN);
      float batteryV  = battSensorValue * 0.011828;
        // 1M, 100K divider across battery and using internal ADC ref of 1.1V
        // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
        // ((1e6+100e3)/100e3)*1.1 = Vmax = 12.1 Volts
        // 12.1/1023 = Volts per bit = 0.011828 
      int batteryPcnt = (batteryV / 4.2) * 100;
      
      #ifdef MY_DEBUG
        Serial.print("Pin Reading: ");
        Serial.println(battSensorValue);
        Serial.print("Battery Voltage: ");
        Serial.print(batteryV);
        Serial.println(" v");
        //Print Battery Percentage
        Serial.print("Battery percent: ");
        Serial.print(batteryPcnt);
        Serial.println(" %");
      #endif
      #if COMPARE_BVOLT == 1
        send(msgBatt.set(batteryV, 2));
        send(msgBattVolt.set(batteryV,2));
        sendBatteryLevel(batteryPcnt);
      #else 
        if (oldBatteryV != batteryV) {
          send(msgBatt.set(batteryV, 2));
          sendBatteryLevel(batteryPcnt);
          send(msgBattVolt.set(batteryV,2));
          oldBatteryV = batteryV;
        }
      #endif
    
      delay(500);
        //Read data and store it to variables hum and temp
        hum = sensor.readHumidity();
        temp= sensor.readTemperature();
        #ifdef MY_DEBUG
        //Print temp and humidity values to serial monitor
        Serial.print("Humidity: ");
        Serial.print(hum);
        Serial.print(" %, Temp: ");
        Serial.print(temp);
        Serial.println(" Celsius");
        #endif
      if (isnan(temp)) {
        Serial.println("Failed reading temperature from DHT!");
      } else if (temp != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
        lastTemp = temp;
     
        // Reset no updates counter
        nNoUpdatesTemp = 0;
        temp += SENSOR_TEMP_OFFSET;
        send(msgTemp.set(temp, 1));
    
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temp);
        #endif
      } else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
      // Get humidity from DHT library
      
      if (isnan(hum)) {
        Serial.println("Failed reading humidity from DHT");
      } else if (hum != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum = hum;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(hum, 1));
    
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(hum);
        #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
      
      sleep(SLEEP_TIME);
    }
    

    My inspirations:


 

444
Online

7.9k
Users

8.8k
Topics

94.3k
Posts