Skip to content

Latest commit

 

History

History
61 lines (47 loc) · 3.82 KB

File metadata and controls

61 lines (47 loc) · 3.82 KB

Channels

← Back to README

A channel is a logical, transport-agnostic named destination for one specific kind of Digital Twin data. Four channel types exist, one per kind of data:

Channel class Input to the payload function Sent... Default DTO (see dto package)
StateOutgoingChannel DigitalTwinState once per state-update cycle, if configured (at most one instance) DigitalTwinStatePropertiesDto { properties }
PropertyOutgoingChannel<T> DigitalTwinStateProperty<T> whenever the matching property key changes DigitalTwinStatePropertyDto { value }
RelationshipInstanceOutgoingChannel<T> DigitalTwinStateRelationshipInstance<T> whenever a relationship instance for the matching relationship name is created/removed DigitalTwinStateRelationshipInstanceDto { targetId, instanceKey, metadata }
EventOutgoingChannel<T> DigitalTwinStateEventNotification<T> whenever an event notification for the matching event key arrives DigitalTwinStateEventNotificationDto { body }

You never instantiate channel classes directly: PlotJugglerDigitalAdapterConfigurationBuilder does it for you via withStateChannel(...), addPropertyChannel(...), addRelationshipChannel(...) and addEventChannel(...).

Custom payload functions

Every add*Channel(...)/withStateChannel(...) builder method comes in two flavors:

  • a default overload (just a channel name, or a key + channel name) that forwards the lean, built-in DTO from the table above;
  • a custom overload taking an extra Function<InputType, Object> ("payload function"), letting you reshape the outgoing payload however you like before it's sent.
Channel Custom function signature
withStateChannel(name, fn) Function<DigitalTwinState, Object>
addPropertyChannel(key, name, fn) Function<DigitalTwinStateProperty<T>, Object>
addRelationshipChannel(key, name, fn) Function<DigitalTwinStateRelationshipInstance<T>, Object>
addEventChannel(key, name, fn) Function<DigitalTwinStateEventNotification<T>, Object>

This is especially useful when the raw value isn't directly plottable: PlotJuggler plots numeric time series, so an event carrying a string or an otherwise non-numeric value needs to be mapped to a number first. UdpCustomFunctionTestMain (src/test/java/.../UdpCustomFunctionTestMain.java) demonstrates exactly this, mapping the test fixture's rotating textual "message" event and boolean "alarm" event to plain integers before sending:

// "message" cycles through a fixed list of strings - map it to its index in that list
private static final List<String> MESSAGE_VALUES = Arrays.asList("nominal", "warming-up", "steady-state", "cooling-down");

private static final Function<DigitalTwinStateEventNotification<String>, Object> messageToIndexFunction =
        notification -> MESSAGE_VALUES.indexOf(notification.getBody());

// "alarm" is a boolean - map it to 1/0
private static final Function<DigitalTwinStateEventNotification<Boolean>, Object> alarmToIntFunction =
        notification -> notification.getBody() ? 1 : 0;

PlotJugglerDigitalAdapterConfiguration configuration = PlotJugglerDigitalAdapterConfiguration
        .builder(new UdpConnectionConfiguration(host, port), PlotJugglerMessageFormat.JSON)
        .addEventChannel(SignalGeneratorPhysicalAdapter.MESSAGE_EVENT_KEY, "event_message", messageToIndexFunction)
        .addEventChannel(SignalGeneratorPhysicalAdapter.ALARM_EVENT_KEY, "event_alarm", alarmToIntFunction)
        .build();

The same pattern applies to properties, relationships and the whole-state channel: a payload function can extract a single field, combine multiple values, look up an enum's ordinal, or return any other Object - whatever ends up plottable (or otherwise useful) once it reaches PlotJuggler.