/ adafruit_amg88xx.py
adafruit_amg88xx.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2017 Dean Miller for Adafruit Industries.
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  
 23  """
 24  `adafruit_amg88xx` - AMG88xx GRID-Eye IR 8x8 IR sensor
 25  ======================================================
 26  This library supports the use of the AMG88xx in CircuitPython.
 27  
 28  Author(s): Dean Miller, Scott Shawcroft for Adafruit Industries.
 29  Date: June 2017
 30  Affiliation: Adafruit Industries
 31  
 32  Implementation Notes
 33  --------------------
 34  **Hardware:**
 35  
 36  **Software and Dependencies:**
 37  * Adafruit CircuitPython: https://github.com/adafruit/circuitpython/releases
 38  * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
 39  * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
 40  
 41  **Notes:**
 42  """
 43  
 44  __version__ = "0.0.0-auto.0"
 45  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_AMG88xx"
 46  
 47  from adafruit_bus_device.i2c_device import I2CDevice
 48  from adafruit_register import i2c_bit, i2c_bits
 49  from micropython import const
 50  
 51  
 52  # Registers are defined below in the class. These are possible register values.
 53  
 54  # Operating Modes
 55  # pylint: disable=bad-whitespace
 56  _NORMAL_MODE = const(0x00)
 57  _SLEEP_MODE = const(0x10)
 58  _STAND_BY_60 = const(0x20)
 59  _STAND_BY_10 = const(0x21)
 60  
 61  # sw resets
 62  _FLAG_RESET = const(0x30)
 63  _INITIAL_RESET = const(0x3F)
 64  
 65  # frame rates
 66  _FPS_10 = const(0x00)
 67  _FPS_1 = const(0x01)
 68  
 69  # int enables
 70  _INT_DISABLED = const(0x00)
 71  _INT_ENABLED = const(0x01)
 72  
 73  # int modes
 74  _DIFFERENCE = const(0x00)
 75  _ABSOLUTE_VALUE = const(0x01)
 76  
 77  _INT_OFFSET = const(0x010)
 78  _PIXEL_OFFSET = const(0x80)
 79  
 80  _PIXEL_ARRAY_WIDTH = const(8)
 81  _PIXEL_ARRAY_HEIGHT = const(8)
 82  _PIXEL_TEMP_CONVERSION = 0.25
 83  _THERMISTOR_CONVERSION = 0.0625
 84  # pylint: enable=bad-whitespace
 85  
 86  
 87  def _signed_12bit_to_float(val):
 88      # take first 11 bits as absolute val
 89      abs_val = val & 0x7FF
 90      if val & 0x800:
 91          return 0 - float(abs_val)
 92      return float(abs_val)
 93  
 94  
 95  def _twos_comp_to_float(val):
 96      val &= 0xFFF
 97      if val & 0x800:
 98          val -= 0x1000
 99      return float(val)
100  
101  
102  class AMG88XX:
103      """Driver for the AMG88xx GRID-Eye IR 8x8 thermal camera."""
104  
105      # Set up the registers
106      _pctl = i2c_bits.RWBits(8, 0x00, 0)
107      _rst = i2c_bits.RWBits(8, 0x01, 0)
108      _fps = i2c_bit.RWBit(0x02, 0)
109      _inten = i2c_bit.RWBit(0x03, 0)
110      _intmod = i2c_bit.RWBit(0x03, 1)
111  
112      _intf = i2c_bit.RWBit(0x04, 1)
113      _ovf_irs = i2c_bit.RWBit(0x04, 2)
114      _ovf_ths = i2c_bit.RWBit(0x04, 3)
115  
116      _intclr = i2c_bit.RWBit(0x05, 1)
117      _ovs_clr = i2c_bit.RWBit(0x05, 2)
118      _ovt_clr = i2c_bit.RWBit(0x05, 3)
119  
120      _mamod = i2c_bit.RWBit(0x07, 5)
121  
122      _inthl = i2c_bits.RWBits(8, 0x08, 0)
123      _inthh = i2c_bits.RWBits(4, 0x09, 0)
124      _intll = i2c_bits.RWBits(8, 0x0A, 0)
125      _intlh = i2c_bits.RWBits(4, 0x0B, 0)
126      _ihysl = i2c_bits.RWBits(8, 0x0C, 0)
127      _ihysh = i2c_bits.RWBits(4, 0x0D, 0)
128  
129      _tthl = i2c_bits.RWBits(8, 0x0E, 0)
130  
131      _tthh = i2c_bits.RWBits(4, 0x0F, 0)
132  
133      def __init__(self, i2c, addr=0x69):
134          self.i2c_device = I2CDevice(i2c, addr)
135  
136          # enter normal mode
137          self._pctl = _NORMAL_MODE
138  
139          # software reset
140          self._rst = _INITIAL_RESET
141  
142          # disable interrupts by default
143          self._inten = False
144  
145          # set to 10 FPS
146          self._fps = _FPS_10
147  
148      @property
149      def temperature(self):
150          """Temperature of the sensor in Celsius"""
151          raw = (self._tthh << 8) | self._tthl
152          return _signed_12bit_to_float(raw) * _THERMISTOR_CONVERSION
153  
154      @property
155      def pixels(self):
156          """Temperature of each pixel across the sensor in Celsius.
157  
158             Temperatures are stored in a two dimensional list where the first index is the row and
159             the second is the column. The first row is on the side closest to the writing on the
160             sensor."""
161          retbuf = [[0] * _PIXEL_ARRAY_WIDTH for _ in range(_PIXEL_ARRAY_HEIGHT)]
162          buf = bytearray(3)
163  
164          with self.i2c_device as i2c:
165              for row in range(0, _PIXEL_ARRAY_HEIGHT):
166                  for col in range(0, _PIXEL_ARRAY_WIDTH):
167                      i = row * _PIXEL_ARRAY_HEIGHT + col
168                      buf[0] = _PIXEL_OFFSET + (i << 1)
169                      i2c.write_then_readinto(buf, buf, out_end=1, in_start=1)
170  
171                      raw = (buf[2] << 8) | buf[1]
172                      retbuf[row][col] = _twos_comp_to_float(raw) * _PIXEL_TEMP_CONVERSION
173  
174          return retbuf