jmri_core.beans.light
Light — a controllable layout light (yard light, building, etc.).
A light may be plain on/off or dimmable. intensity is in the range
[0.0, 1.0]; when set to a non-extreme value, state becomes
INTERMEDIATE.
1"""``Light`` — a controllable layout light (yard light, building, etc.). 2 3A light may be plain on/off or dimmable. ``intensity`` is in the range 4``[0.0, 1.0]``; when set to a non-extreme value, ``state`` becomes 5``INTERMEDIATE``. 6""" 7from __future__ import annotations 8 9from dataclasses import dataclass 10 11from jmri_core.bean import AbstractNamedBean 12from jmri_core.manager import Manager 13from jmri_core.state import LightState 14 15 16@dataclass(frozen=True, slots=True) 17class LightChange: 18 previous_state: LightState 19 current_state: LightState 20 intensity: float 21 22 23class Light(AbstractNamedBean): 24 """Layout light. Supports binary or dimmable control.""" 25 26 __slots__ = ("_intensity", "_state", "supports_dimming") 27 28 type_letter = "L" 29 30 def __init__(self, system_name: str, user_name: str | None = None) -> None: 31 super().__init__(system_name, user_name) 32 self._state: LightState = LightState.UNKNOWN 33 self._intensity: float = 0.0 34 self.supports_dimming: bool = False 35 36 @property 37 def state(self) -> LightState: 38 return self._state 39 40 @property 41 def intensity(self) -> float: 42 return self._intensity 43 44 async def set_state(self, state: LightState) -> None: 45 prev = self._state 46 if state == LightState.ON: 47 self._intensity = 1.0 48 elif state == LightState.OFF: 49 self._intensity = 0.0 50 self._state = state 51 if prev != state: 52 await self.state_changed.emit(LightChange(prev, state, self._intensity)) 53 54 async def set_intensity(self, intensity: float) -> None: 55 if not 0.0 <= intensity <= 1.0: 56 raise ValueError(f"intensity must be in [0,1], got {intensity}") 57 if not self.supports_dimming and intensity not in (0.0, 1.0): 58 raise ValueError("this light does not support dimming") 59 prev = self._state 60 self._intensity = intensity 61 if intensity == 0.0: 62 self._state = LightState.OFF 63 elif intensity == 1.0: 64 self._state = LightState.ON 65 else: 66 self._state = LightState.INTERMEDIATE 67 await self.state_changed.emit(LightChange(prev, self._state, intensity)) 68 69 70class LightManager(Manager[Light]): 71 type_letter = "L" 72 73 def _create(self, system_name: str) -> Light: 74 return Light(system_name)
@dataclass(frozen=True, slots=True)
class
LightChange:
17@dataclass(frozen=True, slots=True) 18class LightChange: 19 previous_state: LightState 20 current_state: LightState 21 intensity: float
LightChange( previous_state: jmri_core.state.LightState, current_state: jmri_core.state.LightState, intensity: float)
previous_state: jmri_core.state.LightState
current_state: jmri_core.state.LightState
24class Light(AbstractNamedBean): 25 """Layout light. Supports binary or dimmable control.""" 26 27 __slots__ = ("_intensity", "_state", "supports_dimming") 28 29 type_letter = "L" 30 31 def __init__(self, system_name: str, user_name: str | None = None) -> None: 32 super().__init__(system_name, user_name) 33 self._state: LightState = LightState.UNKNOWN 34 self._intensity: float = 0.0 35 self.supports_dimming: bool = False 36 37 @property 38 def state(self) -> LightState: 39 return self._state 40 41 @property 42 def intensity(self) -> float: 43 return self._intensity 44 45 async def set_state(self, state: LightState) -> None: 46 prev = self._state 47 if state == LightState.ON: 48 self._intensity = 1.0 49 elif state == LightState.OFF: 50 self._intensity = 0.0 51 self._state = state 52 if prev != state: 53 await self.state_changed.emit(LightChange(prev, state, self._intensity)) 54 55 async def set_intensity(self, intensity: float) -> None: 56 if not 0.0 <= intensity <= 1.0: 57 raise ValueError(f"intensity must be in [0,1], got {intensity}") 58 if not self.supports_dimming and intensity not in (0.0, 1.0): 59 raise ValueError("this light does not support dimming") 60 prev = self._state 61 self._intensity = intensity 62 if intensity == 0.0: 63 self._state = LightState.OFF 64 elif intensity == 1.0: 65 self._state = LightState.ON 66 else: 67 self._state = LightState.INTERMEDIATE 68 await self.state_changed.emit(LightChange(prev, self._state, intensity))
Layout light. Supports binary or dimmable control.
state: jmri_core.state.LightState
45 async def set_state(self, state: LightState) -> None: 46 prev = self._state 47 if state == LightState.ON: 48 self._intensity = 1.0 49 elif state == LightState.OFF: 50 self._intensity = 0.0 51 self._state = state 52 if prev != state: 53 await self.state_changed.emit(LightChange(prev, state, self._intensity))
async def
set_intensity(self, intensity: float) -> None:
55 async def set_intensity(self, intensity: float) -> None: 56 if not 0.0 <= intensity <= 1.0: 57 raise ValueError(f"intensity must be in [0,1], got {intensity}") 58 if not self.supports_dimming and intensity not in (0.0, 1.0): 59 raise ValueError("this light does not support dimming") 60 prev = self._state 61 self._intensity = intensity 62 if intensity == 0.0: 63 self._state = LightState.OFF 64 elif intensity == 1.0: 65 self._state = LightState.ON 66 else: 67 self._state = LightState.INTERMEDIATE 68 await self.state_changed.emit(LightChange(prev, self._state, intensity))
Inherited Members
71class LightManager(Manager[Light]): 72 type_letter = "L" 73 74 def _create(self, system_name: str) -> Light: 75 return Light(system_name)
Per-type bean registry. Subclass and override _create().
Attributes set on the class describe the bean type:
type_letter— single uppercase letter the bean class owns (e.g."T"for Turnout). Must be set by subclass.system_prefix— connection prefix (e.g."L"). Set per-instance because one bean class can have many connection-specific managers.