async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up config entry.""" session = aiohttp_client.async_get_clientsession(hass) hass.data.setdefault(DOMAIN, {}) printer = SyncThru(entry.data[CONF_URL], session, connection_mode=ConnectionMode.API) async def async_update_data() -> SyncThru: """Fetch data from the printer.""" try: async with async_timeout.timeout(10): await printer.update() except SyncThruAPINotSupported as api_error: # if an exception is thrown, printer does not support syncthru _LOGGER.info( "Configured printer at %s does not provide SyncThru JSON API", printer.url, exc_info=api_error, ) raise api_error else: # if the printer is offline, we raise an UpdateFailed if printer.is_unknown_state(): raise UpdateFailed( f"Configured printer at {printer.url} does not respond.") return printer coordinator: DataUpdateCoordinator = DataUpdateCoordinator( hass, _LOGGER, name=DOMAIN, update_method=async_update_data, update_interval=timedelta(seconds=30), ) hass.data[DOMAIN][entry.entry_id] = coordinator await coordinator.async_config_entry_first_refresh() if isinstance(coordinator.last_exception, SyncThruAPINotSupported): # this means that the printer does not support the syncthru JSON API # and the config should simply be discarded return False device_registry = dr.async_get(hass) device_registry.async_get_or_create( config_entry_id=entry.entry_id, configuration_url=printer.url, connections=device_connections(printer), identifiers=device_identifiers(printer), model=printer.model(), name=printer.hostname(), ) hass.config_entries.async_setup_platforms(entry, PLATFORMS) return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up config entry.""" session = aiohttp_client.async_get_clientsession(hass) hass.data.setdefault(DOMAIN, {}) printer = SyncThru(entry.data[CONF_URL], session) async def async_update_data() -> SyncThru: """Fetch data from the printer.""" try: async with async_timeout.timeout(10): await printer.update() except ValueError as value_error: # if an exception is thrown, printer does not support syncthru raise UpdateFailed( f"Configured printer at {printer.url} does not respond. " "Please make sure it supports SyncThru and check your configuration." ) from value_error else: if printer.is_unknown_state(): raise ConfigEntryNotReady return printer coordinator: DataUpdateCoordinator = DataUpdateCoordinator( hass, _LOGGER, name=DOMAIN, update_method=async_update_data, update_interval=timedelta(seconds=30), ) hass.data[DOMAIN][entry.entry_id] = coordinator await coordinator.async_config_entry_first_refresh() device_registry = await dr.async_get_registry(hass) device_registry.async_get_or_create( config_entry_id=entry.entry_id, connections=device_connections(printer), identifiers=device_identifiers(printer), model=printer.model(), name=printer.hostname(), ) hass.config_entries.async_setup_platforms(entry, PLATFORMS) return True
class SyncthruHTMLTest(unittest.TestCase): server = None server_control = None # type: Server port = 0 url = "http://localhost:80" syncthru = None # type: SyncThru def setUp(self) -> None: # Create an arbitrary subclass of TCP Server as the server to be started # Here, it is an Simple HTTP file serving server handler = SyncThruRequestHandler max_retries = 10 r = 0 while not self.server: try: # Connect to any open port self.server = SyncThruServer((ADDRESS, 0), handler) except OSError: if r < max_retries: r += 1 else: raise time.sleep(1) self.server_control = Server(self.server) self.port = self.server_control.get_port() self.url = "{}:{}".format(ADDRESS, self.port) # Start test server before running any tests self.server_control.start_server() async def fetch(): async with aiohttp.ClientSession() as session: self.syncthru = SyncThru( self.url, session, connection_mode=ConnectionMode.HTML ) await self.syncthru.update() loop = asyncio.get_event_loop() loop.run_until_complete(fetch()) def test_location(self) -> None: self.assertEqual(self.syncthru.location(), RAW_HTML["identity"]["location"]) def test_model_name(self) -> None: self.assertEqual(self.syncthru.model(), RAW_HTML["identity"]["model_name"]) def test_hostname(self) -> None: self.assertEqual(self.syncthru.hostname(), RAW_HTML["identity"]["host_name"]) def test_mac_address(self) -> None: self.assertEqual(self.syncthru.mac_address(), RAW_HTML["identity"]["mac_addr"]) def test_toner_filter(self) -> None: self.assertDictEqual( self.syncthru.toner_status(True), {"black": {"opt": 1, "remaining": 66, "newError": ""}}, ) def test_input_tray_filter(self) -> None: self.assertDictEqual( self.syncthru.input_tray_status(True), { "tray_1": { "opt": 1, "newError": "", } }, )
class SyncthruAPITest(unittest.TestCase): server = None server_control = None # type: Server port = 0 url = "http://localhost:80" syncthru = None # type: SyncThru def setUp(self) -> None: # Create an arbitrary subclass of TCP Server as the server to be started # Here, it is an Simple HTTP file serving server handler = SyncThruRequestHandler max_retries = 10 r = 0 while not self.server: try: # Connect to any open port self.server = SyncThruServer((ADDRESS, 0), handler) except OSError: if r < max_retries: r += 1 else: raise time.sleep(1) self.server_control = Server(self.server) self.port = self.server_control.get_port() self.url = "{}:{}".format(ADDRESS, self.port) # Start test server before running any tests self.server_control.start_server() async def fetch(): async with aiohttp.ClientSession() as session: self.syncthru = SyncThru( self.url, session, connection_mode=ConnectionMode.API ) await self.syncthru.update() loop = asyncio.get_event_loop() loop.run_until_complete(fetch()) def test_online(self) -> None: self.assertTrue(self.syncthru.is_online()) def test_status_normal(self) -> None: self.assertEqual(self.syncthru.device_status(), SyncthruState.NORMAL) def test_status_details(self) -> None: self.assertEqual(self.syncthru.device_status_details(), "Sleeping...") def test_model(self) -> None: self.assertEqual(self.syncthru.model(), RAW["identity"]["model_name"]) def test_toner_filter(self) -> None: self.assertDictEqual( self.syncthru.toner_status(True), {"black": {"opt": 1, "remaining": 58, "cnt": 229, "newError": ""}}, ) def test_toner_no_filter(self) -> None: empty = {"opt": 0, "remaining": 0, "cnt": 0, "newError": ""} self.assertDictEqual( self.syncthru.toner_status(False), { "yellow": empty, "magenta": empty, "cyan": empty, "black": {"opt": 1, "remaining": 58, "cnt": 229, "newError": ""}, }, ) def test_input_tray_filter(self) -> None: self.assertDictEqual( self.syncthru.input_tray_status(True), { "tray_1": { "capa": 150, "newError": "", "opt": 1, "paper_size1": 4, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, } }, ) def test_input_tray_no_filter(self) -> None: self.assertDictEqual( self.syncthru.input_tray_status(False), { "tray_1": { "capa": 150, "newError": "", "opt": 1, "paper_size1": 4, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, }, "tray_2": { "capa": 0, "newError": "", "opt": 0, "paper_size1": 0, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, }, "tray_3": { "capa": 0, "newError": "", "opt": 0, "paper_size1": 0, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, }, "tray_4": { "capa": 0, "newError": "", "opt": 2, "paper_size1": 0, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, }, "tray_5": { "opt": 0, "paper_size1": 0, "paper_size2": 0, "paper_type1": 0, "paper_type2": 0, "capa": 0, "newError": "0", }, "mp": { "opt": 0, "paper_size1": 0, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, "capa": 0, "newError": "", }, "manual": { "opt": 0, "paper_size1": 0, "paper_size2": 0, "paper_type1": 2, "paper_type2": 0, "capa": 0, "newError": "", }, }, ) def test_output_tray(self) -> None: self.assertEqual( self.syncthru.output_tray_status(), {0: {"capacity": 100, "name": 1, "status": ""}}, ) def test_drum_status_filter(self) -> None: self.assertEqual(self.syncthru.drum_status(True), {}) def test_drum_status_no_filter(self) -> None: self.assertEqual( self.syncthru.drum_status(False), { "black": {"newError": "", "opt": 0, "remaining": 0}, "cyan": {"newError": "", "opt": 0, "remaining": 100}, "magenta": {"newError": "", "opt": 0, "remaining": 100}, "yellow": {"newError": "", "opt": 0, "remaining": 100}, }, ) def test_location(self) -> None: self.assertEqual(self.syncthru.location(), RAW["identity"]["location"]) def test_serial_number(self) -> None: self.assertEqual(self.syncthru.serial_number(), RAW["identity"]["serial_num"]) def test_hostname(self) -> None: self.assertEqual(self.syncthru.hostname(), RAW["identity"]["host_name"]) def test_cap(self) -> None: self.assertEqual(self.syncthru.capability(), RAW["capability"]) def tearDown(self) -> None: self.server_control.stop_server()