Files
2026-06-26 10:29:23 +02:00

11 KiB

adas-core.module.LightBeacons — Light Beacon Module

A functional module of the ADAS Core platform. Encapsulates all logic for managing, controlling, and monitoring light beacon devices deployed at Points of Care. This module operates as an independent satellite that the Host registers at startup, maintaining full separation from unrelated domain concerns.


Table of Contents

  1. Overview
  2. Responsibilities
  3. Project Structure
  4. Dependencies
  5. Device Abstraction
  6. Beacon Control Flow
  7. LightBeaconService Orchestration
  8. Design Rules

Overview

adas-core.module.LightBeacons is a modular satellite project that encapsulates every concern related to light beacon hardware within the ADAS Core ecosystem. It is responsible for discovering beacon configurations, translating clinical observation statuses into color commands, dispatching those commands to physical devices, and broadcasting state changes to connected subscribers.

Key characteristics:

  • Modular Monolith Pattern — Operates as a self-contained module with its own device drivers, service logic, and repository interactions. No other module depends on it.
  • Polymorphic Devices — Supports multiple beacon hardware models via an abstract LightBeacon base class. New models are added by inheriting from the base and registering the type string in LightBeaconService.
  • State Caching — Maintains an in-memory ConcurrentDictionary of current beacon colors per Point-of-Care to avoid redundant commands.
  • Subscriber Broadcasting — Pushes beacon color changes to WebSocket / SignalR subscribers via IClientMessageService.
  • HTTP-Based Drivers — Current concrete implementation (Turktbens2LightBeacon) communicates over HTTP, parses HTML status pages, and sends form-encoded commands.

Responsibilities

Concern What this project does
Device Abstraction Defines LightBeacon and LightBeaconAbstract base classes that every beacon driver implements.
Hardware Control Sends color commands (red, blue, yellow, off) to physical beacon devices over the network.
Status Retrieval Reads the current color state from a beacon by scraping its web interface or calling its API.
Color Alert Generation Translates PatientObservation status (Warning / Alert) into the configured beacon color.
Configuration CRUD Manages beacon device configurations (name, URL, port, password, type) through ILightBeaconRepository.
Association Management Links beacons to Points of Care via Configuration.BeaconIdList.
State Caching Tracks per-PoC color in memory to suppress duplicate commands.
Subscriber Broadcast Notifies all subscribers of a PoC when the beacon color changes via BeaconResponse.
Retry Logic Implements exponential-backoff retry for transient network failures when sending commands.
Audit Logging Emits audit events for beacon state changes and configuration mutations.

Project Structure

adas-core.module.LightBeacons/
├── Devices/
│   ├── LightBeacon.cs              # Abstract base class for all beacon drivers
│   ├── LightBeaconAbstract.cs      # Legacy abstract base with static factory
│   └── Turktbens2LightBeacon.cs    # Concrete HTTP-based driver for TURKTBENS2
│
└── Services/
    └── LightBeaconService.cs       # Orchestrates beacon control, caching, and broadcasting
File Role
LightBeacon.cs Abstract base defining BlueCode(), RedCode(), YellowCode(), PowerOffLed(), GetBeaconColor(), and GenerateColorAlert().
LightBeaconAbstract.cs Older abstraction with Host/Password fields and reflection-based static factory GetBeaconDevice().
Turktbens2LightBeacon.cs HTTP driver: parses HTML status pages, sends form-encoded commands, retry with exponential backoff, emulation mode.
LightBeaconService.cs Service implementing ILightBeaconService. Mediates between Application-layer commands and physical devices.

Dependencies

Downstream References

Project Role
adas-core.Application Consumes ILightBeaconRepository, IPointOfCareService, ISubscribersService, IClientMessageService, and ILightBeaconService interface.
adas-core.Domain Uses LightBeaconColor, PatientObservation, StatusEnum, PointOfCare, BeaconResponse, OperationType, EquatableDictionary, and domain exceptions.

Upstream References (projects that depend on this)

Project Reason
adas-core (Host) Registers the module at startup. Host controllers invoke ILightBeaconService endpoints.
adas-core.Infrastructure LightBeaconRepository (in Infrastructure) implements ILightBeaconRepository defined in Application.

NuGet Packages

Package Version Purpose
HtmlAgilityPack 1.12.4 HTML DOM parsing for scraping beacon status pages.
AuditLogs 1.0.59 Audit tagging on beacon state transitions and configuration changes.

Device Abstraction

LightBeacon (Primary Async Abstraction)

The main device contract for all modern beacon drivers:

