async def async_setup_entry( hass: core.HomeAssistant, entry: config_entries.ConfigEntry ): """Set up the xiaomi aqara components from a config entry.""" hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN].setdefault(GATEWAYS_KEY, {}) # Connect to Xiaomi Aqara Gateway xiaomi_gateway = await hass.async_add_executor_job( XiaomiGateway, entry.data[CONF_HOST], entry.data[CONF_SID], entry.data[CONF_KEY], DEFAULT_DISCOVERY_RETRY, entry.data[CONF_INTERFACE], entry.data[CONF_PORT], entry.data[CONF_PROTOCOL], ) hass.data[DOMAIN][GATEWAYS_KEY][entry.entry_id] = xiaomi_gateway gateway_discovery = hass.data[DOMAIN].setdefault( LISTENER_KEY, XiaomiGatewayDiscovery(hass.add_job, [], entry.data[CONF_INTERFACE]), ) if len(hass.data[DOMAIN][GATEWAYS_KEY]) == 1: # start listining for local pushes (only once) await hass.async_add_executor_job(gateway_discovery.listen) # register stop callback to shutdown listining for local pushes def stop_xiaomi(event): """Stop Xiaomi Socket.""" _LOGGER.debug("Shutting down Xiaomi Gateway Listener") gateway_discovery.stop_listen() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop_xiaomi) gateway_discovery.gateways[entry.data[CONF_HOST]] = xiaomi_gateway _LOGGER.debug( "Gateway with host '%s' connected, listening for broadcasts", entry.data[CONF_HOST], ) device_registry = dr.async_get(hass) device_registry.async_get_or_create( config_entry_id=entry.entry_id, identifiers={(DOMAIN, entry.unique_id)}, manufacturer="Xiaomi Aqara", name=entry.title, sw_version=entry.data[CONF_PROTOCOL], ) if entry.data[CONF_KEY] is not None: platforms = GATEWAY_PLATFORMS else: platforms = GATEWAY_PLATFORMS_NO_KEY hass.config_entries.async_setup_platforms(entry, platforms) return True
async def async_step_user(self, user_input=None): """Handle a flow initialized by the user.""" errors = {} if user_input is None: return self.async_show_form_step_user(errors) self.interface = user_input[CONF_INTERFACE] # allow optional manual setting of host and mac if self.host is None: self.host = user_input.get(CONF_HOST) if self.sid is None: mac_address = user_input.get(CONF_MAC) # format sid from mac_address if mac_address is not None: self.sid = format_mac(mac_address).replace(":", "") # if host is already known by zeroconf discovery or manual optional settings if self.host is not None and self.sid is not None: # Connect to Xiaomi Aqara Gateway self.selected_gateway = await self.hass.async_add_executor_job( XiaomiGateway, self.host, self.sid, None, DEFAULT_DISCOVERY_RETRY, self.interface, MULTICAST_PORT, None, ) if self.selected_gateway.connection_error: errors[CONF_HOST] = "invalid_host" if self.selected_gateway.mac_error: errors[CONF_MAC] = "invalid_mac" if errors: return self.async_show_form_step_user(errors) return await self.async_step_settings() # Discover Xiaomi Aqara Gateways in the netwerk to get required SIDs. xiaomi = XiaomiGatewayDiscovery(self.hass.add_job, [], self.interface) try: await self.hass.async_add_executor_job(xiaomi.discover_gateways) except gaierror: errors[CONF_INTERFACE] = "invalid_interface" return self.async_show_form_step_user(errors) self.gateways = xiaomi.gateways if len(self.gateways) == 1: self.selected_gateway = list(self.gateways.values())[0] self.sid = self.selected_gateway.sid return await self.async_step_settings() if len(self.gateways) > 1: return await self.async_step_select() errors["base"] = "discovery_error" return self.async_show_form_step_user(errors)
async def async_step_user(self, user_input=None): """Handle a flow initialized by the user.""" errors = {} if user_input is not None: self.interface = user_input[CONF_INTERFACE] # Discover Xiaomi Aqara Gateways in the netwerk to get required SIDs. xiaomi = XiaomiGatewayDiscovery(self.hass.add_job, [], self.interface) try: await self.hass.async_add_executor_job(xiaomi.discover_gateways ) except gaierror: errors[CONF_INTERFACE] = "invalid_interface" if not errors: self.gateways = xiaomi.gateways # if host is already known by zeroconf discovery if self.host is not None: self.selected_gateway = self.gateways.get(self.host) if self.selected_gateway is not None: return await self.async_step_settings() errors["base"] = "not_found_error" else: if len(self.gateways) == 1: self.selected_gateway = list(self.gateways.values())[0] return await self.async_step_settings() if len(self.gateways) > 1: return await self.async_step_select() errors["base"] = "discovery_error" return self.async_show_form(step_id="user", data_schema=GATEWAY_CONFIG, errors=errors)
def setup(hass, config): """Set up the Xiaomi component.""" gateways = [] interface = 'any' discovery_retry = 3 if DOMAIN in config: gateways = config[DOMAIN][CONF_GATEWAYS] interface = config[DOMAIN][CONF_INTERFACE] discovery_retry = config[DOMAIN][CONF_DISCOVERY_RETRY] @asyncio.coroutine def xiaomi_gw_discovered(service, discovery_info): """Perform action when Xiaomi Gateway device(s) has been found.""" # We don't need to do anything here, the purpose of Home Assistant's # discovery service is to just trigger loading of this # component, and then its own discovery process kicks in. discovery.listen(hass, SERVICE_XIAOMI_GW, xiaomi_gw_discovered) from xiaomi_gateway import XiaomiGatewayDiscovery xiaomi = hass.data[PY_XIAOMI_GATEWAY] = XiaomiGatewayDiscovery( hass.add_job, gateways, interface) _LOGGER.debug("Expecting %s gateways", len(gateways)) for k in range(discovery_retry): _LOGGER.info("Discovering Xiaomi Gateways (Try %s)", k + 1) xiaomi.discover_gateways() if len(xiaomi.gateways) >= len(gateways): break if not xiaomi.gateways: _LOGGER.error("No gateway discovered") return False xiaomi.listen() _LOGGER.debug("Gateways discovered. Listening for broadcasts") for component in ['binary_sensor', 'sensor', 'switch', 'light', 'cover']: discovery.load_platform(hass, component, DOMAIN, {}, config) def stop_xiaomi(event): """Stop Xiaomi Socket.""" _LOGGER.info("Shutting down Xiaomi Hub") xiaomi.stop_listen() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_xiaomi) def play_ringtone_service(call): """Service to play ringtone through Gateway.""" ring_id = call.data.get(ATTR_RINGTONE_ID) gateway = call.data.get(ATTR_GW_MAC) kwargs = {'mid': ring_id} ring_vol = call.data.get(ATTR_RINGTONE_VOL) if ring_vol is not None: kwargs['vol'] = ring_vol gateway.write_to_hub(gateway.sid, **kwargs) def stop_ringtone_service(call): """Service to stop playing ringtone on Gateway.""" gateway = call.data.get(ATTR_GW_MAC) gateway.write_to_hub(gateway.sid, mid=10000) def add_device_service(call): """Service to add a new sub-device within the next 30 seconds.""" gateway = call.data.get(ATTR_GW_MAC) gateway.write_to_hub(gateway.sid, join_permission='yes') hass.components.persistent_notification.async_create( 'Join permission enabled for 30 seconds! ' 'Please press the pairing button of the new device once.', title='Xiaomi Aqara Gateway') def remove_device_service(call): """Service to remove a sub-device from the gateway.""" device_id = call.data.get(ATTR_DEVICE_ID) gateway = call.data.get(ATTR_GW_MAC) gateway.write_to_hub(gateway.sid, remove_device=device_id) gateway_only_schema = _add_gateway_to_schema(xiaomi, vol.Schema({})) hass.services.async_register(DOMAIN, SERVICE_PLAY_RINGTONE, play_ringtone_service, schema=_add_gateway_to_schema( xiaomi, SERVICE_SCHEMA_PLAY_RINGTONE)) hass.services.async_register(DOMAIN, SERVICE_STOP_RINGTONE, stop_ringtone_service, schema=gateway_only_schema) hass.services.async_register(DOMAIN, SERVICE_ADD_DEVICE, add_device_service, schema=gateway_only_schema) hass.services.async_register(DOMAIN, SERVICE_REMOVE_DEVICE, remove_device_service, schema=_add_gateway_to_schema( xiaomi, SERVICE_SCHEMA_REMOVE_DEVICE)) return True
class XiaomiAqaraFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a Xiaomi Aqara config flow.""" VERSION = 1 def __init__(self): """Initialize.""" self.host = None self.interface = DEFAULT_INTERFACE self.sid = None self.gateways = None self.selected_gateway = None @callback def async_show_form_step_user(self, errors): """Show the form belonging to the user step.""" schema = GATEWAY_CONFIG if (self.host is None and self.sid is None) or errors: schema = GATEWAY_CONFIG_HOST return self.async_show_form(step_id="user", data_schema=schema, errors=errors) async def async_step_user(self, user_input=None): """Handle a flow initialized by the user.""" errors = {} if user_input is None: return self.async_show_form_step_user(errors) self.interface = user_input[CONF_INTERFACE] # allow optional manual setting of host and mac if self.host is None: self.host = user_input.get(CONF_HOST) if self.sid is None: # format sid from mac_address if (mac_address := user_input.get(CONF_MAC)) is not None: self.sid = format_mac(mac_address).replace(":", "") # if host is already known by zeroconf discovery or manual optional settings if self.host is not None and self.sid is not None: # Connect to Xiaomi Aqara Gateway self.selected_gateway = await self.hass.async_add_executor_job( XiaomiGateway, self.host, self.sid, None, DEFAULT_DISCOVERY_RETRY, self.interface, MULTICAST_PORT, None, ) if self.selected_gateway.connection_error: errors[CONF_HOST] = "invalid_host" if self.selected_gateway.mac_error: errors[CONF_MAC] = "invalid_mac" if errors: return self.async_show_form_step_user(errors) return await self.async_step_settings() # Discover Xiaomi Aqara Gateways in the netwerk to get required SIDs. xiaomi = XiaomiGatewayDiscovery(self.hass.add_job, [], self.interface) try: await self.hass.async_add_executor_job(xiaomi.discover_gateways) except gaierror: errors[CONF_INTERFACE] = "invalid_interface" return self.async_show_form_step_user(errors) self.gateways = xiaomi.gateways if len(self.gateways) == 1: self.selected_gateway = list(self.gateways.values())[0] self.sid = self.selected_gateway.sid return await self.async_step_settings() if len(self.gateways) > 1: return await self.async_step_select() errors["base"] = "discovery_error" return self.async_show_form_step_user(errors)
def start_client(ip, gateways): config = [] [config.append({'key': g['key'], 'sid': g['sid']}) for g in gateways] client = XiaomiGatewayDiscovery(lambda: None, config, ip) clients.append(client) return client
sensor_id = report['sid'] data_report = json.loads(report['data']) # Update device data from given report for _, gateway in mihome.gateways.items(): if not sensor_id in gateway.sensors: print(f'UNKNOWN DEVICE sid = {sensor_id}') else: sensor = gateway.sensors[sensor_id] update_sensor_data(gateway, sensor, data_report, True) except Exception as inst: print(type(inst)) # the exception instance print(inst.args) # arguments stored in .args print(inst) # __str__ allows args to be printed directly, but may be overridden in exception subclasses mihome = XiaomiGatewayDiscovery(report_callback, gateways_config, 'any') mihome.discover_gateways() for host, gateway in mihome.gateways.items(): print(f'GATEWAY [{host}] - SENSOR DISCOVERED:') for sensor_id, sensor in gateway.sensors.items(): print(f'{sensor_id} - {sensor}') mihome.listen() while True: time.sleep(10) for host, gateway in mihome.gateways.items(): print(f'---GATEWAY [{host}]: token: {gateway.token}') for sensor_id, sensor in gateway.sensors.items(): cmd = '{"cmd":"read","sid":"' + sensor_id + '"}' resp = gateway._send_cmd(cmd, "read_ack") if int( gateway.proto[0:1]) == 1 else gateway._send_cmd(cmd, "read_rsp") if _validate_data(resp):
#! /usr/bin/env python #coding=utf-8 from xiaomi_gateway import (XiaomiGateway, XiaomiGatewayDiscovery) a1 = XiaomiGatewayDiscovery() print a1.discover_gateways() ''' ip = "" port = sid = key = '''