class TestFlowSensor(unittest.TestCase):
    def setUp(self):
        self._mux = I2CMux(FLOW_SENSOR_MUX_ADDRESS)
        self._mux.select_channel(2)
        self._sensor = FlowSensor()

    def tearDown(self):
        self._sensor.close()
        self._mux.close()

    @unittest.skipIf(not is_on_raspberry_pi(),
                     "The serial number won't be valid unless this "
                     "is run on hardware.")
    def test_serial_number(self):
        serial_number = self._sensor.serial_number()
        self.assertTrue(
            0 <= serial_number < 2**32,
            f"{serial_number} is not an unsigned 32-bit "
            "serial number")

    @unittest.skipIf(not is_on_raspberry_pi(),
                     "Cannot determine ambient flow unless connected "
                     "to hardware.")
    def test_ambient_flow(self):
        measured_flow = self._sensor.flow()
        self.assertTrue(
            math.isclose(measured_flow, 0, abs_tol=1),
            f"{measured_flow} != 0 +/- 0.1 slm : "
            "Fails to say that there is no flow in still "
            "air.\n"
            "Note that if this test is performed in a "
            "breezy environment, then the ambient flow may "
            "fall ouside the range of this test.")
Example #2
0
class TestCommunicator(unittest.TestCase):
    def setUp(self):
        self._mux = I2CMux(constants.FLOW_SENSOR_MUX_ADDRESS)
        self._mux.select_channel(2)
        self._communicator = Communicator()

    def tearDown(self):
        self._communicator.close()
        self._mux.close()

    def test_is_present(self):
        self.assertTrue(self._communicator.is_present(),
                        "Sensor is not useable at the moment.")

    def test_serial_number(self):
        serial_number = self._communicator.serial_number()
        self.assertTrue(
            0 <= serial_number < 2**32,
            f"{serial_number:#x} is not an unsigned 32-bit "
            "serial number.")

    @unittest.skipIf(not is_on_raspberry_pi(),
                     "Signal isn't 2 bytes + CRC8 unless connected "
                     "to hardware.")
    def test_raw_flow(self):
        self._communicator.init_flow()
        raw_flow = self._communicator.raw_flow()
        self.assertTrue(
            0 <= raw_flow < 2**16,
            f"{raw_flow:#x} is not an unsigned 16-bit flow "
            "number.")
 def test_warn_when_i2c_isnt_available(self):
     if not is_on_raspberry_pi():
         self._i2c.close()
         with self.assertWarns(UserWarning,
                               msg="Fails to warn the user when I2C "
                               "communication isn't available."):
             self._i2c = I2CInterface(0x70)
        pass

    @abstractmethod
    def tubes_with_enough_sensors(self):
        """Returns a list of the ports with both a pressure sensor and
        a flow sensor.

        Returns
        -------
        port_list : list
            A list of ints in range(constants.NUMBER_OF_PATIENTS)
            representing ports that have enough sensors.
        """


