예제 #1
0
    def __init__(self, settings: Settings):
        self._components = ComponentRegistry(settings)

        # thread for watchdog
        self._watch_thread: Optional[
            threading.
            Thread] = None  # re-usable thread, assignment is in init_all
        self._stop_event = threading.Event()  # own stop event for watchdog
        # thread for waiting for comps unload
        self._unload_thread: Optional[
            threading.
            Thread] = None  # re-usable thread, assignment is in unload_all
예제 #2
0
def testStandbyInDayMode(base_fixture, target_mockup_fixture):
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(MOTION_SENSOR_ENABLED, True)
    settings.set(NIGHT_MODE_BEGIN, 22)
    settings.set(NIGHT_MODE_END, 5)
    settings.set(BRIGHTNESS, 70)
    settings.set(DAY_STANDBY_TIMEOUT, 10)

    energy_saver = None
    comps = ComponentRegistry(settings)
    disp = comps.display

    # day
    with freeze_time("2019-01-01 12:59:59"):
        energy_saver = comps.energy_saver
        time.sleep(energy_saver.INIT_WAIT_TIME)
        time.sleep(energy_saver.UPDATE_TIME + 1)
        assert energy_saver.night_mode_active == False
        assert disp.get_brightness() == STANDBY_BRIGHTNESS

    # switch to wake
    comps.motion_detection_sensor._motion_detected = 1
    with freeze_time("2019-01-01 13:00:10"):
        time.sleep(energy_saver.UPDATE_TIME + 2)
        assert disp.get_brightness() == settings.get(BRIGHTNESS)
        time.sleep(10 - energy_saver.UPDATE_TIME)
        # switch to standby
        comps.motion_detection_sensor._motion_detected = 0
        time.sleep(energy_saver.UPDATE_TIME * 2)
        assert disp.get_brightness() == STANDBY_BRIGHTNESS
    energy_saver.stop()
예제 #3
0
def testNightModeEnter(base_fixture, target_mockup_fixture):
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(MOTION_SENSOR_ENABLED, True)
    settings.set(NIGHT_MODE_BEGIN, 23)
    settings.set(NIGHT_MODE_END, 5)
    settings.set(BRIGHTNESS, 70)

    energy_saver = None
    comps = ComponentRegistry(settings)
    disp = comps.display
    # day
    with freeze_time("2019-01-01 22:59:59"):
        energy_saver = ESaver(comps, settings)
        time.sleep(energy_saver.INIT_WAIT_TIME)
        assert not energy_saver._update_thread is None
        assert not energy_saver.night_mode_active
        assert disp.get_brightness() == 70
        time.sleep(energy_saver.UPDATE_TIME + 1)
        assert disp.get_brightness() == STANDBY_BRIGHTNESS
        assert not energy_saver.night_mode_active

    with freeze_time("2019-01-01 23:00:01"):
        time.sleep(2 * energy_saver.UPDATE_TIME + 1)
        assert energy_saver.night_mode_active
        assert disp.get_brightness() == NIGHT_MODE_BRIGHTNESS

    with freeze_time("2019-01-02 04:59:01"):
        time.sleep(energy_saver.UPDATE_TIME + 1)
        assert energy_saver.night_mode_active
        assert disp.get_brightness() == NIGHT_MODE_BRIGHTNESS

    energy_saver.stop()
예제 #4
0
def testDefaultComponentCreation(base_fixture, target_mockup_fixture):
    # test, that all components can be instantiated
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(MOTION_SENSOR_ENABLED, True)
    settings.set(DHT_22_PIN, 15)
    settings.set(BME_280_ENABLED, True)

    comps = ComponentRegistry(settings)

    disp = comps.display
    assert disp
    temp = comps.temp_sensor
    assert temp
    mot = comps.motion_detection_sensor
    assert mot
    tts = comps.tts
    assert tts
    es = comps.energy_saver
    assert es
    weather_info = comps.weather_info
    assert weather_info
    au = comps.auto_updater
    assert au
    hum = comps.humidity_sensor
    assert hum
    ps = comps.pressure_sensor
    assert ps
    co2 = comps.co2_sensor
    assert co2
    tvoc = comps.tvoc_sensor
    assert tvoc
    rt = comps.remote_temp_sensor
    assert rt
    ev = comps.event_handler
    assert ev
