HTU21D Humidity/Temperature Sensor



  • Hi,

    I've tried the new humidity/temperature sensor HTU21D from sparkfun and really like this little breakout board.
    It is a much better replacement for the slow und sometimes unreliable DHTxx sensors. Because of the I2C interface wiring and programming is very easy.

    Here is my adapted version of the MySensors humidity sketch (you need the HTU21D library from sparkfun):

    #include <SPI.h>                                                                                                                                                            
    #include <MySensor.h>                                                                                                                                                       
    #include <Wire.h>                                                                                                                                                           
    #include <HTU21D.h>                                                                                                                                                         
    
    #define CHILD_ID_HUM 0                                                                                                                                                      
    #define CHILD_ID_TEMP 1                                                                                                                                                     
    unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds)                                                                                             
                                                                                                                                                                            
    MySensor gw;                                                                                                                                                                
                                                                                                                                                                            
    //Create an instance of the object                                                                                                                                          
    HTU21D myHumidity;                                                                                                                                                          
                                                                                                                                                                            
    boolean metric = true;                                                                                                                                                      
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);                                                                                                                                      
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);                                                                                                                                   
                                                                                                                                                                            
    void setup()                                                                                                                                                                
    {                                                                                                                                                                           
      gw.begin();                                                                                                                                                               
                                                                                                                                                                            
      // Send the Sketch Version Information to the Gateway                                                                                                                     
      gw.sendSketchInfo("Humidity", "2.0");                                                                                                                                     
                                                                                                                                                                            
      // Register all sensors to gw (they will be created as child devices)                                                                                                     
      gw.present(CHILD_ID_HUM, S_HUM);                                                                                                                                          
      gw.present(CHILD_ID_TEMP, S_TEMP);                                                                                                                                        
    
      metric = gw.getConfig().isMetric;                                                                                                                                         
      myHumidity.begin();                                                                                                                                                       
    }                                                                                                                                                                           
    void loop()                                                                                                                                                                 
    {                                                                                                                                                                           
      float temperature = myHumidity.readTemperature();                                                                                                                         
      if (!metric) {                                                                                                                                                            
          temperature = (temperature * 1.8) + 32.0;                                                                                                                             
      }                                                                                                                                                                         
      gw.send(msgTemp.set(temperature, 1));                                                                                                                                     
    
      float humidity = myHumidity.readHumidity();                                                                                                                               
      gw.send(msgHum.set(humidity, 1));                                                                                                                                         
                                                                                                                                                                            
      gw.sleep(SLEEP_TIME); //sleep a bit                                                                                                                                       
    }
    

    cheers


  • Mod

    @Talisker This is a cheaper version of the Sensirion temp/humidity sensors.
    I have very good experience with Sensirion devices -- I have one measuring temp/humidity levels outside for over a year now so I find them very reliable.

    You could also have a look at silicon labs SI702x devices. They're also compatible.


  • Admin

    @Talisker

    Welcome, and thanks for the sketch!



  • I know this is an old topic, but having recently purchased HTU21D i2c sensor, I have taken the sensebender code and adapted it for this sensor. It is less versatile than Si7021.
    The code reports temperature, humidity and battery voltage.

    /**
     * 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
     * Version 1.0 - Henrik Ekblad
     * Version 1.1 - Alexander Shestakovsky adopted for HTU21D
    *
     * DESCRIPTION
     * Temperature and humidity HTU21D sensor module  
     * http://www.mysensors.org/build/pressure
     *
     */
     
    #include <SPI.h>
    #include <MySensor.h>  
    #include <Wire.h>
    #include <HTU21D.h>
    #include <avr/power.h>
    
    #define NODE_ADDRESS   5
    #define RELEASE "1.1"
    
    
    #define CHILD_ID_TEMP 0
    #define CHILD_ID_HUM 1
    #define BATT_SENSOR 2 
    
    // Sleep time between reads (in seconds). 
    #define MEASURE_INTERVAL 60000 
    #define FORCE_TRANSMIT_INTERVAL 30
    
    #define HUMI_TRANSMIT_THRESHOLD 0.3
    #define TEMP_TRANSMIT_THRESHOLD 0.3
    
    MySensor gw;
    
    HTU21D humiditySensor;
    
    // Sensor messages
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE);
    
    
    // Pins
    #define LED_PIN 8
    
    
    // Global settings
    int measureCount = 0;
    int sendBattery = 0;
    boolean isMetric = true;
    boolean highfreq = true;
    
    // Storage of old measurements
    float lastTemperature = -100;
    float lastHumidity = -100;
    long lastBattery = -100;
    
    
    
    void setup() 
    {
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, LOW);
    
      Serial.begin(115200);
      Serial.print(F("HTU21D Sensor"));
      Serial.print(RELEASE);
      Serial.flush();
    
      digitalWrite(LED_PIN, HIGH); 
      
      gw.begin(NULL, NODE_ADDRESS, false);
    
      
      humiditySensor.begin();
    
      digitalWrite(LED_PIN, LOW);
      
      // Send the sketch version information to the gateway and Controller
      gw.sendSketchInfo("Temp/Hum Sensor - HTU21D", RELEASE);
      Serial.flush();
      Serial.println(F(" - Online!"));  
      // Register sensors to gw (they will be created as child devices)
      gw.present(CHILD_ID_TEMP, S_TEMP);
      gw.present(CHILD_ID_HUM, S_HUM);
      gw.present(BATT_SENSOR, S_POWER);
      
      isMetric = gw.getConfig().isMetric;
      Serial.print(F("isMetric: ")); Serial.println(isMetric);
      sendTempHumidityMeasurements(false);
      sendBattLevel(false);
    }
    
    void loop() {
      measureCount ++;
      sendBattery ++;
      bool forceTransmit = false;
      
      if ((measureCount == 5) && highfreq) 
      {
        clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power.
        highfreq = false;
      } 
      
      if (measureCount > FORCE_TRANSMIT_INTERVAL) { // force a transmission
        forceTransmit = true; 
        measureCount = 0;
      }
        
      gw.process();
    
      sendTempHumidityMeasurements(forceTransmit);
      digitalWrite(LED_PIN, HIGH);
      delay(50); 
      digitalWrite(LED_PIN, LOW); 
    
      if (sendBattery > 60) 
      {
         sendBattLevel(forceTransmit); // Not needed to send battery info that often
         sendBattery = 0;
      }
      
      gw.sleep(MEASURE_INTERVAL);  
    }
    
    
    /*********************************************
     *
     * Sends temperature and humidity from Si7021 sensor
     *
     * Parameters
     * - force : Forces transmission of a value (even if it's the same as previous measurement)
     *
     *********************************************/
    void sendTempHumidityMeasurements(bool force)
    {
      bool tx = force;
      
    float temperature = humiditySensor.readTemperature();
    float humidity = humiditySensor.readHumidity();
     
     float diffTemp = abs(lastTemperature - temperature);
     float diffHum = abs(lastHumidity - humidity);
    
      Serial.print(F("TempDiff :"));Serial.println(diffTemp);
      Serial.print(F("HumDiff  :"));Serial.println(diffHum);   
       
    
      if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true;
      if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true;
    
      if (tx) {
        measureCount = 0;
        
        Serial.print("T: ");Serial.println(temperature);
        Serial.print("H: ");Serial.println(humidity);
        
        gw.send(msgTemp.set(temperature,1));
        gw.send(msgHum.set(humidity,1));
        lastTemperature = temperature;
        lastHumidity = humidity;
      }
    }
    
    /********************************************
     *
     * Sends battery information (battery percentage)
     *
     * Parameters
     * - force : Forces transmission of a value
     *
     *******************************************/
    void sendBattLevel(bool force)
    {
      if (force) lastBattery = -1;
      long vcc = readVcc();
      if (vcc != lastBattery) {
        lastBattery = vcc;
    
    #ifdef BATT_SENSOR
        float Volt = vcc / 1000.0;
        gw.send(msgBatt.set(Volt,2));
    #endif
    
        // Calculate percentage
    
        vcc = vcc - 1800; // subtract 1.9V from vcc, as this is the lowest voltage we will operate at
        
        long percent = vcc / 14.0;
        gw.sendBatteryLevel(percent);
      }
    }
    
    /*******************************************
     *
     * 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
    }
    

  • Hardware Contributor

    We did just do the same here.



  • @LastSamurai Damn! I should have done a better search on the forum. Anyway, thanks for bringing it up. HTU21D is a good inexpensive sensor so I wonder why we have not had anything done with it before



  • Hi, I have built a Slim Node (see https://forum.mysensors.org/topic/3049/slim-node-si7021-sensor-example/137?_=1619862122302) but it seems most of the sketch examples here do not work with mysensors.h (I think the v2 of MySensors).
    Does anybody have a working sketch for mysensors.h for the HTU21D with battery monitoring?

    Alternatively: can anybody point me in the right direction on how to "convert" v1 skteches to v2?

    Thanks a bunch!



  • @maddhin Any version 2 sketch with HTU21D should work as slim node is atmgea328 based. I use adafruit lib for mine and it works well. To conserve battery energy follow all the steps on the battery power page in here and send data as infrequently as you can for your needs.

    here is the code I use to test with - you can safely remove all the "force n updates" to reduce memory use ( I always do). It also only send if the temp or hum has changed since last reading to further reduce battery consumption....

    /**
     * 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
     * Version 1.0: Andrew Sutcliffe
     *  
     * DESCRIPTION
     * This sketch provides an example of how to implement a humidity/temperature
     * sensor using a HTU21DF Sensor.
     *  
     * For more information, please visit:
     * http://www.mysensors.org/build/humidity
     * 
     * Connect Vin to 3-5VDC
     * Connect GND to ground
     * Connect SCL to I2C clock pin (A5 on UNO)
     * Connect SDA to I2C data pin (A4 on UNO)
     * 
     */
    
    // Enable debug prints
    #define MY_DEBUG
    
    // Enable and select radio type attached 
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    //#define MY_RS485
    
    #include <MySensors.h>  
    #include <Wire.h>
    #include "Adafruit_HTU21DF.h"
    
    Adafruit_HTU21DF htu = Adafruit_HTU21DF();
    
    // Set this offset if the sensor has a permanent small offset to the real temperatures
    #define SENSOR_TEMP_OFFSET 0
    
    // Sleep time between sensor updates (in milliseconds)
    
    static const uint64_t UPDATE_INTERVAL = 15*60000;
    
    // Force sending an update of the temperature after n sensor reads, so a controller showing the
    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
    // the value didn't change since;
    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    #define CHILD_ID_HUM 0
    #define CHILD_ID_TEMP 1
    
    float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    bool metric = true;
    
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    void presentation()  
    { 
      // Send the sketch version information to the gateway
      sendSketchInfo("HTU21DF-TemperatureAndHumidity", "1.0");
    
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_TEMP, S_TEMP);
    }
    
    void setup()
    {
      Serial.begin(9600);
      Serial.println("HTU21D-F test");
    
      if (!htu.begin()) {
        Serial.println("Couldn't find sensor!");
        while (1);
        }
    }
    
    void loop(){
      // Get temperature from HTU21DF library
      float temperature = (htu.readTemperature());
     if (temperature != 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 = temperature;
        
        // Reset no updates counter
        nNoUpdatesTemp = 0;
        temperature += SENSOR_TEMP_OFFSET;
        send(msgTemp.set(temperature, 1));
    
        #ifdef MY_DEBUG
        Serial.print("T: ");
        Serial.println(temperature);
        #endif
      } 
      else {
        // Increase no update counter if the temperature stayed the same
        nNoUpdatesTemp++;
      }
    
      // Get humidity from HTU21DF library
      float humidity = (htu.readHumidity());
      if (humidity != 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 = humidity;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(humidity, 1));
    
        #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity);
        #endif
    }
      else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    
      // Sleep for a while to save energy
      sleep(UPDATE_INTERVAL); 
    }
    

    Hope it helps you get up and running.


Log in to reply
 

Suggested Topics

  • 2
  • 2
  • 1
  • 4
  • 16
  • 2
  • 10

174
Online

10.1k
Users

10.6k
Topics

109.0k
Posts