Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Temperature humidity sensor DSTH01

Wed Apr 06, 2016 1:36 pm

Hello all,
i'm looking for something new in my setup, so even if i already have a couple of dht22 sensorrs i was looking with interest to this i2c sensor.

But before buying it, i've a couple of questions:
- is there a clean way to convert the 1,27mm pitch spacing to the common (and widely used) 2.54mm? i'd like to avoid strange soldering..
- the datasheet talks about something i'd never seen for a i2c device

Code: Select all

If the DSTH01 module shares the I2C bus with other slave devices, it should be powered down when the master controller is communicating with the other slave devices, which can be realized either by setting /CS to logic high or setting the VCC pin to 0V. 
is this true? what's the meaning of an i2c device if i have to power it off when i use the bus? anyone tried this sensor and can confirm?

Then i'm quite curious about the heater use, but i'll eventually look into that :)

thanks :)

User avatar
brekee12
Posts: 335
Joined: Wed Feb 03, 2016 3:36 pm
Location: HU

Re: Temperature humidity sensor DSTH01

Wed Apr 06, 2016 3:12 pm

Did you looked up the chinese version of the DHT22 or the original one? I have experience with the chinese one. It has sleeping mode, so first it has to wake-up by addressing and after a while it works normally. It happens; because, it is used as one wire equipment also. Maybe, the original DHT has similar requironment and the quoted text is about the one wire option.
Brekee12
on a Raspberry B+ with whezzy, two Zero with Jessie Light

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Wed Apr 06, 2016 5:46 pm

Have you looked at the si7021?

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Wed Apr 06, 2016 7:59 pm

joan wrote:Have you looked at the si7021?
didn't know that
seems nice
let's buy one :)

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Tue Apr 12, 2016 3:25 pm

Coincidentally my Si7021 arrived today.

I bought http://www.ebay.co.uk/itm/272096714499

Looks good.

I did an hours worth of readings.

Temperature and relative humidity
Si7021-a.png
Si7021-a.png (40.33 KiB) Viewed 4340 times
Temperature
Si7021-b.png
Si7021-b.png (35.8 KiB) Viewed 4340 times
Relative humidity
Si7021-c.png
Si7021-c.png (38.87 KiB) Viewed 4340 times

Code: Select all

#!/usr/bin/env python

import time

import pigpio # http://abyz.co.uk/rpi/pigpio/python.html

"""
Code to read the Si7021 temprature and relative humidity sensor.

The sensor uses I2C to communicate.
"""
BUS=1
ADDR=0x40

pi = pigpio.pi()

if not pi.connected:
   exit(0)

h = pi.i2c_open(BUS, ADDR)

stop = time.time() + 3600

while time.time() < stop:

   # RH
   pi.i2c_write_device(h, [0xF5]) # RH no hold
   time.sleep(0.1)
   c, rh = pi.i2c_read_device(h, 3) # msb, lsb, checksum
   rh_val = (rh[0]<<8) + rh[1]

   # RH (%) = ((125 * rh_val)/65536) - 6

   RH = ((125.0 * rh_val)/65536.0) - 6.0

   # T
   pi.i2c_write_device(h, [0xF3]) # T no hold
   time.sleep(0.1)
   c, t = pi.i2c_read_device(h, 3) # msb, lsb, checksum
   t_val = (t[0]<<8) + t[1]

   # Temperature (C) = ((175.72 * t_val)/65536) - 46.85

   T = ((175.72 * t_val)/65536.0) - 46.85

   print("{:.2f} {:.2f}".format(T, RH))

   time.sleep(1)

pi.i2c_close(h)

pi.stop()

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Tue Apr 12, 2016 3:36 pm

i hate your postal service :) i'll have to wait somewhere near a month for mine..
could you please try a comparison with a DHT22? i'm quite curious about that (and i'm planning to replace my outside DHT22 with the new i2c..)

fruit-uk
Posts: 609
Joined: Wed Aug 06, 2014 4:19 pm
Location: Suffolk, UK

Tue Apr 12, 2016 3:43 pm

I have several Si7021 around the house - running on panStamps though.
They have been very reliable so far

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Tue Apr 12, 2016 4:14 pm