예제 #5
0
def testWakeUpFromNightMode(base_fixture, target_mockup_fixture):
    settings = Settings(base_fixture.testdata_path / "integration")

    settings.set(MOTION_SENSOR_ENABLED, True)
    settings.set(NIGHT_MODE_BEGIN, 22)
    settings.set(NIGHT_MODE_END, 5)
    settings.set(BRIGHTNESS, 70)
    settings.set(NIGHT_STANDBY_TIMEOUT, 10)

    energy_saver = None
    comps = ComponentRegistry(settings)
    disp = comps.display

    with freeze_time("2019-01-01 22:59:59"):
        energy_saver = ESaver(comps, settings)
        time.sleep(energy_saver.INIT_WAIT_TIME)
        time.sleep(energy_saver.UPDATE_TIME + 1)
        assert NIGHT_MODE_BRIGHTNESS == disp.get_brightness()
        assert energy_saver.night_mode_active == True

        # set sensor high
        comps.motion_detection_sensor._motion_detected = 1
        time.sleep(energy_saver.UPDATE_TIME + 1)
        assert disp.get_brightness() == 70 - NIGHTMODE_WAKEUP_DELTA_BRIGHTNESS

        # set sensor low
        comps.motion_detection_sensor._motion_detected = 0
        time.sleep(10 + 1)
        assert disp.get_brightness() == NIGHT_MODE_BRIGHTNESS

    energy_saver.stop()
예제 #6
0
def testComponentRegistryDefaultSensors(base_fixture):

    # disable every hw sensor
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(DHT_22_PIN, 0)
    # settings.set() = 0

    cr = ComponentRegistry(settings)
예제 #7
0
def testComponentRestartWatchdog(base_fixture, target_mockup_fixture):
    # test, that a sensor revives after stopping it
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(DHT_22_PIN, 15)

    comps = ComponentRegistry(settings)
    temp = comps.temp_sensor
    hum = comps.humidity_sensor
    assert temp

    comps.stop_component_instance(temp)
    time.sleep(1)
    assert not hasattr(comps._components, "DHT22")
    assert not hasattr(comps._components, "TempSensor")
    assert not hasattr(comps._components, "HumiditySensor")

    assert comps.temp_sensor
    assert comps.humidity_sensor
    assert comps._components["DHT22"]
def testOnSoundDisabled(base_fixture, capsys):
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(SOUND_ENABLED, "en")
    comps = ComponentRegistry(settings)

    tts = TextToSpeach(comps, settings)
    tts.say("Text1", "en")
    tts.wait_for_tts()
    # we can implicitly check, if the Thread has been started by us
    assert "TTS" in tts._tts_thread.getName()
    # test that no warning was thrown
    captured = capsys.readouterr()
    assert "WARNING" not in captured.out
    assert "Sound: Cannot play sound" not in captured.out
def testComponent(base_fixture):
    # test default constructor
    TestComponent = Component()
    # check default settings
    assert not TestComponent.is_disabled
    assert not TestComponent.reload_forbidden
    assert isinstance(TestComponent._logger, logging.Logger)
    assert isinstance(TestComponent._runtime_system, RuntimeSystem)
    assert TestComponent._settings is None
    assert TestComponent._comps is None

    settings = Settings(base_fixture.testdata_path / "integration")
    TestComponent = Component(settings=settings)
    assert TestComponent._settings == settings

    components = ComponentRegistry(settings)
    TestComponent = Component(components)
    assert TestComponent._comps == components
예제 #10
0
def testCCS811(base_fixture, target_mockup_fixture):
    from adafruit_ccs811 import TVOC, CO2
    settings = Settings(base_fixture.testdata_path / "integration")

    comps = ComponentRegistry(settings)
    sensor = sensors.CCS811(comps, settings)
    measure_points = 2

    sensor._co2_impl._values_capacity = measure_points
    sensor._tvoc_impl._values_capacity = measure_points

    time.sleep(1)
    assert sensor.is_alive
    assert sensor.is_ready

    # wait until all measurement points are filled up, so that mean value equals the constant value
    time.sleep(sensor.UPDATE_TIME * (measure_points + 1))
    assert sensor.get_tvoc() == TVOC
    assert sensor.get_co2() == CO2
예제 #11
0
def testNoStandbyIfSensorIsDisabled(base_fixture):
    settings = Settings(base_fixture.testdata_path / "integration")
    settings.set(MOTION_SENSOR_ENABLED, False)
    settings.set(NIGHT_MODE_BEGIN, 23)
    settings.set(NIGHT_MODE_END, 5)
    settings.set(BRIGHTNESS, 70)

    energy_saver = None
    comps = ComponentRegistry(settings)
    disp = comps.display

    # night mode - no wakeup
    with freeze_time("2019-01-01 12:00:00"):
        # energy_saver needs to be initalized in freeze time, otherwise testing time will have an impact
        energy_saver = ESaver(comps, settings)
        time.sleep(energy_saver.INIT_WAIT_TIME)
        time.sleep(energy_saver.UPDATE_TIME + 1)
        assert disp.get_brightness() == settings.get(BRIGHTNESS)

    energy_saver.stop()
