Sensors & Real-Time Data Bus
BloomSpark includes a high-performance, real-time data bus and pre-built sensor rendering overlays designed to display environmental and telemetry streams without impacting UI performance.
📡 The Real-Time Data Bus (F22)
The DataBus is a unified network wrapper supporting four standard ingestion protocols:
export interface DataBusConfig {
/** Ingestion transport selection. */
protocol: 'mqtt' | 'websocket' | 'sse' | 'rest-poll';
/** Server gateway endpoint URL. */
endpoint: string;
/** Polling frequency in milliseconds (only for REST poll). Default is 5000. */
pollInterval?: number;
/** Topic or channel paths to subscribe to. */
topics: string[];
}Backpressure Ring Buffer & RAF Batching
Environmental sensor streams can generate high packet volumes. To prevent main-thread blockages, the Data Bus implements a performance shield:
- Worker-Level Ingestion: Sockets are established and managed inside the Comlink Web Worker.
- Ring Buffer Caching: Incoming telemetry frames are queued in a high-capacity, circular Ring Buffer.
- rAF Batching: During each browser
requestAnimationFramecycle (every 16ms), the main thread requests only the latest state frame from the buffer, discarding intermediate telemetry spikes. - Imperative State Injection: Updates are injected directly into the MapLibre canvas using
map.setFeatureState(), avoiding costly React re-renders.
🌡️ Pre-Built Sensor Layers (F9)
The SDK provides declarative layers for common IoT building sensors:
import { SensorLayer } from '@bloomsparkagency/core';
export function BuildingIoT() {
return (
<>
{/* Dynamic temperature layer rendered as color-changing spheres */}
<SensorLayer
kind="temperature"
data={liveTelemetry} // Array of { id, position: { levelIndex, x, z }, value }
unit="celsius"
tooltipTemplate="Room {{ id }} is currently {{ formatNumber value fractionDigits=1 }}°C"
/>
</>
);
}Supported sensor kinds:
temperaturehumidityco2voc(Volatile Organic Compounds)pressurepeopleCounter
📝 Handlebars Tooltip Templates
Custom labels and popup boxes are rendered using a built-in, secure subset of Handlebars compiled in the background:
| Helper Name | Parameters | Usage / Description |
|---|---|---|
fallback | value, default | Returns the fallback if the primary variable is missing: {{ fallback temp "N/A" }} |
formatDate | value, format | Parses epoch numbers and formats dates: {{ formatDate ts "YYYY-MM-DD" }} |
formatNumber | value, fractionDigits | Formats floats: {{ formatNumber value fractionDigits=2 }} |
ifEquals | val1, val2 | Conditional block helper evaluating equality. |
json | value | Serializes objects to strings for debugging: {{ json meta }} |
📊 <PopularTimesChart> (F21)
This component aggregates people-counter sensor data to render a Google-style "Popular Times" bar chart, helping teams analyze spatial utilization patterns:
import { PopularTimesChart } from '@bloomsparkagency/ui';
export function AnalyticsPanel() {
return (
<PopularTimesChart
zoneId="meeting-room-hq-42"
window="last-90d" // 'last-30d' | 'last-90d' | 'all-time'
granularity="hour-of-week" // Summarizes peaks per hour across days (168 columns)
style={{ height: 200 }}
/>
);
}Data is pulled directly from the timeseries telemetry logs (persisted using the TimescaleDB hypertable schema, see BACKEND_GUIDE), and parsed inside the Wayfinding/Search Web Worker.