Massi wrote:i hate your postal service :) i'll have to wait somewhere near a month for mine..
could you please try a comparison with a DHT22? i'm quite curious about that (and i'm planning to replace my outside DHT22 with the new i2c..)
I ordered on the 28th March, so I was ahead of you.

I'll see if can set up a DHT11/DHT22/Si7021 running and leave them for a few hours.

The Si7021 has a fixed I2C address so one per bus.

Re first post.
If the DSTH01 module shares the I2C bus with other slave devices, it should be powered down when the master controller is communicating with the other slave devices, which can be realized either by setting /CS to logic high or setting the VCC pin to 0V.
Probably means other DSTH01 (same address) on the same bus.

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Wed Apr 13, 2016 7:37 pm

I left a Pi plus DHT11/DHT22/Si7201 under a plastic tub for seven hours, taking a reading every 3.3 seconds.

The DHT22 and Si7021 are clearly in the same ball park. The Si7021 seems to have a lot less jitter.

Relative Humidity %
DHTvSi-RH.jpg
DHTvSi-RH.jpg (62.47 KiB) Viewed 4184 times
Temperature C
DHTvSi-T.jpg
DHTvSi-T.jpg (62.29 KiB) Viewed 4184 times
I left the DHT11 off this plot as it obscured the view of the other two sensors. It had broad bands as above.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 7:01 pm

eventually, i got it :)
so i wrote a full class for it

Code: Select all

#!/usr/bin/env python3 
#coding=utf-8

import time
import pigpio 

#python class for Si7021 Temp-Humidity Sensor

