Esempio n. 1
0
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
Esempio n. 2
0
    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)
Esempio n. 3
0
    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)
Esempio n. 4
0
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)
Esempio n. 6
0
 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
Esempio n. 7
0
        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):
Esempio n. 8
0
#! /usr/bin/env python
#coding=utf-8
from xiaomi_gateway import (XiaomiGateway, XiaomiGatewayDiscovery)

a1 = XiaomiGatewayDiscovery()
print a1.discover_gateways()
'''
ip = ""
port =
sid = 
key = 
'''