Enable N806 (#171388)

Co-authored-by: Ariel Ebersberger <31776703+justanotherariel@users.noreply.github.com>
This commit is contained in:
Joost Lekkerkerker
2026-05-26 23:23:39 +02:00
committed by GitHub
parent 0b687df9f8
commit 49c045236c
23 changed files with 126 additions and 118 deletions
@@ -230,13 +230,13 @@ async def async_migrate_entry(hass: HomeAssistant, entry: AnthropicConfigEntry)
if entry.version == 2 and entry.minor_version == 3: if entry.version == 2 and entry.minor_version == 3:
# Remove Temperature parameter # Remove Temperature parameter
CONF_TEMPERATURE = "temperature" temperature_key = "temperature"
for subentry in entry.subentries.values(): for subentry in entry.subentries.values():
data = subentry.data.copy() data = subentry.data.copy()
if CONF_TEMPERATURE not in data: if temperature_key not in data:
continue continue
data.pop(CONF_TEMPERATURE, None) data.pop(temperature_key, None)
hass.config_entries.async_update_subentry(entry, subentry, data=data) hass.config_entries.async_update_subentry(entry, subentry, data=data)
hass.config_entries.async_update_entry(entry, minor_version=4) hass.config_entries.async_update_entry(entry, minor_version=4)
+14 -14
View File
@@ -49,6 +49,20 @@ SENSORS_TYPE_COUNT = "sensors_count"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_ENTITY_MIGRATION_ID = {
"sensor_connected_device": "Devices Connected",
"sensor_rx_bytes": "Download",
"sensor_tx_bytes": "Upload",
"sensor_rx_rates": "Download Speed",
"sensor_tx_rates": "Upload Speed",
"sensor_load_avg1": "Load Avg (1m)",
"sensor_load_avg5": "Load Avg (5m)",
"sensor_load_avg15": "Load Avg (15m)",
"2.4GHz": "2.4GHz Temperature",
"5.0GHz": "5GHz Temperature",
"CPU": "CPU Temperature",
}
class AsusWrtSensorDataHandler: class AsusWrtSensorDataHandler:
"""Data handler for AsusWrt sensor.""" """Data handler for AsusWrt sensor."""
@@ -187,20 +201,6 @@ class AsusWrtRouter:
def _migrate_entities_unique_id(self) -> None: def _migrate_entities_unique_id(self) -> None:
"""Migrate router entities to new unique id format.""" """Migrate router entities to new unique id format."""
_ENTITY_MIGRATION_ID = {
"sensor_connected_device": "Devices Connected",
"sensor_rx_bytes": "Download",
"sensor_tx_bytes": "Upload",
"sensor_rx_rates": "Download Speed",
"sensor_tx_rates": "Upload Speed",
"sensor_load_avg1": "Load Avg (1m)",
"sensor_load_avg5": "Load Avg (5m)",
"sensor_load_avg15": "Load Avg (15m)",
"2.4GHz": "2.4GHz Temperature",
"5.0GHz": "5GHz Temperature",
"CPU": "CPU Temperature",
}
entity_reg = er.async_get(self.hass) entity_reg = er.async_get(self.hass)
router_entries = er.async_entries_for_config_entry( router_entries = er.async_entries_for_config_entry(
entity_reg, self._entry.entry_id entity_reg, self._entry.entry_id
+5 -5
View File
@@ -41,7 +41,7 @@ class UKFloodsFlowHandler(ConfigFlow, domain=DOMAIN):
self.stations = {} self.stations = {}
for station in stations: for station in stations:
label = station["label"] label = station["label"]
rloId = station["RLOIid"] rlo_id = station["RLOIid"]
# API annoyingly sometimes returns a list and some times returns a string # API annoyingly sometimes returns a list and some times returns a string
# E.g. L3121 has a label of ['Scurf Dyke', 'Scurf Dyke Dyke Level'] # E.g. L3121 has a label of ['Scurf Dyke', 'Scurf Dyke Dyke Level']
@@ -50,11 +50,11 @@ class UKFloodsFlowHandler(ConfigFlow, domain=DOMAIN):
# Similar for RLOIid # Similar for RLOIid
# E.g. 0018 has an RLOIid of ['10427', '9154'] # E.g. 0018 has an RLOIid of ['10427', '9154']
if isinstance(rloId, list): if isinstance(rlo_id, list):
rloId = rloId[-1] rlo_id = rlo_id[-1]
fullName = label + " - " + rloId full_name = label + " - " + rlo_id
self.stations[fullName] = station["stationReference"] self.stations[full_name] = station["stationReference"]
if not self.stations: if not self.stations:
return self.async_abort(reason="no_stations") return self.async_abort(reason="no_stations")
+3 -3
View File
@@ -124,11 +124,11 @@ async def async_setup_entry(
for camera in coordinator.data: for camera in coordinator.data:
device_category = coordinator.data[camera].get("device_category") device_category = coordinator.data[camera].get("device_category")
supportExt = coordinator.data[camera].get("supportExt") support_ext = coordinator.data[camera].get("supportExt")
if ( if (
device_category == DeviceCatagories.BATTERY_CAMERA_DEVICE_CATEGORY.value device_category == DeviceCatagories.BATTERY_CAMERA_DEVICE_CATEGORY.value
and supportExt and support_ext
and str(SupportExt.SupportBatteryManage.value) in supportExt and str(SupportExt.SupportBatteryManage.value) in support_ext
): ):
entities.append( entities.append(
EzvizSelect(coordinator, camera, BATTERY_WORK_MODE_SELECT_TYPE) EzvizSelect(coordinator, camera, BATTERY_WORK_MODE_SELECT_TYPE)
+5 -5
View File
@@ -117,13 +117,13 @@ class DriveClient:
"""Get storage quota of the current user.""" """Get storage quota of the current user."""
res = await self._api.get_user(params={"fields": "storageQuota"}) res = await self._api.get_user(params={"fields": "storageQuota"})
storageQuota = res["storageQuota"] storage_quota = res["storageQuota"]
limit = storageQuota.get("limit") limit = storage_quota.get("limit")
return StorageQuotaData( return StorageQuotaData(
limit=int(limit) if limit is not None else None, limit=int(limit) if limit is not None else None,
usage=int(storageQuota.get("usage", 0)), usage=int(storage_quota.get("usage", 0)),
usage_in_drive=int(storageQuota.get("usageInDrive", 0)), usage_in_drive=int(storage_quota.get("usageInDrive", 0)),
usage_in_trash=int(storageQuota.get("usageInTrash", 0)), usage_in_trash=int(storage_quota.get("usageInTrash", 0)),
) )
async def async_create_ha_root_folder_if_not_exists(self) -> tuple[str, str]: async def async_create_ha_root_folder_if_not_exists(self) -> tuple[str, str]:
@@ -580,17 +580,17 @@ class GoogleGenerativeAILLMBaseEntity(Entity):
if tool_results: if tool_results:
messages.append(_create_google_tool_response_content(tool_results)) messages.append(_create_google_tool_response_content(tool_results))
generateContentConfig = self.create_generate_content_config() generate_content_config = self.create_generate_content_config()
generateContentConfig.tools = tools or None generate_content_config.tools = tools or None
generateContentConfig.system_instruction = ( generate_content_config.system_instruction = (
prompt if supports_system_instruction else None prompt if supports_system_instruction else None
) )
generateContentConfig.automatic_function_calling = ( generate_content_config.automatic_function_calling = (
AutomaticFunctionCallingConfig(disable=True, maximum_remote_calls=None) AutomaticFunctionCallingConfig(disable=True, maximum_remote_calls=None)
) )
if structure: if structure:
generateContentConfig.response_mime_type = "application/json" generate_content_config.response_mime_type = "application/json"
generateContentConfig.response_schema = _format_schema( generate_content_config.response_schema = _format_schema(
convert( convert(
structure, structure,
custom_serializer=( custom_serializer=(
@@ -608,7 +608,7 @@ class GoogleGenerativeAILLMBaseEntity(Entity):
*messages, *messages,
] ]
chat = self._genai_client.aio.chats.create( chat = self._genai_client.aio.chats.create(
model=model_name, history=messages, config=generateContentConfig model=model_name, history=messages, config=generate_content_config
) )
user_message = chat_log.content[-1] user_message = chat_log.content[-1]
assert isinstance(user_message, conversation.UserContent) assert isinstance(user_message, conversation.UserContent)
@@ -313,7 +313,7 @@ async def _manage_quests(call: ServiceCall) -> ServiceResponse:
) )
coordinator = entry.runtime_data coordinator = entry.runtime_data
FUNC_MAP = { func_map = {
SERVICE_ABORT_QUEST: coordinator.habitica.abort_quest, SERVICE_ABORT_QUEST: coordinator.habitica.abort_quest,
SERVICE_ACCEPT_QUEST: coordinator.habitica.accept_quest, SERVICE_ACCEPT_QUEST: coordinator.habitica.accept_quest,
SERVICE_CANCEL_QUEST: coordinator.habitica.cancel_quest, SERVICE_CANCEL_QUEST: coordinator.habitica.cancel_quest,
@@ -322,7 +322,7 @@ async def _manage_quests(call: ServiceCall) -> ServiceResponse:
SERVICE_START_QUEST: coordinator.habitica.start_quest, SERVICE_START_QUEST: coordinator.habitica.start_quest,
} }
func = FUNC_MAP[call.service] func = func_map[call.service]
try: try:
response = await func() response = await func()
+5 -6
View File
@@ -30,6 +30,11 @@ OPEN_CLOSE_ATTRIBUTES = [
AttributeType.UP_DOWN, AttributeType.UP_DOWN,
] ]
POSITION_ATTRIBUTES = [AttributeType.POSITION, AttributeType.SHUTTER_SLAT_POSITION] POSITION_ATTRIBUTES = [AttributeType.POSITION, AttributeType.SHUTTER_SLAT_POSITION]
COVER_DEVICE_PROFILES = {
NodeProfile.GARAGE_DOOR_OPERATOR: CoverDeviceClass.GARAGE,
NodeProfile.ENTRANCE_GATE_OPERATOR: CoverDeviceClass.GATE,
NodeProfile.SHUTTER_POSITION_SWITCH: CoverDeviceClass.SHUTTER,
}
def get_open_close_attribute(node: HomeeNode) -> HomeeAttribute | None: def get_open_close_attribute(node: HomeeNode) -> HomeeAttribute | None:
@@ -69,12 +74,6 @@ def get_cover_features(
def get_device_class(node: HomeeNode) -> CoverDeviceClass | None: def get_device_class(node: HomeeNode) -> CoverDeviceClass | None:
"""Determine the device class a homee node based on the node profile.""" """Determine the device class a homee node based on the node profile."""
COVER_DEVICE_PROFILES = {
NodeProfile.GARAGE_DOOR_OPERATOR: CoverDeviceClass.GARAGE,
NodeProfile.ENTRANCE_GATE_OPERATOR: CoverDeviceClass.GATE,
NodeProfile.SHUTTER_POSITION_SWITCH: CoverDeviceClass.SHUTTER,
}
return COVER_DEVICE_PROFILES.get(node.profile) return COVER_DEVICE_PROFILES.get(node.profile)
+3 -3
View File
@@ -30,8 +30,8 @@ def log_rate_limits(
) -> None: ) -> None:
"""Output rate limit log line at given level.""" """Output rate limit log line at given level."""
rate_limits = resp["rateLimits"] rate_limits = resp["rateLimits"]
resetsAt = dt_util.parse_datetime(rate_limits["resetsAt"]) resets_at = dt_util.parse_datetime(rate_limits["resetsAt"])
resetsAtTime = resetsAt - dt_util.utcnow() if resetsAt is not None else "---" resets_at_time = resets_at - dt_util.utcnow() if resets_at is not None else "---"
rate_limit_msg = ( rate_limit_msg = (
"iOS push notification rate limits for %s: " "iOS push notification rate limits for %s: "
"%d sent, %d allowed, %d errors, " "%d sent, %d allowed, %d errors, "
@@ -44,7 +44,7 @@ def log_rate_limits(
rate_limits["successful"], rate_limits["successful"],
rate_limits["maximum"], rate_limits["maximum"],
rate_limits["errors"], rate_limits["errors"],
str(resetsAtTime).split(".", maxsplit=1)[0], str(resets_at_time).split(".", maxsplit=1)[0],
) )
+2 -2
View File
@@ -27,7 +27,7 @@ async def async_handle_unload(coordinator: MadVRCoordinator) -> None:
async def async_setup_entry(hass: HomeAssistant, entry: MadVRConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: MadVRConfigEntry) -> bool:
"""Set up the integration from a config entry.""" """Set up the integration from a config entry."""
assert entry.unique_id assert entry.unique_id
madVRClient = Madvr( mad_vr_client = Madvr(
host=entry.data[CONF_HOST], host=entry.data[CONF_HOST],
logger=_LOGGER, logger=_LOGGER,
port=entry.data[CONF_PORT], port=entry.data[CONF_PORT],
@@ -35,7 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: MadVRConfigEntry) -> boo
connect_timeout=10, connect_timeout=10,
loop=hass.loop, loop=hass.loop,
) )
coordinator = MadVRCoordinator(hass, entry, madVRClient) coordinator = MadVRCoordinator(hass, entry, mad_vr_client)
entry.runtime_data = coordinator entry.runtime_data = coordinator
+4 -4
View File
@@ -84,12 +84,12 @@ class MBCover(MicroBeesEntity, CoverEntity):
async def async_open_cover(self, **kwargs: Any) -> None: async def async_open_cover(self, **kwargs: Any) -> None:
"""Open the cover.""" """Open the cover."""
sendCommand = await self.coordinator.microbees.sendCommand( send_command = await self.coordinator.microbees.sendCommand(
self.actuator_up_id, self.actuator_up_id,
self.actuator_up.configuration.actuator_timing * 1000, self.actuator_up.configuration.actuator_timing * 1000,
) )
if not sendCommand: if not send_command:
raise HomeAssistantError(f"Failed to open {self.name}") raise HomeAssistantError(f"Failed to open {self.name}")
self._attr_is_opening = True self._attr_is_opening = True
@@ -101,11 +101,11 @@ class MBCover(MicroBeesEntity, CoverEntity):
async def async_close_cover(self, **kwargs: Any) -> None: async def async_close_cover(self, **kwargs: Any) -> None:
"""Close the cover.""" """Close the cover."""
sendCommand = await self.coordinator.microbees.sendCommand( send_command = await self.coordinator.microbees.sendCommand(
self.actuator_down_id, self.actuator_down_id,
self.actuator_down.configuration.actuator_timing * 1000, self.actuator_down.configuration.actuator_timing * 1000,
) )
if not sendCommand: if not send_command:
raise HomeAssistantError(f"Failed to close {self.name}") raise HomeAssistantError(f"Failed to close {self.name}")
self._attr_is_closing = True self._attr_is_closing = True
+4 -4
View File
@@ -56,10 +56,10 @@ class MBLight(MicroBeesActuatorEntity, LightEntity):
"""Turn on the light.""" """Turn on the light."""
if ATTR_RGBW_COLOR in kwargs: if ATTR_RGBW_COLOR in kwargs:
self._attr_rgbw_color = kwargs[ATTR_RGBW_COLOR] self._attr_rgbw_color = kwargs[ATTR_RGBW_COLOR]
sendCommand = await self.coordinator.microbees.sendCommand( send_command = await self.coordinator.microbees.sendCommand(
self.actuator_id, 1, color=self._attr_rgbw_color self.actuator_id, 1, color=self._attr_rgbw_color
) )
if not sendCommand: if not send_command:
raise HomeAssistantError(f"Failed to turn on {self.name}") raise HomeAssistantError(f"Failed to turn on {self.name}")
self.actuator.value = True self.actuator.value = True
@@ -67,10 +67,10 @@ class MBLight(MicroBeesActuatorEntity, LightEntity):
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the light.""" """Turn off the light."""
sendCommand = await self.coordinator.microbees.sendCommand( send_command = await self.coordinator.microbees.sendCommand(
self.actuator_id, 0, color=self._attr_rgbw_color self.actuator_id, 0, color=self._attr_rgbw_color
) )
if not sendCommand: if not send_command:
raise HomeAssistantError(f"Failed to turn off {self.name}") raise HomeAssistantError(f"Failed to turn off {self.name}")
self.actuator.value = False self.actuator.value = False
@@ -152,8 +152,8 @@ def log_rate_limits(device_name, resp, level=logging.INFO):
return return
rate_limits = resp[ATTR_PUSH_RATE_LIMITS] rate_limits = resp[ATTR_PUSH_RATE_LIMITS]
resetsAt = rate_limits[ATTR_PUSH_RATE_LIMITS_RESETS_AT] resets_at = rate_limits[ATTR_PUSH_RATE_LIMITS_RESETS_AT]
resetsAtTime = dt_util.parse_datetime(resetsAt) - dt_util.utcnow() resets_at_time = dt_util.parse_datetime(resets_at) - dt_util.utcnow()
rate_limit_msg = ( rate_limit_msg = (
"mobile_app push notification rate limits for %s: " "mobile_app push notification rate limits for %s: "
"%d sent, %d allowed, %d errors, " "%d sent, %d allowed, %d errors, "
@@ -166,7 +166,7 @@ def log_rate_limits(device_name, resp, level=logging.INFO):
rate_limits[ATTR_PUSH_RATE_LIMITS_SUCCESSFUL], rate_limits[ATTR_PUSH_RATE_LIMITS_SUCCESSFUL],
rate_limits[ATTR_PUSH_RATE_LIMITS_MAXIMUM], rate_limits[ATTR_PUSH_RATE_LIMITS_MAXIMUM],
rate_limits[ATTR_PUSH_RATE_LIMITS_ERRORS], rate_limits[ATTR_PUSH_RATE_LIMITS_ERRORS],
str(resetsAtTime).split(".", maxsplit=1)[0], str(resets_at_time).split(".", maxsplit=1)[0],
) )
+14 -14
View File
@@ -146,14 +146,14 @@ async def determine_api_version(
debugging. debugging.
""" """
holeV6 = api_by_version(hass, entry, 6, password="wrong_password") hole_v6 = api_by_version(hass, entry, 6, password="wrong_password")
try: try:
await holeV6.authenticate() await hole_v6.authenticate()
except HoleConnectionError as err: except HoleConnectionError as err:
_LOGGER.error( _LOGGER.error(
"Unexpected error connecting to Pi-hole v6 API" "Unexpected error connecting to Pi-hole v6 API"
" at %s: %s. Trying version 5 API", " at %s: %s. Trying version 5 API",
holeV6.base_url, hole_v6.base_url,
err, err,
) )
# Ideally python-hole would raise a specific exception for authentication failures # Ideally python-hole would raise a specific exception for authentication failures
@@ -161,12 +161,12 @@ async def determine_api_version(
if str(ex_v6) == "Authentication failed: Invalid password": if str(ex_v6) == "Authentication failed: Invalid password":
_LOGGER.debug( _LOGGER.debug(
"Success connecting to Pi-hole at %s without auth, API version is : %s", "Success connecting to Pi-hole at %s without auth, API version is : %s",
holeV6.base_url, hole_v6.base_url,
6, 6,
) )
return 6 return 6
_LOGGER.debug( _LOGGER.debug(
"Connection to %s failed: %s, trying API version 5", holeV6.base_url, ex_v6 "Connection to %s failed: %s, trying API version 5", hole_v6.base_url, ex_v6
) )
else: else:
# It seems that occasionally the auth can succeed # It seems that occasionally the auth can succeed
@@ -175,34 +175,34 @@ async def determine_api_version(
"Authenticated with %s through v6 API, but" "Authenticated with %s through v6 API, but"
" succeeded with an incorrect password." " succeeded with an incorrect password."
" This is a known bug", " This is a known bug",
holeV6.base_url, hole_v6.base_url,
) )
return 6 return 6
holeV5 = api_by_version(hass, entry, 5, password="wrong_token") hole_v5 = api_by_version(hass, entry, 5, password="wrong_token")
try: try:
await holeV5.get_data() await hole_v5.get_data()
except HoleConnectionError as err: except HoleConnectionError as err:
_LOGGER.error( _LOGGER.error(
"Failed to connect to Pi-hole v5 API at %s: %s", holeV5.base_url, err "Failed to connect to Pi-hole v5 API at %s: %s", hole_v5.base_url, err
) )
else: else:
# V5 API returns [] to unauthenticated requests # V5 API returns [] to unauthenticated requests
if not holeV5.data: if not hole_v5.data:
_LOGGER.debug( _LOGGER.debug(
"Response '[]' from API without auth," "Response '[]' from API without auth,"
" pihole API version 5 probably" " pihole API version 5 probably"
" detected at %s", " detected at %s",
holeV5.base_url, hole_v5.base_url,
) )
return 5 return 5
_LOGGER.debug( _LOGGER.debug(
"Unexpected response from Pi-hole API at %s: %s", "Unexpected response from Pi-hole API at %s: %s",
holeV5.base_url, hole_v5.base_url,
str(holeV5.data), str(hole_v5.data),
) )
_LOGGER.debug( _LOGGER.debug(
"Could not determine pi-hole API version at: %s", "Could not determine pi-hole API version at: %s",
holeV6.base_url, hole_v6.base_url,
) )
raise HoleError("Could not determine Pi-hole API version") raise HoleError("Could not determine Pi-hole API version")
@@ -15,15 +15,15 @@ async def async_get_config_entry_diagnostics(
host = reolink_data.host host = reolink_data.host
api = host.api api = host.api
IPC_cam: dict[int, dict[str, Any]] = {} ipc_cam: dict[int, dict[str, Any]] = {}
for ch in api.channels: for ch in api.channels:
IPC_cam[ch] = {} ipc_cam[ch] = {}
IPC_cam[ch]["model"] = api.camera_model(ch) ipc_cam[ch]["model"] = api.camera_model(ch)
IPC_cam[ch]["hardware version"] = api.camera_hardware_version(ch) ipc_cam[ch]["hardware version"] = api.camera_hardware_version(ch)
IPC_cam[ch]["firmware version"] = api.camera_sw_version(ch) ipc_cam[ch]["firmware version"] = api.camera_sw_version(ch)
IPC_cam[ch]["encoding main"] = await api.get_encoding(ch) ipc_cam[ch]["encoding main"] = await api.get_encoding(ch)
if (signal := api.wifi_signal(ch)) is not None and api.wifi_connection(ch): if (signal := api.wifi_signal(ch)) is not None and api.wifi_connection(ch):
IPC_cam[ch]["WiFi signal"] = signal ipc_cam[ch]["WiFi signal"] = signal
chimes: dict[int, dict[str, Any]] = {} chimes: dict[int, dict[str, Any]] = {}
for chime in api.chime_list: for chime in api.chime_list:
@@ -50,7 +50,7 @@ async def async_get_config_entry_diagnostics(
"stream protocol": api.protocol, "stream protocol": api.protocol,
"channels": api.channels, "channels": api.channels,
"stream channels": api.stream_channels, "stream channels": api.stream_channels,
"IPC cams": IPC_cam, "IPC cams": ipc_cam,
"Chimes": chimes, "Chimes": chimes,
"capabilities": api.capabilities, "capabilities": api.capabilities,
"cmd list": host.update_cmd, "cmd list": host.update_cmd,
@@ -47,21 +47,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: SolarlogConfigEntry) ->
basic_coordinator = SolarLogBasicDataCoordinator(hass, entry, solarlog) basic_coordinator = SolarLogBasicDataCoordinator(hass, entry, solarlog)
solarLogData = SolarlogIntegrationData( solar_log_data = SolarlogIntegrationData(
api=solarlog, api=solarlog,
basic_data_coordinator=basic_coordinator, basic_data_coordinator=basic_coordinator,
) )
await basic_coordinator.async_config_entry_first_refresh() await basic_coordinator.async_config_entry_first_refresh()
entry.runtime_data = solarLogData entry.runtime_data = solar_log_data
_LOGGER.debug( _LOGGER.debug(
"Basic coordinator setup successful, extended data available: %s", "Basic coordinator setup successful, extended data available: %s",
solarLogData.api.extended_data, solar_log_data.api.extended_data,
) )
if solarLogData.api.extended_data: if solar_log_data.api.extended_data:
timeout = entry.data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT) timeout = entry.data.get(CONF_TIMEOUT, DEFAULT_TIMEOUT)
_LOGGER.debug("Setup of LongtimeDataCoordinator, saved timeout is %s", timeout) _LOGGER.debug("Setup of LongtimeDataCoordinator, saved timeout is %s", timeout)
+15 -12
View File
@@ -335,40 +335,43 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Add solarlog entry.""" """Add solarlog entry."""
solarLogIntegrationData: SolarlogIntegrationData = entry.runtime_data solar_log_integration_data: SolarlogIntegrationData = entry.runtime_data
entities: list[SensorEntity] = [ entities: list[SensorEntity] = [
SolarLogBasicCoordinatorSensor( SolarLogBasicCoordinatorSensor(
solarLogIntegrationData.basic_data_coordinator, sensor solar_log_integration_data.basic_data_coordinator, sensor
) )
for sensor in SOLARLOG_BASIC_SENSOR_TYPES for sensor in SOLARLOG_BASIC_SENSOR_TYPES
] ]
if solarLogIntegrationData.longtime_data_coordinator is not None: if solar_log_integration_data.longtime_data_coordinator is not None:
entities.extend( entities.extend(
SolarLogLongtimeCoordinatorSensor( SolarLogLongtimeCoordinatorSensor(
solarLogIntegrationData.longtime_data_coordinator, sensor solar_log_integration_data.longtime_data_coordinator, sensor
) )
for sensor in SOLARLOG_LONGTIME_SENSOR_TYPES for sensor in SOLARLOG_LONGTIME_SENSOR_TYPES
) )
# add battery sensors only if respective data is # add battery sensors only if respective data is
# available (otherwise no battery attached to solarlog) # available (otherwise no battery attached to solarlog)
if solarLogIntegrationData.basic_data_coordinator.data.battery_data is not None: if (
solar_log_integration_data.basic_data_coordinator.data.battery_data
is not None
):
entities.extend( entities.extend(
SolarLogBatterySensor( SolarLogBatterySensor(
solarLogIntegrationData.basic_data_coordinator, sensor solar_log_integration_data.basic_data_coordinator, sensor
) )
for sensor in SOLARLOG_BATTERY_SENSOR_TYPES for sensor in SOLARLOG_BATTERY_SENSOR_TYPES
) )
if solarLogIntegrationData.device_data_coordinator is not None: if solar_log_integration_data.device_data_coordinator is not None:
device_data = solarLogIntegrationData.device_data_coordinator.data device_data = solar_log_integration_data.device_data_coordinator.data
if device_data: if device_data:
entities.extend( entities.extend(
SolarLogInverterSensor( SolarLogInverterSensor(
solarLogIntegrationData.device_data_coordinator, solar_log_integration_data.device_data_coordinator,
sensor, sensor,
device_id, device_id,
) )
@@ -379,15 +382,15 @@ async def async_setup_entry(
def _async_add_new_device(device_id: int) -> None: def _async_add_new_device(device_id: int) -> None:
async_add_entities( async_add_entities(
SolarLogInverterSensor( SolarLogInverterSensor(
solarLogIntegrationData.device_data_coordinator, solar_log_integration_data.device_data_coordinator,
sensor, sensor,
device_id, device_id,
) )
for sensor in SOLARLOG_INVERTER_SENSOR_TYPES for sensor in SOLARLOG_INVERTER_SENSOR_TYPES
if solarLogIntegrationData.device_data_coordinator is not None if solar_log_integration_data.device_data_coordinator is not None
) )
solarLogIntegrationData.device_data_coordinator.new_device_callbacks.append( solar_log_integration_data.device_data_coordinator.new_device_callbacks.append(
_async_add_new_device _async_add_new_device
) )
@@ -326,7 +326,7 @@ async def make_new_device_data(
manageable_by_webhook=default_config.webhook, manageable_by_webhook=default_config.webhook,
) )
_PLATFORM_LIST_MAP: dict[Platform, list] = { _platform_list_map: dict[Platform, list] = {
Platform.BINARY_SENSOR: devices_data.binary_sensors, Platform.BINARY_SENSOR: devices_data.binary_sensors,
Platform.BUTTON: devices_data.buttons, Platform.BUTTON: devices_data.buttons,
Platform.CLIMATE: devices_data.climates, Platform.CLIMATE: devices_data.climates,
@@ -342,7 +342,7 @@ async def make_new_device_data(
} }
for platform in default_config.entity_config: for platform in default_config.entity_config:
target_list = _PLATFORM_LIST_MAP.get(platform) target_list = _platform_list_map.get(platform)
if target_list is None: if target_list is None:
continue continue
existing_ids = {item[0].device_id for item in target_list} existing_ids = {item[0].device_id for item in target_list}
@@ -502,14 +502,14 @@ def _create_handle_webhook(
_LOGGER.debug("Received invalid data from switchbot webhook %s", repr(data)) _LOGGER.debug("Received invalid data from switchbot webhook %s", repr(data))
return return
_LOGGER.debug("Received data from switchbot webhook: %s", repr(data)) _LOGGER.debug("Received data from switchbot webhook: %s", repr(data))
deviceMac = data["context"]["deviceMac"] device_mac = data["context"]["deviceMac"]
if deviceMac not in coordinators_by_id: if device_mac not in coordinators_by_id:
_LOGGER.error( _LOGGER.error(
"Received data for unknown entity from switchbot webhook: %s", data "Received data for unknown entity from switchbot webhook: %s", data
) )
return return
coordinators_by_id[deviceMac].async_set_updated_data(data["context"]) coordinators_by_id[device_mac].async_set_updated_data(data["context"])
return _internal_handle_webhook return _internal_handle_webhook
@@ -124,6 +124,14 @@ MODEL_TO_CLASS_MAP = {
MODEL_FAN_ZA5: FanZA5, MODEL_FAN_ZA5: FanZA5,
} }
# List of models requiring specific lazy_discover setting
LAZY_DISCOVER_FOR_MODEL = {
"zhimi.fan.za3": True,
"zhimi.fan.za5": True,
"zhimi.airpurifier.za1": True,
"dmaker.fan.1c": True,
}
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the component.""" """Set up the component."""
@@ -307,13 +315,6 @@ async def async_create_miio_device_and_coordinator(
update_method = _async_update_data_default update_method = _async_update_data_default
coordinator_class: type[DataUpdateCoordinator[Any]] = DataUpdateCoordinator coordinator_class: type[DataUpdateCoordinator[Any]] = DataUpdateCoordinator
# List of models requiring specific lazy_discover setting
LAZY_DISCOVER_FOR_MODEL = {
"zhimi.fan.za3": True,
"zhimi.fan.za5": True,
"zhimi.airpurifier.za1": True,
"dmaker.fan.1c": True,
}
lazy_discover = LAZY_DISCOVER_FOR_MODEL.get(model, False) lazy_discover = LAZY_DISCOVER_FOR_MODEL.get(model, False)
if ( if (
+2 -2
View File
@@ -70,8 +70,8 @@ class YoLinkHomeMessageListener(MessageListener):
return return
device_coordinator.dev_online = True device_coordinator.dev_online = True
if (loraInfo := msg_data.get(ATTR_LORA_INFO)) is not None: if (lora_info := msg_data.get(ATTR_LORA_INFO)) is not None:
device_coordinator.dev_net_type = loraInfo.get("devNetType") device_coordinator.dev_net_type = lora_info.get("devNetType")
device_coordinator.async_set_updated_data(msg_data) device_coordinator.async_set_updated_data(msg_data)
# handling events # handling events
if ( if (
+4
View File
@@ -710,6 +710,7 @@ select = [
"LOG", # flake8-logging "LOG", # flake8-logging
"N804", # First argument of a class method should be named cls "N804", # First argument of a class method should be named cls
"N805", # First argument of a method should be named self "N805", # First argument of a method should be named self
"N806", # Variable {name} in function should be snake_case
"N815", # Variable {name} in class scope should not be mixedCase "N815", # Variable {name} in class scope should not be mixedCase
"PERF", # Perflint "PERF", # Perflint
"PGH", # pygrep-hooks "PGH", # pygrep-hooks
@@ -928,6 +929,9 @@ split-on-trailing-comma = false
"homeassistant/scripts/*" = ["T201"] "homeassistant/scripts/*" = ["T201"]
"script/*" = ["T20"] "script/*" = ["T20"]
# Some utils have constants that benefit from being uppercase
"homeassistant/util/*" = ["N806"]
# Allow relative imports within auth and within components # Allow relative imports within auth and within components
"homeassistant/auth/*/*" = ["TID252"] "homeassistant/auth/*/*" = ["TID252"]
"homeassistant/components/*/*/*" = ["TID252"] "homeassistant/components/*/*/*" = ["TID252"]
@@ -17,7 +17,7 @@ async def test_setup_and_remove_config_entry(
) -> None: ) -> None:
"""Test setting up and removing a config entry.""" """Test setting up and removing a config entry."""
input_sensor_entity_id = "sensor.input" input_sensor_entity_id = "sensor.input"
NEW_DOMAIN_entity_id = f"{platform}.my_NEW_DOMAIN" new_domain_entity_id = f"{platform}.my_NEW_DOMAIN"
# Setup the config entry # Setup the config entry
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
@@ -34,10 +34,10 @@ async def test_setup_and_remove_config_entry(
await hass.async_block_till_done() await hass.async_block_till_done()
# Check the entity is registered in the entity registry # Check the entity is registered in the entity registry
assert entity_registry.async_get(NEW_DOMAIN_entity_id) is not None assert entity_registry.async_get(new_domain_entity_id) is not None
# Check the platform is setup correctly # Check the platform is setup correctly
state = hass.states.get(NEW_DOMAIN_entity_id) state = hass.states.get(new_domain_entity_id)
# TODO Check the state of the entity has changed as expected # TODO Check the state of the entity has changed as expected
assert state.state == "unknown" assert state.state == "unknown"
assert state.attributes == {} assert state.attributes == {}
@@ -47,5 +47,5 @@ async def test_setup_and_remove_config_entry(
await hass.async_block_till_done() await hass.async_block_till_done()
# Check the state and entity registry entry are removed # Check the state and entity registry entry are removed
assert hass.states.get(NEW_DOMAIN_entity_id) is None assert hass.states.get(new_domain_entity_id) is None
assert entity_registry.async_get(NEW_DOMAIN_entity_id) is None assert entity_registry.async_get(new_domain_entity_id) is None
+1
View File
@@ -5,6 +5,7 @@ extend = "../pyproject.toml"
extend-ignore = [ extend-ignore = [
"B904", # Use raise from to specify exception cause "B904", # Use raise from to specify exception cause
"N806", # Variable {name} in function should be snake_case
"N815", # Variable {name} in class scope should not be mixedCase "N815", # Variable {name} in class scope should not be mixedCase
"RUF018", # Avoid assignment expressions in assert statements "RUF018", # Avoid assignment expressions in assert statements
"DTZ011", # date.today() used: tests commonly use naive dates "DTZ011", # date.today() used: tests commonly use naive dates