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
class OBlock(jmri_core.bean.AbstractNamedBean):
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
type_letter = 'B'
value: str | None
sensor_name: str | None
warrant_name: str | None
train_name: str | None
status: int
54    @property
55    def status(self) -> int:
56        return self._status
async def set_status(self, status: int) -> None:
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)
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.
type_letter = 'B'