Merge pull request #35001 from home-assistant/rc

This commit is contained in:
Franck Nijhof 2020-05-01 10:35:19 +02:00 committed by GitHub
commit 02cca1a4da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 242 additions and 44 deletions

View File

@ -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

View File

@ -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 .

View File

@ -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"

View File

@ -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,
)

View File

@ -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:

View File

@ -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."""

View File

@ -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]

View File

@ -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"]
} }

View File

@ -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, ""),

View File

@ -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

View File

@ -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)()

View File

@ -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:

View File

@ -24,7 +24,8 @@ CONFIG_SCHEMA = vol.Schema(
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
} }
) )
} },
extra=vol.ALLOW_EXTRA,
) )

View File

@ -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:

View File

@ -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."""

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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."""

View File

@ -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)

View File

@ -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