예제 #12
0
def testDHT22(base_fixture, target_mockup_fixture):
    from adafruit_dht import TEMP, HUM
    settings = Settings(base_fixture.testdata_path / "integration")
    comps = ComponentRegistry(settings)

    sensors.DHT22.UPDATE_TIME = 1
    sensor = sensors.DHT22(pin=10, components=comps, settings=settings)
    measure_points = 2
    sensor._temp_impl._values_capacity = measure_points
    sensor._hum_impl._values_capacity = measure_points

    time.sleep(1)
    assert sensor.is_alive
    assert sensor.is_ready

    # wait until all measurement points are filled up, so that mean value equals the constant value
    time.sleep(sensor.UPDATE_TIME * (measure_points + 1))

    assert sensor.get_humidity() == HUM
    assert sensor.get_temperature() == TEMP
예제 #13
0
def testBMP280(base_fixture, target_mockup_fixture):
    from adafruit_bme280 import TEMP, PRESSURE
    settings = Settings(base_fixture.testdata_path / "integration")

    sensors.BME280.UPDATE_TIME = 1

    comps = ComponentRegistry(settings)
    sensor = sensors.BME280(comps, settings)
    measure_points = 2
    sensor._temp_impl._values_capacity = measure_points
    sensor._pres_impl._values_capacity = measure_points

    time.sleep(1)
    assert sensor.is_alive
    assert sensor.is_ready

    # wait until all measurement points are filled up, so that mean value equals the constant value
    time.sleep(sensor.UPDATE_TIME * (measure_points + 1))
    assert sensor.get_pressure() == PRESSURE
    assert sensor.get_temperature() == TEMP
예제 #14
0
def testComponentRegistry(base_fixture):
    settings = Settings(base_fixture.testdata_path / "integration")
    cr = ComponentRegistry(settings)
    assert not cr._unload_in_progress

    comp = cr._create_component_instance(Component)
    cyc_comp = cr._create_component_instance(CyclicComponent)
    assert isinstance(comp, Component)
    assert isinstance(cyc_comp, CyclicComponent)

    assert "Component" in cr.get_names()
    assert "CyclicComponent" in cr.get_names()

    assert cr._components["Component"] == comp
    assert cr._components["CyclicComponent"] == cyc_comp
예제 #15
0
class ComponentController():
    """ Loader, unloader and watchdog for components. """
    UPDATE_TIME = 5

    def __init__(self, settings: Settings):
        self._components = ComponentRegistry(settings)

        # thread for watchdog
        self._watch_thread: Optional[
            threading.
            Thread] = None  # re-usable thread, assignment is in init_all
        self._stop_event = threading.Event()  # own stop event for watchdog
        # thread for waiting for comps unload
        self._unload_thread: Optional[
            threading.
            Thread] = None  # re-usable thread, assignment is in unload_all

    @property
    def all_ready(self) -> bool:
        """ Signals, that all modules have been started loading """
        all_ready = False
        for comp_name in self._components.get_names():
            component = self._components.get(comp_name)
            if component:
                all_ready |= component.is_ready
        return all_ready

    @property
    def all_unloaded(self) -> bool:
        """ All managed modules are unloaded. """
        if not self._unload_thread:
            return True
        return not self._unload_thread.is_alive()

    @property
    def components(self) -> ComponentRegistry:
        """ Returns held components for higher level functions """
        return self._components

    def init_all(self):
        """
        Start every managed module, by starting the watch thread.
        """
        if self._unload_thread and self._unload_thread.is_alive():
            self._unload_thread.join()
        self._stop_event.clear()
        Logger().info("Start initializing all components")
        self._watch_thread = threading.Thread(name="Watchdog",
                                              target=self._watchdog_loop,
                                              daemon=True)
        self._watch_thread.start()

    def unload_all(self, reload_intended=False, updating=False):
        """
        Start unloading modules. modules_unloaded signals finish.
        """
        self._components.set_unload_in_progress()
        Logger().info("Start unloading all components")
        self._unload_thread = threading.Thread(
            name="UnloadModules",
            target=self._unload_all_components,
            args=[reload_intended, updating])
        self._unload_thread.start()

    def stop(self):
        """
        Stop this module, by sending a stop request.
        Actual stop is asyncron.
        """
        if self._watch_thread and self._watch_thread.is_alive():
            self._stop_event.set()

    def _watchdog_loop(self):
        time.sleep(2)  # wait for execution
        self._components.show()

        ticker = threading.Event()
        while not ticker.wait(self.UPDATE_TIME):
            if self._stop_event.is_set():
                self._stop_event.clear()
                return
            self._components.show()
            self._watch_components()

    def _watch_components(self):
        """
        Checks existence of global variable of each module and starts it.
        """
        # check and restart wifi
        if RuntimeSystem().is_target_system:
            RuntimeSystem().check_internet_connection()

        for comp_name in self._components.get_names():
            component = self._components.get(comp_name)
            if not component:
                break
            if issubclass(type(component), CyclicComponent):
                if component.is_ready and not component.is_alive and not component.is_disabled:
                    # call stop, so it will be initialized in the next cycle
                    self._components.stop_component(comp_name)

        for sensor_name in self._components.get_sensors():
            sensor = self._components.get_sensors()[sensor_name]
            if not sensor:
                break
            if isinstance(sensor, CyclicComponent
                          ) and sensor.is_ready and not sensor.is_alive:
                self._components.get_sensors().pop(sensor_name)

    def _unload_all_components(self, reload_intended, updating):
        """
        Stop own watcher and unload modules.
        :param reload_intended: singals, that objects, which forbid reload will be skipped
        """
        # watch threads needs to stop - updater runs continously
        self.stop()
        if self._watch_thread:
            self._watch_thread.join()

        for comp_name in self._components.get_names():
            if updating:  # exclude updater
                if self._components.auto_updater == self._components.get(
                        comp_name):
                    continue
            self._components.stop_component(comp_name, reload_intended)
        Logger().info("ComponentRegistry: All components unloaded.")
        self._components.set_unload_finished()
