Class BabelControlableLedChainDemo
- All Implemented Interfaces:
BabelDemo
lightControl.
This is the in-repo proof that one Babel application protocol can
drive several Grove devices and react to live sensor input at the
same time — exactly the shape of the StoneFlux edge gateway. A single
GenericProtocol (this class) wires four devices together so the user
controls an RGB light strip with hand gestures and sees feedback on a matrix
and an LCD:
- chainable RGB LED strip — output, via
DigitalOutputControlProtocol(id 2300). The lights to control. - gesture detector — input, via
I2CInputControlProtocol(id 2100). Emits aGestureNotificationfor each hand swipe; this is the reactive control surface. - LED matrix — output, via
I2COutputControlProtocol(id 2000). Shows an arrow/icon acknowledging each gesture. - 16x2 LCD — output, also via
I2COutputControlProtocol(id 2000). Prints a human-readable status line.
The interaction: swipe UP to turn the lights on, DOWN
to turn them off, RIGHT to speed up the colour animation, and
LEFT to slow it down. While the lights are on, a periodic timer
(DemoTimer) shifts a rolling rainbow down the strip; a separate
one-shot timer (ClearScreenTimer) wipes the matrix shortly after each
gesture so the icon does not linger.
The Babel patterns this demonstrates (read the README sections "Pattern 1: driving a Grove device" and "Capabilities and limits" alongside this file):
- Registering multiple devices — one
RegisterIoTDeviceRequestper device, each carrying a distinct alias, sent to the control protocol that owns that device type. The replies arrive asynchronously and out of order, so the reply handler matches each one back to the right field by its alias. - Holding several
DeviceHandles — one opaque handle per device; every later action just references the handle. - Reactive input — subscribe to
GestureNotificationand arm it with aGetReactiveGestureRequestso the gesture protocol pushes events to us instead of us polling. - Timers — a periodic animation tick and a one-shot screen-clear.
- The
execute()bootstrap — instantiate and register every control protocol this demo needs (output digital, output I²C, input I²C) plus the demo itself, then start Babel.
The app never touches Pi4J or the GPIO/I²C buses directly. It only builds Babel requests and lets the control protocols do the hardware work. That indirection is the whole point: the same application code is hardware-, bus-, and Pi4J-context-agnostic.
Runs only on a Raspberry Pi with all four Grove devices wired (see the
README "Raspberry Pi OS setup" and the led.line = 24 wiring note).
Derived from work originally developed at NOVA FCT for the TaRDIS project; see this repository's README "Credits" section.
-
Nested Class Summary
Nested classes/interfaces inherited from class pt.unl.fct.di.novasys.babel.core.GenericProtocol
pt.unl.fct.di.novasys.babel.core.GenericProtocol.ProtocolMetricsBabelMetrics -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final Stringstatic final Stringstatic final StringConfig key for the GPIO line the chainable RGB strip's clock pin sits on.static final StringDefault GPIO line for the strip (BCM 24 clock + BCM 25 data).static final Stringstatic final StringFields inherited from class pt.unl.fct.di.novasys.babel.core.GenericProtocol
babel, babelSecurityFields inherited from interface pt.unl.fct.di.tardis.babel.iot.demos.BabelDemo
PROTO_ID, PROTO_NAME -
Constructor Summary
ConstructorsConstructorDescriptionConstructs the demo as a BabelGenericProtocolunder the shared demo identity (BabelDemo.PROTO_NAME/BabelDemo.PROTO_ID). -
Method Summary
Modifier and TypeMethodDescriptionvoidexecute()Bootstraps the demo's Babel runtime — the entry pointMaincalls.voidhandleClearScreenTimer(ClearScreenTimer t, long time) One-shot screen-clear timer handler (Babel timer).voidhandleDemoTimer(DemoTimer t, long time) Animation tick handler (Babel timer).voidhandleGestureInputReply(pt.unl.fct.di.tardis.babel.iot.controlprotocols.replies.GestureInputReply rep, short protocolId) Acknowledgement reply for theGetReactiveGestureRequestthat armed gesture detection.voidhandleRegisterIoTDeviceReply(pt.unl.fct.di.tardis.babel.iot.api.replies.RegisterIoTDeviceReply rep, short protocolId) Handler forRegisterIoTDeviceReply— the one place where the four device registrations get sorted out.voidinit(Properties props) Babel lifecycle hook, called once after the protocol is registered.Methods inherited from class pt.unl.fct.di.novasys.babel.core.GenericProtocol
addSecret, addSecret, addSecret, addSecret, cancelTimer, closeConnection, closeConnection, closeConnection, closeConnection, closeConnection, closeConnection, createChannel, createSecureChannel, createSecureChannel, createSecureChannel, createSecureChannelWithAliases, createSecureChannelWithAliases, createSecureChannelWithIdentities, createSecureChannelWithIdentities, createSecureChannelWithProtoIdentities, enableGenericMetrics, generateIdentity, generateIdentity, generateIdentity, generateIdentity, generateIdentity, generateIdentity, generateIdentity, generateSecret, generateSecret, generateSecret, generateSecret, generateSecretFromPassword, generateSecretFromPassword, generateSecretFromPassword, generateSecretFromPassword, getChannelOrThrow, getDefaultChannel, getDefaultProtoIdentity, getDefaultProtoIdentityCrypt, getDefaultProtoSecret, getMillisSinceBabelStart, getOrGenerateDefaultProtoIdentity, getProtoId, getProtoName, hasProtocolThreadStarted, openConnection, openConnection, openConnection, openConnection, registerChannelEventHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageHandler, registerMessageSerializer, registerMetric, registerReplyHandler, registerRequestHandler, registerSharedChannel, registerTimerHandler, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendMessage, sendReply, sendRequest, setDefaultChannel, setDefaultProtoIdentity, setDefaultProtoIdentity, setDefaultProtoSecret, setupPeriodicTimer, setupTimer, startEventThread, subscribeNotification, triggerNotification, unsubscribeNotification
-
Field Details
-
LED_PORT
Config key for the GPIO line the chainable RGB strip's clock pin sits on.- See Also:
-
LED_PORT_DEFAULT
Default GPIO line for the strip (BCM 24 clock + BCM 25 data). Deliberately not 26: line+1 = BCM 27 would clash with a seated LoRa HAT's M1 pin and fail withDevice or resource busy(see README wiring note).- See Also:
-
ledAlias
- See Also:
-
matrixAlias
- See Also:
-
lcdAlias
- See Also:
-
gestureAlias
- See Also:
-
-
Constructor Details
-
BabelControlableLedChainDemo
public BabelControlableLedChainDemo()Constructs the demo as a BabelGenericProtocolunder the shared demo identity (BabelDemo.PROTO_NAME/BabelDemo.PROTO_ID). No handlers or hardware here — that all happens ininit(Properties), which Babel calls once the protocol is registered. We only seed the colour RNG and set the initial state (not ready, lights off, 1 s tick).
-
-
Method Details
-
init
public void init(Properties props) throws pt.unl.fct.di.novasys.babel.exceptions.HandlerRegistrationException, IOException Babel lifecycle hook, called once after the protocol is registered. It does two things, in the order Babel's contract requires:- Wire up every handler first — two timer handlers (animation tick + screen clear), two reply handlers (the device-registration reply and the gesture-arming reply), and the gesture notification subscription. Registering before sending guarantees no reply can arrive before its handler exists.
- Then fire one
RegisterIoTDeviceRequestper device. Each is addressed to the control protocol that owns its device type and carries a distinct alias; the matchingRegisterIoTDeviceReplys come back asynchronously and are sorted out inhandleRegisterIoTDeviceReply(pt.unl.fct.di.tardis.babel.iot.api.replies.RegisterIoTDeviceReply, short).
Note the digital RGB strip registration also passes the GPIO line (
this.deviceLine); I²C devices (gesture, matrix, LCD) need no line. The strip length comes from thergb.led.countconfig key.- Specified by:
initin classpt.unl.fct.di.novasys.babel.core.GenericProtocol- Throws:
pt.unl.fct.di.novasys.babel.exceptions.HandlerRegistrationExceptionIOException
-
handleClearScreenTimer
One-shot screen-clear timer handler (Babel timer). Wipes the LED matrix a short while after a gesture icon was shown — but only if nothing newer has been drawn meanwhile. The timer carries thelastScreenUpdatevalue it was scheduled with; if that no longer matches the field, a later gesture already redrew the matrix and owns its own clear timer, so we do nothing. This timestamp guard is how overlapping clear timers avoid wiping a fresh icon. -
handleDemoTimer
Animation tick handler (Babel timer). Each fire shifts the rolling rainbow one position down the strip, generates a fresh colour at the head from a point on the colour wheel, pushes the new colours to the hardware viaupdateLedsColors(), and re-arms itself at the currentrefreshRate. Self-rescheduling (rather than a periodic timer) lets the LEFT/RIGHT gestures change the speed between ticks. Bails out early unless every device is registered (ready) and the lights are on (active). -
handleRegisterIoTDeviceReply
public void handleRegisterIoTDeviceReply(pt.unl.fct.di.tardis.babel.iot.api.replies.RegisterIoTDeviceReply rep, short protocolId) Handler forRegisterIoTDeviceReply— the one place where the four device registrations get sorted out. Because this demo registers several devices and all the replies share a single reply id, this handler is invoked once per device with the replies arriving in arbitrary order. It therefore dispatches on the device type/alias to stash eachDeviceHandlein the correct field, and double-checks the returned alias against the one we asked for (a defensive guard against a misrouted reply). Once all four handles are non-null the demo is fully wired, so it primes the displays and arms reactive gesture detection. A failed registration (missing hardware) aborts the process. -
handleGestureInputReply
public void handleGestureInputReply(pt.unl.fct.di.tardis.babel.iot.controlprotocols.replies.GestureInputReply rep, short protocolId) Acknowledgement reply for theGetReactiveGestureRequestthat armed gesture detection. On success there is nothing to do — the events will now flow tohandleGestureNotification(pt.unl.fct.di.tardis.babel.iot.controlprotocols.notifications.GestureNotification, short). On failure the demo surfaces the error on the matrix (red) and LCD so the bring-up problem is visible on the hardware itself. -
execute
Bootstraps the demo's Babel runtime — the entry pointMaincalls. Unlike the single-device demos, this one needs three control protocols, so it instantiates and registers all of them plus this demo:DigitalOutputControlProtocol(2300) — drives the RGB strip;I2COutputControlProtocol(2000) — drives the matrix and LCD;I2CInputControlProtocol(2100) — reads the gesture detector.
The steps are: get the
Babelsingleton, load config, register every protocol, theniniteach one (the control protocols set up their request handlers; this demo'sinitfires the registration requests), and finallyBabel.start()hands control to the event loop. No Pi4J or GPIO setup here — the control protocols obtain the shared context themselves; the demo only ever speaks Babel.
-