From 8f0d69b42f092481108b204f1ba8028f46671451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Wed, 4 Feb 2026 13:16:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9IThingsBoardDomain.java?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/domain/api/IThingsBoardDomain.java | 36 + .../domain/impl/ThingsBoardDomainImpl.java | 122 ++++ .../constants/TuohengDeviceAttributes.java | 172 +++++ .../constants/TuohengDeviceTelemetry.java | 633 ++++++++++++++++++ 4 files changed, 963 insertions(+) create mode 100644 src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceAttributes.java create mode 100644 src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceTelemetry.java diff --git a/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java b/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java index 1a8074c..9e51b4a 100644 --- a/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java +++ b/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java @@ -107,4 +107,40 @@ public interface IThingsBoardDomain { * @param deviceId 设备ID */ void evictDeviceTelemetryCache(String deviceId); + + /** + * 根据设备ID获取拓恒设备的所有属性 + * 只返回已注册的属性键对应的数据,未注册的键会被忽略 + * + * @param deviceId 设备ID + * @return 类型安全的属性映射 + */ + AttributeMap getTuohengDeviceAttributes(String deviceId); + + /** + * 根据设备ID获取拓恒设备的所有遥测数据 + * 只返回已注册的遥测键对应的数据,未注册的键会被忽略 + * + * @param deviceId 设备ID + * @return 类型安全的遥测数据映射 + */ + TelemetryMap getTuohengDeviceTelemetry(String deviceId); + + /** + * 根据设备ID获取拓恒设备的预定义属性 + * 只返回在 TuohengDeviceAttributes 中预定义的属性 + * + * @param deviceId 设备ID + * @return 类型安全的属性映射,只包含预定义的属性 + */ + AttributeMap getPredefinedTuohengDeviceAttributes(String deviceId); + + /** + * 根据设备ID获取拓恒设备的预定义遥测数据 + * 只返回在 TuohengDeviceTelemetry 中预定义的遥测数据 + * + * @param deviceId 设备ID + * @return 类型安全的遥测数据映射,只包含预定义的遥测数据 + */ + TelemetryMap getPredefinedTuohengDeviceTelemetry(String deviceId); } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java index c293af7..c6b07cf 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java +++ b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java @@ -6,6 +6,8 @@ import com.ruoyi.device.domain.api.IThingsBoardDomain; import com.ruoyi.device.domain.model.thingsboard.*; import com.ruoyi.device.domain.model.thingsboard.constants.DeviceAttributes; import com.ruoyi.device.domain.model.thingsboard.constants.DeviceTelemetry; +import com.ruoyi.device.domain.model.thingsboard.tuoheng.constants.TuohengDeviceAttributes; +import com.ruoyi.device.domain.model.thingsboard.tuoheng.constants.TuohengDeviceTelemetry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -340,4 +342,124 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain { public void evictDeviceTelemetryCache(String deviceId) { // 空实现,仅用于清除缓存 } + + @Override + @Cacheable(value = DeviceCacheConfig.THINGSBOARD_ATTRIBUTES_CACHE, key = "'tuoheng_' + #deviceId", unless = "#result == null || #result.isEmpty()") + public AttributeMap getTuohengDeviceAttributes(String deviceId) { + AttributeMap attributeMap = new AttributeMap(); + + try { + DeviceId deviceIdObj = new DeviceId(UUID.fromString(deviceId)); + + List attributeKeys = client.getAttributeKeys(deviceIdObj); + if (attributeKeys == null || attributeKeys.isEmpty()) { + log.debug("拓恒设备 {} 没有属性", deviceId); + return attributeMap; + } + + List attributeKvEntries = client.getAttributeKvEntries(deviceIdObj, attributeKeys); + if (attributeKvEntries == null || attributeKvEntries.isEmpty()) { + log.debug("拓恒设备 {} 的属性值为空", deviceId); + return attributeMap; + } + + for (AttributeKvEntry entry : attributeKvEntries) { + parseAndPutAttribute(attributeMap, entry); + } + + } catch (Exception e) { + log.error("获取拓恒设备属性失败: deviceId={}, error={}", deviceId, e.getMessage(), e); + } + + return attributeMap; + } + + @Override + @Cacheable(value = DeviceCacheConfig.THINGSBOARD_TELEMETRY_CACHE, key = "'tuoheng_' + #deviceId", unless = "#result == null || #result.isEmpty()") + public TelemetryMap getTuohengDeviceTelemetry(String deviceId) { + TelemetryMap telemetryMap = new TelemetryMap(); + + try { + DeviceId deviceIdObj = new DeviceId(UUID.fromString(deviceId)); + + List timeseriesKeys = client.getTimeseriesKeys(deviceIdObj); + if (timeseriesKeys == null || timeseriesKeys.isEmpty()) { + log.debug("拓恒设备 {} 没有遥测数据", deviceId); + return telemetryMap; + } + + List latestTimeseries = client.getLatestTimeseries(deviceIdObj, timeseriesKeys); + if (latestTimeseries == null || latestTimeseries.isEmpty()) { + log.debug("拓恒设备 {} 的遥测数据为空", deviceId); + return telemetryMap; + } + + for (TsKvEntry entry : latestTimeseries) { + parseAndPutTelemetry(telemetryMap, entry); + } + + } catch (Exception e) { + log.error("获取拓恒设备遥测数据失败: deviceId={}, error={}", deviceId, e.getMessage(), e); + } + + return telemetryMap; + } + + @Override + public AttributeMap getPredefinedTuohengDeviceAttributes(String deviceId) { + // 先获取所有属性(已经处理了异常情况) + AttributeMap allAttributes = getTuohengDeviceAttributes(deviceId); + + // 创建新的 AttributeMap 只包含预定义的键 + AttributeMap predefinedAttributes = new AttributeMap(); + + // 获取预定义的键名称集合 + List predefinedKeyNames = TuohengDeviceAttributes.getPredefinedKeys() + .stream() + .map(AttributeKey::getName) + .toList(); + + // 过滤:只保留预定义的键 + for (AttributeKey key : allAttributes.keySet()) { + if (predefinedKeyNames.contains(key.getName())) { + // 复制到新的 map + allAttributes.get(key).ifPresent(value -> { + @SuppressWarnings("unchecked") + AttributeKey objKey = (AttributeKey) key; + predefinedAttributes.put(objKey, value); + }); + } + } + + return predefinedAttributes; + } + + @Override + public TelemetryMap getPredefinedTuohengDeviceTelemetry(String deviceId) { + // 先获取所有遥测数据(已经处理了 null 值问题) + TelemetryMap allTelemetry = getTuohengDeviceTelemetry(deviceId); + + // 创建新的 TelemetryMap 只包含预定义的键 + TelemetryMap predefinedTelemetry = new TelemetryMap(); + + // 获取预定义的键名称集合 + List predefinedKeyNames = TuohengDeviceTelemetry.getPredefinedKeys() + .stream() + .map(TelemetryKey::getName) + .toList(); + + // 过滤:只保留预定义的键 + for (TelemetryKey key : allTelemetry.keySet()) { + if (predefinedKeyNames.contains(key.getName())) { + // 复制到新的 map + allTelemetry.get(key).ifPresent(telemetryValue -> { + @SuppressWarnings("unchecked") + TelemetryKey objKey = (TelemetryKey) key; + predefinedTelemetry.put(objKey, telemetryValue.getValue(), telemetryValue.getTimestamp()); + }); + } + } + + return predefinedTelemetry; + } } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceAttributes.java b/src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceAttributes.java new file mode 100644 index 0000000..85517a8 --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceAttributes.java @@ -0,0 +1,172 @@ +package com.ruoyi.device.domain.model.thingsboard.tuoheng.constants; + +import com.ruoyi.device.domain.model.thingsboard.AttributeKey; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 拓恒设备属性键 + * 使用类型安全的方式定义拓恒设备专用属性 + */ +public class TuohengDeviceAttributes { + + /** + * 公用服务端属性 + */ + + // 最后连接时间 - Long + public static final AttributeKey LAST_CONNECT_TIME = AttributeKey.of( + "lastConnectTime", + Long.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return Long.parseLong(value.toString()); + } + ); + + // 是否激活 - Boolean + public static final AttributeKey ACTIVE = AttributeKey.of( + "active", + Boolean.class, + value -> { + if (value == null) return null; + if (value instanceof Boolean) { + return (Boolean) value; + } + return Boolean.parseBoolean(value.toString()); + } + ); + + // 最后活动时间 - Long + public static final AttributeKey LAST_ACTIVITY_TIME = AttributeKey.of( + "lastActivityTime", + Long.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return Long.parseLong(value.toString()); + } + ); + + // 最后断开连接时间 - Long + public static final AttributeKey LAST_DISCONNECT_TIME = AttributeKey.of( + "lastDisconnectTime", + Long.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return Long.parseLong(value.toString()); + } + ); + + /** + * 公用客户端属性 (无需配置) + */ + // 连接器类型 - String + public static final AttributeKey CONNECTOR_TYPE = AttributeKey.of( + "connectorType", + String.class, + value -> value != null ? value.toString() : null + ); + + // 连接器名称 - String (值为 "tuoheng") + public static final AttributeKey CONNECTOR_NAME = AttributeKey.of( + "connectorName", + String.class, + value -> value != null ? value.toString() : null + ); + + /** + * 拓恒机场特有属性 (来自 /topic/v1/airportNest/+/realTime/basic) + */ + + // 机场ID - String + public static final AttributeKey AIRPORT_ID = AttributeKey.of( + "airportID", + String.class, + value -> value != null ? value.toString() : null + ); + + // MAC地址 - String + public static final AttributeKey MAC = AttributeKey.of( + "mac", + String.class, + value -> value != null ? value.toString() : null + ); + + // 软件版本 - String + public static final AttributeKey SOFTWARE_VERSION = AttributeKey.of( + "software_version", + String.class, + value -> value != null ? value.toString() : null + ); + + // 硬件版本 - String + public static final AttributeKey HARDWARE_VERSION = AttributeKey.of( + "hardware_version", + String.class, + value -> value != null ? value.toString() : null + ); + + // 发送者标识 - String + public static final AttributeKey SENDER = AttributeKey.of( + "sender", + String.class, + value -> value != null ? value.toString() : null + ); + + /** + * 拓恒无人机特有属性 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // 设备ID - String + public static final AttributeKey DEVICE_ID = AttributeKey.of( + "deviceid", + String.class, + value -> value != null ? value.toString() : null + ); + + private TuohengDeviceAttributes() { + // 工具类,禁止实例化 + } + + /** + * 获取所有预定义的属性键 + * + * @return 预定义的属性键列表 + */ + public static List> getPredefinedKeys() { + return Arrays.asList( + CONNECTOR_TYPE, + CONNECTOR_NAME, + LAST_CONNECT_TIME, + ACTIVE, + LAST_ACTIVITY_TIME, + LAST_DISCONNECT_TIME, + AIRPORT_ID, + MAC, + SOFTWARE_VERSION, + HARDWARE_VERSION, + SENDER, + DEVICE_ID + ); + } + + /** + * 初始化所有属性键 + * 确保所有静态字段被加载和注册 + */ + public static void init() { + // 这个方法的存在是为了触发类的静态初始化 + // 当调用此方法时,所有静态字段都会被初始化 + } +} diff --git a/src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceTelemetry.java b/src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceTelemetry.java new file mode 100644 index 0000000..b50b8dc --- /dev/null +++ b/src/main/java/com/ruoyi/device/domain/model/thingsboard/tuoheng/constants/TuohengDeviceTelemetry.java @@ -0,0 +1,633 @@ +package com.ruoyi.device.domain.model.thingsboard.tuoheng.constants; + +import com.ruoyi.device.domain.model.thingsboard.TelemetryKey; + +import java.util.Arrays; +import java.util.List; + +/** + * 拓恒设备遥测数据键 + * 使用类型安全的方式定义拓恒设备专用遥测数据 + */ +public class TuohengDeviceTelemetry { + + /** + * 机场心跳数据 (来自 /topic/v1/airportNest/+/realTime/basic) + */ + + // 在线状态 - String (online/offline) + public static final TelemetryKey STATUS = TelemetryKey.of( + "status", + String.class, + value -> value != null ? value.toString() : null + ); + + // 发送时间戳 - Long + public static final TelemetryKey SEND_TIMESTAMP = TelemetryKey.of( + "send_timestamp", + Long.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return Long.parseLong(value.toString()); + } + ); + + /** + * 气象数据 (来自 /topic/v1/airportNest/+/realTime/data) + */ + + // 降雨量 - Double + public static final TelemetryKey WEATHER_RAINFALL = TelemetryKey.of( + "weather_rainfall", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 风力等级 - Double + public static final TelemetryKey WEATHER_WIND_LEVEL = TelemetryKey.of( + "weather_windLevel", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 风向 - Double + public static final TelemetryKey WEATHER_WIND_DIR = TelemetryKey.of( + "weather_windDir", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 风速 - Double + public static final TelemetryKey WEATHER_WIND_SPEED = TelemetryKey.of( + "weather_windSpeed", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 降雨标志 - Integer + public static final TelemetryKey WEATHER_RAIN_FLAG = TelemetryKey.of( + "weather_rainFlag", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 风向角度 - Double + public static final TelemetryKey WEATHER_WIND_ANGLE = TelemetryKey.of( + "weather_windAngle", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + /** + * 电池数据 (来自 /topic/v1/airportNest/+/realTime/data) + */ + + // 电池电量百分比 - Integer + public static final TelemetryKey BATTERY_LEVEL = TelemetryKey.of( + "battery_level", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 电池健康度 - Integer + public static final TelemetryKey BATTERY_HEALTH = TelemetryKey.of( + "battery_health", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 总电压 - Double + public static final TelemetryKey BATTERY_TOTAL_VOLTAGE = TelemetryKey.of( + "battery_totalVoltage", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 电芯温度 - Double + public static final TelemetryKey BATTERY_CELL_TEMP = TelemetryKey.of( + "battery_cellTemp", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // MOS温度 - Double + public static final TelemetryKey BATTERY_MOS_TEMP = TelemetryKey.of( + "battery_mosTemp", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 循环次数 - Integer + public static final TelemetryKey BATTERY_NUM_CYCLES = TelemetryKey.of( + "battery_num_cycles", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 放电电流 - Double + public static final TelemetryKey BATTERY_DISCHARGE_CURRENT = TelemetryKey.of( + "battery_discharge_current", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 充电状态 - Integer + public static final TelemetryKey BATTERY_B_CHARGING = TelemetryKey.of( + "battery_bCharging", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + /** + * 舱内传感器数据 (来自 /topic/v1/airportNest/+/realTime/data) + */ + + // 舱内湿度 - Double + public static final TelemetryKey NEST_INNER_HUM = TelemetryKey.of( + "nest_innerHum", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 舱内温度 - Double + public static final TelemetryKey NEST_INNER_TEMP = TelemetryKey.of( + "nest_innerTemp", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + /** + * 充电器数据 (来自 /topic/v1/airportNest/+/realTime/data) + */ + + // 充电电流 - Double + public static final TelemetryKey CHARGER_CURRENT = TelemetryKey.of( + "charger_current", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 充电电压 - Double + public static final TelemetryKey CHARGER_VOLTAGE = TelemetryKey.of( + "charger_voltage", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 充电容量 - Double + public static final TelemetryKey CHARGER_CAPACITY = TelemetryKey.of( + "charger_capacity", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 充电状态 - Integer + public static final TelemetryKey CHARGER_B_CHARGING = TelemetryKey.of( + "charger_bCharging", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + /** + * 无人机位置信息 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // 纬度 - Double + public static final TelemetryKey LATITUDE = TelemetryKey.of( + "latitude", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 经度 - Double + public static final TelemetryKey LONGITUDE = TelemetryKey.of( + "longitude", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 相对高度 - Double + public static final TelemetryKey ALTITUDE = TelemetryKey.of( + "altitude", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 绝对高度 - Double + public static final TelemetryKey ALTITUDE_ASL = TelemetryKey.of( + "altitude_asl", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + /** + * 无人机姿态信息 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // 横滚角 - Double + public static final TelemetryKey ROLL = TelemetryKey.of( + "roll", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 俯仰角 - Double + public static final TelemetryKey PITCH = TelemetryKey.of( + "pitch", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 偏航角 - Double + public static final TelemetryKey YAW = TelemetryKey.of( + "yaw", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + /** + * 无人机速度信息 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // 水平速度 - Double + public static final TelemetryKey HORIZONTAL_SPEED = TelemetryKey.of( + "horizontal_speed", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 垂直速度 - Double + public static final TelemetryKey VERTICAL_SPEED = TelemetryKey.of( + "vertical_speed", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + /** + * 无人机电池信息 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // 剩余电量 - Integer + public static final TelemetryKey BATTERY_REMAIN = TelemetryKey.of( + "battery_remain", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 电压 - Double + public static final TelemetryKey VOLTAGE = TelemetryKey.of( + "voltage", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + /** + * 无人机GPS信息 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // GPS信号强度 - Integer + public static final TelemetryKey GPS_SIGNAL = TelemetryKey.of( + "gps_signal", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 卫星数量 - Integer + public static final TelemetryKey SAT_COUNT = TelemetryKey.of( + "sat_count", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + /** + * 无人机飞行状态 (来自 /topic/v1/airportDrone/+/realTime/data) + */ + + // 飞行模式 - String + public static final TelemetryKey MODE = TelemetryKey.of( + "mode", + String.class, + value -> value != null ? value.toString() : null + ); + + // 解锁状态 - String + public static final TelemetryKey ARMED = TelemetryKey.of( + "armed", + String.class, + value -> value != null ? value.toString() : null + ); + + // 飞行时间 - Integer + public static final TelemetryKey FLIGHT_TIME = TelemetryKey.of( + "flight_time", + Integer.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.parseInt(value.toString()); + } + ); + + // 飞行里程 - Double + public static final TelemetryKey MILEAGE = TelemetryKey.of( + "mileage", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + // 距离返航点距离 - Double + public static final TelemetryKey DISTANCE_TO_HOME = TelemetryKey.of( + "distance_to_home", + Double.class, + value -> { + if (value == null) return null; + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.parseDouble(value.toString()); + } + ); + + private TuohengDeviceTelemetry() { + // 工具类,禁止实例化 + } + + /** + * 获取所有预定义的遥测键 + * + * @return 预定义的遥测键列表 + */ + public static List> getPredefinedKeys() { + return Arrays.asList( + // 机场心跳数据 + STATUS, + SEND_TIMESTAMP, + // 气象数据 + WEATHER_RAINFALL, + WEATHER_WIND_LEVEL, + WEATHER_WIND_DIR, + WEATHER_WIND_SPEED, + WEATHER_RAIN_FLAG, + WEATHER_WIND_ANGLE, + // 电池数据 + BATTERY_LEVEL, + BATTERY_HEALTH, + BATTERY_TOTAL_VOLTAGE, + BATTERY_CELL_TEMP, + BATTERY_MOS_TEMP, + BATTERY_NUM_CYCLES, + BATTERY_DISCHARGE_CURRENT, + BATTERY_B_CHARGING, + // 舱内传感器数据 + NEST_INNER_HUM, + NEST_INNER_TEMP, + // 充电器数据 + CHARGER_CURRENT, + CHARGER_VOLTAGE, + CHARGER_CAPACITY, + CHARGER_B_CHARGING, + // 无人机位置信息 + LATITUDE, + LONGITUDE, + ALTITUDE, + ALTITUDE_ASL, + // 无人机姿态信息 + ROLL, + PITCH, + YAW, + // 无人机速度信息 + HORIZONTAL_SPEED, + VERTICAL_SPEED, + // 无人机电池信息 + BATTERY_REMAIN, + VOLTAGE, + // 无人机GPS信息 + GPS_SIGNAL, + SAT_COUNT, + // 无人机飞行状态 + MODE, + ARMED, + FLIGHT_TIME, + MILEAGE, + DISTANCE_TO_HOME + ); + } + + /** + * 初始化所有遥测键 + * 确保所有静态字段被加载和注册 + */ + public static void init() { + // 这个方法的存在是为了触发类的静态初始化 + // 当调用此方法时,所有静态字段都会被初始化 + } +}