/**
* Copyright © 2017 The Thingsboard Authors
*
* 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 org.thingsboard.gateway.extensions.opc;
import lombok.Data;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.thingsboard.gateway.extensions.opc.conf.mapping.AttributesMapping;
import org.thingsboard.gateway.extensions.opc.conf.mapping.DeviceMapping;
import org.thingsboard.gateway.extensions.common.conf.mapping.KVMapping;
import org.thingsboard.gateway.extensions.opc.conf.mapping.TimeseriesMapping;
import org.thingsboard.server.common.data.kv.*;
import java.util.*;
import java.util.stream.Collectors;
/**
* Created by ashvayka on 16.01.17.
*/
@Data
public class OpcUaDevice {
private final NodeId nodeId;
private final DeviceMapping mapping;
private final Map<String, NodeId> tagKeysMap = new HashMap<>();
private final Map<NodeId, String> tagIdsMap = new HashMap<>();
private final Map<String, String> tagValues = new HashMap<>();
private final Map<NodeId, List<AttributesMapping>> attributesMap = new HashMap<>();
private final Map<NodeId, List<TimeseriesMapping>> timeseriesMap = new HashMap<>();
private String deviceName;
private long scanTs;
public Map<String, NodeId> registerTags(Map<String, NodeId> newTagMap) {
Map<String, NodeId> newTags = new HashMap<>();
for (Map.Entry<String, NodeId> kv : newTagMap.entrySet()) {
NodeId old = registerTag(kv);
if (old == null) {
newTags.put(kv.getKey(), kv.getValue());
}
}
return newTags;
}
private NodeId registerTag(Map.Entry<String, NodeId> kv) {
String tag = kv.getKey();
NodeId tagId = kv.getValue();
mapping.getAttributes().stream()
.filter(attr -> attr.getValue().contains(escape(tag)))
.forEach(attr -> attributesMap.computeIfAbsent(tagId, key -> new ArrayList<>()).add(attr));
mapping.getTimeseries().stream()
.filter(attr -> attr.getValue().contains(escape(tag)))
.forEach(attr -> timeseriesMap.computeIfAbsent(tagId, key -> new ArrayList<>()).add(attr));
tagIdsMap.putIfAbsent(kv.getValue(), kv.getKey());
return tagKeysMap.put(kv.getKey(), kv.getValue());
}
public void calculateDeviceName(Map<String, String> deviceNameTagValues) {
String deviceNameTmp = mapping.getDeviceNamePattern();
for (Map.Entry<String, String> kv : deviceNameTagValues.entrySet()) {
deviceNameTmp = deviceNameTmp.replace(escape(kv.getKey()), kv.getValue());
}
this.deviceName = deviceNameTmp;
}
public void updateTag(NodeId tagId, DataValue dataValue) {
String tag = tagIdsMap.get(tagId);
tagValues.put(tag, dataValue.getValue().getValue().toString());
}
public void updateScanTs() {
scanTs = System.currentTimeMillis();
}
private List<AttributesMapping> getAttributesMapping(NodeId tag) {
return attributesMap.getOrDefault(tag, Collections.emptyList());
}
private List<TimeseriesMapping> getTimeseriesMapping(NodeId tag) {
return timeseriesMap.getOrDefault(tag, Collections.emptyList());
}
private String escape(String tag) {
return "${" + tag + "}";
}
public List<KvEntry> getAffectedAttributes(NodeId tagId, DataValue dataValue) {
List<AttributesMapping> attributes = getAttributesMapping(tagId);
if (attributes.size() > 0) {
return getKvEntries(attributes);
} else {
return Collections.emptyList();
}
}
public List<TsKvEntry> getAffectedTimeseries(NodeId tagId, DataValue dataValue) {
List<AttributesMapping> attributes = getAttributesMapping(tagId);
if (attributes.size() > 0) {
return getKvEntries(attributes).stream()
.map(kv -> new BasicTsKvEntry(dataValue.getSourceTime().getJavaTime(), kv))
.collect(Collectors.toList());
} else {
return Collections.emptyList();
}
}
private List<KvEntry> getKvEntries(List<? extends KVMapping> mappings) {
List<KvEntry> result = new ArrayList<>();
for (KVMapping mapping : mappings) {
String strVal = mapping.getValue();
for (Map.Entry<String, String> tagKV : tagValues.entrySet()) {
strVal = strVal.replace(escape(tagKV.getKey()), tagKV.getValue());
}
switch (mapping.getType().getDataType()) {
case STRING:
result.add(new StringDataEntry(mapping.getKey(), strVal));
break;
case BOOLEAN:
result.add(new BooleanDataEntry(mapping.getKey(), Boolean.valueOf(strVal)));
break;
case DOUBLE:
result.add(new DoubleDataEntry(mapping.getKey(), Double.valueOf(strVal)));
break;
case LONG:
result.add(new LongDataEntry(mapping.getKey(), Long.valueOf(strVal)));
break;
}
}
return result;
}
}