dhtget 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #!/usr/bin/env python3
  2. #
  3. # Read values from DHT11/22 to I2C converter
  4. #
  5. # Copyright (c) 2018 Michael Buesch <m@bues.ch>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. import sys
  22. import time
  23. import getopt
  24. import smbus
  25. class DHT_via_I2C(object):
  26. """Read a DHT11/22 sensor via I2C.
  27. """
  28. # Device types.
  29. DHT11 = 0
  30. DHT22 = 1
  31. DEFAULT_BUS = 1
  32. DEFAULT_ADDR = 0x76
  33. def __init__(self,
  34. devType=DHT11,
  35. i2cBus=DEFAULT_BUS,
  36. i2cAddr=DEFAULT_ADDR):
  37. self.__devType = devType
  38. self.__seqCount = -1
  39. self.__temp = 0.0
  40. self.__hum = 0.0
  41. self.__i2cAddr = i2cAddr
  42. self.__i2c = smbus.SMBus(i2cBus)
  43. def __crc(self, data):
  44. crc = 0
  45. for d in data:
  46. crc ^= d
  47. for i in range(8):
  48. if crc & 0x80:
  49. crc = (crc << 1) & 0xFF
  50. crc ^= 0x07
  51. else:
  52. crc = (crc << 1) & 0xFF
  53. return crc & 0xFF
  54. def update(self):
  55. """Try to get new temperature and humidity values.
  56. Returns True, if new values have been fetched.
  57. """
  58. # Read the data from I2C.
  59. try:
  60. data = self.__i2c.read_i2c_block_data(
  61. self.__i2cAddr,
  62. self.__devType, 7)
  63. except OSError as e:
  64. return False
  65. # Extract and check the I2C data.
  66. seqCount = data[0]
  67. dhtData = data[1:-1]
  68. dataCRC = data[-1]
  69. calcCRC = self.__crc(data[0:-1])
  70. if dataCRC != calcCRC:
  71. return False
  72. if seqCount == self.__seqCount:
  73. return False
  74. # Extract and check the DHT11/22 data.
  75. hum = (dhtData[0] << 8) | (dhtData[1])
  76. temp = (dhtData[2] << 8) | (dhtData[3])
  77. calcChecksum = sum(dhtData[0:-1]) & 0xFF
  78. dataChecksum = dhtData[-1]
  79. if dataChecksum != calcChecksum:
  80. return False
  81. # Convert the temperature and humidity values.
  82. if self.__devType == self.DHT11:
  83. divisor = 256.0
  84. tempFactor = 1.0
  85. else:
  86. divisor = 10.0
  87. if temp & 0x8000:
  88. temp &= 0x7FFF
  89. tempFactor = -1.0
  90. else:
  91. tempFactor = 1.0
  92. self.__hum = float(hum) / divisor
  93. self.__temp = (float(temp) / divisor) * tempFactor
  94. self.__seqCount = seqCount
  95. return True
  96. @property
  97. def tempCelsius(self):
  98. """Get the measured temperature, in Celcius.
  99. """
  100. return self.__temp
  101. @property
  102. def tempFahrenheit(self):
  103. """Get the measured temperature, in Fahrenheit.
  104. """
  105. return self.tempCelsius * 1.8 + 32
  106. @property
  107. def humidityPercent(self):
  108. """Get the measured humidity, in percent.
  109. """
  110. return self.__hum
  111. def usage():
  112. print("Usage: dhtget [OPTIONS]")
  113. print()
  114. print(" -1|--dht11 The connected device is a DHT11 (default).")
  115. print(" -2|--dht22 The connected device is a DHT22.")
  116. print(" -l|--loop COUNT Run in a loop.")
  117. print(" If count is negative, run an infinite loop.")
  118. print(" Default: Run once.")
  119. print(" -c|--csv Print output as CSV.")
  120. print(" -H|--no-header Do not print CSV header.")
  121. print(" -f|--fahrenheit Use Fahrenheit instead of Celsius.")
  122. print(" -b|--i2c-bus BUS Use I2C bus number BUS. Default: 1.")
  123. print(" -a|--i2c-addr ADDR Use I2C address ADDR. Default: 0x76.")
  124. print(" -h|--help Print this help text.")
  125. def main(argv):
  126. opt_devType = DHT_via_I2C.DHT11
  127. opt_loop = 1
  128. opt_csv = False
  129. opt_fahrenheit = False
  130. opt_header = True
  131. opt_i2cBus = DHT_via_I2C.DEFAULT_BUS
  132. opt_i2cAddr = DHT_via_I2C.DEFAULT_ADDR
  133. try:
  134. opts, args = getopt.getopt(argv[1:],
  135. "h12l:cHfb:a:",
  136. [ "help",
  137. "dht11", "dht22",
  138. "loop=",
  139. "csv", "no-header",
  140. "fahrenheit",
  141. "i2c-bus=",
  142. "i2c-addr=", ])
  143. except getopt.GetoptError as e:
  144. print(str(e), file=sys.stderr)
  145. return 1
  146. for o, v in opts:
  147. if o in ("-h", "--help"):
  148. usage()
  149. return 0
  150. if o in ("-1", "--dht11"):
  151. opt_devType = DHT_via_I2C.DHT11
  152. if o in ("-2", "--dht22"):
  153. opt_devType = DHT_via_I2C.DHT22
  154. if o in ("-l", "--loop"):
  155. try:
  156. opt_loop = int(v, 0)
  157. except ValueError as e:
  158. print("Invalid -l|--loop value.", file=sys.stderr)
  159. return 1
  160. if o in ("-c", "--csv"):
  161. opt_csv = True
  162. if o in ("-H", "--no-header"):
  163. opt_header = False
  164. if o in ("-f", "--fahrenheit"):
  165. opt_fahrenheit = True
  166. if o in ("-b", "--i2c-bus"):
  167. try:
  168. opt_i2cBus = int(v, 0)
  169. except ValueError as e:
  170. print("Invalid -b|--i2c-bus value.", file=sys.stderr)
  171. return 1
  172. if o in ("-a", "--i2c-addr"):
  173. try:
  174. opt_i2cAddr = int(v, 0)
  175. except ValueError as e:
  176. print("Invalid -a|--i2c-addr value.", file=sys.stderr)
  177. return 1
  178. try:
  179. dht = DHT_via_I2C(devType=opt_devType,
  180. i2cBus=opt_i2cBus,
  181. i2cAddr=opt_i2cAddr)
  182. except OSError as e:
  183. print("Failed to establish DHT-I2C communication:\n%s" % str(e),
  184. file=sys.stderr)
  185. return 1
  186. tempUnit = "F" if opt_fahrenheit else "*C"
  187. if opt_csv and opt_header:
  188. print("Temperature %s;Humidity %%" % tempUnit)
  189. count = opt_loop
  190. stream = sys.stdout
  191. while count != 0:
  192. if dht.update():
  193. temp = dht.tempFahrenheit if opt_fahrenheit else dht.tempCelsius
  194. hum = dht.humidityPercent
  195. if opt_csv:
  196. stream.write("%.1f;%.1f\n" % (temp, hum))
  197. else:
  198. stream.write("Temperature: %.1f %s\n" % (
  199. temp, tempUnit))
  200. stream.write("Humidity: %.1f %%\n" % hum)
  201. stream.flush()
  202. if count > 0:
  203. count -= 1
  204. time.sleep(0.1)
  205. return 0
  206. try:
  207. sys.exit(main(sys.argv))
  208. except KeyboardInterrupt as e:
  209. sys.exit(0)