def testEventScheduler(base_fixture, qtbot, target_mockup_fixture, monkeypatch): with freeze_time(datetime(2020, 12, 24, 22, 59, 45), tick=True) as frozen: settings = Settings(base_fixture.testdata_path / "integration") #settings.set(NIGHT_MODE_END, 0) settings.set(SOUND_ENABLED, True) comp_ctrl = ComponentController(settings) Logger().info("Start") comps = comp_ctrl.components comps.energy_saver wmu = WeatherMainUi(comp_ctrl, settings) from pytestqt.plugin import _qapp_instance config.qt_app = _qapp_instance qtbot.addWidget(wmu) #monkeypatch.setattr('apscheduler.triggers.date.datetime', frozen) ev = EventHandler(comps, settings) t = get_time_of_day() current_date_time = datetime.now() settings._logger.info(current_date_time) assert t ev.gui_background_update_sig = wmu.change_background_sig while not ev._scheduler: time.sleep(1) comps.motion_detection_sensor._motion_detected = 1 time.sleep(8) comps.motion_detection_sensor._motion_detected = 0 time.sleep(10) time.sleep(10) time.sleep(10) time.sleep(10)
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()
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)
def main(settings_path: Optional[Path] = None): """ Main function, calling setup, loading components and safe shutdown. :param settings_path: Only used for testing to load a settings file. """ # Create user config dir if not config.user_config_dir.exists(): os.makedirs(config.user_config_dir) # System is first, is_target_system is the most basic check runtime_system = RuntimeSystem() if not runtime_system.is_target_system: setup_on_non_target_system() # All other classes depend on settings if not settings_path: settings_path = config.user_config_dir settings = Settings(ini_folder=settings_path) handle_cmd_args(settings) # cmd args set Debug level for logger # to be able to remote debug as much as possible, this call is being done early start_remote_debug() Logger( output_path=config.user_config_dir) # singleton, no assigment needed comp_ctrl = ComponentController(settings) config.comp_ctrl = comp_ctrl #if config.DEBUG_LEVEL > 0: # disable startup sound # comp_ctrl.components.tts.say_internal("startup", [WAQD_VERSION]) display_type = settings.get(DISPLAY_TYPE) if display_type in [DISP_TYPE_RPI, DISP_TYPE_WAVESHARE_5_LCD]: config.qt_app = qt_app_setup(settings) # main_ui must be held in this context, otherwise the gc will destroy the gui loading_sequence(comp_ctrl, settings) try: config.qt_app.exec_() except: # pylint:disable=bare-except trace_back = traceback.format_exc() Logger().error("Application crashed: \n%s", trace_back) elif display_type == DISP_TYPE_WAVESHARE_EPAPER_2_9: pass elif display_type == DISP_TYPE_HEADLESS: comp_ctrl.init_all() comp_ctrl._stop_event.wait() # unload modules - wait for every thread to quit if runtime_system.is_target_system: Logger().info("Prepare to exit...") if comp_ctrl: comp_ctrl.unload_all() while not comp_ctrl.all_unloaded: time.sleep(.1)
def testParser(base_fixture, target_mockup_fixture): settings = Settings(base_fixture.testdata_path / "integration") settings.set(SOUND_ENABLED, True) events = parse_event_file(base_fixture.testdata_path / "events" / "events.json") assert events assert events[0].name == "Daily Greeting" assert events[1].name == "Wakeup" temp_file = tempfile.gettempdir() + "/eventsTest.json" write_events_file(temp_file, events) with open(temp_file) as fp: events_read = json.load(fp) assert events_read.get("events")[0].get("name") == "Daily Greeting" assert events_read.get("events")[1].get("name") == "Wakeup"
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
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 __init__(self, settings: Settings): log_values = bool(settings.get(LOG_SENSOR_DATA)) CO2Sensor.__init__(self, log_values) CyclicComponent.__init__(self) self._start_time = datetime.datetime.now() self._readings_stabilized = False self._start_update_loop(self._init_sensor, self._read_sensor)
def testOptions(base_fixture, qtbot, mocker): # target_mockup_fixture """ Test the option gui. """ mock_run_on_target(mocker) settings = Settings(base_fixture.testdata_path / "integration") comp_ctrl = ComponentController(settings) wmu = WeatherMainUi(comp_ctrl, settings) from pytestqt.plugin import _qapp_instance config.qt_app = _qapp_instance # OptionMainUi start a new root obj execution widget = OptionMainUi(wmu, comp_ctrl, settings) qtbot.addWidget(widget) widget.show() qtbot.waitExposed(widget) # For debug: # while True: # _qapp_instance.processEvents() assert widget.isEnabled() qtbot.mouseClick(widget._ui.ok_button, QtCore.Qt.LeftButton) assert widget.isHidden() # TODO add r/w asserts # unload the now started main ui wmu.unload_gui() comp_ctrl.unload_all() while not comp_ctrl.all_unloaded: time.sleep(.1) time.sleep(3) assert comp_ctrl.all_unloaded
def __init__(self, settings: Settings): log_values = bool(settings.get(LOG_SENSOR_DATA)) DustSensor.__init__(self, settings) CyclicComponent.__init__(self, None, settings) self._sensor_driver = None self._start_update_loop(self._init_sensor, self._read_sensor)
def __init__(self, components: ComponentRegistry, settings: Settings): log_values = bool(settings.get(LOG_SENSOR_DATA)) TempSensor.__init__(self, log_values) BarometricSensor.__init__(self, log_values) CyclicComponent.__init__(self, components, settings) self._sensor_driver = None self._start_update_loop(self._init_sensor, self._read_sensor)
def __init__(self, settings: Settings): MEASURE_POINTS = 2 log_values = bool(settings.get(LOG_SENSOR_DATA)) LightSensor.__init__(self, log_values, MEASURE_POINTS) CyclicComponent.__init__(self) self._sensor_driver = None self._start_update_loop(self._init_sensor, self._read_sensor)
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 set_ui_language(qt_app: QtWidgets.QApplication, settings: Settings): """ Set the ui language. Retranslate must be called afterwards.""" if config.translator: qt_app.removeTranslator(config.translator) if settings.get(LANG) == LANG_ENGLISH: # default case, ui is written in english return if not config.translator: config.translator = QtCore.QTranslator(qt_app) tr_file = Path("NULL") if settings.get(LANG) == LANG_GERMAN: tr_file = config.base_path / "ui/qt/german.qm" if settings.get(LANG) == LANG_HUNGARIAN: tr_file = config.base_path / "ui/qt/hungarian.qm" if not tr_file.exists(): logger.error("Cannot find %s translation file.", str(tr_file)) config.translator.load(str(tr_file)) qt_app.installTranslator(config.translator)
def __init__(self, components: ComponentRegistry, settings: Settings): MEASURE_POINTS = 3 log_values = bool(settings.get(LOG_SENSOR_DATA)) CO2Sensor.__init__(self, log_values, MEASURE_POINTS) TvocSensor.__init__(self, log_values, MEASURE_POINTS) CyclicComponent.__init__(self, components) self._start_time = datetime.datetime.now() self._reload_forbidden = True self._sensor_driver: "CCS811" = None self._error_num = 0 self._start_update_loop(self._init_sensor, self._read_sensor)
def get_localized_date(date_time: datetime.datetime, settings: Settings) -> str: """ Returns a formatted date of a day conforming to the actual locale. Contains weekday name, month and day. """ # switch locale to selected language - needs reboot on linux if settings.get(LANG) != LANG_ENGLISH: locale_name = "" try: if platform.system() == "Windows": if settings.get(LANG) == LANG_GERMAN: locale_name = "de_DE" elif settings.get(LANG) == LANG_HUNGARIAN: locale_name = "hu-HU" elif platform.system() == "Linux": if settings.get(LANG) == LANG_GERMAN: locale_name = "de_DE.UTF8" elif settings.get(LANG) == LANG_HUNGARIAN: locale_name = "hu_HU.UTF8" locale.setlocale(locale.LC_ALL, locale_name) except Exception as error: logger.error("Cannot set language to %s: %s", settings.get(LANG), str(error)) # "sudo apt-get install language-pack-id" is needed... # or sudo locale-gen else: locale.setlocale(locale.LC_ALL, 'C') local_date = time.strftime("%a, %x", date_time.timetuple()) # remove year - twice once with following . and once for none local_date = local_date.replace(str(date_time.year) + ".", "") local_date = local_date.replace(str(date_time.year), "") return local_date
def __init__(self, pin: int, components: ComponentRegistry, settings: Settings): log_values = bool(settings.get(LOG_SENSOR_DATA)) TempSensor.__init__(self, log_values) HumiditySensor.__init__(self, log_values) CyclicComponent.__init__(self, components, log_values) self._pin = pin if not self._pin: self._logger.error("DHT22: No pin, disabled") self._disabled = True return self._sensor_driver = None self._error_num = 0 self._start_update_loop(self._init_sensor, self._read_sensor)
def __init__(self, components: ComponentRegistry, settings: Settings): super().__init__(components, settings) if not settings.get(EVENTS_ENABLED): return self.gui_background_update_sig: Optional[pyqtBoundSignal] = None self._config_events_file = config.user_config_dir / "events.json" self._events = parse_event_file(self._config_events_file) self._scheduler: Optional[BackgroundScheduler] = None self._init_thread = threading.Thread(name="StartScheduler", target=self._init_scheduler, daemon=True) self._init_thread.start()
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
def testMH_Z19(base_fixture, target_mockup_fixture, mocker): mock_run_on_non_target(mocker) assert not RuntimeSystem().is_target_system settings = Settings(base_fixture.testdata_path / "integration") sensor = sensors.MH_Z19(settings) measure_points = 2 sensor._co2_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 # -> takes too long, every call spawns a new python process tgis takes a few seconds time.sleep(sensor.UPDATE_TIME + (measure_points + 1)) from mh_z19 import CO2 assert sensor.get_co2() == CO2
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
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
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
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
def testWeatherDetailView(base_fixture, qtbot): parent = QtWidgets.QMainWindow() parent.resize(800, 480) # initalize settings settings = Settings(base_fixture.testdata_path / "integration") weather = OpenWeatherMap("city_id", "abcd") # inputs do not matter weather._fc_json_file = str(base_fixture.testdata_path / "online_weather/ow_forecast.json") weather._cw_json_file = str(base_fixture.testdata_path / "online_weather/ow_current_weather.json") # get a date matching with the test data #current_date_time = datetime.datetime(2019, 7, 21, 15) with freeze_time("2019-07-21 20:00:00"): forecast = weather.get_5_day_forecast() [daytime_forecast_points, nighttime_forecast_points] = weather.get_forecast_points() widget = WeatherDetailView(daytime_forecast_points[0], settings, parent) qtbot.addWidget(widget) widget.show() qtbot.waitExposed(widget) # while True: # QtWidgets.QApplication.processEvents() assert widget.isVisible() series = widget._chart.series() assert len(series) == 3 # can't test the point directly, because it depends on the timezone assert len(series[0].pointsVector()) == 5 point = series[0].pointsVector()[0] assert point.y() == 23.32 assert series[0].pointLabelsVisible
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()
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")
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()
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()