Class BabelControlableLedChainDemo

java.lang.Object
pt.unl.fct.di.novasys.babel.core.GenericProtocol
pt.unl.fct.di.tardis.babel.iot.demos.BabelControlableLedChainDemo
All Implemented Interfaces:
BabelDemo

public class BabelControlableLedChainDemo extends pt.unl.fct.di.novasys.babel.core.GenericProtocol implements BabelDemo
Flagship multi-device demo — command-line name 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 a GestureNotification for 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 RegisterIoTDeviceRequest per 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 GestureNotification and arm it with a GetReactiveGestureRequest so 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

    Fields
    Modifier and Type
    Field
    Description
    static final String
     
    static final String
     
    static final String
    Config key for the GPIO line the chainable RGB strip's clock pin sits on.
    static final String
    Default GPIO line for the strip (BCM 24 clock + BCM 25 data).
    static final String
     
    static final String
     

    Fields inherited from class pt.unl.fct.di.novasys.babel.core.GenericProtocol

    babel, babelSecurity

    Fields inherited from interface pt.unl.fct.di.tardis.babel.iot.demos.BabelDemo

    PROTO_ID, PROTO_NAME
  • Constructor Summary

    Constructors
    Constructor
    Description
    Constructs the demo as a Babel GenericProtocol under the shared demo identity (BabelDemo.PROTO_NAME / BabelDemo.PROTO_ID).
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Bootstraps the demo's Babel runtime — the entry point Main calls.
    void
    One-shot screen-clear timer handler (Babel timer).
    void
    handleDemoTimer(DemoTimer t, long time)
    Animation tick handler (Babel timer).
    void
    handleGestureInputReply(pt.unl.fct.di.tardis.babel.iot.controlprotocols.replies.GestureInputReply rep, short protocolId)
    Acknowledgement reply for the GetReactiveGestureRequest that armed gesture detection.
    void
    handleRegisterIoTDeviceReply(pt.unl.fct.di.tardis.babel.iot.api.replies.RegisterIoTDeviceReply rep, short protocolId)
    Handler for RegisterIoTDeviceReply — the one place where the four device registrations get sorted out.
    void
    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

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

  • Constructor Details

    • BabelControlableLedChainDemo

      public BabelControlableLedChainDemo()
      Constructs the demo as a Babel GenericProtocol under the shared demo identity (BabelDemo.PROTO_NAME / BabelDemo.PROTO_ID). No handlers or hardware here — that all happens in init(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:
      1. 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.
      2. Then fire one RegisterIoTDeviceRequest per device. Each is addressed to the control protocol that owns its device type and carries a distinct alias; the matching RegisterIoTDeviceReplys come back asynchronously and are sorted out in handleRegisterIoTDeviceReply(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 the rgb.led.count config key.

      Specified by:
      init in class pt.unl.fct.di.novasys.babel.core.GenericProtocol
      Throws:
      pt.unl.fct.di.novasys.babel.exceptions.HandlerRegistrationException
      IOException
    • handleClearScreenTimer

      public void handleClearScreenTimer(ClearScreenTimer t, long time)
      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 the lastScreenUpdate value 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

      public void handleDemoTimer(DemoTimer t, long time)
      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 via updateLedsColors(), and re-arms itself at the current refreshRate. 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 for RegisterIoTDeviceReply — 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 each DeviceHandle in 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 the GetReactiveGestureRequest that armed gesture detection. On success there is nothing to do — the events will now flow to handleGestureNotification(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

      public void execute() throws Exception
      Bootstraps the demo's Babel runtime — the entry point Main calls. 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 Babel singleton, load config, register every protocol, then init each one (the control protocols set up their request handlers; this demo's init fires the registration requests), and finally Babel.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.

      Specified by:
      execute in interface BabelDemo
      Throws:
      Exception