def test_unavailable_device_info_raises(mocker): send = mocker.patch("miio.Device.send", side_effect=PayloadDecodeException) d = Device("127.0.0.1", "68ffffffffffffffffffffffffffffff") with pytest.raises(DeviceInfoUnavailableException): d.info() assert send.call_count == 1
def test_unavailable_device_info_raises(mocker): """Make sure custom exception is raised if the info payload is invalid.""" send = mocker.patch("miio.Device.send", side_effect=PayloadDecodeException) d = Device("127.0.0.1", "68ffffffffffffffffffffffffffffff") with pytest.raises(DeviceInfoUnavailableException): d.info() assert send.call_count == 1
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the sensor from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info( "%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version, ) device = XiaomiMiioGenericDevice(miio_device, config, device_info) except DeviceException: raise PlatformNotReady hass.data[DATA_KEY][host] = device async_add_devices([device], update_before_add=True) @asyncio.coroutine def async_service_handler(service): """Map services to methods on XiaomiMiioDevice.""" method = SERVICE_TO_METHOD.get(service.service) params = { key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID } entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [ device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids ] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: yield from getattr(device, method["method"])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service].get("schema", SERVICE_SCHEMA) hass.services.async_register( DOMAIN, service, async_service_handler, schema=schema )
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): from miio import Device, DeviceException host = config.get(CONF_HOST) token = config.get(CONF_TOKEN) baseUrl = config.get(CONF_BASEURL) basePath = config.get(CONF_BASEPATH) apiKey = config.get(CONF_APIKEY) secretKey = config.get(CONF_SECRETKEY) speed = config.get(CONF_SPEED, 5) pitch = config.get(CONF_PITCH, 5) volume = config.get(CONF_VOLUME, 5) person = config.get(CONF_PERSON, 0) notify = config.get(CONF_NOTIFY, False) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) device = Device(host, token, lazy_discover=False) try: device_info = device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException as ex: _LOGGER.error("Device unavailable or token incorrect: %s", ex) raise PlatformNotReady friendly_name = config.get(CONF_NAME, "miio_miio_acpartner_" + host.replace('.', '_')) xiaomi_miio_radio = XiaomiMiioRadio(friendly_name, device, unique_id, apiKey, secretKey, speed, pitch, volume, person, baseUrl, basePath, notify) async_add_devices([xiaomi_miio_radio])
async def async_step_user(self, user_input=None): errors = {} if user_input is not None: if user_input.get(CONF_HOST): self.host = user_input[CONF_HOST] token = user_input.get(CONF_TOKEN) device = MiioDevice(self.host, token) try: info = device.info() except DeviceException: info = None errors['base'] = 'cannot_connect' _LOGGER.debug('Xiaomi Miot async_step_user %s', { 'user_input': user_input, 'info': info, 'errors': errors, }) if info is not None: unique_id = format_mac(info.mac_address) await self.async_set_unique_id(unique_id) self._abort_if_unique_id_configured() if not user_input.get(CONF_MODEL): user_input[CONF_MODEL] = str(info.model or '') user_input['miio_info'] = dict(info.raw or {}) return self.async_create_entry( title=user_input.get(CONF_NAME), data=user_input, ) return self.async_show_form( step_id='user', data_schema=MIIO_CONFIG_SCHEMA, errors=errors, )
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the sensor from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info( "%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version, ) device = XiaomiHeatcoldDevice(miio_device, config, device_info) except DeviceException: raise PlatformNotReady hass.data[DATA_KEY][host] = device async_add_devices([device], update_before_add=True)
def setup_platform(hass, config, async_add_devices, discovery_info=None): """Perform the setup for Xiaomi heaters.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing Xiaomi heaters with host %s (token %s...)", host, token[:5]) try: device = Device(host, token) device_info = device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: _LOGGER.exception('Fail to setup Xiaomi heater') raise PlatformNotReady miHeater = MiHeater(device, name, unique_id, hass) hass.data[DATA_KEY][host] = miHeater async_add_devices([miHeater], update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiAirConditioningCompanion.""" method = SERVICE_TO_METHOD.get(service.service) params = { key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID } entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [ device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids ] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method['method']): continue await getattr(device, method['method'])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service].get('schema', SERVICE_SCHEMA) hass.services.async_register(DOMAIN, service, async_service_handler, schema=schema)
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the Xiaomi Gateway platform.""" from miio import Device, DeviceException host = config.get(CONF_HOST) token = config.get(CONF_TOKEN) # Create handler _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) # The Chuang Mi IR Radio Controller wants to be re-discovered every # 5 minutes. As long as polling is disabled the device should be # re-discovered (lazy_discover=False) in front of every command. device = Device(host, token, lazy_discover=False) # Check that we can communicate with device. try: device_info = device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException as ex: _LOGGER.error("Device unavailable or token incorrect: %s", ex) raise PlatformNotReady friendly_name = config.get(CONF_NAME, "miio_radio_" + host.replace('.', '_')) xiaomi_miio_radio = XiaomiMiioRadio(friendly_name, device, unique_id) async_add_devices([xiaomi_miio_radio])
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the switch from config.""" from miio import Device, DeviceException host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model in ['chuangmi.plug.v1']: from miio import PlugV1 plug = PlugV1(host, token) # The device has two switchable channels (mains and a USB port). # A switch device per channel will be created. for channel_usb in [True, False]: device = ChuangMiPlugV1Switch( name, plug, model, channel_usb) devices.append(device) elif model in ['qmi.powerstrip.v1', 'zimi.powerstrip.v2']: from miio import PowerStrip plug = PowerStrip(host, token) device = XiaomiPowerStripSwitch(name, plug, model) devices.append(device) elif model in ['chuangmi.plug.m1', 'chuangmi.plug.v2']: from miio import Plug plug = Plug(host, token) device = XiaomiPlugGenericSwitch(name, plug, model) devices.append(device) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/rytilahti/python-miio/issues ' 'and provide the following data: %s', model) return False async_add_devices(devices, update_before_add=True)
def setup_platform(hass, config, add_devices, discovery_info=None): """Perform the setup for Xiaomi heaters.""" host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing Xiaomi heaters with host %s (token %s...)", host, token[:5]) devices = [] unique_id = None try: device = Device(host, token) device_info = device.info() if model is None: model = device_info.model DEVICE_MODEL = model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.warning("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) miHeater = MiHeater(device, name, model, unique_id, hass) devices.append(miHeater) add_devices(devices) async def set_room_temp(service): """Set room temp.""" if DEVICE_MODEL == "zhimi.heater.mc2": aux = device.raw_command('get_properties', [{ "siid": 2, "piid": 5 }]) elif DEVICE_MODEL == "zhimi.heater.zb1" or DEVICE_MODEL == "zhimi.heater.za2": aux = device.raw_command('get_properties', [{ "siid": 2, "piid": 6 }]) else: _LOGGER.exception('Unsupported model: %s', DEVICE_MODEL) temperature = aux[0]["value"] await miHeater.async_set_temperature(temperature) hass.services.async_register(DOMAIN, SERVICE_SET_ROOM_TEMP, set_room_temp, schema=SET_ROOM_TEMP_SCHEMA) except DeviceException: _LOGGER.exception('Fail to setup Xiaomi heater') raise PlatformNotReady
def is_gw3(host: str, token: str) -> Optional[str]: try: device = Device(host, token) info = device.info() if info.model != 'lumi.gateway.mgl03': raise Exception(f"Wrong device model: {info.model}") except Exception as e: return str(e) return None
def update(event_time): """Get the latest data and updates the states.""" try: miio_device = Device(host, token) run_status = miio_device.send('get_prop', ["run_status"])[0] work_status = miio_device.send('get_prop', ["work_status"])[0] #warm_data = miio_device.send('get_prop', ["warm_data"])[0] last_time = miio_device.send('get_prop', ["last_time"])[0] last_temp = miio_device.send('get_prop', ["last_temp"])[0] curr_tempe = miio_device.send('get_prop', ["curr_tempe"])[0] # work_temps = miio_device.send('get_prop', ["work_temps"])[0] mode = miio_device.send('get_prop', ["mode"])[0] #模式 heat_power = miio_device.send('get_prop', ["heat_power"])[0] #功率 warm_time = miio_device.send('get_prop', ["warm_time"])[0] #保温时间 cook_time = miio_device.send('get_prop', ["cook_time"])[0] #蒸煮时间 left_time = miio_device.send('get_prop', ["left_time"])[0] #剩余时间 cook_status = miio_device.send('get_prop', ["cook_status"])[0] #蒸煮状态 cooked_time = miio_device.send('get_prop', ["cooked_time"])[0] voice = miio_device.send('get_prop', ["voice"])[0] stand_top_num = miio_device.send('get_prop', ["stand_top_num"])[0] #mode_sort = miio_device.send('get_prop', ["mode_sort"])[0] __state_attrs = { "run_status": AVAILABLE_RUN_STATUS[int(run_status)], "mode": AVAILABLE_MODE[int(mode)], "last_time": last_time, "last_temp": last_temp, "curr_tempe": curr_tempe, # "work_temps":work_temps, "heat_power": heat_power, "warm_time": warm_time, "cook_time": cook_time, "left_time": left_time, "cook_status": cook_status, "cooked_time": cooked_time, "voice": voice, "stand_top_num": stand_top_num, #"mode_sort":mode_sort, #"warm_data":warm_data, "friendly_name": name } unique_id = "{}_{}".format( "xiaomi", miio_device.info().mac_address.replace(':', '')) entityid = "{}.{}".format(DOMAIN, unique_id) hass.states.set(entityid, AVAILABLE_STATE[int(work_status)], __state_attrs) except DeviceException: _LOGGER.exception('Fail to get_prop from XiaomiHealthPot') raise PlatformNotReady
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Xiaomi Whale Smart Toilet device platform.""" if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) # Create handler _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model or model or MODEL_TOILETLID_XJX_TOILET_PRO unique_id = "{}-{}".format(model, device_info.mac_address) except DeviceException: raise PlatformNotReady toiletlid = Toiletlid(host, token, model=model) device = ToiletlidEntity(name, toiletlid, model, unique_id) hass.data[DATA_KEY][host] = device async_add_entities([device], update_before_add=True) async def async_service_handler(service): """Map services to methods on Xiaomi Whale Smart Toilet.""" method = SERVICE_TO_METHOD.get(service.service) params = service.data.copy() entity_ids = params.pop(ATTR_ENTITY_ID, hass.data[DATA_KEY].values()) update_tasks = [] for device in filter(lambda x: x.entity_id in entity_ids, hass.data[DATA_KEY].values()): if not hasattr(device, method["method"]): continue await getattr(device, method["method"])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks) for toiletlid_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[toiletlid_service].get( "schema", TOILETLID_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, toiletlid_service, async_service_handler, schema=schema)
def setup(hass, config): """初始化小米净水器组件""" if DOMAIN not in hass.data: hass.data[DOMAIN] = {} host = config[DOMAIN][CONF_HOST] token = config[DOMAIN][CONF_TOKEN] name = config[DOMAIN][CONF_NAME] model = config[DOMAIN].get(CONF_MODEL) scan_interval = config[DOMAIN][CONF_SCAN_INTERVAL] if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} hass.data[DATA_KEY][host] = {} try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info("发现净水器设备,型号[%s],软件版本[%s],硬件版本[%s]", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model in SUPPORTED_MODELS: water_purifier = MiWaterPurifier(miio_device, name) _LOGGER.info("实例化小米净水器[%s]", name) hass.data[DOMAIN][host] = water_purifier for component in ['sensor']: discovery.load_platform(hass, component, DOMAIN, {}, config) else: _LOGGER.error("未支持设备型号[%s]", model) return False def update(event_time): """更新设备状态""" try: water_purifier.update() state = water_purifier.state hass.data[DATA_KEY][host][DATA_STATE] = state dispatcher_send(hass, '{}_updated'.format(DOMAIN), host) except DeviceException as ex: dispatcher_send(hass, '{}_unavailable'.format(DOMAIN), host) _LOGGER.error("获取净化器状态时异常[%s]", ex) update(utcnow()) track_time_interval(hass, update, scan_interval) return True
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the light from config.""" from miio import Device, DeviceException host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] try: light = Device(host, token) device_info = light.info() _LOGGER.info("%s %s %s initialized", device_info.model, device_info.firmware_version, device_info.hardware_version) if device_info.model == 'philips.light.sread1': from miio import PhilipsEyecare light = PhilipsEyecare(host, token) device = XiaomiPhilipsEyecareLamp(name, light, device_info) devices.append(device) elif device_info.model == 'philips.light.ceiling': from miio import Ceil light = Ceil(host, token) device = XiaomiPhilipsCeilingLamp(name, light, device_info) devices.append(device) elif device_info.model == 'philips.light.bulb': from miio import PhilipsBulb light = PhilipsBulb(host, token) device = XiaomiPhilipsLightBall(name, light, device_info) devices.append(device) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/rytilahti/python-miio/issues ' 'and provide the following data: %s', device_info.model) except DeviceException: raise PlatformNotReady async_add_devices(devices, update_before_add=True)
def setup_platform(hass, config, add_devices, discovery_info=None): """Perform the setup for Xiaomi heaters.""" from miio import Device, DeviceException host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing Xiaomi heaters with host %s (token %s...)", host, token[:5]) devices = [] unique_id = None try: device = Device(host, token) device_info = device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) miHeater = MiHeater(device, name, unique_id, hass) devices.append(miHeater) add_devices(devices) async def set_room_temp(service): """Set room temp.""" temperature = service.data.get('temperature') await miHeater.async_set_temperature(temperature) hass.services.async_register(DOMAIN, SERVICE_SET_ROOM_TEMP, set_room_temp, schema=SET_ROOM_TEMP_SCHEMA) except DeviceException: _LOGGER.exception('Fail to setup Xiaomi heater') raise PlatformNotReady
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the switch from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] unique_id = None if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model in ['chuangmi.plug.v1', 'chuangmi.plug.v3']: from miio import ChuangmiPlug plug = ChuangmiPlug(host, token, model=model) # The device has two switchable channels (mains and a USB port). # A switch device per channel will be created. for channel_usb in [True, False]: device = ChuangMiPlugSwitch( name, plug, model, unique_id, channel_usb) devices.append(device) hass.data[DATA_KEY][host] = device elif model in ['qmi.powerstrip.v1', 'zimi.powerstrip.v2']: from miio import PowerStrip plug = PowerStrip(host, token, model=model) device = XiaomiPowerStripSwitch(name, plug, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device elif model in ['chuangmi.plug.m1', 'chuangmi.plug.v2']: from miio import ChuangmiPlug plug = ChuangmiPlug(host, token, model=model) device = XiaomiPlugGenericSwitch(name, plug, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/rytilahti/python-miio/issues ' 'and provide the following data: %s', model) return False async_add_entities(devices, update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiPlugGenericSwitch.""" method = SERVICE_TO_METHOD.get(service.service) params = {key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID} entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method['method']): continue await getattr(device, method['method'])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for plug_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[plug_service].get('schema', SERVICE_SCHEMA) hass.services.async_register( DOMAIN, plug_service, async_service_handler, schema=schema)
def setup(hass, config): """Set up the platform from config.""" from miio import Device, DeviceException if DOMAIN not in hass.data: hass.data[DOMAIN] = {} host = config[DOMAIN][CONF_HOST] token = config[DOMAIN][CONF_TOKEN] name = config[DOMAIN][CONF_NAME] model = config[DOMAIN].get(CONF_MODEL) scan_interval = config[DOMAIN][CONF_SCAN_INTERVAL] if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} hass.data[DATA_KEY][host] = {} _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model in SUPPORTED_MODELS: from miio import Cooker cooker = Cooker(host, token) hass.data[DOMAIN][host] = cooker for component in ['sensor']: discovery.load_platform(hass, component, DOMAIN, {}, config) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/syssi/xiaomi_cooker/issues ' 'and provide the following data: %s', model) return False def update(event_time): """Update device status.""" from miio.cooker import OperationMode try: state = cooker.status() _LOGGER.debug("Got new state: %s", state) hass.data[DATA_KEY][host][DATA_STATE] = state if state.mode in [ OperationMode.Running, OperationMode.AutoKeepWarm ]: hass.data[DATA_KEY][host][ DATA_TEMPERATURE_HISTORY] = cooker.get_temperature_history( ) dispatcher_send(hass, '{}_updated'.format(DOMAIN), host) except DeviceException as ex: dispatcher_send(hass, '{}_unavailable'.format(DOMAIN), host) _LOGGER.error("Got exception while fetching the state: %s", ex) update(utcnow()) track_time_interval(hass, update, scan_interval) def start_service(call): """Service to start cooking.""" profile = call.data.get(ATTR_PROFILE) cooker.start(profile) def stop_service(call): """Service to stop cooking.""" cooker.stop() hass.services.register(DOMAIN, SERVICE_START, start_service, schema=SERVICE_SCHEMA_START) hass.services.register(DOMAIN, SERVICE_STOP, stop_service, schema=SERVICE_SCHEMA) return True
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the light from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] unique_id = None if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model == 'philips.light.sread1': from miio import PhilipsEyecare light = PhilipsEyecare(host, token) primary_device = XiaomiPhilipsEyecareLamp( name, light, model, unique_id) devices.append(primary_device) hass.data[DATA_KEY][host] = primary_device secondary_device = XiaomiPhilipsEyecareLampAmbientLight( name, light, model, unique_id) devices.append(secondary_device) # The ambient light doesn't expose additional services. # A hass.data[DATA_KEY] entry isn't needed. elif model in ['philips.light.ceiling', 'philips.light.zyceiling']: from miio import Ceil light = Ceil(host, token) device = XiaomiPhilipsCeilingLamp(name, light, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device elif model == 'philips.light.moonlight': from miio import PhilipsMoonlight light = PhilipsMoonlight(host, token) device = XiaomiPhilipsMoonlightLamp(name, light, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device elif model in ['philips.light.bulb', 'philips.light.candle', 'philips.light.candle2', 'philips.light.downlight']: from miio import PhilipsBulb light = PhilipsBulb(host, token) device = XiaomiPhilipsBulb(name, light, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device elif model == 'philips.light.mono1': from miio import PhilipsBulb light = PhilipsBulb(host, token) device = XiaomiPhilipsGenericLight(name, light, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/syssi/philipslight/issues ' 'and provide the following data: %s', model) return False async_add_entities(devices, update_before_add=True) async def async_service_handler(service): """Map services to methods on Xiaomi Philips Lights.""" method = SERVICE_TO_METHOD.get(service.service) params = {key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID} entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: target_devices = [dev for dev in hass.data[DATA_KEY].values() if dev.entity_id in entity_ids] else: target_devices = hass.data[DATA_KEY].values() update_tasks = [] for target_device in target_devices: if not hasattr(target_device, method['method']): continue await getattr(target_device, method['method'])(**params) update_tasks.append(target_device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for xiaomi_miio_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[xiaomi_miio_service].get( 'schema', XIAOMI_MIIO_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, xiaomi_miio_service, async_service_handler, schema=schema)
class Gateway3(Thread): devices: dict = None updates: dict = None setups: dict = None log = None def __init__(self, host: str, token: str): super().__init__(daemon=True) self.host = host self.miio = Device(host, token) self.mqtt = Client() self.mqtt.on_connect = self.on_connect self.mqtt.on_disconnect = self.on_disconnect self.mqtt.on_message = self.on_message self.mqtt.connect_async(host) if isinstance(self.log, str): self.log = utils.get_logger(self.log) @property def device(self): return self.devices['lumi.0'] def add_update(self, did: str, handler): """Add handler to device update event.""" if self.updates is None: self.updates = {} self.updates.setdefault(did, []).append(handler) def add_setup(self, domain: str, handler): """Add hass device setup funcion.""" if self.setups is None: self.setups = {} self.setups[domain] = handler def run(self): """Main loop""" while self.devices is None: if self._miio_connect(): devices = self._get_devices1() if devices: self.setup_devices(devices) # else: # self._enable_telnet() else: time.sleep(30) while True: if self._mqtt_connect(): self.mqtt.loop_forever() elif self._miio_connect() and self._enable_telnet(): self._enable_mqtt() else: _LOGGER.debug("sleep 30") time.sleep(30) def _mqtt_connect(self) -> bool: try: self.mqtt.reconnect() return True except: return False def _miio_connect(self) -> bool: try: self.miio.send_handshake() return True except: return False def _get_devices1(self) -> Optional[list]: """Load devices via miio protocol.""" _LOGGER.debug(f"{self.host} | Read devices") try: devices = {} # endless loop protection for _ in range(16): # load only 8 device per part part = self.miio.send('get_device_list', retry_count=10) if len(part) == 0: return [] for item in part: devices[item['num']] = { 'did': item['did'], 'mac': f"0x{item['did'][5:]}", 'model': item['model'], } if part[0]['total'] == len(devices): break devices = list(devices.values()) for device in devices: desc = utils.get_device(device['model']) # skip unknown model if desc is None: continue # get xiaomi param names params = [p[1] for p in desc['params'] if p[1] is not None] # skip if don't have retain params if not params: continue # load param values values = self.miio.send('get_device_prop', [device['did']] + params) # get hass param names params = [p[2] for p in desc['params'] if p[1] is not None] data = dict(zip(params, values)) # fix some param values for k, v in data.items(): if k in ('temperature', 'humidity'): data[k] = v / 100.0 elif v == 'on': data[k] = 1 elif v == 'off': data[k] = 0 device['init'] = data device = self.miio.info() devices.append({ 'did': 'lumi.0', 'mac': device.mac_address, # wifi mac!!! 'model': device.model }) return devices except Exception as e: return None def _get_devices2(self) -> Optional[list]: """Load device list via Telnet. Device desc example: mac: '0x158d0002c81234' shortId: '0x0691' manuCode: '0x115f' model: 'lumi.sensor_ht' did: 'lumi.158d0002c81234' devType: 0 appVer: 2 hardVer: 0 devID: 770 status: 0 model_ver: 2 """ _LOGGER.debug(f"{self.host} | Read devices") try: telnet = Telnet(self.host) telnet.read_until(b"login: "******"admin\r\n") telnet.read_until(b'\r\n# ') # skip greeting telnet.write(b"cat /data/zigbee/coordinator.info\r\n") telnet.read_until(b'\r\n') # skip command raw = telnet.read_until(b'# ') device = json.loads(raw[:-2]) device.update({ 'did': 'lumi.0', 'model': 'lumi.gateway.mgl03', 'host': self.host }) devices = [device] telnet.write(b"cat /data/zigbee/device.info\r\n") telnet.read_until(b'\r\n') # skip command raw = telnet.read_until(b'# ') raw = json.loads(raw[:-2]) devices += raw['devInfo'] telnet.close() return devices except Exception as e: _LOGGER.exception(f"Can't read devices: {e}") return None def _enable_telnet(self): _LOGGER.debug(f"{self.host} | Try enable telnet") try: resp = self.miio.send("enable_telnet_service") return resp[0] == 'ok' except Exception as e: _LOGGER.exception(f"Can't enable telnet: {e}") return False def _enable_mqtt(self): _LOGGER.debug(f"{self.host} | Try run public MQTT") try: telnet = Telnet(self.host) telnet.read_until(b"login: "******"admin\r\n") telnet.read_very_eager() # skip response telnet.write(b"killall mosquitto\r\n") telnet.read_very_eager() # skip response telnet.write(b"mosquitto -d\r\n") telnet.read_very_eager() # skip response time.sleep(1) telnet.close() return True except Exception as e: _LOGGER.exception(f"Can't run MQTT: {e}") return False def on_connect(self, client, userdata, flags, rc): _LOGGER.debug(f"{self.host} | MQTT connected") # self.mqtt.subscribe('#') self.mqtt.subscribe('zigbee/send') def on_disconnect(self, client, userdata, rc): _LOGGER.debug(f"{self.host} | MQTT disconnected") # force end mqtt.loop_forever() self.mqtt.disconnect() def on_message(self, client: Client, userdata, msg: MQTTMessage): if self.log: self.log.debug(f"[{self.host}] {msg.topic} {msg.payload.decode()}") if msg.topic == 'zigbee/send': payload = json.loads(msg.payload) self.process_message(payload) def setup_devices(self, devices: list): """Add devices to hass.""" for device in devices: desc = utils.get_device(device['model']) if not desc: _LOGGER.debug(f"Unsupported model: {device}") continue _LOGGER.debug(f"Setup device {device['model']}") device.update(desc) if self.devices is None: self.devices = {} self.devices[device['did']] = device for param in device['params']: domain = param[3] if not domain: continue # wait domain init while domain not in self.setups: time.sleep(1) attr = param[2] self.setups[domain](self, device, attr) def process_message(self, data: dict): if data['cmd'] == 'heartbeat': # don't know if only one item assert len(data['params']) == 1, data data = data['params'][0] pkey = 'res_list' elif data['cmd'] == 'report': pkey = 'params' elif data['cmd'] == 'write_rsp': pkey = 'results' else: raise NotImplemented(f"Unsupported cmd: {data}") did = data['did'] # skip without callback if did not in self.updates: return device = self.devices[did] payload = {} # convert codes to names for param in data[pkey]: if param.get('error_code', 0) != 0: continue prop = param['res_name'] if prop in GLOBAL_PROP: prop = GLOBAL_PROP[prop] else: prop = next((p[2] for p in device['params'] if p[0] == prop), prop) payload[prop] = (param['value'] / 100.0 if prop in DIV_100 else param['value']) _LOGGER.debug(f"{self.host} | {device['did']} {device['model']} <= " f"{payload}") for handler in self.updates[did]: handler(payload) if 'added_device' in payload: device = payload['added_device'] device['mac'] = '0x' + device['mac'] self.setup_devices([device]) def send(self, device: dict, param: str, value): # convert hass prop to lumi prop prop = next(p[0] for p in device['params'] if p[2] == param) payload = { 'cmd': 'write', 'did': device['did'], 'params': [{ 'res_name': prop, 'value': value }], } _LOGGER.debug(f"{self.host} | {device['did']} {device['model']} => " f"{payload}") payload = json.dumps(payload, separators=(',', ':')).encode() self.mqtt.publish('zigbee/recv', payload)
class XjxToilet(BinarySensorEntity): def __init__(self, name, host, token): self._name = name self._device = Device(host, token) self._state = False self._state_attrs = {} device_info = self._device.info() self._unique_id = "{}-{}".format(device_info.model, device_info.mac_address) async def async_update(self): try: seating = self._device.get_properties(properties=['seating']) seatTemp = self._device.get_properties( properties=['seat_temp', 'status_seatheat']) statusLed = self._device.get_properties(properties=['status_led']) self._state = seating[0] == 1 self._state_attrs.update({ "status_seatheat": seatTemp[1] == 1, "seat_temp": seatTemp[0], "status_led": statusLed[0] == 1 }) except Exception: _LOGGER.error('Update state error.', exc_info=True) @property def name(self): """Return the name of the device if any.""" return self._name @property def unique_id(self): """Return an unique ID.""" return self._unique_id @property def is_on(self) -> bool: """Return True if the switch is on based on the state machine.""" if self._state is None: return False return self._state @property def device_class(self): """Return the device class of this entity.""" return DEVICE_CLASS_OCCUPANCY @property def device_state_attributes(self): """Return the state attributes of the device.""" return self._state_attrs async def flush_on(self, **kwargs): try: self._device.send('flush_on', []) except DeviceException: raise PlatformNotReady async def work_seatheat(self, **kwargs): try: self._device.send('work_seatheat', [kwargs["status"]]) # 开启马桶圈加热必须同时发送马桶圈温度命令 if kwargs["status"] == 1: self._device.send('send_seat_heat', [kwargs["status"]]) except DeviceException: raise PlatformNotReady async def work_night_led(self, **kwargs): try: self._device.send('work_night_led', [kwargs["status"]]) except DeviceException: raise PlatformNotReady
def update(event_time): """Get the latest data and updates the states.""" try: miio_device = Device(host, token) run_status = miio_device.send('get_prop', ["run_status"])[0] work_status = miio_device.send('get_prop', ["work_status"])[0] warm_data = miio_device.send('get_prop', ["warm_data"])[0] last_time = miio_device.send('get_prop', ["last_time"])[0] last_temp = miio_device.send('get_prop', ["last_temp"])[0] curr_tempe = miio_device.send('get_prop', ["curr_tempe"])[0] # work_temps = miio_device.send('get_prop', ["work_temps"])[0] mode = miio_device.send('get_prop', ["mode"])[0] #模式 heat_power = miio_device.send('get_prop', ["heat_power"])[0] #功率 warm_time = miio_device.send('get_prop', ["warm_time"])[0] #保温时间 cook_time = miio_device.send('get_prop', ["cook_time"])[0] #蒸煮时间 left_time = miio_device.send('get_prop', ["left_time"])[0] #剩余时间 cook_status = miio_device.send('get_prop', ["cook_status"])[0] #蒸煮状态 cooked_time = miio_device.send('get_prop', ["cooked_time"])[0] voice = miio_device.send('get_prop', ["voice"])[0] stand_top_num = miio_device.send('get_prop', ["stand_top_num"])[0] mode_sort = miio_device.send('get_prop', ["mode_sort"])[0] __run_status = int(run_status) __work_status = int(work_status) __last_time = int(last_time) __last_temp = int(last_temp) __curr_tempe = int(curr_tempe) __work_status_cn = None __mode_cn = None __mode_en = None __mode = int(mode) __heat_power = int(heat_power) __warm_time = int(warm_time) __cook_time = int(cook_time) __left_time = int(left_time) __cook_status = int(cook_status) __cooked_time = int(cooked_time) __voice = int(voice) __stand_top_num = int(stand_top_num) __mode_sort = str(mode_sort) __warm_data = str(warm_data) # __work_temps = int(work_temps) if work_status == 1: # 预约 __current_operation = STATE_1 __work_status_cn = "预约" elif work_status == 2: # 烹饪 __current_operation = STATE_2 __work_status_cn = "烹饪" elif work_status == 3: # 暂停 __current_operation = STATE_3 __work_status_cn = "暂停" elif work_status == 4: # 保温 __current_operation = STATE_4 __work_status_cn = "保温" elif work_status == 5: # 终止 __current_operation = STATE_4 __work_status_cn = "终止" if mode == 11: # 花草茶 __mode_en = MODE_11 __mode_cn = "花草茶" elif mode == 12: # 水果茶 __mode_en = MODE_12 __mode_cn = "水果茶" elif mode == 13: # 煲汤 __mode_en = MODE_13 __mode_cn = "煲汤" elif mode == 14: # 药膳 __mode_en = MODE_14 __mode_cn = "药膳" elif mode == 15: # 粥品 __mode_en = MODE_15 __mode_cn = "粥品" elif mode == 16: # 燕窝 __mode_en = MODE_16 __mode_cn = "燕窝" elif mode == 17: # 火锅 __mode_en = MODE_17 __mode_cn = "火锅" elif mode == 18: # 烧水 __mode_en = MODE_18 __mode_cn = "烧水" elif mode == 19: # 温奶 __mode_en = MODE_19 __mode_cn = "温奶" elif mode == 20: # 温泉蛋 __mode_en = MODE_20 __mode_cn = "温泉蛋" elif mode == 21: # 酸奶 __mode_en = MODE_21 __mode_cn = "酸奶" elif mode == 22: # 蒸水蛋 __mode_en = MODE_22 __mode_cn = "蒸水蛋" elif mode == 23: # 煮茶 __mode_en = MODE_23 __mode_cn = "煮茶" elif mode == 24: # 灵芝 __mode_en = MODE_24 __mode_cn = "灵芝" elif mode == 25: # 消毒 __mode_en = MODE_25 __mode_cn = "消毒" elif mode == 26: # 糖水 __mode_en = MODE_26 __mode_cn = "糖水" elif mode == 1: # 自定义 __mode_en = MODE_1 __mode_cn = "自定义1" elif mode == 2: # 自定义 __mode_en = MODE_2 __mode_cn = "自定义2" elif mode == 3: # 自定义 __mode_en = MODE_3 __mode_cn = "自定义3" elif mode == 4: # 自定义 __mode_en = MODE_4 __mode_cn = "自定义4" elif mode == 5: # 自定义 __mode_en = MODE_5 __mode_cn = "自定义5" elif mode == 6: # 自定义 __mode_en = MODE_6 __mode_cn = "自定义6" elif mode == 7: # 自定义 __mode_en = MODE_7 __mode_cn = "自定义7" elif mode == 8: # 自定义 __mode_en = MODE_8 __mode_cn = "自定义8" __state_attrs = { "run_status": run_status, "work_status": work_status, "work_status_cn": __work_status_cn, "warm_data": warm_data, "last_time": last_time, "last_temp": last_temp, "curr_tempe": curr_tempe, # "work_temps":work_temps, "mode": mode, "mode_en": __mode_en, "mode_cn": __mode_cn, "heat_power": heat_power, "warm_time": warm_time, "cook_time": cook_time, "left_time": left_time, "cook_status": cook_status, "cooked_time": cooked_time, "voice": voice, "stand_top_num": stand_top_num, "mode_sort": mode_sort, "friendly_name": name } unique_id = "{}_{}".format( "xiaomi", miio_device.info().mac_address.replace(':', '')) entityid = "{}.{}".format(DOMAIN, unique_id) hass.states.set(entityid, work_status, __state_attrs) except DeviceException: _LOGGER.exception('Fail to get_prop from XiaomiHealthPot') raise PlatformNotReady
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the switch from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] unique_id = None if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model in ['chuangmi.plug.v1', 'chuangmi.plug.v3']: from miio import ChuangmiPlug plug = ChuangmiPlug(host, token, model=model) # The device has two switchable channels (mains and a USB port). # A switch device per channel will be created. for channel_usb in [True, False]: device = ChuangMiPlugSwitch(name, plug, model, unique_id, channel_usb) devices.append(device) hass.data[DATA_KEY][host] = device elif model in ['qmi.powerstrip.v1', 'zimi.powerstrip.v2']: from miio import PowerStrip plug = PowerStrip(host, token, model=model) device = XiaomiPowerStripSwitch(name, plug, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device elif model in ['chuangmi.plug.m1', 'chuangmi.plug.v2']: from miio import ChuangmiPlug plug = ChuangmiPlug(host, token, model=model) device = XiaomiPlugGenericSwitch(name, plug, model, unique_id) devices.append(device) hass.data[DATA_KEY][host] = device else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/rytilahti/python-miio/issues ' 'and provide the following data: %s', model) return False async_add_entities(devices, update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiPlugGenericSwitch.""" method = SERVICE_TO_METHOD.get(service.service) params = { key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID } entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [ device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids ] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method['method']): continue await getattr(device, method['method'])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for plug_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[plug_service].get('schema', SERVICE_SCHEMA) hass.services.async_register(DOMAIN, plug_service, async_service_handler, schema=schema)
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the miio fan device from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) unique_id = None if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model.startswith('zhimi.airpurifier.'): from miio import AirPurifier air_purifier = AirPurifier(host, token) device = XiaomiAirPurifier(name, air_purifier, model, unique_id) elif model.startswith('zhimi.humidifier.'): from miio import AirHumidifier air_humidifier = AirHumidifier(host, token) device = XiaomiAirHumidifier(name, air_humidifier, model, unique_id) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/syssi/xiaomi_airpurifier/issues ' 'and provide the following data: %s', model) return False hass.data[DATA_KEY][host] = device async_add_devices([device], update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiAirPurifier.""" method = SERVICE_TO_METHOD.get(service.service) params = {key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID} entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method['method']): continue await getattr(device, method['method'])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for air_purifier_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[air_purifier_service].get( 'schema', AIRPURIFIER_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, air_purifier_service, async_service_handler, schema=schema)
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the light from config.""" from miio import Device, DeviceException if PLATFORM not in hass.data: hass.data[PLATFORM] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: light = Device(host, token) device_info = light.info() _LOGGER.info("%s %s %s initialized", device_info.model, device_info.firmware_version, device_info.hardware_version) if device_info.model == 'philips.light.sread1': from miio import PhilipsEyecare light = PhilipsEyecare(host, token) device = XiaomiPhilipsEyecareLamp(name, light, device_info) elif device_info.model == 'philips.light.ceiling': from miio import Ceil light = Ceil(host, token) device = XiaomiPhilipsCeilingLamp(name, light, device_info) elif device_info.model == 'philips.light.bulb': from miio import PhilipsBulb light = PhilipsBulb(host, token) device = XiaomiPhilipsLightBall(name, light, device_info) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/rytilahti/python-miio/issues ' 'and provide the following data: %s', device_info.model) return False except DeviceException: raise PlatformNotReady hass.data[PLATFORM][host] = device async_add_devices([device], update_before_add=True) @asyncio.coroutine def async_service_handler(service): """Map services to methods on Xiaomi Philips Lights.""" method = SERVICE_TO_METHOD.get(service.service) params = {key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID} entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: target_devices = [dev for dev in hass.data[PLATFORM].values() if dev.entity_id in entity_ids] else: target_devices = hass.data[PLATFORM].values() update_tasks = [] for target_device in target_devices: yield from getattr(target_device, method['method'])(**params) update_tasks.append(target_device.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for xiaomi_miio_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[xiaomi_miio_service].get( 'schema', XIAOMI_MIIO_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, xiaomi_miio_service, async_service_handler, schema=schema)
async def async_step_user(self, user_input=None): """Handle a flow initialized by the user.""" errors = {} # Check if already configured # await self.async_set_unique_id(DOMAIN) # self._abort_if_unique_id_configured() if user_input is not None: self._name = user_input[CONF_NAME] self._host = user_input[CONF_HOST] self._token = user_input[CONF_TOKEN] # self._mapping = user_input[CONF_MAPPING] # self._params = user_input[CONF_CONTROL_PARAMS] device = MiioDevice(self._host, self._token) try: self._info = device.info() except DeviceException: # print("DeviceException!!!!!!") errors['base'] = 'cannot_connect' # except ValueError: # errors['base'] = 'value_error' if self._info is not None: unique_id = format_mac(self._info.mac_address) # await self.async_set_unique_id(unique_id) for entry in self._async_current_entries(): if entry.unique_id == unique_id: persistent_notification.async_create( self.hass, f"您新添加的设备: **{self._name}** ,\n" f"其 MAC 地址与现有的某个设备相同。\n" f"只是通知,不会造成任何影响。", "设备可能重复") break self._abort_if_unique_id_configured() d = self._info.raw self._model = d['model'] device_info = (f"Model: {d['model']}\n" f"Firmware: {d['fw_ver']}\n" f"MAC: {d['mac']}\n") # self._info = self.get_devconfg_by_model(self._model) self._info = await async_get_mp_from_net(self.hass, self._model) \ or await guess_mp_from_model(self.hass, self._model) if self._info: device_info += "\n已经自动发现配置参数。\n如无特殊需要,无需修改下列内容。\n" devtype_default = self._info.get('device_type') mapping_default = self._info.get('mapping') params_default = self._info.get('params') else: device_info += "请手动进行配置。\n" devtype_default = '' mapping_default = '{"switch_status":{"siid":2,"piid":1}}' params_default = '{"switch_status":{"power_on":true,"power_off":false}}' self._input2 = user_input return self.async_show_form( step_id="devinfo", data_schema=vol.Schema({ vol.Required('devtype', default=devtype_default): vol.In(SUPPORTED_DOMAINS), vol.Required(CONF_MAPPING, default=mapping_default): str, vol.Required(CONF_CONTROL_PARAMS, default=params_default): str, vol.Optional('cloud_read'): bool, vol.Optional('cloud_write'): bool, }), description_placeholders={"device_info": device_info}, errors=errors, ) return self.async_show_form( step_id="user", data_schema=vol.Schema({ vol.Required(CONF_NAME): str, vol.Required(CONF_HOST, default='192.168.'): str, vol.Required(CONF_TOKEN): str, # vol.Required(CONF_MAPPING, default='{"switch_status":{"siid":2,"piid":1}}'): str, # vol.Required(CONF_CONTROL_PARAMS, default='{"switch_status":{"power_on":true,"power_off":false}}'): str, }), # description_placeholders={"device_info": "device_info"}, errors=errors, )
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the miio fan device from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) unique_id = None if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info("%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version) except DeviceException: raise PlatformNotReady if model.startswith('zhimi.airpurifier.'): from miio import AirPurifier air_purifier = AirPurifier(host, token) device = XiaomiAirPurifier(name, air_purifier, model, unique_id) elif model.startswith('zhimi.humidifier.'): from miio import AirHumidifier air_humidifier = AirHumidifier(host, token, model=model) device = XiaomiAirHumidifier(name, air_humidifier, model, unique_id) elif model.startswith('zhimi.airfresh.'): from miio import AirFresh air_fresh = AirFresh(host, token) device = XiaomiAirFresh(name, air_fresh, model, unique_id) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/syssi/xiaomi_airpurifier/issues ' 'and provide the following data: %s', model) return False hass.data[DATA_KEY][host] = device async_add_entities([device], update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiAirPurifier.""" method = SERVICE_TO_METHOD.get(service.service) params = {key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID} entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method['method']): continue await getattr(device, method['method'])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for air_purifier_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[air_purifier_service].get( 'schema', AIRPURIFIER_SERVICE_SCHEMA) hass.services.async_register( DOMAIN, air_purifier_service, async_service_handler, schema=schema)
def setup(hass, config): from miio import Device, DeviceException if DOMAIN not in hass.data: hass.data[DOMAIN] = {} host = config[DOMAIN][CONF_HOST] token = config[DOMAIN][CONF_TOKEN] name = config[DOMAIN][CONF_NAME] model = config[DOMAIN].get(CONF_MODEL) scan_interval = config[DOMAIN][CONF_SCAN_INTERVAL] if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} hass.data[DATA_KEY][host] = {} _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info( "%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version, ) except DeviceException: raise PlatformNotReady if model not in SUPPORTED_MODELS: _LOGGER.error( "Unsupported device found! Please create an issue at " "https://github.com/fineemb/Xiaomi-Smart-Multipurpose-Kettle/issues " "and provide the following data: %s", model, ) return False def update(event_time): """Get the latest data and updates the states.""" try: miio_device = Device(host, token) run_status = miio_device.send('get_prop', ["run_status"])[0] work_status = miio_device.send('get_prop', ["work_status"])[0] warm_data = miio_device.send('get_prop', ["warm_data"])[0] last_time = miio_device.send('get_prop', ["last_time"])[0] last_temp = miio_device.send('get_prop', ["last_temp"])[0] curr_tempe = miio_device.send('get_prop', ["curr_tempe"])[0] # work_temps = miio_device.send('get_prop', ["work_temps"])[0] mode = miio_device.send('get_prop', ["mode"])[0] #模式 heat_power = miio_device.send('get_prop', ["heat_power"])[0] #功率 warm_time = miio_device.send('get_prop', ["warm_time"])[0] #保温时间 cook_time = miio_device.send('get_prop', ["cook_time"])[0] #蒸煮时间 left_time = miio_device.send('get_prop', ["left_time"])[0] #剩余时间 cook_status = miio_device.send('get_prop', ["cook_status"])[0] #蒸煮状态 cooked_time = miio_device.send('get_prop', ["cooked_time"])[0] voice = miio_device.send('get_prop', ["voice"])[0] stand_top_num = miio_device.send('get_prop', ["stand_top_num"])[0] mode_sort = miio_device.send('get_prop', ["mode_sort"])[0] __run_status = int(run_status) __work_status = int(work_status) __last_time = int(last_time) __last_temp = int(last_temp) __curr_tempe = int(curr_tempe) __work_status_cn = None __mode_cn = None __mode_en = None __mode = int(mode) __heat_power = int(heat_power) __warm_time = int(warm_time) __cook_time = int(cook_time) __left_time = int(left_time) __cook_status = int(cook_status) __cooked_time = int(cooked_time) __voice = int(voice) __stand_top_num = int(stand_top_num) __mode_sort = str(mode_sort) __warm_data = str(warm_data) # __work_temps = int(work_temps) if work_status == 1: # 预约 __current_operation = STATE_1 __work_status_cn = "预约" elif work_status == 2: # 烹饪 __current_operation = STATE_2 __work_status_cn = "烹饪" elif work_status == 3: # 暂停 __current_operation = STATE_3 __work_status_cn = "暂停" elif work_status == 4: # 保温 __current_operation = STATE_4 __work_status_cn = "保温" elif work_status == 5: # 终止 __current_operation = STATE_4 __work_status_cn = "终止" if mode == 11: # 花草茶 __mode_en = MODE_11 __mode_cn = "花草茶" elif mode == 12: # 水果茶 __mode_en = MODE_12 __mode_cn = "水果茶" elif mode == 13: # 煲汤 __mode_en = MODE_13 __mode_cn = "煲汤" elif mode == 14: # 药膳 __mode_en = MODE_14 __mode_cn = "药膳" elif mode == 15: # 粥品 __mode_en = MODE_15 __mode_cn = "粥品" elif mode == 16: # 燕窝 __mode_en = MODE_16 __mode_cn = "燕窝" elif mode == 17: # 火锅 __mode_en = MODE_17 __mode_cn = "火锅" elif mode == 18: # 烧水 __mode_en = MODE_18 __mode_cn = "烧水" elif mode == 19: # 温奶 __mode_en = MODE_19 __mode_cn = "温奶" elif mode == 20: # 温泉蛋 __mode_en = MODE_20 __mode_cn = "温泉蛋" elif mode == 21: # 酸奶 __mode_en = MODE_21 __mode_cn = "酸奶" elif mode == 22: # 蒸水蛋 __mode_en = MODE_22 __mode_cn = "蒸水蛋" elif mode == 23: # 煮茶 __mode_en = MODE_23 __mode_cn = "煮茶" elif mode == 24: # 灵芝 __mode_en = MODE_24 __mode_cn = "灵芝" elif mode == 25: # 消毒 __mode_en = MODE_25 __mode_cn = "消毒" elif mode == 26: # 糖水 __mode_en = MODE_26 __mode_cn = "糖水" elif mode == 1: # 自定义 __mode_en = MODE_1 __mode_cn = "自定义1" elif mode == 2: # 自定义 __mode_en = MODE_2 __mode_cn = "自定义2" elif mode == 3: # 自定义 __mode_en = MODE_3 __mode_cn = "自定义3" elif mode == 4: # 自定义 __mode_en = MODE_4 __mode_cn = "自定义4" elif mode == 5: # 自定义 __mode_en = MODE_5 __mode_cn = "自定义5" elif mode == 6: # 自定义 __mode_en = MODE_6 __mode_cn = "自定义6" elif mode == 7: # 自定义 __mode_en = MODE_7 __mode_cn = "自定义7" elif mode == 8: # 自定义 __mode_en = MODE_8 __mode_cn = "自定义8" __state_attrs = { "run_status": run_status, "work_status": work_status, "work_status_cn": __work_status_cn, "warm_data": warm_data, "last_time": last_time, "last_temp": last_temp, "curr_tempe": curr_tempe, # "work_temps":work_temps, "mode": mode, "mode_en": __mode_en, "mode_cn": __mode_cn, "heat_power": heat_power, "warm_time": warm_time, "cook_time": cook_time, "left_time": left_time, "cook_status": cook_status, "cooked_time": cooked_time, "voice": voice, "stand_top_num": stand_top_num, "mode_sort": mode_sort, "friendly_name": name } unique_id = "{}_{}".format( "xiaomi", miio_device.info().mac_address.replace(':', '')) entityid = "{}.{}".format(DOMAIN, unique_id) hass.states.set(entityid, work_status, __state_attrs) except DeviceException: _LOGGER.exception('Fail to get_prop from XiaomiHealthPot') raise PlatformNotReady track_time_interval(hass, update, scan_interval) def set_voice(voice: str): try: miio_device = Device(host, token) if voice == 'on': miio_device.send('set_voice', [0]) elif voice == 'off': miio_device.send('set_voice', [1]) except DeviceException: raise PlatformNotReady def set_work(**kwargs): """Set work.""" try: miio_device = Device(host, token) miio_device.send('set_work', [ kwargs["status"], kwargs["id"], kwargs["keep_temp"], kwargs["keep_time"], kwargs["timestamp"] ]) except DeviceException: raise PlatformNotReady def delete_modes(**kwargs): """Delete work.删除自定义模式""" try: miio_device = Device(host, token) miio_device.send('delete_modes', [kwargs["modes"]]) except DeviceException: raise PlatformNotReady def set_mode_sort(**kwargs): """Set mode sort.设置模式排序""" try: miio_device = Device(host, token) miio_device.send('set_mode_sort', [kwargs["sort"]]) except DeviceException: raise PlatformNotReady def set_mode(**kwargs): """Set mode.设置自定义模式""" try: miio_device = Device(host, token) miio_device.send('set_mode', [kwargs["id"], kwargs["heat"], kwargs["time"]]) except DeviceException: raise PlatformNotReady def service_handle(service): params = {key: value for key, value in service.data.items()} if service.service == SERVICE_SET_VOICE: set_voice(**params) if service.service == SERVICE_SET_WORK: set_work(**params) if service.service == SERVICE_DELETE_MODES: delete_modes(**params) if service.service == SERVICE_SET_MODE_SORT: set_mode_sort(**params) if service.service == SERVICE_SET_MODE: set_mode(**params) hass.services.register(DOMAIN, SERVICE_SET_VOICE, service_handle, schema=SERVICE_SCHEMA_SET_VOICE) hass.services.register(DOMAIN, SERVICE_SET_WORK, service_handle, schema=SERVICE_SCHEMA_SET_WORK) hass.services.register(DOMAIN, SERVICE_DELETE_MODES, service_handle, schema=SERVICE_SCHEMA_DEL_MODES) hass.services.register(DOMAIN, SERVICE_SET_MODE_SORT, service_handle, schema=SERVICE_SCHEMA_SET_MODE_SORT) hass.services.register(DOMAIN, SERVICE_SET_MODE, service_handle, schema=SERVICE_SCHEMA_SET_MODE) return True
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the miio fan device from config.""" if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config[CONF_HOST] name = config[CONF_NAME] token = config[CONF_TOKEN] model = config.get(CONF_MODEL) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) unique_id = None if model is None: miio_device = Device(host, token) try: device_info = miio_device.info() except DeviceException: raise PlatformNotReady model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info( "%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version, ) if model.startswith("nwt.derh."): air_dehumidifier = AirDehumidifier(host, token, model=model) device = XiaomiAirDehumidifier(name, air_dehumidifier, model, unique_id) else: _LOGGER.error( "Unsupported device found! Please create an issue at " "https://github.com/rytilahti/python-miio/issues " "and provide the following data: %s", model, ) return False hass.data[DATA_KEY][host] = device async_add_entities([device], update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiAirDehumidifier.""" method = SERVICE_TO_METHOD.get(service.service) params = { key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID } entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [ device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids ] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method["method"]): continue await getattr(device, method["method"])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks) for air_dehumidifier_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[air_dehumidifier_service].get( "schema", AIRDEHUMIDIFIER_SERVICE_SCHEMA ) hass.services.async_register( DOMAIN, air_dehumidifier_service, async_service_handler, schema=schema )
def setup(hass, config): # from miio import Device, DeviceException if DOMAIN not in hass.data: hass.data[DOMAIN] = {} host = config[DOMAIN][CONF_HOST] token = config[DOMAIN][CONF_TOKEN] name = config[DOMAIN][CONF_NAME] model = config[DOMAIN].get(CONF_MODEL) scan_interval = config[DOMAIN][CONF_SCAN_INTERVAL] if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} hass.data[DATA_KEY][host] = {} _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) devices = [] if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model _LOGGER.info( "%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version, ) except DeviceException: raise PlatformNotReady if model not in SUPPORTED_MODELS: _LOGGER.error( "Unsupported device found! Please create an issue at " "https://github.com/fineemb/Xiaomi-Smart-Multipurpose-Kettle/issues " "and provide the following data: %s", model, ) return False def update(event_time): """Get the latest data and updates the states.""" try: miio_device = Device(host, token) run_status = miio_device.send('get_prop', ["run_status"])[0] work_status = miio_device.send('get_prop', ["work_status"])[0] #warm_data = miio_device.send('get_prop', ["warm_data"])[0] last_time = miio_device.send('get_prop', ["last_time"])[0] last_temp = miio_device.send('get_prop', ["last_temp"])[0] curr_tempe = miio_device.send('get_prop', ["curr_tempe"])[0] # work_temps = miio_device.send('get_prop', ["work_temps"])[0] mode = miio_device.send('get_prop', ["mode"])[0] #模式 heat_power = miio_device.send('get_prop', ["heat_power"])[0] #功率 warm_time = miio_device.send('get_prop', ["warm_time"])[0] #保温时间 cook_time = miio_device.send('get_prop', ["cook_time"])[0] #蒸煮时间 left_time = miio_device.send('get_prop', ["left_time"])[0] #剩余时间 cook_status = miio_device.send('get_prop', ["cook_status"])[0] #蒸煮状态 cooked_time = miio_device.send('get_prop', ["cooked_time"])[0] voice = miio_device.send('get_prop', ["voice"])[0] stand_top_num = miio_device.send('get_prop', ["stand_top_num"])[0] #mode_sort = miio_device.send('get_prop', ["mode_sort"])[0] __state_attrs = { "run_status": AVAILABLE_RUN_STATUS[int(run_status)], "mode": AVAILABLE_MODE[int(mode)], "last_time": last_time, "last_temp": last_temp, "curr_tempe": curr_tempe, # "work_temps":work_temps, "heat_power": heat_power, "warm_time": warm_time, "cook_time": cook_time, "left_time": left_time, "cook_status": cook_status, "cooked_time": cooked_time, "voice": voice, "stand_top_num": stand_top_num, #"mode_sort":mode_sort, #"warm_data":warm_data, "friendly_name": name } unique_id = "{}_{}".format( "xiaomi", miio_device.info().mac_address.replace(':', '')) entityid = "{}.{}".format(DOMAIN, unique_id) hass.states.set(entityid, AVAILABLE_STATE[int(work_status)], __state_attrs) except DeviceException: _LOGGER.exception('Fail to get_prop from XiaomiHealthPot') raise PlatformNotReady track_time_interval(hass, update, scan_interval) def set_voice(voice: str): try: miio_device = Device(host, token) if voice == 'on': miio_device.send('set_voice', [0]) elif voice == 'off': miio_device.send('set_voice', [1]) except DeviceException: raise PlatformNotReady def set_work(**kwargs): """Set work.""" try: miio_device = Device(host, token) miio_device.send('set_work', [ kwargs["status"], kwargs["id"], kwargs["keep_temp"], kwargs["keep_time"], kwargs["timestamp"] ]) except DeviceException: raise PlatformNotReady def delete_modes(**kwargs): """Delete work.删除自定义模式""" try: miio_device = Device(host, token) miio_device.send('delete_modes', [kwargs["modes"]]) except DeviceException: raise PlatformNotReady def set_mode_sort(**kwargs): """Set mode sort.设置模式排序""" try: miio_device = Device(host, token) miio_device.send('set_mode_sort', [kwargs["sort"]]) except DeviceException: raise PlatformNotReady def set_mode(**kwargs): """Set mode.设置自定义模式""" try: miio_device = Device(host, token) miio_device.send('set_mode', [kwargs["id"], kwargs["heat"], kwargs["time"]]) except DeviceException: raise PlatformNotReady def service_handle(service): params = {key: value for key, value in service.data.items()} if service.service == SERVICE_SET_VOICE: set_voice(**params) if service.service == SERVICE_SET_WORK: set_work(**params) if service.service == SERVICE_DELETE_MODES: delete_modes(**params) if service.service == SERVICE_SET_MODE_SORT: set_mode_sort(**params) if service.service == SERVICE_SET_MODE: set_mode(**params) hass.services.register(DOMAIN, SERVICE_SET_VOICE, service_handle, schema=SERVICE_SCHEMA_SET_VOICE) hass.services.register(DOMAIN, SERVICE_SET_WORK, service_handle, schema=SERVICE_SCHEMA_SET_WORK) hass.services.register(DOMAIN, SERVICE_DELETE_MODES, service_handle, schema=SERVICE_SCHEMA_DEL_MODES) hass.services.register(DOMAIN, SERVICE_SET_MODE_SORT, service_handle, schema=SERVICE_SCHEMA_SET_MODE_SORT) hass.services.register(DOMAIN, SERVICE_SET_MODE, service_handle, schema=SERVICE_SCHEMA_SET_MODE) return True
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the light from config.""" from miio import Device, DeviceException if PLATFORM not in hass.data: hass.data[PLATFORM] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: light = Device(host, token) device_info = light.info() _LOGGER.info("%s %s %s initialized", device_info.model, device_info.firmware_version, device_info.hardware_version) if device_info.model == 'philips.light.sread1': from miio import PhilipsEyecare light = PhilipsEyecare(host, token) device = XiaomiPhilipsEyecareLamp(name, light, device_info) elif device_info.model == 'philips.light.ceiling': from miio import Ceil light = Ceil(host, token) device = XiaomiPhilipsCeilingLamp(name, light, device_info) elif device_info.model == 'philips.light.bulb': from miio import PhilipsBulb light = PhilipsBulb(host, token) device = XiaomiPhilipsLightBall(name, light, device_info) else: _LOGGER.error( 'Unsupported device found! Please create an issue at ' 'https://github.com/rytilahti/python-miio/issues ' 'and provide the following data: %s', device_info.model) return False except DeviceException: raise PlatformNotReady hass.data[PLATFORM][host] = device async_add_devices([device], update_before_add=True) @asyncio.coroutine def async_service_handler(service): """Map services to methods on Xiaomi Philips Lights.""" method = SERVICE_TO_METHOD.get(service.service) params = { key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID } entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: target_devices = [ dev for dev in hass.data[PLATFORM].values() if dev.entity_id in entity_ids ] else: target_devices = hass.data[PLATFORM].values() update_tasks = [] for target_device in target_devices: yield from getattr(target_device, method['method'])(**params) update_tasks.append(target_device.async_update_ha_state(True)) if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) for xiaomi_miio_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[xiaomi_miio_service].get( 'schema', XIAOMI_MIIO_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, xiaomi_miio_service, async_service_handler, schema=schema)
async def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the miio fan device from config.""" from miio import Device, DeviceException if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) model = config.get(CONF_MODEL) retries = config.get(CONF_RETRIES) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) unique_id = None if model is None: try: miio_device = Device(host, token) device_info = miio_device.info() model = device_info.model unique_id = "{}-{}".format(model, device_info.mac_address) _LOGGER.info( "%s %s %s detected", model, device_info.firmware_version, device_info.hardware_version, ) except DeviceException: raise PlatformNotReady if model in [ MODEL_FAN_V2, MODEL_FAN_V3, MODEL_FAN_SA1, MODEL_FAN_ZA1, MODEL_FAN_ZA3, MODEL_FAN_ZA4, ]: from miio import Fan fan = Fan(host, token, model=model) device = XiaomiFan(name, fan, model, unique_id, retries) elif model == MODEL_FAN_P5: from miio import FanP5 fan = FanP5(host, token, model=model) device = XiaomiFanP5(name, fan, model, unique_id, retries) else: _LOGGER.error( "Unsupported device found! Please create an issue at " "https://github.com/syssi/xiaomi_fan/issues " "and provide the following data: %s", model, ) return False hass.data[DATA_KEY][host] = device async_add_devices([device], update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiFan.""" method = SERVICE_TO_METHOD.get(service.service) params = { key: value for key, value in service.data.items() if key != ATTR_ENTITY_ID } entity_ids = service.data.get(ATTR_ENTITY_ID) if entity_ids: devices = [ device for device in hass.data[DATA_KEY].values() if device.entity_id in entity_ids ] else: devices = hass.data[DATA_KEY].values() update_tasks = [] for device in devices: if not hasattr(device, method["method"]): continue await getattr(device, method["method"])(**params) update_tasks.append(device.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) for air_purifier_service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[air_purifier_service].get( "schema", AIRPURIFIER_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, air_purifier_service, async_service_handler, schema=schema)
async def async_step_localinfo(self, user_input=None): # 2. 手动接入,本地通信信息 """Handle a flow initialized by the user.""" errors = {} # Check if already configured # await self.async_set_unique_id(DOMAIN) # self._abort_if_unique_id_configured() if user_input is not None: self._name = user_input[CONF_NAME] self._host = user_input[CONF_HOST] if user_input[CONF_TOKEN] == '0': user_input[CONF_TOKEN] = '0' * 32 self._token = user_input[CONF_TOKEN] self._input2 = {**self._input2, **user_input} device = MiioDevice(self._host, self._token) try: self._info = device.info() except DeviceException: errors['base'] = 'cannot_connect' # except ValueError: # errors['base'] = 'value_error' if self._info is not None: unique_id = format_mac(self._info.mac_address) # await self.async_set_unique_id(unique_id) for entry in self._async_current_entries(): if entry.unique_id == unique_id: persistent_notification.async_create( self.hass, f"您新添加的设备: **{self._name}** ,\n" f"其 MAC 地址与现有的某个设备相同。\n" f"只是通知,不会造成任何影响。", "设备可能重复") break self._abort_if_unique_id_configured() d = self._info.raw self._model = d['model'] device_info = (f"Model: {d['model']}\n" f"Firmware: {d['fw_ver']}\n" f"MAC: {d['mac']}\n") self._info = await guess_mp_from_model(self.hass, self._model) if self._info and self._info.get('mapping') != "{}": device_info += "\n已经自动发现配置参数。\n如无特殊需要,无需修改下列内容。\n" devtype_default = self._info.get('device_type') mp = self._info.get('mapping') prm = self._info.get('params') mapping_default = mp params_default = prm else: device_info += f"很抱歉,未能自动发现配置参数。但这不代表您的设备不受支持。\n您可以[手工编写配置](https://github.com/ha0y/xiaomi_miot_raw/#文件配置法),或者将型号 **{self._model}** 报告给作者。" devtype_default = ['switch'] mapping_default = '{"switch":{"switch_status":{"siid":2,"piid":1}}}' params_default = '{"switch":{"switch_status":{"power_on":true,"power_off":false}}}' if not self._non_interactive: return self.async_show_form( step_id="devinfo", data_schema=vol.Schema( { vol.Required('devtype', default=devtype_default): cv.multi_select(SUPPORTED_DOMAINS), vol.Required(CONF_MAPPING, default=mapping_default): str, vol.Required(CONF_CONTROL_PARAMS, default=params_default): str, vol.Optional('cloud_read'): bool, vol.Optional('cloud_write'): bool, }), description_placeholders={"device_info": device_info}, errors=errors, ) else: return await self.async_step_devinfo({ 'devtype': devtype_default, CONF_MAPPING: mapping_default, CONF_CONTROL_PARAMS: params_default, 'cloud_read': True, 'cloud_write': True, }) else: return await self.async_step_xiaoai( {CONF_MODEL: self._model} if self._model else None) return self.async_show_form( step_id="localinfo", data_schema=vol.Schema({ vol.Required(CONF_NAME): str, vol.Required(CONF_HOST, default='192.168.'): str, vol.Required(CONF_TOKEN): str, }), # description_placeholders={"device_info": "device_info"}, errors=errors, )