mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Merge pull request #55870 from home-assistant/rc
This commit is contained in:
commit
f0649855f9
@ -67,13 +67,13 @@ class IncomfortWaterHeater(IncomfortEntity, WaterHeaterEntity):
|
||||
|
||||
@property
|
||||
def min_temp(self) -> float:
|
||||
"""Return max valid temperature that can be set."""
|
||||
return 80.0
|
||||
"""Return min valid temperature that can be set."""
|
||||
return 30.0
|
||||
|
||||
@property
|
||||
def max_temp(self) -> float:
|
||||
"""Return max valid temperature that can be set."""
|
||||
return 30.0
|
||||
return 80.0
|
||||
|
||||
@property
|
||||
def temperature_unit(self) -> str:
|
||||
|
@ -110,16 +110,10 @@ class IntegrationSensor(RestoreEntity, SensorEntity):
|
||||
self._method = integration_method
|
||||
|
||||
self._name = name if name is not None else f"{source_entity} integral"
|
||||
|
||||
if unit_of_measurement is None:
|
||||
self._unit_template = (
|
||||
f"{'' if unit_prefix is None else unit_prefix}{{}}{unit_time}"
|
||||
)
|
||||
# we postpone the definition of unit_of_measurement to later
|
||||
self._unit_of_measurement = None
|
||||
else:
|
||||
self._unit_of_measurement = unit_of_measurement
|
||||
|
||||
self._unit_template = (
|
||||
f"{'' if unit_prefix is None else unit_prefix}{{}}{unit_time}"
|
||||
)
|
||||
self._unit_of_measurement = unit_of_measurement
|
||||
self._unit_prefix = UNIT_PREFIXES[unit_prefix]
|
||||
self._unit_time = UNIT_TIME[unit_time]
|
||||
self._attr_state_class = STATE_CLASS_TOTAL_INCREASING
|
||||
@ -135,10 +129,10 @@ class IntegrationSensor(RestoreEntity, SensorEntity):
|
||||
_LOGGER.warning("Could not restore last state: %s", err)
|
||||
else:
|
||||
self._attr_device_class = state.attributes.get(ATTR_DEVICE_CLASS)
|
||||
|
||||
self._unit_of_measurement = state.attributes.get(
|
||||
ATTR_UNIT_OF_MEASUREMENT
|
||||
)
|
||||
if self._unit_of_measurement is None:
|
||||
self._unit_of_measurement = state.attributes.get(
|
||||
ATTR_UNIT_OF_MEASUREMENT
|
||||
)
|
||||
|
||||
@callback
|
||||
def calc_integration(event):
|
||||
|
@ -48,7 +48,7 @@ from homeassistant.helpers.integration_platform import (
|
||||
from homeassistant.loader import bind_hass
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
ENTITY_ID_JSON_TEMPLATE = '"entity_id": ?"{}"'
|
||||
ENTITY_ID_JSON_TEMPLATE = '"entity_id":"{}"'
|
||||
ENTITY_ID_JSON_EXTRACT = re.compile('"entity_id": ?"([^"]+)"')
|
||||
DOMAIN_JSON_EXTRACT = re.compile('"domain": ?"([^"]+)"')
|
||||
ICON_JSON_EXTRACT = re.compile('"icon": ?"([^"]+)"')
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Mazda Connected Services",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/mazda",
|
||||
"requirements": ["pymazda==0.2.0"],
|
||||
"requirements": ["pymazda==0.2.1"],
|
||||
"codeowners": ["@bdr99"],
|
||||
"quality_scale": "platinum",
|
||||
"iot_class": "cloud_polling"
|
||||
|
@ -25,9 +25,11 @@ from homeassistant.const import (
|
||||
|
||||
from .const import (
|
||||
CONF_DATA_TYPE,
|
||||
CONF_INPUT_TYPE,
|
||||
CONF_SWAP,
|
||||
CONF_SWAP_BYTE,
|
||||
CONF_SWAP_NONE,
|
||||
CONF_WRITE_TYPE,
|
||||
DATA_TYPE_CUSTOM,
|
||||
DATA_TYPE_FLOAT,
|
||||
DATA_TYPE_FLOAT16,
|
||||
@ -212,6 +214,10 @@ def duplicate_entity_validator(config: dict) -> dict:
|
||||
for index, entry in enumerate(hub[conf_key]):
|
||||
name = entry[CONF_NAME]
|
||||
addr = str(entry[CONF_ADDRESS])
|
||||
if CONF_INPUT_TYPE in entry:
|
||||
addr += "_" + str(entry[CONF_INPUT_TYPE])
|
||||
elif CONF_WRITE_TYPE in entry:
|
||||
addr += "_" + str(entry[CONF_WRITE_TYPE])
|
||||
if CONF_COMMAND_ON in entry:
|
||||
addr += "_" + str(entry[CONF_COMMAND_ON])
|
||||
if CONF_COMMAND_OFF in entry:
|
||||
@ -242,7 +248,10 @@ def duplicate_modbus_validator(config: list) -> list:
|
||||
errors = []
|
||||
for index, hub in enumerate(config):
|
||||
name = hub.get(CONF_NAME, DEFAULT_HUB)
|
||||
host = hub[CONF_PORT] if hub[CONF_TYPE] == SERIAL else hub[CONF_HOST]
|
||||
if hub[CONF_TYPE] == SERIAL:
|
||||
host = hub[CONF_PORT]
|
||||
else:
|
||||
host = f"{hub[CONF_HOST]}_{hub[CONF_PORT]}"
|
||||
if host in hosts:
|
||||
err = f"Modbus {name} contains duplicate host/port {host}, not loaded!"
|
||||
_LOGGER.warning(err)
|
||||
|
@ -75,7 +75,7 @@ class RfxtrxSensorEntityDescription(SensorEntityDescription):
|
||||
|
||||
SENSOR_TYPES = (
|
||||
RfxtrxSensorEntityDescription(
|
||||
key="Barameter",
|
||||
key="Barometer",
|
||||
device_class=DEVICE_CLASS_PRESSURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
native_unit_of_measurement=PRESSURE_HPA,
|
||||
|
@ -144,7 +144,7 @@ class SurePetcareAPI:
|
||||
"""Get the latest data from Sure Petcare."""
|
||||
|
||||
try:
|
||||
self.states = await self.surepy.get_entities()
|
||||
self.states = await self.surepy.get_entities(refresh=True)
|
||||
except SurePetcareError as error:
|
||||
_LOGGER.error("Unable to fetch data: %s", error)
|
||||
return
|
||||
|
@ -80,7 +80,7 @@ class ThinkingCleanerSwitch(SwitchEntity):
|
||||
self.last_lock_time = None
|
||||
self.graceful_state = False
|
||||
|
||||
self._attr_name = f"{tc_object} {description.name}"
|
||||
self._attr_name = f"{tc_object.name} {description.name}"
|
||||
|
||||
def lock_update(self):
|
||||
"""Lock the update since TC clean takes some time to update."""
|
||||
|
@ -116,6 +116,13 @@ MODEL_AIRQUALITYMONITOR_B1 = "cgllc.airmonitor.b1"
|
||||
MODEL_AIRQUALITYMONITOR_S1 = "cgllc.airmonitor.s1"
|
||||
MODEL_AIRQUALITYMONITOR_CGDN1 = "cgllc.airm.cgdn1"
|
||||
|
||||
MODELS_AIR_QUALITY_MONITOR = [
|
||||
MODEL_AIRQUALITYMONITOR_V1,
|
||||
MODEL_AIRQUALITYMONITOR_B1,
|
||||
MODEL_AIRQUALITYMONITOR_S1,
|
||||
MODEL_AIRQUALITYMONITOR_CGDN1,
|
||||
]
|
||||
|
||||
# Light Models
|
||||
MODELS_LIGHT_EYECARE = ["philips.light.sread1"]
|
||||
MODELS_LIGHT_CEILING = ["philips.light.ceiling", "philips.light.zyceiling"]
|
||||
|
@ -405,36 +405,42 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||
self._preset_modes = PRESET_MODES_AIRPURIFIER_PRO
|
||||
self._supported_features = SUPPORT_PRESET_MODE
|
||||
self._speed_count = 1
|
||||
self._operation_mode_class = AirpurifierOperationMode
|
||||
elif self._model == MODEL_AIRPURIFIER_PRO_V7:
|
||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_PRO_V7
|
||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_PRO_V7
|
||||
self._preset_modes = PRESET_MODES_AIRPURIFIER_PRO_V7
|
||||
self._supported_features = SUPPORT_PRESET_MODE
|
||||
self._speed_count = 1
|
||||
self._operation_mode_class = AirpurifierOperationMode
|
||||
elif self._model in [MODEL_AIRPURIFIER_2S, MODEL_AIRPURIFIER_2H]:
|
||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_2S
|
||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_COMMON
|
||||
self._preset_modes = PRESET_MODES_AIRPURIFIER_2S
|
||||
self._supported_features = SUPPORT_PRESET_MODE
|
||||
self._speed_count = 1
|
||||
self._operation_mode_class = AirpurifierOperationMode
|
||||
elif self._model in MODELS_PURIFIER_MIOT:
|
||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_MIOT
|
||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_MIOT
|
||||
self._preset_modes = PRESET_MODES_AIRPURIFIER_MIOT
|
||||
self._supported_features = SUPPORT_SET_SPEED | SUPPORT_PRESET_MODE
|
||||
self._speed_count = 3
|
||||
self._operation_mode_class = AirpurifierMiotOperationMode
|
||||
elif self._model == MODEL_AIRPURIFIER_V3:
|
||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_V3
|
||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER_V3
|
||||
self._preset_modes = PRESET_MODES_AIRPURIFIER_V3
|
||||
self._supported_features = SUPPORT_PRESET_MODE
|
||||
self._speed_count = 1
|
||||
self._operation_mode_class = AirpurifierOperationMode
|
||||
else:
|
||||
self._device_features = FEATURE_FLAGS_AIRPURIFIER_MIIO
|
||||
self._available_attributes = AVAILABLE_ATTRIBUTES_AIRPURIFIER
|
||||
self._preset_modes = PRESET_MODES_AIRPURIFIER
|
||||
self._supported_features = SUPPORT_PRESET_MODE
|
||||
self._speed_count = 1
|
||||
self._operation_mode_class = AirpurifierOperationMode
|
||||
|
||||
self._state_attrs.update(
|
||||
{attribute: None for attribute in self._available_attributes}
|
||||
@ -446,7 +452,7 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||
def preset_mode(self):
|
||||
"""Get the active preset mode."""
|
||||
if self._state:
|
||||
preset_mode = AirpurifierOperationMode(self._state_attrs[ATTR_MODE]).name
|
||||
preset_mode = self._operation_mode_class(self._mode).name
|
||||
return preset_mode if preset_mode in self._preset_modes else None
|
||||
|
||||
return None
|
||||
@ -455,7 +461,7 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||
def percentage(self):
|
||||
"""Return the current percentage based speed."""
|
||||
if self._state:
|
||||
mode = AirpurifierOperationMode(self._state_attrs[ATTR_MODE])
|
||||
mode = self._operation_mode_class(self._state_attrs[ATTR_MODE])
|
||||
if mode in self.REVERSE_SPEED_MODE_MAPPING:
|
||||
return ranged_value_to_percentage(
|
||||
(1, self._speed_count), self.REVERSE_SPEED_MODE_MAPPING[mode]
|
||||
@ -479,7 +485,7 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||
await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
AirpurifierOperationMode(self.SPEED_MODE_MAPPING[speed_mode]),
|
||||
self._operation_mode_class(self.SPEED_MODE_MAPPING[speed_mode]),
|
||||
)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
@ -490,11 +496,13 @@ class XiaomiAirPurifier(XiaomiGenericDevice):
|
||||
if preset_mode not in self.preset_modes:
|
||||
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
|
||||
return
|
||||
await self._try_command(
|
||||
if await self._try_command(
|
||||
"Setting operation mode of the miio device failed.",
|
||||
self._device.set_mode,
|
||||
self.PRESET_MODE_MAPPING[preset_mode],
|
||||
)
|
||||
):
|
||||
self._mode = self._operation_mode_class[preset_mode].value
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_extra_features(self, features: int = 1):
|
||||
"""Set the extra features."""
|
||||
@ -538,15 +546,6 @@ class XiaomiAirPurifierMiot(XiaomiAirPurifier):
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Get the active preset mode."""
|
||||
if self._state:
|
||||
preset_mode = AirpurifierMiotOperationMode(self._mode).name
|
||||
return preset_mode if preset_mode in self._preset_modes else None
|
||||
|
||||
return None
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan.
|
||||
|
||||
|
@ -210,7 +210,7 @@ class XiaomiAirHumidifier(XiaomiGenericHumidifier, HumidifierEntity):
|
||||
self._available_modes = AVAILABLE_MODES_MJJSQ
|
||||
self._min_humidity = 30
|
||||
self._max_humidity = 80
|
||||
self._humidity_steps = 10
|
||||
self._humidity_steps = 100
|
||||
else:
|
||||
self._available_modes = AVAILABLE_MODES_OTHER
|
||||
self._min_humidity = 30
|
||||
|
@ -66,6 +66,7 @@ from .const import (
|
||||
MODEL_FAN_ZA1,
|
||||
MODEL_FAN_ZA3,
|
||||
MODEL_FAN_ZA4,
|
||||
MODELS_AIR_QUALITY_MONITOR,
|
||||
MODELS_HUMIDIFIER_MIIO,
|
||||
MODELS_HUMIDIFIER_MIOT,
|
||||
MODELS_HUMIDIFIER_MJJSQ,
|
||||
@ -371,23 +372,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
host = config_entry.data[CONF_HOST]
|
||||
token = config_entry.data[CONF_TOKEN]
|
||||
model = config_entry.data[CONF_MODEL]
|
||||
device = hass.data[DOMAIN][config_entry.entry_id].get(KEY_DEVICE)
|
||||
sensors = []
|
||||
|
||||
if model in (MODEL_FAN_ZA1, MODEL_FAN_ZA3, MODEL_FAN_ZA4, MODEL_FAN_P5):
|
||||
return
|
||||
if model in MODEL_TO_SENSORS_MAP:
|
||||
sensors = MODEL_TO_SENSORS_MAP[model]
|
||||
elif model in MODELS_HUMIDIFIER_MIOT:
|
||||
sensors = HUMIDIFIER_MIOT_SENSORS
|
||||
elif model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
sensors = HUMIDIFIER_MJJSQ_SENSORS
|
||||
elif model in MODELS_HUMIDIFIER_MIIO:
|
||||
sensors = HUMIDIFIER_MIIO_SENSORS
|
||||
elif model in MODELS_PURIFIER_MIIO:
|
||||
sensors = PURIFIER_MIIO_SENSORS
|
||||
elif model in MODELS_PURIFIER_MIOT:
|
||||
sensors = PURIFIER_MIOT_SENSORS
|
||||
else:
|
||||
|
||||
if model in MODELS_AIR_QUALITY_MONITOR:
|
||||
unique_id = config_entry.unique_id
|
||||
name = config_entry.title
|
||||
_LOGGER.debug("Initializing with host %s (token %s...)", host, token[:5])
|
||||
@ -399,19 +388,35 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
name, device, config_entry, unique_id, description
|
||||
)
|
||||
)
|
||||
for sensor, description in SENSOR_TYPES.items():
|
||||
if sensor not in sensors:
|
||||
continue
|
||||
entities.append(
|
||||
XiaomiGenericSensor(
|
||||
f"{config_entry.title} {description.name}",
|
||||
device,
|
||||
config_entry,
|
||||
f"{sensor}_{config_entry.unique_id}",
|
||||
hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
|
||||
description,
|
||||
else:
|
||||
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
|
||||
sensors = []
|
||||
if model in MODEL_TO_SENSORS_MAP:
|
||||
sensors = MODEL_TO_SENSORS_MAP[model]
|
||||
elif model in MODELS_HUMIDIFIER_MIOT:
|
||||
sensors = HUMIDIFIER_MIOT_SENSORS
|
||||
elif model in MODELS_HUMIDIFIER_MJJSQ:
|
||||
sensors = HUMIDIFIER_MJJSQ_SENSORS
|
||||
elif model in MODELS_HUMIDIFIER_MIIO:
|
||||
sensors = HUMIDIFIER_MIIO_SENSORS
|
||||
elif model in MODELS_PURIFIER_MIIO:
|
||||
sensors = PURIFIER_MIIO_SENSORS
|
||||
elif model in MODELS_PURIFIER_MIOT:
|
||||
sensors = PURIFIER_MIOT_SENSORS
|
||||
|
||||
for sensor, description in SENSOR_TYPES.items():
|
||||
if sensor not in sensors:
|
||||
continue
|
||||
entities.append(
|
||||
XiaomiGenericSensor(
|
||||
f"{config_entry.title} {description.name}",
|
||||
device,
|
||||
config_entry,
|
||||
f"{sensor}_{config_entry.unique_id}",
|
||||
hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
|
||||
description,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
@ -108,7 +108,7 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={
|
||||
CONF_DEVICE: {
|
||||
**current_entry.data[CONF_DEVICE],
|
||||
**current_entry.data.get(CONF_DEVICE, {}),
|
||||
CONF_DEVICE_PATH: dev_path,
|
||||
},
|
||||
}
|
||||
@ -172,7 +172,7 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={
|
||||
CONF_DEVICE: {
|
||||
**current_entry.data[CONF_DEVICE],
|
||||
**current_entry.data.get(CONF_DEVICE, {}),
|
||||
CONF_DEVICE_PATH: device_path,
|
||||
},
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
from zwave_js_server.client import Client as ZwaveClient
|
||||
from zwave_js_server.const.command_class.barrior_operator import BarrierState
|
||||
from zwave_js_server.const.command_class.barrier_operator import BarrierState
|
||||
from zwave_js_server.model.value import Value as ZwaveValue
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
|
@ -32,8 +32,8 @@ from zwave_js_server.const.command_class.multilevel_sensor import (
|
||||
)
|
||||
from zwave_js_server.model.node import Node as ZwaveNode
|
||||
from zwave_js_server.model.value import Value as ZwaveValue, get_value_id
|
||||
from zwave_js_server.util.command_class import (
|
||||
get_meter_scale_type,
|
||||
from zwave_js_server.util.command_class.meter import get_meter_scale_type
|
||||
from zwave_js_server.util.command_class.multilevel_sensor import (
|
||||
get_multilevel_sensor_type,
|
||||
)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Z-Wave JS",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/zwave_js",
|
||||
"requirements": ["zwave-js-server-python==0.29.1"],
|
||||
"requirements": ["zwave-js-server-python==0.30.0"],
|
||||
"codeowners": ["@home-assistant/z-wave"],
|
||||
"dependencies": ["usb", "http", "websocket_api"],
|
||||
"iot_class": "local_push",
|
||||
|
@ -15,7 +15,7 @@ from zwave_js_server.const.command_class.meter import (
|
||||
)
|
||||
from zwave_js_server.model.node import Node as ZwaveNode
|
||||
from zwave_js_server.model.value import ConfigurationValue
|
||||
from zwave_js_server.util.command_class import get_meter_type
|
||||
from zwave_js_server.util.command_class.meter import get_meter_type
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
DEVICE_CLASS_ENERGY,
|
||||
|
@ -5,7 +5,7 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
from zwave_js_server.client import Client as ZwaveClient
|
||||
from zwave_js_server.const.command_class.barrior_operator import (
|
||||
from zwave_js_server.const.command_class.barrier_operator import (
|
||||
BarrierEventSignalingSubsystemState,
|
||||
)
|
||||
|
||||
|
@ -5,7 +5,7 @@ from typing import Final
|
||||
|
||||
MAJOR_VERSION: Final = 2021
|
||||
MINOR_VERSION: Final = 9
|
||||
PATCH_VERSION: Final = "3"
|
||||
PATCH_VERSION: Final = "4"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||
|
@ -1599,7 +1599,7 @@ pymailgunner==1.4
|
||||
pymata-express==1.19
|
||||
|
||||
# homeassistant.components.mazda
|
||||
pymazda==0.2.0
|
||||
pymazda==0.2.1
|
||||
|
||||
# homeassistant.components.mediaroom
|
||||
pymediaroom==0.6.4.1
|
||||
@ -2489,4 +2489,4 @@ zigpy==0.37.1
|
||||
zm-py==0.5.2
|
||||
|
||||
# homeassistant.components.zwave_js
|
||||
zwave-js-server-python==0.29.1
|
||||
zwave-js-server-python==0.30.0
|
||||
|
@ -921,7 +921,7 @@ pymailgunner==1.4
|
||||
pymata-express==1.19
|
||||
|
||||
# homeassistant.components.mazda
|
||||
pymazda==0.2.0
|
||||
pymazda==0.2.1
|
||||
|
||||
# homeassistant.components.melcloud
|
||||
pymelcloud==2.5.3
|
||||
@ -1400,4 +1400,4 @@ zigpy-znp==0.5.4
|
||||
zigpy==0.37.1
|
||||
|
||||
# homeassistant.components.zwave_js
|
||||
zwave-js-server-python==0.29.1
|
||||
zwave-js-server-python==0.30.0
|
||||
|
@ -1289,6 +1289,45 @@ async def test_logbook_entity_matches_only(hass, hass_client):
|
||||
assert json_dict[1]["context_user_id"] == "9400facee45711eaa9308bfd3d19e474"
|
||||
|
||||
|
||||
async def test_custom_log_entry_discoverable_via_entity_matches_only(hass, hass_client):
|
||||
"""Test if a custom log entry is later discoverable via entity_matches_only."""
|
||||
await hass.async_add_executor_job(init_recorder_component, hass)
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
|
||||
|
||||
logbook.async_log_entry(
|
||||
hass,
|
||||
"Alarm",
|
||||
"is triggered",
|
||||
"switch",
|
||||
"switch.test_switch",
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_add_executor_job(trigger_db_commit, hass)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_add_executor_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
|
||||
|
||||
client = await hass_client()
|
||||
|
||||
# Today time 00:00:00
|
||||
start = dt_util.utcnow().date()
|
||||
start_date = datetime(start.year, start.month, start.day)
|
||||
|
||||
# Test today entries with filter by end_time
|
||||
end_time = start + timedelta(hours=24)
|
||||
response = await client.get(
|
||||
f"/api/logbook/{start_date.isoformat()}?end_time={end_time.isoformat()}&entity=switch.test_switch&entity_matches_only"
|
||||
)
|
||||
assert response.status == 200
|
||||
json_dict = await response.json()
|
||||
|
||||
assert len(json_dict) == 1
|
||||
|
||||
assert json_dict[0]["name"] == "Alarm"
|
||||
assert json_dict[0]["message"] == "is triggered"
|
||||
assert json_dict[0]["entity_id"] == "switch.test_switch"
|
||||
|
||||
|
||||
async def test_logbook_entity_matches_only_multiple(hass, hass_client):
|
||||
"""Test the logbook view with a multiple entities and entity_matches_only."""
|
||||
await hass.async_add_executor_job(init_recorder_component, hass)
|
||||
|
@ -7,12 +7,16 @@ from surepy import MESTART_RESOURCE
|
||||
from . import MOCK_API_DATA
|
||||
|
||||
|
||||
async def _mock_call(method, resource):
|
||||
if method == "GET" and resource == MESTART_RESOURCE:
|
||||
return {"data": MOCK_API_DATA}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def surepetcare():
|
||||
"""Mock the SurePetcare for easier testing."""
|
||||
with patch("surepy.SureAPIClient", autospec=True) as mock_client_class, patch(
|
||||
"surepy.find_token"
|
||||
):
|
||||
with patch("surepy.SureAPIClient", autospec=True) as mock_client_class:
|
||||
client = mock_client_class.return_value
|
||||
client.resources = {MESTART_RESOURCE: {"data": MOCK_API_DATA}}
|
||||
client.resources = {}
|
||||
client.call = _mock_call
|
||||
yield client
|
||||
|
@ -12,7 +12,7 @@ EXPECTED_ENTITY_IDS = {
|
||||
}
|
||||
|
||||
|
||||
async def test_binary_sensors(hass, surepetcare) -> None:
|
||||
async def test_sensors(hass, surepetcare) -> None:
|
||||
"""Test the generation of unique ids."""
|
||||
assert await async_setup_component(hass, DOMAIN, MOCK_CONFIG)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -113,6 +113,34 @@ async def test_discovery_via_zeroconf_ip_change(detect_mock, hass):
|
||||
}
|
||||
|
||||
|
||||
@patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True))
|
||||
@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
|
||||
async def test_discovery_via_zeroconf_ip_change_ignored(detect_mock, hass):
|
||||
"""Test zeroconf flow that was ignored gets updated."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id="tube_zb_gw_cc2652p2_poe",
|
||||
source=config_entries.SOURCE_IGNORE,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
service_info = {
|
||||
"host": "192.168.1.22",
|
||||
"port": 6053,
|
||||
"hostname": "tube_zb_gw_cc2652p2_poe.local.",
|
||||
"properties": {"address": "tube_zb_gw_cc2652p2_poe.local"},
|
||||
}
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"zha", context={"source": SOURCE_ZEROCONF}, data=service_info
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert entry.data[CONF_DEVICE] == {
|
||||
CONF_DEVICE_PATH: "socket://192.168.1.22:6638",
|
||||
}
|
||||
|
||||
|
||||
@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
|
||||
async def test_discovery_via_usb(detect_mock, hass):
|
||||
"""Test usb flow -- radio detected."""
|
||||
@ -317,6 +345,37 @@ async def test_discovery_via_usb_deconz_ignored(detect_mock, hass):
|
||||
assert result["step_id"] == "confirm"
|
||||
|
||||
|
||||
@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
|
||||
async def test_discovery_via_usb_zha_ignored_updates(detect_mock, hass):
|
||||
"""Test usb flow that was ignored gets updated."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
source=config_entries.SOURCE_IGNORE,
|
||||
data={},
|
||||
unique_id="AAAA:AAAA_1234_test_zigbee radio",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
await hass.async_block_till_done()
|
||||
discovery_info = {
|
||||
"device": "/dev/ttyZIGBEE",
|
||||
"pid": "AAAA",
|
||||
"vid": "AAAA",
|
||||
"serial_number": "1234",
|
||||
"description": "zigbee radio",
|
||||
"manufacturer": "test",
|
||||
}
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"zha", context={"source": SOURCE_USB}, data=discovery_info
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert result["type"] == RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert entry.data[CONF_DEVICE] == {
|
||||
CONF_DEVICE_PATH: "/dev/ttyZIGBEE",
|
||||
}
|
||||
|
||||
|
||||
@patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True))
|
||||
@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
|
||||
async def test_discovery_already_setup(detect_mock, hass):
|
||||
|
@ -338,7 +338,7 @@ async def test_add_node_secure(
|
||||
assert len(client.async_send_command.call_args_list) == 1
|
||||
assert client.async_send_command.call_args[0][0] == {
|
||||
"command": "controller.begin_inclusion",
|
||||
"options": {"inclusionStrategy": InclusionStrategy.SECURITY_S0},
|
||||
"options": {"strategy": InclusionStrategy.SECURITY_S0},
|
||||
}
|
||||
|
||||
client.async_send_command.reset_mock()
|
||||
@ -363,7 +363,7 @@ async def test_add_node(
|
||||
assert len(client.async_send_command.call_args_list) == 1
|
||||
assert client.async_send_command.call_args[0][0] == {
|
||||
"command": "controller.begin_inclusion",
|
||||
"options": {"inclusionStrategy": InclusionStrategy.INSECURE},
|
||||
"options": {"strategy": InclusionStrategy.INSECURE},
|
||||
}
|
||||
|
||||
event = Event(
|
||||
@ -671,7 +671,7 @@ async def test_replace_failed_node_secure(
|
||||
assert client.async_send_command.call_args[0][0] == {
|
||||
"command": "controller.replace_failed_node",
|
||||
"nodeId": nortek_thermostat.node_id,
|
||||
"options": {"inclusionStrategy": InclusionStrategy.SECURITY_S0},
|
||||
"options": {"strategy": InclusionStrategy.SECURITY_S0},
|
||||
}
|
||||
|
||||
client.async_send_command.reset_mock()
|
||||
@ -720,7 +720,7 @@ async def test_replace_failed_node(
|
||||
assert client.async_send_command.call_args[0][0] == {
|
||||
"command": "controller.replace_failed_node",
|
||||
"nodeId": nortek_thermostat.node_id,
|
||||
"options": {"inclusionStrategy": InclusionStrategy.INSECURE},
|
||||
"options": {"strategy": InclusionStrategy.INSECURE},
|
||||
}
|
||||
|
||||
client.async_send_command.reset_mock()
|
||||
|
Loading…
x
Reference in New Issue
Block a user