Compare commits

..

1 Commits

Author SHA1 Message Date
epenet
662554ec46 Drop single-use service name constants in blue_current 2026-02-27 09:17:11 +00:00
77 changed files with 7394 additions and 28600 deletions

4
CODEOWNERS generated
View File

@@ -1901,8 +1901,8 @@ build.json @home-assistant/supervisor
/tests/components/withings/ @joostlek
/homeassistant/components/wiz/ @sbidy @arturpragacz
/tests/components/wiz/ @sbidy @arturpragacz
/homeassistant/components/wled/ @frenck @mik-laj
/tests/components/wled/ @frenck @mik-laj
/homeassistant/components/wled/ @frenck
/tests/components/wled/ @frenck
/homeassistant/components/wmspro/ @mback2k
/tests/components/wmspro/ @mback2k
/homeassistant/components/wolflink/ @adamkrol93 @mtielen

View File

@@ -13,7 +13,6 @@ UID = "uid"
BCU_APP = "BCU-APP"
WITHOUT_CHARGING_CARD = "without_charging_card"
CHARGING_CARD_ID = "charging_card_id"
SERVICE_START_CHARGE_SESSION = "start_charge_session"
PLUG_AND_CHARGE = "plug_and_charge"
VALUE = "value"
PERMISSION = "permission"

View File

@@ -10,7 +10,7 @@ from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import config_validation as cv, device_registry as dr
from .const import BCU_APP, CHARGING_CARD_ID, DOMAIN, SERVICE_START_CHARGE_SESSION
from .const import BCU_APP, CHARGING_CARD_ID, DOMAIN
SERVICE_START_CHARGE_SESSION_SCHEMA = vol.Schema(
{
@@ -73,7 +73,7 @@ def async_setup_services(hass: HomeAssistant) -> None:
hass.services.async_register(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
start_charge_session,
SERVICE_START_CHARGE_SESSION_SCHEMA,
)

View File

@@ -64,8 +64,6 @@ SENSOR_TYPES: tuple[BSBLanSensorEntityDescription, ...] = (
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
state_class=SensorStateClass.TOTAL_INCREASING,
suggested_display_precision=0,
entity_registry_enabled_default=False,
value_fn=lambda data: (
data.sensor.total_energy.value
if data.sensor.total_energy is not None

View File

@@ -31,6 +31,10 @@ ATTR_FRIDAY_SLOTS = "friday_slots"
ATTR_SATURDAY_SLOTS = "saturday_slots"
ATTR_SUNDAY_SLOTS = "sunday_slots"
# Service names
SERVICE_SET_HOT_WATER_SCHEDULE = "set_hot_water_schedule"
SERVICE_SYNC_TIME = "sync_time"
# Schema for a single time slot
_SLOT_SCHEMA = vol.Schema(
@@ -256,14 +260,14 @@ def async_setup_services(hass: HomeAssistant) -> None:
"""Register the BSB-LAN services."""
hass.services.async_register(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
set_hot_water_schedule,
schema=SERVICE_SET_HOT_WATER_SCHEDULE_SCHEMA,
)
hass.services.async_register(
DOMAIN,
"sync_time",
SERVICE_SYNC_TIME,
async_sync_time,
schema=SYNC_TIME_SCHEMA,
)

View File

@@ -33,8 +33,6 @@ DUNEHD_PLAYER_SUPPORT: Final[MediaPlayerEntityFeature] = (
| MediaPlayerEntityFeature.PLAY
| MediaPlayerEntityFeature.PLAY_MEDIA
| MediaPlayerEntityFeature.BROWSE_MEDIA
| MediaPlayerEntityFeature.VOLUME_STEP
| MediaPlayerEntityFeature.VOLUME_MUTE
)

View File

@@ -405,13 +405,8 @@ CT_SENSORS = (
)
for cttype, key in (
(CtType.NET_CONSUMPTION, "lifetime_net_consumption"),
(CtType.PRODUCTION, "production_ct_energy_delivered"),
# Production CT energy_delivered is not used
(CtType.STORAGE, "lifetime_battery_discharged"),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_energy_delivered"),
(CtType.BACKFEED, "backfeed_ct_energy_delivered"),
(CtType.LOAD, "load_ct_energy_delivered"),
(CtType.EVSE, "evse_ct_energy_delivered"),
(CtType.PV3P, "pv3p_ct_energy_delivered"),
)
]
+ [
@@ -428,13 +423,8 @@ CT_SENSORS = (
)
for cttype, key in (
(CtType.NET_CONSUMPTION, "lifetime_net_production"),
(CtType.PRODUCTION, "production_ct_energy_received"),
# Production CT energy_received is not used
(CtType.STORAGE, "lifetime_battery_charged"),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_energy_received"),
(CtType.BACKFEED, "backfeed_ct_energy_received"),
(CtType.LOAD, "load_ct_energy_received"),
(CtType.EVSE, "evse_ct_energy_received"),
(CtType.PV3P, "pv3p_ct_energy_received"),
)
]
+ [
@@ -451,13 +441,8 @@ CT_SENSORS = (
)
for cttype, key in (
(CtType.NET_CONSUMPTION, "net_consumption"),
(CtType.PRODUCTION, "production_ct_power"),
# Production CT active_power is not used
(CtType.STORAGE, "battery_discharge"),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_power"),
(CtType.BACKFEED, "backfeed_ct_power"),
(CtType.LOAD, "load_ct_power"),
(CtType.EVSE, "evse_ct_power"),
(CtType.PV3P, "pv3p_ct_power"),
)
]
+ [
@@ -476,11 +461,6 @@ CT_SENSORS = (
(CtType.NET_CONSUMPTION, "frequency", "net_ct_frequency"),
(CtType.PRODUCTION, "production_ct_frequency", ""),
(CtType.STORAGE, "storage_ct_frequency", ""),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_frequency", ""),
(CtType.BACKFEED, "backfeed_ct_frequency", ""),
(CtType.LOAD, "load_ct_frequency", ""),
(CtType.EVSE, "evse_ct_frequency", ""),
(CtType.PV3P, "pv3p_ct_frequency", ""),
)
]
+ [
@@ -500,11 +480,6 @@ CT_SENSORS = (
(CtType.NET_CONSUMPTION, "voltage", "net_ct_voltage"),
(CtType.PRODUCTION, "production_ct_voltage", ""),
(CtType.STORAGE, "storage_voltage", "storage_ct_voltage"),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_voltage", ""),
(CtType.BACKFEED, "backfeed_ct_voltage", ""),
(CtType.LOAD, "load_ct_voltage", ""),
(CtType.EVSE, "evse_ct_voltage", ""),
(CtType.PV3P, "pv3p_ct_voltage", ""),
)
]
+ [
@@ -524,11 +499,6 @@ CT_SENSORS = (
(CtType.NET_CONSUMPTION, "net_ct_current"),
(CtType.PRODUCTION, "production_ct_current"),
(CtType.STORAGE, "storage_ct_current"),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_current"),
(CtType.BACKFEED, "backfeed_ct_current"),
(CtType.LOAD, "load_ct_current"),
(CtType.EVSE, "evse_ct_current"),
(CtType.PV3P, "pv3p_ct_current"),
)
]
+ [
@@ -546,11 +516,6 @@ CT_SENSORS = (
(CtType.NET_CONSUMPTION, "net_ct_powerfactor"),
(CtType.PRODUCTION, "production_ct_powerfactor"),
(CtType.STORAGE, "storage_ct_powerfactor"),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_powerfactor"),
(CtType.BACKFEED, "backfeed_ct_powerfactor"),
(CtType.LOAD, "load_ct_powerfactor"),
(CtType.EVSE, "evse_ct_powerfactor"),
(CtType.PV3P, "pv3p_ct_powerfactor"),
)
]
+ [
@@ -572,11 +537,6 @@ CT_SENSORS = (
),
(CtType.PRODUCTION, "production_ct_metering_status", ""),
(CtType.STORAGE, "storage_ct_metering_status", ""),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_metering_status", ""),
(CtType.BACKFEED, "backfeed_ct_metering_status", ""),
(CtType.LOAD, "load_ct_metering_status", ""),
(CtType.EVSE, "evse_ct_metering_status", ""),
(CtType.PV3P, "pv3p_ct_metering_status", ""),
)
]
+ [
@@ -597,11 +557,6 @@ CT_SENSORS = (
),
(CtType.PRODUCTION, "production_ct_status_flags", ""),
(CtType.STORAGE, "storage_ct_status_flags", ""),
(CtType.TOTAL_CONSUMPTION, "total_consumption_ct_status_flags", ""),
(CtType.BACKFEED, "backfeed_ct_status_flags", ""),
(CtType.LOAD, "load_ct_status_flags", ""),
(CtType.EVSE, "evse_ct_status_flags", ""),
(CtType.PV3P, "pv3p_ct_status_flags", ""),
)
]
)

View File

@@ -160,60 +160,6 @@
"available_energy": {
"name": "Available battery energy"
},
"backfeed_ct_current": {
"name": "Backfeed CT current"
},
"backfeed_ct_current_phase": {
"name": "Backfeed CT current {phase_name}"
},
"backfeed_ct_energy_delivered": {
"name": "Backfeed CT energy delivered"
},
"backfeed_ct_energy_delivered_phase": {
"name": "Backfeed CT energy delivered {phase_name}"
},
"backfeed_ct_energy_received": {
"name": "Backfeed CT energy received"
},
"backfeed_ct_energy_received_phase": {
"name": "Backfeed CT energy received {phase_name}"
},
"backfeed_ct_frequency": {
"name": "Frequency backfeed CT"
},
"backfeed_ct_frequency_phase": {
"name": "Frequency backfeed CT {phase_name}"
},
"backfeed_ct_metering_status": {
"name": "Metering status backfeed CT"
},
"backfeed_ct_metering_status_phase": {
"name": "Metering status backfeed CT {phase_name}"
},
"backfeed_ct_power": {
"name": "Backfeed CT power"
},
"backfeed_ct_power_phase": {
"name": "Backfeed CT power {phase_name}"
},
"backfeed_ct_powerfactor": {
"name": "Power factor backfeed CT"
},
"backfeed_ct_powerfactor_phase": {
"name": "Power factor backfeed CT {phase_name}"
},
"backfeed_ct_status_flags": {
"name": "Meter status flags active backfeed CT"
},
"backfeed_ct_status_flags_phase": {
"name": "Meter status flags active backfeed CT {phase_name}"
},
"backfeed_ct_voltage": {
"name": "Voltage backfeed CT"
},
"backfeed_ct_voltage_phase": {
"name": "Voltage backfeed CT {phase_name}"
},
"balanced_net_consumption": {
"name": "Balanced net power consumption"
},
@@ -265,60 +211,6 @@
"energy_today": {
"name": "[%key:component::enphase_envoy::entity::sensor::daily_production::name%]"
},
"evse_ct_current": {
"name": "EVSE CT current"
},
"evse_ct_current_phase": {
"name": "EVSE CT current {phase_name}"
},
"evse_ct_energy_delivered": {
"name": "EVSE CT energy delivered"
},
"evse_ct_energy_delivered_phase": {
"name": "EVSE CT energy delivered {phase_name}"
},
"evse_ct_energy_received": {
"name": "EVSE CT energy received"
},
"evse_ct_energy_received_phase": {
"name": "EVSE CT energy received {phase_name}"
},
"evse_ct_frequency": {
"name": "Frequency EVSE CT"
},
"evse_ct_frequency_phase": {
"name": "Frequency EVSE CT {phase_name}"
},
"evse_ct_metering_status": {
"name": "Metering status EVSE CT"
},
"evse_ct_metering_status_phase": {
"name": "Metering status EVSE CT {phase_name}"
},
"evse_ct_power": {
"name": "EVSE CT power"
},
"evse_ct_power_phase": {
"name": "EVSE CT power {phase_name}"
},
"evse_ct_powerfactor": {
"name": "Power factor EVSE CT"
},
"evse_ct_powerfactor_phase": {
"name": "Power factor EVSE CT {phase_name}"
},
"evse_ct_status_flags": {
"name": "Meter status flags active EVSE CT"
},
"evse_ct_status_flags_phase": {
"name": "Meter status flags active EVSE CT {phase_name}"
},
"evse_ct_voltage": {
"name": "Voltage EVSE CT"
},
"evse_ct_voltage_phase": {
"name": "Voltage EVSE CT {phase_name}"
},
"grid_status": {
"name": "[%key:component::enphase_envoy::entity::binary_sensor::grid_status::name%]",
"state": {
@@ -378,60 +270,6 @@
"lifetime_production_phase": {
"name": "Lifetime energy production {phase_name}"
},
"load_ct_current": {
"name": "Load CT current"
},
"load_ct_current_phase": {
"name": "Load CT current {phase_name}"
},
"load_ct_energy_delivered": {
"name": "Load CT energy delivered"
},
"load_ct_energy_delivered_phase": {
"name": "Load CT energy delivered {phase_name}"
},
"load_ct_energy_received": {
"name": "Load CT energy received"
},
"load_ct_energy_received_phase": {
"name": "Load CT energy received {phase_name}"
},
"load_ct_frequency": {
"name": "Frequency load CT"
},
"load_ct_frequency_phase": {
"name": "Frequency load CT {phase_name}"
},
"load_ct_metering_status": {
"name": "Metering status load CT"
},
"load_ct_metering_status_phase": {
"name": "Metering status load CT {phase_name}"
},
"load_ct_power": {
"name": "Load CT power"
},
"load_ct_power_phase": {
"name": "Load CT power {phase_name}"
},
"load_ct_powerfactor": {
"name": "Power factor load CT"
},
"load_ct_powerfactor_phase": {
"name": "Power factor load CT {phase_name}"
},
"load_ct_status_flags": {
"name": "Meter status flags active load CT"
},
"load_ct_status_flags_phase": {
"name": "Meter status flags active load CT {phase_name}"
},
"load_ct_voltage": {
"name": "Voltage load CT"
},
"load_ct_voltage_phase": {
"name": "Voltage load CT {phase_name}"
},
"max_capacity": {
"name": "Battery capacity"
},
@@ -493,18 +331,6 @@
"production_ct_current_phase": {
"name": "Production CT current {phase_name}"
},
"production_ct_energy_delivered": {
"name": "Production CT energy delivered"
},
"production_ct_energy_delivered_phase": {
"name": "Production CT energy delivered {phase_name}"
},
"production_ct_energy_received": {
"name": "Production CT energy received"
},
"production_ct_energy_received_phase": {
"name": "Production CT energy received {phase_name}"
},
"production_ct_frequency": {
"name": "Frequency production CT"
},
@@ -517,12 +343,6 @@
"production_ct_metering_status_phase": {
"name": "Metering status production CT {phase_name}"
},
"production_ct_power": {
"name": "Production CT power"
},
"production_ct_power_phase": {
"name": "Production CT power {phase_name}"
},
"production_ct_powerfactor": {
"name": "Power factor production CT"
},
@@ -541,60 +361,6 @@
"production_ct_voltage_phase": {
"name": "Voltage production CT {phase_name}"
},
"pv3p_ct_current": {
"name": "PV3P CT current"
},
"pv3p_ct_current_phase": {
"name": "PV3P CT current {phase_name}"
},
"pv3p_ct_energy_delivered": {
"name": "PV3P CT energy delivered"
},
"pv3p_ct_energy_delivered_phase": {
"name": "PV3P CT energy delivered {phase_name}"
},
"pv3p_ct_energy_received": {
"name": "PV3P CT energy received"
},
"pv3p_ct_energy_received_phase": {
"name": "PV3P CT energy received {phase_name}"
},
"pv3p_ct_frequency": {
"name": "Frequency PV3P CT"
},
"pv3p_ct_frequency_phase": {
"name": "Frequency PV3P CT {phase_name}"
},
"pv3p_ct_metering_status": {
"name": "Metering status PV3P CT"
},
"pv3p_ct_metering_status_phase": {
"name": "Metering status PV3P CT {phase_name}"
},
"pv3p_ct_power": {
"name": "PV3P CT power"
},
"pv3p_ct_power_phase": {
"name": "PV3P CT power {phase_name}"
},
"pv3p_ct_powerfactor": {
"name": "Power factor PV3P CT"
},
"pv3p_ct_powerfactor_phase": {
"name": "Power factor PV3P CT {phase_name}"
},
"pv3p_ct_status_flags": {
"name": "Meter status flags active PV3P CT"
},
"pv3p_ct_status_flags_phase": {
"name": "Meter status flags active PV3P CT {phase_name}"
},
"pv3p_ct_voltage": {
"name": "Voltage PV3P CT"
},
"pv3p_ct_voltage_phase": {
"name": "Voltage PV3P CT {phase_name}"
},
"reserve_energy": {
"name": "Reserve battery energy"
},
@@ -648,60 +414,6 @@
},
"storage_ct_voltage_phase": {
"name": "Voltage storage CT {phase_name}"
},
"total_consumption_ct_current": {
"name": "Total consumption CT current"
},
"total_consumption_ct_current_phase": {
"name": "Total consumption CT current {phase_name}"
},
"total_consumption_ct_energy_delivered": {
"name": "Total consumption CT energy delivered"
},
"total_consumption_ct_energy_delivered_phase": {
"name": "Total consumption CT energy delivered {phase_name}"
},
"total_consumption_ct_energy_received": {
"name": "Total consumption CT energy received"
},
"total_consumption_ct_energy_received_phase": {
"name": "Total consumption CT energy received {phase_name}"
},
"total_consumption_ct_frequency": {
"name": "Frequency total consumption CT"
},
"total_consumption_ct_frequency_phase": {
"name": "Frequency total consumption CT {phase_name}"
},
"total_consumption_ct_metering_status": {
"name": "Metering status total consumption CT"
},
"total_consumption_ct_metering_status_phase": {
"name": "Metering status total consumption CT {phase_name}"
},
"total_consumption_ct_power": {
"name": "Total consumption CT power"
},
"total_consumption_ct_power_phase": {
"name": "Total consumption CT power {phase_name}"
},
"total_consumption_ct_powerfactor": {
"name": "Power factor total consumption CT"
},
"total_consumption_ct_powerfactor_phase": {
"name": "Power factor total consumption CT {phase_name}"
},
"total_consumption_ct_status_flags": {
"name": "Meter status flags active total consumption CT"
},
"total_consumption_ct_status_flags_phase": {
"name": "Meter status flags active total consumption CT {phase_name}"
},
"total_consumption_ct_voltage": {
"name": "Voltage total consumption CT"
},
"total_consumption_ct_voltage_phase": {
"name": "Voltage total consumption CT {phase_name}"
}
},
"switch": {

View File

@@ -36,12 +36,12 @@ from homeassistant.const import (
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import dt as dt_util
from .const import ATTR_DURATION, ATTR_PERIOD, DOMAIN, EVOHOME_DATA, EvoService
from .const import ATTR_DURATION, ATTR_PERIOD, ATTR_SETPOINT, EVOHOME_DATA, EvoService
from .coordinator import EvoDataUpdateCoordinator
from .entity import EvoChild, EvoEntity
@@ -132,24 +132,6 @@ class EvoClimateEntity(EvoEntity, ClimateEntity):
_attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT]
_attr_temperature_unit = UnitOfTemperature.CELSIUS
async def async_clear_zone_override(self) -> None:
"""Clear the zone override; only supported by zones."""
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="zone_only_service",
translation_placeholders={"service": EvoService.CLEAR_ZONE_OVERRIDE},
)
async def async_set_zone_override(
self, setpoint: float, duration: timedelta | None = None
) -> None:
"""Set the zone override; only supported by zones."""
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="zone_only_service",
translation_placeholders={"service": EvoService.SET_ZONE_OVERRIDE},
)
class EvoZone(EvoChild, EvoClimateEntity):
"""Base for any evohome-compatible heating zone."""
@@ -188,22 +170,22 @@ class EvoZone(EvoChild, EvoClimateEntity):
| ClimateEntityFeature.TURN_ON
)
async def async_clear_zone_override(self) -> None:
"""Clear the zone's override, if any."""
await self.coordinator.call_client_api(self._evo_device.reset())
async def async_zone_svc_request(self, service: str, data: dict[str, Any]) -> None:
"""Process a service request (setpoint override) for a zone."""
if service == EvoService.CLEAR_ZONE_OVERRIDE:
await self.coordinator.call_client_api(self._evo_device.reset())
return
async def async_set_zone_override(
self, setpoint: float, duration: timedelta | None = None
) -> None:
"""Set the zone's override (mode/setpoint)."""
temperature = max(min(setpoint, self.max_temp), self.min_temp)
# otherwise it is EvoService.SET_ZONE_OVERRIDE
temperature = max(min(data[ATTR_SETPOINT], self.max_temp), self.min_temp)
if duration is not None:
if ATTR_DURATION in data:
duration: timedelta = data[ATTR_DURATION]
if duration.total_seconds() == 0:
await self._update_schedule()
until = self.setpoints.get("next_sp_from")
else:
until = dt_util.now() + duration
until = dt_util.now() + data[ATTR_DURATION]
else:
until = None # indefinitely

