Yet Another WebIOPi+
 All Classes Namespaces Files Functions Variables Macros Pages
htu21d.py
Go to the documentation of this file.
1 # Copyright 2014 Zoltán Zörgő <soltan.zorgo@gmail.com>
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 # Sensor datasheet: http://www.meas-spec.com/downloads/HTU21D.pdf
16 #
17 # Credits to: Jay Wineinger <jay.wineinger@gmail.com>
18 # Based on: https://github.com/jwineinger/quick2wire-HTU21D/blob/master/htu21d.py
19 
20 import time
21 from webiopi.devices.i2c import I2C
22 from webiopi.devices.sensor import Temperature,Humidity
23 from webiopi.utils.types import toint
24 
25 class CRCFailed(Exception): pass
26 
28 
29  CMD_READ_TEMP_HOLD = 0xe3
30  CMD_READ_HUM_HOLD = 0xe5
31  CMD_READ_TEMP_NOHOLD = 0xf3
32  CMD_READ_HUM_NOHOLD = 0xf5
33  CMD_WRITE_USER_REG = 0xe6
34  CMD_READ_USER_REG = 0xe7
35  CMD_SOFT_RESET= 0xfe
36 
37  # uses bits 7 and 0 of the user_register mapping
38  # to the bit resolutions of (relative humidity, temperature)
39  RESOLUTIONS = {
40  (0, 0) : (12, 14),
41  (0, 1) : (8, 12),
42  (1, 0) : (10, 13),
43  (1, 1) : (11, 11),
44  }
45 
46  # sets up the times to wait for measurements to be completed. uses the
47  # max times from the datasheet plus a healthy safety margin (10-20%)
48  MEASURE_TIMES = {
49  (12, 14): (.018, .055),
50  (8, 12): (.005, .015),
51  (10, 13): (.006, .028),
52  (11, 11): (.01, .009),
53  }
54 
55  def __init__(self):
56  I2C.__init__(self, 0x40)
57 
59  self.rh_timing, self.temp_timing = self.MEASURE_TIMES[self.resolutions]
60 
61  def __str__(self):
62  return "HTU21D(slave=0x%02X)" % self.slave
63 
64  def __family__(self):
65  return [Temperature.__family__(self), Humidity.__family__(self)]
66 
67  def check_crc(self, sensor_val):
68  message_from_sensor = sensor_val >> 8
69  check_value_from_sensor = sensor_val & 0x0000FF
70 
71  remainder = message_from_sensor << 8 # Pad with 8 bits because we have to add in the check value
72  remainder |= check_value_from_sensor # Add on the check value
73 
74  divisor = 0x988000 # This is the 0x0131 polynomial shifted to farthest left of three bytes
75 
76  # Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done.
77  for i in range(16):
78 
79  if remainder & (1<<(23 - i)): #Check if there is a one in the left position
80  remainder ^= divisor
81 
82  divisor >>= 1 # Rotate the divisor max 16 times so that we have 8 bits left of a remainder
83 
84  if remainder:
85  raise CRCFailed("CRC checksum failed.")
86 
87  def reset(self):
88  self.writeByte(self.CMD_SOFT_RESET);
89  time.sleep(.02)
90 
91  def set_resolution(self, resIndex):
92  self.writeRegister(self.CMD_WRITE_USER_REG, resIndex)
93  time.sleep(.02)
94 
95  def get_resolutions(self):
96  user_reg = self.readRegister(self.CMD_READ_USER_REG)
97  return self.RESOLUTIONS[user_reg >> 6, user_reg & 0x1]
98 
99  def get_temp(self):
100  self.writeByte(self.CMD_READ_TEMP_NOHOLD);
101  time.sleep(self.temp_timing)
102  results = self.readBytes(3)
103  raw_temp = int.from_bytes(results, byteorder="big")
104  self.check_crc(raw_temp)
105 
106  results[1] = results[1] & 0xFC # clear status bits
107  raw_temp = int.from_bytes(results, byteorder="big")
108  return -46.85 + (175.72 * ((raw_temp >> 8) / float(2**16)))
109 
110  def get_rel_humidity(self):
111  self.writeByte(self.CMD_READ_HUM_NOHOLD);
112  time.sleep(self.rh_timing)
113  results = self.readBytes(3)
114  raw_hum = int.from_bytes(results, byteorder="big")
115  self.check_crc(raw_hum)
116 
117  results[1] = results[1] & 0xFC # clear status bits
118  raw_hum = int.from_bytes(results, byteorder="big")
119  return -6 + (125 * ((raw_hum >> 8) / float(2**16)))
120 
122  RHactualT = self.get_rel_humidity()
123  Tactual = self.get_temp()
124  CoeffTemp = -0.15 # from datasheet
125  return RHactualT + (25 - Tactual)*CoeffTemp
126 
127  def __getCelsius__(self):
128  self.reset()
129  return self.get_temp()
130 
131  def __getFahrenheit__(self):
132  return self.Celsius2Fahrenheit()
133 
134  def __getKelvin__(self):
135  return self.Celsius2Kelvin()
136 
137  def __getHumidity__(self):
138  self.reset()
139  return self.get_comp_rel_humidity() / 100.00