<commit_before>"""
Support for the Daikin HVAC.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/climate.daikin/
"""
import logging
import re

import voluptuous as vol

from homeassistant.components.climate import (
    ATTR_CURRENT_TEMPERATURE, ATTR_FAN_MODE, ATTR_OPERATION_MODE,
    ATTR_SWING_MODE, PLATFORM_SCHEMA, STATE_AUTO, STATE_COOL, STATE_DRY,
    STATE_FAN_ONLY, STATE_HEAT, STATE_OFF, SUPPORT_FAN_MODE,
    SUPPORT_OPERATION_MODE, SUPPORT_SWING_MODE, SUPPORT_TARGET_TEMPERATURE,
    ClimateDevice)
from homeassistant.components.daikin import (
    ATTR_INSIDE_TEMPERATURE, ATTR_OUTSIDE_TEMPERATURE, ATTR_TARGET_TEMPERATURE,
    daikin_api_setup)
from homeassistant.const import (
    ATTR_TEMPERATURE, CONF_HOST, CONF_NAME, TEMP_CELSIUS)
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['pydaikin==0.4']

_LOGGER = logging.getLogger(__name__)

SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE |
                 SUPPORT_FAN_MODE |
                 SUPPORT_OPERATION_MODE |
                 SUPPORT_SWING_MODE)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_HOST): cv.string,
    vol.Optional(CONF_NAME, default=None): cv.string,
})

HA_STATE_TO_DAIKIN = {
    STATE_FAN_ONLY: 'fan',
    STATE_DRY: 'dry',
    STATE_COOL: 'cool',
    STATE_HEAT: 'hot',
    STATE_AUTO: 'auto',
    STATE_OFF: 'off',
}

HA_ATTR_TO_DAIKIN = {
    ATTR_OPERATION_MODE: 'mode',
    ATTR_FAN_MODE: 'f_rate',
    ATTR_SWING_MODE: 'f_dir',
}


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Daikin HVAC platform."""
    if discovery_info is not None:
        host = discovery_info.get('ip')
        name = None
        _LOGGER.debug("Discovered a Daikin AC on %s", host)
    else:
        host = config.get(CONF_HOST)
        name = config.get(CONF_NAME)
        _LOGGER.debug("Added Daikin AC on %s", host)

    api = daikin_api_setup(hass, host, name)
    add_devices([DaikinClimate(api)], True)


class DaikinClimate(ClimateDevice):
    """Representation of a Daikin HVAC."""

    def __init__(self, api):
        """Initialize the climate device."""
        from pydaikin import appliance

        self._api = api
        self._force_refresh = False
        self._list = {
            ATTR_OPERATION_MODE: list(
                map(str.title, set(HA_STATE_TO_DAIKIN.values()))
            ),
            ATTR_FAN_MODE: list(
                map(
                    str.title,
                    appliance.daikin_values(HA_ATTR_TO_DAIKIN[ATTR_FAN_MODE])
                )
            ),
            ATTR_SWING_MODE: list(
                map(
                    str.title,
                    appliance.daikin_values(HA_ATTR_TO_DAIKIN[ATTR_SWING_MODE])
                )
            ),
        }

    def get(self, key):
        """Retrieve device settings from API library cache."""
        value = None
        cast_to_float = False

        if key in [ATTR_TEMPERATURE, ATTR_INSIDE_TEMPERATURE,
                   ATTR_CURRENT_TEMPERATURE]:
            value = self._api.device.values.get('htemp')
            cast_to_float = True
        if key == ATTR_TARGET_TEMPERATURE:
            value = self._api.device.values.get('stemp')
            cast_to_float = True
        elif key == ATTR_OUTSIDE_TEMPERATURE:
            value = self._api.device.values.get('otemp')
            cast_to_float = True
        elif key == ATTR_FAN_MODE:
            value = self._api.device.represent('f_rate')[1].title()
        elif key == ATTR_SWING_MODE:
            value = self._api.device.represent('f_dir')[1].title()
        elif key == ATTR_OPERATION_MODE:
            # Daikin can return also internal states auto-1 or auto-7
            # and we need to translate them as AUTO
            value = re.sub(
                '[^a-z]',
                '',
                self._api.device.represent('mode')[1]
            ).title()

        if value is None:
            _LOGGER.error("Invalid value requested for key %s", key)
        else:
            if value == "-" or value == "--":
                value = None
            elif cast_to_float:
                try:
                    value = float(value)
                except ValueError:
                    value = None

        return value

    def set(self, settings):
        """Set device settings using API."""
        values = {}

        for attr in [ATTR_TEMPERATURE, ATTR_FAN_MODE, ATTR_SWING_MODE,
                     ATTR_OPERATION_MODE]:
            value = settings.get(attr)
            if value is None:
                continue

            daikin_attr = HA_ATTR_TO_DAIKIN.get(attr)
            if daikin_attr is not None:
                if value.title() in self._list[attr]:
                    values[daikin_attr] = value.lower()
                else:
                    _LOGGER.error("Invalid value %s for %s", attr, value)

            # temperature
            elif attr == ATTR_TEMPERATURE:
                try:
                    values['stemp'] = str(int(value))
                except ValueError:
                    _LOGGER.error("Invalid temperature %s", value)

        if values:
            self._force_refresh = True
            self._api.device.set(values)

    @property
    def unique_id(self):
        """Return the ID of this AC."""
        return "{}.{}".format(self.__class__, self._api.ip_address)

    @property
    def supported_features(self):
        """Return the list of supported features."""
        return SUPPORT_FLAGS

    @property
    def name(self):
        """Return the name of the thermostat, if any."""
        return self._api.name<commit_msg>Handle Daikin AC adapters without fan mode and swing mode support (#11840)<commit_after>"""
