diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py
index c1f1dbb9104..bb6cb306426 100644
--- a/homeassistant/components/sonos/speaker.py
+++ b/homeassistant/components/sonos/speaker.py
@@ -420,8 +420,6 @@ class SonosSpeaker:
async_dispatcher_send(self.hass, SONOS_ALARM_UPDATE, self)
- self.async_write_entity_states()
-
async def async_update_battery_info(self, battery_dict: dict[str, Any]) -> None:
"""Update battery info using the decoded SonosEvent."""
self._last_battery_event = dt_util.utcnow()
diff --git a/homeassistant/components/sonos/switch.py b/homeassistant/components/sonos/switch.py
index 967bc21da59..879d5fa0a99 100644
--- a/homeassistant/components/sonos/switch.py
+++ b/homeassistant/components/sonos/switch.py
@@ -43,11 +43,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
entity = SonosAlarmEntity(alarm_id, speaker)
async_add_entities([entity])
configured_alarms.add(alarm_id)
- config_entry.async_on_unload(
- async_dispatcher_connect(
- hass, SONOS_ALARM_UPDATE, entity.async_update
- )
- )
config_entry.async_on_unload(
async_dispatcher_connect(hass, SONOS_CREATE_ALARM, _async_create_entity)
@@ -64,9 +59,20 @@ class SonosAlarmEntity(SonosEntity, SwitchEntity):
self._alarm_id = alarm_id
self.entity_id = ENTITY_ID_FORMAT.format(f"sonos_alarm_{self.alarm_id}")
+ async def async_added_to_hass(self) -> None:
+ """Handle switch setup when added to hass."""
+ await super().async_added_to_hass()
+ self.async_on_remove(
+ async_dispatcher_connect(
+ self.hass,
+ SONOS_ALARM_UPDATE,
+ self.async_update,
+ )
+ )
+
@property
def alarm(self):
- """Return the ID of the alarm."""
+ """Return the alarm instance."""
return self.hass.data[DATA_SONOS].alarms[self.alarm_id]
@property
diff --git a/tests/components/sonos/conftest.py b/tests/components/sonos/conftest.py
index 2feb2b54896..aa14dcaa5cf 100644
--- a/tests/components/sonos/conftest.py
+++ b/tests/components/sonos/conftest.py
@@ -30,7 +30,7 @@ def config_entry_fixture():
@pytest.fixture(name="soco")
def soco_fixture(
- music_library, speaker_info, battery_info, dummy_soco_service, alarmClock
+ music_library, speaker_info, battery_info, dummy_soco_service, alarm_clock
):
"""Create a mock pysonos SoCo fixture."""
with patch("pysonos.SoCo", autospec=True) as mock, patch(
@@ -46,7 +46,7 @@ def soco_fixture(
mock_soco.zoneGroupTopology = dummy_soco_service
mock_soco.contentDirectory = dummy_soco_service
mock_soco.deviceProperties = dummy_soco_service
- mock_soco.alarmClock = alarmClock
+ mock_soco.alarmClock = alarm_clock
mock_soco.mute = False
mock_soco.night_mode = True
mock_soco.dialog_mode = True
@@ -90,12 +90,28 @@ def music_library_fixture():
return music_library
-@pytest.fixture(name="alarmClock")
-def alarmClock_fixture():
+@pytest.fixture(name="alarm_clock")
+def alarm_clock_fixture():
"""Create alarmClock fixture."""
- alarmClock = Mock()
- alarmClock.subscribe = AsyncMock()
- alarmClock.ListAlarms.return_value = {
+ alarm_clock = Mock()
+ alarm_clock.subscribe = AsyncMock()
+ alarm_clock.ListAlarms.return_value = {
+ "CurrentAlarmList": ""
+ ''
+ " "
+ }
+ return alarm_clock
+
+
+@pytest.fixture(name="alarm_clock_extended")
+def alarm_clock_fixture_extended():
+ """Create alarmClock fixture."""
+ alarm_clock = Mock()
+ alarm_clock.subscribe = AsyncMock()
+ alarm_clock.ListAlarms.return_value = {
"CurrentAlarmList": ""
''
" "
}
- return alarmClock
+ return alarm_clock
@pytest.fixture(name="speaker_info")
@@ -141,3 +157,19 @@ def battery_event_fixture(soco):
"more_info": "BattChg:NOT_CHARGING,RawBattPct:100,BattPct:100,BattTmp:25",
}
return SonosMockEvent(soco, variables)
+
+
+@pytest.fixture(name="alarm_event")
+def alarm_event_fixture(soco):
+ """Create alarm_event fixture."""
+ variables = {
+ "time_zone": "ffc40a000503000003000502ffc4",
+ "time_server": "0.sonostime.pool.ntp.org,1.sonostime.pool.ntp.org,2.sonostime.pool.ntp.org,3.sonostime.pool.ntp.org",
+ "time_generation": "20000001",
+ "alarm_list_version": "RINCON_test",
+ "time_format": "INV",
+ "date_format": "INV",
+ "daily_index_refresh_time": None,
+ }
+
+ return SonosMockEvent(soco, variables)
diff --git a/tests/components/sonos/test_switch.py b/tests/components/sonos/test_switch.py
index c33c472ee27..d4448d22b32 100644
--- a/tests/components/sonos/test_switch.py
+++ b/tests/components/sonos/test_switch.py
@@ -9,17 +9,18 @@ from homeassistant.components.sonos.switch import (
ATTR_VOLUME,
)
from homeassistant.const import ATTR_TIME, STATE_ON
+from homeassistant.helpers.entity_registry import async_get as async_get_entity_registry
from homeassistant.setup import async_setup_component
async def setup_platform(hass, config_entry, config):
- """Set up the media player platform for testing."""
+ """Set up the switch platform for testing."""
config_entry.add_to_hass(hass)
assert await async_setup_component(hass, DOMAIN, config)
await hass.async_block_till_done()
-async def test_entity_registry(hass, config_entry, config, soco):
+async def test_entity_registry(hass, config_entry, config):
"""Test sonos device with alarm registered in the device registry."""
await setup_platform(hass, config_entry, config)
@@ -29,7 +30,7 @@ async def test_entity_registry(hass, config_entry, config, soco):
assert "switch.sonos_alarm_14" in entity_registry.entities
-async def test_alarm_attributes(hass, config_entry, config, soco):
+async def test_alarm_attributes(hass, config_entry, config):
"""Test for correct sonos alarm state."""
await setup_platform(hass, config_entry, config)
@@ -45,3 +46,31 @@ async def test_alarm_attributes(hass, config_entry, config, soco):
assert alarm_state.attributes.get(ATTR_VOLUME) == 0.25
assert alarm_state.attributes.get(ATTR_PLAY_MODE) == "SHUFFLE_NOREPEAT"
assert not alarm_state.attributes.get(ATTR_INCLUDE_LINKED_ZONES)
+
+
+async def test_alarm_create_delete(
+ hass, config_entry, config, soco, alarm_clock, alarm_clock_extended, alarm_event
+):
+ """Test for correct creation and deletion of alarms during runtime."""
+ soco.alarmClock = alarm_clock_extended
+
+ await setup_platform(hass, config_entry, config)
+
+ subscription = alarm_clock_extended.subscribe.return_value
+ sub_callback = subscription.callback
+
+ sub_callback(event=alarm_event)
+ await hass.async_block_till_done()
+
+ entity_registry = async_get_entity_registry(hass)
+
+ assert "switch.sonos_alarm_14" in entity_registry.entities
+ assert "switch.sonos_alarm_15" in entity_registry.entities
+
+ alarm_clock_extended.ListAlarms.return_value = alarm_clock.ListAlarms.return_value
+
+ sub_callback(event=alarm_event)
+ await hass.async_block_till_done()
+
+ assert "switch.sonos_alarm_14" in entity_registry.entities
+ assert "switch.sonos_alarm_15" not in entity_registry.entities