This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new 03de78e2e4 feat: Extend capabilities of machine data simulator (#4013)
03de78e2e4 is described below
commit 03de78e2e4a14bfe4ca1f7771482bb0adde9c430
Author: Dominik Riemer <[email protected]>
AuthorDate: Wed Dec 3 09:39:09 2025 +0100
feat: Extend capabilities of machine data simulator (#4013)
---
.../go-client-e2e/adapter/machine.json | 25 +-
.../iiot/IIoTAdaptersExtensionModuleExport.java | 5 +-
.../simulator/machine/MachineDataSimulator.java | 121 ++-----
.../machine/MachineDataSimulatorAdapter.java | 23 +-
.../machine/MachineDataSimulatorUtils.java | 157 ++-------
.../machine/event/DiagnosticSimulator.java | 371 +++++++++++++++++++++
.../simulator/machine/event/EventSimulator.java | 31 ++
.../FlowSimulator.java} | 102 ++----
.../simulator/machine/event/PressureSimulator.java | 80 +++++
.../machine/event/SensorValueSimulator.java | 26 ++
.../machine/event/WaterlevelSimulator.java | 88 +++++
.../migration/MachineDataSimulatorMigrationV1.java | 56 ++++
.../documentation.md | 32 --
.../icon.png | Bin 12881 -> 0 bytes
.../strings.en | 44 ---
.../documentation.md | 34 --
.../icon.png | Bin 31009 -> 0 bytes
.../strings.en | 26 --
.../strings.en | 5 +-
19 files changed, 771 insertions(+), 455 deletions(-)
diff --git a/streampipes-client-e2e/go-client-e2e/adapter/machine.json
b/streampipes-client-e2e/go-client-e2e/adapter/machine.json
index d50a60be01..e532bd837e 100644
--- a/streampipes-client-e2e/go-client-e2e/adapter/machine.json
+++ b/streampipes-client-e2e/go-client-e2e/adapter/machine.json
@@ -39,6 +39,23 @@
"value": "1000",
"valueSpecification": null
},
+ {
+ "@class":
"org.apache.streampipes.model.staticproperty.FreeTextStaticProperty",
+ "description": "The number of sensors to simulate",
+ "internalName": "numberOfSensors",
+ "label": "Number of sensors",
+ "optional": false,
+ "staticPropertyType": "FreeTextStaticProperty",
+ "htmlAllowed": false,
+ "htmlFontFormat": false,
+ "mapsTo": null,
+ "multiLine": false,
+ "placeholdersSupported": false,
+ "requiredDatatype": "http://www.w3.org/2001/XMLSchema#integer",
+ "requiredDomainProperty": null,
+ "value": "1",
+ "valueSpecification": null
+ },
{
"@class":
"org.apache.streampipes.model.staticproperty.OneOfStaticProperty",
"description": "Select simulated sensor data to be published",
@@ -65,6 +82,12 @@
"internalName": null,
"name": "waterlevel",
"selected": false
+ },
+ {
+ "elementId": "sp:option:VWXqSG",
+ "internalName": null,
+ "name": "diagnostics",
+ "selected": false
}
]
}
@@ -222,4 +245,4 @@
"selectedEndpointUrl": null,
"streamRules": [],
"valueRules": []
-}
\ No newline at end of file
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/IIoTAdaptersExtensionModuleExport.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/IIoTAdaptersExtensionModuleExport.java
index 5c9dbf874c..4fbdc74ead 100644
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/IIoTAdaptersExtensionModuleExport.java
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/IIoTAdaptersExtensionModuleExport.java
@@ -21,6 +21,7 @@ package org.apache.streampipes.connect.iiot;
import org.apache.streampipes.connect.iiot.adapters.oi4.Oi4Adapter;
import
org.apache.streampipes.connect.iiot.adapters.oi4.migration.Oi4AdapterMigrationV1;
import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorAdapter;
+import
org.apache.streampipes.connect.iiot.migration.MachineDataSimulatorMigrationV1;
import org.apache.streampipes.connect.iiot.protocol.stream.FileReplayAdapter;
import org.apache.streampipes.connect.iiot.protocol.stream.HttpServerProtocol;
import org.apache.streampipes.connect.iiot.protocol.stream.HttpStreamProtocol;
@@ -51,6 +52,8 @@ public class IIoTAdaptersExtensionModuleExport implements
IExtensionModuleExport
@Override
public List<IModelMigrator<?, ?>> migrators() {
- return List.of(new Oi4AdapterMigrationV1());
+ return List.of(
+ new Oi4AdapterMigrationV1(),
+ new MachineDataSimulatorMigrationV1());
}
}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulator.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulator.java
index ce2a914349..59d200efd8 100644
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulator.java
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulator.java
@@ -17,14 +17,12 @@
*/
package org.apache.streampipes.connect.iiot.adapters.simulator.machine;
-import org.apache.streampipes.commons.exceptions.connect.AdapterException;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.EventSimulator;
import org.apache.streampipes.extensions.api.connect.IEventCollector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.TimeUnit;
public class MachineDataSimulator implements Runnable {
@@ -32,19 +30,22 @@ public class MachineDataSimulator implements Runnable {
private final IEventCollector collector;
private final Integer waitTimeMs;
- private final String selectedSimulatorOption;
+ private final Integer numberOfSensors;
+ private final EventSimulator simulator;
private Boolean running;
private static final Logger LOG =
LoggerFactory.getLogger(MachineDataSimulator.class);
- public MachineDataSimulator(IEventCollector collector,
+ public MachineDataSimulator(EventSimulator simulator,
+ IEventCollector collector,
Integer waitTimeMs,
- String selectedSimulatorOption) {
+ int numberOfSensors) {
+ this.simulator = simulator;
this.collector = collector;
this.waitTimeMs = waitTimeMs;
- this.selectedSimulatorOption = selectedSimulatorOption;
this.running = true;
+ this.numberOfSensors = numberOfSensors;
}
@Override
@@ -53,108 +54,42 @@ public class MachineDataSimulator implements Runnable {
long startTimeMs = System.currentTimeMillis();
while (running) {
- Map<String, Object> event = new HashMap<>();
long currentTimeMs = System.currentTimeMillis();
long timeDeltaMs = currentTimeMs - startTimeMs;
- switch (this.selectedSimulatorOption) {
- case "flowrate":
- // 0 - 30s
- if (timeDeltaMs > 0 && timeDeltaMs <= 30000) {
- event = buildFlowrateEvent(0);
- } else if (timeDeltaMs > 30000 && timeDeltaMs <= 60000) {
- // 30s - 60s
- event = buildFlowrateEvent(1);
- } else {
- // > 60s
- // reset start time to start over again
- startTimeMs = currentTimeMs;
- }
- break;
- case "pressure":
- // 0 - 30s
- if (timeDeltaMs > 0 && timeDeltaMs <= 30000) {
- event = buildPressureEvent(0);
- } else if (timeDeltaMs > 30000 && timeDeltaMs <= 60000) {
- // 30s - 60s
- event = buildPressureEvent(1);
- } else {
- // > 60s
- // reset start time to start over again
- startTimeMs = currentTimeMs;
- }
- break;
- case "waterlevel":
- if (timeDeltaMs > 0 && timeDeltaMs <= 30000) {
- // 0 - 30s
- event = buildWaterlevelEvent(0);
- } else if (timeDeltaMs > 30000 && timeDeltaMs <= 60000) {
- // 30s - 60s
- event = buildWaterlevelEvent(1);
- } else {
- // > 60s
- // reset start time to start over again
- startTimeMs = currentTimeMs;
- }
- break;
- default:
- try {
- throw new AdapterException("resource not found");
- } catch (AdapterException e) {
- throw new RuntimeException(e);
- }
+ Integer simulationPhase = null;
+
+ if (timeDeltaMs > 0 && timeDeltaMs <= 30000) {
+ simulationPhase = 0;
+ } else if (timeDeltaMs > 30000 && timeDeltaMs <= 60000) {
+ simulationPhase = 1;
+ } else {
+ startTimeMs = currentTimeMs; // reset
}
- if (!event.keySet().isEmpty()) {
- collector.collect(event);
+ if (simulationPhase != null) {
+ long timestamp = System.currentTimeMillis();
+
+ for (int sensorIndex = 1; sensorIndex <= numberOfSensors;
sensorIndex++) {
+ var event = simulator.buildEvent(simulationPhase, sensorIndex,
timestamp);
+
+ if (!event.isEmpty()) {
+ collector.collect(event);
+ }
+ }
}
try {
TimeUnit.MILLISECONDS.sleep(waitTimeMs);
} catch (InterruptedException e) {
LOG.error("Machine simulator thread interrupted", e);
+ Thread.currentThread().interrupt();
+ return;
}
}
}
- private Map<String, Object> buildFlowrateEvent(int simulationPhase) {
- Map<String, Object> event = new HashMap<>();
-
- event.put("timestamp", System.currentTimeMillis());
- event.put("sensorId", "flowrate02");
- event.put("mass_flow", randomDoubleBetween(0, 10));
- event.put("volume_flow", randomDoubleBetween(0, 10));
- event.put("temperature", simulationPhase == 0 ? randomDoubleBetween(40,
50) : randomDoubleBetween(80, 100));
- event.put("density", randomDoubleBetween(40, 50));
- event.put("sensor_fault_flags", simulationPhase != 0);
-
- return event;
- }
-
- private Map<String, Object> buildPressureEvent(int simulationPhase) {
- Map<String, Object> event = new HashMap<>();
-
- event.put("timestamp", System.currentTimeMillis());
- event.put("sensorId", "pressure01");
- event.put("pressure", simulationPhase == 0 ? randomDoubleBetween(10, 40) :
randomDoubleBetween(40, 70));
-
- return event;
- }
-
- private Map<String, Object> buildWaterlevelEvent(int simulationPhase) {
- Map<String, Object> event = new HashMap<>();
-
- event.put("timestamp", System.currentTimeMillis());
- event.put("sensorId", "level01");
- event.put("level", simulationPhase == 0 ? randomDoubleBetween(20, 30) :
randomDoubleBetween(60, 80));
- event.put("overflow", simulationPhase != 0);
- return event;
- }
-
- private double randomDoubleBetween(int min, int max) {
- return Math.random() * (max - min + 1) + min;
- }
public void setRunning(Boolean running) {
this.running = running;
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorAdapter.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorAdapter.java
index fe737e31e6..5440d19e86 100644
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorAdapter.java
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorAdapter.java
@@ -25,7 +25,6 @@ import
org.apache.streampipes.extensions.api.connect.StreamPipesAdapter;
import
org.apache.streampipes.extensions.api.connect.context.IAdapterGuessSchemaContext;
import
org.apache.streampipes.extensions.api.connect.context.IAdapterRuntimeContext;
import
org.apache.streampipes.extensions.api.extractor.IAdapterParameterExtractor;
-import org.apache.streampipes.model.AdapterType;
import org.apache.streampipes.model.connect.guess.GuessSchema;
import org.apache.streampipes.model.extensions.ExtensionAssetType;
import org.apache.streampipes.sdk.builder.adapter.AdapterConfigurationBuilder;
@@ -35,41 +34,45 @@ import org.apache.streampipes.sdk.helpers.Options;
public class MachineDataSimulatorAdapter implements StreamPipesAdapter {
- private static final String ID =
"org.apache.streampipes.connect.iiot.adapters.simulator.machine";
+ public static final String ID =
"org.apache.streampipes.connect.iiot.adapters.simulator.machine";
private static final String WAIT_TIME_MS = "wait-time-ms";
private static final String SELECTED_SIMULATOR_OPTION =
"selected-simulator-option";
+ public static final String NUMBER_OF_SENSORS = "numberOfSensors";
private MachineDataSimulator machineDataSimulator;
@Override
public IAdapterConfiguration declareConfig() {
- return AdapterConfigurationBuilder.create(ID, 0,
MachineDataSimulatorAdapter::new)
+ return AdapterConfigurationBuilder.create(ID, 1,
MachineDataSimulatorAdapter::new)
.withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
.withLocales(Locales.EN)
- .withCategory(AdapterType.Debugging)
.requiredIntegerParameter(Labels.withId(WAIT_TIME_MS), 1000)
+ .requiredIntegerParameter(Labels.withId(NUMBER_OF_SENSORS), 1)
.requiredSingleValueSelection(Labels.withId(SELECTED_SIMULATOR_OPTION),
Options.from(
- "flowrate", "pressure", "waterlevel"))
+ "flowrate", "pressure", "waterlevel", "diagnostics"))
.buildConfiguration();
}
@Override
public void onAdapterStarted(IAdapterParameterExtractor extractor,
IEventCollector collector,
- IAdapterRuntimeContext adapterRuntimeContext)
- throws AdapterException {
+ IAdapterRuntimeContext adapterRuntimeContext)
throws AdapterException {
var ex = extractor.getStaticPropertyExtractor();
var waitTimeMs = ex.singleValueParameter(WAIT_TIME_MS, Integer.class);
+ var numberOfSensors = ex.singleValueParameter(NUMBER_OF_SENSORS,
Integer.class);
var selectedSimulatorOption =
ex.selectedSingleValue(SELECTED_SIMULATOR_OPTION, String.class);
- this.machineDataSimulator = new MachineDataSimulator(collector,
waitTimeMs, selectedSimulatorOption);
+ var simulator =
MachineDataSimulatorUtils.getSimulator(selectedSimulatorOption);
+ this.machineDataSimulator = new MachineDataSimulator(
+ simulator, collector, waitTimeMs, numberOfSensors
+ );
Thread thread = new Thread(this.machineDataSimulator);
thread.start();
}
@Override
public void onAdapterStopped(IAdapterParameterExtractor extractor,
- IAdapterRuntimeContext adapterRuntimeContext)
throws AdapterException {
+ IAdapterRuntimeContext adapterRuntimeContext) {
this.machineDataSimulator.setRunning(false);
}
@@ -79,6 +82,6 @@ public class MachineDataSimulatorAdapter implements
StreamPipesAdapter {
IAdapterGuessSchemaContext
adapterGuessSchemaContext) throws AdapterException {
var ex = extractor.getStaticPropertyExtractor();
var selectedSimulatorOption =
ex.selectedSingleValue(SELECTED_SIMULATOR_OPTION, String.class);
- return MachineDataSimulatorUtils.getSchema(selectedSimulatorOption);
+ return
MachineDataSimulatorUtils.getSimulator(selectedSimulatorOption).getSchema();
}
}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
index 1a3a27865d..c795164102 100644
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
@@ -18,16 +18,12 @@
package org.apache.streampipes.connect.iiot.adapters.simulator.machine;
import org.apache.streampipes.commons.exceptions.connect.AdapterException;
-import org.apache.streampipes.model.connect.guess.GuessSchema;
-import org.apache.streampipes.model.schema.PropertyScope;
-import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
-import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
-import org.apache.streampipes.sdk.utils.Datatypes;
-import org.apache.streampipes.vocabulary.SO;
-
-import java.net.URI;
-
-import static
org.apache.streampipes.sdk.helpers.EpProperties.timestampProperty;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.DiagnosticSimulator;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.EventSimulator;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.FlowSimulator;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.PressureSimulator;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.SensorValueSimulator;
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.event.WaterlevelSimulator;
public class MachineDataSimulatorUtils {
@@ -35,133 +31,18 @@ public class MachineDataSimulatorUtils {
public static final String NS =
"https://streampipes.org/vocabulary/examples/watertank/v1/";
public static final String HAS_SENSOR_ID = NS + "hasSensorId";
- private static final String TIMESTAMP = "timestamp";
- private static final String SENSOR_ID = "sensorId";
- private static final String MASS_FLOW = "mass_flow";
- private static final String TEMPERATURE = "temperature";
-
- public static GuessSchema getSchema(String selectedSimulatorOption) throws
AdapterException {
- switch (selectedSimulatorOption) {
- case "flowrate":
- return getFlowrateSchema();
- case "pressure":
- return getPressureSchema();
- case "waterlevel":
- return getWaterlevelSchema();
- default:
- throw new AdapterException("resource not found");
- }
- }
-
- private static GuessSchema getWaterlevelSchema() {
- return GuessSchemaBuilder.create()
- .property(timestampProperty(TIMESTAMP))
- .sample(TIMESTAMP, System.currentTimeMillis())
- .property(PrimitivePropertyBuilder
- .create(Datatypes.String, SENSOR_ID)
- .label("Sensor ID")
- .description("The ID of the sensor")
- .semanticType(HAS_SENSOR_ID)
- .scope(PropertyScope.DIMENSION_PROPERTY)
- .build())
- .sample(SENSOR_ID, "sensor01")
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, "level")
- .label("Water Level")
- .description("Denotes the current water level in the container")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("level", 5.25f)
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Boolean, "overflow")
- .label("Overflow")
- .description("Indicates whether the tank overflows")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("overflow", true)
- .build();
- }
-
- private static GuessSchema getPressureSchema() {
- return GuessSchemaBuilder.create()
- .property(timestampProperty(TIMESTAMP))
- .sample(TIMESTAMP, System.currentTimeMillis())
- .property(PrimitivePropertyBuilder
- .create(Datatypes.String, SENSOR_ID)
- .label("Sensor ID")
- .description("The ID of the sensor")
- .semanticType(HAS_SENSOR_ID)
- .scope(PropertyScope.DIMENSION_PROPERTY)
- .build())
- .sample(SENSOR_ID, "sensor01")
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, "pressure")
- .label("Pressure")
- .description("Denotes the current pressure in the pressure tank")
- .semanticType(SO.NUMBER)
- .valueSpecification(0.0f, 100.0f, 0.5f)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("pressure", 85.22f)
- .build();
- }
-
- public static GuessSchema getFlowrateSchema() {
- return GuessSchemaBuilder.create()
- .property(timestampProperty(TIMESTAMP))
- .sample(TIMESTAMP, System.currentTimeMillis())
- .property(PrimitivePropertyBuilder
- .create(Datatypes.String, SENSOR_ID)
- .label("Sensor ID")
- .description("The ID of the sensor")
- .semanticType(HAS_SENSOR_ID)
- .scope(PropertyScope.DIMENSION_PROPERTY)
- .build())
- .sample(SENSOR_ID, "sensor01")
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, MASS_FLOW)
- .label("Mass Flow")
- .description("Denotes the current mass flow in the sensor")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample(MASS_FLOW, 5.76f)
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, "volume_flow")
- .label("Volume Flow")
- .description("Denotes the current volume flow")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("volume_flow", 3.34f)
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, TEMPERATURE)
- .label("Temperature")
- .description("Denotes the current temperature in degrees celsius")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
-
.measurementUnit(URI.create("http://qudt.org/vocab/unit#DegreeCelsius"))
- .valueSpecification(0.0f, 100.0f, 0.1f)
- .build())
- .sample(TEMPERATURE, 33.221f)
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, "density")
- .label("Density")
- .description("Denotes the current density of the fluid")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("density", 5.0f)
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Boolean, "sensor_fault_flags")
- .label("Sensor Fault Flags")
- .description("Any fault flags of the sensors")
- .semanticType(SO.BOOLEAN)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("sensor_fault_flags", true)
- .build();
+ public static final String TIMESTAMP = "timestamp";
+ public static final String SENSOR_ID = "sensorId";
+ public static final String MASS_FLOW = "mass_flow";
+ public static final String TEMPERATURE = "temperature";
+
+ public static EventSimulator getSimulator(String selectedSimulatorOption)
throws AdapterException {
+ return switch (selectedSimulatorOption) {
+ case "flowrate" -> new FlowSimulator(new SensorValueSimulator());
+ case "pressure" -> new PressureSimulator(new SensorValueSimulator());
+ case "waterlevel" -> new WaterlevelSimulator(new SensorValueSimulator());
+ case "diagnostics" -> new DiagnosticSimulator(new
SensorValueSimulator());
+ default -> throw new AdapterException("resource not found");
+ };
}
}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/DiagnosticSimulator.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/DiagnosticSimulator.java
new file mode 100644
index 0000000000..e54d6d516d
--- /dev/null
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/DiagnosticSimulator.java
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.iiot.adapters.simulator.machine.event;
+
+import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.schema.EventPropertyNested;
+import org.apache.streampipes.sdk.builder.NestedPropertyBuilder;
+import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
+import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
+import org.apache.streampipes.sdk.helpers.EpProperties;
+import org.apache.streampipes.sdk.helpers.Labels;
+import org.apache.streampipes.sdk.utils.Datatypes;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.TIMESTAMP;
+import static
org.apache.streampipes.sdk.helpers.EpProperties.timestampProperty;
+
+public class DiagnosticSimulator implements EventSimulator {
+
+ private static final String SENSOR_ID = "sensorId";
+ private static final String SENSOR_TYPE = "sensorType";
+ private static final String PHASE = "phase";
+ private static final String ACTIVE = "active";
+ private static final String TAGS = "tags";
+ private static final String METRICS = "metrics";
+ private static final String RECENT_SAMPLES = "recentSamples";
+ private static final String VOLUME_FLOW = "volume_flow";
+ private static final String TEMPERATURE = "temperature";
+ private static final String ACTIVE_ALARMS = "activeAlarms";
+ private static final String OVERALL_STATE = "overallState";
+ private static final String STATUS = "status";
+ private static final String OFFSET_MS = "offsetMs";
+
+ private final SensorValueSimulator valueSimulator;
+
+ public DiagnosticSimulator(SensorValueSimulator valueSimulator) {
+ this.valueSimulator = valueSimulator;
+ }
+
+ @Override
+ public Map<String, Object> buildEvent(int simulationPhase, int sensorIndex,
long timestamp) {
+ Map<String, Object> event = new HashMap<>();
+
+ event.put(TIMESTAMP, timestamp);
+ event.put(SENSOR_ID, String.format("sensor%02d", sensorIndex));
+ event.put(SENSOR_TYPE, "diagnostic");
+ event.put(PHASE, simulationPhase);
+ event.put(ACTIVE, Boolean.TRUE);
+
+ List<String> tags = new ArrayList<>();
+ tags.add("diagnostic");
+ tags.add(simulationPhase == 0 ? "normal" : "alarm");
+ event.put(TAGS, tags);
+
+ Map<String, Object> metrics = new HashMap<>();
+
+ double volumeFlowValue = valueSimulator.randomDoubleBetween(0, 10);
+ double temperatureValue = (simulationPhase == 0)
+ ? valueSimulator.randomDoubleBetween(40, 50)
+ : valueSimulator.randomDoubleBetween(80, 100);
+
+ metrics.put(VOLUME_FLOW,
+ buildMetricBlock("l/s", volumeFlowValue, 0.0, 10.0, 1.0, 9.0));
+ metrics.put(TEMPERATURE,
+ buildMetricBlock("°C", temperatureValue,
+ (simulationPhase == 0 ? 30.0 : 70.0),
+ (simulationPhase == 0 ? 60.0 : 120.0),
+ (simulationPhase == 0 ? 35.0 : 75.0),
+ (simulationPhase == 0 ? 55.0 : 110.0)));
+
+
+ event.put(METRICS, metrics);
+
+ List<Map<String, Object>> samples = new ArrayList<>();
+ for (int i = 0; i < 3; i++) {
+ Map<String, Object> sample = new HashMap<>();
+ sample.put(OFFSET_MS, -i * 1000);
+ sample.put(VOLUME_FLOW, volumeFlowValue + (i - 1) * 0.1);
+ sample.put(TEMPERATURE, temperatureValue + (i - 1) * 0.2);
+ samples.add(sample);
+ }
+ event.put(RECENT_SAMPLES, samples);
+
+ Map<String, Object> status = new HashMap<>();
+ status.put(OVERALL_STATE, simulationPhase == 0 ? "OK" : "ALARM");
+
+ List<String> activeAlarms = new ArrayList<>();
+ if (simulationPhase != 0) {
+ if (temperatureValue > 80) {
+ activeAlarms.add("HIGH_TEMPERATURE");
+ }
+ }
+ status.put(ACTIVE_ALARMS, activeAlarms);
+
+ event.put(STATUS, status);
+ return event;
+ }
+
+ @Override
+ public GuessSchema getSchema() {
+ return GuessSchemaBuilder.create()
+ .property(timestampProperty(TIMESTAMP))
+ .sample(TIMESTAMP, System.currentTimeMillis())
+ .property(
+ PrimitivePropertyBuilder
+ .create(Datatypes.String, SENSOR_ID)
+ .label("Sensor ID")
+ .description("The ID of the sensor")
+ .build()
+ )
+ .sample(SENSOR_ID, "sensor01")
+ .property(
+ PrimitivePropertyBuilder
+ .create(Datatypes.String, SENSOR_TYPE)
+ .label("Sensor Type")
+ .description("The type of the sensor")
+ .build()
+ )
+ .sample(SENSOR_TYPE, "diagnostic")
+ .property(
+ PrimitivePropertyBuilder.create(Datatypes.Integer, PHASE)
+ .label("Phase")
+ .description("The current simulation phase")
+ .build()
+ )
+ .sample(PHASE, 0)
+ .property(
+ PrimitivePropertyBuilder.create(Datatypes.Boolean, ACTIVE)
+ .label("Active")
+ .description("Indicates whether the sensor is active")
+ .build()
+ )
+ .sample(ACTIVE, true)
+ .property(
+ EpProperties.listStringEp(
+ Labels.from(TAGS, "Tags", "Tags associated with the sensor"),
+ TAGS,
+ null)
+ )
+ .sample(TAGS, List.of("diagnostic", "normal"))
+ .property(
+ NestedPropertyBuilder.create(METRICS)
+ .withEventProperty(
+ makeMetricsSchema(VOLUME_FLOW)
+ )
+ .withEventProperty(
+ makeMetricsSchema(TEMPERATURE)
+ )
+ .build()
+ )
+ .sample(METRICS, Map.of(
+ VOLUME_FLOW, Map.of("unit", "l/s", "value", 5.0, "thresholds",
+ Map.of("min", 0.0, "max", 10.0, "warningMin", 1.0,
"warningMax", 9.0),
+ "recentValues", List.of(4.75, 5.0, 5.25),
+ "samples", List.of(
+ Map.of("index", 0, "sampleValue", 4.9, "quality", "GOOD"),
+ Map.of("index", 1, "sampleValue", 5.0, "quality", "FAIR"),
+ Map.of("index", 2, "sampleValue", 5.1, "quality", "POOR")
+ )
+ ),
+ TEMPERATURE, Map.of("unit", "°C", "value", 45.0, "thresholds",
+ Map.of("min", 30.0, "max", 60.0, "warningMin", 35.0,
"warningMax", 55.0),
+ "recentValues", List.of(42.75, 45.0, 47.25),
+ "samples", List.of(
+ Map.of("index", 0, "sampleValue", 44.8, "quality", "GOOD"),
+ Map.of("index", 1, "sampleValue", 45.0, "quality", "FAIR"),
+ Map.of("index", 2, "sampleValue", 45.2, "quality", "POOR")
+ )
+ )
+ ))
+ .property(
+ EpProperties.listNestedEp(
+ Labels.from(RECENT_SAMPLES, "Recent Samples", "Recent sensor
samples"),
+ RECENT_SAMPLES,
+ List.of(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Integer, OFFSET_MS)
+ .label("Offset (ms)")
+ .description("Offset in milliseconds from the event
timestamp")
+ .build(),
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, VOLUME_FLOW)
+ .label("Volume Flow")
+ .description("Volume flow value")
+ .build(),
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, TEMPERATURE)
+ .label("Temperature")
+ .description("Temperature value")
+ .build()
+ )
+ )
+ )
+ .sample(RECENT_SAMPLES, List.of(
+ Map.of(
+ OFFSET_MS, -0,
+ VOLUME_FLOW, 5.0,
+ TEMPERATURE, 45.0
+ ),
+ Map.of(
+ OFFSET_MS, -1000,
+ VOLUME_FLOW, 4.9,
+ TEMPERATURE, 44.8
+ ),
+ Map.of(
+ OFFSET_MS, -2000,
+ VOLUME_FLOW, 5.1,
+ TEMPERATURE, 45.2
+ )))
+ .property(
+ NestedPropertyBuilder.create("status")
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.String, OVERALL_STATE)
+ .label("Overall State")
+ .description("Overall state of the sensor")
+ .build()
+ )
+ .withEventProperty(
+ EpProperties.listStringEp(
+ Labels.from(ACTIVE_ALARMS, "Active Alarms", "List of
active alarms"),
+ ACTIVE_ALARMS,
+ null)
+ )
+ .build()
+ )
+ .sample("status", Map.of(
+ OVERALL_STATE, "OK",
+ ACTIVE_ALARMS, List.of()
+ ))
+ .build();
+ }
+
+ private EventPropertyNested makeMetricsSchema(String metricsName) {
+ return NestedPropertyBuilder
+ .create(metricsName)
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.String, "unit")
+ .label("Unit")
+ .description("Unit of the volume flow")
+ .build()
+ )
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, "value")
+ .label("Value")
+ .description("Current value of the volume flow")
+ .build()
+ )
+ .withEventProperty(
+ NestedPropertyBuilder
+ .create("thresholds")
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, "min")
+ .label("Min")
+ .description("Minimum threshold")
+ .build()
+ )
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, "max")
+ .label("Max")
+ .description("Maximum threshold")
+ .build()
+ )
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, "warningMin")
+ .label("Warning Min")
+ .description("Warning minimum threshold")
+ .build()
+ )
+ .withEventProperty(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, "warningMax")
+ .label("Warning Max")
+ .description("Warning maximum threshold")
+ .build()
+ )
+ .build())
+ .withEventProperty(
+ EpProperties.listDoubleEp(
+ Labels.from("recentValues", "Recent Values", "Recent volume
flow values"),
+ "recentValues",
+ null
+ )
+ )
+ .withEventProperty(
+ EpProperties.listNestedEp(
+ Labels.from("samples", "Samples", "Recent volume flow
samples"),
+ "samples",
+ List.of(
+ PrimitivePropertyBuilder
+ .create(Datatypes.Integer, "index")
+ .label("Index")
+ .description("Sample index")
+ .build(),
+ PrimitivePropertyBuilder
+ .create(Datatypes.Double, "sampleValue")
+ .label("Sample Value")
+ .description("Value of the sample")
+ .build(),
+ PrimitivePropertyBuilder
+ .create(Datatypes.String, "quality")
+ .label("Quality")
+ .description("Quality of the sample")
+ .build()
+ )
+ )
+ )
+ .build();
+ }
+
+ private Map<String, Object> buildMetricBlock(String unit,
+ double value,
+ double min,
+ double max,
+ double warningMin,
+ double warningMax) {
+ Map<String, Object> metric = new HashMap<>();
+ metric.put("unit", unit);
+ metric.put("value", value);
+
+ Map<String, Object> thresholds = new HashMap<>();
+ thresholds.put("min", min);
+ thresholds.put("max", max);
+ thresholds.put("warningMin", warningMin);
+ thresholds.put("warningMax", warningMax);
+ metric.put("thresholds", thresholds);
+
+ List<Double> recentValues = new ArrayList<>();
+ recentValues.add(value * 0.95);
+ recentValues.add(value);
+ recentValues.add(value * 1.05);
+ metric.put("recentValues", recentValues);
+
+ List<Map<String, Object>> samples = new ArrayList<>();
+ for (int i = 0; i < 3; i++) {
+ Map<String, Object> sample = new HashMap<>();
+ sample.put("index", i);
+ sample.put("sampleValue", value + (i - 1) * 0.1);
+ sample.put("quality", i == 0 ? "GOOD" : (i == 1 ? "FAIR" : "POOR"));
+ samples.add(sample);
+ }
+ metric.put("samples", samples);
+
+ return metric;
+ }
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/EventSimulator.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/EventSimulator.java
new file mode 100644
index 0000000000..6db71843b8
--- /dev/null
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/EventSimulator.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.iiot.adapters.simulator.machine.event;
+
+import org.apache.streampipes.model.connect.guess.GuessSchema;
+
+import java.util.Map;
+
+public interface EventSimulator {
+
+ Map<String, Object> buildEvent(int simulationPhase, int sensorIndex, long
timestamp);
+
+ GuessSchema getSchema();
+
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/FlowSimulator.java
similarity index 54%
copy from
streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
copy to
streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/FlowSimulator.java
index 1a3a27865d..9a4adfc726 100644
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/MachineDataSimulatorUtils.java
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/FlowSimulator.java
@@ -15,9 +15,9 @@
* limitations under the License.
*
*/
-package org.apache.streampipes.connect.iiot.adapters.simulator.machine;
-import org.apache.streampipes.commons.exceptions.connect.AdapterException;
+package org.apache.streampipes.connect.iiot.adapters.simulator.machine.event;
+
import org.apache.streampipes.model.connect.guess.GuessSchema;
import org.apache.streampipes.model.schema.PropertyScope;
import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
@@ -26,89 +26,41 @@ import org.apache.streampipes.sdk.utils.Datatypes;
import org.apache.streampipes.vocabulary.SO;
import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.HAS_SENSOR_ID;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.MASS_FLOW;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.SENSOR_ID;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.TEMPERATURE;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.TIMESTAMP;
import static
org.apache.streampipes.sdk.helpers.EpProperties.timestampProperty;
-public class MachineDataSimulatorUtils {
-
- // Vocabulary
- public static final String NS =
"https://streampipes.org/vocabulary/examples/watertank/v1/";
- public static final String HAS_SENSOR_ID = NS + "hasSensorId";
+public class FlowSimulator implements EventSimulator {
- private static final String TIMESTAMP = "timestamp";
- private static final String SENSOR_ID = "sensorId";
- private static final String MASS_FLOW = "mass_flow";
- private static final String TEMPERATURE = "temperature";
+ private final SensorValueSimulator valueSimulator;
- public static GuessSchema getSchema(String selectedSimulatorOption) throws
AdapterException {
- switch (selectedSimulatorOption) {
- case "flowrate":
- return getFlowrateSchema();
- case "pressure":
- return getPressureSchema();
- case "waterlevel":
- return getWaterlevelSchema();
- default:
- throw new AdapterException("resource not found");
- }
+ public FlowSimulator(SensorValueSimulator valueSimulator) {
+ this.valueSimulator = valueSimulator;
}
- private static GuessSchema getWaterlevelSchema() {
- return GuessSchemaBuilder.create()
- .property(timestampProperty(TIMESTAMP))
- .sample(TIMESTAMP, System.currentTimeMillis())
- .property(PrimitivePropertyBuilder
- .create(Datatypes.String, SENSOR_ID)
- .label("Sensor ID")
- .description("The ID of the sensor")
- .semanticType(HAS_SENSOR_ID)
- .scope(PropertyScope.DIMENSION_PROPERTY)
- .build())
- .sample(SENSOR_ID, "sensor01")
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, "level")
- .label("Water Level")
- .description("Denotes the current water level in the container")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("level", 5.25f)
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Boolean, "overflow")
- .label("Overflow")
- .description("Indicates whether the tank overflows")
- .semanticType(SO.NUMBER)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("overflow", true)
- .build();
- }
+ @Override
+ public Map<String, Object> buildEvent(int simulationPhase, int sensorIndex,
long timestamp) {
+ Map<String, Object> event = new HashMap<>();
- private static GuessSchema getPressureSchema() {
- return GuessSchemaBuilder.create()
- .property(timestampProperty(TIMESTAMP))
- .sample(TIMESTAMP, System.currentTimeMillis())
- .property(PrimitivePropertyBuilder
- .create(Datatypes.String, SENSOR_ID)
- .label("Sensor ID")
- .description("The ID of the sensor")
- .semanticType(HAS_SENSOR_ID)
- .scope(PropertyScope.DIMENSION_PROPERTY)
- .build())
- .sample(SENSOR_ID, "sensor01")
- .property(PrimitivePropertyBuilder
- .create(Datatypes.Float, "pressure")
- .label("Pressure")
- .description("Denotes the current pressure in the pressure tank")
- .semanticType(SO.NUMBER)
- .valueSpecification(0.0f, 100.0f, 0.5f)
- .scope(PropertyScope.MEASUREMENT_PROPERTY)
- .build())
- .sample("pressure", 85.22f)
- .build();
+ event.put("timestamp", timestamp);
+ event.put("sensorId", String.format("flowrate%02d", sensorIndex));
+ event.put("mass_flow", valueSimulator.randomDoubleBetween(0, 10));
+ event.put("volume_flow", valueSimulator.randomDoubleBetween(0, 10));
+ event.put("temperature",
+ simulationPhase == 0 ? valueSimulator.randomDoubleBetween(40, 50) :
valueSimulator.randomDoubleBetween(80, 100));
+ event.put("density", valueSimulator.randomDoubleBetween(40, 50));
+ event.put("sensor_fault_flags", simulationPhase != 0);
+
+ return event;
}
- public static GuessSchema getFlowrateSchema() {
+ public GuessSchema getSchema() {
return GuessSchemaBuilder.create()
.property(timestampProperty(TIMESTAMP))
.sample(TIMESTAMP, System.currentTimeMillis())
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/PressureSimulator.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/PressureSimulator.java
new file mode 100644
index 0000000000..c9d8255855
--- /dev/null
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/PressureSimulator.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.iiot.adapters.simulator.machine.event;
+
+import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
+import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
+import org.apache.streampipes.sdk.utils.Datatypes;
+import org.apache.streampipes.vocabulary.SO;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.HAS_SENSOR_ID;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.SENSOR_ID;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.TIMESTAMP;
+import static
org.apache.streampipes.sdk.helpers.EpProperties.timestampProperty;
+
+public class PressureSimulator implements EventSimulator {
+
+ private final SensorValueSimulator valueSimulator;
+
+ public PressureSimulator(SensorValueSimulator valueSimulator) {
+ this.valueSimulator = valueSimulator;
+ }
+
+ @Override
+ public Map<String, Object> buildEvent(int simulationPhase, int sensorIndex,
long timestamp) {
+ Map<String, Object> event = new HashMap<>();
+
+ event.put("timestamp", timestamp);
+ event.put("sensorId", String.format("pressure%02d", sensorIndex));
+ event.put("pressure",
+ simulationPhase == 0 ? valueSimulator.randomDoubleBetween(10, 40) :
valueSimulator.randomDoubleBetween(40, 70));
+
+ return event;
+ }
+
+ @Override
+ public GuessSchema getSchema() {
+ return GuessSchemaBuilder.create()
+ .property(timestampProperty(TIMESTAMP))
+ .sample(TIMESTAMP, System.currentTimeMillis())
+ .property(PrimitivePropertyBuilder
+ .create(Datatypes.String, SENSOR_ID)
+ .label("Sensor ID")
+ .description("The ID of the sensor")
+ .semanticType(HAS_SENSOR_ID)
+ .scope(PropertyScope.DIMENSION_PROPERTY)
+ .build())
+ .sample(SENSOR_ID, "sensor01")
+ .property(PrimitivePropertyBuilder
+ .create(Datatypes.Float, "pressure")
+ .label("Pressure")
+ .description("Denotes the current pressure in the pressure tank")
+ .semanticType(SO.NUMBER)
+ .valueSpecification(0.0f, 100.0f, 0.5f)
+ .scope(PropertyScope.MEASUREMENT_PROPERTY)
+ .build())
+ .sample("pressure", 85.22f)
+ .build();
+ }
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/SensorValueSimulator.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/SensorValueSimulator.java
new file mode 100644
index 0000000000..912de2f3de
--- /dev/null
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/SensorValueSimulator.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.iiot.adapters.simulator.machine.event;
+
+public class SensorValueSimulator {
+
+ public double randomDoubleBetween(int min, int max) {
+ return Math.random() * (max - min + 1) + min;
+ }
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/WaterlevelSimulator.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/WaterlevelSimulator.java
new file mode 100644
index 0000000000..50798aa38a
--- /dev/null
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/simulator/machine/event/WaterlevelSimulator.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.iiot.adapters.simulator.machine.event;
+
+import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.schema.PropertyScope;
+import org.apache.streampipes.sdk.builder.PrimitivePropertyBuilder;
+import org.apache.streampipes.sdk.builder.adapter.GuessSchemaBuilder;
+import org.apache.streampipes.sdk.utils.Datatypes;
+import org.apache.streampipes.vocabulary.SO;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.HAS_SENSOR_ID;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.SENSOR_ID;
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorUtils.TIMESTAMP;
+import static
org.apache.streampipes.sdk.helpers.EpProperties.timestampProperty;
+
+public class WaterlevelSimulator implements EventSimulator {
+
+ private final SensorValueSimulator valueSimulator;
+
+ public WaterlevelSimulator(SensorValueSimulator valueSimulator) {
+ this.valueSimulator = valueSimulator;
+ }
+
+ @Override
+ public Map<String, Object> buildEvent(int simulationPhase, int sensorIndex,
long timestamp) {
+ Map<String, Object> event = new HashMap<>();
+
+ event.put("timestamp", timestamp);
+ event.put("sensorId", String.format("level%02d", sensorIndex));
+ event.put("level",
+ simulationPhase == 0 ? valueSimulator.randomDoubleBetween(20, 30) :
valueSimulator.randomDoubleBetween(60, 80));
+ event.put("overflow", simulationPhase != 0);
+
+ return event;
+ }
+
+ @Override
+ public GuessSchema getSchema() {
+ return GuessSchemaBuilder.create()
+ .property(timestampProperty(TIMESTAMP))
+ .sample(TIMESTAMP, System.currentTimeMillis())
+ .property(PrimitivePropertyBuilder
+ .create(Datatypes.String, SENSOR_ID)
+ .label("Sensor ID")
+ .description("The ID of the sensor")
+ .semanticType(HAS_SENSOR_ID)
+ .scope(PropertyScope.DIMENSION_PROPERTY)
+ .build())
+ .sample(SENSOR_ID, "sensor01")
+ .property(PrimitivePropertyBuilder
+ .create(Datatypes.Float, "level")
+ .label("Water Level")
+ .description("Denotes the current water level in the container")
+ .semanticType(SO.NUMBER)
+ .scope(PropertyScope.MEASUREMENT_PROPERTY)
+ .build())
+ .sample("level", 5.25f)
+ .property(PrimitivePropertyBuilder
+ .create(Datatypes.Boolean, "overflow")
+ .label("Overflow")
+ .description("Indicates whether the tank overflows")
+ .semanticType(SO.NUMBER)
+ .scope(PropertyScope.MEASUREMENT_PROPERTY)
+ .build())
+ .sample("overflow", true)
+ .build();
+ }
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/migration/MachineDataSimulatorMigrationV1.java
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/migration/MachineDataSimulatorMigrationV1.java
new file mode 100644
index 0000000000..08ffbbc14b
--- /dev/null
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/migration/MachineDataSimulatorMigrationV1.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.iiot.migration;
+
+import
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorAdapter;
+import
org.apache.streampipes.extensions.api.extractor.IStaticPropertyExtractor;
+import org.apache.streampipes.extensions.api.migration.IAdapterMigrator;
+import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceTagPrefix;
+import org.apache.streampipes.model.migration.MigrationResult;
+import org.apache.streampipes.model.migration.ModelMigratorConfig;
+import org.apache.streampipes.model.staticproperty.OneOfStaticProperty;
+import org.apache.streampipes.model.staticproperty.Option;
+import org.apache.streampipes.sdk.StaticProperties;
+import org.apache.streampipes.sdk.helpers.Labels;
+
+import static
org.apache.streampipes.connect.iiot.adapters.simulator.machine.MachineDataSimulatorAdapter.NUMBER_OF_SENSORS;
+
+public class MachineDataSimulatorMigrationV1 implements IAdapterMigrator {
+ @Override
+ public ModelMigratorConfig config() {
+ return new ModelMigratorConfig(
+ MachineDataSimulatorAdapter.ID,
+ SpServiceTagPrefix.ADAPTER,
+ 0,
+ 1
+ );
+ }
+
+ @Override
+ public MigrationResult<AdapterDescription> migrate(AdapterDescription
element,
+ IStaticPropertyExtractor
extractor) throws RuntimeException {
+ element.getConfig().add(1,
StaticProperties.integerFreeTextProperty(Labels.withId(NUMBER_OF_SENSORS), 1));
+ var sensorTypes = element.getConfig().get(2);
+ if (sensorTypes instanceof OneOfStaticProperty oneOfStaticProperty) {
+ oneOfStaticProperty.getOptions().add(new Option("diagnostics"));
+ }
+ return MigrationResult.success(element);
+ }
+}
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/documentation.md
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/documentation.md
deleted file mode 100644
index a03969e8fa..0000000000
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/documentation.md
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
- ~ Licensed to the Apache Software Foundation (ASF) under one or more
- ~ contributor license agreements. See the NOTICE file distributed with
- ~ this work for additional information regarding copyright ownership.
- ~ The ASF licenses this file to You under the Apache License, Version 2.0
- ~ (the "License"); you may not use this file except in compliance with
- ~ the License. You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- ~
- -->
-
-## File (Stream)
-
-<p align="center">
- <img src="icon.png" width="150px;" class="pe-image-documentation"/>
-</p>
-
-***
-
-## Description
-
-Continuously streams the content from a file
-
-***
-
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/icon.png
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/icon.png
deleted file mode 100644
index 2b3a037857..0000000000
Binary files
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/icon.png
and /dev/null differ
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/strings.en
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/strings.en
deleted file mode 100644
index 8847039ef7..0000000000
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file/strings.en
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-
-org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file.title=File
Stream
-org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.file.description=Continuously
streams the content from a file.
-
-filePath.title=File
-filePath.description=File Path
-
-replaceTimestamp.title=Use current time
-replaceTimestamp.description=Replace Event Time with Current Timestamp
-
-speed.title=Replay Speed
-speed.description=
-
-speedUp.title=Speed Up
-speedUp.description=original = 1; speedup 2x = 2; half speed = 0.5
-
-replayOnce.title=Replay Once
-replayOnce.description='yes' file is only replayed once, 'no' the file is
replayed till adapter is stopped
-
-keepOriginalTime.title=Keep original time
-keepOriginalTime.description=
-
-speedUpFactor.title=Speed Up Factor
-speedUpFactor.description=
-
-fastest.title=Fastest (Ignore original time)
-fastest.description=
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/documentation.md
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/documentation.md
deleted file mode 100644
index ec3ed056bb..0000000000
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/documentation.md
+++ /dev/null
@@ -1,34 +0,0 @@
-<!--
- ~ Licensed to the Apache Software Foundation (ASF) under one or more
- ~ contributor license agreements. See the NOTICE file distributed with
- ~ this work for additional information regarding copyright ownership.
- ~ The ASF licenses this file to You under the Apache License, Version 2.0
- ~ (the "License"); you may not use this file except in compliance with
- ~ the License. You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- ~
- -->
-
-## Machine Data Simulator
-
-<p align="center">
- <img src="icon.png" width="150px;" class="pe-image-documentation"/>
-</p>
-
-***
-
-## Description
-
-Publishes various simulated machine sensor data in a configurable time
interval (in milliseconds).
-Sensors are:
-* flowrate
-* pressure
-* waterlevel
-***
\ No newline at end of file
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/icon.png
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/icon.png
deleted file mode 100644
index 33c09c451c..0000000000
Binary files
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/icon.png
and /dev/null differ
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/strings.en
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/strings.en
deleted file mode 100644
index 21b8edc4c8..0000000000
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2/strings.en
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-
-org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.title=Machine
Data Simulator
-org.apache.streampipes.connect.iiot.adapters.simulator.machine.v2.description=Publishes
various simulated machine sensor data
-
-wait-time-ms.title=Wait Time (MS)
-wait-time-ms.description=The time to wait between two events in milliseconds
-
-selected-simulator-option.title=Select sensor
-selected-simulator-option.description=Select simulated sensor data to be
published
\ No newline at end of file
diff --git
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine/strings.en
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine/strings.en
index f45e9d25bb..2ebb381be1 100644
---
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine/strings.en
+++
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.simulator.machine/strings.en
@@ -23,4 +23,7 @@ wait-time-ms.title=Wait Time (MS)
wait-time-ms.description=The time to wait between two events in milliseconds
selected-simulator-option.title=Select sensor
-selected-simulator-option.description=Select simulated sensor data to be
published
\ No newline at end of file
+selected-simulator-option.description=Select simulated sensor data to be
published
+
+numberOfSensors.title=Number of sensors
+numberOfSensors.description=The number of sensors to simulate