jmri_core.beans.oblock
OBlock — an occupancy block that participates in JMRI's Warrant
system.
Real OBlocks in JMRI Java hold Portals, Paths, and Warrants — they're
the graph substrate the Warrant engine drives trains through. That
whole subsystem is deferred with Panel Editor (Tier 1 #3). This bean
carries only the fields the JSON schema requires, so mobile clients
that probe oblock see valid shapes.
Wire shape (per jmri/server/json/oblock/oblock-server.json):
status— an integer bitfield JMRI uses for occupancy + allocation state. Enum lists valid combos (0/1/2/4/8/16/18/20/24/32/34/36/40/ 64/66/68/72/128/130/132/136); we default 0 (UNOCCUPIED) and let the caller drive it.value— string associated with whatever's in the block (idTag, reporter, or free text).sensor— name of the occupancy sensor.warrant— allocated warrant (a warrant is a train's reservation across a chain of oblocks). We store the name; the Warrant engine itself doesn't exist yet.train— train name from the warrant, mirrored so mobile clients don't have to cross-reference.
1"""``OBlock`` — an occupancy block that participates in JMRI's Warrant 2system. 3 4Real OBlocks in JMRI Java hold Portals, Paths, and Warrants — they're 5the graph substrate the Warrant engine drives trains through. That 6whole subsystem is deferred with Panel Editor (Tier 1 #3). This bean 7carries only the fields the JSON schema requires, so mobile clients 8that probe ``oblock`` see valid shapes. 9 10Wire shape (per ``jmri/server/json/oblock/oblock-server.json``): 11 12* ``status`` — an integer bitfield JMRI uses for occupancy + allocation 13 state. Enum lists valid combos (0/1/2/4/8/16/18/20/24/32/34/36/40/ 14 64/66/68/72/128/130/132/136); we default 0 (UNOCCUPIED) and let the 15 caller drive it. 16* ``value`` — string associated with whatever's in the block (idTag, 17 reporter, or free text). 18* ``sensor`` — name of the occupancy sensor. 19* ``warrant`` — allocated warrant (a warrant is a train's reservation 20 across a chain of oblocks). We store the name; the Warrant engine 21 itself doesn't exist yet. 22* ``train`` — train name from the warrant, mirrored so mobile clients 23 don't have to cross-reference. 24""" 25from __future__ import annotations 26 27from jmri_core.bean import AbstractNamedBean 28from jmri_core.manager import Manager 29 30OBLOCK_STATUS_UNOCCUPIED = 0 31OBLOCK_STATUS_OCCUPIED = 2 32 33 34class OBlock(AbstractNamedBean): 35 """One occupancy block. Round-trip only in this pass.""" 36 37 __slots__ = ( 38 "_status", "sensor_name", "train_name", "value", "warrant_name", 39 ) 40 41 type_letter = "B" 42 43 def __init__( 44 self, system_name: str, user_name: str | None = None, 45 ) -> None: 46 super().__init__(system_name, user_name) 47 self._status: int = OBLOCK_STATUS_UNOCCUPIED 48 self.value: str | None = None 49 self.sensor_name: str | None = None 50 self.warrant_name: str | None = None 51 self.train_name: str | None = None 52 53 @property 54 def status(self) -> int: 55 return self._status 56 57 async def set_status(self, status: int) -> None: 58 if self._status == status: 59 return 60 self._status = status 61 await self.state_changed.emit(self._status) 62 63 64class OBlockManager(Manager[OBlock]): 65 # JMRI uses ``OB``-prefixed system names; managers are constructed 66 # with prefix ``"O"`` + type letter ``"B"``. 67 type_letter = "B" 68 69 def _create(self, system_name: str) -> OBlock: 70 return OBlock(system_name)
OBLOCK_STATUS_UNOCCUPIED =
0
OBLOCK_STATUS_OCCUPIED =
2
35class OBlock(AbstractNamedBean): 36 """One occupancy block. Round-trip only in this pass.""" 37 38 __slots__ = ( 39 "_status", "sensor_name", "train_name", "value", "warrant_name", 40 ) 41 42 type_letter = "B" 43 44 def __init__( 45 self, system_name: str, user_name: str | None = None, 46 ) -> None: 47 super().__init__(system_name, user_name) 48 self._status: int = OBLOCK_STATUS_UNOCCUPIED 49 self.value: str | None = None 50 self.sensor_name: str | None = None 51 self.warrant_name: str | None = None 52 self.train_name: str | None = None 53 54 @property 55 def status(self) -> int: 56 return self._status 57 58 async def set_status(self, status: int) -> None: 59 if self._status == status: 60 return 61 self._status = status 62 await self.state_changed.emit(self._status)
One occupancy block. Round-trip only in this pass.
OBlock(system_name: str, user_name: str | None = None)
44 def __init__( 45 self, system_name: str, user_name: str | None = None, 46 ) -> None: 47 super().__init__(system_name, user_name) 48 self._status: int = OBLOCK_STATUS_UNOCCUPIED 49 self.value: str | None = None 50 self.sensor_name: str | None = None 51 self.warrant_name: str | None = None 52 self.train_name: str | None = None
Inherited Members
65class OBlockManager(Manager[OBlock]): 66 # JMRI uses ``OB``-prefixed system names; managers are constructed 67 # with prefix ``"O"`` + type letter ``"B"``. 68 type_letter = "B" 69 70 def _create(self, system_name: str) -> OBlock: 71 return OBlock(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.