def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the air conditioning companion from config.""" from miio import AirConditioningCompanion, 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 with host %s (token %s...)", host, token[:5]) try: device = AirConditioningCompanion(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 as ex: _LOGGER.error("Device unavailable or token incorrect: %s", ex) raise PlatformNotReady air_conditioning_companion = XiaomiAirConditioningCompanion( hass, name, device, unique_id) hass.data[DATA_KEY][host] = air_conditioning_companion async_add_devices([air_conditioning_companion], 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 air conditioning companion from config.""" from miio import AirConditioningCompanion, DeviceException host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) min_temp = config.get(CONF_MIN_TEMP) max_temp = config.get(CONF_MAX_TEMP) sensor_entity_id = config.get(CONF_SENSOR) _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: device = AirConditioningCompanion(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 as ex: _LOGGER.error("Device unavailable or token incorrect: %s", ex) raise PlatformNotReady async_add_devices([XiaomiAirConditioningCompanion( hass, name, device, unique_id, sensor_entity_id, min_temp, max_temp)], update_before_add=True)
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the air conditioning companion from config.""" from miio import AirConditioningCompanion, DeviceException global CONFIG_FILE global CONFIG_FILE_PATH CONFIG_FILE_PATH = hass.config.path(CONFIGURATION_FILE) CONFIG_FILE = load_json(CONFIG_FILE_PATH) try: save_json(CONFIG_FILE_PATH, CONFIG_FILE) except HomeAssistantError: _LOGGER.error("load climate's states failed") if CONFIG_FILE == {}: CONFIG_FILE[ATTR_DEVICES] = {} host = config.get(CONF_HOST) name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) min_temp = config.get(CONF_MIN_TEMP) max_temp = config.get(CONF_MAX_TEMP) sensor_entity_id = config.get(CONF_SENSOR) instructs = config.get(CONF_INSTRUCTS) fan_mode_list = config.get(CONF_FAN_MODE) operation_list = config.get(CONF_OPERATION) swing_list = config.get(CONF_SWING) aux_heat = config.get(CONF_AUX_HEAT) is_lumi = config.get(CONF_IS_LUMI) min_power = config.get(CONF_MIN_POWER) if fan_mode_list == None: fan_mode_list = 'Low,Medium,High,Auto' if operation_list == None: operation_list = 'Heat,Cool,Dehumidify,Ventilate' instructsMap = {} for instruct in instructs: parts = instruct.split(':', 1) if len(parts) > 1: instructsMap[parts[0]] = parts[1] _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: device = AirConditioningCompanion(host, token) device_info = device.info() model = device_info.model unique_id = "{}-{}-ir".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 async_add_devices([ XiaomiAirConditioningCompanion( hass, name, device, unique_id, sensor_entity_id, min_temp, max_temp, instructsMap, fan_mode_list, operation_list, swing_list, aux_heat, is_lumi, min_power) ], update_before_add=True)
def __init__(self, hass, name, host, token, sensor_entity_id, customize): """Initialize the climate device.""" self.hass = hass self._state = None self._state_attrs = { ATTR_AIR_CONDITION_MODEL: None, ATTR_AIR_CONDITION_POWER: None, ATTR_TEMPERATURE: None, ATTR_SWING_MODE: None, ATTR_FAN_SPEED: None, ATTR_OPERATION_MODE: None, ATTR_LOAD_POWER: None, ATTR_LED: None, } self._air_condition_model = None self._name = name if name else DEFAULT_NAME self._unit_of_measurement = TEMP_CELSIUS self._host = host self._token = token self._sensor_entity_id = sensor_entity_id self._customize = customize self._target_temperature = None self._target_humidity = None self._current_temperature = None self._current_humidity = None self._current_swing_mode = None self._current_operation = None self._current_fan_mode = None self._operation_list = DEFAULT_OPERATION_MODES self._away = None self._hold = None self._aux = None self._target_temperature_high = DEFAULT_MAX_TEMP self._target_temperature_low = DEFAULT_MIN_TEMP self._max_temp = DEFAULT_MAX_TEMP + 1 self._min_temp = DEFAULT_MIN_TEMP - 1 self._target_temp_step = DEFAULT_STEP if self._customize and ('fan' in self._customize): self._customize_fan_list = list(self._customize['fan']) self._fan_list = self._customize_fan_list else: self._fan_list = DEFAULT_FAN_MODES if self._customize and ('swing' in self._customize): self._customize_swing_list = list(self._customize['swing']) self._swing_list = self._customize_swing_list else: self._swing_list = DEFAULT_SWING_MODES if sensor_entity_id: async_track_state_change(hass, sensor_entity_id, self._async_sensor_changed) sensor_state = hass.states.get(sensor_entity_id) if sensor_state: self._async_update_temp(sensor_state) from miio import AirConditioningCompanion _LOGGER.info("initializing with host %s token %s", self._host, self._token) self._climate = AirConditioningCompanion(self._host, self._token)
class XiaomiAirConditioningCompanion(ClimateDevice): """Representation of a Xiaomi Air Conditioning Companion.""" def __init__(self, hass, name, host, token, sensor_entity_id, customize): """Initialize the climate device.""" self.hass = hass self._state = None self._state_attrs = { ATTR_AIR_CONDITION_MODEL: None, ATTR_AIR_CONDITION_POWER: None, ATTR_TEMPERATURE: None, ATTR_SWING_MODE: None, ATTR_FAN_SPEED: None, ATTR_OPERATION_MODE: None, ATTR_LOAD_POWER: None, ATTR_LED: None, } self._air_condition_model = None self._name = name if name else DEFAULT_NAME self._unit_of_measurement = TEMP_CELSIUS self._host = host self._token = token self._sensor_entity_id = sensor_entity_id self._customize = customize self._target_temperature = None self._target_humidity = None self._current_temperature = None self._current_humidity = None self._current_swing_mode = None self._current_operation = None self._current_fan_mode = None self._operation_list = DEFAULT_OPERATION_MODES self._away = None self._hold = None self._aux = None self._target_temperature_high = DEFAULT_MAX_TEMP self._target_temperature_low = DEFAULT_MIN_TEMP self._max_temp = DEFAULT_MAX_TEMP + 1 self._min_temp = DEFAULT_MIN_TEMP - 1 self._target_temp_step = DEFAULT_STEP if self._customize and ('fan' in self._customize): self._customize_fan_list = list(self._customize['fan']) self._fan_list = self._customize_fan_list else: self._fan_list = DEFAULT_FAN_MODES if self._customize and ('swing' in self._customize): self._customize_swing_list = list(self._customize['swing']) self._swing_list = self._customize_swing_list else: self._swing_list = DEFAULT_SWING_MODES if sensor_entity_id: async_track_state_change(hass, sensor_entity_id, self._async_sensor_changed) sensor_state = hass.states.get(sensor_entity_id) if sensor_state: self._async_update_temp(sensor_state) from miio import AirConditioningCompanion _LOGGER.info("initializing with host %s token %s", self._host, self._token) self._climate = AirConditioningCompanion(self._host, self._token) @callback def _async_update_temp(self, state): """Update thermostat with latest state from sensor.""" unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) try: self._current_temperature = self.hass.config.units.temperature( float(state.state), unit) except ValueError as ex: _LOGGER.error('Unable to update from sensor: %s', ex) @asyncio.coroutine def _async_sensor_changed(self, entity_id, old_state, new_state): """Handle temperature changes.""" if new_state is None: return self._async_update_temp(new_state) @asyncio.coroutine def _try_command(self, mask_error, func, *args, **kwargs): """Call a AC companion command handling error messages.""" from miio import DeviceException try: result = yield from self.hass.async_add_job( partial(func, *args, **kwargs)) _LOGGER.debug("Response received: %s", result) return result == SUCCESS except DeviceException as exc: _LOGGER.error(mask_error, exc) return False @asyncio.coroutine def async_turn_on(self: ToggleEntity, speed: str = None, **kwargs) -> None: """Turn the miio device on.""" result = yield from self._try_command( "Turning the miio device on failed.", self._climate.on) if result: self._state = True @asyncio.coroutine def async_turn_off(self: ToggleEntity, **kwargs) -> None: """Turn the miio device off.""" result = yield from self._try_command( "Turning the miio device off failed.", self._climate.off) if result: self._state = False @asyncio.coroutine def async_update(self): """Update the state of this climate device.""" from miio import DeviceException try: state = yield from self.hass.async_add_job(self._climate.status) _LOGGER.debug("Got new state: %s", state) self._state = state.is_on self._state_attrs = { ATTR_AIR_CONDITION_MODEL: state.air_condition_model, ATTR_AIR_CONDITION_POWER: state.air_condition_power, ATTR_TEMPERATURE: state.temperature, ATTR_SWING_MODE: state.swing_mode, ATTR_FAN_SPEED: state.fan_speed.name, ATTR_OPERATION_MODE: state.mode.name, ATTR_LOAD_POWER: state.load_power, ATTR_LED: state.led, } if self._air_condition_model is None: self._air_condition_model = state.air_condition_model self._current_operation = state.mode.name.lower() # BUG? The target_temperature shoudn't be updated here. # It's fine if state.temperature contains the target temperature. # self._target_temperature = state.temperature if (not self._customize) or (self._customize and 'fan' not in self._customize): self._current_fan_mode = state.fan_speed.name.lower() if (not self._customize) or (self._customize and 'swing' not in self._customize): self._current_swing_mode = \ STATE_ON if state.swing_mode else STATE_OFF if not self._sensor_entity_id: self._current_temperature = state.temperature except DeviceException as ex: self._state = None _LOGGER.error("Got exception while fetching the state: %s", ex) @property def supported_features(self): """Return the list of supported features.""" return SUPPORT_FLAGS @property def min_temp(self): """Return the minimum temperature.""" return self._min_temp @property def max_temp(self): """Return the maximum temperature.""" return self._max_temp @property def target_temperature_step(self): """Return the target temperature step.""" return self._target_temp_step @property def should_poll(self): """Return the polling state.""" return True @property def name(self): """Return the name of the climate device.""" return self._name @property def available(self): """Return true when state is known.""" return self._state is not None @property def temperature_unit(self): """Return the unit of measurement.""" return self._unit_of_measurement @property def current_temperature(self): """Return the current temperature.""" return self._current_temperature @property def target_temperature(self): """Return the temperature we try to reach.""" return self._target_temperature @property def target_temperature_high(self): """Return the upper bound of the target temperature we try to reach.""" return self._target_temperature_high @property def target_temperature_low(self): """Return the lower bound of the target temperature we try to reach.""" return self._target_temperature_low @property def current_humidity(self): """Return the current humidity.""" return self._current_humidity @property def target_humidity(self): """Return the humidity we try to reach.""" return self._target_humidity @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" return self._current_operation @property def operation_list(self): """Return the list of available operation modes.""" return self._operation_list @property def is_away_mode_on(self): """Return if away mode is on.""" return self._away @property def current_hold_mode(self): """Return hold mode setting.""" return self._hold @property def is_aux_heat_on(self): """Return true if aux heat is on.""" return self._aux @property def current_fan_mode(self): """Return the current fan mode.""" return self._current_fan_mode @property def fan_list(self): """Return the list of available fan modes.""" return self._fan_list @property def is_on(self) -> bool: """Return True if the entity is on""" return self._state @asyncio.coroutine def async_set_temperature(self, **kwargs): """Set target temperature.""" if kwargs.get(ATTR_TEMPERATURE) is not None: self._target_temperature = kwargs.get(ATTR_TEMPERATURE) if kwargs.get(ATTR_TARGET_TEMP_HIGH) is not None and \ kwargs.get(ATTR_TARGET_TEMP_LOW) is not None: self._target_temperature_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) self._target_temperature_low = kwargs.get(ATTR_TARGET_TEMP_LOW) if kwargs.get(ATTR_OPERATION_MODE) is not None: self._current_operation = kwargs.get(ATTR_OPERATION_MODE) else: if self._target_temperature < self._target_temperature_low: self._current_operation = STATE_OFF self._target_temperature = self._target_temperature_low elif self._target_temperature > self._target_temperature_high: self._current_operation = STATE_OFF self._target_temperature = self._target_temperature_high elif self._current_temperature and ( self._current_operation == STATE_OFF or self._current_operation == STATE_IDLE): self._current_operation = STATE_AUTO self._send_configuration() @asyncio.coroutine def async_set_humidity(self, humidity): """Set the target humidity.""" self._target_humidity = humidity @asyncio.coroutine def async_set_swing_mode(self, swing_mode): """Set target temperature.""" self._current_swing_mode = swing_mode if self._customize and ('swing' in self._customize) and \ (self._current_swing_mode in self._customize['swing']): self._send_custom_command( self._customize['swing'][self._current_swing_mode]) else: self._send_configuration() @asyncio.coroutine def async_set_fan_mode(self, fan): """Set the fan mode.""" self._current_fan_mode = fan if self._customize and ('fan' in self._customize) and \ (self._current_fan_mode in self._customize['fan']): self._send_custom_command( self._customize['fan'][self._current_fan_mode]) else: self._send_configuration() @asyncio.coroutine def async_set_operation_mode(self, operation_mode): """Set operation mode.""" self._current_operation = operation_mode self._send_configuration() @property def current_swing_mode(self): """Return the current swing setting.""" return self._current_swing_mode @property def swing_list(self): """List of available swing modes.""" return self._swing_list @asyncio.coroutine def async_turn_away_mode_on(self): """Turn away mode on.""" self._away = True @asyncio.coroutine def async_turn_away_mode_off(self): """Turn away mode off.""" self._away = False @asyncio.coroutine def async_set_hold_mode(self, hold): """Update hold mode on.""" self._hold = hold @asyncio.coroutine def async_turn_aux_heat_on(self): """Turn auxillary heater on.""" self._aux = True @asyncio.coroutine def async_turn_aux_heat_off(self): """Turn auxiliary heater off.""" self._aux = False def _send_configuration(self): from miio.airconditioningcompanion import \ Power, OperationMode, FanSpeed, SwingMode, Led if self._air_condition_model is not None: yield from self._try_command( "Sending new air conditioner configuration failed.", self._climate.send_configuration( self._air_condition_model, Power(int(self._state)), OperationMode[self._current_operation.title()], self._target_temperature, FanSpeed[self._current_fan_mode.title()], SwingMode[self._current_swing_mode.title()], Led.Off, ), False) else: _LOGGER.error('Model number of the air condition unknown. ' 'Configuration cannot be sent.') def _send_custom_command(self, command: str): if command[0:2] == "01": yield from self._try_command( "Sending new air conditioner configuration failed.", self._climate.send_command(command), False) else: # Learned infrared commands has the prefix 'FE' yield from self._try_command( "Sending new air conditioner configuration failed.", self._climate.send_ir_code(command), False)
def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the air conditioning companion from config.""" from miio import AirConditioningCompanion, 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) min_temp = config.get(CONF_MIN_TEMP) max_temp = config.get(CONF_MAX_TEMP) sensor_entity_id = config.get(CONF_SENSOR) autoSwitch = config.get(CONF_AUTOSWITCH) ir_config_file_path = config.get(CONF_IR_CONFIG_FILE_PATH) try: f = open(ir_config_file_path, 'r', -1, "utf-8") jData = json.load(f) XiaomiAirConditioningCompanion.IR_CODES_MAP = dict(jData['command']) f.close() _LOGGER.info("Got IR map: %s", XiaomiAirConditioningCompanion.IR_CODES_MAP) except IOError: _LOGGER.warning("can not open ir config file:%s", ir_config_file_path) except ValueError: _LOGGER.warning("can not decode ir config file:%s", ir_config_file_path) if f.closed == False: f.close() _LOGGER.info("Initializing with host %s (token %s...)", host, token[:5]) try: device = AirConditioningCompanion(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 as ex: _LOGGER.error("Device unavailable or token incorrect: %s", ex) raise PlatformNotReady air_conditioning_companion = XiaomiAirConditioningCompanion( hass, name, device, unique_id, sensor_entity_id, min_temp, max_temp, autoSwitch, ir_config_file_path) hass.data[DATA_KEY][host] = air_conditioning_companion async_add_devices([air_conditioning_companion], 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)
from miio import AirConditioningCompanion, DeviceException import time xiaomi = AirConditioningCompanion("YOUR IP", "YOUR TOKEN") minTemp = 18 maxTemp = 30 result = "" def prompt(msg): while True: str = input(msg) str = str.lower() if str == 'y' or str == 'yes': return True if str == 'n' or str == 'no': return False if str == 'r' or str == 'p': print(result) def readKey(): while True: xiaomi.send("start_ir_learn", [30]) loop = 0 while xiaomi.send("get_ir_learn_result", []) == ['(null)' ] and loop < 15: time.sleep(1) loop = loop + 1 if loop >= 15:
from miio import AirConditioningCompanion, DeviceException import time xiaomi = AirConditioningCompanion("192.168.2.237", "1111bee4474f0fa15e2e1c970c78c34e") print(xiaomi.status()) while True: print(xiaomi.send("start_ir_learn", [30])) loop = 0 while xiaomi.send("get_ir_learn_result", []) == ['(null)'] and loop < 15: time.sleep(1) loop = loop + 1 if loop >= 15: continue ir_code = "".join(xiaomi.send("get_ir_learn_result", [])) if ir_code: code_list = list(ir_code) code_list[14:26] = '94701FFF96FF' sub = ir_code[34:36] check = hex(int(sub, 16) - 68)[2:] if len(check) == 1: check = '0' + check code_list[33:36] = '7' + check ir_code = ''.join(code_list) print(ir_code)