mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 01:23:55 +08:00
update:接口
This commit is contained in:
+153
-2
@@ -29,15 +29,31 @@ import xiaozhi.modules.device.dto.DeviceManualAddDTO;
|
|||||||
import xiaozhi.modules.device.entity.DeviceEntity;
|
import xiaozhi.modules.device.entity.DeviceEntity;
|
||||||
import xiaozhi.modules.device.service.DeviceService;
|
import xiaozhi.modules.device.service.DeviceService;
|
||||||
import xiaozhi.modules.security.user.SecurityUser;
|
import xiaozhi.modules.security.user.SecurityUser;
|
||||||
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
@Tag(name = "设备管理")
|
@Tag(name = "设备管理")
|
||||||
@AllArgsConstructor
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/device")
|
@RequestMapping("/device")
|
||||||
public class DeviceController {
|
public class DeviceController {
|
||||||
private final DeviceService deviceService;
|
private final DeviceService deviceService;
|
||||||
|
|
||||||
private final RedisUtils redisUtils;
|
private final RedisUtils redisUtils;
|
||||||
|
private final SysParamsService sysParamsService;
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public DeviceController(DeviceService deviceService, RedisUtils redisUtils, SysParamsService sysParamsService, RestTemplate restTemplate, ObjectMapper objectMapper) {
|
||||||
|
this.deviceService = deviceService;
|
||||||
|
this.redisUtils = redisUtils;
|
||||||
|
this.sysParamsService = sysParamsService;
|
||||||
|
this.restTemplate = restTemplate;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/bind/{agentId}/{deviceCode}")
|
@PostMapping("/bind/{agentId}/{deviceCode}")
|
||||||
@Operation(summary = "绑定设备")
|
@Operation(summary = "绑定设备")
|
||||||
@@ -75,6 +91,87 @@ public class DeviceController {
|
|||||||
return new Result<List<DeviceEntity>>().ok(devices);
|
return new Result<List<DeviceEntity>>().ok(devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/bind/{agentId}")
|
||||||
|
@Operation(summary = "转发POST请求到MQTT网关")
|
||||||
|
@RequiresPermissions("sys:role:normal")
|
||||||
|
public Result<String> forwardToMqttGateway(@PathVariable String agentId, @RequestBody String requestBody) {
|
||||||
|
try {
|
||||||
|
// 从系统参数中获取MQTT网关地址
|
||||||
|
String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true);
|
||||||
|
if (StringUtils.isBlank(mqttGatewayUrl)) {
|
||||||
|
return new Result<String>().error("MQTT网关地址未配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前用户的设备列表
|
||||||
|
UserDetail user = SecurityUser.getUser();
|
||||||
|
List<DeviceEntity> devices = deviceService.getUserDevices(user.getId(), agentId);
|
||||||
|
|
||||||
|
// 构建deviceIds数组
|
||||||
|
java.util.List<String> deviceIds = new java.util.ArrayList<>();
|
||||||
|
for (DeviceEntity device : devices) {
|
||||||
|
String macAddress = device.getMacAddress() != null ? device.getMacAddress() : "unknown";
|
||||||
|
String groupId = device.getBoard() != null ? device.getBoard() : "GID_default";
|
||||||
|
|
||||||
|
// 替换冒号为下划线
|
||||||
|
groupId = groupId.replace(":", "_");
|
||||||
|
macAddress = macAddress.replace(":", "_");
|
||||||
|
|
||||||
|
// 构建mqtt客户端ID格式:groupId@@@macAddress@@@macAddress
|
||||||
|
String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress;
|
||||||
|
deviceIds.add(mqttClientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建完整的URL
|
||||||
|
String url = "http://" + mqttGatewayUrl + "/api/devices/status";
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("Content-Type", "application/json");
|
||||||
|
|
||||||
|
// 生成Bearer令牌
|
||||||
|
String token = generateBearerToken();
|
||||||
|
if (token == null) {
|
||||||
|
return new Result<String>().error("令牌生成失败");
|
||||||
|
}
|
||||||
|
headers.set("Authorization", "Bearer " + token);
|
||||||
|
|
||||||
|
// 构建请求体JSON
|
||||||
|
String jsonBody = "{\"deviceIds\":" + objectMapper.writeValueAsString(deviceIds) + "}";
|
||||||
|
HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
|
||||||
|
|
||||||
|
// 发送POST请求
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
// 返回响应
|
||||||
|
return new Result<String>().ok(response.getBody());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Result<String>().error("转发请求失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateBearerToken() {
|
||||||
|
try {
|
||||||
|
// 获取当前日期,格式为yyyy-MM-dd
|
||||||
|
String dateStr = java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
|
|
||||||
|
// 获取MQTT签名密钥
|
||||||
|
String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false);
|
||||||
|
if (StringUtils.isBlank(signatureKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将日期字符串与MQTT_SIGNATURE_KEY连接
|
||||||
|
String tokenContent = dateStr + signatureKey;
|
||||||
|
|
||||||
|
// 对连接后的字符串进行SHA256哈希计算
|
||||||
|
String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/unbind")
|
@PostMapping("/unbind")
|
||||||
@Operation(summary = "解绑设备")
|
@Operation(summary = "解绑设备")
|
||||||
@RequiresPermissions("sys:role:normal")
|
@RequiresPermissions("sys:role:normal")
|
||||||
@@ -109,4 +206,58 @@ public class DeviceController {
|
|||||||
deviceService.manualAddDevice(user.getId(), dto);
|
deviceService.manualAddDevice(user.getId(), dto);
|
||||||
return new Result<>();
|
return new Result<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/commands/{deviceId}")
|
||||||
|
@Operation(summary = "发送设备指令")
|
||||||
|
@RequiresPermissions("sys:role:normal")
|
||||||
|
public Result<String> sendDeviceCommand(@PathVariable String deviceId, @RequestBody String command) {
|
||||||
|
try {
|
||||||
|
// 从系统参数中获取MQTT网关地址
|
||||||
|
String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true);
|
||||||
|
if (StringUtils.isBlank(mqttGatewayUrl)) {
|
||||||
|
return new Result<String>().error("MQTT网关地址未配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建完整的URL
|
||||||
|
// 获取设备信息以构建mqttClientId
|
||||||
|
DeviceEntity deviceById = deviceService.selectById(deviceId);
|
||||||
|
String macAddress = deviceById != null ? deviceById.getMacAddress() : "unknown";
|
||||||
|
String groupId = deviceById != null ? deviceById.getBoard() : null;
|
||||||
|
if (groupId == null) {
|
||||||
|
groupId = "GID_default";
|
||||||
|
}
|
||||||
|
groupId = groupId.replace(":", "_");
|
||||||
|
macAddress = macAddress.replace(":", "_");
|
||||||
|
|
||||||
|
// 拼接为groupId@@@macAddress@@@deviceId格式
|
||||||
|
String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress;
|
||||||
|
|
||||||
|
String url = "http://" + mqttGatewayUrl + "/api/commands/" + mqttClientId;
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("Content-Type", "application/json");
|
||||||
|
|
||||||
|
// 生成Bearer令牌
|
||||||
|
String dateStr = java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
|
String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false);
|
||||||
|
if (StringUtils.isBlank(signatureKey)) {
|
||||||
|
return new Result<String>().error("MQTT签名密钥未配置");
|
||||||
|
}
|
||||||
|
String tokenContent = dateStr + signatureKey;
|
||||||
|
String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent);
|
||||||
|
headers.set("Authorization", "Bearer " + token);
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
HttpEntity<String> requestEntity = new HttpEntity<>(command, headers);
|
||||||
|
|
||||||
|
// 发送POST请求
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
|
// 返回响应
|
||||||
|
return new Result<String>().ok(response.getBody());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Result<String>().error("发送指令失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+3
-5
@@ -188,7 +188,7 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
|||||||
try {
|
try {
|
||||||
String groupId = deviceById != null && deviceById.getBoard() != null ? deviceById.getBoard()
|
String groupId = deviceById != null && deviceById.getBoard() != null ? deviceById.getBoard()
|
||||||
: "GID_default";
|
: "GID_default";
|
||||||
DeviceReportRespDTO.MQTT mqtt = buildMqttConfig(macAddress, clientId, groupId);
|
DeviceReportRespDTO.MQTT mqtt = buildMqttConfig(macAddress, groupId);
|
||||||
if (mqtt != null) {
|
if (mqtt != null) {
|
||||||
mqtt.setEndpoint(mqttUdpConfig);
|
mqtt.setEndpoint(mqttUdpConfig);
|
||||||
response.setMqtt(mqtt);
|
response.setMqtt(mqtt);
|
||||||
@@ -479,11 +479,10 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
|||||||
* 构建MQTT配置信息
|
* 构建MQTT配置信息
|
||||||
*
|
*
|
||||||
* @param macAddress MAC地址
|
* @param macAddress MAC地址
|
||||||
* @param clientId 客户端ID (UUID)
|
|
||||||
* @param groupId 分组ID
|
* @param groupId 分组ID
|
||||||
* @return MQTT配置对象
|
* @return MQTT配置对象
|
||||||
*/
|
*/
|
||||||
private DeviceReportRespDTO.MQTT buildMqttConfig(String macAddress, String clientId, String groupId)
|
private DeviceReportRespDTO.MQTT buildMqttConfig(String macAddress, String groupId)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// 从环境变量或系统参数获取签名密钥
|
// 从环境变量或系统参数获取签名密钥
|
||||||
String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false);
|
String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false);
|
||||||
@@ -495,8 +494,7 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
|
|||||||
// 构建客户端ID格式:groupId@@@macAddress@@@uuid
|
// 构建客户端ID格式:groupId@@@macAddress@@@uuid
|
||||||
String groupIdSafeStr = groupId.replace(":", "_");
|
String groupIdSafeStr = groupId.replace(":", "_");
|
||||||
String deviceIdSafeStr = macAddress.replace(":", "_");
|
String deviceIdSafeStr = macAddress.replace(":", "_");
|
||||||
String clientIdSafeStr = clientId.replace(":", "_");
|
String mqttClientId = String.format("%s@@@%s@@@%s", groupIdSafeStr, deviceIdSafeStr, deviceIdSafeStr);
|
||||||
String mqttClientId = String.format("%s@@@%s@@@%s", groupIdSafeStr, deviceIdSafeStr, clientIdSafeStr);
|
|
||||||
|
|
||||||
// 构建用户数据(包含IP等信息)
|
// 构建用户数据(包含IP等信息)
|
||||||
Map<String, String> userData = new HashMap<>();
|
Map<String, String> userData = new HashMap<>();
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
delete from `sys_params` where param_code = 'server.mqtt_manager_api';
|
||||||
|
INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark)
|
||||||
|
VALUES (119, 'server.mqtt_manager_api', null, 'string', 1, 'MQTT网关管理API的地址');
|
||||||
@@ -345,3 +345,10 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202509080922.sql
|
path: classpath:db/changelog/202509080922.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202509161609
|
||||||
|
author: fyb
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202509161609.sql
|
||||||
Reference in New Issue
Block a user