Support for the Daikin HVAC.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/climate.daikin/
"""
import logging
import re

import voluptuous as vol

from homeassistant.components.climate import (
    ATTR_CURRENT_TEMPERATURE, ATTR_FAN_MODE, ATTR_OPERATION_MODE,
    ATTR_SWING_MODE, PLATFORM_SCHEMA, STATE_AUTO, STATE_COOL, STATE_DRY,
    STATE_FAN_ONLY, STATE_HEAT, STATE_OFF, SUPPORT_FAN_MODE,
    SUPPORT_OPERATION_MODE, SUPPORT_SWING_MODE, SUPPORT_TARGET_TEMPERATURE,
    ClimateDevice)
from homeassistant.components.daikin import (
    ATTR_INSIDE_TEMPERATURE, ATTR_OUTSIDE_TEMPERATURE, ATTR_TARGET_TEMPERATURE,
    daikin_api_setup)
from homeassistant.const import (
    ATTR_TEMPERATURE, CONF_HOST, CONF_NAME, TEMP_CELSIUS)
import homeassistant.helpers.config_validation as cv

REQUIREMENTS = ['pydaikin==0.4']

_LOGGER = logging.getLogger(__name__)

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_HOST): cv.string,
    vol.Optional(CONF_NAME, default=None): cv.string,
})

HA_STATE_TO_DAIKIN = {
    STATE_FAN_ONLY: 'fan',
    STATE_DRY: 'dry',
    STATE_COOL: 'cool',
    STATE_HEAT: 'hot',
    STATE_AUTO: 'auto',
    STATE_OFF: 'off',
}

HA_ATTR_TO_DAIKIN = {
    ATTR_OPERATION_MODE: 'mode',
    ATTR_FAN_MODE: 'f_rate',
    ATTR_SWING_MODE: 'f_dir',
    ATTR_INSIDE_TEMPERATURE: 'htemp',
    ATTR_OUTSIDE_TEMPERATURE: 'otemp',
    ATTR_TARGET_TEMPERATURE: 'stemp'
}


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Daikin HVAC platform."""
    if discovery_info is not None:
        host = discovery_info.get('ip')
        name = None
        _LOGGER.debug("Discovered a Daikin AC on %s", host)
    else:
        host = config.get(CONF_HOST)
        name = config.get(CONF_NAME)
        _LOGGER.debug("Added Daikin AC on %s", host)

    api = daikin_api_setup(hass, host, name)
    add_devices([DaikinClimate(api)], True)


