diff --git a/README.rst b/README.rst index ca8984c..9434a77 100644 --- a/README.rst +++ b/README.rst @@ -61,15 +61,15 @@ Getting the temperature in Celsius is easy! First, import all of the pins from the board, board.I2C() for native I2C communication and the thermometer library itself. -.. code-block:: python +.. code-block:: python3 - from board import * + import board import adafruit_mcp9808 Next, initialize the I2C bus in a with statement so it always gets shut down ok. Then, construct the thermometer class: -.. code-block:: python +.. code-block:: python3 # Do one reading with i2c = board.I2C() as i2c: diff --git a/adafruit_mcp9808.py b/adafruit_mcp9808.py index 80275c9..1899c7f 100644 --- a/adafruit_mcp9808.py +++ b/adafruit_mcp9808.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries -# +# SPDX-FileCopyrightText: 2021 Jose David Montoya # SPDX-License-Identifier: MIT """ @@ -8,21 +8,27 @@ CircuitPython library to support MCP9808 high accuracy temperature sensor. -* Author(s): Scott Shawcroft +* Author(s): Scott Shawcroft, Jose David M. Implementation Notes -------------------- **Hardware:** -* Adafruit `MCP9808 High Accuracy I2C Temperature Sensor Breakout +* `Adafruit MCP9808 High Accuracy I2C Temperature Sensor Breakout `_ (Product ID: 1782) **Software and Dependencies:** * Adafruit CircuitPython firmware for the supported boards: https://github.com/adafruit/circuitpython/releases -* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice + +* Adafruit's Bus Device library: + https://github.com/adafruit/Adafruit_CircuitPython_BusDevice + +* Adafruit's Register library: + https://github.com/adafruit/Adafruit_CircuitPython_Register + **Notes:** @@ -30,16 +36,32 @@ """ +from micropython import const +from adafruit_bus_device.i2c_device import I2CDevice +from adafruit_register.i2c_bits import RWBits +from adafruit_register.i2c_bit import ROBit + __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MCP9808.git" -from adafruit_bus_device.i2c_device import I2CDevice + +_MCP9808_DEFAULT_ADDRESS = const(0x18) +_MCP9808_DEVICE_ID = const(0x54) +_MCP9808_REG_CONFIGURATION = const(0x01) +_MCP9808_REG_UPPER_TEMP = const(0x02) +_MCP9808_REG_LOWER_TEMP = const(0x03) +_MCP9808_REG_CRITICAL_TEMP = const(0x04) +_MCP9808_REG__TEMP = const(0x05) +_MCP9808_REG_MANUFACTURER_ID = const(0x06) +_MCP9808_REG_DEVICE_ID = const(0x07) +_MCP9808_REG_RESOLUTION = const(0x08) # Resolution settings -HALF_C = 0x0 -QUARTER_C = 0x1 -EIGHTH_C = 0x2 -SIXTEENTH_C = 0x3 + +_MCP9808_RESOLUTION_HALF_C = const(0x0) +_MCP9808_RESOLUTION_QUARTER_C = const(0x1) +_MCP9808_RESOLUTION_EIGHTH_C = const(0x2) +_MCP9808_RESOLUTION_SIXTEENTH_C = const(0x3) class MCP9808: @@ -48,6 +70,17 @@ class MCP9808: :param ~busio.I2C i2c_bus: The I2C bus the MCP9808 is connected to. :param int address: The I2C address of the device. Defaults to :const:`0x18` + **MCP9808 Settings** + You could set the MCP9808 with different temperature limits and compare them with the + ambient temperature Ta + + - above_ct this value will be set to `True` when Ta is above this limit + - above_ut: this value will be set to `True` when Ta is above this limit + - below_lt: this value will be set to `True` when Ta is below this limit + + To get this value, you will need to read the temperature, and then access the attribute + + **Quickstart: Importing and using the MCP9808** Here is an example of using the :class:`MCP9808` class. @@ -74,26 +107,33 @@ class MCP9808: """ - # alert_lower_temperature_bound - # alert_upper_temperature_bound - # critical_temperature - # temperature - # temperature_resolution + _MCP9808_REG_RESOLUTION_SET = RWBits(2, 0x08, 0, register_width=2) + above_critical = ROBit(_MCP9808_REG__TEMP, 7, register_width=1) + """True when the temperature is above the currently + set critical temperature. False Otherwise""" + + above_upper = ROBit(_MCP9808_REG__TEMP, 6, register_width=1) + """True when the temperature is above the currently + set high temperature. False Otherwise""" - def __init__(self, i2c_bus, address=0x18): + below_lower = ROBit(_MCP9808_REG__TEMP, 5, register_width=1) + """True when the temperature is below the currently + set lower temperature. False Otherwise""" + + def __init__(self, i2c_bus, address=_MCP9808_DEFAULT_ADDRESS): self.i2c_device = I2CDevice(i2c_bus, address) # Verify the manufacturer and device ids to ensure we are talking to # what we expect. self.buf = bytearray(3) - self.buf[0] = 0x06 + self.buf[0] = _MCP9808_REG_MANUFACTURER_ID with self.i2c_device as i2c: i2c.write_then_readinto(self.buf, self.buf, out_end=1, in_start=1) - ok = self.buf[2] == 0x54 and self.buf[1] == 0 + ok = self.buf[2] == _MCP9808_DEVICE_ID and self.buf[1] == 0 # Check device id. - self.buf[0] = 0x07 + self.buf[0] = _MCP9808_REG_DEVICE_ID with self.i2c_device as i2c: i2c.write_then_readinto(self.buf, self.buf, out_end=1, in_start=1) @@ -105,13 +145,113 @@ def __init__(self, i2c_bus, address=0x18): @property def temperature(self): """Temperature in Celsius. Read-only.""" - self.buf[0] = 0x05 + self.buf[0] = _MCP9808_REG__TEMP with self.i2c_device as i2c: i2c.write_then_readinto(self.buf, self.buf, out_end=1, in_start=1) + return self._temp_conv() + + def _temp_conv(self): + """Internal function to convert temperature given by the sensor""" # Clear flags from the value self.buf[1] = self.buf[1] & 0x1F if self.buf[1] & 0x10 == 0x10: self.buf[1] = self.buf[1] & 0x0F return (self.buf[1] * 16 + self.buf[2] / 16.0) - 256 return self.buf[1] * 16 + self.buf[2] / 16.0 + + def _limit_temperatures(self, temp, t_address=0x02): + """Internal function to setup limit temperature + + :param int temp: temperature limit + :param int t_address: register address for the temperature limit + 0x02 : Upper Limit + 0x03 : Lower Limit + 0x04 : Critical Limit + """ + + if temp < 0: + negative = True + temp = abs(temp) + else: + negative = False + + self.buf[0] = t_address + + self.buf[1] = temp >> 4 + if negative: + self.buf[1] = self.buf[1] | 0x10 + + self.buf[2] = (temp & 0x0F) << 4 + + with self.i2c_device as i2c: + i2c.write(self.buf) + + def _get_temperature(self, address): + self.buf[0] = address + with self.i2c_device as i2c: + i2c.write_then_readinto(self.buf, self.buf, out_end=1, in_start=1) + + return self._temp_conv() + + def _set_temperature(self, temp, address): + self._limit_temperatures(temp, address) + + @property + def upper_temperature(self): + """Upper alarm temperature in Celsius""" + + return self._get_temperature(_MCP9808_REG_UPPER_TEMP) + + @upper_temperature.setter + def upper_temperature(self, temp): + """Setup Upper temperature""" + + self._limit_temperatures(temp, _MCP9808_REG_UPPER_TEMP) + + @property + def lower_temperature(self): + """Lower alarm temperature in Celsius""" + + return self._get_temperature(_MCP9808_REG_LOWER_TEMP) + + @lower_temperature.setter + def lower_temperature(self, temp): + """Setup Lower temperature""" + + self._limit_temperatures(temp, _MCP9808_REG_LOWER_TEMP) + + @property + def critical_temperature(self): + """Critical alarm temperature in Celsius""" + + return self._get_temperature(_MCP9808_REG_CRITICAL_TEMP) + + @critical_temperature.setter + def critical_temperature(self, temp): + """Setup Critical temperature""" + + self._limit_temperatures(temp, _MCP9808_REG_CRITICAL_TEMP) + + @property + def resolution(self): + """Temperature Resolution in Celsius + + ======= ============ ============== + Value Resolution Reading Time + ======= ============ ============== + 0 0.5°C 30 ms + 1 0.25°C 65 ms + 2 0.125°C 130 ms + 3 0.0625°C 250 ms + ======= ============ ============== + + """ + + return self._MCP9808_REG_RESOLUTION_SET + + @resolution.setter + def resolution(self, resol_value=3): + """ Setup Critical temperature""" + + self._MCP9808_REG_RESOLUTION_SET = resol_value # pylint: disable=invalid-name diff --git a/docs/conf.py b/docs/conf.py index df02c8f..ad0b71d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,10 @@ "https://circuitpython.readthedocs.io/projects/busdevice/en/latest/", None, ), + "Register": ( + "https://circuitpython.readthedocs.io/projects/register/en/latest/", + None, + ), "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), } diff --git a/docs/examples.rst b/docs/examples.rst index 2bb6d90..511f915 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -6,3 +6,13 @@ Ensure your device works with this simple test. .. literalinclude:: ../examples/mcp9808_simpletest.py :caption: examples/mcp9808_simpletest.py :linenos: + + +Temperature Limit test +---------------------- + +Show the MCP9808 to setup different temperature values + +.. literalinclude:: ../examples/mcp9808_temperature_limits.py + :caption: examples/mcp9808_temperature_limits.py + :linenos: diff --git a/examples/mcp9808_simpletest.py b/examples/mcp9808_simpletest.py index 6fa99ef..3a5e810 100644 --- a/examples/mcp9808_simpletest.py +++ b/examples/mcp9808_simpletest.py @@ -14,7 +14,6 @@ # Necessary when, for example, connecting A0 to VDD to make address=0x19 # mcp = adafruit_mcp9808.MCP9808(i2c_bus, address=0x19) - while True: tempC = mcp.temperature tempF = tempC * 9 / 5 + 32 diff --git a/examples/mcp9808_temperature_limits.py b/examples/mcp9808_temperature_limits.py new file mode 100644 index 0000000..5f97e33 --- /dev/null +++ b/examples/mcp9808_temperature_limits.py @@ -0,0 +1,32 @@ +# SPDX-FileCopyrightText: 2021 Jose David M. +# SPDX-License-Identifier: MIT + +""" +Show the MCP9808 to setup different temperature values +""" + +import time +import board +import adafruit_mcp9808 + +i2c = board.I2C() # uses board.SCL and board.SDA +mcp = adafruit_mcp9808.MCP9808(i2c) + +# Change the values according to the desired values +print("Setting Temperature Limits") +mcp.upper_temperature = 23 +mcp.lower_temperature = 10 +mcp.critical_temperature = 100 + +# To verify the limits we need to read the temperature value +print(mcp.temperature) +time.sleep(0.3) # This is the time temperature conversion at maximum resolution + +# Showing temperature Limits +while True: + if mcp.below_lt: + print("too cold!") + if mcp.above_ut: + print("getting hot!") + if mcp.above_ct: + print("Above critical temp!") diff --git a/requirements.txt b/requirements.txt index 87e1960..f162505 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,6 @@ # # SPDX-License-Identifier: Unlicense +Adafruit-Blinka adafruit-circuitpython-busdevice +adafruit-circuitpython-register