* Climate 1.0 / part 1/2/3 * fix flake * Lint * Update Google Assistant * ambiclimate to climate 1.0 (#24911) * Fix Alexa * Lint * Migrate zhong_hong * Migrate tuya * Migrate honeywell to new climate schema (#24257) * Update one * Fix model climate v2 * Cleanup p4 * Add comfort hold mode * Fix old code * Update homeassistant/components/climate/__init__.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * Update homeassistant/components/climate/const.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * First renaming * Rename operation to hvac for paulus * Rename hold mode to preset mode * Cleanup & update comments * Remove on/off * Fix supported feature count * Update services * Update demo * Fix tests & use current_hvac * Update comment * Fix tests & add typing * Add more typing * Update modes * Fix tests * Cleanup low/high with range * Update homematic part 1 * Finish homematic * Fix lint * fix hm mapping * Support simple devices * convert lcn * migrate oem * Fix xs1 * update hive * update mil * Update toon * migrate deconz * cleanup * update tesla * Fix lint * Fix vera * Migrate zwave * Migrate velbus * Cleanup humity feature * Cleanup * Migrate wink * migrate dyson * Fix current hvac * Renaming * Fix lint * Migrate tfiac * migrate tado * Fix PRESET can be None * apply PR#23913 from dev * remove EU component, etc. * remove EU component, etc. * ready to test now * de-linted * some tweaks * de-lint * better handling of edge cases * delint * fix set_mode typos * apply PR#23913 from dev * remove EU component, etc. * ready to test now * de-linted * some tweaks * de-lint * better handling of edge cases * delint * fix set_mode typos * delint, move debug code * away preset now working * code tidy-up * code tidy-up 2 * code tidy-up 3 * address issues #18932, #15063 * address issues #18932, #15063 - 2/2 * refactor MODE_AUTO to MODE_HEAT_COOL and use F not C * add low/high to set_temp * add low/high to set_temp 2 * add low/high to set_temp - delint * run HA scripts * port changes from PR #24402 * manual rebase * manual rebase 2 * delint * minor change * remove SUPPORT_HVAC_ACTION * Migrate radiotherm * Convert touchline * Migrate flexit * Migrate nuheat * Migrate maxcube * Fix names maxcube const * Migrate proliphix * Migrate heatmiser * Migrate fritzbox * Migrate opentherm_gw * Migrate venstar * Migrate daikin * Migrate modbus * Fix elif * Migrate Homematic IP Cloud to climate-1.0 (#24913) * hmip climate fix * Update hvac_mode and preset_mode * fix lint * Fix lint * Migrate generic_thermostat * Migrate incomfort to new climate schema (#24915) * initial commit * Update climate.py * Migrate eq3btsmart * Lint * cleanup PRESET_MANUAL * Migrate ecobee * No conditional features * KNX: Migrate climate component to new climate platform (#24931) * Migrate climate component * Remove unused code * Corrected line length * Lint * Lint * fix tests * Fix value * Migrate geniushub to new climate schema (#24191) * Update one * Fix model climate v2 * Cleanup p4 * Add comfort hold mode * Fix old code * Update homeassistant/components/climate/__init__.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * Update homeassistant/components/climate/const.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * First renaming * Rename operation to hvac for paulus * Rename hold mode to preset mode * Cleanup & update comments * Remove on/off * Fix supported feature count * Update services * Update demo * Fix tests & use current_hvac * Update comment * Fix tests & add typing * Add more typing * Update modes * Fix tests * Cleanup low/high with range * Update homematic part 1 * Finish homematic * Fix lint * fix hm mapping * Support simple devices * convert lcn * migrate oem * Fix xs1 * update hive * update mil * Update toon * migrate deconz * cleanup * update tesla * Fix lint * Fix vera * Migrate zwave * Migrate velbus * Cleanup humity feature * Cleanup * Migrate wink * migrate dyson * Fix current hvac * Renaming * Fix lint * Migrate tfiac * migrate tado * delinted * delinted * use latest client * clean up mappings * clean up mappings * add duration to set_temperature * add duration to set_temperature * manual rebase * tweak * fix regression * small fix * fix rebase mixup * address comments * finish refactor * fix regression * tweak type hints * delint * manual rebase * WIP: Fixes for honeywell migration to climate-1.0 (#24938) * add type hints * code tidy-up * Fixes for incomfort migration to climate-1.0 (#24936) * delint type hints * no async unless await * revert: no async unless await * revert: no async unless await 2 * delint * fix typo * Fix homekit_controller on climate-1.0 (#24948) * Fix tests on climate-1.0 branch * As part of climate-1.0, make state return the heating-cooling.current characteristic * Fixes from review * lint * Fix imports * Migrate stibel_eltron * Fix lint * Migrate coolmaster to climate 1.0 (#24967) * Migrate coolmaster to climate 1.0 * fix lint errors * More lint fixes * Fix demo to work with UI * Migrate spider * Demo update * Updated frontend to 20190705.0 * Fix boost mode (#24980) * Prepare Netatmo for climate 1.0 (#24973) * Migration Netatmo * Address comments * Update climate.py * Migrate ephember * Migrate Sensibo * Implemented review comments (#24942) * Migrate ESPHome * Migrate MQTT * Migrate Nest * Migrate melissa * Initial/partial migration of ST * Migrate ST * Remove Away mode (#24995) * Migrate evohome, cache access tokens (#24491) * add water_heater, add storage - initial commit * add water_heater, add storage - initial commit delint add missing code desiderata update honeywell client library & CODEOWNER add auth_tokens code, refactor & delint refactor for broker delint * Add Broker, Water Heater & Refactor add missing code desiderata * update honeywell client library & CODEOWNER add auth_tokens code, refactor & delint refactor for broker * bugfix - loc_idx may not be 0 more refactor - ensure pure async more refactoring appears all r/o attributes are working tweak precsion, DHW & delint remove unused code remove unused code 2 remove unused code, refactor _save_auth_tokens() * support RoundThermostat bugfix opmode, switch to util.dt, add until=1h revert breaking change * store at_expires as naive UTC remove debug code delint tidy up exception handling delint add water_heater, add storage - initial commit delint add missing code desiderata update honeywell client library & CODEOWNER add auth_tokens code, refactor & delint refactor for broker add water_heater, add storage - initial commit delint add missing code desiderata update honeywell client library & CODEOWNER add auth_tokens code, refactor & delint refactor for broker delint bugfix - loc_idx may not be 0 more refactor - ensure pure async more refactoring appears all r/o attributes are working tweak precsion, DHW & delint remove unused code remove unused code 2 remove unused code, refactor _save_auth_tokens() support RoundThermostat bugfix opmode, switch to util.dt, add until=1h revert breaking change store at_expires as naive UTC remove debug code delint tidy up exception handling delint * update CODEOWNERS * fix regression * fix requirements * migrate to climate-1.0 * tweaking * de-lint * TCS working? & delint * tweaking * TCS code finalised * remove available() logic * refactor _switchpoints() * tidy up switchpoint code * tweak * teaking device_state_attributes * some refactoring * move PRESET_CUSTOM back to evohome * move CONF_ACCESS_TOKEN_EXPIRES CONF_REFRESH_TOKEN back to evohome * refactor SP code and dt conversion * delinted * delinted * remove water_heater * fix regression * Migrate homekit * Cleanup away mode * Fix tests * add helpers * fix tests melissa * Fix nehueat * fix zwave * add more tests * fix deconz * Fix climate test emulate_hue * fix tests * fix dyson tests * fix demo with new layout * fix honeywell * Switch homekit_controller to use HVAC_MODE_HEAT_COOL instead of HVAC_MODE_AUTO (#25009) * Lint * PyLint * Pylint * fix fritzbox tests * Fix google * Fix all tests * Fix lint * Fix auto for homekit like controler * Fix lint * fix lint
604 lines
18 KiB
Python
604 lines
18 KiB
Python
"""Alexa capabilities."""
|
|
from datetime import datetime
|
|
import logging
|
|
|
|
from homeassistant.const import (
|
|
ATTR_SUPPORTED_FEATURES,
|
|
ATTR_TEMPERATURE,
|
|
ATTR_UNIT_OF_MEASUREMENT,
|
|
STATE_LOCKED,
|
|
STATE_OFF,
|
|
STATE_ON,
|
|
STATE_UNAVAILABLE,
|
|
STATE_UNLOCKED,
|
|
)
|
|
import homeassistant.components.climate.const as climate
|
|
from homeassistant.components import (
|
|
light,
|
|
fan,
|
|
cover,
|
|
)
|
|
import homeassistant.util.color as color_util
|
|
|
|
from .const import (
|
|
API_TEMP_UNITS,
|
|
API_THERMOSTAT_MODES,
|
|
API_THERMOSTAT_PRESETS,
|
|
DATE_FORMAT,
|
|
PERCENTAGE_FAN_MAP,
|
|
)
|
|
from .errors import UnsupportedProperty
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class AlexaCapibility:
|
|
"""Base class for Alexa capability interfaces.
|
|
|
|
The Smart Home Skills API defines a number of "capability interfaces",
|
|
roughly analogous to domains in Home Assistant. The supported interfaces
|
|
describe what actions can be performed on a particular device.
|
|
|
|
https://developer.amazon.com/docs/device-apis/message-guide.html
|
|
"""
|
|
|
|
def __init__(self, entity):
|
|
"""Initialize an Alexa capibility."""
|
|
self.entity = entity
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
raise NotImplementedError
|
|
|
|
@staticmethod
|
|
def properties_supported():
|
|
"""Return what properties this entity supports."""
|
|
return []
|
|
|
|
@staticmethod
|
|
def properties_proactively_reported():
|
|
"""Return True if properties asynchronously reported."""
|
|
return False
|
|
|
|
@staticmethod
|
|
def properties_retrievable():
|
|
"""Return True if properties can be retrieved."""
|
|
return False
|
|
|
|
@staticmethod
|
|
def get_property(name):
|
|
"""Read and return a property.
|
|
|
|
Return value should be a dict, or raise UnsupportedProperty.
|
|
|
|
Properties can also have a timeOfSample and uncertaintyInMilliseconds,
|
|
but returning those metadata is not yet implemented.
|
|
"""
|
|
raise UnsupportedProperty(name)
|
|
|
|
@staticmethod
|
|
def supports_deactivation():
|
|
"""Applicable only to scenes."""
|
|
return None
|
|
|
|
def serialize_discovery(self):
|
|
"""Serialize according to the Discovery API."""
|
|
result = {
|
|
'type': 'AlexaInterface',
|
|
'interface': self.name(),
|
|
'version': '3',
|
|
'properties': {
|
|
'supported': self.properties_supported(),
|
|
'proactivelyReported': self.properties_proactively_reported(),
|
|
'retrievable': self.properties_retrievable(),
|
|
},
|
|
}
|
|
|
|
# pylint: disable=assignment-from-none
|
|
supports_deactivation = self.supports_deactivation()
|
|
if supports_deactivation is not None:
|
|
result['supportsDeactivation'] = supports_deactivation
|
|
return result
|
|
|
|
def serialize_properties(self):
|
|
"""Return properties serialized for an API response."""
|
|
for prop in self.properties_supported():
|
|
prop_name = prop['name']
|
|
# pylint: disable=assignment-from-no-return
|
|
prop_value = self.get_property(prop_name)
|
|
if prop_value is not None:
|
|
yield {
|
|
'name': prop_name,
|
|
'namespace': self.name(),
|
|
'value': prop_value,
|
|
'timeOfSample': datetime.now().strftime(DATE_FORMAT),
|
|
'uncertaintyInMilliseconds': 0
|
|
}
|
|
|
|
|
|
class AlexaEndpointHealth(AlexaCapibility):
|
|
"""Implements Alexa.EndpointHealth.
|
|
|
|
https://developer.amazon.com/docs/smarthome/state-reporting-for-a-smart-home-skill.html#report-state-when-alexa-requests-it
|
|
"""
|
|
|
|
def __init__(self, hass, entity):
|
|
"""Initialize the entity."""
|
|
super().__init__(entity)
|
|
self.hass = hass
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.EndpointHealth'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'connectivity'}]
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return False
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'connectivity':
|
|
raise UnsupportedProperty(name)
|
|
|
|
if self.entity.state == STATE_UNAVAILABLE:
|
|
return {'value': 'UNREACHABLE'}
|
|
return {'value': 'OK'}
|
|
|
|
|
|
class AlexaPowerController(AlexaCapibility):
|
|
"""Implements Alexa.PowerController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-powercontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.PowerController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'powerState'}]
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'powerState':
|
|
raise UnsupportedProperty(name)
|
|
|
|
if self.entity.domain == climate.DOMAIN:
|
|
is_on = self.entity.state != climate.HVAC_MODE_OFF
|
|
|
|
else:
|
|
is_on = self.entity.state != STATE_OFF
|
|
|
|
return 'ON' if is_on else 'OFF'
|
|
|
|
|
|
class AlexaLockController(AlexaCapibility):
|
|
"""Implements Alexa.LockController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-lockcontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.LockController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'lockState'}]
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'lockState':
|
|
raise UnsupportedProperty(name)
|
|
|
|
if self.entity.state == STATE_LOCKED:
|
|
return 'LOCKED'
|
|
if self.entity.state == STATE_UNLOCKED:
|
|
return 'UNLOCKED'
|
|
return 'JAMMED'
|
|
|
|
|
|
class AlexaSceneController(AlexaCapibility):
|
|
"""Implements Alexa.SceneController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-scenecontroller.html
|
|
"""
|
|
|
|
def __init__(self, entity, supports_deactivation):
|
|
"""Initialize the entity."""
|
|
super().__init__(entity)
|
|
self.supports_deactivation = lambda: supports_deactivation
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.SceneController'
|
|
|
|
|
|
class AlexaBrightnessController(AlexaCapibility):
|
|
"""Implements Alexa.BrightnessController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-brightnesscontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.BrightnessController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'brightness'}]
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'brightness':
|
|
raise UnsupportedProperty(name)
|
|
if 'brightness' in self.entity.attributes:
|
|
return round(self.entity.attributes['brightness'] / 255.0 * 100)
|
|
return 0
|
|
|
|
|
|
class AlexaColorController(AlexaCapibility):
|
|
"""Implements Alexa.ColorController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-colorcontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.ColorController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'color'}]
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'color':
|
|
raise UnsupportedProperty(name)
|
|
|
|
hue, saturation = self.entity.attributes.get(
|
|
light.ATTR_HS_COLOR, (0, 0))
|
|
|
|
return {
|
|
'hue': hue,
|
|
'saturation': saturation / 100.0,
|
|
'brightness': self.entity.attributes.get(
|
|
light.ATTR_BRIGHTNESS, 0) / 255.0,
|
|
}
|
|
|
|
|
|
class AlexaColorTemperatureController(AlexaCapibility):
|
|
"""Implements Alexa.ColorTemperatureController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-colortemperaturecontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.ColorTemperatureController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'colorTemperatureInKelvin'}]
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'colorTemperatureInKelvin':
|
|
raise UnsupportedProperty(name)
|
|
if 'color_temp' in self.entity.attributes:
|
|
return color_util.color_temperature_mired_to_kelvin(
|
|
self.entity.attributes['color_temp'])
|
|
return 0
|
|
|
|
|
|
class AlexaPercentageController(AlexaCapibility):
|
|
"""Implements Alexa.PercentageController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-percentagecontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.PercentageController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'percentage'}]
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'percentage':
|
|
raise UnsupportedProperty(name)
|
|
|
|
if self.entity.domain == fan.DOMAIN:
|
|
speed = self.entity.attributes.get(fan.ATTR_SPEED)
|
|
|
|
return PERCENTAGE_FAN_MAP.get(speed, 0)
|
|
|
|
if self.entity.domain == cover.DOMAIN:
|
|
return self.entity.attributes.get(cover.ATTR_CURRENT_POSITION, 0)
|
|
|
|
return 0
|
|
|
|
|
|
class AlexaSpeaker(AlexaCapibility):
|
|
"""Implements Alexa.Speaker.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-speaker.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.Speaker'
|
|
|
|
|
|
class AlexaStepSpeaker(AlexaCapibility):
|
|
"""Implements Alexa.StepSpeaker.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-stepspeaker.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.StepSpeaker'
|
|
|
|
|
|
class AlexaPlaybackController(AlexaCapibility):
|
|
"""Implements Alexa.PlaybackController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-playbackcontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.PlaybackController'
|
|
|
|
|
|
class AlexaInputController(AlexaCapibility):
|
|
"""Implements Alexa.InputController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-inputcontroller.html
|
|
"""
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.InputController'
|
|
|
|
|
|
class AlexaTemperatureSensor(AlexaCapibility):
|
|
"""Implements Alexa.TemperatureSensor.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-temperaturesensor.html
|
|
"""
|
|
|
|
def __init__(self, hass, entity):
|
|
"""Initialize the entity."""
|
|
super().__init__(entity)
|
|
self.hass = hass
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.TemperatureSensor'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'temperature'}]
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'temperature':
|
|
raise UnsupportedProperty(name)
|
|
|
|
unit = self.entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
|
temp = self.entity.state
|
|
if self.entity.domain == climate.DOMAIN:
|
|
unit = self.hass.config.units.temperature_unit
|
|
temp = self.entity.attributes.get(
|
|
climate.ATTR_CURRENT_TEMPERATURE)
|
|
return {
|
|
'value': float(temp),
|
|
'scale': API_TEMP_UNITS[unit],
|
|
}
|
|
|
|
|
|
class AlexaContactSensor(AlexaCapibility):
|
|
"""Implements Alexa.ContactSensor.
|
|
|
|
The Alexa.ContactSensor interface describes the properties and events used
|
|
to report the state of an endpoint that detects contact between two
|
|
surfaces. For example, a contact sensor can report whether a door or window
|
|
is open.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-contactsensor.html
|
|
"""
|
|
|
|
def __init__(self, hass, entity):
|
|
"""Initialize the entity."""
|
|
super().__init__(entity)
|
|
self.hass = hass
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.ContactSensor'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'detectionState'}]
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'detectionState':
|
|
raise UnsupportedProperty(name)
|
|
|
|
if self.entity.state == STATE_ON:
|
|
return 'DETECTED'
|
|
return 'NOT_DETECTED'
|
|
|
|
|
|
class AlexaMotionSensor(AlexaCapibility):
|
|
"""Implements Alexa.MotionSensor.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-motionsensor.html
|
|
"""
|
|
|
|
def __init__(self, hass, entity):
|
|
"""Initialize the entity."""
|
|
super().__init__(entity)
|
|
self.hass = hass
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.MotionSensor'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
return [{'name': 'detectionState'}]
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name != 'detectionState':
|
|
raise UnsupportedProperty(name)
|
|
|
|
if self.entity.state == STATE_ON:
|
|
return 'DETECTED'
|
|
return 'NOT_DETECTED'
|
|
|
|
|
|
class AlexaThermostatController(AlexaCapibility):
|
|
"""Implements Alexa.ThermostatController.
|
|
|
|
https://developer.amazon.com/docs/device-apis/alexa-thermostatcontroller.html
|
|
"""
|
|
|
|
def __init__(self, hass, entity):
|
|
"""Initialize the entity."""
|
|
super().__init__(entity)
|
|
self.hass = hass
|
|
|
|
def name(self):
|
|
"""Return the Alexa API name of this interface."""
|
|
return 'Alexa.ThermostatController'
|
|
|
|
def properties_supported(self):
|
|
"""Return what properties this entity supports."""
|
|
properties = [{'name': 'thermostatMode'}]
|
|
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
|
if supported & climate.SUPPORT_TARGET_TEMPERATURE:
|
|
properties.append({'name': 'targetSetpoint'})
|
|
if supported & climate.SUPPORT_TARGET_TEMPERATURE_RANGE:
|
|
properties.append({'name': 'lowerSetpoint'})
|
|
properties.append({'name': 'upperSetpoint'})
|
|
return properties
|
|
|
|
def properties_proactively_reported(self):
|
|
"""Return True if properties asynchronously reported."""
|
|
return True
|
|
|
|
def properties_retrievable(self):
|
|
"""Return True if properties can be retrieved."""
|
|
return True
|
|
|
|
def get_property(self, name):
|
|
"""Read and return a property."""
|
|
if name == 'thermostatMode':
|
|
preset = self.entity.attributes.get(climate.ATTR_PRESET_MODE)
|
|
|
|
if preset in API_THERMOSTAT_PRESETS:
|
|
mode = API_THERMOSTAT_PRESETS[preset]
|
|
else:
|
|
mode = API_THERMOSTAT_MODES.get(self.entity.state)
|
|
if mode is None:
|
|
_LOGGER.error(
|
|
"%s (%s) has unsupported state value '%s'",
|
|
self.entity.entity_id, type(self.entity),
|
|
self.entity.state)
|
|
raise UnsupportedProperty(name)
|
|
return mode
|
|
|
|
unit = self.hass.config.units.temperature_unit
|
|
if name == 'targetSetpoint':
|
|
temp = self.entity.attributes.get(ATTR_TEMPERATURE)
|
|
elif name == 'lowerSetpoint':
|
|
temp = self.entity.attributes.get(climate.ATTR_TARGET_TEMP_LOW)
|
|
elif name == 'upperSetpoint':
|
|
temp = self.entity.attributes.get(climate.ATTR_TARGET_TEMP_HIGH)
|
|
else:
|
|
raise UnsupportedProperty(name)
|
|
|
|
if temp is None:
|
|
return None
|
|
|
|
return {
|
|
'value': float(temp),
|
|
'scale': API_TEMP_UNITS[unit],
|
|
}
|