This is an automated email from the ASF dual-hosted git repository.

zehnder 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 50199e09b Sp 1592 (#1647)
50199e09b is described below

commit 50199e09b7fb847470eb32bccfef5c8b6292f9e7
Author: Philipp Zehnder <[email protected]>
AuthorDate: Mon Jun 5 15:17:36 2023 +0200

    Sp 1592 (#1647)
    
    * [hotfix] Remove set adapters from extensions
    
    * [hotfix] Remove old resource files
    
    * [#1289] Remove data set model
    
    * [#1289] Remove data set model from ui
    
    * [#1289] Remove `adapterType` and fix tests
    
    * [#1289] Remove class `SpDataSet`
    
    * [#1289] Remove legacy code in class `AdapterDescription`
    
    * [#1289] Remove class `AdapterStreamDescription`
    
    * [#1289] Remove class `ProtocolStreamDescription`
    
    * [hotfix] Remove class `AdapterDescription`
    
    * [#1289] Very first version for new adapter interface
    
    * [#1289] Started to migrate the API
    
    * [#1289] Deactivate old protocol API
    
    * [#1289] Remove old models from the ui
    
    * [#1289] Remove old models from the ui
    
    * [#1289] Fix icons for adapters
    
    * [#1289] Fix minor bug
    
    * [#1289] Fix maven build
    
    * [#1289] WIP refactor `AdapterConfigurationBuilder`
    
    * [#1289] Fix AdapterConfigurationBuilder
    
    * [#1289] Fix AdapterConfigurationBuilder
    
    * [#1289] Guess schema works now for NewMachineDataSimulatorAdapter
    
    * [#1289] Add start adapter
    
    * [#1289] First version of new machine data simulator works
    
    * [#1289] Working on the first new parser
    
    * [#1289] First version of declare parser description
    
    * [WIP] Add adapter configuration test
    
    * [#1289] First generic adapter works now
    
    * [#1289] Add parser exception to json parser
    
    * [#1289] Add csv parser
    
    * [#1289] Change implementation for json parser
    
    * [#1289] Add json array parsers
    
    * Add runtime context to adapters (#1290)
    
    * Extract interface of  (#1290)
    
    * Refactor OPC-UA adapter to new model (#1290)
    
    * Refactor S7 adapter (#1290)
    
    * Refactor Modbus adapter (#1290)
    
    * Refactor Ros adapter (#1290)
    
    * [#1289] Add geo json parser
    
    * [#1289] Add xml parser
    
    * [#1289] Add image parser
    
    * Refactor Kafka adapter (#1290)
    
    * Refactor MQTT adapter (#1290)
    
    * Refactor Nats adapter (#1290)
    
    * Refactor Pulsar adapter (#1290)
    
    * Refactor RocketMQ adapter (#1290)
    
    * Refactor TubeMQ adapter (#1290)
    
    * Refactor HTTP server adapter (#1290)
    
    * Refactor HTTP Stream adapter (#1290)
    
    * [WIP] Refactor Parser API
    
    * [WIP] Refactor Parser API
    
    * [#1289] Fix file stream e2e test
    
    * [#1289] Fix tests and csv parser for timestamps
    
    * [#1289] Fix e2e connect tests
    
    * [hotfix] Fix build
    
    * [hotfix] Deactivate Mqtt integration test
    
    * [#1289] Remove old format implementation from backend
    
    * [#1289] Remove old format implementation from backend
    
    * [#1289] Remove old format implementation from ui
    
    * [#1289] Fix kafka e2e test
    
    * Add migration script for specific adapters (#1289)
    
    * Add initial version to migrate generic adapters (#1289)
    
    * Modify format migrators (#1289)
    
    * [#1289] Migrate influxdb to new interface
    
    * [#1289] Fix ROS bridge adapter
    
    * [#1289] Rename specific-adapter-configuration.component
    
    * [#1289] Remove old data model
    
    * [#1289] Fix mqtt integration test
    
    * [#1289] Update Pulsar integration test
    
    * [#1289] Remove DebugAdapterSink which is no longer needed for integration 
tests
    
    * [#1289] Fix kafka adapter on restart
    
    * [#1289] Fix migrations for all parser
    
    * [hotfix] Fix image parser for adapters
    
    * [hotfix] Change StreamPipes version to fix build problem
    
    * [#1289] Move adapters
    
    * [hotfix] Remove duplicate licence headers
    
    * [hotfix] Fix conversion of pipeline element templates
    
    * Move PullAdapter to extensions-management and api modules (#1289)
    
    * Refactor structure of extensions-api, add supplier to adapter interface 
(#1581)
    
    * Rename AdapterInterface to StreamPipesAdapter (#1590)
    
    * [hotfix] Fix checkstyle issues
    
    * [hotfix] Fix checkstyle issue
    
    * [hotfix] Fix checkstyle issue
    
    * [hotfix] Fix checkstyle
    
    * Migrate ISS adapter and Flic adapter (#1289)
    
    * Migrate connect adapters to new model (#1289)
    
    * Properly apply configs to influx adapter (#1289)
    
    * [hotfix] Fix checkstyle
    
    * fix: minor adaptions
    
    * fix: remove data set artifacts
    
    * fix: minor fixes
    
    * [hotfix] Regenerate typescript model
    
    * [#1592] Add first version for an io link adapter
    
    * Refactor data processor and sink API (#1632) (#1633)
    
    * chore: mark streampipes-wrapper-python as deprecated (#1623)
    
    * Bump types-requests in /streampipes-client-python (#1588)
    
    Bumps [types-requests](https://github.com/python/typeshed) from 2.30.0.0 to 
2.31.0.0.
    - [Commits](https://github.com/python/typeshed/commits)
    
    ---
    updated-dependencies:
    - dependency-name: types-requests
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: dependabot[bot] 
<49699333+dependabot[bot]@users.noreply.github.com>
    
    * Bump mkdocstrings[python] in /streampipes-client-python (#1631)
    
    * chore: add missing support of NATS as messaging protocol (#1628)
    
    * Bump spring-boot.version from 3.0.6 to 3.1.0 (#1595)
    
    Bumps `spring-boot.version` from 3.0.6 to 3.1.0.
    
    Updates `spring-boot-properties-migrator` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    Updates `spring-boot-starter-jersey` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    Updates `spring-boot-starter-jetty` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    Updates `spring-boot-starter-oauth2-client` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    Updates `spring-boot-starter-undertow` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    Updates `spring-boot-starter-web` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    Updates `spring-boot-maven-plugin` from 3.0.6 to 3.1.0
    - [Release notes](https://github.com/spring-projects/spring-boot/releases)
    - 
[Commits](https://github.com/spring-projects/spring-boot/compare/v3.0.6...v3.1.0)
    
    ---
    updated-dependencies:
    - dependency-name: org.springframework.boot:spring-boot-properties-migrator
      dependency-type: direct:production
      update-type: version-update:semver-minor
    - dependency-name: org.springframework.boot:spring-boot-starter-jersey
      dependency-type: direct:production
      update-type: version-update:semver-minor
    - dependency-name: org.springframework.boot:spring-boot-starter-jetty
      dependency-type: direct:production
      update-type: version-update:semver-minor
    - dependency-name: 
org.springframework.boot:spring-boot-starter-oauth2-client
      dependency-type: direct:production
      update-type: version-update:semver-minor
    - dependency-name: org.springframework.boot:spring-boot-starter-undertow
      dependency-type: direct:production
      update-type: version-update:semver-minor
    - dependency-name: org.springframework.boot:spring-boot-starter-web
      dependency-type: direct:production
      update-type: version-update:semver-minor
    - dependency-name: org.springframework.boot:spring-boot-maven-plugin
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: dependabot[bot] 
<49699333+dependabot[bot]@users.noreply.github.com>
    
    * Refactor data processor and sink API (#1632)
    
    * Cleanup pom file (#1632)
    
    * Migrate processors to API (#1632)
    
    * [hotfix] Add runtime provider, update pom
    
    * Fix bug in standalone wrapper (#1632)
    
    * Fix instance provision in compatibility layer (#1632)
    
    * [hotfix] Disable Maven cache in workflow file
    
    * [hotfix] Fix failing build by reverting Flink version
    
    * [hotfix] Add proper time selection to another cypress test (#1641)
    
    * Fix bug in aggregation flink module
    
    * Properly return output source and schema info
    
    ---------
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: Tim <[email protected]>
    Co-authored-by: dependabot[bot] 
<49699333+dependabot[bot]@users.noreply.github.com>
    
    * chore: remove Plc4xPassiveAdapter
    
    * Add implementation for schema guessing from the example file in the HTTP
    
    resolves #1637
    fixes #1518 for streampipes-extensions
    
    * [#1592] Add io link master id to event
    
    * [#1592] Provide documentation for io link adapter
    
    ---------
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: Dominik Riemer <[email protected]>
    Co-authored-by: Stefan Obermeier <[email protected]>
    Co-authored-by: bossenti <[email protected]>
    Co-authored-by: Tim <[email protected]>
    Co-authored-by: dependabot[bot] 
<49699333+dependabot[bot]@users.noreply.github.com>
---
 .../connect/iiot/ConnectAdapterIiotInit.java       |   2 +
 .../iiot/adapters/iolink/IfmAlMqttAdapter.java     | 186 +++++++++++++++++++++
 .../iiot/adapters/iolink/sensor/IoLinkSensor.java  |  29 ++++
 .../iiot/adapters/iolink/sensor/SensorVVB001.java  | 162 ++++++++++++++++++
 .../documentation.md                               |  84 ++++++++++
 .../icon.png                                       | Bin 0 -> 9219 bytes
 .../strings.en                                     |  50 ++++++
 .../streampipes/sensor/SensorVVB001Test.java       |  52 ++++++
 8 files changed, 565 insertions(+)

diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java
index 03685343b..dcd646eac 100644
--- 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/ConnectAdapterIiotInit.java
@@ -18,6 +18,7 @@
 
 package org.apache.streampipes.connect.iiot;
 
+import org.apache.streampipes.connect.iiot.adapters.iolink.IfmAlMqttAdapter;
 import org.apache.streampipes.connect.iiot.adapters.opcua.OpcUaAdapter;
 import 
org.apache.streampipes.connect.iiot.adapters.plc4x.modbus.Plc4xModbusAdapter;
 import org.apache.streampipes.connect.iiot.adapters.plc4x.s7.Plc4xS7Adapter;
@@ -49,6 +50,7 @@ public class ConnectAdapterIiotInit extends 
ExtensionsModelSubmitter {
             8001)
         .registerAdapter(new MachineDataSimulatorAdapter())
         .registerAdapter(new FileReplayAdapter())
+        .registerAdapter(new IfmAlMqttAdapter())
         .registerAdapter(new RosBridgeAdapter())
         .registerAdapter(new OpcUaAdapter())
         .registerAdapter(new Plc4xS7Adapter())
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/IfmAlMqttAdapter.java
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/IfmAlMqttAdapter.java
new file mode 100644
index 000000000..c5db51d94
--- /dev/null
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/IfmAlMqttAdapter.java
@@ -0,0 +1,186 @@
+/*
+ * 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.iolink;
+
+import org.apache.streampipes.commons.exceptions.connect.AdapterException;
+import org.apache.streampipes.commons.exceptions.connect.ParseException;
+import org.apache.streampipes.connect.iiot.adapters.iolink.sensor.SensorVVB001;
+import org.apache.streampipes.extensions.api.connect.IAdapterConfiguration;
+import org.apache.streampipes.extensions.api.connect.IEventCollector;
+import org.apache.streampipes.extensions.api.connect.IParser;
+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.extensions.api.extractor.IStaticPropertyExtractor;
+import 
org.apache.streampipes.extensions.management.connect.adapter.parser.JsonParsers;
+import 
org.apache.streampipes.extensions.management.connect.adapter.parser.json.JsonObjectParser;
+import org.apache.streampipes.model.AdapterType;
+import org.apache.streampipes.model.StreamPipesErrorMessage;
+import org.apache.streampipes.model.connect.guess.GuessSchema;
+import org.apache.streampipes.model.monitoring.SpLogEntry;
+import org.apache.streampipes.pe.shared.config.mqtt.MqttConfig;
+import org.apache.streampipes.pe.shared.config.mqtt.MqttConnectUtils;
+import org.apache.streampipes.pe.shared.config.mqtt.MqttConsumer;
+import org.apache.streampipes.sdk.builder.adapter.AdapterConfigurationBuilder;
+import org.apache.streampipes.sdk.helpers.Labels;
+import org.apache.streampipes.sdk.helpers.Locales;
+import org.apache.streampipes.sdk.helpers.Options;
+import org.apache.streampipes.sdk.utils.Assets;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+public class IfmAlMqttAdapter implements StreamPipesAdapter {
+
+  public static final String ID = 
"org.apache.streampipes.connect.iiot.adapters.iolink";
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(IfmAlMqttAdapter.class);
+
+  private static final String PORTS = "ports";
+  private static final String SENSOR_TYPE = "sensor_type";
+
+  private MqttConsumer mqttConsumer;
+  private MqttConfig mqttConfig;
+
+  private final IParser parser;
+
+  private List<String> ports;
+
+  public IfmAlMqttAdapter() {
+    parser = new JsonParsers(new JsonObjectParser());
+  }
+
+  @Override
+  public IAdapterConfiguration declareConfig() {
+    return AdapterConfigurationBuilder
+        .create(ID, IfmAlMqttAdapter::new)
+        .withLocales(Locales.EN)
+        .withAssets(Assets.DOCUMENTATION, Assets.ICON)
+        .withCategory(AdapterType.Generic, AdapterType.Manufacturing)
+        .requiredTextParameter(MqttConnectUtils.getBrokerUrlLabel())
+        .requiredAlternatives(MqttConnectUtils.getAccessModeLabel(), 
MqttConnectUtils.getAlternativesOne(),
+            MqttConnectUtils.getAlternativesTwo())
+        .requiredMultiValueSelection(Labels.withId(PORTS),
+            Options.from("Port 1", "Port 2", "Port 3", "Port 4"))
+        .requiredSingleValueSelection(Labels.withId(SENSOR_TYPE),
+            Options.from("VVB001"))
+        .requiredTextParameter(MqttConnectUtils.getTopicLabel())
+        .buildConfiguration();
+  }
+
+  @Override
+  public void onAdapterStarted(IAdapterParameterExtractor extractor,
+                               IEventCollector collector,
+                               IAdapterRuntimeContext adapterRuntimeContext) 
throws AdapterException {
+    var sensor = new SensorVVB001();
+
+    this.applyConfiguration(extractor.getStaticPropertyExtractor());
+    this.mqttConsumer = new MqttConsumer(
+        this.mqttConfig,
+        (mqttEvent) -> {
+          try {
+            InputStream in = convertByte(mqttEvent);
+            parser.parse(in, (event) -> {
+
+              var data = getMap(event, "data");
+              var payload = getMap(data, "payload");
+
+              var deviceInfo = getMap(payload, "/deviceinfo/serialnumber");
+              var serialnumber = deviceInfo.get("data");
+
+              for (int i = 0; i < ports.size(); i++) {
+
+                var portResult = getMap(payload,
+                    
"/iolinkmaster/port[%s]/iolinkdevice/pdin".formatted(ports.get(i)));
+                var eventData = (String) portResult.get("data");
+
+                var parsedEvent = sensor.parseEvent(eventData);
+                parsedEvent.put("timestamp", System.currentTimeMillis() + i);
+                parsedEvent.put("port", "port" + ports.get(i));
+                parsedEvent.put(SensorVVB001.IO_LINK_MASTER_SN, serialnumber);
+
+                collector.collect(parsedEvent);
+              }
+            });
+          } catch (Exception e) {
+            adapterRuntimeContext
+                .getLogger()
+                .addErrorMessage(
+                    extractor.getAdapterDescription().getElementId(),
+                    SpLogEntry.from(System.currentTimeMillis(), 
StreamPipesErrorMessage.from(e)));
+            LOG.error("Could not parse event", e);
+          }
+        });
+
+    Thread thread = new Thread(this.mqttConsumer);
+    thread.start();
+  }
+
+  @Override
+  public void onAdapterStopped(IAdapterParameterExtractor extractor,
+                               IAdapterRuntimeContext adapterRuntimeContext) 
throws AdapterException {
+    this.mqttConsumer.close();
+  }
+
+  @Override
+  public GuessSchema onSchemaRequested(IAdapterParameterExtractor extractor,
+                                       IAdapterGuessSchemaContext 
adapterGuessSchemaContext) throws AdapterException {
+    this.applyConfiguration(extractor.getStaticPropertyExtractor());
+
+    return new SensorVVB001().getEventSchema();
+  }
+
+
+  private void applyConfiguration(IStaticPropertyExtractor extractor) {
+    mqttConfig = MqttConnectUtils.getMqttConfig(extractor);
+    String sensorType = extractor.selectedSingleValue(SENSOR_TYPE, 
String.class);
+    var selectedPorts = extractor.selectedMultiValues(PORTS, String.class);
+    ports = selectedPorts.stream()
+        .map(port -> port.substring(5))
+        .toList();
+  }
+
+  private Map<String, Object> getMap(Map<String, Object> event, String key) {
+    if (event.containsKey(key)) {
+      var payload = event.get(key);
+      if (payload instanceof Map) {
+        return (Map<String, Object>) event.get(key);
+      } else {
+        throw new ParseException(getErrorMessage(key));
+      }
+    } else {
+      throw new ParseException(getErrorMessage(key));
+    }
+  }
+
+  private String getErrorMessage(String key) {
+    return "The event does not contain key: %s. Please reconfigure the IOLink 
master to include this key".formatted(
+        key);
+  }
+
+  private InputStream convertByte(byte[] event) {
+    return IOUtils.toInputStream(new String(event), "UTF-8");
+  }
+}
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/sensor/IoLinkSensor.java
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/sensor/IoLinkSensor.java
new file mode 100644
index 000000000..f371aa1e3
--- /dev/null
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/sensor/IoLinkSensor.java
@@ -0,0 +1,29 @@
+/*
+ * 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.iolink.sensor;
+
+import org.apache.streampipes.model.connect.guess.GuessSchema;
+
+import java.util.Map;
+
+public interface IoLinkSensor {
+  GuessSchema getEventSchema();
+
+  Map<String, Object> parseEvent(String encodedEvent);
+}
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/sensor/SensorVVB001.java
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/sensor/SensorVVB001.java
new file mode 100644
index 000000000..61bf36954
--- /dev/null
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/iolink/sensor/SensorVVB001.java
@@ -0,0 +1,162 @@
+/*
+ * 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.iolink.sensor;
+
+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 java.util.HashMap;
+import java.util.Map;
+
+import static 
org.apache.streampipes.sdk.helpers.EpProperties.timestampProperty;
+
+public class SensorVVB001 implements IoLinkSensor {
+
+  public static final String V_RMS_NAME = "vRms";
+  public static final String A_PEAK_NAME = "aPeak";
+  public static final String A_RMS_NAME = "aRms";
+  public static final String TEMPERATURE_NAME = "temperature";
+  public static final String CREST_NAME = "crest";
+  public static final String STATUS_NAME = "status";
+  public static final String OUT_1_NAME = "out1";
+  public static final String OUT_2_NAME = "out2";
+  public static final String PORT_NAME = "port";
+
+  public static final String IO_LINK_MASTER_SN = "ioLinkMasterSN";
+
+
+  @Override
+  public GuessSchema getEventSchema() {
+
+    return GuessSchemaBuilder.create()
+        .property(timestampProperty("timestamp"))
+        .sample("timestamp", 1685525380729L)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Float, V_RMS_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Speed RMS value")
+                .build()
+        )
+        .sample(V_RMS_NAME, 0.0023)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Float, A_PEAK_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Acceleration peak value")
+                .build()
+        )
+        .sample(A_PEAK_NAME, 6.6)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Float, A_RMS_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Acceleration RMS value")
+                .build()
+        )
+        .sample(A_RMS_NAME, 1.8)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Float, TEMPERATURE_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Current temperature")
+                .build()
+        )
+        .sample(TEMPERATURE_NAME, 22.0)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Float, CREST_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Acceleration crest factor")
+                .build()
+        )
+        .sample(CREST_NAME, 3.7)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Integer, STATUS_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Device status (0: OK, 1: Maintenance required, "
+                             + "2: Out of specification, 3: Function Test, 4: 
Error)")
+                .build()
+        )
+        .sample(STATUS_NAME, 0)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Boolean, OUT_1_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Current state of the digital signal")
+                .build()
+        )
+        .sample(OUT_1_NAME, true)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.Boolean, OUT_2_NAME)
+                .scope(PropertyScope.MEASUREMENT_PROPERTY)
+                .description("Current state of the digital signal")
+                .build()
+        )
+        .sample(OUT_2_NAME, true)
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.String, PORT_NAME)
+                .scope(PropertyScope.DIMENSION_PROPERTY)
+                .description("Port the sensor is connected to at IOLink 
master")
+                .build()
+        )
+        .sample(PORT_NAME, "port1")
+        .property(
+            PrimitivePropertyBuilder
+                .create(Datatypes.String, IO_LINK_MASTER_SN)
+                .scope(PropertyScope.DIMENSION_PROPERTY)
+                .description("This is the serial number of the IO-Link Master")
+                .build()
+        )
+        .sample(PORT_NAME, "XXXXXXXXXXXX")
+        .build();
+  }
+
+  @Override
+  public Map<String, Object> parseEvent(String encodedEvent) {
+    var event = new HashMap<String, Object>();
+    event.put(V_RMS_NAME, getValue(0, 4, 0.0001, encodedEvent));
+    event.put(A_PEAK_NAME, getValue(8, 12, 0.1, encodedEvent));
+    event.put(A_RMS_NAME, getValue(16, 20, 0.1, encodedEvent));
+    event.put(TEMPERATURE_NAME, getValue(24, 28, 0.1, encodedEvent));
+    event.put(CREST_NAME, getValue(32, 36, 0.1, encodedEvent));
+    event.put(STATUS_NAME, (int) getValue(38, 39, 1.0, encodedEvent));
+
+    // The last two bits represent the status
+    var outValues = (int) getValue(39, 40, 1.0, encodedEvent);
+    event.put(OUT_1_NAME, (outValues & 1) != 0);
+    event.put(OUT_2_NAME, (outValues & 2) != 0);
+
+    return event;
+  }
+
+  private double getValue(int start, int end, double scaleFactor, String 
encodedEvent) {
+    var word = encodedEvent.substring(start, end);
+
+    var rawValue = (double) (Integer.parseInt(word, 16));
+
+    return rawValue * scaleFactor;
+  }
+}
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/documentation.md
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/documentation.md
new file mode 100644
index 000000000..37c176779
--- /dev/null
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/documentation.md
@@ -0,0 +1,84 @@
+<!--
+  ~ 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.
+  ~
+  -->
+
+## ifm IOLink
+
+<p align="center"> 
+    <img src="icon.png" width="150px;" class="pe-image-documentation"/>
+</p>
+
+***
+
+## Description
+
+This adapter enables the integration of IO-Link sensor data produced by an ifm 
IO-Link Master
+(e.g., AL1350) with Apache StreamPipes. To use this adapter, you need to 
configure your IO-Link
+master to publish events to an MQTT broker. This can be achieved through a 
REST interface or via
+the browser at `http://##IP_OF_IO_LINK_MASTER##/web/subscribe`. For detailed 
instructions,
+please refer to the ifm documentation.
+
+### Requirements
+The JSON events should include the following information:
+- `deviceinfo.serialnumber`
+- Only the pdin value is required for each port (e.g., `port[0]`).
+- The event `timer[1].datachanged` can be used as a trigger.
+Using this adapter, you can create a stream for sensors of the same type.
+
+### Restrictions
+This version supports a single IO-Link master. If you want to connect multiple 
masters, they must have the same setup.
+If you have different requirements, please inform us through the mailing list 
or GitHub discussions.
+
+***
+
+## Configuration
+
+Here is a list of the configuration parameters you must provide.
+
+### Broker URL
+
+Enter the URL of the broker, including the protocol (e.g. 
`tcp://10.20.10.3:1883`)
+
+### Access Mode
+
+If necessary, provide broker credentials.
+
+### Ports
+
+Select the ports that are connected to the IO-Link sensors.
+
+### Sensor Type
+
+Choose the type of sensor you want to connect. (**IMPORTANT:** Currently, only 
the VVB001 is supported)
+
+## Output
+
+The output includes all values from the selected sensor type. Here is an 
example for the `VVB001 sensor`:
+```
+{
+    "aPeak": 6.6,
+    "aRms": 1.8,
+    "crest": 3.7,
+    "out1": true,
+    "out2": true,
+    "port": "000000001234",
+    "status": 0,
+    "temperature": 22,
+    "timestamp": 1685525380729,
+    "vRms": 0.0023
+}
+```
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/icon.png
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/icon.png
new file mode 100644
index 000000000..39c33a25e
Binary files /dev/null and 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/icon.png
 differ
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/strings.en
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/strings.en
new file mode 100644
index 000000000..099298627
--- /dev/null
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/resources/org.apache.streampipes.connect.iiot.adapters.iolink/strings.en
@@ -0,0 +1,50 @@
+#
+# 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.iolink.title=ifm IOLink
+org.apache.streampipes.connect.iiot.adapters.iolink.description=Consumes MQTT 
data produced by an IOLink master of ifm
+
+access-mode.title=Access Mode
+access-mode.description=Provide user credentials for the MQTT broker
+
+anonymous-alternative.title=Unauthenticated
+anonymous-alternative.description=
+
+username-alternative.title=Username/Password
+username-alternative.description=
+
+username-group.title=User Group
+username-group.description=
+
+username.title=Username
+username.description=
+
+password.title=Password
+password.description=
+
+broker_url.title=Broker URL
+broker_url.description=Example: tcp://test-server.com:1883 (Protocol required. 
Port required)"
+
+topic.title=Topic
+topic.description=Example: test/topic
+
+ports.title=Ports
+ports.description=Select the ports with the selected sensor type
+
+sensor_type.title=Sensor Type
+sensor_type.description=Select the sensor type that you want to connect
diff --git 
a/streampipes-extensions/streampipes-connect-adapters-iiot/src/test/java/org/apache/streampipes/sensor/SensorVVB001Test.java
 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/test/java/org/apache/streampipes/sensor/SensorVVB001Test.java
new file mode 100644
index 000000000..199818d51
--- /dev/null
+++ 
b/streampipes-extensions/streampipes-connect-adapters-iiot/src/test/java/org/apache/streampipes/sensor/SensorVVB001Test.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sensor;
+
+import org.apache.streampipes.connect.iiot.adapters.iolink.sensor.SensorVVB001;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class SensorVVB001Test {
+
+  private SensorVVB001 sensor = new SensorVVB001();
+
+  private String sampleInput = "0017FC000042FF000012FF00015CFF000025FF03";
+
+  @Test
+  public void checkEventSize() {
+    var result = sensor.parseEvent(sampleInput);
+    assertEquals(8, result.keySet().size());
+  }
+
+  @Test
+  public void parseEvent() {
+    var result = sensor.parseEvent(sampleInput);
+
+    assertEquals(0.0023, (double) result.get(SensorVVB001.V_RMS_NAME), 0.001);
+    assertEquals(6.600, (double) result.get(SensorVVB001.A_PEAK_NAME), 0.001);
+    assertEquals(1.8, (double) result.get(SensorVVB001.A_RMS_NAME), 0.001);
+    assertEquals(34.8, (double) result.get(SensorVVB001.TEMPERATURE_NAME), 
0.001);
+    assertEquals(3.7, (double) result.get(SensorVVB001.CREST_NAME), 0.001);
+    assertEquals(0, result.get(SensorVVB001.STATUS_NAME));
+    assertEquals(true, result.get(SensorVVB001.OUT_1_NAME));
+    assertEquals(true, result.get(SensorVVB001.OUT_2_NAME));
+  }
+}
\ No newline at end of file


Reply via email to