class DaikinClimate(ClimateDevice):
    """Representation of a Daikin HVAC."""

    def __init__(self, api):
        """Initialize the climate device."""
        from pydaikin import appliance

        self._api = api
        self._force_refresh = False
        self._list = {
            ATTR_OPERATION_MODE: list(
                map(str.title, set(HA_STATE_TO_DAIKIN.values()))
            ),
            ATTR_FAN_MODE: list(
                map(
                    str.title,
                    appliance.daikin_values(HA_ATTR_TO_DAIKIN[ATTR_FAN_MODE])
                )
            ),
            ATTR_SWING_MODE: list(
                map(
                    str.title,
                    appliance.daikin_values(HA_ATTR_TO_DAIKIN[ATTR_SWING_MODE])
                )
            ),
        }

        self._supported_features = SUPPORT_TARGET_TEMPERATURE \
            | SUPPORT_OPERATION_MODE

        daikin_attr = HA_ATTR_TO_DAIKIN[ATTR_FAN_MODE]
        if self._api.device.values.get(daikin_attr) is not None:
            self._supported_features |= SUPPORT_FAN_MODE

        daikin_attr = HA_ATTR_TO_DAIKIN[ATTR_SWING_MODE]
        if self._api.device.values.get(daikin_attr) is not None:
            self._supported_features |= SUPPORT_SWING_MODE

    def get(self, key):
        """Retrieve device settings from API library cache."""
        value = None
        cast_to_float = False

        if key in [ATTR_TEMPERATURE, ATTR_INSIDE_TEMPERATURE,
                   ATTR_CURRENT_TEMPERATURE]:
            key = ATTR_INSIDE_TEMPERATURE

        daikin_attr = HA_ATTR_TO_DAIKIN.get(key)

        if key == ATTR_INSIDE_TEMPERATURE:
            value = self._api.device.values.get(daikin_attr)
            cast_to_float = True
        elif key == ATTR_TARGET_TEMPERATURE:
            value = self._api.device.values.get(daikin_attr)
            cast_to_float = True
        elif key == ATTR_OUTSIDE_TEMPERATURE:
            value = self._api.device.values.get(daikin_attr)
            cast_to_float = True
        elif key == ATTR_FAN_MODE:
            value = self._api.device.represent(daikin_attr)[1].title()
        elif key == ATTR_SWING_MODE:
            value = self._api.device.represent(daikin_attr)[1].title()
        elif key == ATTR_OPERATION_MODE:
            # Daikin can return also internal states auto-1 or auto-7
            # and we need to translate them as AUTO
            value = re.sub(
                '[^a-z]',
                '',
                self._api.device.represent(daikin_attr)[1]
            ).title()

        if value is None:
            _LOGGER.error("Invalid value requested for key %s", key)
        else:
            if value == "-" or value == "--":
                value = None
            elif cast_to_float:
                try:
                    value = float(value)
                except ValueError:
                    value = None

        return value

    def set(self, settings):
        """Set device settings using API."""
        values = {}

        for attr in [ATTR_TEMPERATURE, ATTR_FAN_MODE, ATTR_SWING_MODE,
                     ATTR_OPERATION_MODE]:
            value = settings.get(attr)
            if value is None:
                continue

            daikin_attr = HA_ATTR_TO_DAIKIN.get(attr)
            if daikin_attr is not None:
                if value.title() in self._list[attr]:
                    values[daikin_attr] = value.lower()
                else:
                    _LOGGER.error("Invalid value %s for %s", attr, value)

            # temperature
            elif attr == ATTR_TEMPERATURE:
                try:
                    values['stemp'] = str(int(value))
                except ValueError:
                    _LOGGER.error("Invalid temperature %s", value)

        if values:
            self._force_refresh = True
            self._api.device.set(values)

    @property
    def unique_id(self):
        """Return the ID of this AC."""
        return "{}.{}".format(self.__class__, self._api.ip_address)

    @property
    def supported_features(self):
        """Return the list of supported features."""
        return self._supported_features

    @property
    def name(self):
        """Return the name of the thermostat, if any."""
        return self._api.name
{'fraction_non_alphanumeric': 0.09273120425815036, 'fraction_numerical': 0.001580172987358616, 'mean_word_length': 2.100825167612171, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6529105', 'n_tokens_mistral': 3845, 'n_tokens_neox': 3675, 'n_words': 801}