class SI7021:
	
	#sensor has fixed address
	address = 0x40
	maxHeatLevel = 2 #this is 16mA, enough for me.. 15 would be 95 (!!) mA

	#RH Conversion Times
	#max conversion time for RH reading. In ms. 12,11,10 and 8 bit
	HtConvRh = 12
	MHtConvRh = 7
	MLtConvRh = 4.5
	LtConvRh = 3.1

	#Temp Conversion Times
	#max conversion time for TEMP reading. In ms. 14,13,12 and 11 bit
	HtConvTemp = 10.8
	MHtConvTemp = 6.2
	MLtConvTemp = 3.8
	LtConvTemp = 2.4

	HtConvFull = HtConvRh + HtConvTemp
	MHtConvFull = MHtConvRh + MHtConvTemp
	MLtConvFull = MLtConvRh + MLtConvTemp
	LtConvFull = LtConvRh + LtConvTemp
	
	#time of powerup after reset. In ms.
	resetTime = 15
	
	#commands
	HumHoldCmd = 0xE5 #Measure Relative Humidity, Hold Master Mode
	HumNoHoldCmd = 0xF5 #Measure Relative Humidity, No Hold Master Mode 
	TempHoldCmd = 0xE3 #Measure Temperature, Hold Master Mode 
	TempNoHoldCmd = 0xF3 #Measure Temperature, No Hold Master Mode 
	TempLastRhCmd = 0xE0 #Read Temperature Value from Previous RH Measurement 
	SensorResetCmd = 0xFE
	'''
	D7-D0 Measurement Resolution:
		RH 		Temp
	00	12 bit	14 bit
	01	 8 bit 	12 bit
	10	10 bit 	13 bit
	11	11 bit 	11 bit

	D2 HTRE 
	1 = On-chip Heater Enable
	0 = On-chip Heater Disable
	'''
	WriteUserRegCmd = 0xE6 #Write User Register
	ReadUserRegCmd = 0xE7 #Read User Register
	'''
	For heater, write 4 LSB of register. From 0000 to 1111, from 3mA to 95mA power consumption
	'''
	WriteHeatRegCmd = 0x51 #Write Heater Control Register
	ReadHeatRegCmd = 0x11 #Read Heater Control Register 
	FirmwareRevCmd = [0x84,0xB8] #Read Firmware Revision  
	'''
	checksum byte is calculated using a CRC generator polynomial of x8 + x5 + x4 + 1, with an initialization of 0x00
	'''
	ReadIDlowCmd = [0xFA,0x0F] #Read Electronic ID 1st Byte  
	ReadIDhighCmd = [0xFC,0xC9] #Read Electronic ID 2nd Byte  

	def __init__(self, bus=1, debug=False):
		self.debug = debug
		self.pi = pigpio.pi()
		self.i2c = self.pi.i2c_open(bus, self.address, 0)

	def resetSensor(self):
		self.pi.i2c_write_device(self.i2c, [self.SensorResetCmd])
		time.sleep(self.resetTime/1000.0)

	def readRH(self,hold=False):
		#check what resolution is set up
		resolution = self.getRes()
		if resolution == 0b00: sleepTime = self.HtConvFull/1000.0
		elif resolution == 0b01: sleepTime = self.MHtConvFull/1000.0
		elif resolution == 0b10: sleepTime = self.MLtConvFull/1000.0
		else: sleepTime = self.LtConvFull/1000.0
		#now start a new conversion
		if hold: command = self.HumHoldCmd
		else: command = self.HumNoHoldCmd
		self.pi.i2c_write_device(self.i2c, [command])
		#wait for the reading to end
		time.sleep(sleepTime)
		c, rh = self.pi.i2c_read_device(self.i2c, 3) # msb, lsb, checksum		
		#check the checksum.. to be implemented		
		if self.checkChecksum(rh) > 0:
			raise Exception("Wrong Checksum in RH reading")
		value = (rh[0]<<8) + rh[1]
		return min(max(0.0,((125.0*value)/65536.0)-6.0),100.0)
		
	def readTemp(self,hold=False,last=False,checksum=False):
		#i'f i'm requesting the last converted temp (in a RH read) i can skip half function
		if last: 
			command = self.TempLastRhCmd
			sleepTime = 0
		else:
			#check what resolution is set up
			resolution = self.getRes()
			if resolution == 0b00: sleepTime = self.HtConvTemp/1000.0
			elif resolution == 0b01: sleepTime = self.MHtConvTemp/1000.0
			elif resolution == 0b10: sleepTime = self.MLtConvTemp/1000.0
			else: sleepTime = self.LtConvTemp/1000.0
			#now start a new conversion
			if hold: command = self.TempHoldCmd
			else: command = self.TempNoHoldCmd
		self.pi.i2c_write_device(self.i2c, [command])
		#wait for the reading to end
		time.sleep(sleepTime)
		c, t = self.pi.i2c_read_device(self.i2c, 3) # msb, lsb, checksum		
		#check the checksum.. to be implemented reading IDs
		if self.checkChecksum(t) > 0:
			raise Exception("Wrong Checksum in Temp reading")
		value = (t[0]<<8) + t[1]
		return ((175.72*value)/65536.0)-46.85
	
	def readUserReg(self):
		self.pi.i2c_write_device(self.i2c, [self.ReadUserRegCmd])
		regValue = self.pi.i2c_read_byte(self.i2c) # reg value
		return regValue

	def readHeatReg(self):
		self.pi.i2c_write_device(self.i2c, [self.ReadHeatRegCmd])
		regValue = self.pi.i2c_read_byte(self.i2c) # reg value
		return regValue

	def writeUserReg(self,data):
		self.pi.i2c_write_device(self.i2c, [self.WriteUserRegCmd, data])

	def writeHeatReg(self,data):
		if data > maxHeatLevel: raise ValueError("Heat Level too high")
		self.pi.i2c_write_device(self.i2c, [self.writeHeatRegCmd, data])
		
	def setRes(self,resolution):
		#we have 4 levels. 0-3? but inverted (in the reg 00 is the highest)
		if resolution not in range(0,4): raise ValueError("Resolution must be in range 0-3")
		#inverting the range
		resolution = 3-resolution
		#exploding bits
		resMSB = resolution>>1&1
		resLSB = resolution&1
		#getting actual register
		reg = self.readUserReg()
		#bitwising it
		reg = self.setBit(reg,resMSB,7)
		reg = self.setBit(reg,resLSB,0)
		#writing it back to the device
		self.writeUserReg(reg)
		
	def getRes(self):
		userReg = self.readUserReg()
		return((userReg>>0&1) | (userReg>>7&1)<<1)
		
	def heaterControl(self,power=0,level=0):
		#power control!
		#getting actual register
		reg = self.readUserReg()
		#bitwising it
		reg = self.setBit(reg,power,2)
		#writing it back to the device
		self.writeUserReg(reg)		
		#level control
		self.writeHeatReg(level)
		
	def checkChecksum(self,data):
		rem = 0
		for b in data:
			rem ^= b
			for bit in range(8):
				if rem & 128:
					rem = (rem << 1) ^ 0x131
				else:
					rem = (rem << 1)
		return rem & 0xFF	
		
	def getFirmwareRev(self):
		self.pi.i2c_write_device(self.i2c, self.FirmwareRevCmd)
		regValue = self.pi.i2c_read_byte(self.i2c) # reg value
		return regValue
		
	def getSerial(self):
		self.pi.i2c_write_device(self.i2c, self.ReadIDlowCmd)
		c, resultLow = self.pi.i2c_read_device(self.i2c, 8)
		self.pi.i2c_write_device(self.i2c, self.ReadIDhighCmd)
		c, resultHigh = self.pi.i2c_read_device(self.i2c, 6)

		crc = (resultLow[1],resultLow[3],resultLow[5],resultLow[7],resultHigh[2],resultHigh[5])
		serial = (resultLow[0],resultLow[2],resultLow[4],resultLow[6],resultHigh[0],resultHigh[1],resultHigh[3],resultHigh[4])
		if 	self.checkChecksum((resultLow[0],resultLow[1])) or \
			self.checkChecksum((resultLow[0],resultLow[2],resultLow[3])) or \
			self.checkChecksum((resultLow[0],resultLow[2],resultLow[4],resultLow[5])) or \
			self.checkChecksum((resultLow[0],resultLow[2],resultLow[4],resultLow[6],resultLow[7])) or \
			self.checkChecksum((resultHigh[0],resultHigh[1],resultHigh[2])) or \
			self.checkChecksum((resultHigh[0],resultHigh[1],resultHigh[3],resultHigh[4],resultHigh[5])): 
			raise Exception("Checksum error in Serial")
		return (resultLow[0]<<56)|(resultLow[2]<<48)|(resultLow[4]<<40)|(resultLow[6]<<32)|(resultHigh[0]<<24)|(resultHigh[1]<<16)|(resultHigh[3]<<8)|resultHigh[4]
		
	def setBit(self,byte,bit,index):
		#Set the index:th bit of byte to bit, and return the new value.
		mask = 1 << index
		byte &= ~mask
		if bit:
			byte |= mask
		return byte

	def close(self):
		self.pi.i2c_close(self.i2c)
		self.pi.stop()

