Project tutorial
Lake turbidity and environmental monitoring  with BLE

Lake turbidity and environmental monitoring with BLE © GPL3+

Monitor lake turbidity as well as temperature and humidity with your smartphone via BLE

  • 1,994 views
  • 0 comments
  • 11 respects

Components and supplies

About this project

This project will show how to build a sensor monitor for lake turbidity monitoring and two other environmental variables such as temperature and humidity. It is usually the case that water quality of public lakes is rarely monitored in a transparent manner for the public to see. Turbidity referes to the clarity of the water or the amount of particles in it.

The problem is that turbidity sensors are relatively expensive and not very power efficient. The idea behind this project is to re purpose cheap ambient light sensor with LED in order to quantify turbidity. This will require calibartion of the unit which can be done via BLE. The gathered data can then be transferred to an on shore hub and analyzed via machine learning algorithms.

The project prototype is envisioned as a sensor puck that is mounted near the lake shore. The BLE capabilities allows the unit to advertise UV, IR and lake turbidity levels . Optionally, the GPS coordinates will serve to uniquely identify the sensor location.Since it would be expensive to change batteries for such sensor nodes a rechargeable battery with a solar panel will be used.

The complete solution would allow anybody to measure water turbidity , UV, temperature and humidity levels. Currently, the mechanical design of the project is not factored in.

Hardware

The project prototype is composed of the following hardware:

  • Arduino 101 (BLE enabled)
  • Si1133 ambient light and IR sensor
  • Si7020 temperature and humdity sensor
  • 1.7 inch TFT display
  • 915 Mhz radio (not used currently)
  • GPS (not used currently)

The TFT display was used only for visualizing the live sensor data. Arduino 101 was used as a BLE beacon that transmits the sensor data to nearby phones. A very sensitive IR/UV and ambient light sensor was used . The idea was to verify that the ambient light sensor in conjunction with an LED can be used to measure how clear is the water located beneath the sensor.

A long range radio was also used but due to time constraints it was not integrated in the final prototype.

How it works

The Arduino software uses the following libraries:

  • Curie BLE library
  • TFT display
  • Si1133
  • Si7020

The Arduino 101 behaves as a BLE central device is created which advertises the sensor data.To monitor all the environmental variables including temperature and humidity, we need to first send a beacon advertisement transmission. To identify which sensor puck the BLE advertisement came from the node is given a unique name derived from the ID of the Arduino 101 memory chip.

The temperature ,humidity , IR and UV values are embedded in the advertisement. Every time the sensor data changes the data is updated and a notification is sent to any nearby smartphone.

One notable issue that was encountered with the humidity sensor. During times of prolonged high humidity levels, as when it rains for 3-4 consecutive rainy days, the polymer sensor film inside the sensor becomes supersaturated and produce high humidity values which can be above 100%. Humidity values appear to recover alone after a day of drier conditions. Alternatively one can use the internal heater of the Si7020 sensor.

To visualize the temperature and humidity values, I used an 1.7 inch TFT display. These displays are based on the ST7735 controller and many flavors exist. The display uses the SPI bus protocol for communication. Notice that this display operates at 3V3. The usual connections from the board to the Arduino use pins 8,9,10,11,12 for the SPI bus and control signals.

The image below shows the BLE temperature and humidity services as they show up on my smartphone. The sensor data is shown on the data field of the sensors. Each of the services has NOTIFY and READ capabilities allowing the sensor puck to notify the smartphone if the values change.

The BLE environmental service was used. This service has specific ID for humidity and temperature. For more info check the BLE specs.

Demo

The image shows the data showing up on my smartphone.

I used the Nordic Semiconductor nRFconnect app to read the temperature humidity data. IR and UV were not added in order not to crowd the services .

Adding a BLE battery service would be the next logical step for a mobile sensor node.

Future work will focus on the rechargeable power supply and adding battery capabilities.

Code and conceptual Fritzing schematic are shown below. Enjoy!

Code

