Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(16146) - AB EIP ready for testing #241

Merged
merged 3 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hivemq-edge/src/frontend/src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@
"publishing": "Publishing",
"http": "HTTP",
"ads": "ADS",
"eip": "Ethernet IP",
"s7advanced": "S7 Device",
"authentication": "Authentication"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ const useGetUiSchema = (isNewAdapter = true) => {
title: t('protocolAdapter.uiSchema.groups.ads'),
properties: ['sourceAmsPort', 'targetAmsPort', 'sourceAmsNetId', 'targetAmsNetId'],
},
{
id: 'eip',
title: t('protocolAdapter.uiSchema.groups.eip'),
properties: ['slot', 'backplane'],
},
{
id: 's7advanced',
title: t('protocolAdapter.uiSchema.groups.s7advanced'),
Expand Down
6 changes: 5 additions & 1 deletion modules/hivemq-edge-module-plc4x/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ dependencies {
implementation("org.apache.plc4x:plc4j-api:${property("org.apache.plc4x.version")}")
implementation("org.apache.plc4x:plc4j-driver-s7:${property("org.apache.plc4x.version")}")
implementation("org.apache.plc4x:plc4j-driver-ads:${property("org.apache.plc4x.version")}")
implementation("org.apache.plc4x:plc4j-driver-ads:${property("org.apache.plc4x.version")}")
implementation("org.apache.plc4x:plc4j-driver-eip:${property("org.apache.plc4x.version")}")
implementation("org.apache.plc4x:plc4j-driver-ab-eth:${property("org.apache.plc4x.version")}")
implementation("org.apache.plc4x:plc4j-transport-raw-socket:${property("org.apache.plc4x.version")}")

// implementation("org.apache.plc4x:plc4j-driver-bacnet:${property("org.apache.plc4x.version")}")
// implementation("org.apache.plc4x:plc4j-driver-profinet:${property("org.apache.plc4x.version")}")
// implementation("org.apache.plc4x:plc4j-driver-eip:${property("org.apache.plc4x.version")}")

runtimeOnly("com.google.guava:guava:${property("guava.version")}") {
exclude("org.checkerframework", "checker-qual")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
public abstract class AbstractPlc4xAdapter<T extends Plc4xAdapterConfig>
extends AbstractPollingPerSubscriptionAdapter<T, ProtocolAdapterDataSample<T>> {

static final String TAG_ADDRESS_TYPE_SEP = ":";
protected static final String TAG_ADDRESS_TYPE_SEP = ":";
private static final Logger log = LoggerFactory.getLogger(Plc4xAdapterConfig.class);
private final static @NotNull PlcDriverManager driverManager = PlcDriverManager.getDefault();
protected final static @NotNull PlcDriverManager driverManager = PlcDriverManager.getDefault();
private final @NotNull Object lock = new Object();
private volatile @Nullable Plc4xConnection connection;
protected volatile @Nullable Plc4xConnection connection;
private final @NotNull Map<String, ProtocolAdapterDataSample<T>> lastSamples = new HashMap<>(1);

public enum ReadType {
Expand All @@ -61,20 +61,7 @@ private Plc4xConnection initConnection() {
if (connection == null) {
try {
log.info("Creating new Instance Of Plc4x Connector with {}", adapterConfig);
connection = new Plc4xConnection<>(driverManager,
adapterConfig,
plc4xAdapterConfig -> Plc4xDataUtils.createQueryString(createQueryStringParams(
plc4xAdapterConfig), true)) {
@Override
protected String getProtocol() {
return getProtocolHandler();
}

@Override
protected String getTagAddressForSubscription(final Plc4xAdapterConfig.Subscription subscription) {
return createTagAddressForSubscription(subscription);
}
};
connection = createConnection();
setConnectionStatus(ConnectionStatus.CONNECTED);
} catch (Plc4xException e) {
throw new RuntimeException(e);
Expand All @@ -85,6 +72,28 @@ protected String getTagAddressForSubscription(final Plc4xAdapterConfig.Subscript
return connection;
}

protected Plc4xConnection<?> createConnection() throws Plc4xException {
return new Plc4xConnection<>(driverManager,
adapterConfig,
plc4xAdapterConfig -> Plc4xDataUtils.createQueryString(createQueryStringParams(
plc4xAdapterConfig), true)) {
@Override
protected String getProtocol() {
return getProtocolHandler();
}

@Override
protected String createConnectionString(final T config) {
return super.createConnectionString(config);
}

@Override
protected String getTagAddressForSubscription(final Plc4xAdapterConfig.Subscription subscription) {
return createTagAddressForSubscription(subscription);
}
};
}

@Override
protected CompletableFuture<ProtocolAdapterStartOutput> startInternal(final @NotNull ProtocolAdapterStartOutput output) {
CompletableFuture<Plc4xConnection<T>> startFuture = CompletableFuture.supplyAsync(() -> initConnection());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public abstract class Plc4xConnection<T extends Plc4xAdapterConfig> {

private static final Logger log = LoggerFactory.getLogger(Plc4xConnection.class);
private final Object lock = new Object();
private final @NotNull PlcDriverManager plcDriverManager;
private final @NotNull T config;
private final @NotNull Plc4xConnectionQueryStringProvider connectionQueryStringProvider;
protected final @NotNull PlcDriverManager plcDriverManager;
protected final @NotNull T config;
protected final @NotNull Plc4xConnectionQueryStringProvider connectionQueryStringProvider;
protected volatile PlcConnection plcConnection;

public Plc4xConnection(final @NotNull PlcDriverManager plcDriverManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,72 @@
*/
package com.hivemq.edge.adapters.plc4x.types.ab;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.hivemq.edge.adapters.plc4x.model.Plc4xAdapterConfig;
import com.hivemq.edge.modules.adapters.annotations.ModuleConfigField;
import com.hivemq.extension.sdk.api.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public class ABAdapterConfig extends Plc4xAdapterConfig {

@JsonProperty("station")
@ModuleConfigField(title = "Station",
description = "IP Address or hostname of the device you wish to connect to",
required = true)
private @NotNull String station;

@JsonProperty("subscriptions")
@ModuleConfigField(title = "Subscriptions",
description = "Map your sensor data to MQTT Topics")
private @NotNull List<? extends Subscription> subscriptions = new ArrayList<>();

public String getStation() {
return station;
}

public enum AB_DATA_TYPE {

WORD((short) 0x03, Short.class),
DWORD((short) 0x04, Integer.class),
INTEGER((short) 0x71, Byte.class);

AB_DATA_TYPE(short code, Class<?> javaType){
this.code = code;
this.javaType = javaType;
}

private short code;
private Class<?> javaType;

public short getCode() {
return code;
}

public Class<?> getJavaType() {
return javaType;
}
}

@JsonPropertyOrder({"tagName", "tagAddress", "dataType", "destination", "qos"})
@JsonIgnoreProperties({"dataType"})
public static class Subscription extends Plc4xAdapterConfig.Subscription {
@JsonProperty("abDataType")
@ModuleConfigField(title = "Data Type",
description = "The expected data type of the tag",
enumDisplayValues = {
"Word (unit 16)",
"DWord (uint 32)",
"Integer (int 16)",
},
required = true)
private @NotNull ABAdapterConfig.AB_DATA_TYPE abDataType;

public ABAdapterConfig.AB_DATA_TYPE getAbDataType() {
return abDataType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,28 @@
package com.hivemq.edge.adapters.plc4x.types.ab;

import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.hivemq.edge.adapters.plc4x.Plc4xException;
import com.hivemq.edge.adapters.plc4x.impl.AbstractPlc4xAdapter;
import com.hivemq.edge.adapters.plc4x.impl.Plc4xConnection;
import com.hivemq.edge.adapters.plc4x.impl.Plc4xDataUtils;
import com.hivemq.edge.adapters.plc4x.model.Plc4xAdapterConfig;
import com.hivemq.edge.adapters.plc4x.model.Plc4xDataType;
import com.hivemq.edge.modules.adapters.annotations.ModuleConfigField;
import com.hivemq.edge.modules.api.adapters.ProtocolAdapterInformation;
import com.hivemq.edge.modules.config.impl.AbstractProtocolAdapterConfig;
import com.hivemq.extension.sdk.api.annotations.NotNull;

import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
Expand All @@ -43,4 +61,48 @@ protected String getProtocolHandler() {
protected ReadType getReadType() {
return ReadType.Read;
}


protected Plc4xConnection<?> createConnection() throws Plc4xException {
return new Plc4xConnection<>(driverManager,
adapterConfig,
plc4xAdapterConfig -> Plc4xDataUtils.createQueryString(createQueryStringParams(
plc4xAdapterConfig), true)) {
@Override
protected String getProtocol() {
return getProtocolHandler();
}

@Override
protected String getTagAddressForSubscription(final Plc4xAdapterConfig.Subscription subscription) {
return createTagAddressForSubscription(subscription);
}

// @Override
// protected String createConnectionString(final @NotNull ABAdapterConfig config){
// String queryString = connectionQueryStringProvider.getConnectionQueryString(config);
// if(queryString != null && !queryString.trim().equals("")){
// return String.format("%s://%s:%s/%s?%s",
// getProtocol().trim(),
// config.getHost().trim(),
// config.getPort(),
// config.getStation().trim(),
// queryString.trim());
// } else {
// return String.format("%s://%s:%s/%s",
// getProtocol().trim(),
// config.getHost().trim(),
// config.getPort(),
// config.getStation().trim());
// }
// }
};
}

/*
The connection string looks as follows: ab-eth://<ip-address>/<station>
The field address: N<file>:<offset></bitnumber>:<datatype>[<numberofbytes>]. The following data types are available at the moment: SINBLEBIT (requires bitnumber to be set), WORD (2 byte integer), DWORD (4 byte integer), INTEGER (returns the number of bytes requested as an array, for other data types <numberofbytes> will be ignored).
Example of a SINGLEBIT read: N10:22/5:SINGLEBIT (file 10, offset 22, bitnumber 5)
Example of a WORD read: N10:84:WORD (file 10, offset 84, 2 byte integer)
*/
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright 2023-present HiveMQ GmbH
*
* Licensed 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 com.hivemq.edge.adapters.plc4x.types.eip;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.hivemq.edge.adapters.plc4x.model.Plc4xAdapterConfig;
import com.hivemq.edge.adapters.plc4x.types.ab.ABAdapterConfig;
import com.hivemq.edge.modules.adapters.annotations.ModuleConfigField;
import com.hivemq.extension.sdk.api.annotations.NotNull;

import java.math.BigInteger;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;


public class EIPAdapterConfig extends Plc4xAdapterConfig {

@JsonProperty("backplane")
@ModuleConfigField(title = "Backplane",
description = "Backplane device value",
required = true)
private @NotNull Integer backplane;

@JsonProperty("slot")
@ModuleConfigField(title = "Slot",
description = "Slot device value",
defaultValue = "0",
required = true)
private @NotNull Integer slot;

@JsonProperty("subscriptions")
@ModuleConfigField(title = "Subscriptions",
description = "Map your sensor data to MQTT Topics")
private @NotNull List<? extends EIPAdapterConfig.Subscription> subscriptions = new ArrayList<>();

public enum EIP_DATA_TYPE {
BOOL((short) 0x01, Boolean.class),
DWORD((short) 0x04, Integer.class),
SINT((short) 0x21, Byte.class),
INT((short) 0x22, Short.class),
DINT((short) 0x23, Integer.class),
LINT((short) 0x24, Long.class),
REAL((short) 0x31, Float.class);

EIP_DATA_TYPE(short code, Class<?> javaType){
this.code = code;
this.javaType = javaType;
}

private short code;
private Class<?> javaType;

public short getCode() {
return code;
}

public Class<?> getJavaType() {
return javaType;
}
}

@JsonPropertyOrder({"tagName", "tagAddress", "dataType", "destination", "qos"})
@JsonIgnoreProperties({"dataType"})
public static class Subscription extends Plc4xAdapterConfig.Subscription {
@JsonProperty("eipDataType")
@ModuleConfigField(title = "Data Type",
description = "The expected data type of the tag",
enumDisplayValues = {
"Boolean (unit 16)",
"DWord (uint 32)",
"SInt (int 16)",
"Integer (int 16)",
"DInt (int 32)",
"LInt (int 64)",
"Real (float 32)",
},
required = true)
private @NotNull EIPAdapterConfig.EIP_DATA_TYPE eipDataType;

public EIPAdapterConfig.EIP_DATA_TYPE getEipDataType() {
return eipDataType;
}
}

public Integer getBackplane() {
return backplane;
}

public Integer getSlot() {
return slot;
}
}
Loading
Loading