if __name__ == "__main__":
	sensor = SI7021()
	print("User Reg: {:8b}".format(sensor.readUserReg()))
	print("Heat Reg{:8b}".format(sensor.readHeatReg()))
	print("Resolution: {:2b}".format(sensor.getRes()))
	print("RH: {}".format(sensor.readRH()))
	print("Temp {}".format(sensor.readTemp()))
	print("Firmware: {:x}".format(sensor.getFirmwareRev()))
	print("Serial: {}".format(sensor.getSerial()))	
	sensor.close()
but how to check the checksum??
what does this mean?
The
checksum byte is calculated using a CRC generator polynomial of x8 + x5 + x4 + 1, with an initialization of 0x00.
and why is it needed to read the id?

Edit: reviewed code to add joan's crc :)
Last edited by Massi on Sat May 07, 2016 8:05 pm, edited 1 time in total.

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 7:20 pm

Here is some code I started but has been on the back burner (i.e. I have been doing other things instead).

I don't think it was that far off being okay but I hadn't finished testing. Make of it what you will.

Code: Select all

#!/usr/bin/env python

import time

import pigpio # http://abyz.co.uk/rpi/pigpio/python.html

"""
Code to read the Si7021 temprature and relative humidity sensor.

The sensor uses I2C to communicate.

Code      Command

0xE5      Measure Relative Humidity, Hold Master Mode
   MSB LSB CRC

0xF5      Measure Relative Humidity, No Hold Master Mode
   MSB LSB CRC

0xE3      Measure Temperature, Hold Master Mode
   MSB LSB CRC

0xF3      Measure Temperature, No Hold Master Mode
   MSB LSB CRC

0xE0      Read Temperature Value from Previous RH Measurement
   MSB LSB

0xFE      Reset
   ---

0xE6 VAL  Write RH/T User Register 1

   D7   D6   D5   D4   D3   D2   D1   D0
   RES1 VDDS RSVD RSVD RSVD HTRE RSVD RES0

   RES:  RH/T 0 12/14, 1 8/12, 2 10/13, 3 11/11
   VDDS: 0 okay, 1 low
   HTRE: 0 heater disable, 1 heater enable

0xE7      Read RH/T User Register 1
   VAL

0x51 VAL  Write Heater Control Register

   D7   D6   D5   D4   D3   D2   D1   D0
   RSVD RSVD RSVD RSVD HTR3 HTR2 HTR1 HTR0

   HTR: mA 0 3.09, 1 9.18, 2 15.24, 4 27.39, 8 51.69, 15 94.2

0x11      Read Heater Control Register
   VAL

0xFA 0x0F Read Electronic ID 1st Byte
   SNA_3 CRC SNA_2 CRC SNA_1 CRC SNA_0 CRC

0xFC 0xC9 Read Electronic ID 2nd Byte
   SNB_3 CRC SNB_2 CRC SNB_1 CRC SNB_0 CRC

   SNB_3: 0x00 sample, 0x0D 7013, 0x14 7020, 0x15 7021, 0xFF sample

0x84 0xB8 Read Firmware Revision
   REV

   REV: 0xFF 1.0, 0x20 2.0

"""

