Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions custom_components/wyzeapi/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,14 @@ async def async_setup_entry(
if lock.product_model != "YD_BT1"
]
lock_bolts = []
coordinators = hass.data[DOMAIN][config_entry.entry_id].get("coordinators", {})
for lock in all_locks:
if lock.product_model == "YD_BT1":
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinators"][
lock.mac
]
lock_bolts.append(WyzeLockBolt(coordinator))
coordinator = coordinators.get(lock.mac)
if coordinator is not None:
lock_bolts.append(WyzeLockBolt(coordinator))
else:
_LOGGER.warning("No coordinator found for lock with MAC: %s", lock.mac)

async_add_entities(locks + lock_bolts, True)

Expand Down
10 changes: 10 additions & 0 deletions custom_components/wyzeapi/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,15 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
}
},
"issues": {
"entity_changed": {
"title": "Wyze Entity Error",
"description": "{automation} may need attention. {entity} may have changed or been removed. This is due to a change in outdoor plug devices. Once fixed you can ignore this issue."
},
"device_changed": {
"title": "Wyze Device Error",
"description": "{automation} may need attention. A device has changed or been removed. This is due to a change in outdoor plug devices. Once fixed you can ignore this issue."
}
}
}
104 changes: 101 additions & 3 deletions custom_components/wyzeapi/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,25 @@
from wyzeapy.services.switch_service import Switch
from wyzeapy.types import Device, DeviceTypes, Event

from homeassistant.components.automation import (
automations_with_device,
automations_with_entity,
)
from homeassistant.components.script import scripts_with_device, scripts_with_entity
from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import (
device_registry as dr,
entity_registry as er,
issue_registry as ir,
)
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.issue_registry import IssueSeverity

from .const import (
CAMERA_UPDATED,
Expand Down Expand Up @@ -75,6 +85,7 @@ async def async_setup_entry(
bulb_service = await client.bulb_service

switches: list[SwitchEntity] = []
has_outdoor_plug: bool = False

base_switches = await switch_service.get_switches()
# The outdoor plug has a dummy switch that doesn't control anything
Expand All @@ -83,10 +94,14 @@ async def async_setup_entry(
switches.extend(
WyzeSwitch(switch_service, switch)
for switch in base_switches
if switch.product_model not in OUTDOOR_PLUGS
or switch.product_model.endswith("-SUB") # Outdoor plug individual outlet
if switch.product_model not in [OUTDOOR_PLUGS, OUTDOOR_PLUG_INDIVUAL_OUTLETS]
)

for switch in base_switches:
if switch.product_model in [OUTDOOR_PLUG_INDIVUAL_OUTLETS]:
has_outdoor_plug = True
switches.append(WyzeSwitch(switch_service, switch))

switches.extend(
WyzeSwitch(wall_switch_service, switch)
for switch in await wall_switch_service.get_switches()
Expand Down Expand Up @@ -115,9 +130,92 @@ async def async_setup_entry(
if bulb.type is DeviceTypes.LIGHTSTRIP
)

# Catch old outdoor plug devices and entities and remove.
# This can be removed at a later date.
if has_outdoor_plug:
devices_to_migrate = []
device_registry = dr.async_get(hass)
devices = dr.async_entries_for_config_entry(
device_registry, config_entry.entry_id
)
for device in devices:
for identifier in device.identifiers:
mac = identifier[1]
if (
"-" in mac and device.model == OUTDOOR_PLUG_INDIVUAL_OUTLETS
): # The old devices have a '-' in the mac
devices_to_migrate.append(device.id)

# Also catch the old dummy switch to remove below.
# Should only happen once while the old devices are still around.
if devices_to_migrate:
devices_to_migrate.extend(
device.id for device in devices if device.model == OUTDOOR_PLUGS
)
await async_migrate_switch_data(
hass, config_entry, devices_to_migrate, device_registry
)

async_add_entities(switches, True)


async def async_migrate_switch_data(
hass: HomeAssistant,
config_entry: ConfigEntry,
device_list,
device_registry,
):
"""Remove redundant switch devices and entities and flag for repair.

This can be removed in the future.
"""

entity_registry = er.async_get(hass)
entities = er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)

for entity in entities:
if entity.device_id in device_list and entity.domain == "switch":
entity_automations = automations_with_entity(hass, entity.entity_id)
entity_automations.extend(scripts_with_entity(hass, entity.entity_id))
if entity_automations:
for issue in entity_automations:
ir.async_create_issue(
hass,
DOMAIN,
issue_id=f"{issue}-entity-issue",
is_fixable=False,
is_persistent=True,
severity=IssueSeverity.ERROR,
learn_more_url="https://github.com/SecKatie/ha-wyzeapi/issues/789",
translation_key="entity_changed",
translation_placeholders={
"entity": entity.entity_id,
"automation": issue,
},
)
entity_registry.async_remove(entity.id)

for device in device_list:
device_automations = automations_with_device(hass, device)
device_automations.extend(scripts_with_device(hass, device))
if device_automations:
for issue in device_automations:
ir.async_create_issue(
hass,
DOMAIN,
issue_id=f"{issue}-device-issue",
is_fixable=False,
is_persistent=True,
severity=IssueSeverity.ERROR,
learn_more_url="https://github.com/SecKatie/ha-wyzeapi/issues/789",
translation_key="device_changed",
translation_placeholders={
"automation": issue,
},
)
device_registry.async_remove_device(device)


class WyzeNotifications(SwitchEntity):
"""Class for notification switch."""

Expand Down
10 changes: 10 additions & 0 deletions custom_components/wyzeapi/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,15 @@
"already_configured": "Device is already configured",
"reauth_successful": "Reauthentication Successful"
}
},
"issues": {
"entity_changed": {
"title": "Wyze Entity Error",
"description": "{automation} may neeed attention. {entity} may have changed or been removed. This is due to a change in outdoor plug devices. Once fixed you can ignore this issue."
},
"device_changed": {
"title": "Wyze Device Error",
"description": "{automation} may need attention. A device has changed or been removed. This is due to a change in outdoor plug devices. Once fixed you can ignore this issue."
}
}
}
Loading