|
|
|
@ -20,8 +20,10 @@ import org.thingsboard.rule.engine.api.TbContext; |
|
|
|
import org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode; |
|
|
|
import org.thingsboard.server.common.data.DataConstants; |
|
|
|
import org.thingsboard.server.common.data.Device; |
|
|
|
import org.thingsboard.server.common.data.DeviceProfile; |
|
|
|
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; |
|
|
|
import org.thingsboard.server.common.data.id.DeviceId; |
|
|
|
import org.thingsboard.server.common.data.id.DeviceProfileId; |
|
|
|
import org.thingsboard.server.common.data.id.EntityId; |
|
|
|
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|
|
|
import org.thingsboard.server.common.data.kv.KvEntry; |
|
|
|
@ -40,20 +42,44 @@ import java.util.Set; |
|
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
|
import java.util.concurrent.ConcurrentMap; |
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
class DeviceState { |
|
|
|
|
|
|
|
private final DeviceId deviceId; |
|
|
|
private DeviceProfileState deviceProfile; |
|
|
|
private DeviceDataSnapshot latestValues; |
|
|
|
private final ConcurrentMap<String, DeviceProfileAlarmState> alarmStates = new ConcurrentHashMap<>(); |
|
|
|
|
|
|
|
public DeviceState(DeviceProfileState deviceProfile) { |
|
|
|
public DeviceState(DeviceId deviceId, DeviceProfileState deviceProfile) { |
|
|
|
this.deviceId = deviceId; |
|
|
|
this.deviceProfile = deviceProfile; |
|
|
|
} |
|
|
|
|
|
|
|
public void updateProfile(TbContext ctx, DeviceProfile deviceProfile) throws ExecutionException, InterruptedException { |
|
|
|
Set<EntityKey> oldKeys = this.deviceProfile.getEntityKeys(); |
|
|
|
this.deviceProfile.updateDeviceProfile(deviceProfile); |
|
|
|
if (latestValues != null) { |
|
|
|
Set<EntityKey> keysToFetch = new HashSet<>(this.deviceProfile.getEntityKeys()); |
|
|
|
keysToFetch.removeAll(oldKeys); |
|
|
|
if (!keysToFetch.isEmpty()) { |
|
|
|
addEntityKeysToSnapshot(ctx, deviceId, keysToFetch, latestValues); |
|
|
|
} |
|
|
|
} |
|
|
|
Set<String> newAlarmStateIds = this.deviceProfile.getAlarmSettings().stream().map(DeviceProfileAlarm::getId).collect(Collectors.toSet()); |
|
|
|
alarmStates.keySet().removeIf(id -> !newAlarmStateIds.contains(id)); |
|
|
|
for (DeviceProfileAlarm alarm : this.deviceProfile.getAlarmSettings()) { |
|
|
|
if (alarmStates.containsKey(alarm.getId())) { |
|
|
|
alarmStates.get(alarm.getId()).updateState(alarm); |
|
|
|
} else { |
|
|
|
alarmStates.putIfAbsent(alarm.getId(), new DeviceProfileAlarmState(deviceId, alarm)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void process(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { |
|
|
|
if (latestValues == null) { |
|
|
|
latestValues = fetchLatestValues(ctx, msg.getOriginator()); |
|
|
|
latestValues = fetchLatestValues(ctx, deviceId); |
|
|
|
} |
|
|
|
if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) { |
|
|
|
processTelemetry(ctx, msg); |
|
|
|
@ -69,7 +95,7 @@ class DeviceState { |
|
|
|
List<KvEntry> data = entry.getValue(); |
|
|
|
latestValues = merge(latestValues, ts, data); |
|
|
|
for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) { |
|
|
|
DeviceProfileAlarmState alarmState = alarmStates.computeIfAbsent(alarm.getId(), a -> new DeviceProfileAlarmState(msg.getOriginator(), alarm)); |
|
|
|
DeviceProfileAlarmState alarmState = alarmStates.computeIfAbsent(alarm.getId(), a -> new DeviceProfileAlarmState(deviceId, alarm)); |
|
|
|
alarmState.process(ctx, msg, latestValues); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -85,8 +111,13 @@ class DeviceState { |
|
|
|
} |
|
|
|
|
|
|
|
private DeviceDataSnapshot fetchLatestValues(TbContext ctx, EntityId originator) throws ExecutionException, InterruptedException { |
|
|
|
DeviceDataSnapshot result = new DeviceDataSnapshot(deviceProfile.getEntityKeys()); |
|
|
|
Set<EntityKey> entityKeysToFetch = deviceProfile.getEntityKeys(); |
|
|
|
DeviceDataSnapshot result = new DeviceDataSnapshot(entityKeysToFetch); |
|
|
|
addEntityKeysToSnapshot(ctx, originator, entityKeysToFetch, result); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
private void addEntityKeysToSnapshot(TbContext ctx, EntityId originator, Set<EntityKey> entityKeysToFetch, DeviceDataSnapshot result) throws InterruptedException, ExecutionException { |
|
|
|
Set<String> serverAttributeKeys = new HashSet<>(); |
|
|
|
Set<String> clientAttributeKeys = new HashSet<>(); |
|
|
|
Set<String> sharedAttributeKeys = new HashSet<>(); |
|
|
|
@ -94,7 +125,7 @@ class DeviceState { |
|
|
|
Set<String> latestTsKeys = new HashSet<>(); |
|
|
|
|
|
|
|
Device device = null; |
|
|
|
for (EntityKey entityKey : deviceProfile.getEntityKeys()) { |
|
|
|
for (EntityKey entityKey : entityKeysToFetch) { |
|
|
|
String key = entityKey.getKey(); |
|
|
|
switch (entityKey.getType()) { |
|
|
|
case SERVER_ATTRIBUTE: |
|
|
|
@ -159,8 +190,6 @@ class DeviceState { |
|
|
|
addToSnapshot(result, commonAttributeKeys, |
|
|
|
ctx.getAttributesService().find(ctx.getTenantId(), originator, DataConstants.SERVER_SCOPE, serverAttributeKeys).get()); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
private void addToSnapshot(DeviceDataSnapshot snapshot, Set<String> commonAttributeKeys, List<AttributeKvEntry> data) { |
|
|
|
@ -192,4 +221,8 @@ class DeviceState { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public DeviceProfileId getProfileId() { |
|
|
|
return deviceProfile.getProfileId(); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|