async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, str]: """Validate the user input allows us to connect. Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. """ bridge = Bridge( BridgeClient(aiohttp_client.async_get_clientsession(hass)), f"http://{data[CONF_HOST]}:{data[CONF_PORT]}", data[CONF_API_KEY], ) hostname = data[CONF_HOST] try: async with async_timeout.timeout(30): bridge_os: Os = await bridge.async_get_os() if bridge_os.hostname is not None: hostname = bridge_os.hostname bridge_system: System = await bridge.async_get_system() except BridgeAuthenticationException as exception: _LOGGER.info(exception) raise InvalidAuth from exception except BRIDGE_CONNECTION_ERRORS as exception: _LOGGER.info(exception) raise CannotConnect from exception return {"hostname": hostname, "uuid": bridge_system.uuid.os}
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up System Bridge from a config entry.""" bridge = Bridge( BridgeClient(aiohttp_client.async_get_clientsession(hass)), f"http://{entry.data[CONF_HOST]}:{entry.data[CONF_PORT]}", entry.data[CONF_API_KEY], ) try: async with async_timeout.timeout(30): await bridge.async_get_information() except BridgeAuthenticationException as exception: raise ConfigEntryAuthFailed( f"Authentication failed for {entry.title} ({entry.data[CONF_HOST]})" ) from exception except BRIDGE_CONNECTION_ERRORS as exception: raise ConfigEntryNotReady( f"Could not connect to {entry.title} ({entry.data[CONF_HOST]})." ) from exception coordinator = SystemBridgeDataUpdateCoordinator(hass, bridge, _LOGGER, entry=entry) await coordinator.async_config_entry_first_refresh() # Wait for initial data try: async with async_timeout.timeout(60): while ( coordinator.bridge.battery is None or coordinator.bridge.cpu is None or coordinator.bridge.filesystem is None or coordinator.bridge.graphics is None or coordinator.bridge.information is None or coordinator.bridge.memory is None or coordinator.bridge.network is None or coordinator.bridge.os is None or coordinator.bridge.processes is None or coordinator.bridge.system is None ): _LOGGER.debug( "Waiting for initial data from %s (%s)", entry.title, entry.data[CONF_HOST], ) await asyncio.sleep(1) except asyncio.TimeoutError as exception: raise ConfigEntryNotReady( f"Timed out waiting for {entry.title} ({entry.data[CONF_HOST]})." ) from exception hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator hass.config_entries.async_setup_platforms(entry, PLATFORMS) if hass.services.has_service(DOMAIN, SERVICE_SEND_COMMAND): return True async def handle_send_command(call): """Handle the send_command service call.""" device_registry = dr.async_get(hass) device_id = call.data[CONF_BRIDGE] device_entry = device_registry.async_get(device_id) if device_entry is None: _LOGGER.warning("Missing device: %s", device_id) return command = call.data[CONF_COMMAND] arguments = shlex.split(call.data.get(CONF_ARGUMENTS, "")) entry_id = next( entry.entry_id for entry in hass.config_entries.async_entries(DOMAIN) if entry.entry_id in device_entry.config_entries ) coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][entry_id] bridge: Bridge = coordinator.bridge _LOGGER.debug( "Command payload: %s", {CONF_COMMAND: command, CONF_ARGUMENTS: arguments, CONF_WAIT: False}, ) try: response: CommandResponse = await bridge.async_send_command( {CONF_COMMAND: command, CONF_ARGUMENTS: arguments, CONF_WAIT: False} ) if response.success: _LOGGER.debug( "Sent command. Response message was: %s", response.message ) else: _LOGGER.warning( "Error sending command. Response message was: %s", response.message ) except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: _LOGGER.warning("Error sending command. Error was: %s", exception) async def handle_open(call): """Handle the open service call.""" device_registry = dr.async_get(hass) device_id = call.data[CONF_BRIDGE] device_entry = device_registry.async_get(device_id) if device_entry is None: _LOGGER.warning("Missing device: %s", device_id) return path = call.data[CONF_PATH] entry_id = next( entry.entry_id for entry in hass.config_entries.async_entries(DOMAIN) if entry.entry_id in device_entry.config_entries ) coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][entry_id] bridge: Bridge = coordinator.bridge _LOGGER.debug("Open payload: %s", {CONF_PATH: path}) try: await bridge.async_open({CONF_PATH: path}) _LOGGER.debug("Sent open request") except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: _LOGGER.warning("Error sending. Error was: %s", exception) hass.services.async_register( DOMAIN, SERVICE_SEND_COMMAND, handle_send_command, schema=SERVICE_SEND_COMMAND_SCHEMA, ) hass.services.async_register( DOMAIN, SERVICE_OPEN, handle_open, schema=SERVICE_OPEN_SCHEMA, ) # Reload entry when its updated. entry.async_on_unload(entry.add_update_listener(async_reload_entry)) return True
async def main() -> None: async with ClientSession() as session: client = Bridge( BridgeClient(session), f"http://{HOST}:{PORT}", API_KEY, ) async def handle_event(event: Event): print("Unused Event:", event.__dict__) await client.async_connect_websocket(HOST, (await client.async_get_setting( "network", "wsPort")).value) await client.async_send_event("test", "text") asyncio.ensure_future(client.listen_for_events(handle_event)) async with async_timeout.timeout(60): await asyncio.gather(*[ client.async_get_audio(), client.async_get_battery(), client.async_get_bluetooth(), client.async_get_cpu(), client.async_get_display(), client.async_get_filesystem(), client.async_get_graphics(), client.async_get_memory(), client.async_get_network(), client.async_get_os(), client.async_get_processes(), client.async_get_settings(), client.async_get_system(), ]) print() print("Results") print() print(client.audio) # print(client.audio.__dict__) # print() print(client.bluetooth) # print(client.bluetooth.__dict__) # print() print(client.battery) # print(client.battery.__dict__) # print() print(client.cpu) # print(client.cpu.__dict__) # print() print(client.display) # print(client.display.__dict__) # print() print(client.filesystem) # print(client.filesystem.__dict__) # print() print(client.graphics) # print(client.graphics.__dict__) # print() print(client.memory) # print(client.memory.__dict__) # print() print(client.network) # print(client.network.__dict__) # print() print(client.os) # print(client.os.__dict__) # print() print(client.processes) # print(client.processes.__dict__) # print() print(client.settings) # for setting in client.settings: # print(setting.__dict__) # print(setting.key) # print(setting.name) # print(setting.value) # print() print(client.system) # print(client.system.__dict__) while True: await asyncio.sleep(1)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up System Bridge from a config entry.""" bridge = Bridge( BridgeClient(aiohttp_client.async_get_clientsession(hass)), f"http://{entry.data[CONF_HOST]}:{entry.data[CONF_PORT]}", entry.data[CONF_API_KEY], ) try: async with async_timeout.timeout(30): await bridge.async_get_information() except BridgeAuthenticationException as exception: raise ConfigEntryAuthFailed( f"Authentication failed for {entry.title} ({entry.data[CONF_HOST]})" ) from exception except BRIDGE_CONNECTION_ERRORS as exception: raise ConfigEntryNotReady( f"Could not connect to {entry.title} ({entry.data[CONF_HOST]})." ) from exception coordinator = SystemBridgeDataUpdateCoordinator(hass, bridge, _LOGGER, entry=entry) await coordinator.async_config_entry_first_refresh() # Wait for initial data try: async with async_timeout.timeout(60): while (coordinator.bridge.battery is None or coordinator.bridge.cpu is None or coordinator.bridge.display is None or coordinator.bridge.filesystem is None or coordinator.bridge.graphics is None or coordinator.bridge.information is None or coordinator.bridge.memory is None or coordinator.bridge.network is None or coordinator.bridge.os is None or coordinator.bridge.processes is None or coordinator.bridge.system is None): _LOGGER.debug( "Waiting for initial data from %s (%s)", entry.title, entry.data[CONF_HOST], ) await asyncio.sleep(1) except asyncio.TimeoutError as exception: raise ConfigEntryNotReady( f"Timed out waiting for {entry.title} ({entry.data[CONF_HOST]})." ) from exception hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator hass.config_entries.async_setup_platforms(entry, PLATFORMS) if hass.services.has_service(DOMAIN, SERVICE_SEND_COMMAND): return True def valid_device(device: str): """Check device is valid.""" device_registry = dr.async_get(hass) device_entry = device_registry.async_get(device) if device_entry is not None: try: return next( entry.entry_id for entry in hass.config_entries.async_entries(DOMAIN) if entry.entry_id in device_entry.config_entries) except StopIteration as exception: raise vol.Invalid from exception raise vol.Invalid(f"Device {device} does not exist") async def handle_send_command(call): """Handle the send_command service call.""" coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][ call.data[CONF_BRIDGE]] bridge: Bridge = coordinator.bridge command = call.data[CONF_COMMAND] arguments = shlex.split(call.data[CONF_ARGUMENTS]) _LOGGER.debug( "Command payload: %s", { CONF_COMMAND: command, CONF_ARGUMENTS: arguments, CONF_WAIT: False }, ) try: response: CommandResponse = await bridge.async_send_command({ CONF_COMMAND: command, CONF_ARGUMENTS: arguments, CONF_WAIT: False }) if not response.success: raise HomeAssistantError( f"Error sending command. Response message was: {response.message}" ) except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: raise HomeAssistantError("Error sending command") from exception _LOGGER.debug("Sent command. Response message was: %s", response.message) async def handle_open(call): """Handle the open service call.""" coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][ call.data[CONF_BRIDGE]] bridge: Bridge = coordinator.bridge path = call.data[CONF_PATH] _LOGGER.debug("Open payload: %s", {CONF_PATH: path}) try: await bridge.async_open({CONF_PATH: path}) except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: raise HomeAssistantError("Error sending") from exception _LOGGER.debug("Sent open request") async def handle_send_keypress(call): """Handle the send_keypress service call.""" coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][ call.data[CONF_BRIDGE]] bridge: Bridge = coordinator.data keyboard_payload: KeyboardPayload = { CONF_KEY: call.data[CONF_KEY], CONF_MODIFIERS: shlex.split(call.data.get(CONF_MODIFIERS, "")), } _LOGGER.debug("Keypress payload: %s", keyboard_payload) try: await bridge.async_send_keypress(keyboard_payload) except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: raise HomeAssistantError("Error sending") from exception _LOGGER.debug("Sent keypress request") async def handle_send_text(call): """Handle the send_keypress service call.""" coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][ call.data[CONF_BRIDGE]] bridge: Bridge = coordinator.data keyboard_payload: KeyboardPayload = {CONF_TEXT: call.data[CONF_TEXT]} _LOGGER.debug("Text payload: %s", keyboard_payload) try: await bridge.async_send_keypress(keyboard_payload) except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: raise HomeAssistantError("Error sending") from exception _LOGGER.debug("Sent text request") hass.services.async_register( DOMAIN, SERVICE_SEND_COMMAND, handle_send_command, schema=vol.Schema( { vol.Required(CONF_BRIDGE): valid_device, vol.Required(CONF_COMMAND): cv.string, vol.Optional(CONF_ARGUMENTS, ""): cv.string, }, ), ) hass.services.async_register( DOMAIN, SERVICE_OPEN, handle_open, schema=vol.Schema( { vol.Required(CONF_BRIDGE): valid_device, vol.Required(CONF_PATH): cv.string, }, ), ) hass.services.async_register( DOMAIN, SERVICE_SEND_KEYPRESS, handle_send_keypress, schema=vol.Schema( { vol.Required(CONF_BRIDGE): valid_device, vol.Required(CONF_KEY): cv.string, vol.Optional(CONF_MODIFIERS): cv.string, }, ), ) hass.services.async_register( DOMAIN, SERVICE_SEND_TEXT, handle_send_text, schema=vol.Schema( { vol.Required(CONF_BRIDGE): valid_device, vol.Required(CONF_TEXT): cv.string, }, ), ) # Reload entry when its updated. entry.async_on_unload(entry.add_update_listener(async_reload_entry)) return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up System Bridge from a config entry.""" client = Bridge( BridgeClient(aiohttp_client.async_get_clientsession(hass)), f"http://{entry.data[CONF_HOST]}:{entry.data[CONF_PORT]}", entry.data[CONF_API_KEY], ) async def async_update_data() -> Bridge: """Fetch data from Bridge.""" try: async with async_timeout.timeout(60): await asyncio.gather(*[ client.async_get_battery(), client.async_get_cpu(), client.async_get_filesystem(), client.async_get_memory(), client.async_get_network(), client.async_get_os(), client.async_get_processes(), client.async_get_system(), ]) return client except BridgeAuthenticationException as exception: raise ConfigEntryAuthFailed from exception except BRIDGE_CONNECTION_ERRORS as exception: raise UpdateFailed( "Could not connect to System Bridge.") from exception coordinator = DataUpdateCoordinator( hass, _LOGGER, # Name of the data. For logging purposes. name=f"{DOMAIN}_coordinator", update_method=async_update_data, # Polling interval. Will only be polled if there are subscribers. update_interval=timedelta(seconds=60), ) hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator # Fetch initial data so we have data when entities subscribe await coordinator.async_config_entry_first_refresh() hass.config_entries.async_setup_platforms(entry, PLATFORMS) if hass.services.has_service(DOMAIN, SERVICE_SEND_COMMAND): return True async def handle_send_command(call): """Handle the send_command service call.""" device_registry = dr.async_get(hass) device_id = call.data[CONF_BRIDGE] device_entry = device_registry.async_get(device_id) if device_entry is None: _LOGGER.warning("Missing device: %s", device_id) return command = call.data[CONF_COMMAND] arguments = shlex.split(call.data.get(CONF_ARGUMENTS, "")) entry_id = next(entry.entry_id for entry in hass.config_entries.async_entries(DOMAIN) if entry.entry_id in device_entry.config_entries) coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry_id] bridge: Bridge = coordinator.data _LOGGER.debug( "Command payload: %s", { CONF_COMMAND: command, CONF_ARGUMENTS: arguments, CONF_WAIT: False }, ) try: response: CommandResponse = await bridge.async_send_command({ CONF_COMMAND: command, CONF_ARGUMENTS: arguments, CONF_WAIT: False }) if response.success: _LOGGER.debug("Sent command. Response message was: %s", response.message) else: _LOGGER.warning( "Error sending command. Response message was: %s", response.message) except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: _LOGGER.warning("Error sending command. Error was: %s", exception) async def handle_open(call): """Handle the open service call.""" device_registry = dr.async_get(hass) device_id = call.data[CONF_BRIDGE] device_entry = device_registry.async_get(device_id) if device_entry is None: _LOGGER.warning("Missing device: %s", device_id) return path = call.data[CONF_PATH] entry_id = next(entry.entry_id for entry in hass.config_entries.async_entries(DOMAIN) if entry.entry_id in device_entry.config_entries) coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry_id] bridge: Bridge = coordinator.data _LOGGER.debug("Open payload: %s", {CONF_PATH: path}) try: await bridge.async_open({CONF_PATH: path}) _LOGGER.debug("Sent open request") except (BridgeAuthenticationException, *BRIDGE_CONNECTION_ERRORS) as exception: _LOGGER.warning("Error sending. Error was: %s", exception) hass.services.async_register( DOMAIN, SERVICE_SEND_COMMAND, handle_send_command, schema=SERVICE_SEND_COMMAND_SCHEMA, ) hass.services.async_register( DOMAIN, SERVICE_OPEN, handle_open, schema=SERVICE_OPEN_SCHEMA, ) return True