예제 #1
0
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)
예제 #2
0
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)
예제 #3
0
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)
예제 #7
0
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:
예제 #8
0
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)