jmri_core.beans.sensor
Sensor — a layout input (block detector, button, switch).
1"""``Sensor`` — a layout input (block detector, button, switch).""" 2from __future__ import annotations 3 4from dataclasses import dataclass 5 6from jmri_core.bean import AbstractNamedBean 7from jmri_core.manager import Manager 8from jmri_core.state import SensorState 9 10 11@dataclass(frozen=True, slots=True) 12class SensorStateChange: 13 previous: SensorState 14 current: SensorState 15 16 17class Sensor(AbstractNamedBean): 18 """Generic layout input. Drivers call :meth:`_set_known_state` on receipt. 19 20 Sensors are write-only from the layout's perspective — the application 21 doesn't *command* them, only observes. The ``inverted`` flag flips the 22 semantic meaning of the raw hardware bit. 23 """ 24 25 __slots__ = ("_known_state", "inverted") 26 27 type_letter = "S" 28 29 def __init__(self, system_name: str, user_name: str | None = None) -> None: 30 super().__init__(system_name, user_name) 31 self._known_state: SensorState = SensorState.UNKNOWN 32 self.inverted: bool = False 33 34 @property 35 def known_state(self) -> SensorState: 36 return self._known_state 37 38 async def _set_known_state(self, state: SensorState) -> None: 39 prev = self._known_state 40 if prev == state: 41 return 42 self._known_state = state 43 await self.state_changed.emit(SensorStateChange(prev, state)) 44 45 @property 46 def is_active(self) -> bool: 47 return self._known_state == SensorState.ACTIVE 48 49 50class SensorManager(Manager[Sensor]): 51 type_letter = "S" 52 53 def _create(self, system_name: str) -> Sensor: 54 return Sensor(system_name)
@dataclass(frozen=True, slots=True)
class
SensorStateChange:
12@dataclass(frozen=True, slots=True) 13class SensorStateChange: 14 previous: SensorState 15 current: SensorState
SensorStateChange( previous: jmri_core.state.SensorState, current: jmri_core.state.SensorState)
previous: jmri_core.state.SensorState
current: jmri_core.state.SensorState
18class Sensor(AbstractNamedBean): 19 """Generic layout input. Drivers call :meth:`_set_known_state` on receipt. 20 21 Sensors are write-only from the layout's perspective — the application 22 doesn't *command* them, only observes. The ``inverted`` flag flips the 23 semantic meaning of the raw hardware bit. 24 """ 25 26 __slots__ = ("_known_state", "inverted") 27 28 type_letter = "S" 29 30 def __init__(self, system_name: str, user_name: str | None = None) -> None: 31 super().__init__(system_name, user_name) 32 self._known_state: SensorState = SensorState.UNKNOWN 33 self.inverted: bool = False 34 35 @property 36 def known_state(self) -> SensorState: 37 return self._known_state 38 39 async def _set_known_state(self, state: SensorState) -> None: 40 prev = self._known_state 41 if prev == state: 42 return 43 self._known_state = state 44 await self.state_changed.emit(SensorStateChange(prev, state)) 45 46 @property 47 def is_active(self) -> bool: 48 return self._known_state == SensorState.ACTIVE
Generic layout input. Drivers call _set_known_state() on receipt.
Sensors are write-only from the layout's perspective — the application
doesn't command them, only observes. The inverted flag flips the
semantic meaning of the raw hardware bit.
known_state: jmri_core.state.SensorState
Inherited Members
51class SensorManager(Manager[Sensor]): 52 type_letter = "S" 53 54 def _create(self, system_name: str) -> Sensor: 55 return Sensor(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.