class sensor:

   def __init__(self, pi, bus=1, addr=0x40):
      self.pi = pi
      self._h = pi.i2c_open(bus, addr)

   def close(self):
      self.pi.i2c_close(self._h)

   def temperature(self):
      self.pi.i2c_write_device(self._h, [0xF3]) # T no hold
      time.sleep(0.1)
      c, t = self.pi.i2c_read_device(self._h, 3) # msb, lsb, checksum
      if self._crc(t) == 0:
         t_val = (t[0]<<8) + t[1]
         T = ((175.72 * t_val)/65536.0) - 46.85
      else:
         T = 999
      return T

   def humidity(self):
      self.pi.i2c_write_device(self._h, [0xF5]) # RH no hold
      time.sleep(0.1)
      c, rh = self.pi.i2c_read_device(self._h, 3) # msb, lsb, checksum
      if self._crc(rh) == 0:
         rh_val = (rh[0]<<8) + rh[1]
         RH = ((125.0 * rh_val)/65536.0) - 6.0
      else:
         RH = 999
      return RH

   def switch_heater_on(self):
      # read register and only update heater bit
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0xFB) | 4
      self.pi.i2c_write_device(self._h, [0xE6, v])

   def switch_heater_off(self):
      # read register and only update heater bit
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0xFB)
      self.pi.i2c_write_device(self._h, [0xE6, v])

   def set_resolution(self, res):
      # read register and only update resolution bits
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0x7E) | (res & 1) | ((res & 2)<<6)
      self.pi.i2c_write_device(self._h, [0xE6, v])

   def get_resolution(self):
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = ((val[0]&128)>>6) | (val[0]&1)
      return v

   def set_heater_level(self, level):

      # read register and only update heater bits
      self.pi.i2c_write_device(self._h, [0x11])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0xF0) | (level & 0x0F)
      self.pi.i2c_write_device(self._h, [0x51, v])

   def get_heater_level(self):
      self.pi.i2c_write_device(self._h, [0x11])
      c, level = self.pi.i2c_read_device(self._h, 1) # level
      return level[0]&0x0F

   def firmware_revision(self):
      self.pi.i2c_write_device(self._h, [0x84, 0xB8])
      c, rev = self.pi.i2c_read_device(self._h, 1) # rev
      return rev[0]

   def electronic_id_1(self):
      self.pi.i2c_write_device(self._h, [0xFA, 0x0F])
      c, id1 = self.pi.i2c_read_device(self._h, 8) # id1
      return (id1[0]<<24)|(id1[2]<<16)|(id1[4]<<8)|id1[6]

   def electronic_id_2(self):
      self.pi.i2c_write_device(self._h, [0xFC, 0xC9])
      c, id2 = self.pi.i2c_read_device(self._h, 8) # id2
      return (id2[0]<<24)|(id2[2]<<16)|(id2[4]<<8)|id2[6]

   def _crc(self, data):
      rem = 0
      for b in data:
         rem ^= b
         for bit in range(8):
            if rem & 128:
               rem = (rem << 1) ^ 0x31
            else:
               rem = (rem << 1)
      return rem & 0xFF

