jmri_core.beans.power

Track power control.

Each ~jmri_core.hal.connection.SystemConnection exposes a single PowerManager instance — there is no per-bean Power object because the layout track has exactly one power state per connection.

 1"""Track power control.
 2
 3Each :class:`~jmri_core.hal.connection.SystemConnection` exposes a single
 4:class:`PowerManager` instance — there is no per-bean Power object because
 5the layout track has exactly one power state per connection.
 6"""
 7from __future__ import annotations
 8
 9from dataclasses import dataclass
10
11from jmri_core.events import Signal
12from jmri_core.state import PowerState
13
14
15@dataclass(frozen=True, slots=True)
16class PowerChange:
17    previous: PowerState
18    current: PowerState
19
20
21class PowerManager:
22    """Track power state for one system connection.
23
24    Not a NamedBean — it has no system name and there is exactly one per
25    connection. Drivers override :meth:`set_power` to send the hardware
26    command and call :meth:`_set_state` when the layout reports a change.
27    """
28
29    def __init__(self) -> None:
30        self._state: PowerState = PowerState.UNKNOWN
31        self.state_changed: Signal[PowerChange] = Signal()
32
33    @property
34    def state(self) -> PowerState:
35        return self._state
36
37    async def set_power(self, state: PowerState) -> None:
38        """Command the layout to *state*. Base impl just updates in-memory."""
39        await self._set_state(state)
40
41    async def _set_state(self, state: PowerState) -> None:
42        prev = self._state
43        if prev == state:
44            return
45        self._state = state
46        await self.state_changed.emit(PowerChange(prev, state))
@dataclass(frozen=True, slots=True)
class PowerChange:
16@dataclass(frozen=True, slots=True)
17class PowerChange:
18    previous: PowerState
19    current: PowerState
PowerChange( previous: jmri_core.state.PowerState, current: jmri_core.state.PowerState)
class PowerManager:
22class PowerManager:
23    """Track power state for one system connection.
24
25    Not a NamedBean — it has no system name and there is exactly one per
26    connection. Drivers override :meth:`set_power` to send the hardware
27    command and call :meth:`_set_state` when the layout reports a change.
28    """
29
30    def __init__(self) -> None:
31        self._state: PowerState = PowerState.UNKNOWN
32        self.state_changed: Signal[PowerChange] = Signal()
33
34    @property
35    def state(self) -> PowerState:
36        return self._state
37
38    async def set_power(self, state: PowerState) -> None:
39        """Command the layout to *state*. Base impl just updates in-memory."""
40        await self._set_state(state)
41
42    async def _set_state(self, state: PowerState) -> None:
43        prev = self._state
44        if prev == state:
45            return
46        self._state = state
47        await self.state_changed.emit(PowerChange(prev, state))

Track power state for one system connection.

Not a NamedBean — it has no system name and there is exactly one per connection. Drivers override set_power() to send the hardware command and call _set_state() when the layout reports a change.

state_changed: jmri_core.Signal[PowerChange]
state: jmri_core.state.PowerState
34    @property
35    def state(self) -> PowerState:
36        return self._state
async def set_power(self, state: jmri_core.state.PowerState) -> None:
38    async def set_power(self, state: PowerState) -> None:
39        """Command the layout to *state*. Base impl just updates in-memory."""
40        await self._set_state(state)

Command the layout to state. Base impl just updates in-memory.