From 37f7e0d2f544a09d89700d65db3c81238c05a065 Mon Sep 17 00:00:00 2001 From: jposada202020 Date: Mon, 12 Jun 2023 14:08:09 -0400 Subject: [PATCH 1/2] updating lib --- adafruit_adt7410.py | 403 ++++++++++++++++++++-------- docs/examples.rst | 29 +- examples/adt7410_operation_mode.py | 20 ++ examples/adt7410_resolution_mode.py | 21 ++ examples/adt7410_temp_limits.py | 31 +++ 5 files changed, 384 insertions(+), 120 deletions(-) create mode 100644 examples/adt7410_operation_mode.py create mode 100644 examples/adt7410_resolution_mode.py create mode 100644 examples/adt7410_temp_limits.py diff --git a/adafruit_adt7410.py b/adafruit_adt7410.py index d048fa5..7073dd9 100644 --- a/adafruit_adt7410.py +++ b/adafruit_adt7410.py @@ -1,4 +1,5 @@ # SPDX-FileCopyrightText: 2019 ladyada for Adafruit Industries +# SPDX-FileCopyrightText: 2023 Jose D. Montoya # # SPDX-License-Identifier: MIT @@ -35,14 +36,14 @@ import time -import struct -from adafruit_bus_device.i2c_device import I2CDevice -from adafruit_register.i2c_bit import RWBit, ROBit +from collections import namedtuple from micropython import const +from adafruit_bus_device import i2c_device +from adafruit_register.i2c_struct import UnaryStruct +from adafruit_register.i2c_bits import RWBits try: - # Used only for typing - import busio # pylint: disable=unused-import + from busio import I2C except ImportError: pass @@ -50,19 +51,30 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ADT7410.git" -_ADT7410_TEMPMSB: int = const(0x0) -_ADT7410_TEMPLSB: int = const(0x1) -_ADT7410_STATUS: int = const(0x2) -_ADT7410_CONFIG: int = const(0x3) -_ADT7410_THIGHMSB: int = const(0x4) -_ADT7410_THIGHLSB: int = const(0x5) -_ADT7410_TLOWMSB: int = const(0x6) -_ADT7410_TLOWLSB: int = const(0x7) -_ADT7410_TCRITMSB: int = const(0x8) -_ADT7410_TCRITLSB: int = const(0x9) -_ADT7410_THYST: int = const(0x0A) -_ADT7410_ID: int = const(0xB) -_ADT7410_SWRST: int = const(0x2F) +_REG_WHOAMI = const(0xB) +_TEMP = const(0x00) +_STATUS = const(0x02) +_CONFIGURATION = const(0x03) +_TEMP_HIGH = const(0x04) +_TEMP_LOW = const(0x06) +_TEMP_CRITICAL = const(0x08) +_TEMP_HYSTERESIS = const(0x0A) + +CONTINUOUS = const(0b00) +ONE_SHOT = const(0b01) +SPS = const(0b10) +SHUTDOWN = const(0b11) +operation_mode_values = (CONTINUOUS, ONE_SHOT, SPS, SHUTDOWN) + +LOW_RESOLUTION = const(0b0) +HIGH_RESOLUTION = const(0b1) +resolution_mode_values = (LOW_RESOLUTION, HIGH_RESOLUTION) + +COMP_DISABLED = const(0b0) +COMP_ENABLED = const(0b1) +comparator_mode_values = (COMP_DISABLED, COMP_ENABLED) + +AlertStatus = namedtuple("AlertStatus", ["high_alert", "low_alert", "critical_alert"]) class ADT7410: @@ -96,128 +108,281 @@ class ADT7410: """ - # many modes can be set with register objects for simplicity - ready: ROBit = ROBit(_ADT7410_STATUS, 7) - ctpin_polarity: RWBit = RWBit(_ADT7410_CONFIG, 2) - intpin_polarity: RWBit = RWBit(_ADT7410_CONFIG, 3) - comparator_mode: RWBit = RWBit(_ADT7410_CONFIG, 4) - high_resolution: RWBit = RWBit(_ADT7410_CONFIG, 7) - - # Status Information configuration - temp_over_critiq: ROBit = ROBit(_ADT7410_STATUS, 6) - temp_over_high: ROBit = ROBit(_ADT7410_STATUS, 5) - temp_under_low: ROBit = ROBit(_ADT7410_STATUS, 4) - - def __init__(self, i2c_bus: busio.I2C, address: int = 0x48) -> None: - self.i2c_device = I2CDevice(i2c_bus, address) - self._buf = bytearray(3) - # Verify the manufacturer and device ids to ensure we are talking to - # what we expect. - _id = (self._read_register(_ADT7410_ID)[0]) & 0xF8 - if _id != 0xC8: - raise ValueError( - "Unable to find ADT7410 at i2c address " + str(hex(address)) - ) - self.reset() + _device_id = UnaryStruct(_REG_WHOAMI, "B") + _temperature = UnaryStruct(_TEMP, ">h") + _temperature_high = UnaryStruct(_TEMP_HIGH, ">h") + _temperature_low = UnaryStruct(_TEMP_LOW, ">h") + _temperature_critical = UnaryStruct(_TEMP_CRITICAL, ">h") + _temperature_hysteresis = UnaryStruct(_TEMP_HYSTERESIS, "B") + _status = UnaryStruct(_STATUS, "B") + + # Configuration register + _resolution_mode = RWBits(1, _CONFIGURATION, 7) + _operation_mode = RWBits(2, _CONFIGURATION, 5) + _comparator_mode = RWBits(1, _CONFIGURATION, 4) + + # Status Register + _critical_alert = RWBits(1, _STATUS, 6) + _high_alert = RWBits(1, _STATUS, 5) + _low_alert = RWBits(1, _STATUS, 4) + + def __init__(self, i2c_bus: I2C, address: int = 0x48) -> None: + self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) + + if self._device_id != 0xCB: + raise RuntimeError("Failed to find ADT7410") + + @property + def operation_mode(self) -> str: + """ + Sensor operation_mode + + Continuous Mode + --------------- + + In continuous conversion mode, the read operation provides the most recent + converted result. + + One Shot Mode + -------------- + + When one-shot mode is enabled, the ADT7410 immediately + completes a conversion and then goes into shutdown mode. The + one-shot mode is useful when one of the circuit design priorities is + to reduce power consumption. + + SPS Mode + ---------- + + In this mode, the part performs one measurement per second. + A conversion takes only 60 ms, and it remains in the idle state + for the remaining 940 ms period + + Shutdown Mode + --------------- + The ADT7410 can be placed in shutdown mode, the entire IC is + shut down and no further conversions are initiated until the + ADT7410 is taken out of shutdown mode. The conversion result from the + last conversion prior to shutdown can still be read from the + ADT7410 even when it is in shutdown mode. When the part is + taken out of shutdown mode, the internal clock is started and a + conversion is initiated + + +--------------------------------+------------------+ + | Mode | Value | + +================================+==================+ + | :py:const:`adt7410.CONTINUOUS` | :py:const:`0b00` | + +--------------------------------+------------------+ + | :py:const:`adt7410.ONE_SHOT` | :py:const:`0b01` | + +--------------------------------+------------------+ + | :py:const:`adt7410.SPS` | :py:const:`0b10` | + +--------------------------------+------------------+ + | :py:const:`adt7410.SHUTDOWN` | :py:const:`0b11` | + +--------------------------------+------------------+ + """ + values = ( + "CONTINUOUS", + "ONE_SHOT", + "SPS", + "SHUTDOWN", + ) + return values[self._operation_mode] + + @operation_mode.setter + def operation_mode(self, value: int) -> None: + if value not in operation_mode_values: + raise ValueError("Value must be a valid operation_mode setting") + self._operation_mode = value + time.sleep(0.24) @property def temperature(self) -> float: - """The temperature in Celsius""" - temp = self._read_register(_ADT7410_TEMPMSB, 2) - return struct.unpack(">h", temp)[0] / 128 + """ + Temperature in Celsius + In normal mode, the ADT7410 runs an automatic conversion + sequence. During this automatic conversion sequence, a conversion + takes 240 ms to complete and the ADT7410 is continuously + converting. This means that as soon as one temperature conversion + is completed, another temperature conversion begins. + On power-up, the first conversion is a fast conversion, taking + typically 6 ms. Fast conversion temperature accuracy is typically + within ±5°C. + The measured temperature value is compared with a critical + temperature limit, a high temperature limit, and a low temperature + limit. If the measured value + exceeds these limits, the INT pin is activated; and if it exceeds the + :attr:`critical_temp` limit, the CT pin is activated. + """ + return self._temperature / 128 @property - def status(self) -> int: - """The ADT7410 status registers current value""" - return self._read_register(_ADT7410_STATUS)[0] + def resolution_mode(self) -> str: + """ + Sensor resolution_mode + + +-------------------------------------+-----------------+ + | Mode | Value | + +=====================================+=================+ + | :py:const:`adt7410.LOW_RESOLUTION` | :py:const:`0b0` | + +-------------------------------------+-----------------+ + | :py:const:`adt7410.HIGH_RESOLUTION` | :py:const:`0b1` | + +-------------------------------------+-----------------+ + """ + values = ( + "LOW_RESOLUTION", + "HIGH_RESOLUTION", + ) + return values[self._resolution_mode] + + @resolution_mode.setter + def resolution_mode(self, value: int) -> None: + if value not in resolution_mode_values: + raise ValueError("Value must be a valid resolution_mode setting") + self._resolution_mode = value + + @property + def alert_status(self): + """The current triggered status of the high and low temperature alerts as a AlertStatus + named tuple with attributes for the triggered status of each alert. + + .. code-block :: python + + import time + import board + import adt7410 + + i2c = board.I2C() # uses board.SCL and board.SDA + adt = adt7410.ADT7410(i2c) + + tmp.low_temperature = 20 + tmp.high_temperature = 23 + tmp.critical_temperature = 30 + + print("High limit: {}".format(tmp.high_temperature)) + print("Low limit: {}".format(tmp.low_temperature)) + print("Critical limit: {}".format(tmp.critical_temperature)) + + adt.comparator_mode = adt7410.COMP_ENABLED + + while True: + print("Temperature: {:.2f}C".format(adt.temperature)) + alert_status = tmp.alert_status + if alert_status.high_alert: + print("Temperature above high set limit!") + if alert_status.low_alert: + print("Temperature below low set limit!") + if alert_status.critical_alert: + print("Temperature above critical set limit!") + time.sleep(1) + + """ + + return AlertStatus( + high_alert=self._high_alert, + low_alert=self._low_alert, + critical_alert=self._critical_alert, + ) @property - def configuration(self) -> int: - """The ADT7410 configuration register""" - return self._read_register(_ADT7410_CONFIG)[0] - - @configuration.setter - def configuration(self, val: int) -> None: - self._write_register(_ADT7410_CONFIG, val) - - def reset(self) -> None: - """Perform a software reset""" - self._write_register(_ADT7410_SWRST) - time.sleep(0.5) - - def _read_register(self, addr: int, num: int = 1) -> int: - self._buf[0] = addr - with self.i2c_device as i2c: - i2c.write_then_readinto( - self._buf, self._buf, out_end=1, in_start=1, in_end=num + 1 - ) - return self._buf[1 : num + 1] - - def _write_register(self, addr: int, data: int = None) -> None: - self._buf[0] = addr - end = 1 - if data: - self._buf[1] = data - end = 2 - with self.i2c_device as i2c: - i2c.write(self._buf, end=end) + def comparator_mode(self) -> str: + """ + Sensor comparator_mode + + +-----------------------------------+-----------------+ + | Mode | Value | + +===================================+=================+ + | :py:const:`adt7410.COMP_DISABLED` | :py:const:`0b0` | + +-----------------------------------+-----------------+ + | :py:const:`adt7410.COMP_ENABLED` | :py:const:`0b1` | + +-----------------------------------+-----------------+ + """ + values = ( + "COMP_DISABLED", + "COMP_ENABLED", + ) + return values[self._comparator_mode] + + @comparator_mode.setter + def comparator_mode(self, value: int) -> None: + if value not in comparator_mode_values: + raise ValueError("Value must be a valid comparator_mode setting") + self._comparator_mode = value @property - def high_temperature(self) -> int: - """The over temperature limit value in Celsius""" - temp = self._read_register(_ADT7410_THIGHMSB, 2) - return struct.unpack(">h", temp)[0] / 128 + def high_temperature(self) -> float: + """ + High temperature limit value in Celsius + When the temperature goes above the :attr:`high_temperature`, + and if :attr:`comparator_mode` is selected. The :attr:`alert_status` + high_alert clears to 0 when the status register is read and/or when + the temperature measured goes back below the limit set in the setpoint + :attr:`high_temperature` + :attr:`hysteresis_temperature` + + The INT pin is activated if an over temperature event occur + The default setting is 64°C + + """ + return self._temperature_high // 128 @high_temperature.setter def high_temperature(self, value: int) -> None: - value = struct.pack(">h", int(value * 128)) - self._write_register(_ADT7410_THIGHMSB, value[0]) - self._write_register(_ADT7410_THIGHLSB, value[1]) + if value not in range(-55, 151, 1): + raise ValueError("Temperature should be between -55C and 150C") + self._temperature_high = value * 128 @property - def low_temperature(self) -> int: - """The over temperature limit value in Celsius. Only works when - comparator mode is selected""" - temp = self._read_register(_ADT7410_TLOWMSB, 2) - return struct.unpack(">h", temp)[0] / 128 + def low_temperature(self) -> float: + """ + Low temperature limit value in Celsius. + When the temperature goes below the :attr:`low_temperature`, + and if :attr:`comparator_mode` is selected. The :attr:`alert_status` + low_alert clears to 0 when the status register is read and/or when + the temperature measured goes back above the limit set in the setpoint + :attr:`low_temperature` + :attr:`hysteresis_temperature` + + The INT pin is activated if an under temperature event occur + The default setting is 10°C + """ + return self._temperature_low // 128 @low_temperature.setter def low_temperature(self, value: int) -> None: - value = struct.pack(">h", int(value * 128)) - self._write_register(_ADT7410_TLOWMSB, value[0]) - self._write_register(_ADT7410_TLOWLSB, value[1]) + if value not in range(-55, 151, 1): + raise ValueError("Temperature should be between -55C and 150C") + self._temperature_low = value * 128 @property - def critical_temperature(self) -> int: - """The critical temperature limit value in Celsius. Only works when - comparator mode is selected""" - temp = self._read_register(_ADT7410_TCRITMSB, 2) - return struct.unpack(">h", temp)[0] / 128 + def critical_temperature(self) -> float: + """ + Critical temperature limit value in Celsius + When the temperature goes above the :attr:`critical_temperature`, + and if :attr:`comparator_mode` is selected. The :attr:`alert_status` + critical_alert clears to 0 when the status register is read and/or when + the temperature measured goes back below the limit set in + :attr:`critical_temperature` + :attr:`hysteresis_temperature` + + The INT pin is activated if a critical over temperature event occur + The default setting is 147°C + """ + return self._temperature_critical // 128 @critical_temperature.setter def critical_temperature(self, value: int) -> None: - """The over temperature limit value in Celsius - There is a bug in the sensor, so the address 0x09 could no be written to 0x00 - for this reason only odd numbers could be given. We could make the 0x09 with - a value of 0x01, however make the logic more complex. Only works when - comparator mode is selected - """ - value = struct.pack(">h", int(value * 128)) - self._write_register(_ADT7410_TCRITMSB, value[0]) - self._write_register(_ADT7410_TCRITLSB, value[1]) + if value not in range(-55, 151, 1): + raise ValueError("Temperature should be between -55C and 15C") + self._temperature_critical = value * 128 @property - def hysteresis(self) -> int: - """The hysteresis temperature limit value in Celsius. Only works when - comparator mode is selected. From 0 to 15 Celsius""" - temp = self._read_register(_ADT7410_THYST)[0] - return temp - - @hysteresis.setter - def hysteresis(self, value: int) -> None: - if value > 15 or isinstance(value, float): - raise ValueError( - "Hysteresis value must be an integer lower than 15 Celsius" - ) - - self._write_register(_ADT7410_THYST, value) + def hysteresis_temperature(self) -> float: + """ + Hysteresis temperature limit value in Celsius for the + :attr:`critical_temperature`, :attr:`high_temperature` and + :attr:`low_temperature` limits + """ + return self._temperature_hysteresis + + @hysteresis_temperature.setter + def hysteresis_temperature(self, value: int) -> None: + if value not in range(0, 16, 1): + raise ValueError("Temperature should be between 0C and 15C") + self._temperature_hysteresis = value diff --git a/docs/examples.rst b/docs/examples.rst index 03fae23..4b45281 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -5,4 +5,31 @@ Ensure your device works with this simple test. .. literalinclude:: ../examples/adt7410_simpletest.py :caption: examples/adt7410_simpletest.py - :linenos: + :lines: 5- + +Resolution mode settings +------------------------- + +Example showing the Resolution mode setting + +.. literalinclude:: ../examples/adt7410_resolution_mode.py + :caption: examples/adt7410_resolution_mode.py + :lines: 5- + +Temperature Limits +------------------------- + +Temperature Limits example + +.. literalinclude:: ../examples/adt7410_temp_limits.py + :caption: examples/adt7410_temp_limits.py + :lines: 5- + +Operation mode settings +------------------------ + +Example showing the Operation mode setting + +.. literalinclude:: ../examples/adt7410_operation_mode.py + :caption: examples/adt7410_operation_mode.py + :lines: 5- diff --git a/examples/adt7410_operation_mode.py b/examples/adt7410_operation_mode.py new file mode 100644 index 0000000..ed1e840 --- /dev/null +++ b/examples/adt7410_operation_mode.py @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +import time +import board +import adt7410 + +i2c = board.I2C() +adt = adt7410.ADT7410(i2c) + +adt.operation_mode = adt7410.SPS + +while True: + for operation_mode in adt7410.operation_mode_values: + print("Current Operation mode setting: ", adt.operation_mode) + for _ in range(10): + print("Temperature: {:.2f}C".format(adt.temperature)) + time.sleep(0.5) + adt.operation_mode = operation_mode diff --git a/examples/adt7410_resolution_mode.py b/examples/adt7410_resolution_mode.py new file mode 100644 index 0000000..e3319cb --- /dev/null +++ b/examples/adt7410_resolution_mode.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya +# +# SPDX-License-Identifier: MIT + +import time +import board +import adt7410 + +i2c = board.I2C() +adt = adt7410.ADT7410(i2c) + +adt.resolution_mode = adt7410.HIGH_RESOLUTION + +while True: + for resolution_mode in adt7410.resolution_mode_values: + print("Current Resolution mode setting: ", adt.resolution_mode) + for _ in range(10): + temp = adt.temperature + print("Temperature :{:.2f}C".format(temp)) + time.sleep(0.5) + adt.resolution_mode = resolution_mode diff --git a/examples/adt7410_temp_limits.py b/examples/adt7410_temp_limits.py new file mode 100644 index 0000000..2524563 --- /dev/null +++ b/examples/adt7410_temp_limits.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries +# SPDX-License-Identifier: MIT + +import time +import board +import adt7410 + +i2c = board.I2C() # uses board.SCL and board.SDA +adt = adt7410.ADT7410(i2c) + +adt.low_temperature = 18 +adt.high_temperature = 29 +adt.critical_temperature = 35 +adt.hysteresis_temperature = 2 + +print("High limit: {}C".format(adt.high_temperature)) +print("Low limit: {}C".format(adt.low_temperature)) +print("Critical limit: {}C".format(adt.critical_temperature)) + +adt.comparator_mode = adt7410.COMP_ENABLED + +while True: + print("Temperature: {:.2f}C".format(adt.temperature)) + alert_status = adt.alert_status + if alert_status.high_alert: + print("Temperature above high set limit!") + if alert_status.low_alert: + print("Temperature below low set limit!") + if alert_status.critical_alert: + print("Temperature above critical set limit!") + time.sleep(1) From 6fa5d57251df00c9f2d1a6a077c60d1c8ad03314 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 8 Jan 2024 11:18:47 -0600 Subject: [PATCH 2/2] high_resolution convenience property. Allow getter values to be fed back into setters --- adafruit_adt7410.py | 66 ++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/adafruit_adt7410.py b/adafruit_adt7410.py index 7073dd9..19e1cdd 100644 --- a/adafruit_adt7410.py +++ b/adafruit_adt7410.py @@ -34,7 +34,6 @@ """ - import time from collections import namedtuple from micropython import const @@ -47,10 +46,14 @@ except ImportError: pass +try: + from typing import Union +except ImportError: + pass + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ADT7410.git" - _REG_WHOAMI = const(0xB) _TEMP = const(0x00) _STATUS = const(0x02) @@ -65,14 +68,22 @@ SPS = const(0b10) SHUTDOWN = const(0b11) operation_mode_values = (CONTINUOUS, ONE_SHOT, SPS, SHUTDOWN) +operation_mode_strings = ( + "CONTINUOUS", + "ONE_SHOT", + "SPS", + "SHUTDOWN", +) LOW_RESOLUTION = const(0b0) HIGH_RESOLUTION = const(0b1) resolution_mode_values = (LOW_RESOLUTION, HIGH_RESOLUTION) +resolution_mode_strings = ("LOW_RESOLUTION", "HIGH_RESOLUTION") COMP_DISABLED = const(0b0) COMP_ENABLED = const(0b1) comparator_mode_values = (COMP_DISABLED, COMP_ENABLED) +comparator_mode_strings = ("COMP_DISABLED", "COMP_ENABLED") AlertStatus = namedtuple("AlertStatus", ["high_alert", "low_alert", "critical_alert"]) @@ -180,18 +191,15 @@ def operation_mode(self) -> str: | :py:const:`adt7410.SHUTDOWN` | :py:const:`0b11` | +--------------------------------+------------------+ """ - values = ( - "CONTINUOUS", - "ONE_SHOT", - "SPS", - "SHUTDOWN", - ) - return values[self._operation_mode] + return operation_mode_strings[self._operation_mode] @operation_mode.setter - def operation_mode(self, value: int) -> None: + def operation_mode(self, value: Union[int, str]) -> None: if value not in operation_mode_values: - raise ValueError("Value must be a valid operation_mode setting") + if value not in operation_mode_strings: + raise ValueError("Value must be a valid operation_mode setting") + + value = operation_mode_strings.index(value) self._operation_mode = value time.sleep(0.24) @@ -228,18 +236,27 @@ def resolution_mode(self) -> str: | :py:const:`adt7410.HIGH_RESOLUTION` | :py:const:`0b1` | +-------------------------------------+-----------------+ """ - values = ( - "LOW_RESOLUTION", - "HIGH_RESOLUTION", - ) - return values[self._resolution_mode] + + return resolution_mode_strings[self._resolution_mode] @resolution_mode.setter - def resolution_mode(self, value: int) -> None: + def resolution_mode(self, value: Union[int, str]) -> None: if value not in resolution_mode_values: - raise ValueError("Value must be a valid resolution_mode setting") + if value not in resolution_mode_strings: + raise ValueError("Value must be a valid resolution_mode setting") + + value = resolution_mode_strings.index(value) self._resolution_mode = value + @property + def high_resolution(self) -> bool: + """Whether the device is currently configured for high resolution mode.""" + return self.resolution_mode == HIGH_RESOLUTION + + @high_resolution.setter + def high_resolution(self, value: bool) -> None: + self.resolution_mode = HIGH_RESOLUTION if value else LOW_RESOLUTION + @property def alert_status(self): """The current triggered status of the high and low temperature alerts as a AlertStatus @@ -296,16 +313,15 @@ def comparator_mode(self) -> str: | :py:const:`adt7410.COMP_ENABLED` | :py:const:`0b1` | +-----------------------------------+-----------------+ """ - values = ( - "COMP_DISABLED", - "COMP_ENABLED", - ) - return values[self._comparator_mode] + return comparator_mode_strings[self._comparator_mode] @comparator_mode.setter - def comparator_mode(self, value: int) -> None: + def comparator_mode(self, value: Union[int, str]) -> None: if value not in comparator_mode_values: - raise ValueError("Value must be a valid comparator_mode setting") + if value not in comparator_mode_strings: + raise ValueError("Value must be a valid comparator_mode setting") + + value = comparator_mode_strings.index(value) self._comparator_mode = value @property