mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 06:07:17 +00:00
commit
82a5c23c9c
@ -4,7 +4,7 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/ambient_station",
|
||||
"requirements": [
|
||||
"aioambient==0.3.2"
|
||||
"aioambient==1.0.2"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
|
@ -3,10 +3,7 @@
|
||||
"name": "Auth",
|
||||
"documentation": "https://www.home-assistant.io/integrations/auth",
|
||||
"requirements": [],
|
||||
"dependencies": [
|
||||
"http"
|
||||
],
|
||||
"codeowners": [
|
||||
"@home-assistant/core"
|
||||
]
|
||||
"dependencies": ["http"],
|
||||
"after_dependencies": ["onboarding"],
|
||||
"codeowners": ["@home-assistant/core"]
|
||||
}
|
||||
|
@ -3,11 +3,6 @@
|
||||
"name": "Camera",
|
||||
"documentation": "https://www.home-assistant.io/integrations/camera",
|
||||
"requirements": [],
|
||||
"dependencies": [
|
||||
"http"
|
||||
],
|
||||
"after_dependencies": [
|
||||
"stream"
|
||||
],
|
||||
"dependencies": ["http"],
|
||||
"codeowners": []
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/cast",
|
||||
"requirements": ["pychromecast==4.0.1"],
|
||||
"dependencies": [],
|
||||
"after_dependencies": ["cloud"],
|
||||
"zeroconf": ["_googlecast._tcp.local."],
|
||||
"codeowners": []
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
"name": "Flume",
|
||||
"documentation": "https://www.home-assistant.io/integrations/flume/",
|
||||
"requirements": [
|
||||
"pyflume==0.2.1"
|
||||
"pyflume==0.2.4"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@ChrisMandich"]
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,11 +37,14 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
password = config[CONF_PASSWORD]
|
||||
client_id = config[CONF_CLIENT_ID]
|
||||
client_secret = config[CONF_CLIENT_SECRET]
|
||||
flume_token_file = hass.config.path("FLUME_TOKEN_FILE")
|
||||
time_zone = str(hass.config.time_zone)
|
||||
name = config[CONF_NAME]
|
||||
flume_entity_list = []
|
||||
|
||||
flume_devices = FlumeDeviceList(username, password, client_id, client_secret)
|
||||
flume_devices = FlumeDeviceList(
|
||||
username, password, client_id, client_secret, flume_token_file
|
||||
)
|
||||
|
||||
for device in flume_devices.device_list:
|
||||
if device["type"] == FLUME_TYPE_SENSOR:
|
||||
@ -53,6 +56,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
device["id"],
|
||||
time_zone,
|
||||
SCAN_INTERVAL,
|
||||
flume_token_file,
|
||||
)
|
||||
flume_entity_list.append(FlumeSensor(flume, f"{name} {device['id']}"))
|
||||
|
||||
|
@ -4,5 +4,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/google_assistant",
|
||||
"requirements": [],
|
||||
"dependencies": ["http"],
|
||||
"after_dependencies": ["camera"],
|
||||
"codeowners": ["@home-assistant/cloud"]
|
||||
}
|
||||
|
@ -35,7 +35,12 @@ from homeassistant.components.light import (
|
||||
Light,
|
||||
preprocess_turn_on_alternatives,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_MODE, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_MODE,
|
||||
ENTITY_MATCH_ALL,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
@ -369,6 +374,9 @@ class LIFXManager:
|
||||
|
||||
async def async_service_to_entities(self, service):
|
||||
"""Return the known entities that a service call mentions."""
|
||||
if service.data.get(ATTR_ENTITY_ID) == ENTITY_MATCH_ALL:
|
||||
return self.entities.values()
|
||||
|
||||
entity_ids = await async_extract_entity_ids(self.hass, service)
|
||||
return [
|
||||
entity
|
||||
|
@ -3,9 +3,7 @@
|
||||
"name": "Logbook",
|
||||
"documentation": "https://www.home-assistant.io/integrations/logbook",
|
||||
"requirements": [],
|
||||
"dependencies": [
|
||||
"frontend",
|
||||
"recorder"
|
||||
],
|
||||
"dependencies": ["frontend", "http", "recorder"],
|
||||
"after_dependencies": ["homekit"],
|
||||
"codeowners": []
|
||||
}
|
||||
|
@ -37,9 +37,7 @@ class RegistrationsView(HomeAssistantView):
|
||||
|
||||
webhook_id = generate_secret()
|
||||
|
||||
cloud_loaded = "cloud" in hass.config.components
|
||||
|
||||
if cloud_loaded and hass.components.cloud.async_active_subscription():
|
||||
if hass.components.cloud.async_active_subscription():
|
||||
data[
|
||||
CONF_CLOUDHOOK_URL
|
||||
] = await hass.components.cloud.async_create_cloudhook(webhook_id)
|
||||
@ -59,11 +57,10 @@ class RegistrationsView(HomeAssistantView):
|
||||
)
|
||||
|
||||
remote_ui_url = None
|
||||
if cloud_loaded:
|
||||
try:
|
||||
remote_ui_url = hass.components.cloud.async_remote_ui_url()
|
||||
except hass.components.cloud.CloudNotAvailable:
|
||||
pass
|
||||
try:
|
||||
remote_ui_url = hass.components.cloud.async_remote_ui_url()
|
||||
except hass.components.cloud.CloudNotAvailable:
|
||||
pass
|
||||
|
||||
return self.json(
|
||||
{
|
||||
|
@ -5,5 +5,6 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/mobile_app",
|
||||
"requirements": ["PyNaCl==1.3.0"],
|
||||
"dependencies": ["http", "webhook"],
|
||||
"after_dependencies": ["cloud"],
|
||||
"codeowners": ["@robbiet480"]
|
||||
}
|
||||
|
@ -190,10 +190,7 @@ async def handle_webhook(
|
||||
|
||||
device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
identifiers={
|
||||
(ATTR_DEVICE_ID, registration[ATTR_DEVICE_ID]),
|
||||
(CONF_WEBHOOK_ID, registration[CONF_WEBHOOK_ID]),
|
||||
},
|
||||
identifiers={(DOMAIN, registration[ATTR_DEVICE_ID])},
|
||||
manufacturer=new_registration[ATTR_MANUFACTURER],
|
||||
model=new_registration[ATTR_MODEL],
|
||||
name=new_registration[ATTR_DEVICE_NAME],
|
||||
@ -309,10 +306,9 @@ async def handle_webhook(
|
||||
if CONF_CLOUDHOOK_URL in registration:
|
||||
resp[CONF_CLOUDHOOK_URL] = registration[CONF_CLOUDHOOK_URL]
|
||||
|
||||
if "cloud" in hass.config.components:
|
||||
try:
|
||||
resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url()
|
||||
except hass.components.cloud.CloudNotAvailable:
|
||||
pass
|
||||
try:
|
||||
resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url()
|
||||
except hass.components.cloud.CloudNotAvailable:
|
||||
pass
|
||||
|
||||
return webhook_response(resp, registration=registration, headers=headers)
|
||||
|
@ -115,7 +115,7 @@ async def websocket_delete_registration(
|
||||
except HomeAssistantError:
|
||||
return error_message(msg["id"], "internal_error", "Error deleting registration")
|
||||
|
||||
if CONF_CLOUDHOOK_URL in registration and "cloud" in hass.config.components:
|
||||
if CONF_CLOUDHOOK_URL in registration:
|
||||
await hass.components.cloud.async_delete_cloudhook(webhook_id)
|
||||
|
||||
connection.send_message(result_message(msg["id"], "ok"))
|
||||
|
@ -3,11 +3,6 @@
|
||||
"name": "Onboarding",
|
||||
"documentation": "https://www.home-assistant.io/integrations/onboarding",
|
||||
"requirements": [],
|
||||
"dependencies": [
|
||||
"auth",
|
||||
"http"
|
||||
],
|
||||
"codeowners": [
|
||||
"@home-assistant/core"
|
||||
]
|
||||
"dependencies": ["auth", "http", "person"],
|
||||
"codeowners": ["@home-assistant/core"]
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ async def async_unload_entry(hass, entry):
|
||||
|
||||
async def async_remove_entry(hass, entry):
|
||||
"""Remove an OwnTracks config entry."""
|
||||
if not entry.data.get("cloudhook") or "cloud" not in hass.config.components:
|
||||
if not entry.data.get("cloudhook"):
|
||||
return
|
||||
|
||||
await hass.components.cloud.async_delete_cloudhook(entry.data[CONF_WEBHOOK_ID])
|
||||
|
@ -66,10 +66,7 @@ class OwnTracksFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
async def _get_webhook_id(self):
|
||||
"""Generate webhook ID."""
|
||||
webhook_id = self.hass.components.webhook.async_generate_id()
|
||||
if (
|
||||
"cloud" in self.hass.config.components
|
||||
and self.hass.components.cloud.async_active_subscription()
|
||||
):
|
||||
if self.hass.components.cloud.async_active_subscription():
|
||||
webhook_url = await self.hass.components.cloud.async_create_cloudhook(
|
||||
webhook_id
|
||||
)
|
||||
|
@ -3,14 +3,8 @@
|
||||
"name": "Owntracks",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/owntracks",
|
||||
"requirements": [
|
||||
"PyNaCl==1.3.0"
|
||||
],
|
||||
"dependencies": [
|
||||
"webhook"
|
||||
],
|
||||
"after_dependencies": [
|
||||
"mqtt"
|
||||
],
|
||||
"requirements": ["PyNaCl==1.3.0"],
|
||||
"dependencies": ["webhook"],
|
||||
"after_dependencies": ["mqtt", "cloud"],
|
||||
"codeowners": []
|
||||
}
|
||||
|
@ -7,7 +7,13 @@ import logging
|
||||
from PIL import Image
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.camera import PLATFORM_SCHEMA, Camera
|
||||
from homeassistant.components.camera import (
|
||||
PLATFORM_SCHEMA,
|
||||
Camera,
|
||||
async_get_image,
|
||||
async_get_mjpeg_stream,
|
||||
async_get_still_stream,
|
||||
)
|
||||
from homeassistant.const import CONF_ENTITY_ID, CONF_MODE, CONF_NAME
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
@ -227,7 +233,7 @@ class ProxyCamera(Camera):
|
||||
return self._last_image
|
||||
|
||||
self._last_image_time = now
|
||||
image = await self.hass.components.camera.async_get_image(self._proxied_camera)
|
||||
image = await async_get_image(self.hass, self._proxied_camera)
|
||||
if not image:
|
||||
_LOGGER.error("Error getting original camera image")
|
||||
return self._last_image
|
||||
@ -247,12 +253,12 @@ class ProxyCamera(Camera):
|
||||
async def handle_async_mjpeg_stream(self, request):
|
||||
"""Generate an HTTP MJPEG stream from camera images."""
|
||||
if not self._stream_opts:
|
||||
return await self.hass.components.camera.async_get_mjpeg_stream(
|
||||
request, self._proxied_camera
|
||||
return await async_get_mjpeg_stream(
|
||||
self.hass, request, self._proxied_camera
|
||||
)
|
||||
|
||||
return await self.hass.components.camera.async_get_still_stream(
|
||||
request, self._async_stream_image, self.content_type, self.frame_interval
|
||||
return await async_get_still_stream(
|
||||
request, self._async_stream_image, self.content_type, self.frame_interval,
|
||||
)
|
||||
|
||||
@property
|
||||
@ -263,9 +269,7 @@ class ProxyCamera(Camera):
|
||||
async def _async_stream_image(self):
|
||||
"""Return a still image response from the camera."""
|
||||
try:
|
||||
image = await self.hass.components.camera.async_get_image(
|
||||
self._proxied_camera
|
||||
)
|
||||
image = await async_get_image(self.hass, self._proxied_camera)
|
||||
if not image:
|
||||
return None
|
||||
except HomeAssistantError:
|
||||
|
@ -2,9 +2,7 @@
|
||||
"domain": "proxy",
|
||||
"name": "Proxy",
|
||||
"documentation": "https://www.home-assistant.io/integrations/proxy",
|
||||
"requirements": [
|
||||
"pillow==6.2.1"
|
||||
],
|
||||
"requirements": ["pillow==6.2.1"],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
||||
"requirements": [
|
||||
"simplisafe-python==5.3.5"
|
||||
"simplisafe-python==5.3.6"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": [
|
||||
|
@ -3,14 +3,8 @@
|
||||
"name": "Smartthings",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/smartthings",
|
||||
"requirements": [
|
||||
"pysmartapp==0.3.2",
|
||||
"pysmartthings==0.6.9"
|
||||
],
|
||||
"dependencies": [
|
||||
"webhook"
|
||||
],
|
||||
"codeowners": [
|
||||
"@andrewsayre"
|
||||
]
|
||||
"requirements": ["pysmartapp==0.3.2", "pysmartthings==0.6.9"],
|
||||
"dependencies": ["webhook"],
|
||||
"after_dependencies": ["cloud"],
|
||||
"codeowners": ["@andrewsayre"]
|
||||
}
|
||||
|
@ -88,10 +88,7 @@ async def validate_installed_app(api, installed_app_id: str):
|
||||
|
||||
def validate_webhook_requirements(hass: HomeAssistantType) -> bool:
|
||||
"""Ensure HASS is setup properly to receive webhooks."""
|
||||
if (
|
||||
"cloud" in hass.config.components
|
||||
and hass.components.cloud.async_active_subscription()
|
||||
):
|
||||
if hass.components.cloud.async_active_subscription():
|
||||
return True
|
||||
if hass.data[DOMAIN][CONF_CLOUDHOOK_URL] is not None:
|
||||
return True
|
||||
@ -105,11 +102,7 @@ def get_webhook_url(hass: HomeAssistantType) -> str:
|
||||
Return the cloudhook if available, otherwise local webhook.
|
||||
"""
|
||||
cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL]
|
||||
if (
|
||||
"cloud" in hass.config.components
|
||||
and hass.components.cloud.async_active_subscription()
|
||||
and cloudhook_url is not None
|
||||
):
|
||||
if hass.components.cloud.async_active_subscription() and cloudhook_url is not None:
|
||||
return cloudhook_url
|
||||
return webhook.async_generate_url(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID])
|
||||
|
||||
@ -229,7 +222,6 @@ async def setup_smartapp_endpoint(hass: HomeAssistantType):
|
||||
cloudhook_url = config.get(CONF_CLOUDHOOK_URL)
|
||||
if (
|
||||
cloudhook_url is None
|
||||
and "cloud" in hass.config.components
|
||||
and hass.components.cloud.async_active_subscription()
|
||||
and not hass.config_entries.async_entries(DOMAIN)
|
||||
):
|
||||
@ -281,11 +273,7 @@ async def unload_smartapp_endpoint(hass: HomeAssistantType):
|
||||
return
|
||||
# Remove the cloudhook if it was created
|
||||
cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL]
|
||||
if (
|
||||
cloudhook_url
|
||||
and "cloud" in hass.config.components
|
||||
and hass.components.cloud.async_is_logged_in()
|
||||
):
|
||||
if cloudhook_url and hass.components.cloud.async_is_logged_in():
|
||||
await hass.components.cloud.async_delete_cloudhook(
|
||||
hass.data[DOMAIN][CONF_WEBHOOK_ID]
|
||||
)
|
||||
|
@ -4,7 +4,7 @@ import datetime
|
||||
import logging
|
||||
|
||||
import requests
|
||||
import tank_utility
|
||||
from tank_utility import auth, device as tank_monitor
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||
@ -47,7 +47,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
devices = config.get(CONF_DEVICES)
|
||||
|
||||
try:
|
||||
token = tank_utility.auth.get_token(email, password)
|
||||
token = auth.get_token(email, password)
|
||||
except requests.exceptions.HTTPError as http_error:
|
||||
if (
|
||||
http_error.response.status_code
|
||||
@ -111,17 +111,15 @@ class TankUtilitySensor(Entity):
|
||||
|
||||
data = {}
|
||||
try:
|
||||
data = tank_utility.device.get_device_data(self._token, self.device)
|
||||
data = tank_monitor.get_device_data(self._token, self.device)
|
||||
except requests.exceptions.HTTPError as http_error:
|
||||
if (
|
||||
http_error.response.status_code
|
||||
== requests.codes.unauthorized # pylint: disable=no-member
|
||||
):
|
||||
_LOGGER.info("Getting new token")
|
||||
self._token = tank_utility.auth.get_token(
|
||||
self._email, self._password, force=True
|
||||
)
|
||||
data = tank_utility.device.get_device_data(self._token, self.device)
|
||||
self._token = auth.get_token(self._email, self._password, force=True)
|
||||
data = tank_monitor.get_device_data(self._token, self.device)
|
||||
else:
|
||||
raise http_error
|
||||
data.update(data.pop("device", {}))
|
||||
|
@ -1,11 +1,12 @@
|
||||
"""Support for Z-Wave climate devices."""
|
||||
# Because we do not compile openzwave on CI
|
||||
import logging
|
||||
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from homeassistant.components.climate import ClimateDevice
|
||||
from homeassistant.components.climate.const import (
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
CURRENT_HVAC_COOL,
|
||||
CURRENT_HVAC_FAN,
|
||||
CURRENT_HVAC_HEAT,
|
||||
@ -14,29 +15,26 @@ from homeassistant.components.climate.const import (
|
||||
DOMAIN,
|
||||
HVAC_MODE_AUTO,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_DRY,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_HEAT_COOL,
|
||||
HVAC_MODE_OFF,
|
||||
PRESET_AWAY,
|
||||
PRESET_BOOST,
|
||||
PRESET_NONE,
|
||||
SUPPORT_AUX_HEAT,
|
||||
SUPPORT_FAN_MODE,
|
||||
SUPPORT_PRESET_MODE,
|
||||
SUPPORT_SWING_MODE,
|
||||
SUPPORT_TARGET_TEMPERATURE,
|
||||
SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
SUPPORT_PRESET_MODE,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
|
||||
|
||||
from . import ZWaveDeviceEntity
|
||||
from . import ZWaveDeviceEntity, const
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -149,10 +147,14 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
def get_device(hass, values, **kwargs):
|
||||
"""Create Z-Wave entity device."""
|
||||
temp_unit = hass.config.units.temperature_unit
|
||||
return ZWaveClimate(values, temp_unit)
|
||||
if values.primary.command_class == const.COMMAND_CLASS_THERMOSTAT_SETPOINT:
|
||||
return ZWaveClimateSingleSetpoint(values, temp_unit)
|
||||
if values.primary.command_class == const.COMMAND_CLASS_THERMOSTAT_MODE:
|
||||
return ZWaveClimateMultipleSetpoint(values, temp_unit)
|
||||
return None
|
||||
|
||||
|
||||
class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
class ZWaveClimateBase(ZWaveDeviceEntity, ClimateDevice):
|
||||
"""Representation of a Z-Wave Climate device."""
|
||||
|
||||
def __init__(self, values, temp_unit):
|
||||
@ -190,18 +192,21 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
self._zxt_120 = 1
|
||||
self.update_properties()
|
||||
|
||||
def _current_mode_setpoints(self):
|
||||
current_mode = str(self.values.primary.data).lower()
|
||||
setpoints_names = MODE_SETPOINT_MAPPINGS.get(current_mode, ())
|
||||
return tuple(getattr(self.values, name, None) for name in setpoints_names)
|
||||
def _mode(self) -> None:
|
||||
"""Return thermostat mode Z-Wave value."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def _current_mode_setpoints(self) -> Tuple:
|
||||
"""Return a tuple of current setpoint Z-Wave value(s)."""
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
support = SUPPORT_TARGET_TEMPERATURE
|
||||
if HVAC_MODE_HEAT_COOL in self._hvac_list:
|
||||
if self._hvac_list and HVAC_MODE_HEAT_COOL in self._hvac_list:
|
||||
support |= SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
if PRESET_AWAY in self._preset_list:
|
||||
if self._preset_list and PRESET_AWAY in self._preset_list:
|
||||
support |= SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
|
||||
if self.values.fan_mode:
|
||||
@ -239,13 +244,13 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
|
||||
def _update_operation_mode(self):
|
||||
"""Update hvac and preset modes."""
|
||||
if self.values.primary:
|
||||
if self._mode():
|
||||
self._hvac_list = []
|
||||
self._hvac_mapping = {}
|
||||
self._preset_list = []
|
||||
self._preset_mapping = {}
|
||||
|
||||
mode_list = self.values.primary.data_items
|
||||
mode_list = self._mode().data_items
|
||||
if mode_list:
|
||||
for mode in mode_list:
|
||||
ha_mode = HVAC_STATE_MAPPINGS.get(str(mode).lower())
|
||||
@ -273,7 +278,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
# Presets are supported
|
||||
self._preset_list.append(PRESET_NONE)
|
||||
|
||||
current_mode = self.values.primary.data
|
||||
current_mode = self._mode().data
|
||||
_LOGGER.debug("current_mode=%s", current_mode)
|
||||
_hvac_temp = next(
|
||||
(
|
||||
@ -426,7 +431,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
|
||||
Need to be one of HVAC_MODE_*.
|
||||
"""
|
||||
if self.values.primary:
|
||||
if self._mode():
|
||||
return self._hvac_mode
|
||||
return self._default_hvac_mode
|
||||
|
||||
@ -436,7 +441,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
|
||||
Need to be a subset of HVAC_MODES.
|
||||
"""
|
||||
if self.values.primary:
|
||||
if self._mode():
|
||||
return self._hvac_list
|
||||
return []
|
||||
|
||||
@ -453,7 +458,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
"""Return true if aux heater."""
|
||||
if not self._aux_heat:
|
||||
return None
|
||||
if self.values.primary.data == AUX_HEAT_ZWAVE_MODE:
|
||||
if self._mode().data == AUX_HEAT_ZWAVE_MODE:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -463,7 +468,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
|
||||
Need to be one of PRESET_*.
|
||||
"""
|
||||
if self.values.primary:
|
||||
if self._mode():
|
||||
return self._preset_mode
|
||||
return PRESET_NONE
|
||||
|
||||
@ -473,7 +478,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
|
||||
Need to be a subset of PRESET_MODES.
|
||||
"""
|
||||
if self.values.primary:
|
||||
if self._mode():
|
||||
return self._preset_list
|
||||
return []
|
||||
|
||||
@ -522,11 +527,11 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
def set_hvac_mode(self, hvac_mode):
|
||||
"""Set new target hvac mode."""
|
||||
_LOGGER.debug("Set hvac_mode to %s", hvac_mode)
|
||||
if not self.values.primary:
|
||||
if not self._mode():
|
||||
return
|
||||
operation_mode = self._hvac_mapping.get(hvac_mode)
|
||||
_LOGGER.debug("Set operation_mode to %s", operation_mode)
|
||||
self.values.primary.data = operation_mode
|
||||
self._mode().data = operation_mode
|
||||
|
||||
def turn_aux_heat_on(self):
|
||||
"""Turn auxillary heater on."""
|
||||
@ -534,7 +539,7 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
return
|
||||
operation_mode = AUX_HEAT_ZWAVE_MODE
|
||||
_LOGGER.debug("Aux heat on. Set operation mode to %s", operation_mode)
|
||||
self.values.primary.data = operation_mode
|
||||
self._mode().data = operation_mode
|
||||
|
||||
def turn_aux_heat_off(self):
|
||||
"""Turn auxillary heater off."""
|
||||
@ -545,23 +550,23 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
else:
|
||||
operation_mode = self._hvac_mapping.get(HVAC_MODE_OFF)
|
||||
_LOGGER.debug("Aux heat off. Set operation mode to %s", operation_mode)
|
||||
self.values.primary.data = operation_mode
|
||||
self._mode().data = operation_mode
|
||||
|
||||
def set_preset_mode(self, preset_mode):
|
||||
"""Set new target preset mode."""
|
||||
_LOGGER.debug("Set preset_mode to %s", preset_mode)
|
||||
if not self.values.primary:
|
||||
if not self._mode():
|
||||
return
|
||||
if preset_mode == PRESET_NONE:
|
||||
# Activate the current hvac mode
|
||||
self._update_operation_mode()
|
||||
operation_mode = self._hvac_mapping.get(self.hvac_mode)
|
||||
_LOGGER.debug("Set operation_mode to %s", operation_mode)
|
||||
self.values.primary.data = operation_mode
|
||||
self._mode().data = operation_mode
|
||||
else:
|
||||
operation_mode = self._preset_mapping.get(preset_mode, preset_mode)
|
||||
_LOGGER.debug("Set operation_mode to %s", operation_mode)
|
||||
self.values.primary.data = operation_mode
|
||||
self._mode().data = operation_mode
|
||||
|
||||
def set_swing_mode(self, swing_mode):
|
||||
"""Set new target swing mode."""
|
||||
@ -577,3 +582,37 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice):
|
||||
if self._fan_action:
|
||||
data[ATTR_FAN_ACTION] = self._fan_action
|
||||
return data
|
||||
|
||||
|
||||
class ZWaveClimateSingleSetpoint(ZWaveClimateBase):
|
||||
"""Representation of a single setpoint Z-Wave thermostat device."""
|
||||
|
||||
def __init__(self, values, temp_unit):
|
||||
"""Initialize the Z-Wave climate device."""
|
||||
ZWaveClimateBase.__init__(self, values, temp_unit)
|
||||
|
||||
def _mode(self) -> None:
|
||||
"""Return thermostat mode Z-Wave value."""
|
||||
return self.values.mode
|
||||
|
||||
def _current_mode_setpoints(self) -> Tuple:
|
||||
"""Return a tuple of current setpoint Z-Wave value(s)."""
|
||||
return (self.values.primary,)
|
||||
|
||||
|
||||
class ZWaveClimateMultipleSetpoint(ZWaveClimateBase):
|
||||
"""Representation of a multiple setpoint Z-Wave thermostat device."""
|
||||
|
||||
def __init__(self, values, temp_unit):
|
||||
"""Initialize the Z-Wave climate device."""
|
||||
ZWaveClimateBase.__init__(self, values, temp_unit)
|
||||
|
||||
def _mode(self) -> None:
|
||||
"""Return thermostat mode Z-Wave value."""
|
||||
return self.values.primary
|
||||
|
||||
def _current_mode_setpoints(self) -> Tuple:
|
||||
"""Return a tuple of current setpoint Z-Wave value(s)."""
|
||||
current_mode = str(self.values.primary.data).lower()
|
||||
setpoints_names = MODE_SETPOINT_MAPPINGS.get(current_mode, ())
|
||||
return tuple(getattr(self.values, name, None) for name in setpoints_names)
|
||||
|
@ -48,11 +48,60 @@ DISCOVERY_SCHEMAS = [
|
||||
),
|
||||
},
|
||||
{
|
||||
const.DISC_COMPONENT: "climate",
|
||||
const.DISC_COMPONENT: "climate", # thermostat without COMMAND_CLASS_THERMOSTAT_MODE
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [
|
||||
const.GENERIC_TYPE_THERMOSTAT,
|
||||
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
||||
],
|
||||
const.DISC_SPECIFIC_DEVICE_CLASS: [
|
||||
const.SPECIFIC_TYPE_THERMOSTAT_HEATING,
|
||||
const.SPECIFIC_TYPE_SETPOINT_THERMOSTAT,
|
||||
],
|
||||
const.DISC_VALUES: dict(
|
||||
DEFAULT_VALUES_SCHEMA,
|
||||
**{
|
||||
const.DISC_PRIMARY: {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_SETPOINT]
|
||||
},
|
||||
"temperature": {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_SENSOR_MULTILEVEL],
|
||||
const.DISC_INDEX: [const.INDEX_SENSOR_MULTILEVEL_TEMPERATURE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
"fan_mode": {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_FAN_MODE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
"operating_state": {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE
|
||||
],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
"fan_action": {
|
||||
const.DISC_COMMAND_CLASS: [
|
||||
const.COMMAND_CLASS_THERMOSTAT_FAN_ACTION
|
||||
],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
"mode": {
|
||||
const.DISC_COMMAND_CLASS: [const.COMMAND_CLASS_THERMOSTAT_MODE],
|
||||
const.DISC_OPTIONAL: True,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
const.DISC_COMPONENT: "climate", # thermostat with COMMAND_CLASS_THERMOSTAT_MODE
|
||||
const.DISC_GENERIC_DEVICE_CLASS: [
|
||||
const.GENERIC_TYPE_THERMOSTAT,
|
||||
const.GENERIC_TYPE_SENSOR_MULTILEVEL,
|
||||
],
|
||||
const.DISC_SPECIFIC_DEVICE_CLASS: [
|
||||
const.SPECIFIC_TYPE_THERMOSTAT_GENERAL,
|
||||
const.SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2,
|
||||
const.SPECIFIC_TYPE_SETBACK_THERMOSTAT,
|
||||
],
|
||||
const.DISC_VALUES: dict(
|
||||
DEFAULT_VALUES_SCHEMA,
|
||||
**{
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 103
|
||||
PATCH_VERSION = "0"
|
||||
PATCH_VERSION = "1"
|
||||
__short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = "{}.{}".format(__short_version__, PATCH_VERSION)
|
||||
REQUIRED_PYTHON_VER = (3, 6, 1)
|
||||
|
@ -288,8 +288,8 @@ async def async_process_deps_reqs(
|
||||
raise HomeAssistantError("Could not set up all dependencies.")
|
||||
|
||||
if not hass.config.skip_pip and integration.requirements:
|
||||
await requirements.async_process_requirements(
|
||||
hass, integration.domain, integration.requirements
|
||||
await requirements.async_get_integration_with_requirements(
|
||||
hass, integration.domain
|
||||
)
|
||||
|
||||
processed.add(integration.domain)
|
||||
|
@ -133,7 +133,7 @@ aio_geojson_geonetnz_volcano==0.5
|
||||
aio_geojson_nsw_rfs_incidents==0.1
|
||||
|
||||
# homeassistant.components.ambient_station
|
||||
aioambient==0.3.2
|
||||
aioambient==1.0.2
|
||||
|
||||
# homeassistant.components.asuswrt
|
||||
aioasuswrt==1.1.22
|
||||
@ -1231,7 +1231,7 @@ pyflexit==0.3
|
||||
pyflic-homeassistant==0.4.dev0
|
||||
|
||||
# homeassistant.components.flume
|
||||
pyflume==0.2.1
|
||||
pyflume==0.2.4
|
||||
|
||||
# homeassistant.components.flunearyou
|
||||
pyflunearyou==1.0.3
|
||||
@ -1793,7 +1793,7 @@ shodan==1.20.0
|
||||
simplepush==1.1.4
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==5.3.5
|
||||
simplisafe-python==5.3.6
|
||||
|
||||
# homeassistant.components.sisyphus
|
||||
sisyphus-control==2.2.1
|
||||
|
@ -44,7 +44,7 @@ aio_geojson_geonetnz_volcano==0.5
|
||||
aio_geojson_nsw_rfs_incidents==0.1
|
||||
|
||||
# homeassistant.components.ambient_station
|
||||
aioambient==0.3.2
|
||||
aioambient==1.0.2
|
||||
|
||||
# homeassistant.components.asuswrt
|
||||
aioasuswrt==1.1.22
|
||||
@ -558,7 +558,7 @@ rxv==0.6.0
|
||||
samsungctl[websocket]==0.7.1
|
||||
|
||||
# homeassistant.components.simplisafe
|
||||
simplisafe-python==5.3.5
|
||||
simplisafe-python==5.3.6
|
||||
|
||||
# homeassistant.components.sleepiq
|
||||
sleepyq==0.7
|
||||
|
@ -43,15 +43,12 @@ def validate_dependencies(integration: Integration):
|
||||
|
||||
if referenced:
|
||||
for domain in sorted(referenced):
|
||||
print(
|
||||
"Warning: {} references integration {} but it's not a "
|
||||
"dependency".format(integration.domain, domain)
|
||||
integration.add_error(
|
||||
"dependencies",
|
||||
"Using component {} but it's not in 'dependencies' or 'after_dependencies'".format(
|
||||
domain
|
||||
),
|
||||
)
|
||||
# Not enforced yet.
|
||||
# integration.add_error(
|
||||
# 'dependencies',
|
||||
# "Using component {} but it's not a dependency".format(domain)
|
||||
# )
|
||||
|
||||
|
||||
def validate(integrations: Dict[str, Integration], config):
|
||||
|
@ -7,7 +7,6 @@ from pysmartthings import APIResponseError
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.components import cloud
|
||||
from homeassistant.components.smartthings import smartapp
|
||||
from homeassistant.components.smartthings.config_flow import SmartThingsFlowHandler
|
||||
from homeassistant.components.smartthings.const import (
|
||||
@ -18,7 +17,7 @@ from homeassistant.components.smartthings.const import (
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
|
||||
|
||||
async def test_step_user(hass):
|
||||
@ -211,9 +210,11 @@ async def test_cloudhook_app_created_then_show_wait_form(
|
||||
await smartapp.unload_smartapp_endpoint(hass)
|
||||
|
||||
with patch.object(
|
||||
cloud, "async_active_subscription", return_value=True
|
||||
hass.components.cloud, "async_active_subscription", return_value=True
|
||||
), patch.object(
|
||||
cloud, "async_create_cloudhook", return_value="http://cloud.test"
|
||||
hass.components.cloud,
|
||||
"async_create_cloudhook",
|
||||
return_value=mock_coro("http://cloud.test"),
|
||||
) as mock_create_cloudhook:
|
||||
|
||||
await smartapp.setup_smartapp_endpoint(hass)
|
||||
|
@ -13,6 +13,7 @@ from homeassistant.components.climate.const import (
|
||||
PRESET_BOOST,
|
||||
PRESET_ECO,
|
||||
PRESET_NONE,
|
||||
SUPPORT_AUX_HEAT,
|
||||
SUPPORT_FAN_MODE,
|
||||
SUPPORT_PRESET_MODE,
|
||||
SUPPORT_SWING_MODE,
|
||||
@ -21,8 +22,11 @@ from homeassistant.components.climate.const import (
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
)
|
||||
from homeassistant.components.zwave import climate
|
||||
from homeassistant.components.zwave.climate import DEFAULT_HVAC_MODES
|
||||
from homeassistant.components.zwave import climate, const
|
||||
from homeassistant.components.zwave.climate import (
|
||||
AUX_HEAT_ZWAVE_MODE,
|
||||
DEFAULT_HVAC_MODES,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||
|
||||
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed
|
||||
@ -34,6 +38,7 @@ def device(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT,
|
||||
data_items=[
|
||||
HVAC_MODE_OFF,
|
||||
@ -62,6 +67,7 @@ def device_zxt_120(hass, mock_openzwave):
|
||||
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT,
|
||||
data_items=[
|
||||
HVAC_MODE_OFF,
|
||||
@ -90,6 +96,7 @@ def device_mapping(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data="Heat",
|
||||
data_items=["Off", "Cool", "Heat", "Full Power", "Auto"],
|
||||
node=node,
|
||||
@ -112,6 +119,7 @@ def device_unknown(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data="Heat",
|
||||
data_items=["Off", "Cool", "Heat", "heat_cool", "Abcdefg"],
|
||||
node=node,
|
||||
@ -134,6 +142,7 @@ def device_heat_cool(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT,
|
||||
data_items=[
|
||||
HVAC_MODE_OFF,
|
||||
@ -162,6 +171,7 @@ def device_heat_cool_range(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT_COOL,
|
||||
data_items=[
|
||||
HVAC_MODE_OFF,
|
||||
@ -189,6 +199,7 @@ def device_heat_cool_away(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT_COOL,
|
||||
data_items=[
|
||||
HVAC_MODE_OFF,
|
||||
@ -219,6 +230,7 @@ def device_heat_eco(hass, mock_openzwave):
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT,
|
||||
data_items=[HVAC_MODE_OFF, HVAC_MODE_HEAT, "heat econ"],
|
||||
node=node,
|
||||
@ -235,6 +247,100 @@ def device_heat_eco(hass, mock_openzwave):
|
||||
yield device
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_aux_heat(hass, mock_openzwave):
|
||||
"""Fixture to provide a precreated climate device. aux heat."""
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT,
|
||||
data_items=[HVAC_MODE_OFF, HVAC_MODE_HEAT, "Aux Heat"],
|
||||
node=node,
|
||||
),
|
||||
setpoint_heating=MockValue(data=2, node=node),
|
||||
setpoint_eco_heating=MockValue(data=1, node=node),
|
||||
temperature=MockValue(data=5, node=node, units=None),
|
||||
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
|
||||
operating_state=MockValue(data="test4", node=node),
|
||||
fan_action=MockValue(data=7, node=node),
|
||||
)
|
||||
device = climate.get_device(hass, node=node, values=values, node_config={})
|
||||
|
||||
yield device
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_single_setpoint(hass, mock_openzwave):
|
||||
"""Fixture to provide a precreated climate device.
|
||||
|
||||
SETPOINT_THERMOSTAT device class.
|
||||
"""
|
||||
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_SETPOINT, data=1, node=node
|
||||
),
|
||||
mode=None,
|
||||
temperature=MockValue(data=5, node=node, units=None),
|
||||
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
|
||||
operating_state=MockValue(data=CURRENT_HVAC_HEAT, node=node),
|
||||
fan_action=MockValue(data=7, node=node),
|
||||
)
|
||||
device = climate.get_device(hass, node=node, values=values, node_config={})
|
||||
|
||||
yield device
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def device_single_setpoint_with_mode(hass, mock_openzwave):
|
||||
"""Fixture to provide a precreated climate device.
|
||||
|
||||
SETPOINT_THERMOSTAT device class with COMMAND_CLASS_THERMOSTAT_MODE command class
|
||||
"""
|
||||
|
||||
node = MockNode()
|
||||
values = MockEntityValues(
|
||||
primary=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_SETPOINT, data=1, node=node
|
||||
),
|
||||
mode=MockValue(
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_MODE,
|
||||
data=HVAC_MODE_HEAT,
|
||||
data_items=[HVAC_MODE_OFF, HVAC_MODE_HEAT],
|
||||
node=node,
|
||||
),
|
||||
temperature=MockValue(data=5, node=node, units=None),
|
||||
fan_mode=MockValue(data="test2", data_items=[3, 4, 5], node=node),
|
||||
operating_state=MockValue(data=CURRENT_HVAC_HEAT, node=node),
|
||||
fan_action=MockValue(data=7, node=node),
|
||||
)
|
||||
device = climate.get_device(hass, node=node, values=values, node_config={})
|
||||
|
||||
yield device
|
||||
|
||||
|
||||
def test_get_device_detects_none(hass, mock_openzwave):
|
||||
"""Test get_device returns None."""
|
||||
node = MockNode()
|
||||
value = MockValue(data=0, node=node)
|
||||
values = MockEntityValues(primary=value)
|
||||
|
||||
device = climate.get_device(hass, node=node, values=values, node_config={})
|
||||
assert device is None
|
||||
|
||||
|
||||
def test_get_device_detects_multiple_setpoint_device(device):
|
||||
"""Test get_device returns a Z-Wave multiple setpoint device."""
|
||||
assert isinstance(device, climate.ZWaveClimateMultipleSetpoint)
|
||||
|
||||
|
||||
def test_get_device_detects_single_setpoint_device(device_single_setpoint):
|
||||
"""Test get_device returns a Z-Wave single setpoint device."""
|
||||
assert isinstance(device_single_setpoint, climate.ZWaveClimateSingleSetpoint)
|
||||
|
||||
|
||||
def test_default_hvac_modes():
|
||||
"""Test wether all hvac modes are included in default_hvac_modes."""
|
||||
for hvac_mode in HVAC_MODES:
|
||||
@ -274,6 +380,18 @@ def test_supported_features_preset_mode(device_mapping):
|
||||
)
|
||||
|
||||
|
||||
def test_supported_features_preset_mode_away(device_heat_cool_away):
|
||||
"""Test supported features flags with swing mode."""
|
||||
device = device_heat_cool_away
|
||||
assert (
|
||||
device.supported_features
|
||||
== SUPPORT_FAN_MODE
|
||||
+ SUPPORT_TARGET_TEMPERATURE
|
||||
+ SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
+ SUPPORT_PRESET_MODE
|
||||
)
|
||||
|
||||
|
||||
def test_supported_features_swing_mode(device_zxt_120):
|
||||
"""Test supported features flags with swing mode."""
|
||||
device = device_zxt_120
|
||||
@ -286,6 +404,27 @@ def test_supported_features_swing_mode(device_zxt_120):
|
||||
)
|
||||
|
||||
|
||||
def test_supported_features_aux_heat(device_aux_heat):
|
||||
"""Test supported features flags with aux heat."""
|
||||
device = device_aux_heat
|
||||
assert (
|
||||
device.supported_features
|
||||
== SUPPORT_FAN_MODE + SUPPORT_TARGET_TEMPERATURE + SUPPORT_AUX_HEAT
|
||||
)
|
||||
|
||||
|
||||
def test_supported_features_single_setpoint(device_single_setpoint):
|
||||
"""Test supported features flags for SETPOINT_THERMOSTAT."""
|
||||
device = device_single_setpoint
|
||||
assert device.supported_features == SUPPORT_FAN_MODE + SUPPORT_TARGET_TEMPERATURE
|
||||
|
||||
|
||||
def test_supported_features_single_setpoint_with_mode(device_single_setpoint_with_mode):
|
||||
"""Test supported features flags for SETPOINT_THERMOSTAT."""
|
||||
device = device_single_setpoint_with_mode
|
||||
assert device.supported_features == SUPPORT_FAN_MODE + SUPPORT_TARGET_TEMPERATURE
|
||||
|
||||
|
||||
def test_zxt_120_swing_mode(device_zxt_120):
|
||||
"""Test operation of the zxt 120 swing mode."""
|
||||
device = device_zxt_120
|
||||
@ -331,6 +470,22 @@ def test_data_lists(device):
|
||||
assert device.preset_modes == []
|
||||
|
||||
|
||||
def test_data_lists_single_setpoint(device_single_setpoint):
|
||||
"""Test data lists from zwave value items."""
|
||||
device = device_single_setpoint
|
||||
assert device.fan_modes == [3, 4, 5]
|
||||
assert device.hvac_modes == []
|
||||
assert device.preset_modes == []
|
||||
|
||||
|
||||
def test_data_lists_single_setpoint_with_mode(device_single_setpoint_with_mode):
|
||||
"""Test data lists from zwave value items."""
|
||||
device = device_single_setpoint_with_mode
|
||||
assert device.fan_modes == [3, 4, 5]
|
||||
assert device.hvac_modes == [HVAC_MODE_OFF, HVAC_MODE_HEAT]
|
||||
assert device.preset_modes == []
|
||||
|
||||
|
||||
def test_data_lists_mapping(device_mapping):
|
||||
"""Test data lists from zwave value items."""
|
||||
device = device_mapping
|
||||
@ -404,6 +559,14 @@ def test_target_value_set_eco(device_heat_eco):
|
||||
assert device.values.setpoint_eco_heating.data == 0
|
||||
|
||||
|
||||
def test_target_value_set_single_setpoint(device_single_setpoint):
|
||||
"""Test values changed for climate device."""
|
||||
device = device_single_setpoint
|
||||
assert device.values.primary.data == 1
|
||||
device.set_temperature(**{ATTR_TEMPERATURE: 2})
|
||||
assert device.values.primary.data == 2
|
||||
|
||||
|
||||
def test_operation_value_set(device):
|
||||
"""Test values changed for climate device."""
|
||||
assert device.values.primary.data == HVAC_MODE_HEAT
|
||||
@ -546,6 +709,15 @@ def test_target_changed_with_mode(device):
|
||||
assert device.target_temperature_high == 10
|
||||
|
||||
|
||||
def test_target_value_changed_single_setpoint(device_single_setpoint):
|
||||
"""Test values changed for climate device."""
|
||||
device = device_single_setpoint
|
||||
assert device.target_temperature == 1
|
||||
device.values.primary.data = 2
|
||||
value_changed(device.values.primary)
|
||||
assert device.target_temperature == 2
|
||||
|
||||
|
||||
def test_temperature_value_changed(device):
|
||||
"""Test values changed for climate device."""
|
||||
assert device.current_temperature == 5
|
||||
@ -677,3 +849,44 @@ def test_fan_action_value_changed(device):
|
||||
device.values.fan_action.data = 9
|
||||
value_changed(device.values.fan_action)
|
||||
assert device.device_state_attributes[climate.ATTR_FAN_ACTION] == 9
|
||||
|
||||
|
||||
def test_aux_heat_unsupported_set(device):
|
||||
"""Test aux heat for climate device."""
|
||||
device = device
|
||||
assert device.values.primary.data == HVAC_MODE_HEAT
|
||||
device.turn_aux_heat_on()
|
||||
assert device.values.primary.data == HVAC_MODE_HEAT
|
||||
device.turn_aux_heat_off()
|
||||
assert device.values.primary.data == HVAC_MODE_HEAT
|
||||
|
||||
|
||||
def test_aux_heat_unsupported_value_changed(device):
|
||||
"""Test aux heat for climate device."""
|
||||
device = device
|
||||
assert device.is_aux_heat is None
|
||||
device.values.primary.data = HVAC_MODE_HEAT
|
||||
value_changed(device.values.primary)
|
||||
assert device.is_aux_heat is None
|
||||
|
||||
|
||||
def test_aux_heat_set(device_aux_heat):
|
||||
"""Test aux heat for climate device."""
|
||||
device = device_aux_heat
|
||||
assert device.values.primary.data == HVAC_MODE_HEAT
|
||||
device.turn_aux_heat_on()
|
||||
assert device.values.primary.data == AUX_HEAT_ZWAVE_MODE
|
||||
device.turn_aux_heat_off()
|
||||
assert device.values.primary.data == HVAC_MODE_HEAT
|
||||
|
||||
|
||||
def test_aux_heat_value_changed(device_aux_heat):
|
||||
"""Test aux heat for climate device."""
|
||||
device = device_aux_heat
|
||||
assert device.is_aux_heat is False
|
||||
device.values.primary.data = AUX_HEAT_ZWAVE_MODE
|
||||
value_changed(device.values.primary)
|
||||
assert device.is_aux_heat is True
|
||||
device.values.primary.data = HVAC_MODE_HEAT
|
||||
value_changed(device.values.primary)
|
||||
assert device.is_aux_heat is False
|
||||
|
@ -573,7 +573,11 @@ async def test_value_discovery_existing_entity(hass, mock_openzwave):
|
||||
|
||||
assert len(mock_receivers) == 1
|
||||
|
||||
node = MockNode(node_id=11, generic=const.GENERIC_TYPE_THERMOSTAT)
|
||||
node = MockNode(
|
||||
node_id=11,
|
||||
generic=const.GENERIC_TYPE_THERMOSTAT,
|
||||
specific=const.SPECIFIC_TYPE_THERMOSTAT_GENERAL_V2,
|
||||
)
|
||||
thermostat_mode = MockValue(
|
||||
data="Heat",
|
||||
data_items=["Off", "Heat"],
|
||||
@ -638,6 +642,42 @@ async def test_value_discovery_existing_entity(hass, mock_openzwave):
|
||||
)
|
||||
|
||||
|
||||
async def test_value_discovery_legacy_thermostat(hass, mock_openzwave):
|
||||
"""Test discovery of a node. Special case for legacy thermostats."""
|
||||
mock_receivers = []
|
||||
|
||||
def mock_connect(receiver, signal, *args, **kwargs):
|
||||
if signal == MockNetwork.SIGNAL_VALUE_ADDED:
|
||||
mock_receivers.append(receiver)
|
||||
|
||||
with patch("pydispatch.dispatcher.connect", new=mock_connect):
|
||||
await async_setup_component(hass, "zwave", {"zwave": {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(mock_receivers) == 1
|
||||
|
||||
node = MockNode(
|
||||
node_id=11,
|
||||
generic=const.GENERIC_TYPE_THERMOSTAT,
|
||||
specific=const.SPECIFIC_TYPE_SETPOINT_THERMOSTAT,
|
||||
)
|
||||
setpoint_heating = MockValue(
|
||||
data=22.0,
|
||||
node=node,
|
||||
command_class=const.COMMAND_CLASS_THERMOSTAT_SETPOINT,
|
||||
index=1,
|
||||
genre=const.GENRE_USER,
|
||||
)
|
||||
|
||||
hass.async_add_job(mock_receivers[0], node, setpoint_heating)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert (
|
||||
hass.states.get("climate.mock_node_mock_value").attributes["temperature"]
|
||||
== 22.0
|
||||
)
|
||||
|
||||
|
||||
async def test_power_schemes(hass, mock_openzwave):
|
||||
"""Test power attribute."""
|
||||
mock_receivers = []
|
||||
|
Loading…
x
Reference in New Issue
Block a user