Skip to content

Switch

One SwitchEntity is created per PWM channel where pwm#X#onoff = true and pwm#X#color != "".

These channels are treated as binary (on/off) — the device still accepts a PWM value, but the controller UI presents them as switches.

Reference

switch

Classes

SunRiserMaintenanceSwitch

Bases: CoordinatorEntity[SunRiserCoordinator], SwitchEntity

Maintenance mode switch — freezes all PWM channels on the device.

Source code in custom_components/sunriser/switch.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class SunRiserMaintenanceSwitch(CoordinatorEntity[SunRiserCoordinator], SwitchEntity):
    """Maintenance mode switch — freezes all PWM channels on the device."""

    _attr_has_entity_name = True
    _attr_translation_key = "maintenance_mode"
    _attr_device_class = SwitchDeviceClass.SWITCH

    def __init__(self, coordinator: SunRiserCoordinator, entry: ConfigEntry) -> None:
        super().__init__(coordinator)
        self._attr_unique_id = f"{entry.entry_id}_maintenance"
        self._attr_device_info = coordinator.device_info

    @property
    def is_on(self) -> bool:
        if self.coordinator.data is None:
            return False
        # service_mode is 0 when off, or a Unix timestamp when on
        return bool(self.coordinator.data.get("service_mode"))

    async def async_turn_on(self, **kwargs: object) -> None:
        await self.coordinator.async_set_service_mode(True)
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs: object) -> None:
        await self.coordinator.async_set_service_mode(False)
        await self.coordinator.async_request_refresh()

SunRiserSwitch

Bases: CoordinatorEntity[SunRiserCoordinator], SwitchEntity

On/off PWM channel (pwm#X#onoff = true) on a SunRiser device.

Source code in custom_components/sunriser/switch.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
class SunRiserSwitch(CoordinatorEntity[SunRiserCoordinator], SwitchEntity):
    """On/off PWM channel (pwm#X#onoff = true) on a SunRiser device."""

    _attr_has_entity_name = True

    def __init__(
        self,
        coordinator: SunRiserCoordinator,
        entry: ConfigEntry,
        pwm_num: int,
    ) -> None:
        super().__init__(coordinator)
        self._pwm_num = pwm_num
        self._attr_unique_id = f"{entry.entry_id}_pwm_{pwm_num}"
        self._attr_name = coordinator.pwm_name(pwm_num)
        self._attr_device_info = coordinator.device_info

    @property
    def is_on(self) -> bool:
        return self.coordinator.pwm_value(self._pwm_num) > 0

    async def async_turn_on(self, **kwargs: object) -> None:
        await self.coordinator.async_set_pwms({str(self._pwm_num): PWM_MAX})
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs: object) -> None:
        await self.coordinator.async_set_pwms({str(self._pwm_num): 0})
        await self.coordinator.async_request_refresh()

SunRiserTimelapseSwitch

Bases: CoordinatorEntity[SunRiserCoordinator], SwitchEntity

Time-lapse (timewarp) mode — runs the day/week planner at ~1800× speed.

Source code in custom_components/sunriser/switch.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
class SunRiserTimelapseSwitch(CoordinatorEntity[SunRiserCoordinator], SwitchEntity):
    """Time-lapse (timewarp) mode — runs the day/week planner at ~1800× speed."""

    _attr_has_entity_name = True
    _attr_translation_key = "timelapse"

    def __init__(self, coordinator: SunRiserCoordinator, entry: ConfigEntry) -> None:
        super().__init__(coordinator)
        self._attr_unique_id = f"{entry.entry_id}_timelapse"
        self._attr_device_info = coordinator.device_info

    @property
    def is_on(self) -> bool:
        if self.coordinator.data is None:
            return False
        return bool(self.coordinator.data.get("timewarp"))

    async def async_turn_on(self, **kwargs: object) -> None:
        await self.coordinator.async_set_timewarp(True)
        await self.coordinator.async_request_refresh()

    async def async_turn_off(self, **kwargs: object) -> None:
        await self.coordinator.async_set_timewarp(False)
        await self.coordinator.async_request_refresh()

SunRiserDSTAutoSwitch

Bases: CoordinatorEntity[SunRiserCoordinator], SwitchEntity, RestoreEntity

Automatic DST tracking — keeps the device summertime config in sync with the HA timezone.

Source code in custom_components/sunriser/switch.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
class SunRiserDSTAutoSwitch(
    CoordinatorEntity[SunRiserCoordinator], SwitchEntity, RestoreEntity
):
    """Automatic DST tracking — keeps the device summertime config in sync with the HA timezone."""

    _attr_has_entity_name = True
    _attr_translation_key = "dst_auto_track"
    _attr_entity_category = EntityCategory.CONFIG

    def __init__(self, coordinator: SunRiserCoordinator, entry: ConfigEntry) -> None:
        super().__init__(coordinator)
        self._attr_unique_id = f"{entry.entry_id}_dst_auto_track"
        self._attr_device_info = coordinator.device_info

    async def async_added_to_hass(self) -> None:
        await super().async_added_to_hass()
        # The hass.data bridge in coordinator.__init__ already restores
        # _dst_auto_track on same-session reloads (options change, reconfigure).
        # Only fall back to the recorder when the bridge didn't supply the value
        # (i.e. a true HA restart), to avoid a redundant PUT / that fires
        # immediately after init and causes rapid back-to-back TCP connections.
        if not self.coordinator._dst_auto_track:
            last_state = await self.async_get_last_state()
            if last_state is not None and last_state.state == STATE_ON:
                await self.coordinator.async_set_dst_auto_track(True)

    @property
    def is_on(self) -> bool:
        return self.coordinator._dst_auto_track

    async def async_turn_on(self, **kwargs: object) -> None:
        await self.coordinator.async_set_dst_auto_track(True)
        self.async_write_ha_state()

    async def async_turn_off(self, **kwargs: object) -> None:
        await self.coordinator.async_set_dst_auto_track(False)
        self.async_write_ha_state()