CurieLakeMonitorC/C++
Curie lake monitoring app.
/* Arduino 101 CurieLakeMonitor for lake turbidity monitoring
 * Copyright (C) 2017 by Dimiter Kendri
 *
 *
 * This Library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This Library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Arduino 101 Curie Lake monitor.  If not, see
 * <http://www.gnu.org/licenses/>.
 */


#include <CurieBLE.h>

#include <TFT.h>  // Arduino LCD library
#include <SPI.h>

#include "Si7020.h"
#include "SI1133.h"

// pin definition for the Uno
#define cs   10
#define dc   9
#define rst  8

// create an instance of the library
TFT TFTscreen = TFT(cs, dc, rst);
SI1133 uvir = SI1133();
Si7020 temphum;

/*********************************************************************************/
// char array to print to the screen
char SPLPrintout[6];
char humidityPrintout[6];
char tempPrintout[6];
char UVPrintout[6];

float temperature = 0;
float humidity =    0;
float uv =    0;
float ir =    0;

int16_t oldTemp =   0;
uint16_t oldHum =   0;
/*********************************************************************************/

const char *moduleName = "ArduinoLakeMonitor01";

BLEPeripheral blePeripheral;

// Environment sensing service UUID
// https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.environmental_sensing.xml
#define SERVICE_UUID_ESS "181A"           
#define CHAR_UUID_TEMPERATURE "2A6E"        // Temperature characteristic UUID
#define CHAR_UUID_HUMIDITY "2A6F"           // Humidity characteristic UUID

BLEService esSvc(SERVICE_UUID_ESS);

// We want notifications to be supported
BLEShortCharacteristic tempChar(CHAR_UUID_TEMPERATURE,  BLERead | BLENotify);

BLEUnsignedShortCharacteristic humChar(CHAR_UUID_HUMIDITY,   BLERead | BLENotify);
/*********************************************************************************/

void setupTemperatureHumidityIRSensors(void);
void updateSensorData(void);

void setup() {
  Serial.begin(9600);
  while (!Serial);    // wait for the serial port to open

  setupTemperatureHumidityIRSensors();
  
  // Put this line at the beginning of every sketch that uses the GLCD:
  TFTscreen.begin();
  TFTscreen.background(0, 0, 0);        // clear the screen with a black background

  // write the static text to the screen  set the font color to white
  TFTscreen.stroke(255, 255, 40);              // set the font size
  TFTscreen.setTextSize(2);                      // write the text to the top left corner of the screen
  TFTscreen.text("SPL Value :\n ", 0, 0);       // ste the font size very large for the loop
  TFTscreen.text("Hum: ", 0, 40);       // ste the font size very large for the loop
  TFTscreen.text("Temp: ", 0, 60);       // ste the font size very large for the loop
  TFTscreen.text("UV: ", 0, 80);       // ste the font size very large for the loop
  TFTscreen.setTextSize(2);


    // Set BLE name for the module
  blePeripheral.setLocalName(moduleName);
  // Add the service UUID
  blePeripheral.setAdvertisedServiceUuid(esSvc.uuid());
  // Add the BLE service
  blePeripheral.addAttribute(esSvc);
  // Add characteristics
  blePeripheral.addAttribute(tempChar);
  blePeripheral.addAttribute(humChar);

  // Set initial values
  updateSensorData();

  /* Activate the BLE device.  It will start continuously transmitting BLE
     advertising packets and will be visible to remote BLE central devices
     until it receives a new connection */
  blePeripheral.begin();
  
}

