Browse Source

Refactoring due to comments

pull/8186/head
Andrii Shvaika 4 years ago
parent
commit
3477ddac0f
  1. 12
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  2. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/AbstractMqttIntegrationTest.java
  3. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestConfigProperties.java
  4. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/AbstractMqttV5ClientSparkplugTest.java
  5. 5
      application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/AbstractMqttV5ClientSparkplugAttributesTest.java
  6. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/MqttV5ClientSparkplugBAttributesInProfileTest.java
  7. 1
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  8. 4
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttDeviceProfileTransportConfiguration.java
  9. 40
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java
  10. 48
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
  11. 14
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java
  12. 29
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugDeviceSessionContext.java
  13. 37
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugNodeSessionHandler.java
  14. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/session/DeviceAwareSessionContext.java
  15. 12
      ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html
  16. 22
      ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts
  17. 4
      ui-ngx/src/app/shared/models/device.models.ts

12
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -47,8 +47,6 @@ import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfigu
import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.device.data.PowerSavingConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
@ -308,8 +306,7 @@ public class DefaultTransportApiService implements TransportApiService {
if (customerId != null && !customerId.isNullUid()) {
metaData.putValue("customerId", customerId.toString());
}
String deviceIdStr = requestMsg.getSparkplug() ? "sparkplugId" : "gatewayId";
metaData.putValue(deviceIdStr, gatewayId.toString());
metaData.putValue("gatewayId", gatewayId.toString());
DeviceId deviceId = device.getId();
ObjectNode entityNode = mapper.valueToTree(device);
@ -320,12 +317,11 @@ public class DefaultTransportApiService implements TransportApiService {
if (deviceAdditionalInfo == null) {
deviceAdditionalInfo = JacksonUtil.newObjectNode();
}
String lastConnectedStr = requestMsg.getSparkplug() ? DataConstants.LAST_CONNECTED_SPARKPLUG : DataConstants.LAST_CONNECTED_GATEWAY;
if (deviceAdditionalInfo.isObject() &&
(!deviceAdditionalInfo.has(lastConnectedStr)
|| !gatewayId.toString().equals(deviceAdditionalInfo.get(lastConnectedStr).asText()))) {
(!deviceAdditionalInfo.has(DataConstants.LAST_CONNECTED_GATEWAY)
|| !gatewayId.toString().equals(deviceAdditionalInfo.get(DataConstants.LAST_CONNECTED_GATEWAY).asText()))) {
ObjectNode newDeviceAdditionalInfo = (ObjectNode) deviceAdditionalInfo;
newDeviceAdditionalInfo.put(lastConnectedStr, gatewayId.toString());
newDeviceAdditionalInfo.put(DataConstants.LAST_CONNECTED_GATEWAY, gatewayId.toString());
Device savedDevice = deviceService.saveDevice(device);
tbClusterService.onDeviceUpdated(savedDevice, device);
}

4
application/src/test/java/org/thingsboard/server/transport/mqtt/AbstractMqttIntegrationTest.java

@ -103,8 +103,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
if (StringUtils.hasLength(config.getAttributesTopicFilter())) {
mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(config.getAttributesTopicFilter());
}
mqttDeviceProfileTransportConfiguration.setSparkPlug(config.isSparkPlug());
mqttDeviceProfileTransportConfiguration.setSparkPlugAttributesMetricNames(config.sparkPlugAttributesMetricNames);
mqttDeviceProfileTransportConfiguration.setSparkplug(config.isSparkplug());
mqttDeviceProfileTransportConfiguration.setSparkplugAttributesMetricNames(config.sparkplugAttributesMetricNames);
mqttDeviceProfileTransportConfiguration.setSendAckOnValidationException(config.isSendAckOnValidationException());
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
if (TransportPayloadType.JSON.equals(transportPayloadType)) {

4
application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestConfigProperties.java

@ -28,8 +28,8 @@ public class MqttTestConfigProperties {
String deviceName;
String gatewayName;
boolean isSparkPlug;
Set<String> sparkPlugAttributesMetricNames;
boolean isSparkplug;
Set<String> sparkplugAttributesMetricNames;
TransportPayloadType transportPayloadType;

6
application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/AbstractMqttV5ClientSparkplugTest.java

@ -95,13 +95,13 @@ public abstract class AbstractMqttV5ClientSparkplugTest extends AbstractMqttInte
//*BIRTH
protected static final MetricDataType metricBirthDataType_Int32 = Int32;
protected static final String metricBirthName_Int32 = "Device Metric int32";
protected Set<String> sparkPlugAttributesMetricNames;
protected Set<String> sparkplugAttributesMetricNames;
public void beforeSparkplugTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.gatewayName("Test Connect Sparkplug client node")
.isSparkPlug(true)
.sparkPlugAttributesMetricNames(sparkPlugAttributesMetricNames)
.isSparkplug(true)
.sparkplugAttributesMetricNames(sparkplugAttributesMetricNames)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.build();
processBeforeTest(configProperties);

5
application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/AbstractMqttV5ClientSparkplugAttributesTest.java

@ -41,11 +41,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopi
@Slf4j
public abstract class AbstractMqttV5ClientSparkplugAttributesTest extends AbstractMqttV5ClientSparkplugTest {
/**
* "sparkPlugAttributesMetricNames": ["SN node", "SN device", "Firmware version", "Date version", "Last date update"]
* @throws Exception
*/
protected void processClientWithCorrectAccessTokenPublishNCMDReBirth() throws Exception {
clientWithCorrectNodeAccessTokenWithNDEATH();
List<String> listKeys = connectionWithNBirth(metricBirthDataType_Int32, metricBirthName_Int32, nextInt32());

4
application/src/test/java/org/thingsboard/server/transport/mqtt/sparkplug/attributes/MqttV5ClientSparkplugBAttributesInProfileTest.java

@ -31,8 +31,8 @@ public class MqttV5ClientSparkplugBAttributesInProfileTest extends AbstractMqttV
@Before
public void beforeTest() throws Exception {
sparkPlugAttributesMetricNames = new HashSet<>();
sparkPlugAttributesMetricNames.add(metricBirthName_Int32);
sparkplugAttributesMetricNames = new HashSet<>();
sparkplugAttributesMetricNames.add(metricBirthName_Int32);
beforeSparkplugTest();
}

1
common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java

@ -120,7 +120,6 @@ public class DataConstants {
public static final String MSG_SOURCE_KEY = "source";
public static final String LAST_CONNECTED_GATEWAY = "lastConnectedGateway";
public static final String LAST_CONNECTED_SPARKPLUG = "lastConnectedSparkplug";
public static final String MAIN_QUEUE_NAME = "Main";
public static final String MAIN_QUEUE_TOPIC = "tb_rule_engine.main";

4
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttDeviceProfileTransportConfiguration.java

@ -29,8 +29,8 @@ public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTra
@NoXss
private String deviceAttributesTopic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC;
private TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
private boolean sparkPlug;
private Set<String> sparkPlugAttributesMetricNames;
private boolean sparkplug;
private Set<String> sparkplugAttributesMetricNames;
private boolean sendAckOnValidationException;
@Override

40
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java

@ -392,21 +392,14 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
int msgId = mqttMsg.variableHeader().packetId();
try {
SparkplugTopic sparkplugTopic = parseTopicPublish(topicName);
String deviceName = sparkplugTopic.isNode() ? deviceSessionCtx.getDeviceInfo().getDeviceName() : sparkplugTopic.getDeviceId();
if (sparkplugTopic.isNode()) {
// A node topic
SparkplugBProto.Payload sparkplugBProtoNode = SparkplugBProto.Payload.parseFrom(ProtoMqttAdaptor.toBytes(mqttMsg.payload()));
switch (sparkplugTopic.getType()) {
case STATE:
// TODO
break;
case NBIRTH:
case NCMD:
case NDATA:
sparkplugSessionHandler.onAttributesTelemetryProto(msgId, sparkplugBProtoNode, deviceName, sparkplugTopic);
break;
case NRECORD:
// TODO
sparkplugSessionHandler.onAttributesTelemetryProto(msgId, sparkplugBProtoNode, deviceSessionCtx.getDeviceInfo().getDeviceName(), sparkplugTopic);
break;
default:
}
@ -414,30 +407,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
// A device topic
SparkplugBProto.Payload sparkplugBProtoDevice = SparkplugBProto.Payload.parseFrom(ProtoMqttAdaptor.toBytes(mqttMsg.payload()));
switch (sparkplugTopic.getType()) {
case STATE:
// TODO
break;
case DBIRTH:
case DCMD:
case DDATA:
sparkplugSessionHandler.onAttributesTelemetryProto(msgId, sparkplugBProtoDevice, deviceName, sparkplugTopic);
sparkplugSessionHandler.onAttributesTelemetryProto(msgId, sparkplugBProtoDevice, sparkplugTopic.getDeviceId(), sparkplugTopic);
break;
/**
* TODO
* 7.3.2. Device Death Certificate (DDEATH)
* The Sparkplug™ Topic Namespace for a device Death Certificate is:
* namespace/group_id/DDEATH/edge_node_id/device_id
* It is the responsibility of the MQTT EoN node to indicate the real-time state of either physical legacy device using
* poll/response protocols and/or local logical devices. If the device becomes unavailable for any reason (no
* response, CRC error, etc.) it is the responsibility of the EoN node to publish a DDEATH on behalf of the end device.
* Immediately upon reception of a DDEATH, any MQTT client subscribed to this device should set the data quality of
* all metrics to “STALE” and should note the time stamp when the DDEATH message was received.
*/
case DDEATH:
sparkplugSessionHandler.onDeviceDisconnect(mqttMsg, deviceName);
break;
case DRECORD:
// TODO
sparkplugSessionHandler.onDeviceDisconnect(mqttMsg, sparkplugTopic.getDeviceId());
break;
default:
}
@ -1084,16 +1060,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
}
/**
* Sparkplug™ Specification Version 2.2
* 7.1.1. EoN Node Death Certificate (NDEATH)
* The Death Certificate topic for an MQTT EoN node is:
* namespace/group_id/NDEATH/edge_node_id
* The Death Certificate topic and payload described here are not “published” as an MQTT message by a client, but
* provided as parameters within the MQTT CONNECT control packet when this MQTT EoN node first establishes the
* MQTT Client session.
*/
private void checkSparkplugNodeSession(MqttConnectMessage connectMessage, ChannelHandlerContext ctx) {
try {
if (sparkplugSessionHandler == null) {

48
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java

@ -83,7 +83,7 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMess
* Created by ashvayka on 19.01.17.
*/
@Slf4j
public abstract class AbstractGatewaySessionHandler {
public abstract class AbstractGatewaySessionHandler<T extends AbstractGatewayDeviceSessionContext> {
protected static final String DEFAULT_DEVICE_TYPE = "default";
private static final String CAN_T_PARSE_VALUE = "Can't parse value: ";
@ -94,8 +94,8 @@ public abstract class AbstractGatewaySessionHandler {
protected final TransportDeviceInfo gateway;
protected final UUID sessionId;
private final ConcurrentMap<String, Lock> deviceCreationLockMap;
private final ConcurrentMap<String, MqttDeviceAwareSessionContext> devices;
private final ConcurrentMap<String, ListenableFuture<MqttDeviceAwareSessionContext>> deviceFutures;
private final ConcurrentMap<String, T> devices;
private final ConcurrentMap<String, ListenableFuture<T>> deviceFutures;
protected final ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap;
protected final ChannelHandlerContext channel;
protected final DeviceSessionCtx deviceSessionCtx;
@ -206,9 +206,9 @@ public abstract class AbstractGatewaySessionHandler {
protected void processOnConnect(MqttPublishMessage msg, String deviceName, String deviceType) {
log.trace("[{}] onDeviceConnect: {}", sessionId, deviceName);
Futures.addCallback(onDeviceConnect(deviceName, deviceType), new FutureCallback<MqttDeviceAwareSessionContext>() {
Futures.addCallback(onDeviceConnect(deviceName, deviceType), new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext result) {
public void onSuccess(@Nullable T result) {
ack(msg, ReturnCode.SUCCESS);
log.trace("[{}] onDeviceConnectOk: {}", sessionId, deviceName);
}
@ -221,8 +221,8 @@ public abstract class AbstractGatewaySessionHandler {
}, context.getExecutor());
}
ListenableFuture<MqttDeviceAwareSessionContext> onDeviceConnect(String deviceName, String deviceType) {
MqttDeviceAwareSessionContext result = devices.get(deviceName);
ListenableFuture<T> onDeviceConnect(String deviceName, String deviceType) {
T result = devices.get(deviceName);
if (result == null) {
Lock deviceCreationLock = deviceCreationLockMap.computeIfAbsent(deviceName, s -> new ReentrantLock());
deviceCreationLock.lock();
@ -241,9 +241,9 @@ public abstract class AbstractGatewaySessionHandler {
}
}
private ListenableFuture<MqttDeviceAwareSessionContext> getDeviceCreationFuture(String deviceName, String deviceType) {
final SettableFuture<MqttDeviceAwareSessionContext> futureToSet = SettableFuture.create();
ListenableFuture<MqttDeviceAwareSessionContext> future = deviceFutures.putIfAbsent(deviceName, futureToSet);
private ListenableFuture<T> getDeviceCreationFuture(String deviceName, String deviceType) {
final SettableFuture<T> futureToSet = SettableFuture.create();
ListenableFuture<T> future = deviceFutures.putIfAbsent(deviceName, futureToSet);
if (future != null) {
return future;
}
@ -258,7 +258,7 @@ public abstract class AbstractGatewaySessionHandler {
new TransportServiceCallback<>() {
@Override
public void onSuccess(GetOrCreateDeviceFromGatewayResponse msg) {
AbstractGatewayDeviceSessionContext deviceSessionCtx = newDeviceSessionCtx(msg);
T deviceSessionCtx = newDeviceSessionCtx(msg);
if (devices.putIfAbsent(deviceName, deviceSessionCtx) == null) {
log.trace("[{}] First got or created device [{}], type [{}] for the gateway session", sessionId, deviceName, deviceType);
SessionInfoProto deviceSessionInfo = deviceSessionCtx.getSessionInfo();
@ -288,7 +288,7 @@ public abstract class AbstractGatewaySessionHandler {
}
}
protected abstract AbstractGatewayDeviceSessionContext newDeviceSessionCtx(GetOrCreateDeviceFromGatewayResponse msg);
protected abstract T newDeviceSessionCtx(GetOrCreateDeviceFromGatewayResponse msg);
protected int getMsgId(MqttPublishMessage mqttMsg) {
return mqttMsg.variableHeader().packetId();
@ -341,7 +341,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
if (!deviceEntry.getValue().isJsonArray()) {
throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
}
@ -375,7 +375,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
TransportProtos.PostTelemetryMsg msg = telemetryMsg.getMsg();
try {
TransportProtos.PostTelemetryMsg postTelemetryMsg = ProtoConverter.validatePostTelemetryMsg(msg.toByteArray());
@ -425,7 +425,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
if (!deviceEntry.getValue().isJsonObject()) {
throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
}
@ -459,7 +459,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
TransportApiProtos.ClaimDevice claimRequest = claimDeviceMsg.getClaimRequest();
if (claimRequest == null) {
throw new IllegalArgumentException("Claim request for device: " + deviceName + " is null!");
@ -501,7 +501,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
if (!deviceEntry.getValue().isJsonObject()) {
throw new JsonSyntaxException(CAN_T_PARSE_VALUE + json);
}
@ -530,7 +530,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
TransportProtos.PostAttributeMsg kvListProto = attributesMsg.getMsg();
if (kvListProto == null) {
throw new IllegalArgumentException("Attributes List for device: " + deviceName + " is empty!");
@ -609,7 +609,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
Integer requestId = jsonObj.get("id").getAsInt();
String data = jsonObj.get("data").toString();
TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
@ -634,7 +634,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
Integer requestId = gatewayRpcResponseMsg.getId();
String data = gatewayRpcResponseMsg.getData();
TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
@ -661,7 +661,7 @@ public abstract class AbstractGatewaySessionHandler {
Futures.addCallback(checkDeviceConnected(deviceName),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable MqttDeviceAwareSessionContext deviceCtx) {
public void onSuccess(@Nullable T deviceCtx) {
transportService.process(deviceCtx.getSessionInfo(), requestMsg, getPubAckCallback(channel, deviceName, msgId, requestMsg));
}
@ -685,8 +685,8 @@ public abstract class AbstractGatewaySessionHandler {
return result.build();
}
protected ListenableFuture<MqttDeviceAwareSessionContext> checkDeviceConnected(String deviceName) {
MqttDeviceAwareSessionContext ctx = devices.get(deviceName);
protected ListenableFuture<T> checkDeviceConnected(String deviceName) {
T ctx = devices.get(deviceName);
if (ctx == null) {
log.debug("[{}] Missing device [{}] for the gateway session", sessionId, deviceName);
return onDeviceConnect(deviceName, DEFAULT_DEVICE_TYPE);
@ -729,7 +729,6 @@ public abstract class AbstractGatewaySessionHandler {
private void deregisterSession(String deviceName, MqttDeviceAwareSessionContext deviceSessionCtx) {
if (this.deviceSessionCtx.isSparkplug()) {
// add Msg Telemetry: key STATE type: String value: OFFLINE ts: sparkplugBProto.getTimestamp()
sendSparkplugStateOnTelemetry(deviceSessionCtx.getSessionInfo(),
deviceSessionCtx.getDeviceInfo().getDeviceName(), OFFLINE, new Date().getTime());
}
@ -744,7 +743,6 @@ public abstract class AbstractGatewaySessionHandler {
keyValueProtoBuilder.setType(TransportProtos.KeyValueType.STRING_V);
keyValueProtoBuilder.setStringV(connectionState.name());
TransportProtos.PostTelemetryMsg postTelemetryMsg = postTelemetryMsgCreated(keyValueProtoBuilder.build(), ts);
transportService.process(sessionInfo, postTelemetryMsg, getPubAckCallback(channel, deviceName, -1, postTelemetryMsg));
}

14
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java

@ -32,30 +32,16 @@ import java.util.stream.Collectors;
public abstract class MqttDeviceAwareSessionContext extends DeviceAwareSessionContext {
private final ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap;
private Map<String, SparkplugBProto.Payload.Metric> deviceBirthMetrics;
public MqttDeviceAwareSessionContext(UUID sessionId, ConcurrentMap<MqttTopicMatcher, Integer> mqttQoSMap) {
super(sessionId);
this.mqttQoSMap = mqttQoSMap;
this.deviceBirthMetrics = null;
}
public ConcurrentMap<MqttTopicMatcher, Integer> getMqttQoSMap() {
return mqttQoSMap;
}
public Map<String, SparkplugBProto.Payload.Metric> getDeviceBirthMetrics() {
return deviceBirthMetrics;
}
public void setDeviceBirthMetrics(java.util.List<org.thingsboard.server.gen.transport.mqtt.SparkplugBProto.Payload.Metric> metrics) {
if (this.deviceBirthMetrics == null) {
this.deviceBirthMetrics = new ConcurrentHashMap<>();
}
this.deviceBirthMetrics.putAll(metrics.stream()
.collect(Collectors.toMap(metric -> metric.getName(), metric -> metric)));
}
public MqttQoS getQoSForTopic(String topic) {
List<Integer> qosList = mqttQoSMap.entrySet()
.stream()

29
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugDeviceSessionContext.java

@ -23,19 +23,25 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.mqtt.SparkplugBProto;
import org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMessageType;
import org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugRpcRequestHeader;
import org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopic;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMetricUtil.getTsKvProto;
@Slf4j
public class SparkplugDeviceSessionContext extends AbstractGatewayDeviceSessionContext<SparkplugNodeSessionHandler> {
private final Map<String, SparkplugBProto.Payload.Metric> deviceBirthMetrics = new ConcurrentHashMap<>();
public SparkplugDeviceSessionContext(SparkplugNodeSessionHandler parent,
TransportDeviceInfo deviceInfo,
DeviceProfile deviceProfile,
@ -45,6 +51,16 @@ public class SparkplugDeviceSessionContext extends AbstractGatewayDeviceSessionC
super(parent, deviceInfo, deviceProfile, mqttQoSMap, transportService);
}
public Map<String, SparkplugBProto.Payload.Metric> getDeviceBirthMetrics() {
return deviceBirthMetrics;
}
public void setDeviceBirthMetrics(java.util.List<org.thingsboard.server.gen.transport.mqtt.SparkplugBProto.Payload.Metric> metrics) {
this.deviceBirthMetrics.putAll(metrics.stream()
.collect(Collectors.toMap(SparkplugBProto.Payload.Metric::getName, metric -> metric)));
}
@Override
public void onAttributeUpdate(UUID sessionId, TransportProtos.AttributeUpdateNotificationMsg notification) {
log.trace("[{}] Received attributes update notification to sparkplug device", sessionId);
@ -64,20 +80,7 @@ public class SparkplugDeviceSessionContext extends AbstractGatewayDeviceSessionC
public void onToDeviceRpcRequest(UUID sessionId, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) {
log.trace("[{}] Received RPC Request notification to sparkplug device", sessionId);
try {
/**
* DCMD {"metricName":"MyDeviceMetricText","value":"MyNodeMetric05_String_Value"}
* DCMD {"metricName":"MyNodeMetric02_LongInt64","value":2814119464032075444}
* DCMD {"metricName":"MyNodeMetric03_Double","value":6336935578763180333}
* DCMD {"metricName":"MyNodeMetric04_Float","value":413.18222}
* DCMD {"metricName":"Node Control/Rebirth","value":false}
* DCMD {"metricName":"MyNodeMetric06_Json_Bytes", "value":[40,47,-49]}
*/
SparkplugMessageType messageType = SparkplugMessageType.parseMessageType(rpcRequest.getMethodName());
if (messageType == null) {
parent.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(),
ThingsboardErrorCode.INVALID_ARGUMENTS, "Unsupported SparkplugMessageType: " + rpcRequest.getMethodName() + rpcRequest.getParams());
return;
}
SparkplugRpcRequestHeader header = JacksonUtil.fromString(rpcRequest.getParams(), SparkplugRpcRequestHeader.class);
header.setMessageType(messageType.name());
TransportProtos.TsKvProto tsKvProto = getTsKvProto(header.getMetricName(), header.getValue(), new Date().getTime());

37
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/SparkplugNodeSessionHandler.java

@ -18,6 +18,7 @@ package org.thingsboard.server.transport.mqtt.session;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.google.protobuf.Descriptors;
@ -65,7 +66,7 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugTopi
* Created by nickAS21 on 12.12.22
*/
@Slf4j
public class SparkplugNodeSessionHandler extends AbstractGatewaySessionHandler {
public class SparkplugNodeSessionHandler extends AbstractGatewaySessionHandler<SparkplugDeviceSessionContext> {
private final SparkplugTopic sparkplugTopicNode;
private final Map<String, SparkplugBProto.Payload.Metric> nodeBirthMetrics;
@ -81,7 +82,7 @@ public class SparkplugNodeSessionHandler extends AbstractGatewaySessionHandler {
public void setNodeBirthMetrics(java.util.List<org.thingsboard.server.gen.transport.mqtt.SparkplugBProto.Payload.Metric> metrics) {
this.nodeBirthMetrics.putAll(metrics.stream()
.collect(Collectors.toMap(metric -> metric.getName(), metric -> metric)));
.collect(Collectors.toMap(SparkplugBProto.Payload.Metric::getName, metric -> metric)));
}
public Map<String, SparkplugBProto.Payload.Metric> getNodeBirthMetrics() {
@ -102,24 +103,28 @@ public class SparkplugNodeSessionHandler extends AbstractGatewaySessionHandler {
public void onAttributesTelemetryProto(int msgId, SparkplugBProto.Payload sparkplugBProto, String deviceName, SparkplugTopic topic) throws AdaptorException, ThingsboardException {
checkDeviceName(deviceName);
ListenableFuture<MqttDeviceAwareSessionContext> contextListenableFuture = topic.isNode() ?
Futures.immediateFuture(this.deviceSessionCtx) : onDeviceConnectProto(deviceName);
try {
if (topic.isType(NBIRTH) || topic.isType(DBIRTH)) {
// add Msg Telemetry: key STATE type: String value: ONLINE ts: sparkplugBProto.getTimestamp()
sendSparkplugStateOnTelemetry(contextListenableFuture.get().getSessionInfo(), deviceName, ONLINE,
sparkplugBProto.getTimestamp());
}
ListenableFuture<MqttDeviceAwareSessionContext> contextListenableFuture;
if (topic.isNode()) {
if (topic.isType(NBIRTH)) {
sendSparkplugStateOnTelemetry(this.deviceSessionCtx.getSessionInfo(), deviceName, ONLINE,
sparkplugBProto.getTimestamp());
setNodeBirthMetrics(sparkplugBProto.getMetricsList());
} else if (topic.isType(DBIRTH)) {
contextListenableFuture.get().setDeviceBirthMetrics(sparkplugBProto.getMetricsList());
}
} catch (InterruptedException | ExecutionException e) {
log.error("Failed add Metrics or change SparkplugConnectionState. MessageType *BIRTH.", e);
contextListenableFuture = Futures.immediateFuture(this.deviceSessionCtx);
} else {
ListenableFuture<SparkplugDeviceSessionContext> deviceCtx = onDeviceConnectProto(deviceName);
contextListenableFuture = Futures.transform(deviceCtx, ctx -> {
if (topic.isType(DBIRTH)) {
sendSparkplugStateOnTelemetry(ctx.getSessionInfo(), deviceName, ONLINE,
sparkplugBProto.getTimestamp());
ctx.setDeviceBirthMetrics(sparkplugBProto.getMetricsList());
}
return ctx;
}, MoreExecutors.directExecutor());
}
Set<String> attributesMetricNames = ((MqttDeviceProfileTransportConfiguration) deviceSessionCtx
.getDeviceProfile().getProfileData().getTransportConfiguration()).getSparkPlugAttributesMetricNames();
.getDeviceProfile().getProfileData().getTransportConfiguration()).getSparkplugAttributesMetricNames();
if (attributesMetricNames != null) {
List<TransportApiProtos.AttributesMsg> attributesMsgList = convertToPostAttributes(sparkplugBProto, attributesMetricNames, deviceName);
onDeviceAttributesProto(contextListenableFuture, msgId, attributesMsgList, deviceName);
@ -213,7 +218,7 @@ public class SparkplugNodeSessionHandler extends AbstractGatewaySessionHandler {
}
}
private ListenableFuture<MqttDeviceAwareSessionContext> onDeviceConnectProto(String deviceName) throws ThingsboardException {
private ListenableFuture<SparkplugDeviceSessionContext> onDeviceConnectProto(String deviceName) throws ThingsboardException {
try {
String deviceType = this.gateway.getDeviceType() + "-node";
return onDeviceConnect(deviceName, deviceType);

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/session/DeviceAwareSessionContext.java

@ -87,7 +87,7 @@ public abstract class DeviceAwareSessionContext implements SessionContext {
public boolean isSparkplug() {
DeviceProfileTransportConfiguration transportConfiguration = this.deviceProfile.getProfileData().getTransportConfiguration();
if (transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) {
return ((MqttDeviceProfileTransportConfiguration) transportConfiguration).isSparkPlug();
return ((MqttDeviceProfileTransportConfiguration) transportConfiguration).isSparkplug();
} else {
return false;
}

12
ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.html

@ -16,17 +16,17 @@
-->
<form [formGroup]="mqttDeviceProfileTransportConfigurationFormGroup" style="padding-top: 8px;">
<mat-checkbox formControlName="sparkPlug">
<mat-checkbox formControlName="sparkplug">
{{ 'device-profile.mqtt-device-topic-filters-spark-plug' | translate }}
</mat-checkbox>
<div *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').value"
<div *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').value"
class="tb-hint" innerHTML="{{ 'device-profile.mqtt-device-topic-filters-spark-plug-hint' | translate }}"></div>
<mat-form-field floatLabel="always" class="mat-block" style="padding-top: 8px;"
*ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').value">
*ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').value">
<mat-label translate>device-profile.mqtt-device-topic-filters-spark-plug-attribute-metric-names</mat-label>
<mat-chip-list #attrMetricNamesChipList formControlName="sparkPlugAttributesMetricNames">
<mat-chip-list #attrMetricNamesChipList formControlName="sparkplugAttributesMetricNames">
<mat-chip
*ngFor="let name of mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlugAttributesMetricNames').value;"
*ngFor="let name of mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplugAttributesMetricNames').value;"
(removed)="removeAttributeMetricName(name)">
{{name}}
<mat-icon matChipRemove>close</mat-icon>
@ -40,7 +40,7 @@
<mat-hint innerHTML="{{ 'device-profile.mqtt-device-topic-filters-spark-plug-attribute-metric-names-hint' | translate }}"></mat-hint>
</mat-form-field>
</form>
<form [formGroup]="mqttDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;" *ngIf="!mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').value">
<form [formGroup]="mqttDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;" *ngIf="!mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').value">
<fieldset class="fields-group">
<legend class="group-title" translate>device-profile.mqtt-device-topic-filters</legend>
<div fxLayoutGap="8px" fxLayout="column">

22
ui-ngx/src/app/modules/home/components/profile/device/mqtt-device-profile-transport-configuration.component.ts

@ -96,8 +96,8 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
this.mqttDeviceProfileTransportConfigurationFormGroup = this.fb.group({
deviceAttributesTopic: [null, [Validators.required, this.validationMQTTTopic()]],
deviceTelemetryTopic: [null, [Validators.required, this.validationMQTTTopic()]],
sparkPlug: [false],
sparkPlugAttributesMetricNames: [null],
sparkplug: [false],
sparkplugAttributesMetricNames: [null],
sendAckOnValidationException: [false, Validators.required],
transportPayloadTypeConfiguration: this.fb.group({
transportPayloadType: [TransportPayloadType.JSON, Validators.required],
@ -123,13 +123,13 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
.patchValue(false, {emitEvent: false});
}
});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').valueChanges.pipe(
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value) => {
if (value) {
this.mqttDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').enable({emitEvent: false});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlugAttributesMetricNames').enable({emitEvent: false});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').enable({emitEvent: false});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplugAttributesMetricNames').enable({emitEvent: false});
} else {
this.mqttDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
}
@ -152,7 +152,7 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
this.mqttDeviceProfileTransportConfigurationFormGroup.disable({emitEvent: false});
} else {
this.mqttDeviceProfileTransportConfigurationFormGroup.enable({emitEvent: false});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').updateValueAndValidity({onlySelf: true});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').updateValueAndValidity({onlySelf: true});
}
}
@ -170,17 +170,17 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
this.mqttDeviceProfileTransportConfigurationFormGroup.patchValue(value, {emitEvent: false});
this.updateTransportPayloadBasedControls(value.transportPayloadTypeConfiguration?.transportPayloadType);
if (!this.disabled) {
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlug').updateValueAndValidity({onlySelf: true});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplug').updateValueAndValidity({onlySelf: true});
}
}
}
removeAttributeMetricName(name: string): void {
const names: string[] = this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlugAttributesMetricNames').value;
const names: string[] = this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplugAttributesMetricNames').value;
const index = names.indexOf(name);
if (index >= 0) {
names.splice(index, 1);
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlugAttributesMetricNames').setValue(names);
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplugAttributesMetricNames').setValue(names);
}
}
@ -189,13 +189,13 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
let value = event.value;
if ((value || '').trim()) {
value = value.trim();
let names: string[] = this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlugAttributesMetricNames').value;
let names: string[] = this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplugAttributesMetricNames').value;
if (!names || names.indexOf(value) === -1) {
if (!names) {
names = [];
}
names.push(value);
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkPlugAttributesMetricNames').setValue(names, {emitEvent: true});
this.mqttDeviceProfileTransportConfigurationFormGroup.get('sparkplugAttributesMetricNames').setValue(names, {emitEvent: true});
}
}
if (input) {

4
ui-ngx/src/app/shared/models/device.models.ts

@ -242,7 +242,7 @@ export interface DefaultDeviceProfileTransportConfiguration {
export interface MqttDeviceProfileTransportConfiguration {
deviceTelemetryTopic?: string;
deviceAttributesTopic?: string;
sparkPlug?: boolean;
sparkplug?: boolean;
sendAckOnValidationException?: boolean;
transportPayloadTypeConfiguration?: {
transportPayloadType?: TransportPayloadType;
@ -360,7 +360,7 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
const mqttTransportConfiguration: MqttDeviceProfileTransportConfiguration = {
deviceTelemetryTopic: 'v1/devices/me/telemetry',
deviceAttributesTopic: 'v1/devices/me/attributes',
sparkPlug: false,
sparkplug: false,
sendAckOnValidationException: false,
transportPayloadTypeConfiguration: {
transportPayloadType: TransportPayloadType.JSON,

Loading…
Cancel
Save