View File

@@ -12,7 +12,7 @@ from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .const import DOMAIN, EvoService
from .coordinator import EvoDataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
@@ -47,12 +47,22 @@ class EvoEntity(CoordinatorEntity[EvoDataUpdateCoordinator]):
raise NotImplementedError
if payload["unique_id"] != self._attr_unique_id:
return
if payload["service"] in (
EvoService.SET_ZONE_OVERRIDE,
EvoService.CLEAR_ZONE_OVERRIDE,
):
await self.async_zone_svc_request(payload["service"], payload["data"])
return
await self.async_tcs_svc_request(payload["service"], payload["data"])
async def async_tcs_svc_request(self, service: str, data: dict[str, Any]) -> None:
"""Process a service request (system mode) for a controller."""
raise NotImplementedError
async def async_zone_svc_request(self, service: str, data: dict[str, Any]) -> None:
"""Process a service request (setpoint override) for a zone."""
raise NotImplementedError
@property
def extra_state_attributes(self) -> Mapping[str, Any]:
"""Return the evohome-specific state attributes."""

View File

@@ -3,7 +3,7 @@
from __future__ import annotations
from datetime import timedelta
from typing import Any, Final
from typing import Final
from evohomeasync2.const import SZ_CAN_BE_TEMPORARY, SZ_SYSTEM_MODE, SZ_TIMING_MODE
from evohomeasync2.schemas.const import (
@@ -13,10 +13,9 @@ from evohomeasync2.schemas.const import (
)
import voluptuous as vol
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
from homeassistant.const import ATTR_MODE
from homeassistant.const import ATTR_ENTITY_ID, ATTR_MODE
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_validation as cv, service
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.service import verify_domain_control
@@ -26,38 +25,21 @@ from .coordinator import EvoDataUpdateCoordinator
# system mode schemas are built dynamically when the services are registered
# because supported modes can vary for edge-case systems
# Zone service schemas (registered as entity services)
CLEAR_ZONE_OVERRIDE_SCHEMA: Final[dict[str | vol.Marker, Any]] = {}
SET_ZONE_OVERRIDE_SCHEMA: Final[dict[str | vol.Marker, Any]] = {
vol.Required(ATTR_SETPOINT): vol.All(
vol.Coerce(float), vol.Range(min=4.0, max=35.0)
),
vol.Optional(ATTR_DURATION): vol.All(
cv.time_period,
vol.Range(min=timedelta(days=0), max=timedelta(days=1)),
),
}
def _register_zone_entity_services(hass: HomeAssistant) -> None:
"""Register entity-level services for zones."""
service.async_register_platform_entity_service(
hass,
DOMAIN,
EvoService.CLEAR_ZONE_OVERRIDE,
entity_domain=CLIMATE_DOMAIN,
schema=CLEAR_ZONE_OVERRIDE_SCHEMA,
func="async_clear_zone_override",
)
service.async_register_platform_entity_service(
hass,
DOMAIN,
EvoService.SET_ZONE_OVERRIDE,
entity_domain=CLIMATE_DOMAIN,
schema=SET_ZONE_OVERRIDE_SCHEMA,
func="async_set_zone_override",
)
CLEAR_ZONE_OVERRIDE_SCHEMA: Final = vol.Schema(
{vol.Required(ATTR_ENTITY_ID): cv.entity_id}
)
SET_ZONE_OVERRIDE_SCHEMA: Final = vol.Schema(
{
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
vol.Required(ATTR_SETPOINT): vol.All(
vol.Coerce(float), vol.Range(min=4.0, max=35.0)
),
vol.Optional(ATTR_DURATION): vol.All(
cv.time_period,
vol.Range(min=timedelta(days=0), max=timedelta(days=1)),
),
}
)
@callback
@@ -69,6 +51,8 @@ def setup_service_functions(
Not all Honeywell TCC-compatible systems support all operating modes. In addition,
each mode will require any of four distinct service schemas. This has to be
enumerated before registering the appropriate handlers.
It appears that all TCC-compatible systems support the same three zones modes.
"""
@verify_domain_control(DOMAIN)
@@ -88,6 +72,28 @@ def setup_service_functions(
}
async_dispatcher_send(hass, DOMAIN, payload)
@verify_domain_control(DOMAIN)
async def set_zone_override(call: ServiceCall) -> None:
"""Set the zone override (setpoint)."""
entity_id = call.data[ATTR_ENTITY_ID]
registry = er.async_get(hass)
registry_entry = registry.async_get(entity_id)
if registry_entry is None or registry_entry.platform != DOMAIN:
raise ValueError(f"'{entity_id}' is not a known {DOMAIN} entity")
if registry_entry.domain != "climate":
raise ValueError(f"'{entity_id}' is not an {DOMAIN} controller/zone")
payload = {
"unique_id": registry_entry.unique_id,
"service": call.service,
"data": call.data,
}
async_dispatcher_send(hass, DOMAIN, payload)
assert coordinator.tcs is not None # mypy
hass.services.async_register(DOMAIN, EvoService.REFRESH_SYSTEM, force_refresh)
@@ -150,4 +156,16 @@ def setup_service_functions(
schema=vol.Schema(vol.Any(*system_mode_schemas)),
)
_register_zone_entity_services(hass)
# The zone modes are consistent across all systems and use the same schema
hass.services.async_register(
DOMAIN,
EvoService.CLEAR_ZONE_OVERRIDE,
set_zone_override,
schema=CLEAR_ZONE_OVERRIDE_SCHEMA,
)
hass.services.async_register(
DOMAIN,
EvoService.SET_ZONE_OVERRIDE,
set_zone_override,
schema=SET_ZONE_OVERRIDE_SCHEMA,
)

View File

@@ -28,11 +28,14 @@ reset_system:
refresh_system:
set_zone_override:
target:
entity:
integration: evohome
domain: climate
fields:
entity_id:
required: true
example: climate.bathroom
selector:
entity:
integration: evohome
domain: climate
setpoint:
required: true
selector:
@@ -46,7 +49,10 @@ set_zone_override:
object:
clear_zone_override:
target:
entity:
integration: evohome
domain: climate
fields:
entity_id:
required: true
selector:
entity:
integration: evohome
domain: climate

View File

@@ -1,12 +1,13 @@
{
"exceptions": {
"zone_only_service": {
"message": "Only zones support the `{service}` action"
}
},
"services": {
"clear_zone_override": {
"description": "Sets a zone to follow its schedule.",
"fields": {
"entity_id": {
"description": "[%key:component::evohome::services::set_zone_override::fields::entity_id::description%]",
"name": "[%key:component::evohome::services::set_zone_override::fields::entity_id::name%]"
}
},
"name": "Clear zone override"
},
"refresh_system": {
@@ -42,6 +43,10 @@
"description": "The zone will revert to its schedule after this time. If 0 the change is until the next scheduled setpoint.",
"name": "Duration"
},
"entity_id": {
"description": "The entity ID of the Evohome zone.",
"name": "Entity"
},
"setpoint": {
"description": "The temperature to be used instead of the scheduled setpoint.",
"name": "Setpoint"

View File

@@ -45,10 +45,6 @@ async def async_user_store(hass: HomeAssistant, user_id: str) -> UserStore:
except BaseException as ex:
del stores[user_id]
future.set_exception(ex)
# Ensure the future is marked as retrieved
# since if there is no concurrent call it
# will otherwise never be retrieved.
future.exception()
raise
future.set_result(store)

View File

@@ -57,8 +57,8 @@
"battery_charge_discharge_state": {
"name": "Battery charge/discharge state",
"state": {
"charging": "[%key:common::state::charging%]",
"discharging": "[%key:common::state::discharging%]",
"charging": "Charging",
"discharging": "Discharging",
"static": "Static"
}
},

View File

@@ -5,13 +5,13 @@ from __future__ import annotations
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_API_TOKEN, CONF_URL
from homeassistant.const import CONF_API_TOKEN
from homeassistant.core import HomeAssistant
from . import PortainerConfigEntry
from .coordinator import PortainerCoordinator
TO_REDACT = [CONF_API_TOKEN, CONF_URL]
TO_REDACT = [CONF_API_TOKEN]
def _serialize_coordinator(coordinator: PortainerCoordinator) -> dict[str, Any]:

View File

@@ -38,12 +38,6 @@
"ssl": "[%key:common::config_flow::data::ssl%]",
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
},
"data_description": {
"group": "[%key:component::sma::config::step::user::data_description::group%]",
"host": "[%key:component::sma::config::step::user::data_description::host%]",
"ssl": "[%key:component::sma::config::step::user::data_description::ssl%]",
"verify_ssl": "[%key:component::sma::config::step::user::data_description::verify_ssl%]"
},
"description": "Use the following form to reconfigure your SMA device.",
"title": "Reconfigure SMA Solar Integration"
},
@@ -56,11 +50,7 @@
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
},
"data_description": {
"group": "The group of your SMA device, where the Modbus connection is configured",
"host": "The hostname or IP address of your SMA device",
"password": "The password for your SMA device",
"ssl": "Whether to use SSL to connect to your SMA device. This is required for newer SMA devices, but older devices do not support SSL",
"verify_ssl": "Whether to verify SSL certificates. Disable only if you have a self-signed certificate"
"host": "The hostname or IP address of your SMA device."
},
"description": "Enter your SMA device information.",
"title": "Set up SMA Solar"

View File

@@ -177,12 +177,6 @@
"on": "mdi:lightbulb-on"
}
},
"do_not_disturb": {
"default": "mdi:minus-circle-off",
"state": {
"on": "mdi:minus-circle"
}
},
"dry_plus": {
"default": "mdi:heat-wave"
},

View File

@@ -95,7 +95,6 @@ ROBOT_CLEANER_TURBO_MODE_STATE_MAP = {
ROBOT_CLEANER_MOVEMENT_MAP = {
"powerOff": "off",
"washingMop": "washing_mop",
}
OVEN_MODE = {
@@ -881,7 +880,6 @@ CAPABILITY_TO_SENSORS: dict[
"after",
"cleaning",
"pause",
"washing_mop",
],
device_class=SensorDeviceClass.ENUM,
value_fn=lambda value: ROBOT_CLEANER_MOVEMENT_MAP.get(value, value),

View File

@@ -718,8 +718,7 @@
"off": "[%key:common::state::off%]",
"pause": "[%key:common::state::paused%]",
"point": "Point",
"reserve": "Reserve",
"washing_mop": "Washing mop"
"reserve": "Reserve"
}
},
"robot_cleaner_turbo_mode": {
@@ -859,9 +858,6 @@
"display_lighting": {
"name": "Display lighting"
},
"do_not_disturb": {
"name": "Do not disturb"
},
"dry_plus": {
"name": "Dry plus"
},

View File

@@ -162,14 +162,6 @@ CAPABILITY_TO_SWITCHES: dict[Capability | str, SmartThingsSwitchEntityDescriptio
status_attribute=Attribute.STATUS,
entity_category=EntityCategory.CONFIG,
),
Capability.CUSTOM_DO_NOT_DISTURB_MODE: SmartThingsSwitchEntityDescription(
key=Capability.CUSTOM_DO_NOT_DISTURB_MODE,
translation_key="do_not_disturb",
status_attribute=Attribute.DO_NOT_DISTURB,
entity_category=EntityCategory.CONFIG,
on_command=Command.DO_NOT_DISTURB_ON,
off_command=Command.DO_NOT_DISTURB_OFF,
),
}
DISHWASHER_WASHING_OPTIONS_TO_SWITCHES: dict[
Attribute | str, SmartThingsDishwasherWashingOptionSwitchEntityDescription

View File

@@ -42,5 +42,5 @@
"iot_class": "local_push",
"loggers": ["switchbot"],
"quality_scale": "gold",
"requirements": ["PySwitchbot==1.1.0"]
"requirements": ["PySwitchbot==1.0.0"]
}

View File

@@ -236,6 +236,12 @@ class StateVacuumEntity(
if self.__vacuum_legacy_battery_icon:
self._report_deprecated_battery_properties("battery_icon")
@callback
def async_write_ha_state(self) -> None:
"""Write the state to the state machine."""
super().async_write_ha_state()
self._async_check_segments_issues()
@callback
def async_registry_entry_updated(self) -> None:
"""Run when the entity registry entry has been updated."""
@@ -508,6 +514,43 @@ class StateVacuumEntity(
return
options: Mapping[str, Any] = self.registry_entry.options.get(DOMAIN, {})
should_have_not_configured_issue = (
VacuumEntityFeature.CLEAN_AREA in self.supported_features
and options.get("area_mapping") is None
)
if (
should_have_not_configured_issue
and not self._segments_not_configured_issue_created
):
issue_id = (
f"{ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED}_{self.registry_entry.id}"
)
ir.async_create_issue(
self.hass,
DOMAIN,
issue_id,
data={
"entry_id": self.registry_entry.id,
"entity_id": self.entity_id,
},
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
translation_key=ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED,
translation_placeholders={
"entity_id": self.entity_id,
},
)
self._segments_not_configured_issue_created = True
elif (
not should_have_not_configured_issue
and self._segments_not_configured_issue_created
):
issue_id = (
f"{ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED}_{self.registry_entry.id}"
)
ir.async_delete_issue(self.hass, DOMAIN, issue_id)
self._segments_not_configured_issue_created = False
if self._segments_changed_last_seen is not None and (
VacuumEntityFeature.CLEAN_AREA not in self.supported_features

View File

@@ -93,6 +93,10 @@
"segments_changed": {
"description": "",
"title": "Vacuum segments have changed for {entity_id}"
},
"segments_mapping_not_configured": {
"description": "",
"title": "Vacuum segment mapping not configured for {entity_id}"
}
},
"selector": {

View File

@@ -1,7 +1,7 @@
{
"domain": "wled",
"name": "WLED",
"codeowners": ["@frenck", "@mik-laj"],
"codeowners": ["@frenck"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wled",
"integration_type": "device",

View File

@@ -32,11 +32,8 @@ def write_utf8_file_atomic(
Using this function frequently will significantly
negatively impact performance.
"""
encoding = "utf-8" if "b" not in mode else None
try:
with AtomicWriter( # type: ignore[call-arg] # atomicwrites-stubs is outdated, encoding is a valid kwarg
filename, mode=mode, overwrite=True, encoding=encoding
).open() as fdesc:
with AtomicWriter(filename, mode=mode, overwrite=True).open() as fdesc:
if not private:
os.fchmod(fdesc.fileno(), 0o644)
fdesc.write(utf8_data)

2
requirements_all.txt generated
View File

@@ -83,7 +83,7 @@ PyRMVtransport==0.3.3
PySrDaliGateway==0.19.3
# homeassistant.components.switchbot
PySwitchbot==1.1.0
PySwitchbot==1.0.0
# homeassistant.components.switchmate
PySwitchmate==0.5.1

View File

@@ -83,7 +83,7 @@ PyRMVtransport==0.3.3
PySrDaliGateway==0.19.3
# homeassistant.components.switchbot
PySwitchbot==1.1.0
PySwitchbot==1.0.0
# homeassistant.components.syncthru
PySyncThru==0.8.0

View File

@@ -213,7 +213,6 @@ async def test_reauth_flow_scenario(
ap_fixture: AirOSData,
mock_airos_client: AsyncMock,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
) -> None:
"""Test successful reauthentication."""
mock_config_entry.add_to_hass(hass)
@@ -221,15 +220,11 @@ async def test_reauth_flow_scenario(
mock_airos_client.login.side_effect = AirOSConnectionAuthenticationError
await hass.config_entries.async_setup(mock_config_entry.entry_id)
with patch(
"homeassistant.components.airos.config_flow.async_get_firmware_data",
side_effect=AirOSConnectionAuthenticationError,
):
flow = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH, "entry_id": mock_config_entry.entry_id},
data=mock_config_entry.data,
)
flow = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH, "entry_id": mock_config_entry.entry_id},
data=mock_config_entry.data,
)
assert flow["type"] == FlowResultType.FORM
assert flow["step_id"] == REAUTH_STEP
@@ -241,22 +236,20 @@ async def test_reauth_flow_scenario(
hostname=ap_fixture.host.hostname,
)
mock_firmware = AsyncMock(return_value=valid_data)
with (
patch(
"homeassistant.components.airos.config_flow.async_get_firmware_data",
new=mock_firmware,
new=AsyncMock(return_value=valid_data),
),
patch(
"homeassistant.components.airos.async_get_firmware_data",
new=mock_firmware,
new=AsyncMock(return_value=valid_data),
),
):
result = await hass.config_entries.flow.async_configure(
flow["flow_id"],
user_input={CONF_PASSWORD: NEW_PASSWORD},
)
await hass.async_block_till_done(wait_background_tasks=True)
# Always test resolution
assert result["type"] is FlowResultType.ABORT