void loop() {

  // Read the value of the sensor on A0
  String sensorVal        =  String(analogRead(A0));
  String humidityVal      =  String(humidity);
  String temperatureVal   =  String(temperature);
  String uvVal            =  String(uv);
  
  // convert the reading to a char array
  sensorVal.toCharArray(SPLPrintout, 6);
  temperatureVal.toCharArray(tempPrintout, 6);
  humidityVal.toCharArray(humidityPrintout, 6);       // convert the reading to a char array
  uvVal.toCharArray(UVPrintout, 6);

  // set the font color
  TFTscreen.stroke(2, 215, 255);   // print the sensor values in yellow
  
  TFTscreen.text(SPLPrintout, 0, 20);     
  TFTscreen.text(humidityPrintout, 60, 40);    
  TFTscreen.text(tempPrintout, 60, 60);    
  TFTscreen.text(UVPrintout, 60, 80);    
  
  TFTscreen.text("Arduino 101", 10, 110);     // wait for a moment
  
  updateSensorData();

  TFTscreen.stroke(0, 0, 0);
  TFTscreen.text(SPLPrintout, 0, 20);
  TFTscreen.text(humidityPrintout, 60, 40);
  TFTscreen.text(tempPrintout, 60, 60);
  TFTscreen.text(UVPrintout, 60, 80);

  BLECentral central = blePeripheral.central();

  // If central has connected to us
  if (central) {

    // Update sensor data as long as central is connected
    while (central.connected()) {
      updateSensorData();
    }
  }
}


void setupTemperatureHumidityIRSensors(void)
{
  Serial.println("Initializing Si1133 device...");
  
  if (! uvir.begin()) {
    Serial.println("Can't find Si1133");
    while (1);
  }
  Serial.println("Initializing Si7020 device...\r\n");
  
  temphum.begin();
  temphum.resetSettings();
  // To change resolution of the sensor use sensor.changeResolution(int i) where i=[0-3], 
  temphum.changeResolution(3);
}

  
// Get data from sensors, process and push to BLE characteristics
void updateSensorData(void)
{
  // We don't really need it to be very frequent, let's say every 10 seconds.
  // TODO: this must be exposed through BLE and configurable by user
  delay(10000);

  uv = uvir.readUV();
  ir = uvir.readIR();
  temperature = temphum.getTemp();
  humidity = temphum.getRH();

  
  // BLE ESS has float data with 0.01 precision stored as ints
  int16_t essTemp = temperature*100;
  uint16_t essHum = round(humidity)*100;

  // Update BLE characteristics if values changed
  if (essTemp != oldTemp) {
    tempChar.setValue(essTemp);
    oldTemp = essTemp;
  }
  if (essHum != oldHum) {
    humChar.setValue(essHum);
    oldHum = essHum;
  }

  
  Serial.print("FULL-IR: ");    Serial.println(ir,BIN);
  Serial.print("UV: ");     Serial.println(uv,BIN);
  Serial.print("UV: ");     Serial.println(uv);
  if(uv>545){
    Serial.println("UVI: 14");
  }
  else
  {
    Serial.print("UVI: ");  
  Serial.println(0.0082*(0.00391*uv*uv+uv));
  }
  
  
  Serial.println("Status\tHumidity (%)\tTemperature (C)");
  Serial.print("\t");
  Serial.print(humidity);
  Serial.print("\t\t");
  Serial.print(temperature,2);
  
}
SI1133.cppC/C++
IR/UV and ambient light sensor
#include "SI1133.h"

SI1133::SI1133() {
  _addr = SI1133_ADDR;
}

boolean SI1133::begin(void) {
Wire.begin();
 
  uint8_t id = read8(SI1133_REG_PARTID);
  if (id != 0x33) return false;
  
  reset();


  writeParam(SI1133_PARAM_CHLIST,0X01);
  //=======================================================

  writeParam(SI1133_PARAM_ADCCONFIG0,0x78 );

  writeParam(SI1133_PARAM_ADCSENS0,0x09);

  writeParam(SI1133_PARAM_ADCPSOT0,0x00);
  writeParam(SI1133_PARAM_MEASCONFIG0,COUNT0);


  write8(SI1133_REG_COMMAND, SI1133_START);

   Serial.println(Wire.read());
   return true;
}

void SI1133::reset() {
  write8(SI1133_REG_COMMAND, SI1133_RESET_SW);
  delay(10);  
}

uint8_t SI1133::read8(uint8_t reg) {
    Wire.beginTransmission(_addr);
    Wire.write((uint8_t)reg);
    Wire.endTransmission();
    Wire.requestFrom((uint8_t)_addr, (uint8_t)1);  
    return Wire.read();
}

