diff --git a/Capture.PNG b/Capture.PNG deleted file mode 100644 index aa37e07..0000000 Binary files a/Capture.PNG and /dev/null differ diff --git a/Capture2.PNG b/Capture2.PNG deleted file mode 100644 index f5a9ed5..0000000 Binary files a/Capture2.PNG and /dev/null differ diff --git a/README.md b/README.md index 492edcc..e0bbba2 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,18 @@ This is a platform to support Fujitsu General Airconditioners under Climate comp ### Sample UI: -![UI_SCREENSHOT](https://github.com/Mmodarre/pyfujitsu_for_homeassistant/blob/master/Capture.PNG) -![UI_SCREENSHOT](https://github.com/Mmodarre/pyfujitsu_for_homeassistant/blob/master/Capture2.PNG) +![UI_SCREENSHOT](https://raw.githubusercontent.com/xerxes87/pyfujitsu_for_homeassistant/master/ha_fujitsu.jpg) ### Usage: 1. create this directory path `/config/custom_components/fujitsu_general_heatpump/` if it does not already exist. -2. Download the `fujitsu_general_heatpump.py` `manifest.json' and 'init.py` from the repo and place it in the directory mentioned in previous step. Rename `fujitsu_general_heatpump.py` to `climate.py` +2. Download the `climate.py` `manifest.json' and '__init__.py` from the repo and place it in the directory mentioned in previous step. So the end result would look like: `/config/custom_components/fujitsu_general_heatpump/climate.py` `/config/custom_components/fujitsu_general_heatpump/manifest.json` -`/config/custom_components/fujitsu_general_heatpump/init.py` +`/config/custom_components/fujitsu_general_heatpump/__init__.py` 3. add the below lines to your `configuration.yaml` file and replace it with your FGLair app username/password: ``` @@ -24,13 +23,26 @@ climate: - platform: fujitsu_general_heatpump username: password: + region: [eu, cn, us] (optional, default: us) + tokenpath: (optional, default: 'token.txt') ``` + +Full Example: +``` +climate: + - platform: fujitsu_general_heatpump + username: !secret FGLAIR_USER + password: !secret FGLAIR_PASS + region: 'eu' + tokenpath: 'token.txt' +``` + 4. Restart Home Assistant in order for the new component to show and all of your A/Cs in your account should appear in HASS. ### Known issues and missing features: -[RESOLVED]1. Google Assistant integration is not working [most possibly due to states not matching what Google assistant is expecting] -2. Logging needs to be implemented -3. The “powerful” functionality is implemented through aux_heat button in UI -4. There are some other functionalities in the A/C which currently is not implemented. -5. Could not reverse engineer the API to give the ambient room temperature. If you figured it out let me know and I am happy to update the library. + +- [X] Logging needs to be implemented +- [ ] The “powerful” functionality is implemented through aux_heat button in UI +- [ ] There are some other functionalities in the A/C which currently is not implemented. +- [ ] Possibility to add external temerature sensor diff --git a/custom_components/fujitsu_general_heatpump/__init__.py b/custom_components/fujitsu_general_heatpump/__init__.py new file mode 100644 index 0000000..2e153dd --- /dev/null +++ b/custom_components/fujitsu_general_heatpump/__init__.py @@ -0,0 +1 @@ +""" fujitsu_general_heatpump integration.""" \ No newline at end of file diff --git a/custom_components/fujitsu_general_heatpump/climate.py b/custom_components/fujitsu_general_heatpump/climate.py new file mode 100644 index 0000000..c08c7fe --- /dev/null +++ b/custom_components/fujitsu_general_heatpump/climate.py @@ -0,0 +1,242 @@ +""" +Support for the Fujitsu General Split A/C Wifi platform AKA FGLair . +""" + +import logging +import voluptuous as vol +from pyfujitseu.api import Api as fgapi +from pyfujitseu.splitAC import splitAC + + +from homeassistant.components.climate import ClimateEntity, PLATFORM_SCHEMA +from homeassistant.components.climate.const import ( + HVAC_MODE_OFF, + HVAC_MODE_HEAT, + HVAC_MODE_COOL, + HVAC_MODE_AUTO, + HVAC_MODE_DRY, + HVAC_MODE_FAN_ONLY, + SUPPORT_FAN_MODE, + SUPPORT_SWING_MODE, + SUPPORT_TARGET_TEMPERATURE, + SUPPORT_AUX_HEAT, + FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH, FAN_DIFFUSE, + CURRENT_HVAC_HEAT, + CURRENT_HVAC_IDLE) +from homeassistant.const import ( + ATTR_TEMPERATURE, CONF_USERNAME, CONF_PASSWORD, TEMP_CELSIUS) +import homeassistant.helpers.config_validation as cv + +__version__ = '0.9.1' + + + +_LOGGER = logging.getLogger(__name__) + +#REQUIREMENTS = ['pyfujitseu==0.9.3.2'] + +# Values from web interface +MIN_TEMP = 16 +MAX_TEMP = 30 + +SUPPORT_FLAGS = SUPPORT_FAN_MODE | SUPPORT_SWING_MODE | SUPPORT_TARGET_TEMPERATURE + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional('region'): cv.string, + vol.Optional('tokenpath'): cv.string, + +}) + + +HA_FAN_TO_FUJITSU = { + FAN_AUTO: "Auto", + FAN_LOW: "Low", + FAN_MEDIUM: "Medium", + FAN_HIGH: "High", + FAN_DIFFUSE: "Quiet" +} + +FUJITSU_FAN_TO_HA = { + "Auto": FAN_AUTO, + "Low": FAN_LOW, + "Medium": FAN_MEDIUM, + "High": FAN_HIGH, + "Quiet": FAN_DIFFUSE +} + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Setup the E-Thermostaat Platform.""" + + _LOGGER.debug("FujitsuClimate setup_platform called") + _LOGGER.debug("FujitsuClimate setup_platform called") + + username = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + region = config.get('region') + tokenpath = config.get('tokenpath') + _LOGGER.debug("FujitsuClimate config.get ") + + fglairapi = fgapi(username, password, region, tokenpath) + if not fglairapi._authenticate(): + _LOGGER.error("Unable to authenticate with Fujistsu General") + return + + _LOGGER.debug("FujitsuClimate fglairapi._authenticate ") + + devices = fglairapi.get_devices_dsn() + add_entities(FujitsuClimate(fglairapi, dsn) for dsn in devices) + _LOGGER.debug("FujitsuClimate setup_platform fine") + + +class FujitsuClimate(ClimateEntity): + """Representation of a E-Thermostaat device.""" + + def __init__(self, api, dsn): + """Initialize the thermostat.""" + _LOGGER.debug("FujitsuClimate init called for dsn: %s", dsn) + _LOGGER.debug("FujitsuClimate pyfujitseu.splitAC called") + self._api = api + self._dsn = dsn + self._fujitsu_device = splitAC(self._dsn, self._api) + _LOGGER.debug("FujitsuClimate _fujitsu_device setup.") + self._name = self.name + _LOGGER.debug("FujitsuClimate name set: %s", self._name) + self._aux_heat = self.is_aux_heat_on + self._target_temperature = self.target_temperature + self._fan_mode = self.fan_mode + self._hvac_mode = self.hvac_mode + self._swing_mode = self.swing_mode + + self._fan_modes = [FUJITSU_FAN_TO_HA['Quiet'], FAN_LOW, FAN_MEDIUM, FAN_HIGH, FAN_AUTO] + self._hvac_modes = [HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_AUTO, HVAC_MODE_DRY, HVAC_MODE_FAN_ONLY, HVAC_MODE_OFF] + self._swing_modes = ['Horizontal' ,'Down', 'Unknown', 'Swing' ] + self._on = self.is_on + + + _LOGGER.debug("FujitsuClimate init fine.") + + @property + def name(self): + """Return the name of the thermostat.""" + return self._fujitsu_device.device_name['value'] + + @property + def is_aux_heat_on(self): + """Reusing is for Powerfull mode.""" + if not hasattr(self._fujitsu_device.powerful_mode, 'value'): + return False + elif self._fujitsu_device.powerful_mode['value'] == 1: + return True + else: + return False + + @property + def target_temperature(self): + """Return the temperature we try to reach.""" + return self._fujitsu_device.adjust_temperature_degree + + @property + def target_temperature_step(self): + """Return the supported step of target temperature.""" + return 1 + + + @property + def is_on(self): + """Return true if on.""" + if self._fujitsu_device.operation_mode['value'] != 0: + return True + else: + return False + + @property + def hvac_mode(self): + """Return current operation ie. heat, cool, idle.""" + _LOGGER.debug("FujitsuClimate hvac_mode: %s", self._fujitsu_device.operation_mode['value']) + return self._fujitsu_device.operation_mode_desc + + @property + def hvac_modes(self): + """HVAC modes.""" + return self._hvac_modes + + def set_hvac_mode(self, hvac_mode): + """Set HVAC mode.""" + _LOGGER.debug("FujitsuClimate set_hvac_mode called. self._hvac_mode: %s ; hvac_mode: %s", self._hvac_mode, hvac_mode) + if(hvac_mode == HVAC_MODE_OFF): + self._fujitsu_device.turnOff() + elif(self._hvac_mode != hvac_mode): + _LOGGER.debug("FujitsuClimate set_hvac_mode elif path called. ") + self._fujitsu_device.changeOperationMode(hvac_mode) + + def set_temperature(self, **kwargs): + """Set new target temperature.""" + _LOGGER.debug("FujitsuClimate set_temperature: %s ; 2: %s", kwargs.get(ATTR_TEMPERATURE), kwargs.get(ATTR_TEMPERATURE)) + self._fujitsu_device.changeTemperature(kwargs.get(ATTR_TEMPERATURE)) + + def update(self): + """Retrieve latest state.""" + self._fujitsu_device.refresh_properties() + + @property + def fan_mode(self): + """Return the fan setting.""" + return FUJITSU_FAN_TO_HA[self._fujitsu_device.get_fan_speed_desc()] + + @property + def fan_modes(self): + """Return the list of available fan modes.""" + return self._fan_modes + + def set_fan_mode(self, fan_mode): + """Set fan mode.""" + self._fujitsu_device.changeFanSpeed(HA_FAN_TO_FUJITSU[fan_mode]) + + @property + def swing_mode(self): + """Return the fan setting.""" + return self._fujitsu_device.get_swing_mode_desc() + + @property + def swing_modes(self): + """List of available swing modes.""" + return self._swing_modes + + def set_swing_mode(self, swing_mode): + """Set new target temperature.""" + self._fujitsu_device.changeSwingMode(swing_mode) + +############old stufffff + + @property + def unique_id(self) -> str: + """Return the unique ID for this thermostat.""" + return '_'.join([self._name, 'climate']) + + @property + def should_poll(self): + """Polling is required.""" + return True + + @property + def min_temp(self): + """Return the minimum temperature.""" + return MIN_TEMP + + @property + def max_temp(self): + """Return the maximum temperature.""" + return MAX_TEMP + + @property + def temperature_unit(self): + """Return the unit of measurement.""" + return TEMP_CELSIUS + + @property + def supported_features(self): + """Return the list of supported features.""" + return SUPPORT_FLAGS \ No newline at end of file diff --git a/custom_components/fujitsu_general_heatpump/manifest.json b/custom_components/fujitsu_general_heatpump/manifest.json new file mode 100644 index 0000000..0db67cc --- /dev/null +++ b/custom_components/fujitsu_general_heatpump/manifest.json @@ -0,0 +1,12 @@ +{ + "domain": "fujitsu_general_heatpump", + "name": "Fujitsu general heatpump", + "documentation": "https://github.com/Mmodarre/pyfujitsu_for_homeassistant/blob/master/README.md", + "requirements": ["pyfujitseu"], + "dependencies": [], + "codeowners": [ + "@Mmodarre", + "@xerxes87" + ], + "version": "1.0.0" +} \ No newline at end of file diff --git a/fujitsu_general_heatpump.py b/fujitsu_general_heatpump.py deleted file mode 100644 index 18c5a43..0000000 --- a/fujitsu_general_heatpump.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -Support for the Fujitsu General Split A/C Wifi platform AKA FGLair . - -""" - -import logging -import voluptuous as vol - -from homeassistant.components.climate import ( - PLATFORM_SCHEMA, - ClimateDevice -) - -from homeassistant.components.climate.const import ( - ATTR_AWAY_MODE, ATTR_CURRENT_TEMPERATURE, ATTR_FAN_MODE, - ATTR_OPERATION_MODE, ATTR_SWING_MODE, STATE_AUTO, STATE_COOL, STATE_DRY, - STATE_FAN_ONLY, STATE_HEAT, SUPPORT_AWAY_MODE, SUPPORT_FAN_MODE, - SUPPORT_ON_OFF, SUPPORT_OPERATION_MODE, SUPPORT_SWING_MODE, - SUPPORT_TARGET_TEMPERATURE, SUPPORT_AUX_HEAT -) - -from homeassistant.const import (ATTR_TEMPERATURE, CONF_USERNAME, CONF_PASSWORD, TEMP_CELSIUS,STATE_ON, STATE_OFF,STATE_ON) -import homeassistant.helpers.config_validation as cv - -REQUIREMENTS = ['pyfujitsu==0.8.1.1'] - - -_LOGGER = logging.getLogger(__name__) - -SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_USERNAME): cv.string, - vol.Optional(CONF_PASSWORD): cv.string, -}) - -HA_STATE_TO_FUJITSU = { - STATE_FAN_ONLY: 'Fan', - STATE_DRY: 'Dry', - STATE_COOL: 'Cool', - STATE_HEAT: 'Heat', - STATE_AUTO: 'Auto', - STATE_OFF: 'Off', - STATE_ON: 'On' -} - -FUJITSU_TO_HA_STATE = { - 'Fan': STATE_FAN_ONLY, - 'Dry': STATE_DRY, - 'Cool': STATE_COOL, - 'Heat': STATE_HEAT, - 'Auto': STATE_AUTO, - 'fan': STATE_FAN_ONLY, - 'dry': STATE_DRY, - 'cool': STATE_COOL, - 'heat': STATE_HEAT, - 'Auto': STATE_AUTO, - - 'Off': STATE_OFF, - 'off': STATE_OFF, - - 'On': STATE_ON, - 'on': STATE_ON -} - -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up the Fujitsu Split platform.""" - import pyfujitsu.api as fgapi - username = config.get(CONF_USERNAME) - password = config.get(CONF_PASSWORD) - _LOGGER.debug("Added Fujitsu Account for username: %s ", username) - - fglairapi = fgapi.Api(username, password) - if not fglairapi._authenticate(): - _LOGGER.error("Unable to authenticate with Fujistsu General") - return - - devices = fglairapi.get_devices_dsn() - add_entities(FujitsuClimate(fglairapi, dsn) for dsn in devices) - -class FujitsuClimate(ClimateDevice): - """Representation of a Fujitsu Heatpump.""" - - def __init__(self, api, dsn): - #from homeassistant.components.pyfujitsu import splitAC - from pyfujitsu import splitAC - self._api = api - self._dsn = dsn - self._fujitsu_device = splitAC.splitAC(self._dsn, self._api) - self._name = self.name - self._aux_heat = self.is_aux_heat_on - self._target_temperature = self.target_temperature - self._unit_of_measurement = self.unit_of_measurement - self._current_fan_mode = self.current_fan_mode - self._current_operation = FUJITSU_TO_HA_STATE[self.current_operation] - self._current_swing_mode = self.current_swing_mode - self._fan_list = ['Quiet', 'Low', 'Medium', 'High', 'Auto'] - self._operation_list = [FUJITSU_TO_HA_STATE['Heat'], FUJITSU_TO_HA_STATE['Cool'], FUJITSU_TO_HA_STATE['Auto'], FUJITSU_TO_HA_STATE['Dry'], FUJITSU_TO_HA_STATE['Fan'],FUJITSU_TO_HA_STATE['Off'],FUJITSU_TO_HA_STATE['On']] - self._swing_list = ['Vertical Swing','Horizontal Swing', 'Vertical high', - 'Vertical Mid', 'Vertical Low' ] - self._target_temperature_high = self.target_temperature_high - self._target_temperature_low = self.target_temperature_low - self._on = self.is_on - self._supported_features = SUPPORT_TARGET_TEMPERATURE \ - | SUPPORT_OPERATION_MODE | SUPPORT_FAN_MODE \ - | SUPPORT_SWING_MODE | SUPPORT_ON_OFF | SUPPORT_AUX_HEAT - - @property - def name(self): - """Return the name of the climate device.""" - return self._fujitsu_device.device_name['value'] - - - @property - def temperature_unit(self): - """Return the unit of measurement used by the platform.""" - return TEMP_CELSIUS - - - @property - def current_operation(self): - """Return current operation ie. heat, cool, idle.""" - return FUJITSU_TO_HA_STATE[self._fujitsu_device.operation_mode_desc] - - @property - def operation_list(self): - """Return the list of available operation modes.""" - return self._operation_list - - @property - def target_temperature(self): - """Return the temperature we try to reach.""" - return self._fujitsu_device.adjust_temperature_degree - - @property - def target_temperature_step(self): - """Return the supported step of target temperature.""" - return 0.5 - - @property - def powerfull_mode(self): - """ Return Powerfull mode state""" - return self._fujitsu_device.powerful_mode - - - @property - def is_on(self): - """Return true if on.""" - if self._fujitsu_device.operation_mode['value'] != 0: - return True - else: - return False - - @property - def current_fan_mode(self): - """Return the fan setting.""" - return self._fujitsu_device.get_fan_speed_desc() - - @property - def fan_list(self): - """Return the list of available fan modes.""" - return self._fan_list - - @property - ## Todo combine swing modes in to one - def current_swing_mode(self): - """Return the fan setting.""" - return self._fujitsu_device.af_horizontal_direction['value'] - - @property - def swing_list(self): - """Return the list of available swing modes.""" - return self._swing_list - - def set_temperature(self, **kwargs): - """Set new target temperature.""" - self._fujitsu_device.changeTemperature(kwargs.get(ATTR_TEMPERATURE)) - - def set_fan_mode(self, fan_mode): - """Set new target fan mode.""" - print(fan_mode) - self._fujitsu_device.changeFanSpeed(fan_mode) - - def set_operation_mode(self, operation_mode): - """Set new target operation mode.""" - self._fujitsu_device.changeOperationMode(operation_mode) - -# def set_swing_mode(self, swing_mode): -# """Set new target swing operation.""" -# raise NotImplementedError() - - def turn_on(self): - """Turn device on.""" - return self._fujitsu_device.turnOn() - - - def turn_off(self): - """Turn device off.""" - return self._fujitsu_device.turnOff() - - @property - def is_aux_heat_on(self): - """Reusing is for Powerfull mode.""" - if self._fujitsu_device.powerful_mode['value'] == 1: - return True - else: - return False - - def turn_aux_heat_on(self): - """Reusing is for Powerfull mode.""" - self._fujitsu_device.powerfull_mode_on() - - def turn_aux_heat_off(self): - """Reusing is for Powerfull mode.""" - self._fujitsu_device.powerfull_mode_off() - - @property - def supported_features(self): - """Return the list of supported features.""" - return self._supported_features - - def update(self): - """Retrieve latest state.""" - self._fujitsu_device.refresh_properties() diff --git a/ha_fujitsu.jpg b/ha_fujitsu.jpg new file mode 100644 index 0000000..159ea59 Binary files /dev/null and b/ha_fujitsu.jpg differ diff --git a/init.py b/init.py deleted file mode 100644 index 8b13789..0000000 --- a/init.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/manifest.json b/manifest.json deleted file mode 100644 index 26a1335..0000000 --- a/manifest.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "domain": "https://github.com/Mmodarre/pyfujitsu_for_homeassistant", - "name": "fujitsu_general_heatpump", - "documentation": "https://github.com/Mmodarre/pyfujitsu_for_homeassistant/blob/master/README.md", - "dependencies": [], - "codeowners": [], - "requirements": ["pyfujitsu==0.8.1.1"] - }