diff --git a/src/pms/core/reader.py b/src/pms/core/reader.py index a9d6d1f..3306d17 100644 --- a/src/pms/core/reader.py +++ b/src/pms/core/reader.py @@ -93,6 +93,7 @@ def __init__( interval: Optional[int] = None, samples: Optional[int] = None, timeout: Optional[float] = None, + max_retries: Optional[int] = None, ) -> None: """Configure serial port""" self.sensor = sensor if isinstance(sensor, Sensor) else Sensor[sensor] @@ -101,6 +102,7 @@ def __init__( self.serial.port = port self.serial.baudrate = self.sensor.baud self.serial.timeout = timeout or 5 # max time to wake up sensor + self.max_retries = max_retries self.interval = interval self.samples = samples logger.debug( @@ -169,6 +171,7 @@ def __call__(self, *, raw: Optional[bool] = None): """Passive mode reading at regular intervals""" sample = 0 + failures = 0 while self.serial.is_open: try: buffer = self._cmd("passive_read") @@ -176,9 +179,15 @@ def __call__(self, *, raw: Optional[bool] = None): try: obs = self.sensor.decode(buffer) except SensorNotReady as e: + failures += 1 + if self.max_retries is not None and failures > self.max_retries: + raise logger.debug(e) time.sleep(5) except SensorWarning as e: + failures += 1 + if self.max_retries is not None and failures > self.max_retries: + raise logger.debug(e) self.serial.reset_input_buffer() else: diff --git a/tests/core/test_reader.py b/tests/core/test_reader.py index 208b23e..429ac71 100644 --- a/tests/core/test_reader.py +++ b/tests/core/test_reader.py @@ -1,5 +1,6 @@ import pytest +import pms from pms.core import reader from pms.core.sensor import Sensor from tests.conftest import captured_data @@ -139,6 +140,7 @@ def factory( samples=0, # exit immediately interval=None, sensor="PMSx003", # match with stubs + max_retries=None, ): sensor_reader = reader.SensorReader( port=mock_sensor.port, @@ -146,6 +148,7 @@ def factory( interval=interval, sensor=sensor, timeout=0.01, # low to avoid hanging on failure + max_retries=max_retries, ) # https://github.com/pyserial/pyserial/issues/625 @@ -229,6 +232,18 @@ def test_sensor_reader_warm_up( assert len(obs) == 1 +def test_sensor_reader_warm_up_exhaust_retries( + mock_sensor, + sensor_reader_factory, + mock_sensor_warm_up, +): + sensor_reader = sensor_reader_factory(max_retries=0) + + with sensor_reader as r: + with pytest.raises(pms.SensorWarmingUp): + list(r()) + + def test_sensor_reader_temp_failure( mock_sensor, sensor_reader_factory, @@ -246,6 +261,18 @@ def test_sensor_reader_temp_failure( assert mock_sensor.stubs["passive_read"].calls == 2 +def test_sensor_reader_temp_failure_exhaust_retries( + mock_sensor, + sensor_reader_factory, + mock_sensor_temp_failure, +): + sensor_reader = sensor_reader_factory(max_retries=0) + + with sensor_reader as r: + with pytest.raises(pms.SensorWarning): + list(r()) + + def test_sensor_reader_sensor_mismatch(mock_sensor, sensor_reader_factory): sensor_reader = sensor_reader_factory()