uint16_t SI1133::read16(uint8_t a) {
  uint16_t ret;
  Wire.beginTransmission(_addr); 
  Wire.write(a); 
  Wire.endTransmission(); // complete transmission
  Wire.requestFrom(_addr, (uint8_t)2);// 
  ret = Wire.read(); // 
  ret |= (uint16_t)Wire.read() << 8; //
  return ret;
}
void SI1133::write8(uint8_t reg, uint8_t val) {

  Wire.beginTransmission(_addr); //
  Wire.write(reg); //
  Wire.write(val); // 
  Wire.endTransmission(); // fin
}

/*********************************************************************/

uint8_t SI1133::writeParam(uint8_t p, uint8_t v) {
  //Serial.print("Param 0x"); Serial.print(p, HEX);
  //Serial.print(" = 0x"); Serial.println(v, HEX);
  
  write8(SI1133_REG_HOSTIN0, v);
  write8(SI1133_REG_COMMAND, p | SI1133_PARAM_SET);
  return read8(SI1133_REG_RESPONSE1);
}

uint8_t SI1133::readParam(uint8_t p) {
  write8(SI1133_REG_COMMAND, p | SI1133_PARAM_QUERY);
  return read8(SI1133_REG_RESPONSE1);
}

/*********************************************************************/

uint32_t SI1133::readUV(void) {
	uint32_t temp;
	temp=read8(SI1133_REG_HOSTOUT0);
	temp<<=8;
	temp|=read8(SI1133_REG_HOSTOUT1);
 	return temp; 
}
uint32_t SI1133::readIR(void) {
	uint32_t temp;
	read8(SI1133_REG_HOSTOUT2);
	temp<<=8;
	temp|=read8(SI1133_REG_HOSTOUT3);
	temp<<=8;
	temp|=read8(SI1133_REG_HOSTOUT4);
 	return temp; 
}