public abstract class LightBeacon(EquatableDictionary<string, object> options)
{
    public abstract Task BlueCode();
    public abstract Task RedCode();
    public abstract Task YellowCode();
    public abstract Task PowerOffLed();
    public abstract Task GenerateColorAlert(PatientObservation obs);
    public abstract Task<LightBeaconColor> GetBeaconColor();
}

Turktbens2LightBeacon (Concrete Driver)

  • Communication — HTTP POST to the beacon's embedded web server.
  • Status Reading — Scrapes /IO01_03.html and /IO12_03.html, parses checkbox states with HtmlAgilityPack.
  • Command Mapping — Converts LightBeaconColor to a 3-bit binary code sent as form fields.
  • Retry Policy — Exponential backoff (500 ms -> 1 s -> 2 s) with max 3 retries on network failures.
  • Emulation Mode — When emulate: true, skips HTTP calls and returns LightBeaconColor.Off for reads.
  • Port Selection — Supports multi-port beacons (ports 1-4) via _portMappings.

Beacon Control Flow

[PatientObservation Status Change] --> [LightBeaconService.GenerateColorAlert]
                                               |
                                               v
                                   [Map StatusEnum -> LightBeaconColor]
                                   [Warning -> WarnColor, Alert -> AlertColor]
                                               |
                                               v
                                   [GetBeacon(beaconId)]
                                   [Resolve device from config.Type]
                                               |
                                               v
                                   [SendColor(poc, color)]
                                   [Cache check: skip if unchanged]
                                               |
                                               v
                                   [Dispatch to physical device]
                                   [Turktbens2: HTTP POST with retry]
                                               |
                                               v
                                   [Update in-memory cache]
                                   [SendBeaconBroadcast -> subscribers]
                                               |
                                               v
                                   [Return / Log]

LightBeaconService Orchestration

Color Dispatch

Method Behavior
SendColor(pocId, color) Resolves PoC, retrieves associated beacons, dispatches color command, updates cache, broadcasts.
PowerOffLed(pocId) Sets all associated beacons to LightBeaconColor.Off, updates cache.
GetColor(pocId) Returns cached color or queries the physical beacon for current state.

Alert Generation

GenerateColorAlert(PatientObservation) converts:

  • StatusEnum.Type.Warning -> obs.WarnColor (e.g., "Yellow", "001")
  • StatusEnum.Type.Alert -> obs.AlertColor (e.g., "Red", "100")
  • Other -> LightBeaconColor.Off

The method builds an HTTP form body and sends it via SendMessage.

Broadcasting

SendBeaconBroadcast(poc, color):

  1. Queries ISubscribersService.GetSubscribers() filtered by LocationIds.
  2. Builds a BeaconResponse (color string, PoC ID, Unit ID).
  3. Sends to each subscriber via IClientMessageService.SendAsync(..., OperationType.Beacon, ...).

This drives real-time UI updates in client applications.

Configuration CRUD

Method Behavior
InsertOne(beacon) Validates uniqueness by name, inserts via repository.
UpdateOne(beacon) Updates record, returns refreshed entity.
GetPaginatedBeacons(filter) Paginated list with InUse flag computed from PointOfCare associations.
GetSearchByName(text) Partial-match search on beacon names.

State Caching

_locationsWithColor is a ConcurrentDictionary<ObjectId, LightBeaconColor> keyed by PoC ID:

  • Prevents redundant commands when the requested color matches the cached color.
  • Updated under lock() during writes to avoid race conditions.
  • Falls back to device query when the PoC is not in the cache.

Design Rules

  1. Module Independence — No project outside Infrastructure depends on this module. The Host registers it via assembly scan.
  2. Device Abstraction — All hardware-specific code is isolated in Devices/. LightBeaconService only sees the LightBeacon base type.
  3. No Blocking Calls — Modern drivers use async/await exclusively. Legacy LightBeaconAbstract remains synchronous but is deprecated.
  4. Cache Consistency — In-memory cache is always updated after a successful physical-device command, never before.
  5. Graceful Degradation — Network failures return LightBeaconColor.Off rather than crashing the observation pipeline.
  6. Retry Discipline — Exponential backoff capped at 3 attempts. Logs each retry attempt with Warning, final failure with Error.
  7. Audit Emission — Every InsertOne, UpdateOne, SendColor, and PowerOffLed emits an audit event.
  8. Configuration-Driven — Beacon URL, port, password, timeout, and emulation flag all come from LightBeacon.Options. No hardcoded device addresses.
  9. Factory Extensibility — Adding a new beacon model requires only: (a) inherit LightBeacon, (b) add a case in LightBeaconService.GetBeacon, (c) register in DI. No other code changes.
  10. Broadcast DecouplingIClientMessageService is an injected abstraction. Replacing SignalR with WebSockets or SSE requires no changes in this module.

Back to adas-core Root README