if __name__ == "__main__":

   import time
   import Si7021
   import pigpio

   pi = pigpio.pi()

   if not pi.connected:
      exit(0)

   s = Si7021.sensor(pi)

   s.set_resolution(0)
   print("res=", s.get_resolution())

   stop = time.time() + 10

   print("revision={:x} id1={:08x} id2={:08x}".format(s.firmware_revision(),
      s.electronic_id_1(), s.electronic_id_2()))

   while time.time() < stop:

      print("{:.2f} {:.2f}".format(s.temperature(), s.humidity()))

      time.sleep(1)

   s.close()

   pi.stop()
The CRC for the electronic ids don't work as I expected. It seems to work for the first four bytes (from memory, I haven't got one set-up at the moment, each CRC appears to be for the preceding bytes, so the first CRC is for SNA_3, second CRC is for SNA_3 and SNA_2, third CRC is for SNA_3, 2, 1, and fourth CRC is for SNA_3, 2, 1, 0).

I can't make it work at all for the second four bytes of the electronic id.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 7:33 pm

well more or less we did the same for code :)
but what's that 0x31 in the crc function?
shouldn't it be 0x131 starting from the polynomial function?

x8+x5+x4+x should be 0b100110001, so 0x131
am i wrong?

i'll try to get what you did :)

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 7:37 pm

Massi wrote:well more or less we did the same for code :)
but what's that 0x31 in the crc function?
shouldn't it be 0x131 starting from the polynomial function?

x8+x5+x4+x should be 0b100110001, so 0x131
am i wrong?

i'll try to get what you did :)
I used to understand CRCs and error correction codes etc. but through lack of use I've forgotten most of what I knew.

You can use 0x131 if you want, it should have the same result, as the CRC is truncated to be 8 bits.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 7:52 pm

joan wrote:
Massi wrote:well more or less we did the same for code :)
but what's that 0x31 in the crc function?
shouldn't it be 0x131 starting from the polynomial function?

x8+x5+x4+x should be 0b100110001, so 0x131
am i wrong?

i'll try to get what you did :)
I used to understand CRCs and error correction codes etc. but through lack of use I've forgotten most of what I knew.

You can use 0x131 if you want, it should have the same result, as the CRC is truncated to be 8 bits.
Fancy that, it's all working!
So as you said for the first command (8 bytes) every CRC is related to all what is before:
And for the second command (6 bytes) it's the same:

CRC1 is for SNB_3 and SNB_2
CRC2 is for SNB_3, SNB_2, SNB_1 and SNB_0

Thanks a lot :)

Edit: in your code i see you read 8 bytes even for the second serial call, but in the datasheet it's 6bytes long. Maybe that's why you can't check checksums?

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 8:04 pm

Massi wrote: ...
Edit: in your code i see you read 8 bytes even for the second serial call, but in the datasheet it's 6bytes long. Maybe that's why you can't check checksums?
Almost certainly, I don't know how I managed to misread the pdf, but I did! :(

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 8:09 pm

well now it works, WE fixed it :)
with the si7021 i got also a bmp280, i'm gonna try also that

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Sat May 07, 2016 9:01 pm

Massi wrote:well now it works, WE fixed it :)
with the si7021 i got also a bmp280, i'm gonna try also that
I updated my code to correctly read the second four bytes of the electronic Id.

Code: Select all

#!/usr/bin/env python

# Si87021.py
# Public Domain
# 2016-05-07

import time
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html