uint32_t SI1133::printOut() {
	uint32_t temp = 0;
	temp = read8(SI1133_REG_HOSTOUT0);
  Serial.print("HOSTOUT0 : ");  Serial.println(temp);
	temp = read8(SI1133_REG_HOSTOUT1);
  Serial.print("HOSTOUT1 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT2);
  Serial.print("HOSTOUT2 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT3);
  Serial.print("HOSTOUT3 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT4);
  Serial.print("HOSTOUT4 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT5);
  Serial.print("HOSTOUT5 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT6);
  Serial.print("HOSTOUT6 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT7);
  Serial.print("HOSTOUT7 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT8);
  Serial.print("HOSTOUT8 : ");  Serial.println(temp);
  temp = read8(SI1133_REG_HOSTOUT9);
  Serial.print("HOSTOUT9 : ");  Serial.println(temp);
 	return temp; 
}
SI1133.hC/C++
#if (ARDUINO >= 100)
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif
#include <Wire.h>

//VALORES
//============================
#define RATE_SHORT  0X60 //24.4us
#define RATE_NORMAL 0X00 //48.8us
#define RATE_LONG   0X20 //97.6us
#define RATE_VLONG  0X40  //195us
//============================
#define BITS_24 0X00
#define BITS_16 0X40
//============================
#define COUNT0 0X40
#define COUNT1 0X80
//===========================




//PHOTODIODOS
//===========================
#define F_SMALL_IR  0X00 
#define F_MEDIUM_IR 0X01
#define F_LARGE_IR  0X02
#define F_WHITE     0X0B
#define F_LARGE_WHITE   0X0C
#define F_UV    0X18
#define F_UV_DEEP   0X19
//=============================

/* COMMANDS */

#define SI1133_RESET_CMD_CTR  0X00  
#define SI1133_RESET_SW 0X01
#define SI1133_FORCE  0X11
#define SI1133_PAUSE  0X12
#define SI1133_START  0X13
#define SI1133_PARAM_QUERY  0X40
#define SI1133_PARAM_SET  0X80

/* REGISTERS */

#define SI1133_REG_PARTID 0X00  //IN
#define SI1133_REG_REVID  0X01  //IN 
#define SI1133_REG_MFRID  0X02  //IN
#define SI1133_REG_INFO0  0X03  //IN
#define SI1133_REG_INFO1  0X04  //IN
#define SI1133_REG_HOSTIN3  0X07
#define SI1133_REG_HOSTIN2  0X08
#define SI1133_REG_HOSTIN1  0X09
#define SI1133_REG_HOSTIN0  0X0A
#define SI1133_REG_COMMAND  0X0B
#define SI1133_REG_IRQ_ENABLE 0X0F
#define SI1133_REG_RESPONSE1  0X10
#define SI1133_REG_RESPONSE0  0X11
#define SI1133_REG_IRQ_STATUS 0X12
#define SI1133_REG_HOSTOUT0   0X13
#define SI1133_REG_HOSTOUT1   0X14
#define SI1133_REG_HOSTOUT2   0X15
#define SI1133_REG_HOSTOUT3   0X16
#define SI1133_REG_HOSTOUT4   0X17
#define SI1133_REG_HOSTOUT5   0X18
#define SI1133_REG_HOSTOUT6   0X19
#define SI1133_REG_HOSTOUT7   0X1A
#define SI1133_REG_HOSTOUT8   0X1B
#define SI1133_REG_HOSTOUT9   0X1C
#define SI1133_REG_HOSTOUT10  0X1D
#define SI1133_REG_HOSTOUT11  0X1E
#define SI1133_REG_HOSTOUT12  0X1F
#define SI1133_REG_HOSTOUT13  0X20
#define SI1133_REG_HOSTOUT14  0X21
#define SI1133_REG_HOSTOUT15  0X22
#define SI1133_REG_HOSTOUT16  0X23
#define SI1133_REG_HOSTOUT17  0X24
#define SI1133_REG_HOSTOUT18  0X25
#define SI1133_REG_HOSTOUT19  0X26
#define SI1133_REG_HOSTOUT20  0X27
#define SI1133_REG_HOSTOUT21  0X28
#define SI1133_REG_HOSTOUT22  0X29
#define SI1133_REG_HOSTOUT23  0X2A
#define SI1133_REG_HOSTOUT24  0X2B
#define SI1133_REG_HOSTOUT25  0X2C

/* Parameters */

#define SI1133_PARAM_I2CADDR   0X00
#define SI1133_PARAM_CHLIST   0X01
#define SI1133_PARAM_ADCCONFIG0 0X02
#define SI1133_PARAM_ADCSENS0   0X03
#define SI1133_PARAM_ADCPSOT0   0X04
#define SI1133_PARAM_MEASCONFIG0  0X05
#define SI1133_PARAM_ADCCONFIG1   0X06
#define SI1133_PARAM_ADCSENS1   0X07
#define SI1133_PARAM_ADCPSOT1   0X08
#define SI1133_PARAM_MEASCONFIG1  0X09
#define SI1133_PARAM_ADCCONFIG20  0X0A
#define SI1133_PARAM_ADCSENS2   0X0B
#define SI1133_PARAM_ADCPSOT2   0X0C
#define SI1133_PARAM_MEASCONFIG2  0X0D
#define SI1133_PARAM_ADCCONFIG3 0X0E
#define SI1133_PARAM_ADCSENS3   0X0F
#define SI1133_PARAM_ADCPSOT3   0X10
#define SI1133_PARAM_MEASCONFIG3  0X11
#define SI1133_PARAM_ADCCONFIG4   0X12
#define SI1133_PARAM_ADCSENS4   0X13
#define SI1133_PARAM_ADCPSOT4   0X14
#define SI1133_PARAM_MEASCONFIG4  0X15
#define SI1133_PARAM_ADCCONFIG5   0X16
#define SI1133_PARAM_ADCSENS5   0X17
#define SI1133_PARAM_ADCPSOT5   0X18
#define SI1133_PARAM_MEASCONFIG5  0X19
#define SI1133_PARAM_MEASRATEH  0X1A
#define SI1133_PARAM_MEASRATEL  0X1B
#define SI1133_PARAM_MEASCOUNT0   0X1C
#define SI1133_PARAM_MEASCOUNT1   0X1D
#define SI1133_PARAM_MEASCOUNT2   0X1E
#define SI1133_PARAM_THRESHOLD0_H   0X25
#define SI1133_PARAM_THRESHOLD0_L   0X26  
#define SI1133_PARAM_THRESHOLD1_H   0X27
#define SI1133_PARAM_THRESHOLD1_L   0X28
#define SI1133_PARAM_THRESHOLD2_H   0X29
#define SI1133_PARAM_THRESHOLD2_L   0X2A
#define SI1133_PARAM_BURST   0X2B

#define SI1133_ADDR 0x55

class SI1133  {
 public:
  SI1133(void);
  boolean begin();
  void reset();
  uint32_t readUV();
  uint32_t readIR();
  uint32_t printOut();


 private:
  uint16_t read16(uint8_t addr);
  uint8_t read8(uint8_t addr);
  void write8(uint8_t reg, uint8_t val);
  uint8_t readParam(uint8_t p);
  uint8_t writeParam(uint8_t p, uint8_t v);
  
  uint8_t _addr;
};
Si7020.cppC/C++
Temperature , humidity sensor
/* Arduino Si7010 relative humidity + temperature sensor
 * Copyright (C) 2014 by Jakub Kaminski
 *
 * This file is part of the Arduino Si7020 Library
 *
 * This Library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This Library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Arduino Si7020 Library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * TODO: implement checksum checking
 */

#include "Si7020.h"

Si7020::Si7020(){}

void Si7020::begin()
{
	Wire.begin();
}

float Si7020::getRH()
{
	// Measure the relative humidity 
	uint16_t RH_Code = makeMeasurment(RH_NOHOLD);
	float result = (125.0*RH_Code/65536)-6;
	return result;
}

float Si7020::readTemp()
{
	// Read temperature from previous RH measurement.
	uint16_t temp_Code = makeMeasurment(TEMP_PREV);
	float result = (175.25*temp_Code/65536)-46.85;
	return result;
}

float Si7020::getTemp()
{
	// Measure temperature 
	uint16_t temp_Code = makeMeasurment(TEMP_NOHOLD);
	float result = (175.25*temp_Code/65536)-46.85;
	return result;
}

void Si7020::heaterOn()
{
	// Turns on the Si7020 heater
	uint8_t regVal = readReg();
	regVal |= _BV(HTRE);
	//turn on the heater
	writeReg(regVal);
}

void Si7020::heaterOff()
{
	// Turns off the Si7020 heater
	uint8_t regVal = readReg();
	regVal &= ~_BV(HTRE);
	writeReg(regVal);
}

void Si7020::changeResolution(uint8_t i)
{
	// Changes to resolution of Si7020 measurements.
	// Set i to:
	//      RH         Temp
	// 0: 12 bit       14 bit (default)
	// 1:  8 bit       12 bit
	// 2: 10 bit       13 bit
	// 3: 11 bit       11 bit

	uint8_t regVal = readReg();
	// zero resolution bits
	regVal &= 0b011111110;
	switch (i) {
	  case 1:
	    regVal |= 0b00000001;
	    break;
	  case 2:
	    regVal |= 0b10000000;
	    break;
	  case 3:
	    regVal |= 0b10000001;
	  default:
	    regVal |= 0b00000000;
	    break;
	}
	// write new resolution settings to the register
	writeReg(regVal);
}

void Si7020::resetSettings()
{
	//Reset user resister
	writeReg(RESET_SI);
}

uint16_t Si7020::makeMeasurment(uint8_t command)
{
	// Take one Si7020 measurement given by command.
	// It can be either temperature or relative humidity
	// TODO: implement checksum checking
	
	uint16_t nBytes = 3;
	// if we are only reading old temperature, read olny msb and lsb
	if (command == 0xE0) nBytes = 2;

	Wire.beginTransmission(SI7020);
	Wire.write(command);
	Wire.endTransmission();
	// When not using clock stretching (*_NOHOLD commands) delay here 
	// is needed to wait for the measurement.
	// According to datasheet the max. conversion time is ~22ms
	 delay(100);
		
	Wire.requestFrom(SI7020,nBytes);
	//Wait for data
	int counter = 0;
	while (Wire.available() < nBytes){
	  delay(1);
	  counter ++;
	  if (counter >100){
	    // Timeout: Sensor did not return any data
	    return 100;
	  }
	}

	unsigned int msb = Wire.read();
	unsigned int lsb = Wire.read();
	// Clear the last to bits of LSB to 00. 
	// According to datasheet LSB of RH is always xxxxxx10
	lsb &= 0xFC;
	unsigned int mesurment = msb << 8 | lsb;

	return mesurment;
}

void Si7020::writeReg(uint8_t value)
{  
	// Write to user register on Si7020
	Wire.beginTransmission(SI7020);
	Wire.write(WREG);
	Wire.write(value);
	Wire.endTransmission();
}

uint8_t Si7020::readReg()
{
	// Read from user register on Si7020
	Wire.beginTransmission(SI7020);
	Wire.write(RREG);
	Wire.endTransmission();
	Wire.requestFrom(SI7020,1);
	uint8_t regVal = Wire.read();
	return regVal;
}
Si7020.hC/C++
/* Arduino Si7010 relative humidity + temperature sensor
 * Copyright (C) 2014 by Jakub Kaminski
 *
 * This file is part of the Arduino Si7020 Library
 *
 * This Library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This Library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Arduino Si7020 Library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

// There are some differences in libraries between Arduino and Spark
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#include "Wire.h"
#elif defined(SPARK)
#include "application.h"
#define _BV(bit) (1 << (bit))
#endif

#ifndef Si7020_h
#define Si7020_h

#define SI7020      0x40
#define RH_HOLD     0xE5
#define RH_NOHOLD   0xF5
#define TEMP_HOLD   0xE3
#define TEMP_NOHOLD 0xF3
#define TEMP_PREV   0xE0
#define RESET_SI    0xFE
#define WREG        0xE6
#define RREG        0xE7
#define HTRE        0x02 

class Si7020
{
	public:
		Si7020();
		void  begin();
		float getRH();
		float readTemp();
		float getTemp();
		void  heaterOn();
		void  heaterOff();
		void  changeResolution(uint8_t i);
		void  resetSettings();
	private:
		uint16_t makeMeasurment(uint8_t command);
		void     writeReg(uint8_t value);
		uint8_t  readReg();
};

#endif

Schematics

I2C digital Sensors and microphone connections
Schematic x7zwa4r5dn
Arduino BLE sensor data
12 abpolxdjss

Comments

Author

Default
Dimiter Kendri
  • 3 projects
  • 44 followers

Additional contributors

Published on

July 30, 2017

Members who respect this project

AdambenzDefaultDefaultJohnnydoePhoto

and 6 others

See similar projects
you might like

Similar projects you might like

Arduino Environmental Monitoring

Project showcase by Prajay Basu

  • 13,743 views
  • 1 comment
  • 25 respects

Arduino 101 Home BLE System

Project tutorial by Alexis Santiago Allende

  • 2,424 views
  • 0 comments
  • 11 respects

BLE Bot 9000

Project tutorial by 5 developers

  • 23,927 views
  • 7 comments
  • 71 respects

Intel Arduino 101 BLE Blynk Tank

Project tutorial by Johnathan Hottell

  • 10,437 views
  • 6 comments
  • 41 respects

BLE Sharp Dust Sensor - ARTIK IoT Cloud

Project tutorial by Elijah Scheele

  • 4,322 views
  • 1 comment
  • 21 respects

Smart Monitoring System for Football Players

Project tutorial by Team Doppelgangers

  • 2,817 views
  • 0 comments
  • 7 respects
Add projectSign up / Login