a-tuoheng-device/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java

202 lines
7.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ruoyi.device.domain.impl;
import com.ruoyi.device.domain.api.IThingsBoardDomain;
import com.ruoyi.device.domain.model.thingsboard.*;
import com.ruoyi.device.domain.model.thingsboard.constants.DeviceAttributes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.thingsboard.rest.client.RestClient;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* ThingsBoard设备服务实现类
*/
@Component
public class ThingsBoardDomainImpl implements IThingsBoardDomain {
private static final Logger log = LoggerFactory.getLogger(ThingsBoardDomainImpl.class);
private final RestClient client;
private final int pageSize;
/**
* 构造函数 - Spring 会自动装配
* @param clientManager RestClient 管理器
* @param pageSize 分页大小,从配置文件读取,默认值为 10
*/
public ThingsBoardDomainImpl(RestClientManager clientManager,
@Value("${thingsboard.page-size:10}") int pageSize) {
this.client = clientManager.getClient();
this.pageSize = pageSize;
}
@Override
public Iterable<List<DeviceInfo>> getAllDevices() {
return new DeviceIterator(client, pageSize);
}
@Override
public AttributeMap getDeviceAttributes(String deviceId) {
AttributeMap attributeMap = new AttributeMap();
try {
DeviceId id = new DeviceId(UUID.fromString(deviceId));
// 获取所有属性键
List<String> attributeKeys = client.getAttributeKeys(id);
if (attributeKeys == null || attributeKeys.isEmpty()) {
log.debug("设备 {} 没有属性", deviceId);
return attributeMap;
}
// 获取属性值
List<AttributeKvEntry> attributeKvEntries = client.getAttributeKvEntries(id, attributeKeys);
if (attributeKvEntries == null || attributeKvEntries.isEmpty()) {
log.debug("设备 {} 的属性值为空", deviceId);
return attributeMap;
}
// 解析并填充到AttributeMap
for (AttributeKvEntry entry : attributeKvEntries) {
parseAndPutAttribute(attributeMap, entry);
}
} catch (Exception e) {
log.error("获取设备属性失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
return attributeMap;
}
@Override
public TelemetryMap getDeviceTelemetry(String deviceId) {
TelemetryMap telemetryMap = new TelemetryMap();
try {
DeviceId id = new DeviceId(UUID.fromString(deviceId));
// 获取所有遥测键
List<String> timeseriesKeys = client.getTimeseriesKeys(id);
if (timeseriesKeys == null || timeseriesKeys.isEmpty()) {
log.debug("设备 {} 没有遥测数据", deviceId);
return telemetryMap;
}
// 获取最新的遥测数据
List<TsKvEntry> latestTimeseries = client.getLatestTimeseries(id, timeseriesKeys);
if (latestTimeseries == null || latestTimeseries.isEmpty()) {
log.debug("设备 {} 的遥测数据为空", deviceId);
return telemetryMap;
}
// 解析并填充到TelemetryMap
for (TsKvEntry entry : latestTimeseries) {
parseAndPutTelemetry(telemetryMap, entry);
}
} catch (Exception e) {
log.error("获取设备遥测数据失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
return telemetryMap;
}
/**
* 解析属性并添加到AttributeMap
* 使用延迟注册机制,自动处理所有属性
*/
@SuppressWarnings("unchecked")
private void parseAndPutAttribute(AttributeMap attributeMap, AttributeKvEntry entry) {
String keyName = entry.getKey();
Object value = entry.getValue();
try {
// 使用延迟注册机制:如果键不存在则自动创建
AttributeKey<?> key = AttributeKey.getOrCreate(keyName, value);
// 使用键的解析器解析值
Object parsedValue = ((AttributeKey<Object>) key).parse(value);
attributeMap.put((AttributeKey<Object>) key, parsedValue);
log.debug("成功解析属性: {} = {} (type: {})", keyName, parsedValue, key.getType().getSimpleName());
} catch (Exception e) {
log.warn("解析属性失败: key={}, value={}, error={}", keyName, value, e.getMessage());
}
}
/**
* 解析遥测数据并添加到TelemetryMap
* 使用延迟注册机制,自动处理所有遥测数据
*/
@SuppressWarnings("unchecked")
private void parseAndPutTelemetry(TelemetryMap telemetryMap, TsKvEntry entry) {
String keyName = entry.getKey();
Object value = entry.getValue();
try {
// 使用延迟注册机制:如果键不存在则自动创建
TelemetryKey<?> key = TelemetryKey.getOrCreate(keyName, value);
// 使用键的解析器解析值
Object parsedValue = ((TelemetryKey<Object>) key).parse(value);
telemetryMap.put((TelemetryKey<Object>) key, parsedValue, entry.getTs());
log.debug("成功解析遥测数据: {} = {} (timestamp: {}, type: {})",
keyName, parsedValue, entry.getTs(), key.getType().getSimpleName());
} catch (Exception e) {
log.warn("解析遥测数据失败: key={}, value={}, error={}", keyName, value, e.getMessage());
}
}
/**
* 定时任务每隔1分钟打印所有设备信息
* 执行时间每分钟的第0秒执行
*/
@Scheduled(cron = "0 * * * * ?")
public void printAllDevicesScheduled() {
try {
log.info("========== 开始执行定时任务:打印所有设备信息 ==========");
Iterable<List<DeviceInfo>> allDevices = getAllDevices();
int totalCount = 0;
for (List<DeviceInfo> deviceBatch : allDevices) {
for (DeviceInfo device : deviceBatch) {
// 获取设备属性以获取活跃状态
Boolean activeStatus = false;
try {
AttributeMap attributes = getDeviceAttributes(device.getId());
// 尝试从 AttributeMap 中获取 active 属性
Optional<Boolean> active = attributes.get(DeviceAttributes.ACTIVE);
if (active.isPresent()) {
activeStatus = active.get();
}
} catch (Exception e) {
log.debug("获取设备 {} 的活跃状态失败: {}", device.getId(), e.getMessage());
}
log.info("Device Name: {}, Device ID: {}, Device Type: {}, Active: {}",
device.getName(),
device.getId(),
device.getType(),
activeStatus);
totalCount++;
}
}
log.info("========== 定时任务执行完成,共打印 {} 个设备 ==========", totalCount);
} catch (Exception e) {
log.error("定时任务执行失败: {}", e.getMessage(), e);
}
}
}