"""
Code to read the Si7021 temprature and relative humidity sensor.

The sensor uses I2C to communicate.

Code      Command

0xE5      Measure Relative Humidity, Hold Master Mode
   MSB LSB CRC

0xF5      Measure Relative Humidity, No Hold Master Mode
   MSB LSB CRC

0xE3      Measure Temperature, Hold Master Mode
   MSB LSB CRC

0xF3      Measure Temperature, No Hold Master Mode
   MSB LSB CRC

0xE0      Read Temperature Value from Previous RH Measurement
   MSB LSB

0xFE      Reset
   ---

0xE6 VAL  Write RH/T User Register 1

   D7   D6   D5   D4   D3   D2   D1   D0
   RES1 VDDS RSVD RSVD RSVD HTRE RSVD RES0

   RES:  RH/T 0 12/14, 1 8/12, 2 10/13, 3 11/11
   VDDS: 0 okay, 1 low
   HTRE: 0 heater disable, 1 heater enable

0xE7      Read RH/T User Register 1
   VAL

0x51 VAL  Write Heater Control Register

   D7   D6   D5   D4   D3   D2   D1   D0
   RSVD RSVD RSVD RSVD HTR3 HTR2 HTR1 HTR0

   HTR: mA 0 3.09, 1 9.18, 2 15.24, 4 27.39, 8 51.69, 15 94.2

0x11      Read Heater Control Register
   VAL

0xFA 0x0F Read Electronic ID 1st Byte
   SNA_3 CRC SNA_2 CRC SNA_1 CRC SNA_0 CRC

0xFC 0xC9 Read Electronic ID 2nd Byte
   SNB_3 SNB_2 CRC SNB_1 SNB_0 CRC

   SNB_3: 0x00 sample, 0x0D 7013, 0x14 7020, 0x15 7021, 0xFF sample

0x84 0xB8 Read Firmware Revision
   REV

   REV: 0xFF 1.0, 0x20 2.0

"""

class sensor:

   def __init__(self, pi, bus=1, addr=0x40):
      self.pi = pi
      self._h = pi.i2c_open(bus, addr)

   def close(self):
      self.pi.i2c_close(self._h)

   def temperature(self):
      self.pi.i2c_write_device(self._h, [0xF3]) # T no hold
      time.sleep(0.1)
      c, t = self.pi.i2c_read_device(self._h, 3) # msb, lsb, checksum
      if self._crc(t) == 0:
         t_val = (t[0]<<8) + t[1]
         T = ((175.72 * t_val)/65536.0) - 46.85
      else:
         T = 999
      return T

   def humidity(self):
      self.pi.i2c_write_device(self._h, [0xF5]) # RH no hold
      time.sleep(0.1)
      c, rh = self.pi.i2c_read_device(self._h, 3) # msb, lsb, checksum
      if self._crc(rh) == 0:
         rh_val = (rh[0]<<8) + rh[1]
         RH = ((125.0 * rh_val)/65536.0) - 6.0
      else:
         RH = 999
      return RH

   def switch_heater_on(self):
      # read register and only update heater bit
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0xFB) | 4
      self.pi.i2c_write_device(self._h, [0xE6, v])

   def switch_heater_off(self):
      # read register and only update heater bit
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0xFB)
      self.pi.i2c_write_device(self._h, [0xE6, v])

   def set_resolution(self, res):
      # read register and only update resolution bits
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0x7E) | (res & 1) | ((res & 2)<<6)
      self.pi.i2c_write_device(self._h, [0xE6, v])

   def get_resolution(self):
      self.pi.i2c_write_device(self._h, [0xE7])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = ((val[0]&128)>>6) | (val[0]&1)
      return v

   def set_heater_level(self, level):

      # read register and only update heater bits
      self.pi.i2c_write_device(self._h, [0x11])
      c, val = self.pi.i2c_read_device(self._h, 1)
      v = (val[0] & 0xF0) | (level & 0x0F)
      self.pi.i2c_write_device(self._h, [0x51, v])

   def get_heater_level(self):
      self.pi.i2c_write_device(self._h, [0x11])
      c, level = self.pi.i2c_read_device(self._h, 1) # level
      return level[0]&0x0F

   def firmware_revision(self):
      self.pi.i2c_write_device(self._h, [0x84, 0xB8])
      c, rev = self.pi.i2c_read_device(self._h, 1) # rev
      return rev[0]

   def electronic_id_1(self):
      self.pi.i2c_write_device(self._h, [0xFA, 0x0F])
      c, id1 = self.pi.i2c_read_device(self._h, 8) # id1
      if self._crc([id1[0], id1[2], id1[4], id1[6]]) == id1[7]:
         return (id1[0]<<24)|(id1[2]<<16)|(id1[4]<<8)|id1[6]
      else:
         return 0

   def electronic_id_2(self):
      self.pi.i2c_write_device(self._h, [0xFC, 0xC9])
      c, id2 = self.pi.i2c_read_device(self._h, 6) # id2
      if self._crc([id2[0], id2[1], id2[3], id2[4]]) == id2[5]:
         return (id2[0]<<24)|(id2[1]<<16)|(id2[3]<<8)|id2[4]
      else:
         return 0

   def _crc(self, data):
      rem = 0
      for b in data:
         rem ^= b
         for bit in range(8):
            if rem & 128:
               rem = (rem << 1) ^ 0x31
            else:
               rem = (rem << 1)
      return rem & 0xFF

