feat: 新功能开发,监测历史记录。微信和物联网平台,模块搭建。
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package com.intc.iot.service;
|
||||
|
||||
/**
|
||||
* 设备数据服务接口
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
public interface DeviceDataService {
|
||||
|
||||
/**
|
||||
* 订阅设备属性上报
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void subscribeDeviceProperties(String iotId) throws Exception;
|
||||
|
||||
/**
|
||||
* 订阅设备事件上报
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void subscribeDeviceEvents(String iotId) throws Exception;
|
||||
|
||||
/**
|
||||
* 订阅所有设备数据
|
||||
*
|
||||
* @param productKey 产品Key
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void subscribeAllDevices(String productKey) throws Exception;
|
||||
|
||||
/**
|
||||
* 取消订阅设备数据
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void unsubscribeDevice(String iotId) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.intc.iot.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 阿里云生活物联网平台(飞燕平台)设备管理服务
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
public interface IotDeviceService {
|
||||
|
||||
/**
|
||||
* 查询设备列表
|
||||
*
|
||||
* @param pageNo 页码
|
||||
* @param pageSize 每页大小
|
||||
* @return 设备列表
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
Map<String, Object> queryDeviceList(Integer pageNo, Integer pageSize) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询设备详情
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @return 设备详情
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
Map<String, Object> queryDeviceInfo(String iotId) throws Exception;
|
||||
|
||||
/**
|
||||
* 查询设备属性
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @return 设备属性
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
Map<String, Object> queryDeviceProperties(String iotId) throws Exception;
|
||||
|
||||
/**
|
||||
* 设置设备属性
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @param properties 属性JSON
|
||||
* @return 设置结果
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
Map<String, Object> setDeviceProperty(String iotId, String properties) throws Exception;
|
||||
|
||||
/**
|
||||
* 调用设备服务
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @param identifier 服务标识符
|
||||
* @param args 参数
|
||||
* @return 调用结果
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
Map<String, Object> invokeService(String iotId, String identifier, String args) throws Exception;
|
||||
|
||||
/**
|
||||
* 解绑设备
|
||||
*
|
||||
* @param iotId 设备ID
|
||||
* @return 解绑结果
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
Map<String, Object> unbindDevice(String iotId) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.intc.iot.service;
|
||||
|
||||
/**
|
||||
* MQTT 消息服务
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
public interface MqttService {
|
||||
|
||||
/**
|
||||
* 发布消息
|
||||
*
|
||||
* @param topic 主题
|
||||
* @param payload 消息内容
|
||||
* @param qos 服务质量等级(0/1/2)
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void publish(String topic, String payload, int qos) throws Exception;
|
||||
|
||||
/**
|
||||
* 订阅主题
|
||||
*
|
||||
* @param topic 主题
|
||||
* @param qos 服务质量等级(0/1/2)
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void subscribe(String topic, int qos) throws Exception;
|
||||
|
||||
/**
|
||||
* 取消订阅
|
||||
*
|
||||
* @param topic 主题
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
void unsubscribe(String topic) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.intc.iot.service.impl;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.intc.iot.service.DeviceDataService;
|
||||
import com.intc.iot.service.MqttService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 设备数据服务实现
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnBean(MqttClient.class)
|
||||
public class DeviceDataServiceImpl implements DeviceDataService {
|
||||
|
||||
private final MqttService mqttService;
|
||||
|
||||
/**
|
||||
* 飞燕平台设备属性上报 Topic 格式
|
||||
* /sys/{productKey}/{deviceName}/thing/event/property/post
|
||||
*/
|
||||
private static final String PROPERTY_POST_TOPIC = "/sys/%s/%s/thing/event/property/post";
|
||||
|
||||
/**
|
||||
* 飞燕平台设备事件上报 Topic 格式
|
||||
* /sys/{productKey}/{deviceName}/thing/event/{eventIdentifier}/post
|
||||
*/
|
||||
private static final String EVENT_POST_TOPIC = "/sys/%s/%s/thing/event/+/post";
|
||||
|
||||
/**
|
||||
* 所有设备属性上报 Topic(使用通配符)
|
||||
* /sys/{productKey}/+/thing/event/property/post
|
||||
*/
|
||||
private static final String ALL_DEVICES_PROPERTY_TOPIC = "/sys/%s/+/thing/event/property/post";
|
||||
|
||||
@Override
|
||||
public void subscribeDeviceProperties(String iotId) throws Exception {
|
||||
// 注意:需要根据 iotId 获取 productKey 和 deviceName
|
||||
// 这里简化处理,实际应该从数据库或缓存中查询
|
||||
log.info("订阅设备属性上报,IotId: {}", iotId);
|
||||
|
||||
// 示例:假设从设备信息中获取
|
||||
// String productKey = getProductKeyByIotId(iotId);
|
||||
// String deviceName = getDeviceNameByIotId(iotId);
|
||||
// String topic = String.format(PROPERTY_POST_TOPIC, productKey, deviceName);
|
||||
|
||||
// mqttService.subscribe(topic, 1);
|
||||
|
||||
log.warn("请先实现 iotId 到 productKey/deviceName 的映射逻辑");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeDeviceEvents(String iotId) throws Exception {
|
||||
log.info("订阅设备事件上报,IotId: {}", iotId);
|
||||
|
||||
// 类似属性订阅,需要映射关系
|
||||
log.warn("请先实现 iotId 到 productKey/deviceName 的映射逻辑");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeAllDevices(String productKey) throws Exception {
|
||||
log.info("订阅产品下所有设备属性上报,ProductKey: {}", productKey);
|
||||
|
||||
String topic = String.format(ALL_DEVICES_PROPERTY_TOPIC, productKey);
|
||||
mqttService.subscribe(topic, 1);
|
||||
|
||||
log.info("成功订阅 Topic: {}", topic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeDevice(String iotId) throws Exception {
|
||||
log.info("取消订阅设备数据,IotId: {}", iotId);
|
||||
|
||||
// 需要取消对应的 Topic 订阅
|
||||
log.warn("请先实现 iotId 到 productKey/deviceName 的映射逻辑");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.intc.iot.service.impl;
|
||||
|
||||
import com.aliyuncs.IAcsClient;
|
||||
import com.aliyuncs.iot.model.v20180120.*;
|
||||
import com.intc.iot.config.AliyunIotProperties;
|
||||
import com.intc.iot.service.IotDeviceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 阿里云生活物联网平台(飞燕平台)设备管理服务实现
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnBean(IAcsClient.class)
|
||||
public class IotDeviceServiceImpl implements IotDeviceService {
|
||||
|
||||
private final IAcsClient acsClient;
|
||||
private final AliyunIotProperties iotProperties;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryDeviceList(Integer pageNo, Integer pageSize) throws Exception {
|
||||
log.info("查询设备列表,页码: {}, 每页大小: {}", pageNo, pageSize);
|
||||
|
||||
QueryDeviceRequest request = new QueryDeviceRequest();
|
||||
request.setCurrentPage(pageNo);
|
||||
request.setPageSize(pageSize);
|
||||
|
||||
QueryDeviceResponse response = acsClient.getAcsResponse(request);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("data", response.getData());
|
||||
result.put("total", response.getTotal());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryDeviceInfo(String iotId) throws Exception {
|
||||
log.info("查询设备详情,IotId: {}", iotId);
|
||||
|
||||
QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
|
||||
request.setIotId(iotId);
|
||||
|
||||
QueryDeviceDetailResponse response = acsClient.getAcsResponse(request);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("data", response.getData());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryDeviceProperties(String iotId) throws Exception {
|
||||
log.info("查询设备属性,IotId: {}", iotId);
|
||||
|
||||
QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();
|
||||
request.setIotId(iotId);
|
||||
|
||||
QueryDevicePropertyStatusResponse response = acsClient.getAcsResponse(request);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("data", response.getData());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> setDeviceProperty(String iotId, String properties) throws Exception {
|
||||
log.info("设置设备属性,IotId: {}, Properties: {}", iotId, properties);
|
||||
|
||||
SetDevicePropertyRequest request = new SetDevicePropertyRequest();
|
||||
request.setIotId(iotId);
|
||||
request.setItems(properties);
|
||||
|
||||
SetDevicePropertyResponse response = acsClient.getAcsResponse(request);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("data", response.getData());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> invokeService(String iotId, String identifier, String args) throws Exception {
|
||||
log.info("调用设备服务,IotId: {}, Identifier: {}", iotId, identifier);
|
||||
|
||||
InvokeThingServiceRequest request = new InvokeThingServiceRequest();
|
||||
request.setIotId(iotId);
|
||||
request.setIdentifier(identifier);
|
||||
request.setArgs(args);
|
||||
|
||||
InvokeThingServiceResponse response = acsClient.getAcsResponse(request);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("data", response.getData());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> unbindDevice(String iotId) throws Exception {
|
||||
log.info("解绑设备,IotId: {}", iotId);
|
||||
|
||||
// 注: 通用IoT SDK没有直接的解绑接口,这里使用删除设备
|
||||
DeleteDeviceRequest request = new DeleteDeviceRequest();
|
||||
request.setIotId(iotId);
|
||||
|
||||
DeleteDeviceResponse response = acsClient.getAcsResponse(request);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", response.getSuccess());
|
||||
result.put("errorMessage", response.getErrorMessage());
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.intc.iot.service.impl;
|
||||
|
||||
import com.intc.iot.handler.DeviceDataHandler;
|
||||
import com.intc.iot.service.MqttService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* MQTT 消息服务实现
|
||||
*
|
||||
* @author intc
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnBean(MqttClient.class)
|
||||
public class MqttServiceImpl implements MqttService {
|
||||
|
||||
private final MqttClient mqttClient;
|
||||
|
||||
@Autowired(required = false)
|
||||
private DeviceDataHandler deviceDataHandler;
|
||||
|
||||
@Override
|
||||
public void publish(String topic, String payload, int qos) throws Exception {
|
||||
if (!mqttClient.isConnected()) {
|
||||
log.warn("MQTT 客户端未连接,尝试重连...");
|
||||
mqttClient.reconnect();
|
||||
}
|
||||
|
||||
MqttMessage message = new MqttMessage(payload.getBytes());
|
||||
message.setQos(qos);
|
||||
message.setRetained(false);
|
||||
|
||||
mqttClient.publish(topic, message);
|
||||
log.info("MQTT 消息发布成功,Topic: {}, Payload: {}", topic, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(String topic, int qos) throws Exception {
|
||||
if (!mqttClient.isConnected()) {
|
||||
log.warn("MQTT 客户端未连接,尝试重连...");
|
||||
mqttClient.reconnect();
|
||||
}
|
||||
|
||||
mqttClient.subscribe(topic, qos, new IMqttMessageListener() {
|
||||
@Override
|
||||
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||
String payload = new String(message.getPayload());
|
||||
log.info("收到 MQTT 消息,Topic: {}, Payload: {}", topic, payload);
|
||||
|
||||
// 根据 Topic 类型分发处理
|
||||
if (deviceDataHandler != null) {
|
||||
if (topic.contains("/thing/event/property/post")) {
|
||||
// 设备属性上报
|
||||
deviceDataHandler.handlePropertyPost(topic, payload);
|
||||
} else if (topic.contains("/thing/event/") && topic.endsWith("/post")) {
|
||||
// 设备事件上报
|
||||
deviceDataHandler.handleEventPost(topic, payload);
|
||||
} else {
|
||||
log.debug("未匹配的 Topic 类型: {}", topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
log.info("MQTT 主题订阅成功,Topic: {}", topic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribe(String topic) throws Exception {
|
||||
if (!mqttClient.isConnected()) {
|
||||
log.warn("MQTT 客户端未连接");
|
||||
return;
|
||||
}
|
||||
|
||||
mqttClient.unsubscribe(topic);
|
||||
log.info("MQTT 主题取消订阅成功,Topic: {}", topic);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user