The example below (adapted from src/test/java/.../MqttTestMain.java) wires up a Digital Twin that
generates test signals and streams all of it to PlotJuggler over MQTT, using a base topic and one
dedicated topic per property/event:
public class MqttExample {
private static final String STATE_CHANNEL = "dt-state";
public static void main(String[] args) throws Exception {
// 1. A Digital Twin needs a ShadowingFunction to mirror Physical Adapter data into its state
DigitalTwin digitalTwin = new DigitalTwin("plotjuggler-mqtt-digital-twin", new DefaultShadowingFunction());
// 2. Attach any Physical Adapter - here, the test fixture that generates sine/cosine x/y/z
// properties plus rotating "message"/"alarm" events (src/test/.../utils/SignalGeneratorPhysicalAdapter.java)
digitalTwin.addPhysicalAdapter(
new SignalGeneratorPhysicalAdapter("test-pa", new SignalGeneratorPhysicalAdapterConfiguration(200, 1000, 0.1))
);
// 3. Configure the MQTT connection: broker target, plus an optional topic prefix
MqttConnectionConfiguration mqttConnectionConfiguration = new MqttConnectionConfiguration("127.0.0.1", 1883);
mqttConnectionConfiguration.setBaseTopic("test/wldt-da");
// 4. Build the adapter configuration: JSON format, one whole-state channel, one channel per
// property/event - each becomes its own MQTT topic under "test/wldt-da/..."
PlotJugglerDigitalAdapterConfiguration configuration = PlotJugglerDigitalAdapterConfiguration
.builder(mqttConnectionConfiguration, PlotJugglerMessageFormat.JSON)
.withStateChannel(STATE_CHANNEL)
.addPropertyChannel(SignalGeneratorPhysicalAdapter.X_PROPERTY_KEY, "x")
.addPropertyChannel(SignalGeneratorPhysicalAdapter.Y_PROPERTY_KEY, "y")
.addPropertyChannel(SignalGeneratorPhysicalAdapter.Z_PROPERTY_KEY, "z")
.addEventChannel(SignalGeneratorPhysicalAdapter.MESSAGE_EVENT_KEY, "event_message")
.addEventChannel(SignalGeneratorPhysicalAdapter.ALARM_EVENT_KEY, "event_alarm")
.build();
// 5. Attach the PlotJuggler Digital Adapter and start everything
digitalTwin.addDigitalAdapter(new PlotJugglerDigitalAdapter("plotjuggler-mqtt-da", configuration));
DigitalTwinEngine digitalTwinEngine = new DigitalTwinEngine();
digitalTwinEngine.addDigitalTwin(digitalTwin);
digitalTwinEngine.startAll();
}
}There are no automated tests in this project: every connection is meant to be exercised by hand
against real, already running infrastructure (a real PlotJuggler instance for UDP/WebSocket, a real
external MQTT broker for MQTT). src/test/java/.../it/wldt/adapter/plotjuggler/digital/ contains
ready-to-run entry points, all sharing the same SignalGeneratorPhysicalAdapter/DefaultShadowingFunction
test fixtures and each exercising a different scenario:
MqttTestMain- MQTT, default target127.0.0.1:1883, override with-Dmqtt.broker.host=... -Dmqtt.broker.port=.... UsesbaseTopic/isSingleTopicto demonstrate the topic-layout options (see protocols.md).UdpTestMain- UDP, default target127.0.0.1:9870, override with-Dplotjuggler.udp.host=... -Dplotjuggler.udp.port=.... Has the other formats (BSON/CBOR/MessagePack) left commented next to the active JSON one, as a quick reference for swapping formats.UdpCustomFunctionTestMain- same UDP target/overrides asUdpTestMain, but demonstrates custom event payload functions (see channels.md): the "message"/"alarm" events are mapped to plain integers (a message-list index, and0/1) instead of forwarded as-is, since PlotJuggler plots numeric series and a raw string/boolean value isn't directly plottable.WebSocketTestMain- WebSocket, default target127.0.0.1:9871, override with-Dplotjuggler.websocket.host=... -Dplotjuggler.websocket.port=....
Each is a plain class with a main(String[] args): run it directly from your IDE (passing any -D...
overrides as VM options), then watch the data arrive live in PlotJuggler (or with an external tool such as
mosquitto_sub for the MQTT case) to confirm end-to-end delivery.