if __name__ == "__main__":

   import time
   import Si7021
   import pigpio

   pi = pigpio.pi()

   if not pi.connected:
      exit(0)

   s = Si7021.sensor(pi)

   s.set_resolution(0)
   print("res=", s.get_resolution())

   stop = time.time() + 10

   print("revision={:x} id1={:08x} id2={:08x}".format(s.firmware_revision(),
      s.electronic_id_1(), s.electronic_id_2()))

   while time.time() < stop:

      print("{:.2f} {:.2f}".format(s.temperature(), s.humidity()))

      time.sleep(1)

   s.close()

   pi.stop()

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Mon May 09, 2016 12:58 pm

am i wrong or even clock stretching is working with this device?
i expected it to fail with a raspi, but executing the reading with the hold is working for me..

(btw, my sensor is a rev. 1.0 and it's new, lol, where's the 2.0?)

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Mon May 09, 2016 1:39 pm

Massi wrote:am i wrong or even clock stretching is working with this device?
i expected it to fail with a raspi, but executing the reading with the hold is working for me..

(btw, my sensor is a rev. 1.0 and it's new, lol, where's the 2.0?)
My sensor returns 0xFF (for a Rev. 1.0) as well.

I didn't try the clock stretching mode. I will try later, perhaps tonight. Perhaps the i2c_bcm2708 driver has been updated. I know someone gave a clock stretching patch with a request for it to be included in the driver.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Mon May 09, 2016 2:04 pm

well i have to admit that at my level of noobness i just tried using the 0xE5 - 0xE3 commands, and i got the same results than 0xF5 - 0xF3 commands.
i did not look to piscope so maybe i'm completely wrong :)

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Tue May 10, 2016 6:30 pm

i was going to install the sensor in it's final position (that is outside) and.. surprise!
i can't see it!
e checked connections 3 times
i exchanged it with other i2c sensors
i tried with 5v
nothing!
any idea?
it's working perfectly inside, and i don't think it's a matter of distance because:
- i have a range extender for i2c bus in the middle
- all other sensors work flawlessly
- i also tried adding a PCA9548 next to the sensor

ideas?
i'm so sad :(

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Tue May 10, 2016 6:52 pm

Massi wrote:i was going to install the sensor in it's final position (that is outside) and.. surprise!
i can't see it!
e checked connections 3 times
i exchanged it with other i2c sensors
i tried with 5v
nothing!
any idea?
it's working perfectly inside, and i don't think it's a matter of distance because:
- i have a range extender for i2c bus in the middle
- all other sensors work flawlessly
- i also tried adding a PCA9548 next to the sensor

ideas?
i'm so sad :(
All I can suggest is to lower the bus speed.

/boot/config.txt

dtparam=i2c_baudrate=50000

All my connections are just a few inches.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Tue May 10, 2016 7:12 pm

i already tried :(
but at 400k everything else is working.. this isn't working even at 100k
i really can't understand this..

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Temperature humidity sensor DSTH01

Wed May 11, 2016 10:06 am

the sensor should have an embedded 10k pullup resistor, do you think it can be a good idea to strengthen it adding, i.e., another 10k in parallel?

User avatar
joan
Posts: 14559
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Temperature humidity sensor DSTH01

Wed May 11, 2016 10:12 am

Massi wrote:the sensor should have an embedded 10k pullup resistor, do you think it can be a good idea to strengthen it adding, i.e., another 10k in parallel?
No idea. I have to assume there is some interaction with the I2C extender. You may need to open a new post mentioning the Si7021 by name. The people who can help may not be reading this thread.

Return to “Automation, sensing and robotics”