View File

@@ -19,16 +19,18 @@ async def test_setup_entry(config_entry_setup: MockConfigEntry) -> None:
async def test_setup_entry_fails(
hass: HomeAssistant, config_entry: MockConfigEntry
) -> None:
"""Test failed setup of entry."""
"""Test successful setup of entry."""
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.axis.get_axis_api",
side_effect=axis.CannotConnect,
):
await hass.config_entries.async_setup(config_entry.entry_id)
mock_device = Mock()
mock_device.async_setup = AsyncMock(return_value=False)
assert config_entry.state is ConfigEntryState.SETUP_RETRY
with patch.object(axis, "AxisHub") as mock_device_class:
mock_device_class.return_value = mock_device
assert not await hass.config_entries.async_setup(config_entry.entry_id)
assert config_entry.state is ConfigEntryState.SETUP_ERROR
async def test_unload_entry(

View File

@@ -13,11 +13,7 @@ import pytest
from voluptuous import MultipleInvalid
from homeassistant.components.blue_current import async_setup_entry
from homeassistant.components.blue_current.const import (
CHARGING_CARD_ID,
DOMAIN,
SERVICE_START_CHARGE_SESSION,
)
from homeassistant.components.blue_current.const import CHARGING_CARD_ID, DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_DEVICE_ID, Platform
from homeassistant.core import HomeAssistant
@@ -124,7 +120,7 @@ async def test_start_charging_action(
await hass.services.async_call(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
{
CONF_DEVICE_ID: list(device_registry.devices)[0],
CHARGING_CARD_ID: "TEST_CARD",
@@ -144,7 +140,7 @@ async def test_start_charging_action_without_card(
await hass.services.async_call(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
{
CONF_DEVICE_ID: list(device_registry.devices)[0],
},
@@ -166,7 +162,7 @@ async def test_start_charging_action_errors(
# No device id
await hass.services.async_call(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
{},
blocking=True,
)
@@ -175,7 +171,7 @@ async def test_start_charging_action_errors(
# Invalid device id
await hass.services.async_call(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
{CONF_DEVICE_ID: "INVALID"},
blocking=True,
)
@@ -192,7 +188,7 @@ async def test_start_charging_action_errors(
):
await hass.services.async_call(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
{
CONF_DEVICE_ID: list(device_registry.devices)[0],
},
@@ -212,7 +208,7 @@ async def test_start_charging_action_errors(
):
await hass.services.async_call(
DOMAIN,
SERVICE_START_CHARGE_SESSION,
"start_charge_session",
{
CONF_DEVICE_ID: list(device_registry.devices)[0],
},

View File

@@ -139,7 +139,7 @@
'object_id_base': 'Total energy',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,

View File

@@ -3,7 +3,6 @@
from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.const import Platform
@@ -19,7 +18,6 @@ ENTITY_OUTSIDE_TEMP = "sensor.bsb_lan_outside_temperature"
ENTITY_TOTAL_ENERGY = "sensor.bsb_lan_total_energy"
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_sensor_entity_properties(
hass: HomeAssistant,
mock_bsblan: AsyncMock,

View File

@@ -10,6 +10,10 @@ import pytest
import voluptuous as vol
from homeassistant.components.bsblan.const import DOMAIN
from homeassistant.components.bsblan.services import (
SERVICE_SET_HOT_WATER_SCHEDULE,
async_setup_services,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import device_registry as dr
@@ -130,7 +134,7 @@ async def test_set_hot_water_schedule(
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
service_call_data,
blocking=True,
)
@@ -159,7 +163,7 @@ async def test_invalid_device_id(
with pytest.raises(ServiceValidationError) as exc_info:
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": "invalid_device_id",
"monday_slots": [
@@ -172,12 +176,11 @@ async def test_invalid_device_id(
assert exc_info.value.translation_key == "invalid_device_id"
@pytest.mark.usefixtures("setup_integration")
@pytest.mark.parametrize(
("service_name", "service_data"),
[
(
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{"monday_slots": [{"start_time": time(6, 0), "end_time": time(8, 0)}]},
),
("sync_time", {}),
@@ -202,6 +205,9 @@ async def test_no_config_entry_for_device(
name="Other Device",
)
# Register the bsblan service without setting up any bsblan config entry
async_setup_services(hass)
with pytest.raises(ServiceValidationError) as exc_info:
await hass.services.async_call(
DOMAIN,
@@ -216,15 +222,26 @@ async def test_no_config_entry_for_device(
async def test_config_entry_not_loaded(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
device_entry: dr.DeviceEntry,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test error when config entry is not loaded."""
await hass.config_entries.async_unload(mock_config_entry.entry_id)
# Add the config entry but don't set it up (so it stays in NOT_LOADED state)
mock_config_entry.add_to_hass(hass)
# Create the device manually since setup won't run
device_entry = device_registry.async_get_or_create(
config_entry_id=mock_config_entry.entry_id,
identifiers={(DOMAIN, TEST_DEVICE_MAC)},
name="BSB-LAN Device",
)
# Register the service
async_setup_services(hass)
with pytest.raises(ServiceValidationError) as exc_info:
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": device_entry.id,
"monday_slots": [
@@ -249,7 +266,7 @@ async def test_api_error(
with pytest.raises(HomeAssistantError) as exc_info:
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": device_entry.id,
"monday_slots": [
@@ -285,7 +302,7 @@ async def test_time_validation_errors(
with pytest.raises(ServiceValidationError) as exc_info:
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": device_entry.id,
"monday_slots": [
@@ -308,7 +325,7 @@ async def test_unprovided_days_are_none(
# Only provide Monday and Tuesday, leave other days unprovided
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": device_entry.id,
"monday_slots": [
@@ -352,7 +369,7 @@ async def test_string_time_formats(
# Test with string time formats
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": device_entry.id,
"monday_slots": [
@@ -389,7 +406,7 @@ async def test_non_standard_time_types(
with pytest.raises(vol.MultipleInvalid):
await hass.services.async_call(
DOMAIN,
"set_hot_water_schedule",
SERVICE_SET_HOT_WATER_SCHEDULE,
{
"device_id": device_entry.id,
"monday_slots": [
@@ -407,7 +424,7 @@ async def test_async_setup_services(
) -> None:
"""Test service registration."""
# Verify service doesn't exist initially
assert not hass.services.has_service(DOMAIN, "set_hot_water_schedule")
assert not hass.services.has_service(DOMAIN, SERVICE_SET_HOT_WATER_SCHEDULE)
# Set up the integration
mock_config_entry.add_to_hass(hass)
@@ -415,7 +432,7 @@ async def test_async_setup_services(
await hass.async_block_till_done()
# Verify service is now registered
assert hass.services.has_service(DOMAIN, "set_hot_water_schedule")
assert hass.services.has_service(DOMAIN, SERVICE_SET_HOT_WATER_SCHEDULE)
async def test_sync_time_service(

View File

@@ -1,8 +1,7 @@
"""Tests for the Daikin config flow."""
from collections.abc import Generator
from ipaddress import ip_address
from unittest.mock import AsyncMock, PropertyMock, patch
from unittest.mock import PropertyMock, patch
from aiohttp import ClientError, web_exceptions
from pydaikin.exceptions import DaikinException
@@ -21,15 +20,6 @@ MAC = "AABBCCDDEEFF"
HOST = "127.0.0.1"
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.daikin.async_setup_entry", return_value=True
) as mock_setup:
yield mock_setup
@pytest.fixture
def mock_daikin():
"""Mock pydaikin."""

View File

@@ -1,10 +1,5 @@
"""Tests for emulated_roku config flow."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
import pytest
from homeassistant import config_entries
from homeassistant.components.emulated_roku import config_flow
from homeassistant.core import HomeAssistant
@@ -13,15 +8,6 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Override async_setup_entry."""
with patch(
"homeassistant.components.emulated_roku.async_setup_entry", return_value=True
) as mock_setup:
yield mock_setup
async def test_flow_works(hass: HomeAssistant) -> None:
"""Test that config flow works."""
result = await hass.config_entries.flow.async_init(

View File

@@ -196,66 +196,6 @@
"measurement_type": "storage",
"metering_status": "normal",
"status_flags": []
},
"backfeed": {
"eid": "100000040",
"timestamp": 1708006120,
"energy_delivered": 41234,
"energy_received": 42345,
"active_power": 104,
"power_factor": 0.24,
"voltage": 114,
"current": 0.5,
"frequency": 50.4,
"state": "enabled",
"measurement_type": "backfeed",
"metering_status": "normal",
"status_flags": []
},
"load": {
"eid": "100000050",
"timestamp": 1708006120,
"energy_delivered": 51234,
"energy_received": 52345,
"active_power": 105,
"power_factor": 0.25,
"voltage": 115,
"current": 0.6,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "load",
"metering_status": "normal",
"status_flags": []
},
"evse": {
"eid": "100000060",
"timestamp": 1708006120,
"energy_delivered": 61234,
"energy_received": 62345,
"active_power": 106,
"power_factor": 0.26,
"voltage": 116,
"current": 0.7,
"frequency": 50.7,
"state": "enabled",
"measurement_type": "evse",
"metering_status": "normal",
"status_flags": []
},
"pv3p": {
"eid": "100000070",
"timestamp": 1708006120,
"energy_delivered": 71234,
"energy_received": 72345,
"active_power": 107,
"power_factor": 0.27,
"voltage": 117,
"current": 0.8,
"frequency": 50.8,
"state": "enabled",
"measurement_type": "pv3p",
"metering_status": "normal",
"status_flags": []
}
},
"ctmeters_phases": {
@@ -399,194 +339,6 @@
"metering_status": "normal",
"status_flags": []
}
},
"backfeed": {
"L1": {
"eid": "100000041",
"timestamp": 1708006121,
"energy_delivered": 412341,
"energy_received": 423451,
"active_power": 114,
"power_factor": 0.24,
"voltage": 114,
"current": 4.1,
"frequency": 50.4,
"state": "enabled",
"measurement_type": "backfeed",
"metering_status": "normal",
"status_flags": []
},
"L2": {
"eid": "100000042",
"timestamp": 1708006122,
"energy_delivered": 412342,
"energy_received": 423452,
"active_power": 124,
"power_factor": 0.24,
"voltage": 114,
"current": 4.2,
"frequency": 50.4,
"state": "enabled",
"measurement_type": "backfeed",
"metering_status": "normal",
"status_flags": []
},
"L3": {
"eid": "100000042",
"timestamp": 1708006123,
"energy_delivered": 412343,
"energy_received": 423453,
"active_power": 134,
"power_factor": 0.24,
"voltage": 114,
"current": 4.3,
"frequency": 50.4,
"state": "enabled",
"measurement_type": "backfeed",
"metering_status": "normal",
"status_flags": []
}
},
"load": {
"L1": {
"eid": "100000051",
"timestamp": 1708006121,
"energy_delivered": 512341,
"energy_received": 523451,
"active_power": 115,
"power_factor": 0.25,
"voltage": 115,
"current": 5.1,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "load",
"metering_status": "normal",
"status_flags": []
},
"L2": {
"eid": "100000052",
"timestamp": 1708006122,
"energy_delivered": 512342,
"energy_received": 523452,
"active_power": 125,
"power_factor": 0.25,
"voltage": 115,
"current": 5.2,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "load",
"metering_status": "normal",
"status_flags": []
},
"L3": {
"eid": "100000052",
"timestamp": 1708006123,
"energy_delivered": 512343,
"energy_received": 523453,
"active_power": 135,
"power_factor": 0.25,
"voltage": 115,
"current": 5.3,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "load",
"metering_status": "normal",
"status_flags": []
}
},
"evse": {
"L1": {
"eid": "100000061",
"timestamp": 1708006121,
"energy_delivered": 612341,
"energy_received": 623451,
"active_power": 116,
"power_factor": 0.26,
"voltage": 116,
"current": 6.1,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "evse",
"metering_status": "normal",
"status_flags": []
},
"L2": {
"eid": "100000062",
"timestamp": 1708006122,
"energy_delivered": 612342,
"energy_received": 623452,
"active_power": 126,
"power_factor": 0.26,
"voltage": 116,
"current": 6.2,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "evse",
"metering_status": "normal",
"status_flags": []
},
"L3": {
"eid": "100000063",
"timestamp": 1708006123,
"energy_delivered": 612343,
"energy_received": 623453,
"active_power": 136,
"power_factor": 0.26,
"voltage": 116,
"current": 6.3,
"frequency": 50.6,
"state": "enabled",
"measurement_type": "evse",
"metering_status": "normal",
"status_flags": []
}
},
"pv3p": {
"L1": {
"eid": "100000071",
"timestamp": 1708006127,
"energy_delivered": 712341,
"energy_received": 723451,
"active_power": 117,
"power_factor": 0.27,
"voltage": 117,
"current": 7.1,
"frequency": 50.7,
"state": "enabled",
"measurement_type": "pv3p",
"metering_status": "normal",
"status_flags": []
},
"L2": {
"eid": "100000072",
"timestamp": 1708006122,
"energy_delivered": 712342,
"energy_received": 723452,
"active_power": 127,
"power_factor": 0.27,
"voltage": 117,
"current": 7.2,
"frequency": 50.7,
"state": "enabled",
"measurement_type": "pv3p",
"metering_status": "normal",
"status_flags": []
},
"L3": {
"eid": "100000073",
"timestamp": 1708006123,
"energy_delivered": 712343,
"energy_received": 723453,
"active_power": 137,
"power_factor": 0.27,
"voltage": 117,
"current": 7.3,
"frequency": 50.7,
"state": "enabled",
"measurement_type": "pv3p",
"metering_status": "normal",
"status_flags": []
}
}
},
"ctmeter_production": {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
from pyenphase.exceptions import EnvoyError
from pyenphase.models.meters import CtType
import pytest
from syrupy.assertion import SnapshotAssertion
@@ -119,68 +118,6 @@ async def test_entry_diagnostics_with_interface_information(
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
# fix order of entities by device to avoid snapshot assertion
# failures due to changed id based order between test runs
diagnostics = await get_diagnostics_for_config_entry(
assert await get_diagnostics_for_config_entry(
hass, hass_client, config_entry
)
diagnostics["envoy_entities_by_device"] = [
{
"device": device_entities["device"],
"entities": sorted(
device_entities["entities"], key=lambda e: e["entity"]["entity_id"]
),
}
for device_entities in sorted(
diagnostics["envoy_entities_by_device"],
key=lambda e: e["device"]["identifiers"],
)
]
assert diagnostics == snapshot(exclude=limit_diagnostic_attrs)
@pytest.mark.parametrize(
("mock_envoy", "ctpresent"),
[
("envoy", ()),
("envoy_1p_metered", (CtType.PRODUCTION, CtType.NET_CONSUMPTION)),
("envoy_acb_batt", (CtType.PRODUCTION, CtType.NET_CONSUMPTION)),
("envoy_eu_batt", (CtType.PRODUCTION, CtType.NET_CONSUMPTION)),
(
"envoy_metered_batt_relay",
(
CtType.PRODUCTION,
CtType.NET_CONSUMPTION,
CtType.STORAGE,
CtType.BACKFEED,
CtType.LOAD,
CtType.EVSE,
CtType.PV3P,
),
),
("envoy_nobatt_metered_3p", (CtType.PRODUCTION, CtType.NET_CONSUMPTION)),
("envoy_tot_cons_metered", (CtType.PRODUCTION, CtType.TOTAL_CONSUMPTION)),
],
indirect=["mock_envoy"],
)
async def test_entry_diagnostics_ct_presence(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
mock_envoy: AsyncMock,
ctpresent: tuple[CtType, ...],
) -> None:
"""Test config entry diagnostics including interface data."""
await setup_integration(hass, config_entry)
diagnostics = await get_diagnostics_for_config_entry(
hass, hass_client, config_entry
)
# are expected ct in diagnostic report
for ct in ctpresent:
assert diagnostics["envoy_model_data"]["ctmeters"][ct]
# are no more ct in diagnostic report as in ctpresent
for ct in diagnostics["envoy_model_data"]["ctmeters"]:
assert ct in ctpresent
) == snapshot(exclude=limit_diagnostic_attrs)

View File

@@ -680,186 +680,6 @@ async def test_sensor_storage_ct_phase_data(
assert entity_state.state == target
CT_NAMES_FLOAT = (
"<cttype>_ct_energy_delivered",
"<cttype>_ct_energy_received",
"<cttype>_ct_power",
"frequency_<cttype>_ct",
"voltage_<cttype>_ct",
"<cttype>_ct_current",
"power_factor_<cttype>_ct",
"meter_status_flags_active_<cttype>_ct",
)
CT_NAMES_STR = ("metering_status_<cttype>_ct",)
@pytest.mark.parametrize(
("cttype", "mock_envoy"),
[
(CtType.PRODUCTION, "envoy_metered_batt_relay"),
(CtType.TOTAL_CONSUMPTION, "envoy_tot_cons_metered"),
(CtType.BACKFEED, "envoy_metered_batt_relay"),
(CtType.LOAD, "envoy_metered_batt_relay"),
(CtType.EVSE, "envoy_metered_batt_relay"),
(CtType.PV3P, "envoy_metered_batt_relay"),
],
indirect=["mock_envoy"],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_sensor_ct_data(
hass: HomeAssistant,
mock_envoy: AsyncMock,
config_entry: MockConfigEntry,
cttype: CtType,
) -> None:
"""Test ct entities values."""
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, config_entry)
sn = mock_envoy.serial_number
ENTITY_BASE: str = f"{Platform.SENSOR}.envoy_{sn}"
data = mock_envoy.data.ctmeters[cttype]
CT_TARGETS_FLOAT = (
data.energy_delivered / 1000000.0,
data.energy_received / 1000000.0,
data.active_power / 1000.0,
data.frequency,
data.voltage,
data.current,
data.power_factor,
len(data.status_flags),
)
count_names: int = 0
for name, target in list(
zip(
[
entity.replace("<cttype>", cttype).replace("-", "_")
for entity in CT_NAMES_FLOAT
],
CT_TARGETS_FLOAT,
strict=False,
)
):
assert (entity_state := hass.states.get(f"{ENTITY_BASE}_{name}"))
assert float(entity_state.state) == target
count_names += 1
CT_TARGETS_STR = (data.metering_status,)
for name, target in list(
zip(
[
entity.replace("<cttype>", cttype).replace("-", "_")
for entity in CT_NAMES_STR
],
CT_TARGETS_STR,
strict=False,
)
):
assert (entity_state := hass.states.get(f"{ENTITY_BASE}_{name}"))
assert entity_state.state == target
count_names += 1
# verify we're testing them all
assert len(CT_NAMES_FLOAT) + len(CT_NAMES_STR) == count_names
CT_NAMES_FLOAT_PHASE = [
f"{name}_{phase.lower()}" for phase in PHASENAMES for name in (CT_NAMES_FLOAT)
]
CT_NAMES_STR_PHASE = [
f"{name}_{phase.lower()}" for phase in PHASENAMES for name in (CT_NAMES_STR)
]
@pytest.mark.parametrize(
"cttype",
[
CtType.PRODUCTION,
CtType.BACKFEED,
CtType.LOAD,
CtType.EVSE,
CtType.PV3P,
],
)
@pytest.mark.parametrize(
("mock_envoy"),
[
"envoy_metered_batt_relay",
],
indirect=["mock_envoy"],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_sensor_ct_phase_data(
hass: HomeAssistant,
mock_envoy: AsyncMock,
config_entry: MockConfigEntry,
cttype: CtType,
) -> None:
"""Test ct phase entities values."""
with patch("homeassistant.components.enphase_envoy.PLATFORMS", [Platform.SENSOR]):
await setup_integration(hass, config_entry)
sn = mock_envoy.serial_number
ENTITY_BASE: str = f"{Platform.SENSOR}.envoy_{sn}"
CT_NAMES_FLOAT_PHASE_TARGET = chain(
*[
(
phase_data.energy_delivered / 1000000.0,
phase_data.energy_received / 1000000.0,
phase_data.active_power / 1000.0,
phase_data.frequency,
phase_data.voltage,
phase_data.current,
phase_data.power_factor,
len(phase_data.status_flags),
)
for phase_data in mock_envoy.data.ctmeters_phases[cttype].values()
]
)
count_names: int = 0
for name, target in list(
zip(
[
entity.replace("<cttype>", cttype).replace("-", "_")
for entity in CT_NAMES_FLOAT_PHASE
],
CT_NAMES_FLOAT_PHASE_TARGET,
strict=False,
)
):
assert (entity_state := hass.states.get(f"{ENTITY_BASE}_{name}"))
assert float(entity_state.state) == target
count_names += 1
CT_NAMES_STR_PHASE_TARGET = [
phase_data.metering_status
for phase_data in mock_envoy.data.ctmeters_phases[cttype].values()
]
for name, target in list(
zip(
[
entity.replace("<cttype>", cttype).replace("-", "_")
for entity in CT_NAMES_STR_PHASE
],
CT_NAMES_STR_PHASE_TARGET,
strict=False,
)
):
assert (entity_state := hass.states.get(f"{ENTITY_BASE}_{name}"))
assert entity_state.state == target
count_names += 1
# verify we're testing them all
assert len(CT_NAMES_FLOAT_PHASE) + len(CT_NAMES_STR_PHASE) == count_names
@pytest.mark.parametrize(
("mock_envoy"),
[

View File

@@ -3,7 +3,6 @@
from __future__ import annotations
from datetime import UTC, datetime
from typing import Any
from unittest.mock import patch
from evohomeasync2 import EvohomeClient
@@ -19,11 +18,10 @@ from homeassistant.components.evohome.const import (
)
from homeassistant.const import ATTR_ENTITY_ID, ATTR_MODE
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
@pytest.mark.parametrize("install", ["default"])
async def test_refresh_system(
async def test_service_refresh_system(
hass: HomeAssistant,
evohome: EvohomeClient,
) -> None:
@@ -42,7 +40,7 @@ async def test_refresh_system(
@pytest.mark.parametrize("install", ["default"])
async def test_reset_system(
async def test_service_reset_system(
hass: HomeAssistant,
ctl_id: str,
) -> None:
@@ -61,7 +59,7 @@ async def test_reset_system(
@pytest.mark.parametrize("install", ["default"])
async def test_set_system_mode(
async def test_ctl_set_system_mode(
hass: HomeAssistant,
ctl_id: str,
freezer: FrozenDateTimeFactory,
@@ -117,7 +115,7 @@ async def test_set_system_mode(
@pytest.mark.parametrize("install", ["default"])
async def test_clear_zone_override(
async def test_zone_clear_zone_override(
hass: HomeAssistant,
zone_id: str,
) -> None:
@@ -128,8 +126,9 @@ async def test_clear_zone_override(
await hass.services.async_call(
DOMAIN,
EvoService.CLEAR_ZONE_OVERRIDE,
{},
target={ATTR_ENTITY_ID: zone_id},
{
ATTR_ENTITY_ID: zone_id,
},
blocking=True,
)
@@ -137,7 +136,7 @@ async def test_clear_zone_override(
@pytest.mark.parametrize("install", ["default"])
async def test_set_zone_override(
async def test_zone_set_zone_override(
hass: HomeAssistant,
zone_id: str,
freezer: FrozenDateTimeFactory,
@@ -152,9 +151,9 @@ async def test_set_zone_override(
DOMAIN,
EvoService.SET_ZONE_OVERRIDE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_SETPOINT: 19.5,
},
target={ATTR_ENTITY_ID: zone_id},
blocking=True,
)
@@ -166,41 +165,13 @@ async def test_set_zone_override(
DOMAIN,
EvoService.SET_ZONE_OVERRIDE,
{
ATTR_ENTITY_ID: zone_id,
ATTR_SETPOINT: 19.5,
ATTR_DURATION: {"minutes": 135},
},
target={ATTR_ENTITY_ID: zone_id},
blocking=True,
)
mock_fcn.assert_awaited_once_with(
19.5, until=datetime(2024, 7, 10, 14, 15, tzinfo=UTC)
)
@pytest.mark.parametrize("install", ["default"])
@pytest.mark.parametrize(
("service", "service_data"),
[
(EvoService.CLEAR_ZONE_OVERRIDE, {}),
(EvoService.SET_ZONE_OVERRIDE, {ATTR_SETPOINT: 19.5}),
],
)
async def test_zone_services_with_ctl_id(
hass: HomeAssistant,
ctl_id: str,
service: EvoService,
service_data: dict[str, Any],
) -> None:
"""Test calling zone-only services with a non-zone entity_id fail."""
with pytest.raises(ServiceValidationError) as excinfo:
await hass.services.async_call(
DOMAIN,
service,
service_data,
target={ATTR_ENTITY_ID: ctl_id},
blocking=True,
)
assert excinfo.value.translation_key == "zone_only_service"

View File

@@ -76,10 +76,6 @@ async def test_config_flow(hass: HomeAssistant, config_entry: MockConfigEntry) -
"homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request",
autospec=True,
) as mock_get_request,
patch(
"homeassistant.components.forked_daapd.async_setup_entry",
return_value=True,
),
):
mock_get_request.return_value = SAMPLE_CONFIG
mock_test_connection.return_value = ["ok", "My Music on myhost"]
@@ -233,16 +229,10 @@ async def test_config_flow_zeroconf_valid(hass: HomeAssistant) -> None:
async def test_options_flow(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Test config flow options."""
with (
patch(
"homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request",
autospec=True,
) as mock_get_request,
patch(
"homeassistant.components.forked_daapd.async_setup_entry",
return_value=True,
),
):
with patch(
"homeassistant.components.forked_daapd.ForkedDaapdAPI.get_request",
autospec=True,
) as mock_get_request:
mock_get_request.return_value = SAMPLE_CONFIG
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)

View File

@@ -336,13 +336,7 @@ async def test_entity_migration(
config_entry=config_entry_v1_1,
)
with (
patch("homeassistant.components.home_connect.PLATFORMS", platforms),
patch(
"homeassistant.components.home_connect.async_setup_entry",
return_value=True,
),
):
with patch("homeassistant.components.home_connect.PLATFORMS", platforms):
await hass.config_entries.async_setup(config_entry_v1_1.entry_id)
await hass.async_block_till_done()
@@ -370,12 +364,8 @@ async def test_config_entry_unique_id_migration(
assert config_entry_v1_2.unique_id != "1234567890"
assert config_entry_v1_2.minor_version == 2
with patch(
"homeassistant.components.home_connect.async_setup_entry",
return_value=True,
):
await hass.config_entries.async_setup(config_entry_v1_2.entry_id)
await hass.async_block_till_done()
await hass.config_entries.async_setup(config_entry_v1_2.entry_id)
await hass.async_block_till_done()
assert config_entry_v1_2.unique_id == "1234567890"
assert config_entry_v1_2.minor_version == 3

View File

@@ -1,7 +1,5 @@
"""The tests for the Homematic notification platform."""
from unittest.mock import MagicMock, patch
from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
@@ -11,15 +9,11 @@ from tests.common import assert_setup_component
async def test_setup_full(hass: HomeAssistant) -> None:
"""Test valid configuration."""
with patch(
"homeassistant.components.homematic.HMConnection",
return_value=MagicMock(),
):
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
with assert_setup_component(1, domain="notify") as handle_config:
assert await async_setup_component(
hass,
@@ -41,15 +35,11 @@ async def test_setup_full(hass: HomeAssistant) -> None:
async def test_setup_without_optional(hass: HomeAssistant) -> None:
"""Test valid configuration without optional."""
with patch(
"homeassistant.components.homematic.HMConnection",
return_value=MagicMock(),
):
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
await async_setup_component(
hass,
"homematic",
{"homematic": {"hosts": {"ccu2": {"host": "127.0.0.1"}}}},
)
with assert_setup_component(1, domain="notify") as handle_config:
assert await async_setup_component(
hass,

View File

@@ -136,7 +136,6 @@ def fixture_mock_config_entry() -> MockConfigEntry:
async def fixture_mock_integration(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_device: MagicMock,
) -> MockConfigEntry:
"""Return a mock ConfigEntry setup for the integration."""
with (

View File

@@ -400,18 +400,14 @@ async def test_reconfigure(
return_value={"scb:network": {"Hostname": "scb"}}
)
with patch(
"homeassistant.components.kostal_plenticore.async_setup_entry",
return_value=True,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "1.1.1.1",
"password": "test-password",
},
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"host": "1.1.1.1",
"password": "test-password",
},
)
await hass.async_block_till_done()
mock_apiclient_class.assert_called_once_with(ANY, "1.1.1.1")
mock_apiclient.__aenter__.assert_called_once()

View File

@@ -90,7 +90,6 @@ async def test_device_already_configured(
async def test_user_step_fail_with_error(
hass: HomeAssistant,
mock_lunatone_info: AsyncMock,
mock_setup_entry: AsyncMock,
exception: Exception,
expected_error: str,
) -> None:
@@ -125,7 +124,6 @@ async def test_user_step_fail_with_error(
async def test_reconfigure(
hass: HomeAssistant,
mock_lunatone_info: AsyncMock,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconfigure flow."""
@@ -155,7 +153,6 @@ async def test_reconfigure(
async def test_reconfigure_fail_with_error(
hass: HomeAssistant,
mock_lunatone_info: AsyncMock,
mock_setup_entry: AsyncMock,
mock_config_entry: MockConfigEntry,
exception: Exception,
expected_error: str,

View File

@@ -46,6 +46,6 @@
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
'state': 'off',
})
# ---

View File

@@ -20,7 +20,6 @@ from tests.common import MockConfigEntry, snapshot_platform
async def test_binary_sensor_setup(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_madvr_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:

View File

@@ -38,7 +38,6 @@ from tests.common import MockConfigEntry, snapshot_platform
async def test_remote_setup(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_madvr_client: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:

View File

@@ -9,9 +9,7 @@ import pytest
@pytest.fixture
def mock_simple_manager_fail():
"""Mock datapoint Manager with default values for testing in config_flow."""
with patch(
"homeassistant.components.metoffice.config_flow.Manager"
) as mock_manager:
with patch("datapoint.Manager.Manager") as mock_manager:
instance = mock_manager.return_value
instance.get_forecast = APIException()
instance.latitude = None

View File

@@ -687,11 +687,10 @@ async def test_discovered_by_dhcp_updates_host(
assert config_entry.data[CONF_HOST] == "1.2.3.4"
await hass.config_entries.async_unload(config_entry.entry_id)
with patch("homeassistant.components.onvif.async_setup_entry", return_value=True):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_DHCP}, data=DHCP_DISCOVERY
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_DHCP}, data=DHCP_DISCOVERY
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"

View File

@@ -1,10 +1,8 @@
"""Test the Panasonic Viera config flow."""
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
from unittest.mock import patch
from panasonic_viera import SOAPError
import pytest
from homeassistant import config_entries
from homeassistant.components.panasonic_viera.const import (
@@ -28,16 +26,6 @@ from .conftest import (
from tests.common import MockConfigEntry
@pytest.fixture(autouse=True)
def mock_setup_entry() -> Generator[AsyncMock]:
"""Mock setting up a config entry."""
with patch(
"homeassistant.components.panasonic_viera.async_setup_entry",
return_value=True,
) as mock_setup:
yield mock_setup
async def test_flow_non_encrypted(hass: HomeAssistant) -> None:
"""Test flow without encryption."""

View File

@@ -4,7 +4,7 @@
'config_entry': dict({
'data': dict({
'api_token': '**REDACTED**',
'url': '**REDACTED**',
'url': 'https://127.0.0.1:9000/',
'verify_ssl': True,
}),
'disabled_by': None,

View File

@@ -122,12 +122,9 @@ async def test_unknown_error(hass: HomeAssistant) -> None:
async def test_zero_conf(hass: HomeAssistant) -> None:
"""Test the manual flow for zero config."""
with (
patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
),
patch_async_setup_entry(),
with patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
@@ -142,12 +139,9 @@ async def test_zero_conf(hass: HomeAssistant) -> None:
async def test_url_rewrite(hass: HomeAssistant) -> None:
"""Test auth flow url rewrite."""
with (
patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
),
patch_async_setup_entry(),
with patch(
"homeassistant.components.radarr.config_flow.RadarrClient.async_try_zeroconf",
return_value=("v3", API_KEY, "/test"),
):
result = await hass.config_entries.flow.async_init(
DOMAIN,

View File

@@ -62,12 +62,4 @@ MOCK_VEHICLES = {
"pressure": "pressure.1.json",
},
},
"megane_e_tech": {
"endpoints": {
"battery_status": "battery_status_charging.json",
"cockpit": "cockpit_ev.json",
"hvac_status": "hvac_status.1.json",
"location": "location.json",
},
},
}

View File

@@ -1,219 +0,0 @@
{
"accountId": "account-id-1",
"country": "FR",
"vehicleLinks": [
{
"brand": "RENAULT",
"vin": "VF1MEGANEETECHVIN",
"status": "ACTIVE",
"linkType": "OWNER",
"garageBrand": "renault",
"startDate": "2024-01-16",
"createdDate": "2024-01-16T13:31:27.089634Z",
"lastModifiedDate": "2024-01-17T18:15:38.607328Z",
"ownershipStartDate": "2024-01-16",
"connectedDriver": {
"role": "MAIN_DRIVER",
"createdDate": "2024-01-17T18:15:38.607044265Z",
"lastModifiedDate": "2024-01-17T18:15:38.607044265Z"
},
"vehicleDetails": {
"vin": "VF1MEGANEETECHVIN",
"registrationDate": "2024-01-16",
"firstRegistrationDate": "2024-01-16",
"engineType": "6AM",
"engineRatio": "402",
"modelSCR": "ZO1",
"passToSalesDate": "2023-04-04",
"deliveryCountry": {
"code": "FR",
"label": "FRANCE"
},
"family": {
"code": "XCB",
"label": "XCB FAMILY",
"group": "007"
},
"tcu": {
"code": "AIVCT",
"label": "WITH AIVC CONNECTION UNIT",
"group": "E70"
},
"battery": {
"code": "BTBAE",
"label": "BTBAE BATTERY",
"group": "968"
},
"radioType": {
"code": "NA448",
"label": "IVI2 FULL PREM DAB",
"group": "425"
},
"registrationCountry": {
"code": "FR"
},
"brand": {
"label": "RENAULT"
},
"model": {
"code": "XCB1VE",
"label": "MEGANE E-TECH",
"group": "971"
},
"gearbox": {
"code": "1EVGB",
"label": "REDUCER FOR ELECTRIC MOTOR",
"group": "427"
},
"version": {
"code": "ICO2M J1 L"
},
"energy": {
"code": "ELECX",
"label": "ELECTRICITY",
"group": "019"
},
"bodyType": {
"code": "BCB",
"label": "BERLINE FOR XCB",
"group": "008"
},
"steeringSide": {
"code": "LHDG",
"label": "LEFT-HAND DRIVE",
"group": "027"
},
"additionalEngineType": {
"code": "NOATY",
"label": "WITHOUT ADDITIONAL ENGINE TYPE",
"group": "948"
},
"hybridation": {
"code": "NOHYB",
"label": "NO HYBRIDISATION LEVEL",
"group": "956"
},
"registrationNumber": "REG-MEG-0",
"vcd": "PAVEH/XCB/BCB/EA4/J1/ELECX/LHDG/TEMP/2WDRV/BEMBK/ACC02/00ABS/ACD03/STDRF/HTRWI/WFURP/CLK00/RVX07/1RVLG/FFGL2/SDLGT/RAL20/FSBAJ/SPADP/FAB02/NOCNV/LRSCO/LRS02/HAR04/RHR03/FSE06/RSE00/BIXPA/NTIBC/KMETR/TPRM2/SDSGL/NOSTK/SABG5/LEDCO/ESCHS/PALAW/SPBDA/M3CA3/PRROP/DB4C0/NOAGR/LRSW0/OSEWA/RVICM/TRSV0/NBRVX/FWL1T/RWL1T/NOOSW/REPKT/HTS02/00NLD/BRA03/AJSW2/HSTPL/SBR05/RMSB3/NA448/1EVGB/ASOC2/EVAU2/RIM09/TYSUM/ISOFI/EPER0/HR11M/SLCCA/NOATD/CPTC0/CHGS4/TL01A/BDPRO/NOADT/AIRBDE/PRUPTA/ELC1/NOETC/NOLSV/NOFEX/M2021/PHAS1/NOLTD/NOATY/NOHYB/60K0B/BTBAE/VEC151/XCB1VE/NB003/6AM/SFANT/ADR00/LKA05/PSFT0/BIHT0/NODUP/NOWAP/NOCCH/AMLT0/DRL02/RCALL/NOART/TBI00/MET05/BSD02/ECMD0/NRCAR/NOM2C/AIVCT/GSI00/TPNNP/TSGNE/2BCOL/ITP14/MDMOD/PXA00/NOPXB/PIG02/HTSW0/DAALT/WICH0/EV1GA1/SMOSP/NOWMC/FCOWA/C1AHS/NOPRA/VSPTA/1234Y/NOLIE/NOLII/NOWFI/AEB09/WOSRE/PRAHL/SPMIR/AVCAM/RAEB2/DTRNI",
"manufacturingDate": "2023-04-04",
"assets": [
{
"assetType": "PICTURE",
"viewpoint": "mybrand_2",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=RSITE&bookmark=EXT_34_DESSUS&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=RSITE&bookmark=EXT_34_DESSUS&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "mybrand_2"
},
{
"assetType": "PICTURE",
"viewpoint": "mybrand_5",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=RSITE&bookmark=EXT_34_AV&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=RSITE&bookmark=EXT_34_AV&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "mybrand_5"
},
{
"assetType": "PICTURE",
"viewpoint": "myb_car_selector",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=RSITE&bookmark=EXT_34_AV&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=RSITE&bookmark=EXT_34_AV&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "myb_car_selector"
},
{
"assetType": "PICTURE",
"viewpoint": "myb_car_page_dashboard",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_LEFT_SIDE&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_LEFT_SIDE&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "myb_car_page_dashboard"
},
{
"assetType": "PICTURE",
"viewpoint": "myb_program_settings_page",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_LEFT_SIDE&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_LEFT_SIDE&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "myb_program_settings_page"
},
{
"assetType": "PICTURE",
"viewpoint": "myb_plug_and_charge_activation",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_RIGHT_SIDE&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_RIGHT_SIDE&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "myb_plug_and_charge_activation"
},
{
"assetType": "PICTURE",
"viewpoint": "myb_plug_and_charge_my_car",
"renditions": [
{
"resolutionType": "ONE_MYRENAULT_SMALL",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_LEFT_SIDE&profile=HELIOS_OWNERSERVICES_SMALL_V2"
},
{
"resolutionType": "ONE_MYRENAULT_LARGE",
"url": "https://3dv.renault.com/ImageFromBookmark?configuration=BCB%2FEA4%2FLHDG%2FACD03%2FSTDRF%2FWFURP%2FRVX07%2FRAL20%2FLRS02%2FFSE06%2FBIXPA%2FLEDCO%2FPALAW%2FSPBDA%2FLRSW0%2FRVICM%2FTRSV0%2FAJSW2%2FNA448%2FASOC2%2FRIM09%2FSLCCA%2FNOATD%2FCPTC0%2FBDPRO%2FAIRBDE%2FPRUPTA%2FNOETC%2FM2021%2FNB003%2FSFANT%2FPSFT0%2FNODUP%2FNOWAP%2FRCALL%2FBSD02%2F2BCOL%2FITP14%2FMDMOD%2FPXA00%2FNOPXB%2FPIG02%2FNOLII%2FAVCAM%2FDTRNI&databaseId=a7cc2a21-d3fe-43bf-8643-14d3b8f9b2fa&bookmarkSet=CARPICKER&bookmark=EXT_LEFT_SIDE&profile=HELIOS_OWNERSERVICES_LARGE"
}
],
"viewPointInLowerCase": "myb_plug_and_charge_my_car"
}
],
"yearsOfMaintenance": 12,
"connectivityTechnology": "OPENRLINK",
"easyConnectStore": true,
"electrical": true,
"deliveryDate": "2024-01-16",
"retrievedFromDhs": false,
"engineEnergyType": "ELEC",
"radioCode": "",
"premiumSubscribed": false,
"batteryType": "NMC"
}
}
]
}

View File

@@ -495,155 +495,6 @@
'state': 'on',
})
# ---
# name: test_binary_sensors[megane_e_tech][binary_sensor.reg_meg_0_charging-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.reg_meg_0_charging',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Charging',
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.BATTERY_CHARGING: 'battery_charging'>,
'original_icon': None,
'original_name': 'Charging',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'vf1meganeetechvin_charging',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[megane_e_tech][binary_sensor.reg_meg_0_charging-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'battery_charging',
'friendly_name': 'REG-MEG-0 Charging',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.reg_meg_0_charging',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensors[megane_e_tech][binary_sensor.reg_meg_0_hvac-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.reg_meg_0_hvac',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'HVAC',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'HVAC',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hvac_status',
'unique_id': 'vf1meganeetechvin_hvac_status',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[megane_e_tech][binary_sensor.reg_meg_0_hvac-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 HVAC',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.reg_meg_0_hvac',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_binary_sensors[megane_e_tech][binary_sensor.reg_meg_0_plug-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.reg_meg_0_plug',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Plug',
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.PLUG: 'plug'>,
'original_icon': None,
'original_name': 'Plug',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'vf1meganeetechvin_plugged_in',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[megane_e_tech][binary_sensor.reg_meg_0_plug-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'plug',
'friendly_name': 'REG-MEG-0 Plug',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.reg_meg_0_plug',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_binary_sensors[twingo_3_electric][binary_sensor.reg_twingo_iii_charging-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -1371,202 +1371,6 @@
'state': 'unknown',
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_flash_lights-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.reg_meg_0_flash_lights',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Flash lights',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Flash lights',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'flash_lights',
'unique_id': 'vf1meganeetechvin_flash_lights',
'unit_of_measurement': None,
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_flash_lights-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 Flash lights',
}),
'context': <ANY>,
'entity_id': 'button.reg_meg_0_flash_lights',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_sound_horn-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.reg_meg_0_sound_horn',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Sound horn',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Sound horn',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'sound_horn',
'unique_id': 'vf1meganeetechvin_sound_horn',
'unit_of_measurement': None,
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_sound_horn-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 Sound horn',
}),
'context': <ANY>,
'entity_id': 'button.reg_meg_0_sound_horn',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_start_air_conditioner-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.reg_meg_0_start_air_conditioner',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Start air conditioner',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Start air conditioner',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'start_air_conditioner',
'unique_id': 'vf1meganeetechvin_start_air_conditioner',
'unit_of_measurement': None,
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_start_air_conditioner-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 Start air conditioner',
}),
'context': <ANY>,
'entity_id': 'button.reg_meg_0_start_air_conditioner',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_start_charge-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'button',
'entity_category': None,
'entity_id': 'button.reg_meg_0_start_charge',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Start charge',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Start charge',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'start_charge',
'unique_id': 'vf1meganeetechvin_start_charge',
'unit_of_measurement': None,
})
# ---
# name: test_buttons[megane_e_tech][button.reg_meg_0_start_charge-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 Start charge',
}),
'context': <ANY>,
'entity_id': 'button.reg_meg_0_start_charge',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_buttons[twingo_3_electric][button.reg_twingo_iii_flash_lights-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -204,59 +204,6 @@
'state': 'not_home',
})
# ---
# name: test_device_trackers[megane_e_tech][device_tracker.reg_meg_0_location-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'device_tracker',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'device_tracker.reg_meg_0_location',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Location',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Location',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'location',
'unique_id': 'vf1meganeetechvin_location',
'unit_of_measurement': None,
})
# ---
# name: test_device_trackers[megane_e_tech][device_tracker.reg_meg_0_location-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 Location',
'gps_accuracy': 0,
'latitude': 48.1234567,
'longitude': 11.1234567,
'source_type': <SourceType.GPS: 'gps'>,
}),
'context': <ANY>,
'entity_id': 'device_tracker.reg_meg_0_location',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'not_home',
})
# ---
# name: test_device_trackers[twingo_3_electric][device_tracker.reg_twingo_iii_location-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -65,39 +65,6 @@
}),
])
# ---
# name: test_device_registry[megane_e_tech]
list([
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entries': <ANY>,
'config_entries_subentries': <ANY>,
'configuration_url': None,
'connections': set({
}),
'disabled_by': None,
'entry_type': None,
'hw_version': None,
'id': <ANY>,
'identifiers': set({
tuple(
'renault',
'VF1MEGANEETECHVIN',
),
}),
'labels': set({
}),
'manufacturer': 'Renault',
'model': 'Megane e-tech',
'model_id': 'XCB1VE',
'name': 'REG-MEG-0',
'name_by_user': None,
'primary_config_entry': <ANY>,
'serial_number': None,
'sw_version': None,
'via_device_id': None,
}),
])
# ---
# name: test_device_registry[twingo_3_electric]
list([
DeviceRegistryEntrySnapshot({

View File

@@ -2758,795 +2758,6 @@
'state': 'plugged',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_admissible_charging_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_admissible_charging_power',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Admissible charging power',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'original_icon': None,
'original_name': 'Admissible charging power',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'admissible_charging_power',
'unique_id': 'vf1meganeetechvin_charging_power',
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_admissible_charging_power-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'power',
'friendly_name': 'REG-MEG-0 Admissible charging power',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.KILO_WATT: 'kW'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_admissible_charging_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '27.0',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_battery',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Battery',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
'original_icon': None,
'original_name': 'Battery',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'vf1meganeetechvin_battery_level',
'unit_of_measurement': '%',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'battery',
'friendly_name': 'REG-MEG-0 Battery',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_battery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '60',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery_autonomy-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_battery_autonomy',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Battery autonomy',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.DISTANCE: 'distance'>,
'original_icon': None,
'original_name': 'Battery autonomy',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'battery_autonomy',
'unique_id': 'vf1meganeetechvin_battery_autonomy',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery_autonomy-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'distance',
'friendly_name': 'REG-MEG-0 Battery autonomy',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_battery_autonomy',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '141',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery_available_energy-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_battery_available_energy',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Battery available energy',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Battery available energy',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'battery_available_energy',
'unique_id': 'vf1meganeetechvin_battery_available_energy',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery_available_energy-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'REG-MEG-0 Battery available energy',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_battery_available_energy',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '31',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_battery_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Battery temperature',
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Battery temperature',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'battery_temperature',
'unique_id': 'vf1meganeetechvin_battery_temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_battery_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'REG-MEG-0 Battery temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_battery_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_charge_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'not_in_charge',
'waiting_for_a_planned_charge',
'charge_ended',
'waiting_for_current_charge',
'energy_flap_opened',
'charge_in_progress',
'charge_error',
'unavailable',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_charge_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Charge state',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Charge state',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charge_state',
'unique_id': 'vf1meganeetechvin_charge_state',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_charge_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'REG-MEG-0 Charge state',
'options': list([
'not_in_charge',
'waiting_for_a_planned_charge',
'charge_ended',
'waiting_for_current_charge',
'energy_flap_opened',
'charge_in_progress',
'charge_error',
'unavailable',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_charge_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'charge_in_progress',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_charging_remaining_time-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_charging_remaining_time',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Charging remaining time',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Charging remaining time',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'charging_remaining_time',
'unique_id': 'vf1meganeetechvin_charging_remaining_time',
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_charging_remaining_time-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'duration',
'friendly_name': 'REG-MEG-0 Charging remaining time',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_charging_remaining_time',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '145',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_hvac_soc_threshold-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_hvac_soc_threshold',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'HVAC SoC threshold',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'HVAC SoC threshold',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hvac_soc_threshold',
'unique_id': 'vf1meganeetechvin_hvac_soc_threshold',
'unit_of_measurement': '%',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_hvac_soc_threshold-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'REG-MEG-0 HVAC SoC threshold',
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_hvac_soc_threshold',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_last_battery_activity-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_last_battery_activity',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Last battery activity',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last battery activity',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'battery_last_activity',
'unique_id': 'vf1meganeetechvin_battery_last_activity',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_last_battery_activity-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'REG-MEG-0 Last battery activity',
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_last_battery_activity',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2020-01-12T21:40:16+00:00',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_last_hvac_activity-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_last_hvac_activity',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Last HVAC activity',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last HVAC activity',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'hvac_last_activity',
'unique_id': 'vf1meganeetechvin_hvac_last_activity',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_last_hvac_activity-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'REG-MEG-0 Last HVAC activity',
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_last_hvac_activity',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_last_location_activity-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_last_location_activity',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Last location activity',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last location activity',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'location_last_activity',
'unique_id': 'vf1meganeetechvin_location_last_activity',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_last_location_activity-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'timestamp',
'friendly_name': 'REG-MEG-0 Last location activity',
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_last_location_activity',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2020-02-18T16:58:38+00:00',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_mileage-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_mileage',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mileage',
'options': dict({
'sensor': dict({
'suggested_display_precision': 2,
}),
}),
'original_device_class': <SensorDeviceClass.DISTANCE: 'distance'>,
'original_icon': None,
'original_name': 'Mileage',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'mileage',
'unique_id': 'vf1meganeetechvin_mileage',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_mileage-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'distance',
'friendly_name': 'REG-MEG-0 Mileage',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_mileage',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '49114',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_outside_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_outside_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Outside temperature',
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Outside temperature',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'outside_temperature',
'unique_id': 'vf1meganeetechvin_outside_temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_outside_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'REG-MEG-0 Outside temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_outside_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '8.0',
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_plug_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'unplugged',
'plugged',
'plugged_waiting_for_charge',
'plug_error',
'plug_unknown',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.reg_meg_0_plug_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Plug state',
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Plug state',
'platform': 'renault',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'plug_state',
'unique_id': 'vf1meganeetechvin_plug_state',
'unit_of_measurement': None,
})
# ---
# name: test_sensors[megane_e_tech][sensor.reg_meg_0_plug_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'REG-MEG-0 Plug state',
'options': list([
'unplugged',
'plugged',
'plugged_waiting_for_charge',
'plug_error',
'plug_unknown',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.reg_meg_0_plug_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'plugged',
})
# ---
# name: test_sensors[twingo_3_electric][sensor.reg_twingo_iii_admissible_charging_power-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -264,9 +264,7 @@ async def test_ssdp_discovery(
async def test_options_flow(
hass: HomeAssistant,
mock_setup_entry: None,
mock_config_entry: MockConfigEntry,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test options config flow."""
mock_config_entry.add_to_hass(hass)

View File

@@ -31,8 +31,7 @@ async def test_setup_success_no_region(hass: HomeAssistant) -> None:
)
mock_config.add_to_hass(hass)
with patch("homeassistant.components.sharkiq.async_setup_entry", return_value=True):
result = await async_setup_component(hass=hass, domain=DOMAIN, config={})
result = await async_setup_component(hass=hass, domain=DOMAIN, config={})
assert result is True

View File

@@ -149,9 +149,7 @@ async def test_dhcp_discovery(
async def test_dhcp_already_configured(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test starting a flow by dhcp when already configured."""
mock_config_entry.add_to_hass(hass)
@@ -164,9 +162,7 @@ async def test_dhcp_already_configured(
async def test_dhcp_already_configured_duplicate(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_sma_client: MagicMock,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test starting a flow by DHCP when already configured and MAC is added."""
mock_config_entry.add_to_hass(hass)
@@ -284,7 +280,6 @@ async def test_full_flow_reauth(
async def test_reauth_flow_exceptions(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
exception: Exception,
error: str,
) -> None:

View File

@@ -10780,7 +10780,6 @@
'after',
'cleaning',
'pause',
'washing_mop',
]),
}),
'config_entry_id': <ANY>,
@@ -10829,7 +10828,6 @@
'after',
'cleaning',
'pause',
'washing_mop',
]),
}),
'context': <ANY>,
@@ -11154,7 +11152,6 @@
'after',
'cleaning',
'pause',
'washing_mop',
]),
}),
'config_entry_id': <ANY>,
@@ -11203,7 +11200,6 @@
'after',
'cleaning',
'pause',
'washing_mop',
]),
}),
'context': <ANY>,

View File

@@ -244,55 +244,6 @@
'state': 'on',
})
# ---
# name: test_all_entities[da_ks_hood_01001][switch.range_hood_do_not_disturb-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.range_hood_do_not_disturb',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Do not disturb',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Do not disturb',
'platform': 'smartthings',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'do_not_disturb',
'unique_id': 'fa5fca25-fa7a-1807-030a-2f72ee0f7bff_main_custom.doNotDisturbMode_doNotDisturb_doNotDisturb',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_hood_01001][switch.range_hood_do_not_disturb-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Range hood Do not disturb',
}),
'context': <ANY>,
'entity_id': 'switch.range_hood_do_not_disturb',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_all_entities[da_ks_walloven_0107x][switch.four_sabbath_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -1028,55 +979,6 @@
'state': 'on',
})
# ---
# name: test_all_entities[da_rvc_map_01011][switch.robot_vacuum_do_not_disturb-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.robot_vacuum_do_not_disturb',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Do not disturb',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Do not disturb',
'platform': 'smartthings',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'do_not_disturb',
'unique_id': '05accb39-2017-c98b-a5ab-04a81f4d3d9a_main_custom.doNotDisturbMode_doNotDisturb_doNotDisturb',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_rvc_map_01011][switch.robot_vacuum_do_not_disturb-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Robot vacuum Do not disturb',
}),
'context': <ANY>,
'entity_id': 'switch.robot_vacuum_do_not_disturb',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_all_entities[da_rvc_normal_000001][switch.robot_vacuum-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -7,16 +7,6 @@ import pytest
from . import MOCK_SERVERS
@pytest.fixture
def mock_setup_entry():
"""Mock setting up a config entry."""
with patch(
"homeassistant.components.speedtestdotnet.async_setup_entry",
return_value=True,
) as mock_setup:
yield mock_setup
@pytest.fixture
def mock_api():
"""Mock entry setup."""

View File

@@ -14,7 +14,7 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_flow_works(hass: HomeAssistant, mock_setup_entry: MagicMock) -> None:
async def test_flow_works(hass: HomeAssistant) -> None:
"""Test user config."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}

View File

@@ -25,15 +25,12 @@ async def test_flow_user(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"] == {}
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -51,15 +48,12 @@ async def test_flow_user_cannot_connect(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"]["base"] == "cannot_connect"
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -77,15 +71,12 @@ async def test_flow_user_invalid_auth(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"]["base"] == "invalid_auth"
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -103,15 +94,12 @@ async def test_flow_user_unknown_error(hass: HomeAssistant) -> None:
assert result["step_id"] == "user"
assert result["errors"]["base"] == "unknown"
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=CONF_DATA,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME
@@ -150,15 +138,12 @@ async def test_flow_user_multiple_entries_allowed(hass: HomeAssistant) -> None:
CONF_API_KEY: "efgh",
CONF_VERIFY_SSL: True,
}
with (
patch_config_flow_tautulli(AsyncMock()),
patch("homeassistant.components.tautulli.async_setup_entry", return_value=True),
):
with patch_config_flow_tautulli(AsyncMock()):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input=user_input,
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert result2["type"] is FlowResultType.CREATE_ENTRY
assert result2["title"] == NAME

View File

@@ -57,8 +57,6 @@ async def test_service_reconnect_client(
async def test_service_reconnect_failed_with_invalid_entry(
hass: HomeAssistant,
mock_omada_site_client: MagicMock,
mock_omada_client: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconnect with invalid config entry raises ServiceValidationError."""
@@ -104,8 +102,6 @@ async def test_service_reconnect_without_config_entry_id(
async def test_service_reconnect_entry_not_loaded(
hass: HomeAssistant,
mock_omada_site_client: MagicMock,
mock_omada_client: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconnect service raises error when entry is not loaded."""

View File

@@ -30,7 +30,6 @@ from tests.common import MockConfigEntry, async_fire_time_changed
async def test_config_flow_entry_migrate_1_1_to_1_2(
hass: HomeAssistant,
mock_transmission_client: AsyncMock,
) -> None:
"""Test that config flow entry is migrated correctly from v1.1 to v1.2."""
entry = MockConfigEntry(
@@ -151,7 +150,6 @@ async def test_unload_entry(
)
async def test_migrate_unique_id(
hass: HomeAssistant,
mock_transmission_client: AsyncMock,
entity_registry: er.EntityRegistry,
domain: str,
old_unique_id: str,

View File

@@ -487,6 +487,80 @@ async def test_segments_changed_issue(
assert ir.async_get(hass).async_get_issue(DOMAIN, issue_id) is None
@pytest.mark.usefixtures("config_flow_fixture")
@pytest.mark.parametrize("area_mapping", [{"area_1": ["seg_1"]}, {}])
async def test_segments_mapping_not_configured_issue(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
area_mapping: dict[str, list[str]],
) -> None:
"""Test segments_mapping_not_configured issue."""
mock_vacuum = MockVacuumWithCleanArea(name="Testing", entity_id="vacuum.testing")
config_entry = MockConfigEntry(domain="test")
config_entry.add_to_hass(hass)
mock_integration(
hass,
MockModule(
"test",
async_setup_entry=help_async_setup_entry_init,
async_unload_entry=help_async_unload_entry,
),
)
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_entry = entity_registry.async_get(mock_vacuum.entity_id)
issue_id = f"segments_mapping_not_configured_{entity_entry.id}"
issue = ir.async_get(hass).async_get_issue(DOMAIN, issue_id)
assert issue is not None
assert issue.severity == ir.IssueSeverity.WARNING
assert issue.translation_key == "segments_mapping_not_configured"
entity_registry.async_update_entity_options(
mock_vacuum.entity_id,
DOMAIN,
{
"area_mapping": area_mapping,
"last_seen_segments": [asdict(segment) for segment in mock_vacuum.segments],
},
)
await hass.async_block_till_done()
assert ir.async_get(hass).async_get_issue(DOMAIN, issue_id) is None
@pytest.mark.usefixtures("config_flow_fixture")
async def test_no_segments_mapping_issue_without_clean_area(
hass: HomeAssistant,
) -> None:
"""Test no repair issue is created when CLEAN_AREA is not supported."""
mock_vacuum = MockVacuum(name="Testing", entity_id="vacuum.testing")
config_entry = MockConfigEntry(domain="test")
config_entry.add_to_hass(hass)
mock_integration(
hass,
MockModule(
"test",
async_setup_entry=help_async_setup_entry_init,
async_unload_entry=help_async_unload_entry,
),
)
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
issues = ir.async_get(hass).issues
assert not any(
issue_id[1].startswith("segments_mapping_not_configured") for issue_id in issues
)
@pytest.mark.parametrize(("is_built_in", "log_warnings"), [(True, 0), (False, 3)])
async def test_vacuum_log_deprecated_battery_using_properties(
hass: HomeAssistant,

View File

@@ -153,9 +153,12 @@ async def test_reboot_gateway_service_raises_on_exception(
async def test_reboot_gateway_service_raises_validation_error(
hass: HomeAssistant,
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test that reboot_gateway service raises ServiceValidationError when no gateway is loaded."""
# Add the config entry but don't set it up
mock_config_entry.add_to_hass(hass)
# Set up the velux integration's async_setup to register the service
await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()

View File

@@ -159,10 +159,9 @@ async def test_full_ssdp_flow_implementation(hass: HomeAssistant) -> None:
"components": "light",
}
with patch("homeassistant.components.wilight.async_setup_entry", return_value=True):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == f"WL{WILIGHT_ID}"

View File

@@ -83,19 +83,6 @@ def test_write_utf8_file_fails_at_rename_and_remove(
assert "File replacement cleanup failed" in caplog.text
@pytest.mark.parametrize("func", [write_utf8_file, write_utf8_file_atomic])
def test_write_utf8_file_with_non_ascii_content(tmp_path: Path, func) -> None:
"""Test files with non-ASCII content can be written even when locale is ASCII."""
test_file = tmp_path / "test.json"
non_ascii_data = '{"name":"自动化","emoji":"🏠"}'
with patch("locale.getpreferredencoding", return_value="ascii"):
func(test_file, non_ascii_data, False)
file_text = test_file.read_text(encoding="utf-8")
assert file_text == non_ascii_data
def test_write_utf8_file_atomic_fails(tmpdir: py.path.local) -> None:
"""Test OSError from write_utf8_file_atomic is rethrown as WriteError."""
test_dir = tmpdir.mkdir("files")