mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 08:07:45 +00:00
Merge pull request #35001 from home-assistant/rc
This commit is contained in:
commit
02cca1a4da
@ -195,6 +195,7 @@ homeassistant/components/ipp/* @ctalkington
|
|||||||
homeassistant/components/iqvia/* @bachya
|
homeassistant/components/iqvia/* @bachya
|
||||||
homeassistant/components/irish_rail_transport/* @ttroy50
|
homeassistant/components/irish_rail_transport/* @ttroy50
|
||||||
homeassistant/components/islamic_prayer_times/* @engrbm87
|
homeassistant/components/islamic_prayer_times/* @engrbm87
|
||||||
|
homeassistant/components/isy994/* @bdraco
|
||||||
homeassistant/components/izone/* @Swamp-Ig
|
homeassistant/components/izone/* @Swamp-Ig
|
||||||
homeassistant/components/jewish_calendar/* @tsvi
|
homeassistant/components/jewish_calendar/* @tsvi
|
||||||
homeassistant/components/juicenet/* @jesserockz
|
homeassistant/components/juicenet/* @jesserockz
|
||||||
|
@ -190,6 +190,9 @@ stages:
|
|||||||
pip install -U pip setuptools wheel
|
pip install -U pip setuptools wheel
|
||||||
pip install -r requirements_all.txt -c homeassistant/package_constraints.txt
|
pip install -r requirements_all.txt -c homeassistant/package_constraints.txt
|
||||||
pip install -r requirements_test.txt -c homeassistant/package_constraints.txt
|
pip install -r requirements_test.txt -c homeassistant/package_constraints.txt
|
||||||
|
# This is a TEMP. Eventually we should make sure our 4 dependencies drop typing.
|
||||||
|
# Find offending deps with `pipdeptree -r -p typing`
|
||||||
|
pip uninstall -y typing
|
||||||
- script: |
|
- script: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
pip install -e .
|
pip install -e .
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Brother Printer",
|
"name": "Brother Printer",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/brother",
|
"documentation": "https://www.home-assistant.io/integrations/brother",
|
||||||
"codeowners": ["@bieniu"],
|
"codeowners": ["@bieniu"],
|
||||||
"requirements": ["brother==0.1.13"],
|
"requirements": ["brother==0.1.14"],
|
||||||
"zeroconf": ["_printer._tcp.local."],
|
"zeroconf": ["_printer._tcp.local."],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"quality_scale": "platinum"
|
"quality_scale": "platinum"
|
||||||
|
@ -5,7 +5,7 @@ from typing import Any, Callable, Iterable, List
|
|||||||
|
|
||||||
from directv import DIRECTV, DIRECTVError
|
from directv import DIRECTV, DIRECTVError
|
||||||
|
|
||||||
from homeassistant.components.remote import RemoteDevice
|
from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteDevice
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
|
|
||||||
@ -95,12 +95,15 @@ class DIRECTVRemote(DIRECTVEntity, RemoteDevice):
|
|||||||
blue, chanup, chandown, prev, 0, 1, 2, 3, 4, 5,
|
blue, chanup, chandown, prev, 0, 1, 2, 3, 4, 5,
|
||||||
6, 7, 8, 9, dash, enter
|
6, 7, 8, 9, dash, enter
|
||||||
"""
|
"""
|
||||||
for single_command in command:
|
num_repeats = kwargs[ATTR_NUM_REPEATS]
|
||||||
try:
|
|
||||||
await self.dtv.remote(single_command, self._address)
|
for _ in range(num_repeats):
|
||||||
except DIRECTVError:
|
for single_command in command:
|
||||||
_LOGGER.exception(
|
try:
|
||||||
"Sending command %s to device %s failed",
|
await self.dtv.remote(single_command, self._address)
|
||||||
single_command,
|
except DIRECTVError:
|
||||||
self._device_id,
|
_LOGGER.exception(
|
||||||
)
|
"Sending command %s to device %s failed",
|
||||||
|
single_command,
|
||||||
|
self._device_id,
|
||||||
|
)
|
||||||
|
@ -165,7 +165,9 @@ class Fan(HomeAccessory):
|
|||||||
self.char_direction.set_value(hk_direction)
|
self.char_direction.set_value(hk_direction)
|
||||||
|
|
||||||
# Handle Speed
|
# Handle Speed
|
||||||
if self.char_speed is not None:
|
if self.char_speed is not None and state != STATE_OFF:
|
||||||
|
# We do not change the homekit speed when turning off
|
||||||
|
# as it will clear the restore state
|
||||||
speed = new_state.attributes.get(ATTR_SPEED)
|
speed = new_state.attributes.get(ATTR_SPEED)
|
||||||
hk_speed_value = self.speed_mapping.speed_to_homekit(speed)
|
hk_speed_value = self.speed_mapping.speed_to_homekit(speed)
|
||||||
if hk_speed_value is not None and self.char_speed.value != hk_speed_value:
|
if hk_speed_value is not None and self.char_speed.value != hk_speed_value:
|
||||||
|
@ -200,7 +200,7 @@ class HomeKitSpeedMapping:
|
|||||||
if speed is None:
|
if speed is None:
|
||||||
return None
|
return None
|
||||||
speed_range = self.speed_ranges[speed]
|
speed_range = self.speed_ranges[speed]
|
||||||
return speed_range.target
|
return round(speed_range.target)
|
||||||
|
|
||||||
def speed_to_states(self, speed):
|
def speed_to_states(self, speed):
|
||||||
"""Map HomeKit speed to Home Assistant speed state."""
|
"""Map HomeKit speed to Home Assistant speed state."""
|
||||||
|
@ -3,12 +3,15 @@ import logging
|
|||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
from homeassistant.components.light import DOMAIN, SUPPORT_BRIGHTNESS, Light
|
from homeassistant.components.light import DOMAIN, SUPPORT_BRIGHTNESS, Light
|
||||||
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from . import ISY994_NODES, ISYDevice
|
from . import ISY994_NODES, ISYDevice
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ATTR_LAST_BRIGHTNESS = "last_brightness"
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(
|
def setup_platform(
|
||||||
hass, config: ConfigType, add_entities: Callable[[list], None], discovery_info=None
|
hass, config: ConfigType, add_entities: Callable[[list], None], discovery_info=None
|
||||||
@ -21,13 +24,13 @@ def setup_platform(
|
|||||||
add_entities(devices)
|
add_entities(devices)
|
||||||
|
|
||||||
|
|
||||||
class ISYLightDevice(ISYDevice, Light):
|
class ISYLightDevice(ISYDevice, Light, RestoreEntity):
|
||||||
"""Representation of an ISY994 light device."""
|
"""Representation of an ISY994 light device."""
|
||||||
|
|
||||||
def __init__(self, node) -> None:
|
def __init__(self, node) -> None:
|
||||||
"""Initialize the ISY994 light device."""
|
"""Initialize the ISY994 light device."""
|
||||||
super().__init__(node)
|
super().__init__(node)
|
||||||
self._last_brightness = self.brightness
|
self._last_brightness = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
@ -56,7 +59,7 @@ class ISYLightDevice(ISYDevice, Light):
|
|||||||
# pylint: disable=arguments-differ
|
# pylint: disable=arguments-differ
|
||||||
def turn_on(self, brightness=None, **kwargs) -> None:
|
def turn_on(self, brightness=None, **kwargs) -> None:
|
||||||
"""Send the turn on command to the ISY994 light device."""
|
"""Send the turn on command to the ISY994 light device."""
|
||||||
if brightness is None and self._last_brightness is not None:
|
if brightness is None and self._last_brightness:
|
||||||
brightness = self._last_brightness
|
brightness = self._last_brightness
|
||||||
if not self._node.on(val=brightness):
|
if not self._node.on(val=brightness):
|
||||||
_LOGGER.debug("Unable to turn on light")
|
_LOGGER.debug("Unable to turn on light")
|
||||||
@ -65,3 +68,23 @@ class ISYLightDevice(ISYDevice, Light):
|
|||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
return SUPPORT_BRIGHTNESS
|
return SUPPORT_BRIGHTNESS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
"""Return the light attributes."""
|
||||||
|
return {ATTR_LAST_BRIGHTNESS: self._last_brightness}
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Restore last_brightness on restart."""
|
||||||
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
|
self._last_brightness = self.brightness or 255
|
||||||
|
last_state = await self.async_get_last_state()
|
||||||
|
if not last_state:
|
||||||
|
return
|
||||||
|
|
||||||
|
if (
|
||||||
|
ATTR_LAST_BRIGHTNESS in last_state.attributes
|
||||||
|
and last_state.attributes[ATTR_LAST_BRIGHTNESS]
|
||||||
|
):
|
||||||
|
self._last_brightness = last_state.attributes[ATTR_LAST_BRIGHTNESS]
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
"name": "Universal Devices ISY994",
|
"name": "Universal Devices ISY994",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/isy994",
|
"documentation": "https://www.home-assistant.io/integrations/isy994",
|
||||||
"requirements": ["PyISY==1.1.2"],
|
"requirements": ["PyISY==1.1.2"],
|
||||||
"codeowners": []
|
"codeowners": ["@bdraco"]
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ def log_messages(hass: HomeAssistantType, entity_id: str) -> MessageCallbackType
|
|||||||
debug_info = hass.data[DATA_MQTT_DEBUG_INFO]
|
debug_info = hass.data[DATA_MQTT_DEBUG_INFO]
|
||||||
messages = debug_info["entities"][entity_id]["subscriptions"][
|
messages = debug_info["entities"][entity_id]["subscriptions"][
|
||||||
msg.subscribed_topic
|
msg.subscribed_topic
|
||||||
]
|
]["messages"]
|
||||||
if msg not in messages:
|
if msg not in messages:
|
||||||
messages.append(msg)
|
messages.append(msg)
|
||||||
|
|
||||||
@ -50,16 +50,27 @@ def add_subscription(hass, message_callback, subscription):
|
|||||||
entity_info = debug_info["entities"].setdefault(
|
entity_info = debug_info["entities"].setdefault(
|
||||||
entity_id, {"subscriptions": {}, "discovery_data": {}}
|
entity_id, {"subscriptions": {}, "discovery_data": {}}
|
||||||
)
|
)
|
||||||
entity_info["subscriptions"][subscription] = deque([], STORED_MESSAGES)
|
if subscription not in entity_info["subscriptions"]:
|
||||||
|
entity_info["subscriptions"][subscription] = {
|
||||||
|
"count": 0,
|
||||||
|
"messages": deque([], STORED_MESSAGES),
|
||||||
|
}
|
||||||
|
entity_info["subscriptions"][subscription]["count"] += 1
|
||||||
|
|
||||||
|
|
||||||
def remove_subscription(hass, message_callback, subscription):
|
def remove_subscription(hass, message_callback, subscription):
|
||||||
"""Remove debug data for subscription."""
|
"""Remove debug data for subscription if it exists."""
|
||||||
entity_id = getattr(message_callback, "__entity_id", None)
|
entity_id = getattr(message_callback, "__entity_id", None)
|
||||||
if entity_id and entity_id in hass.data[DATA_MQTT_DEBUG_INFO]["entities"]:
|
if entity_id and entity_id in hass.data[DATA_MQTT_DEBUG_INFO]["entities"]:
|
||||||
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop(
|
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"][
|
||||||
subscription
|
subscription
|
||||||
)
|
]["count"] -= 1
|
||||||
|
if not hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"][
|
||||||
|
subscription
|
||||||
|
]["count"]:
|
||||||
|
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop(
|
||||||
|
subscription
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_entity_discovery_data(hass, discovery_data, entity_id):
|
def add_entity_discovery_data(hass, discovery_data, entity_id):
|
||||||
@ -127,10 +138,10 @@ async def info_for_device(hass, device_id):
|
|||||||
"topic": topic,
|
"topic": topic,
|
||||||
"messages": [
|
"messages": [
|
||||||
{"payload": msg.payload, "time": msg.timestamp, "topic": msg.topic}
|
{"payload": msg.payload, "time": msg.timestamp, "topic": msg.topic}
|
||||||
for msg in list(messages)
|
for msg in list(subscription["messages"])
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
for topic, messages in entity_info["subscriptions"].items()
|
for topic, subscription in entity_info["subscriptions"].items()
|
||||||
]
|
]
|
||||||
discovery_data = {
|
discovery_data = {
|
||||||
"topic": entity_info["discovery_data"].get(ATTR_DISCOVERY_TOPIC, ""),
|
"topic": entity_info["discovery_data"].get(ATTR_DISCOVERY_TOPIC, ""),
|
||||||
|
@ -123,7 +123,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
if not person.controllers:
|
if not person.controllers:
|
||||||
_LOGGER.error("No Rachio devices found in account %s", person.username)
|
_LOGGER.error("No Rachio devices found in account %s", person.username)
|
||||||
return False
|
return False
|
||||||
_LOGGER.info("%d Rachio device(s) found", len(person.controllers))
|
_LOGGER.info(
|
||||||
|
"%d Rachio device(s) found; The url %s must be accessible from the internet in order to receive updates",
|
||||||
|
len(person.controllers),
|
||||||
|
webhook_url,
|
||||||
|
)
|
||||||
|
|
||||||
# Enable component
|
# Enable component
|
||||||
hass.data[DOMAIN][entry.entry_id] = person
|
hass.data[DOMAIN][entry.entry_id] = person
|
||||||
|
@ -7,7 +7,7 @@ from requests.exceptions import (
|
|||||||
)
|
)
|
||||||
from roku import RokuException
|
from roku import RokuException
|
||||||
|
|
||||||
from homeassistant.components.remote import RemoteDevice
|
from homeassistant.components.remote import ATTR_NUM_REPEATS, RemoteDevice
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
|
|
||||||
@ -84,8 +84,11 @@ class RokuRemote(RemoteDevice):
|
|||||||
|
|
||||||
def send_command(self, command, **kwargs):
|
def send_command(self, command, **kwargs):
|
||||||
"""Send a command to one device."""
|
"""Send a command to one device."""
|
||||||
for single_command in command:
|
num_repeats = kwargs[ATTR_NUM_REPEATS]
|
||||||
if not hasattr(self.roku, single_command):
|
|
||||||
continue
|
|
||||||
|
|
||||||
getattr(self.roku, single_command)()
|
for _ in range(num_repeats):
|
||||||
|
for single_command in command:
|
||||||
|
if not hasattr(self.roku, single_command):
|
||||||
|
continue
|
||||||
|
|
||||||
|
getattr(self.roku, single_command)()
|
||||||
|
@ -3,6 +3,7 @@ import asyncio
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.vacuum import (
|
from homeassistant.components.vacuum import (
|
||||||
|
ATTR_STATUS,
|
||||||
STATE_CLEANING,
|
STATE_CLEANING,
|
||||||
STATE_DOCKED,
|
STATE_DOCKED,
|
||||||
STATE_ERROR,
|
STATE_ERROR,
|
||||||
@ -16,6 +17,7 @@ from homeassistant.components.vacuum import (
|
|||||||
SUPPORT_SEND_COMMAND,
|
SUPPORT_SEND_COMMAND,
|
||||||
SUPPORT_START,
|
SUPPORT_START,
|
||||||
SUPPORT_STATE,
|
SUPPORT_STATE,
|
||||||
|
SUPPORT_STATUS,
|
||||||
SUPPORT_STOP,
|
SUPPORT_STOP,
|
||||||
StateVacuumDevice,
|
StateVacuumDevice,
|
||||||
)
|
)
|
||||||
@ -40,6 +42,7 @@ SUPPORT_IROBOT = (
|
|||||||
| SUPPORT_SEND_COMMAND
|
| SUPPORT_SEND_COMMAND
|
||||||
| SUPPORT_START
|
| SUPPORT_START
|
||||||
| SUPPORT_STATE
|
| SUPPORT_STATE
|
||||||
|
| SUPPORT_STATUS
|
||||||
| SUPPORT_STOP
|
| SUPPORT_STOP
|
||||||
| SUPPORT_LOCATE
|
| SUPPORT_LOCATE
|
||||||
)
|
)
|
||||||
@ -143,7 +146,7 @@ class IRobotVacuum(IRobotEntity, StateVacuumDevice):
|
|||||||
state = STATE_MAP[phase]
|
state = STATE_MAP[phase]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return STATE_ERROR
|
return STATE_ERROR
|
||||||
if cycle != "none" and state != STATE_CLEANING and state != STATE_RETURNING:
|
if cycle != "none" and state in (STATE_IDLE, STATE_DOCKED):
|
||||||
state = STATE_PAUSED
|
state = STATE_PAUSED
|
||||||
return state
|
return state
|
||||||
|
|
||||||
@ -173,6 +176,9 @@ class IRobotVacuum(IRobotEntity, StateVacuumDevice):
|
|||||||
# Set properties that are to appear in the GUI
|
# Set properties that are to appear in the GUI
|
||||||
state_attrs = {ATTR_SOFTWARE_VERSION: software_version}
|
state_attrs = {ATTR_SOFTWARE_VERSION: software_version}
|
||||||
|
|
||||||
|
# Set legacy status to avoid break changes
|
||||||
|
state_attrs[ATTR_STATUS] = self.vacuum.current_state
|
||||||
|
|
||||||
# Only add cleaning time and cleaned area attrs when the vacuum is
|
# Only add cleaning time and cleaned area attrs when the vacuum is
|
||||||
# currently on
|
# currently on
|
||||||
if self.state == STATE_CLEANING:
|
if self.state == STATE_CLEANING:
|
||||||
|
@ -24,7 +24,8 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
vol.Required(CONF_PASSWORD): cv.string,
|
vol.Required(CONF_PASSWORD): cv.string,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
extra=vol.ALLOW_EXTRA,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ def add_entities(controller, async_add_entities):
|
|||||||
|
|
||||||
if tracker_class is UniFiClientTracker:
|
if tracker_class is UniFiClientTracker:
|
||||||
|
|
||||||
if item.is_wired:
|
if mac not in controller.wireless_clients:
|
||||||
if not controller.option_track_wired_clients:
|
if not controller.option_track_wired_clients:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
|
@ -132,7 +132,7 @@ class VizioDevice(MediaPlayerDevice):
|
|||||||
self._state = None
|
self._state = None
|
||||||
self._volume_level = None
|
self._volume_level = None
|
||||||
self._volume_step = config_entry.options[CONF_VOLUME_STEP]
|
self._volume_step = config_entry.options[CONF_VOLUME_STEP]
|
||||||
self._is_muted = None
|
self._is_volume_muted = None
|
||||||
self._current_input = None
|
self._current_input = None
|
||||||
self._current_app = None
|
self._current_app = None
|
||||||
self._current_app_config = None
|
self._current_app_config = None
|
||||||
@ -190,7 +190,7 @@ class VizioDevice(MediaPlayerDevice):
|
|||||||
if not is_on:
|
if not is_on:
|
||||||
self._state = STATE_OFF
|
self._state = STATE_OFF
|
||||||
self._volume_level = None
|
self._volume_level = None
|
||||||
self._is_muted = None
|
self._is_volume_muted = None
|
||||||
self._current_input = None
|
self._current_input = None
|
||||||
self._available_inputs = None
|
self._available_inputs = None
|
||||||
self._current_app = None
|
self._current_app = None
|
||||||
@ -207,7 +207,10 @@ class VizioDevice(MediaPlayerDevice):
|
|||||||
)
|
)
|
||||||
if audio_settings is not None:
|
if audio_settings is not None:
|
||||||
self._volume_level = float(audio_settings["volume"]) / self._max_volume
|
self._volume_level = float(audio_settings["volume"]) / self._max_volume
|
||||||
self._is_muted = audio_settings["mute"].lower() == "on"
|
if "mute" in audio_settings:
|
||||||
|
self._is_volume_muted = audio_settings["mute"].lower() == "on"
|
||||||
|
else:
|
||||||
|
self._is_volume_muted = None
|
||||||
|
|
||||||
if VIZIO_SOUND_MODE in audio_settings:
|
if VIZIO_SOUND_MODE in audio_settings:
|
||||||
self._supported_commands |= SUPPORT_SELECT_SOUND_MODE
|
self._supported_commands |= SUPPORT_SELECT_SOUND_MODE
|
||||||
@ -324,7 +327,7 @@ class VizioDevice(MediaPlayerDevice):
|
|||||||
@property
|
@property
|
||||||
def is_volume_muted(self):
|
def is_volume_muted(self):
|
||||||
"""Boolean if volume is currently muted."""
|
"""Boolean if volume is currently muted."""
|
||||||
return self._is_muted
|
return self._is_volume_muted
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def source(self) -> str:
|
def source(self) -> str:
|
||||||
@ -428,10 +431,10 @@ class VizioDevice(MediaPlayerDevice):
|
|||||||
"""Mute the volume."""
|
"""Mute the volume."""
|
||||||
if mute:
|
if mute:
|
||||||
await self._device.mute_on()
|
await self._device.mute_on()
|
||||||
self._is_muted = True
|
self._is_volume_muted = True
|
||||||
else:
|
else:
|
||||||
await self._device.mute_off()
|
await self._device.mute_off()
|
||||||
self._is_muted = False
|
self._is_volume_muted = False
|
||||||
|
|
||||||
async def async_media_previous_track(self) -> None:
|
async def async_media_previous_track(self) -> None:
|
||||||
"""Send previous channel command."""
|
"""Send previous channel command."""
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 109
|
MINOR_VERSION = 109
|
||||||
PATCH_VERSION = "1"
|
PATCH_VERSION = "2"
|
||||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER = (3, 7, 0)
|
REQUIRED_PYTHON_VER = (3, 7, 0)
|
||||||
|
@ -365,7 +365,7 @@ bravia-tv==1.0.2
|
|||||||
broadlink==0.13.2
|
broadlink==0.13.2
|
||||||
|
|
||||||
# homeassistant.components.brother
|
# homeassistant.components.brother
|
||||||
brother==0.1.13
|
brother==0.1.14
|
||||||
|
|
||||||
# homeassistant.components.brottsplatskartan
|
# homeassistant.components.brottsplatskartan
|
||||||
brottsplatskartan==0.0.1
|
brottsplatskartan==0.0.1
|
||||||
|
@ -147,7 +147,7 @@ bravia-tv==1.0.2
|
|||||||
broadlink==0.13.2
|
broadlink==0.13.2
|
||||||
|
|
||||||
# homeassistant.components.brother
|
# homeassistant.components.brother
|
||||||
brother==0.1.13
|
brother==0.1.14
|
||||||
|
|
||||||
# homeassistant.components.buienradar
|
# homeassistant.components.buienradar
|
||||||
buienradar==1.0.4
|
buienradar==1.0.4
|
||||||
|
@ -304,6 +304,7 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||||||
call_set_speed = async_mock_service(hass, DOMAIN, "set_speed")
|
call_set_speed = async_mock_service(hass, DOMAIN, "set_speed")
|
||||||
|
|
||||||
char_speed_iid = acc.char_speed.to_HAP()[HAP_REPR_IID]
|
char_speed_iid = acc.char_speed.to_HAP()[HAP_REPR_IID]
|
||||||
|
char_active_iid = acc.char_active.to_HAP()[HAP_REPR_IID]
|
||||||
|
|
||||||
hk_driver.set_characteristics(
|
hk_driver.set_characteristics(
|
||||||
{
|
{
|
||||||
@ -320,12 +321,37 @@ async def test_fan_speed(hass, hk_driver, cls, events):
|
|||||||
await hass.async_add_executor_job(acc.char_speed.client_update_value, 42)
|
await hass.async_add_executor_job(acc.char_speed.client_update_value, 42)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
acc.speed_mapping.speed_to_states.assert_called_with(42)
|
acc.speed_mapping.speed_to_states.assert_called_with(42)
|
||||||
|
assert acc.char_speed.value == 42
|
||||||
|
assert acc.char_active.value == 1
|
||||||
|
|
||||||
assert call_set_speed[0]
|
assert call_set_speed[0]
|
||||||
assert call_set_speed[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_set_speed[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert call_set_speed[0].data[ATTR_SPEED] == "ludicrous"
|
assert call_set_speed[0].data[ATTR_SPEED] == "ludicrous"
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] == "ludicrous"
|
assert events[-1].data[ATTR_VALUE] == "ludicrous"
|
||||||
|
|
||||||
|
# Verify speed is preserved from off to on
|
||||||
|
hass.states.async_set(entity_id, STATE_OFF, {ATTR_SPEED: SPEED_OFF})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_speed.value == 42
|
||||||
|
assert acc.char_active.value == 0
|
||||||
|
|
||||||
|
hk_driver.set_characteristics(
|
||||||
|
{
|
||||||
|
HAP_REPR_CHARS: [
|
||||||
|
{
|
||||||
|
HAP_REPR_AID: acc.aid,
|
||||||
|
HAP_REPR_IID: char_active_iid,
|
||||||
|
HAP_REPR_VALUE: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mock_addr",
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_speed.value == 42
|
||||||
|
assert acc.char_active.value == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_fan_set_all_one_shot(hass, hk_driver, cls, events):
|
async def test_fan_set_all_one_shot(hass, hk_driver, cls, events):
|
||||||
"""Test fan with speed."""
|
"""Test fan with speed."""
|
||||||
|
@ -960,6 +960,42 @@ async def test_mqtt_ws_remove_discovered_device_twice(
|
|||||||
assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND
|
assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
|
async def test_mqtt_ws_remove_discovered_device_same_topic(
|
||||||
|
hass, device_reg, hass_ws_client, mqtt_mock
|
||||||
|
):
|
||||||
|
"""Test MQTT websocket device removal."""
|
||||||
|
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await async_start(hass, "homeassistant", {}, config_entry)
|
||||||
|
|
||||||
|
data = (
|
||||||
|
'{ "device":{"identifiers":["0AFFD2"]},'
|
||||||
|
' "state_topic": "foobar/sensor",'
|
||||||
|
' "availability_topic": "foobar/sensor",'
|
||||||
|
' "unique_id": "unique" }'
|
||||||
|
)
|
||||||
|
|
||||||
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")}, set())
|
||||||
|
assert device_entry is not None
|
||||||
|
|
||||||
|
client = await hass_ws_client(hass)
|
||||||
|
await client.send_json(
|
||||||
|
{"id": 5, "type": "mqtt/device/remove", "device_id": device_entry.id}
|
||||||
|
)
|
||||||
|
response = await client.receive_json()
|
||||||
|
assert response["success"]
|
||||||
|
|
||||||
|
await client.send_json(
|
||||||
|
{"id": 6, "type": "mqtt/device/remove", "device_id": device_entry.id}
|
||||||
|
)
|
||||||
|
response = await client.receive_json()
|
||||||
|
assert not response["success"]
|
||||||
|
assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
async def test_mqtt_ws_remove_non_mqtt_device(
|
async def test_mqtt_ws_remove_non_mqtt_device(
|
||||||
hass, device_reg, hass_ws_client, mqtt_mock
|
hass, device_reg, hass_ws_client, mqtt_mock
|
||||||
):
|
):
|
||||||
@ -1306,7 +1342,60 @@ async def test_debug_info_filter_same(hass, mqtt_mock):
|
|||||||
assert {
|
assert {
|
||||||
"topic": "sensor/#",
|
"topic": "sensor/#",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"topic": "sensor/abc", "payload": "123", "time": dt1},
|
{"payload": "123", "time": dt1, "topic": "sensor/abc"},
|
||||||
{"topic": "sensor/abc", "payload": "123", "time": dt2},
|
{"payload": "123", "time": dt2, "topic": "sensor/abc"},
|
||||||
],
|
],
|
||||||
} == debug_info_data["entities"][0]["subscriptions"][0]
|
} == debug_info_data["entities"][0]["subscriptions"][0]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_debug_info_same_topic(hass, mqtt_mock):
|
||||||
|
"""Test debug info."""
|
||||||
|
config = {
|
||||||
|
"device": {"identifiers": ["helloworld"]},
|
||||||
|
"platform": "mqtt",
|
||||||
|
"name": "test",
|
||||||
|
"state_topic": "sensor/status",
|
||||||
|
"availability_topic": "sensor/status",
|
||||||
|
"unique_id": "veryunique",
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = MockConfigEntry(domain=mqtt.DOMAIN)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
await async_start(hass, "homeassistant", {}, entry)
|
||||||
|
registry = await hass.helpers.device_registry.async_get_registry()
|
||||||
|
|
||||||
|
data = json.dumps(config)
|
||||||
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
device = registry.async_get_device({("mqtt", "helloworld")}, set())
|
||||||
|
assert device is not None
|
||||||
|
|
||||||
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
|
assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1
|
||||||
|
assert {"topic": "sensor/status", "messages": []} in debug_info_data["entities"][0][
|
||||||
|
"subscriptions"
|
||||||
|
]
|
||||||
|
|
||||||
|
start_dt = datetime(2019, 1, 1, 0, 0, 0)
|
||||||
|
with mock.patch("homeassistant.util.dt.utcnow") as dt_utcnow:
|
||||||
|
dt_utcnow.return_value = start_dt
|
||||||
|
async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False)
|
||||||
|
|
||||||
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
|
assert {
|
||||||
|
"payload": "123",
|
||||||
|
"time": start_dt,
|
||||||
|
"topic": "sensor/status",
|
||||||
|
} in debug_info_data["entities"][0]["subscriptions"][0]["messages"]
|
||||||
|
|
||||||
|
config["availability_topic"] = "sensor/availability"
|
||||||
|
data = json.dumps(config)
|
||||||
|
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
start_dt = datetime(2019, 1, 1, 0, 0, 0)
|
||||||
|
with mock.patch("homeassistant.util.dt.utcnow") as dt_utcnow:
|
||||||
|
dt_utcnow.return_value = start_dt
|
||||||
|
async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False)
|
||||||
|
@ -621,3 +621,26 @@ async def test_setup_with_no_running_app(
|
|||||||
assert attr["source"] == "CAST"
|
assert attr["source"] == "CAST"
|
||||||
assert "app_id" not in attr
|
assert "app_id" not in attr
|
||||||
assert "app_name" not in attr
|
assert "app_name" not in attr
|
||||||
|
|
||||||
|
|
||||||
|
async def test_setup_tv_without_mute(
|
||||||
|
hass: HomeAssistantType,
|
||||||
|
vizio_connect: pytest.fixture,
|
||||||
|
vizio_update: pytest.fixture,
|
||||||
|
) -> None:
|
||||||
|
"""Test Vizio TV entity setup when mute property isn't returned by Vizio API."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data=vol.Schema(VIZIO_SCHEMA)(MOCK_USER_VALID_TV_CONFIG),
|
||||||
|
unique_id=UNIQUE_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
async with _cm_for_test_setup_without_apps(
|
||||||
|
{"volume": int(MAX_VOLUME[VIZIO_DEVICE_CLASS_TV] / 2)}, STATE_ON,
|
||||||
|
):
|
||||||
|
await _add_config_entry_to_hass(hass, config_entry)
|
||||||
|
|
||||||
|
attr = _get_attr_and_assert_base_attr(hass, DEVICE_CLASS_TV, STATE_ON)
|
||||||
|
_assert_sources_and_volume(attr, VIZIO_DEVICE_CLASS_TV)
|
||||||
|
assert "sound_mode" not in attr
|
||||||
|
assert "is_volume_muted" not in attr
|
||||||
|
Loading…
x
Reference in New Issue
Block a user