if is_on_raspberry_pi():

    class Sensors(SensorsABC):
        def __init__(self, dump_communication=False):
            self._pressure_mux = I2CMux(constants.PRESSURE_SENSOR_MUX_ADDRESS)
            self._pressure_sensors = []
            for i in range(constants.NUMBER_OF_PRESSURE_SENSORS):
                self._pressure_mux.select_channel(i)
                self._pressure_sensors.append(
                    PressureSensor(dump_communication=dump_communication))
                self._pressure_sensors[i].set_sampling(
                    pressure_oversample=constants.PRESSURE_OVERSAMPLING,
                    pressure_sampling_rate=constants.PRESSURE_RATE,
                    temperature_oversample=constants.TEMPERATURE_OVERSAMPLING,
                    temperature_sampling_rate=constants.TEMPERATURE_RATE)
                self._pressure_sensors[i].set_op_mode(
def step_impl(context):
    if is_on_raspberry_pi():
        context.scenario.skip("Cannot automatically test that the "
                              "sensor is not present unless this is "
                              "run on hardware.")
        return
def step_impl(context):
    if not is_on_raspberry_pi():
        context.scenario.skip("Cannot test that the sensor is present unless "
                              "this is run on hardware.")
        return
class TestPressureSensor(unittest.TestCase):
    def setUp(self):
        self._mux = I2CMux(PRESSURE_SENSOR_MUX_ADDRESS)
        self._mux.select_channel(0)
        self._sensor = PressureSensor()

    def tearDown(self):
        self._sensor.close()
        self._mux.close()

    @unittest.skipIf(not is_on_raspberry_pi(),
                     "Pressure sensor won't be present unless you're on "
                     "hardware.")
    def test_is_present(self):
        self.assertTrue(
            self._sensor.is_present(),
            "Fails to identify that the sensor is present.\n"
            "Note that if the sensor is not connected, this "
            "test will fail.")

    @unittest.skipIf(is_on_raspberry_pi(),
                     "This can only be tested non-interactively off of "
                     "hardware.")
    def test_not_is_present(self):
        self.assertTrue(
            not self._sensor.is_present(),
            "Fails to correctly identify that a sensor is not "
            "present.")

    def test_set_op_mode_standby(self):
        self.assertEqual(
            self._sensor.set_op_mode(PressureSensor.OpMode.standby),
            PressureSensor.OpMode.standby,
            "Fails to put the sensor into Standby Mode.")

    def test_set_op_mode_background(self):
        self.assertEqual(
            self._sensor.set_op_mode(PressureSensor.OpMode.background),
            PressureSensor.OpMode.background,
            "Fails to put the sensor into Background Mode")

    def test_set_op_mode_command(self):
        self.assertEqual(
            self._sensor.set_op_mode(PressureSensor.OpMode.command),
            PressureSensor.OpMode.command,
            "Fails to put the sensor into Command Mode.")

    def test_set_sampling_default(self):
        self.assertTrue(
            self._sensor.set_sampling(),
            "Fails to successfully set the oversample and "
            "sampling rate to default values for temerature "
            "and pressure.")

    def test_set_sampling_valid_values(self):
        self.assertTrue(
            self._sensor.set_sampling(pressure_oversample=1,
                                      pressure_sampling_rate=1,
                                      temperature_oversample=1,
                                      temperature_sampling_rate=1),
            "Fails to set the oversample and sampling rate "
            "to valid custom values for temperature and "
            "pressure")

    def test_set_sampling_invalid_values(self):
        with self.assertRaises(ValueError,
                               msg="Fails to raise a ValueError when "
                               "oversample or temperature values are not "
                               "in the set {1, 2, 4, 8, 16, 32, 64, 128}."):
            self._sensor.set_sampling(pressure_oversample=3,
                                      pressure_sampling_rate=3,
                                      temperature_oversample=3,
                                      temperature_sampling_rate=3)

    def test_pressure_without_sampling_set(self):
        self.assertTrue(
            math.isnan(self._sensor.pressure()),
            "Fails to return NaN for pressure when the user "
            "has not yet set the sampling parameters.")
        self.assertTrue(
            math.isnan(self._sensor.temperature()),
            "Fails to return NaN for temperature when the "
            "user has not yet set the sampling parameters.")

    @unittest.skipIf(not is_on_raspberry_pi(),
                     "Cannot determine ambient temperature unless "
                     "connected to hardware.")
    def test_ambient_temperature(self):
        self._sensor.set_op_mode(PressureSensor.OpMode.command)
        self._sensor.set_sampling(temperature_sampling_rate=8)
        measured_temperature = self._sensor.temperature()
        standard_temperature = 20  # degC
        relative_tolerance = 0.50
        self.assertTrue(
            math.isclose(measured_temperature,
                         standard_temperature,
                         rel_tol=relative_tolerance),
            f"{measured_temperature} != "
            f"20 ± {int(100*relative_tolerance)}% degC :\n"
            "Fails to return ambient temperature in "
            "degC.\nNote that if this test is "
            "performed in a very cold or hot "
            "environment, the\nambient temperature "
            "may fall outside the range of this test.")

    @unittest.skipIf(not is_on_raspberry_pi(),
                     "Cannot determine ambient pressure unless "
                     "connected to hardware.")
    def test_ambient_pressure(self):
        self._sensor.set_sampling()
        self._sensor.set_op_mode(PressureSensor.OpMode.command)
        measured_pressure = self._sensor.pressure()
        standard_pressure = 101325  # Pa
        relative_tolerance = 0.10
        self.assertTrue(
            math.isclose(measured_pressure,
                         standard_pressure,
                         rel_tol=relative_tolerance),
            f"{measured_pressure} != "
            f"101325 ± {int(100*relative_tolerance)}% Pa :\n"
            "Fails to return ambient pressure in Pa.\n"
            "Note that if this test is performed in a "
            "very low pressure environment,\nthe ambient "
            "pressure may fall outside the range of this "
            "test.")