def testRepoIsReachable(base_fixture):
    settings = Settings(base_fixture.testdata_path / "integration")
    comps = ComponentRegistry(settings)
    online_updater = OnlineUpdater(comps, enabled=True, use_beta_channel=True)
    online_updater._connect_to_repository()
    assert online_updater._repository # only check if object exists
def testCheckShouldUpdate(base_fixture):
    import waqd.components.updater as updater # import the module here, so we can access the loaded global var of WAQD version
    settings = Settings(base_fixture.testdata_path / "integration")
    comps = ComponentRegistry(settings)

    online_updater = OnlineUpdater(comps, enabled=True, use_beta_channel=True)
    # Main versions to Main versions
    updater.WAQD_VERSION = "1.1.0"
    # same version -  no update
    assert not online_updater._check_should_update("v1.1.0")  # use v to see if it is cut
    # lesser version - no update
    assert not online_updater._check_should_update("1.0.0")
    # higher version
    assert online_updater._check_should_update("1.2.0")

    # Main Version
    # Main version to Beta version
    # beta flag enabled
    # lesser version - no update
    assert not online_updater._check_should_update("1.0.0b19")
    # same version - but Beta -> must be older
    assert not online_updater._check_should_update("1.1.0b2")
    # higher version
    assert online_updater._check_should_update("1.2.0b0")

    # beta flag disabled - no update
    online_updater._use_beta_channel = False
    assert not online_updater._check_should_update("1.0.0b19")
    assert not online_updater._check_should_update("1.1.0b2")

    # Beta Version
    # Beta Version to Main Version
    updater.WAQD_VERSION = "1.1.0b1"
    assert not online_updater._check_should_update("1.0.0")
    assert online_updater._check_should_update("1.2.0")

    # Beta Version to Beta Version
    online_updater._use_beta_channel = True
    assert not online_updater._check_should_update("1.1.0b0")
    assert online_updater._check_should_update("1.1.0b2")
    online_updater._use_beta_channel = False
    assert not online_updater._check_should_update("1.1.0b2")

    # Beta Version to Alpha Version
    # negative test, not enabled
    assert not online_updater._check_should_update("1.1.0a2")
    # enable - higher version should work
    updater.config.DEBUG_LEVEL = 1
    online_updater._use_beta_channel = True
    assert online_updater._check_should_update("1.1.0a2")
    # lower or equal should not
    assert not online_updater._check_should_update("1.1.0a1")
    assert not online_updater._check_should_update("1.1.0a0")

    # Alpha Version
    updater.WAQD_VERSION = "1.1.0a1"
    online_updater._use_beta_channel = True
    updater.config.DEBUG_LEVEL = 1
    # to alpha
    assert online_updater._check_should_update("1.1.0a2")
    assert not online_updater._check_should_update("1.1.0a0")
    assert not online_updater._check_should_update("1.1.0a1")
    # to beta
    assert online_updater._check_should_update("1.1.0b2")
    assert online_updater._check_should_update("1.1.0b1")
    # TODO currently will always update to beta
    assert online_updater._check_should_update("1.1.0b0")
    # to main
    assert online_updater._check_should_update("1.1.0")
    assert online_updater._check_should_update("1.2.0")
    assert not online_updater._check_should_update("1.0.0")
    # disabled debug level - only update to beta or main
    updater.config.DEBUG_LEVEL = 0
    # TODO: updates from alpha to alpha
    assert online_updater._check_should_update("1.1.0a2")
    assert online_updater._check_should_update("1.1.0b1")
    assert online_updater._check_should_update("1.1.0")