forked from dyf/fys-Multi-tenant
Compare commits
43 Commits
dff37b245a
...
6170
| Author | SHA1 | Date | |
|---|---|---|---|
| 47d40cf9d2 | |||
| 83b97841ef | |||
| 9d84265f57 | |||
| fa5dfab939 | |||
| 5fb71dd092 | |||
| 1ce87aaec5 | |||
| 4f3e7b0ed0 | |||
| b75b7ef431 | |||
| c9cad751f0 | |||
| 34841c8704 | |||
| 20ac6b0baa | |||
| 4d5292cebc | |||
| 7a35baa8f0 | |||
| dbb7076b50 | |||
| 15c85d4c62 | |||
| e036ef05ce | |||
| 03f453f901 | |||
| e23c5267ee | |||
| 552bf0af0a | |||
| efad1f5a4b | |||
| f3551be093 | |||
| 855714106e | |||
| 04cb699081 | |||
| 0f0dd4c6b1 | |||
| 2db37a75d2 | |||
| 696bbb4aa4 | |||
| ee445dc0d2 | |||
| 897561ba89 | |||
| 2e575f78b1 | |||
| 6fd7f8ca94 | |||
| 9936a5ad13 | |||
| c267fe0c14 | |||
| e80830e76c | |||
| 346792d5c1 | |||
| cb87871982 | |||
| 437ab110b7 | |||
| b280038502 | |||
| 3e119b1dd8 | |||
| cab0884d7f | |||
| 88650c3d9f | |||
| ca11ef0e35 | |||
| ef2dc6a6f6 | |||
| ec28ab1092 |
@ -133,6 +133,19 @@
|
|||||||
<version>1.5.7</version>
|
<version>1.5.7</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Java音频转换库 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ws.schild</groupId>
|
||||||
|
<artifactId>jave-core</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <dependency>
|
||||||
|
<groupId>ws.schild</groupId>
|
||||||
|
<artifactId>jave-nativebin-all</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
</dependency>-->
|
||||||
|
|
||||||
|
|
||||||
<!-- skywalking 整合 logback -->
|
<!-- skywalking 整合 logback -->
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
|
|||||||
81
fys-admin/src/main/java/com/fuyuanshen/SimpleQR.java
Normal file
81
fys-admin/src/main/java/com/fuyuanshen/SimpleQR.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package com.fuyuanshen;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class SimpleQR {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String text = "HELLO";
|
||||||
|
int size = 21; // 版本1的大小
|
||||||
|
boolean[][] qr = new boolean[size][size];
|
||||||
|
|
||||||
|
// 1. 三个定位标记
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
for (int j = 0; j < 7; j++) {
|
||||||
|
boolean black = i == 0 || i == 6 || j == 0 || j == 6 || (i > 1 && i < 5 && j > 1 && j < 5);
|
||||||
|
qr[i][j] = qr[i][size - 1 - j] = qr[size - 1 - i][j] = black;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 定时图案(简化)
|
||||||
|
for (int i = 8; i < 13; i++) qr[i][6] = qr[6][i] = (i % 2 == 0);
|
||||||
|
|
||||||
|
// 3. 编码数据(极简编码)
|
||||||
|
byte[] data = text.getBytes();
|
||||||
|
int x = 20, y = 20, up = 1; // 从右下角开始
|
||||||
|
for (byte b : data)
|
||||||
|
for (int bit = 7; bit >= 0; bit--) {
|
||||||
|
while (qr[x][y] || (x == 6 && y < 9) || (y == 6 && x < 9) || (x < 9 && y < 9) ||
|
||||||
|
(x < 9 && y > size - 10) || (y < 9 && x > size - 10)) {
|
||||||
|
if (up > 0) {
|
||||||
|
if (--y < 0) {
|
||||||
|
y = 0;
|
||||||
|
x -= 2;
|
||||||
|
up = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (++y >= size) {
|
||||||
|
y = size - 1;
|
||||||
|
x -= 2;
|
||||||
|
up = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x == 6) x--;
|
||||||
|
}
|
||||||
|
qr[x][y] = ((b >> bit) & 1) == 1;
|
||||||
|
if (up > 0) {
|
||||||
|
if (--y < 0) {
|
||||||
|
y = 0;
|
||||||
|
x -= 2;
|
||||||
|
up = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (++y >= size) {
|
||||||
|
y = size - 1;
|
||||||
|
x -= 2;
|
||||||
|
up = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x == 6) x--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 保存图像
|
||||||
|
int scale = 10, margin = 4;
|
||||||
|
BufferedImage img = new BufferedImage(
|
||||||
|
size * scale + margin * 2, size * scale + margin * 2, BufferedImage.TYPE_INT_RGB);
|
||||||
|
for (int i = 0; i < img.getWidth(); i++)
|
||||||
|
for (int j = 0; j < img.getHeight(); j++)
|
||||||
|
img.setRGB(i, j, 0xFFFFFF); // 白色背景
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
for (int j = 0; j < size; j++)
|
||||||
|
if (qr[i][j])
|
||||||
|
for (int di = 0; di < scale; di++)
|
||||||
|
for (int dj = 0; dj < scale; dj++)
|
||||||
|
img.setRGB(margin + i * scale + di, margin + j * scale + dj, 0x000000);
|
||||||
|
|
||||||
|
ImageIO.write(img, "PNG", new File("qr.png"));
|
||||||
|
System.out.println("二维码已生成");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package com.fuyuanshen.app.controller;
|
package com.fuyuanshen.app.controller;
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||||
import com.fuyuanshen.app.service.AppFileService;
|
import com.fuyuanshen.app.service.AppFileService;
|
||||||
import com.fuyuanshen.common.core.domain.R;
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
import com.fuyuanshen.common.web.core.BaseController;
|
import com.fuyuanshen.common.web.core.BaseController;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package com.fuyuanshen.app.controller;
|
package com.fuyuanshen.app.controller;
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||||
import com.fuyuanshen.common.core.domain.R;
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
||||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||||
|
|||||||
@ -1,13 +1,19 @@
|
|||||||
package com.fuyuanshen.app.controller;
|
package com.fuyuanshen.app.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
|
import com.fuyuanshen.app.domain.dto.AppAudioFileDto;
|
||||||
|
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||||
|
import com.fuyuanshen.app.domain.dto.AppFileRenameDto;
|
||||||
|
import com.fuyuanshen.app.domain.dto.TextToSpeechRequest;
|
||||||
import com.fuyuanshen.app.service.AudioProcessService;
|
import com.fuyuanshen.app.service.AudioProcessService;
|
||||||
import com.fuyuanshen.app.service.VideoProcessService;
|
import com.fuyuanshen.app.service.VideoProcessService;
|
||||||
import com.fuyuanshen.common.core.domain.R;
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
|
||||||
import com.fuyuanshen.common.web.core.BaseController;
|
import com.fuyuanshen.common.web.core.BaseController;
|
||||||
|
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -56,6 +62,7 @@ public class AppVideoController extends BaseController {
|
|||||||
return R.ok(audioProcessService.generateStandardPcmData(text));
|
return R.ok(audioProcessService.generateStandardPcmData(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取文本内容(只支持txt/docx)
|
* 提取文本内容(只支持txt/docx)
|
||||||
*/
|
*/
|
||||||
@ -65,4 +72,68 @@ public class AppVideoController extends BaseController {
|
|||||||
return R.ok("Success",audioProcessService.extract(file));
|
return R.ok("Success",audioProcessService.extract(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传音频文件进行处理
|
||||||
|
* 支持MP3、WAV、PCM格式
|
||||||
|
*/
|
||||||
|
@PostMapping("/uploadAudioToOss")
|
||||||
|
public R<String> uploadAudioToOss(@ModelAttribute AppAudioFileDto bo) {
|
||||||
|
try {
|
||||||
|
String result = audioProcessService.uploadAudioToOss(bo);
|
||||||
|
return R.ok(result);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return R.fail("文件格式错误: " + e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
return R.fail("上传处理失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本转语音
|
||||||
|
* 支持MP3、WAV、PCM格式
|
||||||
|
*/
|
||||||
|
@PostMapping("/ttsToOss")
|
||||||
|
public R<String> textToSpeech(@RequestBody TextToSpeechRequest request) {
|
||||||
|
try {
|
||||||
|
if (request.getDeviceId() == null) {
|
||||||
|
return R.fail("设备ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = audioProcessService.textToSpeech(
|
||||||
|
request.getDeviceId(),
|
||||||
|
request.getText(),
|
||||||
|
request.getFileSuffix()
|
||||||
|
);
|
||||||
|
return R.ok(result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return R.fail("文本转语音失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询语音文件列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/queryAudioFileList")
|
||||||
|
public R<List<AppFileVo>> queryAudioFileList(Long deviceId) {
|
||||||
|
return R.ok(audioProcessService.queryAudioFileList(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除语音文件
|
||||||
|
*/
|
||||||
|
@GetMapping("/deleteAudioFile")
|
||||||
|
public R<Void> deleteAudioFile(Long fileId,Long deviceId) {
|
||||||
|
return audioProcessService.deleteAudioFile(fileId,deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件重命名
|
||||||
|
*/
|
||||||
|
@PostMapping("/renameAudioFile")
|
||||||
|
public R<Void> renameAudioFile(@RequestBody AppFileRenameDto bo) {
|
||||||
|
return audioProcessService.renameAudioFile(bo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HBY670设备控制类
|
* HBY670设备控制类
|
||||||
@ -133,7 +134,7 @@ public class AppDeviceXinghanController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @Log("新增设备")
|
// @Log("新增设备")
|
||||||
@Operation(summary = "新增设备")
|
@Log(title = "新增设备")
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
public R<Void> addDevice(@RequestBody DeviceForm deviceForm) {
|
public R<Void> addDevice(@RequestBody DeviceForm deviceForm) {
|
||||||
try {
|
try {
|
||||||
@ -144,4 +145,26 @@ public class AppDeviceXinghanController extends BaseController {
|
|||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/GetDeviceByName")
|
||||||
|
@Operation(summary = "通过蓝牙名/设备名称查询设备")
|
||||||
|
public R<Object> GetDeviceByName(@RequestBody DeviceForm deviceForm) {
|
||||||
|
Object device = appDeviceService.GetDeviceByName(deviceForm);
|
||||||
|
return R.ok(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping(value = "/getEquipCountByType")
|
||||||
|
@Operation(summary = "查询某个类型下的设备总数量")
|
||||||
|
public R<Object> getEquipCountByType(@RequestBody DeviceForm deviceForm) {
|
||||||
|
Object device = appDeviceService.getEquipCountByType(deviceForm);
|
||||||
|
return R.ok(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/getEquipAllByType")
|
||||||
|
@Operation(summary = "查询某个类型下的设备")
|
||||||
|
public R<List<Map<String,Object>>> getEquipAllByType(@RequestBody DeviceForm deviceForm){
|
||||||
|
List<Map<String,Object>> list=appDeviceService.getEquipAllByType(deviceForm);
|
||||||
|
return R.ok(list);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,104 @@
|
|||||||
|
package com.fuyuanshen.app.controller.device.bjq;
|
||||||
|
|
||||||
|
import com.fuyuanshen.app.domain.vo.AppDeviceHBY100JDetailVo;
|
||||||
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
|
import com.fuyuanshen.common.web.core.BaseController;
|
||||||
|
import com.fuyuanshen.web.controller.device.domain.dto.*;
|
||||||
|
import com.fuyuanshen.web.service.device.DeviceHBY100JBizService;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HBY100J设备控制类
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/app/hby100j/device")
|
||||||
|
public class AppDeviceHBY100JController extends BaseController {
|
||||||
|
|
||||||
|
private final DeviceHBY100JBizService deviceHBY100JBizService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备详细信息
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public R<AppDeviceHBY100JDetailVo> getInfo(@NotNull(message = "主键不能为空")
|
||||||
|
@PathVariable Long id) {
|
||||||
|
return R.ok(deviceHBY100JBizService.getInfo(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新语音
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateVoice")
|
||||||
|
public R<Void> updateVoice(@RequestBody HBY100JUpdateVoiceDto dto) {
|
||||||
|
deviceHBY100JBizService.updateVoice(dto);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制报警
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@PostMapping("/forceAlarmActivation")
|
||||||
|
public R<Void> forceAlarmActivation(@RequestBody HBY100JForceAlarmActivationDto bo) {
|
||||||
|
deviceHBY100JBizService.forceAlarmActivation(bo);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音播报
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PostMapping("/voiceBroadcast")
|
||||||
|
public R<Void> voiceBroadcast(@RequestBody HBY100JVoiceBroadcastDto params) {
|
||||||
|
deviceHBY100JBizService.voiceBroadcast(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪模式
|
||||||
|
*/
|
||||||
|
@PostMapping("/strobeMode")
|
||||||
|
public R<Void> strobeMode(@RequestBody HBY100JStrobeModeDto params) {
|
||||||
|
deviceHBY100JBizService.strobeMode(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 灯光调节
|
||||||
|
*/
|
||||||
|
@PostMapping("/lightAdjustment")
|
||||||
|
public R<Void> lightAdjustment(@RequestBody HBY100JLightAdjustmentDto params) {
|
||||||
|
deviceHBY100JBizService.lightAdjustment(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪频率
|
||||||
|
*/
|
||||||
|
@PostMapping("/strobeFrequency")
|
||||||
|
public R<Void> strobeFrequency(@RequestBody HBY100JStrobeFrequencyDto params) {
|
||||||
|
deviceHBY100JBizService.strobeFrequency(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改音量
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateVolume")
|
||||||
|
public R<Void> updateVolume(@RequestBody HBY100JUpdateVolumeDto params) {
|
||||||
|
deviceHBY100JBizService.updateVolume(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.fuyuanshen.app.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AppAudioFileDto {
|
||||||
|
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件
|
||||||
|
*/
|
||||||
|
private MultipartFile file;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.fuyuanshen.app.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AppFileRenameDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件id
|
||||||
|
*/
|
||||||
|
private Long fileId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备id
|
||||||
|
*/
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件名称
|
||||||
|
*/
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.fuyuanshen.app.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PCM生成请求实体
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PcmGenerationRequest {
|
||||||
|
private String text;
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package com.fuyuanshen.app.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本转语音请求实体
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TextToSpeechRequest {
|
||||||
|
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件后缀格式
|
||||||
|
*/
|
||||||
|
private String fileSuffix;
|
||||||
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
package com.fuyuanshen.app.http;
|
||||||
|
|
||||||
|
import com.alibaba.nls.client.AccessToken;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Base64;
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import static cn.dev33.satoken.SaManager.log;
|
||||||
|
|
||||||
|
public class HttpTtsClient {
|
||||||
|
|
||||||
|
private String accessKeyId;
|
||||||
|
private String accessKeySecret;
|
||||||
|
private String appKey;
|
||||||
|
/**
|
||||||
|
* 阿里云TTS服务基础URL
|
||||||
|
*/
|
||||||
|
private static final String BASE_URL = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
|
||||||
|
|
||||||
|
public HttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) {
|
||||||
|
this.accessKeyId = accessKeyId;
|
||||||
|
this.accessKeySecret = accessKeySecret;
|
||||||
|
this.appKey = appKey;
|
||||||
|
}
|
||||||
|
private String refreshAccessToken() {
|
||||||
|
try {
|
||||||
|
// 调用阿里云API获取访问令牌
|
||||||
|
AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
|
||||||
|
accessToken.apply();
|
||||||
|
String token = accessToken.getToken();
|
||||||
|
log.info("访问令牌刷新成功");
|
||||||
|
|
||||||
|
return token;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("刷新访问令牌失败: {}", e.getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 使用HTTP POST方式调用阿里云TTS服务生成MP3格式语音
|
||||||
|
*/
|
||||||
|
public byte[] synthesizeTextToMp3(String text,String fileSuffix) throws IOException {
|
||||||
|
String endpoint = "https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/tts";
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
// String requestBody = String.format(
|
||||||
|
// "{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}",
|
||||||
|
// appKey,
|
||||||
|
// text.replace("\"", "\\\"")zhide
|
||||||
|
// );
|
||||||
|
|
||||||
|
String token = refreshAccessToken();
|
||||||
|
String requestBody = " {\n" +
|
||||||
|
" \"appkey\":\""+appKey+"\",\n" +
|
||||||
|
" \"voice\":\"zhide\",\n" +
|
||||||
|
" \"text\":\""+text+"\",\n" +
|
||||||
|
" \"token\":\""+token+"\",\n" +
|
||||||
|
" \"volume\": 100,\n" +
|
||||||
|
" \"pitch_rate\": 0,\n" +
|
||||||
|
" \"format\":\""+fileSuffix+"\"\n" +
|
||||||
|
" }";
|
||||||
|
|
||||||
|
URL url = new URL(endpoint);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
// 设置请求方法和头部
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("Content-Type", "application/json");
|
||||||
|
conn.setRequestProperty("Authorization", buildAuthorization());
|
||||||
|
conn.setRequestProperty("Content-Length", String.valueOf(requestBody.getBytes().length));
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
|
||||||
|
// 发送请求体
|
||||||
|
try (OutputStream os = conn.getOutputStream()) {
|
||||||
|
os.write(requestBody.getBytes("UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
int responseCode = conn.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
// 读取音频数据
|
||||||
|
try (InputStream is = conn.getInputStream()) {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
int nRead;
|
||||||
|
byte[] data = new byte[1024];
|
||||||
|
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
||||||
|
buffer.write(data, 0, nRead);
|
||||||
|
}
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IOException("HTTP请求失败,状态码: " + responseCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建授权头部
|
||||||
|
*/
|
||||||
|
private String buildAuthorization() {
|
||||||
|
// 实际实现需要根据阿里云API规范构建签名
|
||||||
|
// 这里是简化示例
|
||||||
|
return "Bearer " + generateAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成访问令牌
|
||||||
|
*/
|
||||||
|
private String generateAccessToken() {
|
||||||
|
// 实际实现需要调用阿里云获取token的API
|
||||||
|
return "your-access-token";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存MP3到文件
|
||||||
|
*/
|
||||||
|
public String saveMp3ToFile(String text, String outputPath) throws IOException {
|
||||||
|
byte[] mp3Data = synthesizeTextToMp3(text,"mp3");
|
||||||
|
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(outputPath)) {
|
||||||
|
fos.write(mp3Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.fuyuanshen.app.http;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class HttpTtsExample {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appKey: lbGuq5K5bEH4uxmT
|
||||||
|
* akId: LTAI5t66moCkhNC32TDJ5ReP
|
||||||
|
* akSecret: 2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH
|
||||||
|
* @param args
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP";
|
||||||
|
String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH";
|
||||||
|
String appKey = "lbGuq5K5bEH4uxmT";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 使用HTTP方式调用
|
||||||
|
HttpTtsClient httpClient = new HttpTtsClient(accessKeyId, accessKeySecret, appKey);
|
||||||
|
|
||||||
|
String text = "前方拥堵,请绕道而行。";
|
||||||
|
String outputPath = "D:\\http_output11.mp3";
|
||||||
|
|
||||||
|
String resultFile = httpClient.saveMp3ToFile(text, outputPath);
|
||||||
|
System.out.println("MP3音频已保存至: " + resultFile);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.fuyuanshen.app.http;
|
||||||
|
|
||||||
|
import okhttp3.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class OkHttpTtsClient {
|
||||||
|
|
||||||
|
private OkHttpClient client = new OkHttpClient();
|
||||||
|
private String accessKeyId;
|
||||||
|
private String accessKeySecret;
|
||||||
|
private String appKey;
|
||||||
|
|
||||||
|
public OkHttpTtsClient(String accessKeyId, String accessKeySecret, String appKey) {
|
||||||
|
this.accessKeyId = accessKeyId;
|
||||||
|
this.accessKeySecret = accessKeySecret;
|
||||||
|
this.appKey = appKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用OkHttp调用TTS服务
|
||||||
|
*/
|
||||||
|
public byte[] synthesizeTextToMp3(String text) throws IOException {
|
||||||
|
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||||
|
|
||||||
|
String jsonPayload = String.format(
|
||||||
|
"{\"appkey\":\"%s\",\"text\":\"%s\",\"voice\":\"zhifeng\",\"format\":\"MP3\",\"sample_rate\":24000,\"volume\":50,\"speech_rate\":0,\"pitch_rate\":0}",
|
||||||
|
appKey,
|
||||||
|
text.replace("\"", "\\\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
RequestBody body = RequestBody.create(JSON,jsonPayload);
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url("https://nls-gateway.cn-shanghai.aliyuncs.com/v1/tts")
|
||||||
|
.post(body)
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.addHeader("Authorization", "Bearer " + getAccessToken())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
throw new IOException("HTTP请求失败: " + response.code());
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseBody responseBody = response.body();
|
||||||
|
if (responseBody != null) {
|
||||||
|
return responseBody.bytes();
|
||||||
|
} else {
|
||||||
|
throw new IOException("响应体为空");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAccessToken() {
|
||||||
|
// 实现获取访问令牌的逻辑
|
||||||
|
return "your-access-token";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package com.fuyuanshen.app.http;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取阿里云TTS服务访问令牌
|
||||||
|
*/
|
||||||
|
public class TokenClient {
|
||||||
|
|
||||||
|
public static String getAccessToken(String accessKeyId, String accessKeySecret) throws IOException {
|
||||||
|
String endpoint = "https://nls-meta.cn-shanghai.aliyuncs.com/v1/token";
|
||||||
|
|
||||||
|
URL url = new URL(endpoint);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
|
||||||
|
// 发送认证信息
|
||||||
|
String params = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s",
|
||||||
|
accessKeyId, accessKeySecret);
|
||||||
|
|
||||||
|
try (OutputStream os = conn.getOutputStream()) {
|
||||||
|
os.write(params.getBytes("UTF-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int responseCode = conn.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
try (InputStream is = conn.getInputStream();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
|
||||||
|
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
response.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析响应获取token(实际需要使用JSON解析库)
|
||||||
|
return response.toString().replaceAll(".*\"access_token\":\"([^\"]+)\".*", "$1");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IOException("获取令牌失败,状态码: " + responseCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,14 @@
|
|||||||
package com.fuyuanshen.app.service;
|
package com.fuyuanshen.app.service;
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||||
import com.fuyuanshen.common.oss.core.OssClient;
|
import com.fuyuanshen.common.oss.core.OssClient;
|
||||||
import com.fuyuanshen.common.oss.factory.OssFactory;
|
import com.fuyuanshen.common.oss.factory.OssFactory;
|
||||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||||
|
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||||
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
||||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||||
import com.fuyuanshen.system.service.ISysOssService;
|
import com.fuyuanshen.system.service.ISysOssService;
|
||||||
@ -96,5 +97,4 @@ public class AppFileService {
|
|||||||
}
|
}
|
||||||
return appBusinessFileService.deleteWithValidByIds(List.of(ids), true);
|
return appBusinessFileService.deleteWithValidByIds(List.of(ids), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,28 @@
|
|||||||
package com.fuyuanshen.app.service;
|
package com.fuyuanshen.app.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.fuyuanshen.app.domain.dto.AppAudioFileDto;
|
||||||
|
import com.fuyuanshen.app.domain.dto.AppFileRenameDto;
|
||||||
|
import com.fuyuanshen.app.http.HttpTtsClient;
|
||||||
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
|
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||||
|
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||||
|
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||||
|
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||||
|
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||||
|
import com.fuyuanshen.equipment.mapper.AppBusinessFileMapper;
|
||||||
|
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||||
import com.fuyuanshen.equipment.utils.AlibabaTTSUtil;
|
import com.fuyuanshen.equipment.utils.AlibabaTTSUtil;
|
||||||
import com.fuyuanshen.equipment.utils.AudioProcessUtil;
|
import com.fuyuanshen.equipment.utils.AudioProcessUtil;
|
||||||
|
import com.fuyuanshen.equipment.utils.FileHashUtil;
|
||||||
|
import com.fuyuanshen.equipment.utils.Mp3Duration;
|
||||||
|
import com.fuyuanshen.global.mqtt.utils.FfmpegVolumeUtil;
|
||||||
|
import com.fuyuanshen.global.mqtt.utils.FfmpegVolumeUtil3;
|
||||||
|
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||||
|
import com.fuyuanshen.system.service.ISysOssService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@ -16,9 +35,12 @@ import javax.xml.stream.XMLStreamException;
|
|||||||
import javax.xml.stream.XMLStreamReader;
|
import javax.xml.stream.XMLStreamReader;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
@ -39,6 +61,21 @@ public class AudioProcessService {
|
|||||||
private final AudioProcessUtil audioProcessUtil;
|
private final AudioProcessUtil audioProcessUtil;
|
||||||
private final AlibabaTTSUtil alibabaTTSUtil;
|
private final AlibabaTTSUtil alibabaTTSUtil;
|
||||||
|
|
||||||
|
private final FileHashUtil fileHashUtil;
|
||||||
|
private final ISysOssService ossService;
|
||||||
|
private final IAppBusinessFileService appBusinessFileService;
|
||||||
|
private final AppBusinessFileMapper appBusinessFileMapper;
|
||||||
|
|
||||||
|
// String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP";
|
||||||
|
// String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH";
|
||||||
|
// String appKey = "lbGuq5K5bEH4uxmT";
|
||||||
|
@Value("${alibaba.tts.appKey}")
|
||||||
|
private String appKey;
|
||||||
|
@Value("${alibaba.tts.akId}")
|
||||||
|
private String accessKeyId;
|
||||||
|
@Value("${alibaba.tts.akSecret}")
|
||||||
|
private String accessKeySecret;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理上传的音频文件
|
* 处理上传的音频文件
|
||||||
*/
|
*/
|
||||||
@ -172,9 +209,32 @@ public class AudioProcessService {
|
|||||||
fos.write(data);
|
fos.write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return file.getAbsolutePath();
|
return file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String saveByteArrayToFile(InputStream inputStream, String filename) throws IOException {
|
||||||
|
// 确定保存路径(可以是临时目录或指定目录)
|
||||||
|
String directory = System.getProperty("java.io.tmpdir"); // 使用系统临时目录
|
||||||
|
File dir = new File(directory);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建完整文件路径
|
||||||
|
File file = new File(dir, filename);
|
||||||
|
|
||||||
|
// 从输入流读取数据并写入文件
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
InputStream is = inputStream) {
|
||||||
|
byte[] buffer = new byte[8192]; // 8KB缓冲区
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = is.read(buffer)) != -1) {
|
||||||
|
fos.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,4 +365,214 @@ public class AudioProcessService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String uploadAudioToOss(AppAudioFileDto bo) {
|
||||||
|
MultipartFile file = bo.getFile();
|
||||||
|
// 校验文件格式和大小
|
||||||
|
validateAudioFileForRestful(file);
|
||||||
|
// 上传文件
|
||||||
|
// SysOssVo upload = sysOssService.upload(file);
|
||||||
|
String filename = file.getOriginalFilename();
|
||||||
|
String savedPath = null;
|
||||||
|
try {
|
||||||
|
String fileHash = fileHashUtil.hash(file);
|
||||||
|
SysOssVo upload = ossService.updateHash(file, fileHash);
|
||||||
|
// 强制将HTTP替换为HTTPS
|
||||||
|
if (upload.getUrl() != null && upload.getUrl().startsWith("http://")) {
|
||||||
|
upload.setUrl(upload.getUrl().replaceFirst("^http://", "https://"));
|
||||||
|
}
|
||||||
|
String fileSuffix = filename.substring(filename.lastIndexOf('.')).toLowerCase();
|
||||||
|
AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo();
|
||||||
|
appBusinessFileBo.setFileId(upload.getOssId());
|
||||||
|
appBusinessFileBo.setBusinessId(bo.getDeviceId());
|
||||||
|
appBusinessFileBo.setFileType(3L);
|
||||||
|
appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId());
|
||||||
|
savedPath = saveByteArrayToFile(file.getInputStream(), generateRandomFileName(fileSuffix));
|
||||||
|
if (savedPath != null) {
|
||||||
|
log.info("MP3文件已保存: {}", savedPath);
|
||||||
|
Integer mp3Duration = Mp3Duration.getMp3Duration(savedPath);
|
||||||
|
log.info("MP3文件时长: {} 秒", mp3Duration);
|
||||||
|
appBusinessFileBo.setDuration(mp3Duration);
|
||||||
|
}
|
||||||
|
appBusinessFileService.insertByBo(appBusinessFileBo);
|
||||||
|
if (upload != null) {
|
||||||
|
return upload.getUrl();
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
log.error("上传音频文件失败", e);
|
||||||
|
}finally {
|
||||||
|
log.info("删除临时文件: {}", savedPath);
|
||||||
|
if(savedPath != null){
|
||||||
|
deleteTempFile(new File(savedPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验音频文件格式
|
||||||
|
*/
|
||||||
|
private void validateAudioFileForRestful(MultipartFile file) {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("上传文件不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (originalFilename == null) {
|
||||||
|
throw new IllegalArgumentException("文件名不能为空");
|
||||||
|
}
|
||||||
|
List<String> SUPPORTED_FORMATS = Arrays.asList(
|
||||||
|
".wav", ".mp3", ".pcm"
|
||||||
|
);
|
||||||
|
|
||||||
|
String ext = originalFilename.substring(originalFilename.lastIndexOf('.')).toLowerCase();
|
||||||
|
// 检查文件扩展名
|
||||||
|
if (!SUPPORTED_FORMATS.contains(ext)) {
|
||||||
|
throw new IllegalArgumentException("只允许上传MP3、WAV、PCM格式的音频文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件大小
|
||||||
|
if (file.getSize() > MAX_AUDIO_SIZE) {
|
||||||
|
throw new IllegalArgumentException("音频大小不能超过5MB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断文件是否为支持的音频格式
|
||||||
|
*/
|
||||||
|
private boolean isSupportedFormat(String filename) {
|
||||||
|
if (filename == null || filename.lastIndexOf('.') == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String ext = filename.substring(filename.lastIndexOf('.')).toLowerCase();
|
||||||
|
return SUPPORTED_FORMATS.contains(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String textToSpeech(Long deviceId,String text, String fileSuffix) {
|
||||||
|
//支持PCM/WAV/MP3格式
|
||||||
|
if (fileSuffix == null || fileSuffix.isEmpty()) {
|
||||||
|
fileSuffix = "mp3";
|
||||||
|
}
|
||||||
|
fileSuffix = fileSuffix.toLowerCase();
|
||||||
|
List<String> SUPPORTED_FORMATS = Arrays.asList(
|
||||||
|
"wav", "mp3", "pcm"
|
||||||
|
);
|
||||||
|
boolean contains = SUPPORTED_FORMATS.contains(fileSuffix);
|
||||||
|
if (!contains) {
|
||||||
|
throw new IllegalArgumentException("不支持的音频格式");
|
||||||
|
}
|
||||||
|
// String accessKeyId = "LTAI5t66moCkhNC32TDJ5ReP";
|
||||||
|
// String accessKeySecret = "2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH";
|
||||||
|
// String appKey = "lbGuq5K5bEH4uxmT";
|
||||||
|
String savedPath = null;
|
||||||
|
String savedMp3VolumePath = null;
|
||||||
|
try {
|
||||||
|
// 使用HTTP方式调用
|
||||||
|
HttpTtsClient httpClient = new HttpTtsClient(accessKeyId, accessKeySecret, appKey);
|
||||||
|
//
|
||||||
|
byte[] mp3Data = httpClient.synthesizeTextToMp3(text,fileSuffix);
|
||||||
|
// byte[] mp3Data = alibabaTTSUtil.synthesizeTextToMp3(text,fileSuffix);
|
||||||
|
|
||||||
|
|
||||||
|
AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo();
|
||||||
|
|
||||||
|
savedPath = saveByteArrayToFile(mp3Data, generateRandomFileName(fileSuffix));
|
||||||
|
|
||||||
|
Integer mp3Duration = getMp3Duration2(savedPath);
|
||||||
|
appBusinessFileBo.setDuration(mp3Duration);
|
||||||
|
|
||||||
|
String directory = System.getProperty("java.io.tmpdir"); // 使用系统临时目录
|
||||||
|
String fileName = generateRandomFileName(fileSuffix);
|
||||||
|
savedMp3VolumePath = directory + "/" + fileName;
|
||||||
|
log.info("保存MP3文件: {}", savedMp3VolumePath);
|
||||||
|
FfmpegVolumeUtil.increaseMp3Volume(savedPath, savedMp3VolumePath, 12);
|
||||||
|
|
||||||
|
File file = new File(savedMp3VolumePath);
|
||||||
|
String fileHash = fileHashUtil.getFileHash(file,"SHA-256");
|
||||||
|
SysOssVo upload = ossService.updateHash(file, fileHash);
|
||||||
|
|
||||||
|
// 强制将HTTP替换为HTTPS
|
||||||
|
if (upload.getUrl() != null && upload.getUrl().startsWith("http://")) {
|
||||||
|
upload.setUrl(upload.getUrl().replaceFirst("^http://", "https://"));
|
||||||
|
}
|
||||||
|
|
||||||
|
appBusinessFileBo.setFileId(upload.getOssId());
|
||||||
|
appBusinessFileBo.setBusinessId(deviceId);
|
||||||
|
appBusinessFileBo.setFileType(3L);
|
||||||
|
appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId());
|
||||||
|
appBusinessFileService.insertByBo(appBusinessFileBo);
|
||||||
|
if (upload != null) {
|
||||||
|
return upload.getUrl();
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
log.error("上传音频文件失败", e);
|
||||||
|
} finally {
|
||||||
|
log.info("删除savedPath临时文件: {}", savedPath);
|
||||||
|
if(savedPath != null){
|
||||||
|
deleteTempFile(new File(savedPath));
|
||||||
|
}
|
||||||
|
if(savedMp3VolumePath != null){
|
||||||
|
log.info("删除savedMp3VolumePath临时文件: {}", savedMp3VolumePath);
|
||||||
|
deleteTempFile(new File(savedMp3VolumePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer getMp3Duration2(String savedPath) {
|
||||||
|
if (savedPath != null) {
|
||||||
|
log.info("MP3文件已保存: {}", savedPath);
|
||||||
|
Integer mp3Duration = Mp3Duration.getMp3Duration(savedPath);
|
||||||
|
log.info("MP3文件时长: {} 秒", mp3Duration);
|
||||||
|
return mp3Duration;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Random random = new Random();
|
||||||
|
private static final DateTimeFormatter formatter =
|
||||||
|
DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||||
|
/**
|
||||||
|
* 生成纯随机文件名(无原文件名依赖)
|
||||||
|
*/
|
||||||
|
public static String generateRandomFileName(String extension) {
|
||||||
|
String timestamp = LocalDateTime.now().format(formatter);
|
||||||
|
int randomNum = random.nextInt(10000);
|
||||||
|
String uuidPart = UUID.randomUUID().toString().substring(0, 8);
|
||||||
|
|
||||||
|
if (!extension.startsWith(".")) {
|
||||||
|
extension = "." + extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AppFileVo> queryAudioFileList(Long deviceId) {
|
||||||
|
if(deviceId == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Long userId = LoginHelper.getUserId();
|
||||||
|
AppBusinessFileBo bo = new AppBusinessFileBo();
|
||||||
|
bo.setBusinessId(deviceId);
|
||||||
|
bo.setCreateBy(userId);
|
||||||
|
bo.setFileType(3L);
|
||||||
|
return appBusinessFileService.queryAppFileList(bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public R<Void> deleteAudioFile(Long fileId,Long deviceId) {
|
||||||
|
UpdateWrapper<AppBusinessFile> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("file_id",fileId);
|
||||||
|
updateWrapper.eq("business_id",deviceId);
|
||||||
|
appBusinessFileMapper.delete(updateWrapper);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public R<Void> renameAudioFile(AppFileRenameDto bo) {
|
||||||
|
UpdateWrapper<AppBusinessFile> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("file_id",bo.getFileId());
|
||||||
|
updateWrapper.eq("business_id",bo.getDeviceId());
|
||||||
|
updateWrapper.set("re_name",bo.getFileName());
|
||||||
|
appBusinessFileMapper.update(updateWrapper);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,9 +1,5 @@
|
|||||||
package com.fuyuanshen.global.mqtt.base;
|
package com.fuyuanshen.global.mqtt.base;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.core.task.TaskExecutor;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -16,9 +12,9 @@ import java.util.List;
|
|||||||
@Component
|
@Component
|
||||||
public class MqttRuleEngine {
|
public class MqttRuleEngine {
|
||||||
|
|
||||||
@Autowired
|
// @Autowired
|
||||||
@Qualifier("threadPoolTaskExecutor")
|
// @Qualifier("threadPoolTaskExecutor")
|
||||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
// private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||||
|
|
||||||
private final LinkedHashMap<String, MqttMessageRule> rulesMap = new LinkedHashMap<>();
|
private final LinkedHashMap<String, MqttMessageRule> rulesMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
@ -41,7 +37,8 @@ public class MqttRuleEngine {
|
|||||||
int commandType = context.getCommandType();
|
int commandType = context.getCommandType();
|
||||||
MqttMessageRule mqttMessageRule = rulesMap.get("Light_" + commandType);
|
MqttMessageRule mqttMessageRule = rulesMap.get("Light_" + commandType);
|
||||||
if (mqttMessageRule != null) {
|
if (mqttMessageRule != null) {
|
||||||
threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context));
|
// threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context));
|
||||||
|
mqttMessageRule.execute(context);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT消息处理接口
|
||||||
|
*/
|
||||||
|
public interface NewMqttMessageRule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取命令类型
|
||||||
|
* @return 命令类型
|
||||||
|
*/
|
||||||
|
String getCommandType();
|
||||||
|
/**
|
||||||
|
* 执行处理
|
||||||
|
* @param context 处理上下文
|
||||||
|
*/
|
||||||
|
void execute(NewMqttRuleContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取优先级,数值越小优先级越高
|
||||||
|
* @return 优先级
|
||||||
|
*/
|
||||||
|
default int getPriority() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.base;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT消息处理上下文
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class NewMqttRuleContext {
|
||||||
|
/**
|
||||||
|
* 命令类型
|
||||||
|
*/
|
||||||
|
private String commandType;
|
||||||
|
/**
|
||||||
|
* 设备IMEI
|
||||||
|
*/
|
||||||
|
private String deviceImei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT消息负载字典
|
||||||
|
*/
|
||||||
|
private Map<String, Object> payloadDict;
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.base;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT消息引擎
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class NewMqttRuleEngine {
|
||||||
|
|
||||||
|
// @Autowired
|
||||||
|
// @Qualifier("threadPoolTaskExecutor")
|
||||||
|
// private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||||
|
|
||||||
|
private final LinkedHashMap<String, NewMqttMessageRule> rulesMap = new LinkedHashMap<>();
|
||||||
|
public NewMqttRuleEngine(List<NewMqttMessageRule> rules) {
|
||||||
|
// 按优先级排序
|
||||||
|
rules.sort(Comparator.comparing(NewMqttMessageRule::getPriority));
|
||||||
|
rules.forEach(rule -> rulesMap.put(rule.getCommandType(), rule)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行匹配
|
||||||
|
* @param context 处理上下文
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean executeRule(NewMqttRuleContext context) {
|
||||||
|
String commandType = context.getCommandType();
|
||||||
|
// String funcType = context.getFuncType();
|
||||||
|
NewMqttMessageRule mqttMessageRule = rulesMap.get(commandType);
|
||||||
|
if (mqttMessageRule != null) {
|
||||||
|
// threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context));
|
||||||
|
mqttMessageRule.execute(context);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -44,12 +44,12 @@ public class MqttInboundConfiguration {
|
|||||||
if (url == null) {
|
if (url == null) {
|
||||||
throw new IllegalStateException("MQTT服务器URL未配置");
|
throw new IllegalStateException("MQTT服务器URL未配置");
|
||||||
}
|
}
|
||||||
|
String subTopic = mqttPropertiesConfig.getSubTopic();
|
||||||
MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
|
MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
|
||||||
url,
|
url,
|
||||||
clientId,
|
clientId,
|
||||||
mqttPahoClientFactory,
|
mqttPahoClientFactory,
|
||||||
mqttPropertiesConfig.getSubTopic().split(",")
|
subTopic.split(",")
|
||||||
);
|
);
|
||||||
mqttPahoMessageDrivenChannelAdapter.setQos(1);
|
mqttPahoMessageDrivenChannelAdapter.setQos(1);
|
||||||
mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
|
mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class MqttOutboundConfiguration {
|
|||||||
mqttPahoClientFactory
|
mqttPahoClientFactory
|
||||||
);
|
);
|
||||||
mqttPahoMessageHandler.setDefaultQos(1);
|
mqttPahoMessageHandler.setDefaultQos(1);
|
||||||
mqttPahoMessageHandler.setDefaultTopic("B/#");
|
mqttPahoMessageHandler.setDefaultTopic(mqttPropertiesConfig.getPubTopic());
|
||||||
mqttPahoMessageHandler.setAsync(true);
|
mqttPahoMessageHandler.setAsync(true);
|
||||||
return mqttPahoMessageHandler;
|
return mqttPahoMessageHandler;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,8 @@ public class MqttPropertiesConfig {
|
|||||||
private String url;
|
private String url;
|
||||||
private String subClientId;
|
private String subClientId;
|
||||||
private String subTopic;
|
private String subTopic;
|
||||||
|
private String subTopic2;
|
||||||
private String pubClientId;
|
private String pubClientId;
|
||||||
private String pubTopic;
|
private String pubTopic;
|
||||||
|
private String pubTopic2;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
//package com.fuyuanshen.global.mqtt.config;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//import cn.hutool.core.lang.UUID;
|
||||||
|
//import com.fuyuanshen.global.mqtt.receiver.NewReceiverMessageHandler;
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
//import org.springframework.context.annotation.Bean;
|
||||||
|
//import org.springframework.context.annotation.Configuration;
|
||||||
|
//import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
//import org.springframework.integration.channel.DirectChannel;
|
||||||
|
//import org.springframework.integration.core.MessageProducer;
|
||||||
|
//import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||||
|
//import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
|
||||||
|
//import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
|
||||||
|
//import org.springframework.messaging.MessageChannel;
|
||||||
|
//import org.springframework.messaging.MessageHandler;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//@Configuration
|
||||||
|
//@Slf4j
|
||||||
|
//public class NewMqttInboundConfiguration {
|
||||||
|
// @Autowired
|
||||||
|
// private MqttPropertiesConfig mqttPropertiesConfig;
|
||||||
|
// @Autowired
|
||||||
|
// private MqttPahoClientFactory mqttPahoClientFactory;
|
||||||
|
// @Autowired
|
||||||
|
// private NewReceiverMessageHandler receiverMessageHandler2;
|
||||||
|
// //消息通道
|
||||||
|
// @Bean
|
||||||
|
// public MessageChannel messageInboundChannel2(){
|
||||||
|
// return new DirectChannel();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 配置入站适配器
|
||||||
|
// * 作用: 设置订阅主题,以及指定消息的通道 等相关属性
|
||||||
|
// * */
|
||||||
|
// @Bean
|
||||||
|
// public MessageProducer messageProducer2(){
|
||||||
|
// // 生成一个不重复的随机数
|
||||||
|
// String clientId = mqttPropertiesConfig.getSubClientId() + "_" + UUID.fastUUID();
|
||||||
|
// String subTopic = mqttPropertiesConfig.getSubTopic2();
|
||||||
|
// log.info("订阅主题:{}", subTopic);
|
||||||
|
// MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
|
||||||
|
// mqttPropertiesConfig.getUrl(),
|
||||||
|
// clientId,
|
||||||
|
// mqttPahoClientFactory,
|
||||||
|
// subTopic.split(",")
|
||||||
|
// );
|
||||||
|
// mqttPahoMessageDrivenChannelAdapter.setQos(1);
|
||||||
|
// mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
|
||||||
|
// mqttPahoMessageDrivenChannelAdapter.setOutputChannel(messageInboundChannel2());
|
||||||
|
// return mqttPahoMessageDrivenChannelAdapter;
|
||||||
|
// }
|
||||||
|
// /** 指定处理消息来自哪个通道 */
|
||||||
|
// @Bean
|
||||||
|
// @ServiceActivator(inputChannel = "messageInboundChannel2")
|
||||||
|
// public MessageHandler messageHandler2(){
|
||||||
|
// return receiverMessageHandler2;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // @Bean
|
||||||
|
// // @ServiceActivator(inputChannel = "messageInboundChannel") // 确保通道名称正确
|
||||||
|
// // public MessageHandler deviceAlarmMessageHandler() {
|
||||||
|
// // return new DeviceAlrmMessageHandler();
|
||||||
|
// // }
|
||||||
|
//}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
//package com.fuyuanshen.global.mqtt.config;
|
||||||
|
//
|
||||||
|
//import cn.hutool.core.lang.UUID;
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
//import org.springframework.context.annotation.Bean;
|
||||||
|
//import org.springframework.context.annotation.Configuration;
|
||||||
|
//import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
//import org.springframework.integration.channel.DirectChannel;
|
||||||
|
//import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||||
|
//import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
|
||||||
|
//import org.springframework.messaging.MessageChannel;
|
||||||
|
//import org.springframework.messaging.MessageHandler;
|
||||||
|
//
|
||||||
|
//@Configuration
|
||||||
|
//@Slf4j
|
||||||
|
//public class NewMqttOutboundConfiguration {
|
||||||
|
// @Autowired
|
||||||
|
// private MqttPropertiesConfig mqttPropertiesConfig;
|
||||||
|
// @Autowired
|
||||||
|
// private MqttPahoClientFactory mqttPahoClientFactory;
|
||||||
|
//
|
||||||
|
// // 消息通道
|
||||||
|
// @Bean
|
||||||
|
// public MessageChannel mqttOutboundChannel2(){
|
||||||
|
// return new DirectChannel();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// /** 配置出站消息处理器 */
|
||||||
|
// @Bean
|
||||||
|
// @ServiceActivator(inputChannel = "mqttOutboundChannel2") // 指定处理器针对哪个通道的消息进行处理
|
||||||
|
// public MessageHandler mqttOutboundMessageHandler2(){
|
||||||
|
// String clientId = mqttPropertiesConfig.getPubClientId() + "_" + UUID.fastUUID();
|
||||||
|
// MqttPahoMessageHandler mqttPahoMessageHandler = new MqttPahoMessageHandler(
|
||||||
|
// mqttPropertiesConfig.getUrl(),
|
||||||
|
// clientId,
|
||||||
|
// mqttPahoClientFactory
|
||||||
|
// );
|
||||||
|
// mqttPahoMessageHandler.setDefaultQos(1);
|
||||||
|
// mqttPahoMessageHandler.setDefaultTopic(mqttPropertiesConfig.getPubTopic2());
|
||||||
|
// mqttPahoMessageHandler.setAsync(true);
|
||||||
|
// return mqttPahoMessageHandler;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.config;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.UUID;
|
||||||
|
//import com.fuyuanshen.global.mqtt.receiver.NewReceiverMessageHandler;
|
||||||
|
import com.fuyuanshen.global.mqtt.receiver.RegisEquipReceiverMessageHandler;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
import org.springframework.integration.channel.DirectChannel;
|
||||||
|
import org.springframework.integration.core.MessageProducer;
|
||||||
|
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||||
|
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
|
||||||
|
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
|
||||||
|
import org.springframework.messaging.MessageChannel;
|
||||||
|
import org.springframework.messaging.MessageHandler;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
|
public class RegisEquipMqttInboundConfiguration {
|
||||||
|
@Autowired
|
||||||
|
private MqttPropertiesConfig mqttPropertiesConfig;
|
||||||
|
@Autowired
|
||||||
|
private MqttPahoClientFactory mqttPahoClientFactory;
|
||||||
|
@Autowired
|
||||||
|
private RegisEquipReceiverMessageHandler receiverMessageHandler3;
|
||||||
|
//消息通道
|
||||||
|
@Bean
|
||||||
|
public MessageChannel messageInboundChannel3(){
|
||||||
|
return new DirectChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置入站适配器
|
||||||
|
* 作用: 设置订阅主题,以及指定消息的通道 等相关属性
|
||||||
|
* */
|
||||||
|
@Bean
|
||||||
|
public MessageProducer messageProducer3(){
|
||||||
|
// 生成一个不重复的随机数
|
||||||
|
String clientId = mqttPropertiesConfig.getSubClientId() + "_" + UUID.fastUUID();
|
||||||
|
String subTopic = mqttPropertiesConfig.getSubTopic2();
|
||||||
|
log.info("订阅主题:{}", subTopic);
|
||||||
|
MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter = new MqttPahoMessageDrivenChannelAdapter(
|
||||||
|
mqttPropertiesConfig.getUrl(),
|
||||||
|
clientId,
|
||||||
|
mqttPahoClientFactory,
|
||||||
|
subTopic.split(",")
|
||||||
|
);
|
||||||
|
mqttPahoMessageDrivenChannelAdapter.setQos(1);
|
||||||
|
mqttPahoMessageDrivenChannelAdapter.setConverter(new DefaultPahoMessageConverter());
|
||||||
|
mqttPahoMessageDrivenChannelAdapter.setOutputChannel(messageInboundChannel3());
|
||||||
|
return mqttPahoMessageDrivenChannelAdapter;
|
||||||
|
}
|
||||||
|
/** 指定处理消息来自哪个通道 */
|
||||||
|
@Bean
|
||||||
|
@ServiceActivator(inputChannel = "messageInboundChannel3")
|
||||||
|
public MessageHandler messageHandler3(){
|
||||||
|
return receiverMessageHandler3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Bean
|
||||||
|
// @ServiceActivator(inputChannel = "messageInboundChannel") // 确保通道名称正确
|
||||||
|
// public MessageHandler deviceAlarmMessageHandler() {
|
||||||
|
// return new DeviceAlrmMessageHandler();
|
||||||
|
// }
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.UUID;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
import org.springframework.integration.channel.DirectChannel;
|
||||||
|
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||||
|
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
|
||||||
|
import org.springframework.messaging.MessageChannel;
|
||||||
|
import org.springframework.messaging.MessageHandler;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
|
public class RegisEquipMqttOutboundConfiguration {
|
||||||
|
@Autowired
|
||||||
|
private MqttPropertiesConfig mqttPropertiesConfig;
|
||||||
|
@Autowired
|
||||||
|
private MqttPahoClientFactory mqttPahoClientFactory;
|
||||||
|
|
||||||
|
// 消息通道
|
||||||
|
@Bean
|
||||||
|
public MessageChannel mqttOutboundChannel3(){
|
||||||
|
return new DirectChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 配置出站消息处理器 */
|
||||||
|
@Bean
|
||||||
|
@ServiceActivator(inputChannel = "mqttOutboundChannel3") // 指定处理器针对哪个通道的消息进行处理
|
||||||
|
public MessageHandler mqttOutboundMessageHandler3(){
|
||||||
|
String clientId = mqttPropertiesConfig.getPubClientId() + "_" + UUID.fastUUID();
|
||||||
|
MqttPahoMessageHandler mqttPahoMessageHandler = new MqttPahoMessageHandler(
|
||||||
|
mqttPropertiesConfig.getUrl(),
|
||||||
|
clientId,
|
||||||
|
mqttPahoClientFactory
|
||||||
|
);
|
||||||
|
mqttPahoMessageHandler.setDefaultQos(1);
|
||||||
|
mqttPahoMessageHandler.setDefaultTopic(mqttPropertiesConfig.getPubTopic2());
|
||||||
|
mqttPahoMessageHandler.setAsync(true);
|
||||||
|
return mqttPahoMessageHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,4 +13,5 @@ public interface MqttConstants {
|
|||||||
*/
|
*/
|
||||||
String GLOBAL_SUB_KEY = "A/";
|
String GLOBAL_SUB_KEY = "A/";
|
||||||
|
|
||||||
|
String GLOBAL_PUB_KEY2 = "command/";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
package com.fuyuanshen.global.mqtt.publish;
|
package com.fuyuanshen.global.mqtt.publish;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/")
|
@RequestMapping("/api")
|
||||||
|
@SaIgnore
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class DeviceDataController {
|
public class DeviceDataController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MqttClientTest mqttClientTest;
|
private MqttClientTest mqttClientTest;
|
||||||
|
@GetMapping("/command")
|
||||||
// @PostMapping("/{deviceId}/command")
|
|
||||||
public ResponseEntity<String> sendCommand() {
|
public ResponseEntity<String> sendCommand() {
|
||||||
|
|
||||||
mqttClientTest.sendMsg();
|
mqttClientTest.sendMsg();
|
||||||
|
|||||||
@ -13,10 +13,10 @@ public class MqttClientTest {
|
|||||||
private MqttGateway mqttGateway;
|
private MqttGateway mqttGateway;
|
||||||
|
|
||||||
public void sendMsg() {
|
public void sendMsg() {
|
||||||
mqttGateway.sendMsgToMqtt("worker/location/1", "hello mqtt spring boot");
|
mqttGateway.sendMsgToMqtt("command/894078/HBY670/864865082081523", "hello mqtt spring boot");
|
||||||
log.info("message is send");
|
log.info("message is send");
|
||||||
|
|
||||||
mqttGateway.sendMsgToMqtt("worker/alert/2", "hello mqtt spring boot2");
|
mqttGateway.sendMsgToMqtt("report/894078/HBY670/864865082081523", "hello mqtt spring boot2");
|
||||||
log.info("message is send2");
|
log.info("message is send2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
//package com.fuyuanshen.global.mqtt.receiver;
|
||||||
|
//
|
||||||
|
//import cn.hutool.core.lang.Dict;
|
||||||
|
//import com.baomidou.lock.LockTemplate;
|
||||||
|
//import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
//import com.fuyuanshen.common.core.utils.StringUtils;
|
||||||
|
//import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||||
|
//import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
//import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
//import com.fuyuanshen.global.mqtt.base.NewMqttRuleEngine;
|
||||||
|
//import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
|
//import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
|
//import org.redisson.api.RLock;
|
||||||
|
//import org.redisson.api.RedissonClient;
|
||||||
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
//import org.springframework.messaging.Message;
|
||||||
|
//import org.springframework.messaging.MessageHandler;
|
||||||
|
//import org.springframework.messaging.MessageHeaders;
|
||||||
|
//import org.springframework.messaging.MessagingException;
|
||||||
|
//import org.springframework.stereotype.Service;
|
||||||
|
//
|
||||||
|
//import java.time.Duration;
|
||||||
|
//import java.util.Objects;
|
||||||
|
//import java.util.concurrent.TimeUnit;
|
||||||
|
//
|
||||||
|
//import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
//
|
||||||
|
//@Service
|
||||||
|
//@Slf4j
|
||||||
|
//public class NewReceiverMessageHandler implements MessageHandler {
|
||||||
|
//
|
||||||
|
// @Autowired
|
||||||
|
// private NewMqttRuleEngine newRuleEngine;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void handleMessage(Message<?> message) throws MessagingException {
|
||||||
|
//
|
||||||
|
// Object payload = message.getPayload();
|
||||||
|
// MessageHeaders headers = message.getHeaders();
|
||||||
|
// String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
|
||||||
|
// String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString();
|
||||||
|
// String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString();
|
||||||
|
//
|
||||||
|
// log.info("MQTT2 payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}",
|
||||||
|
// payload, receivedTopic, receivedQos, timestamp);
|
||||||
|
//
|
||||||
|
// Dict payloadDict = JsonUtils.parseMap(payload.toString());
|
||||||
|
// if (receivedTopic == null || payloadDict == null) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// String imei = payloadDict.getStr("imei");
|
||||||
|
// String funcType = payloadDict.getStr("funcType");
|
||||||
|
// // 执行业务逻辑
|
||||||
|
// if(StringUtils.isNotBlank(imei)){
|
||||||
|
// String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||||
|
// String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||||
|
// RedisUtils.offerDeduplicated(queueKey,dedupKey,imei, Duration.ofSeconds(900));
|
||||||
|
// //在线状态
|
||||||
|
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ imei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||||
|
// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// String[] topicArr = receivedTopic.split("/");
|
||||||
|
//
|
||||||
|
// NewMqttRuleContext context = new NewMqttRuleContext();
|
||||||
|
// context.setCommandType(topicArr[2]+"_"+funcType);
|
||||||
|
// context.setDeviceImei(imei);
|
||||||
|
// context.setPayloadDict(payloadDict);
|
||||||
|
//
|
||||||
|
// boolean ruleExecuted = newRuleEngine.executeRule(context);
|
||||||
|
//
|
||||||
|
// if (!ruleExecuted) {
|
||||||
|
// log.warn("未找到匹配的规则来处理命令类型: {}", topicArr[2] + " : " +funcType);
|
||||||
|
// }
|
||||||
|
//// final LockInfo lockInfo = lockTemplate.lock(GlobalConstants.GLOBAL_REDIS_KEY + lockKey + imei, 100L, 3000L, RedissonLockExecutor.class);
|
||||||
|
//// if (null == lockInfo) {
|
||||||
|
//// log.info("MQTT3业务处理中,请稍后再试:funcType=>{},imei=>{}",funcType,imei);
|
||||||
|
//// return;
|
||||||
|
//// }
|
||||||
|
////// 获取锁成功,处理业务
|
||||||
|
//// try {
|
||||||
|
//// if(StringUtils.isNotBlank(imei)){
|
||||||
|
//// String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY;
|
||||||
|
//// String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY;
|
||||||
|
//// RedisUtils.offerDeduplicated(queueKey,dedupKey,imei, Duration.ofSeconds(900));
|
||||||
|
//// //在线状态
|
||||||
|
//// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ imei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
||||||
|
//// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// String[] topicArr = receivedTopic.split("/");
|
||||||
|
////
|
||||||
|
//// NewMqttRuleContext context = new NewMqttRuleContext();
|
||||||
|
//// context.setCommandType(topicArr[2]+"_"+funcType);
|
||||||
|
//// context.setDeviceImei(imei);
|
||||||
|
//// context.setPayloadDict(payloadDict);
|
||||||
|
////
|
||||||
|
//// boolean ruleExecuted = newRuleEngine.executeRule(context);
|
||||||
|
////
|
||||||
|
//// if (!ruleExecuted) {
|
||||||
|
//// log.warn("未找到匹配的规则来处理命令类型: {}", topicArr[2] + " : " +funcType);
|
||||||
|
//// }
|
||||||
|
//// } finally {
|
||||||
|
//// //释放锁
|
||||||
|
//// lockTemplate.releaseLock(lockInfo);
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// /* ===== 追加:根据报文内容识别格式并统一解析 ===== */
|
||||||
|
//// int intType = MqttXinghanCommandType.computeVirtualCommandType(payloadDict);
|
||||||
|
//// if (intType > 0) {
|
||||||
|
//// MqttRuleContext newCtx = new MqttRuleContext();
|
||||||
|
//// String commandType = "Light_"+intType;
|
||||||
|
//// newCtx.setCommandType(commandType);
|
||||||
|
//// newCtx.setDeviceImei(imei);
|
||||||
|
//// newCtx.setPayloadDict(payloadDict);
|
||||||
|
////
|
||||||
|
//// boolean ok = ruleEngine.executeRule(newCtx);
|
||||||
|
//// if (!ok) {
|
||||||
|
//// log.warn("新规则引擎未命中, imei={}", imei);
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@ -6,12 +6,12 @@ import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
|
|||||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
|
import com.fuyuanshen.global.mqtt.base.*;
|
||||||
import com.fuyuanshen.global.mqtt.base.MqttRuleEngine;
|
|
||||||
import com.fuyuanshen.global.mqtt.base.MqttXinghanCommandType;
|
|
||||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
|
import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHandler;
|
import org.springframework.messaging.MessageHandler;
|
||||||
@ -21,6 +21,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
@ -31,6 +32,9 @@ public class ReceiverMessageHandler implements MessageHandler {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MqttRuleEngine ruleEngine;
|
private MqttRuleEngine ruleEngine;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private NewMqttRuleEngine newRuleEngine;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message<?> message) throws MessagingException {
|
public void handleMessage(Message<?> message) throws MessagingException {
|
||||||
Object payload = message.getPayload();
|
Object payload = message.getPayload();
|
||||||
@ -46,8 +50,28 @@ public class ReceiverMessageHandler implements MessageHandler {
|
|||||||
if (receivedTopic == null || payloadDict == null) {
|
if (receivedTopic == null || payloadDict == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 模版格式匹配
|
||||||
|
boolean flag = checkTemplateFormatMatching(payloadDict);
|
||||||
|
|
||||||
|
|
||||||
String[] subStr = receivedTopic.split("/");
|
String[] subStr = receivedTopic.split("/");
|
||||||
String deviceImei = subStr[1];
|
String deviceImei = null;
|
||||||
|
if(flag){
|
||||||
|
deviceImei = payloadDict.getStr("imei");
|
||||||
|
} else {
|
||||||
|
deviceImei = subStr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
RedissonClient client = RedisUtils.getClient();
|
||||||
|
String lockKey = "mqtt:consumer:lock:";
|
||||||
|
String KEY = GlobalConstants.GLOBAL_REDIS_KEY + lockKey + deviceImei;
|
||||||
|
RLock lock = client.getLock(KEY);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 尝试获取锁,
|
||||||
|
boolean isLocked = lock.tryLock(60, 3000, TimeUnit.MILLISECONDS);
|
||||||
|
if (isLocked) {
|
||||||
String state = payloadDict.getStr("state");
|
String state = payloadDict.getStr("state");
|
||||||
Object[] convertArr = ImageToCArrayConverter.convertByteStringToMixedObjectArray(state);
|
Object[] convertArr = ImageToCArrayConverter.convertByteStringToMixedObjectArray(state);
|
||||||
if(StringUtils.isNotBlank(deviceImei)){
|
if(StringUtils.isNotBlank(deviceImei)){
|
||||||
@ -59,7 +83,22 @@ public class ReceiverMessageHandler implements MessageHandler {
|
|||||||
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新的通信协议
|
||||||
|
if(flag){
|
||||||
|
String[] topicArr = receivedTopic.split("/");
|
||||||
|
String funcType = payloadDict.getStr("funcType");
|
||||||
|
NewMqttRuleContext context = new NewMqttRuleContext();
|
||||||
|
context.setCommandType(topicArr[2]+"_"+funcType);
|
||||||
|
context.setDeviceImei(deviceImei);
|
||||||
|
context.setPayloadDict(payloadDict);
|
||||||
|
|
||||||
|
boolean ruleExecuted = newRuleEngine.executeRule(context);
|
||||||
|
|
||||||
|
if (!ruleExecuted) {
|
||||||
|
log.warn("未找到匹配的规则来处理命令类型: {}", topicArr[2] + " : " +funcType);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (convertArr.length > 0) {
|
if (convertArr.length > 0) {
|
||||||
Byte val1 = (Byte) convertArr[0];
|
Byte val1 = (Byte) convertArr[0];
|
||||||
@ -74,6 +113,7 @@ public class ReceiverMessageHandler implements MessageHandler {
|
|||||||
if (!ruleExecuted) {
|
if (!ruleExecuted) {
|
||||||
log.warn("未找到匹配的规则来处理命令类型: {}", val1);
|
log.warn("未找到匹配的规则来处理命令类型: {}", val1);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 追加:根据报文内容识别格式并统一解析 ===== */
|
/* ===== 追加:根据报文内容识别格式并统一解析 ===== */
|
||||||
@ -89,6 +129,31 @@ public class ReceiverMessageHandler implements MessageHandler {
|
|||||||
log.warn("新规则引擎未命中, imei={}", deviceImei);
|
log.warn("新规则引擎未命中, imei={}", deviceImei);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
log.warn("MQTT获取锁失败,请稍后再试");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} finally {
|
||||||
|
// 释放锁
|
||||||
|
if (lock.isHeldByCurrentThread()) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkTemplateFormatMatching(Dict payloadDict) {
|
||||||
|
// 检查是否包含指定的 key
|
||||||
|
boolean hasImei = payloadDict.containsKey("imei");
|
||||||
|
boolean hasFuncType = payloadDict.containsKey("funcType");
|
||||||
|
boolean hasStatus = payloadDict.containsKey("status");
|
||||||
|
boolean hasTimestamp = payloadDict.containsKey("timestamp");
|
||||||
|
boolean hasData = payloadDict.containsKey("data");
|
||||||
|
|
||||||
|
// 输出检查结果
|
||||||
|
log.info("包含 imei: {}, funcType: {}, status: {}, timestamp: {}, data: {}",
|
||||||
|
hasImei, hasFuncType, hasStatus, hasTimestamp, hasData);
|
||||||
|
return hasImei && hasFuncType && hasStatus && hasTimestamp && hasData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,143 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.receiver;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||||
|
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
|
import com.fuyuanshen.equipment.domain.DeviceType;
|
||||||
|
import com.fuyuanshen.equipment.domain.form.DeviceForm;
|
||||||
|
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
|
||||||
|
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||||
|
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||||
|
import com.fuyuanshen.equipment.service.DeviceService;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleEngine;
|
||||||
|
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
||||||
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
|
import com.fuyuanshen.global.queue.MqttMessageQueueConstants;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.MessageHandler;
|
||||||
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
import org.springframework.messaging.MessagingException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册设备消息接收处理
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class RegisEquipReceiverMessageHandler implements MessageHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private NewMqttRuleEngine newRuleEngine;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttGateway mqttGateway;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceMapper deviceMapper;
|
||||||
|
@Autowired
|
||||||
|
private DeviceService deviceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceTypeMapper deviceTypeMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message<?> message) throws MessagingException {
|
||||||
|
|
||||||
|
Object payload = message.getPayload();
|
||||||
|
MessageHeaders headers = message.getHeaders();
|
||||||
|
String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
|
||||||
|
|
||||||
|
// 只处理 regis/equip/# 主题的消息
|
||||||
|
if (!receivedTopic.startsWith("regis/equip/")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从主题中提取设备ID
|
||||||
|
String[] topicParts = receivedTopic.split("/");
|
||||||
|
if (topicParts.length < 3) {
|
||||||
|
log.warn("Invalid topic format: {}", receivedTopic);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String deviceTypeName = topicParts[2]; // HBY100-J
|
||||||
|
|
||||||
|
String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString();
|
||||||
|
String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString();
|
||||||
|
|
||||||
|
log.info("MQTT3 payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}",
|
||||||
|
payload, receivedTopic, receivedQos, timestamp);
|
||||||
|
|
||||||
|
// 解析JSON payload获取imei和mac
|
||||||
|
Dict payloadDict = JsonUtils.parseMap(payload.toString());
|
||||||
|
if (payloadDict == null) {
|
||||||
|
log.warn("Failed to parse payload JSON");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String imei = payloadDict.getStr("imei");
|
||||||
|
String mac = payloadDict.getStr("mac");
|
||||||
|
|
||||||
|
log.info("Extracted IMEI: {}, MAC: {}", imei, mac);
|
||||||
|
|
||||||
|
// 验证必要字段
|
||||||
|
if (StringUtils.isEmpty(imei) || StringUtils.isEmpty(mac)) {
|
||||||
|
log.warn("Missing required fields - IMEI: {}, MAC: {}", imei, mac);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceTypeQueryCriteria criteria = new DeviceTypeQueryCriteria();
|
||||||
|
criteria.setTypeName(deviceTypeName);
|
||||||
|
DeviceType deviceType = deviceTypeMapper.queryByName(criteria);
|
||||||
|
if (deviceType == null) {
|
||||||
|
log.warn("Device type not found for name: {}", deviceTypeName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device device = deviceMapper.selectDeviceByImei(imei);
|
||||||
|
if (device != null) {
|
||||||
|
log.warn("Device already exists for IMEI: {}", imei);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取MAC地址后6位
|
||||||
|
String macSuffix = mac.replaceAll(":", "").substring(6); // 43:73:43:33:53:33 -> 335333
|
||||||
|
// 构建设备名称和蓝牙名称:设备类型+MAC后6位
|
||||||
|
String deviceName = deviceTypeName + "-" + macSuffix; // HBY100-335333
|
||||||
|
|
||||||
|
DeviceForm deviceForm = new DeviceForm();
|
||||||
|
deviceForm.setDeviceImei(imei);
|
||||||
|
deviceForm.setDeviceMac(mac);
|
||||||
|
deviceForm.setDeviceName(deviceName);
|
||||||
|
deviceForm.setBluetoothName(deviceName);
|
||||||
|
deviceForm.setDeviceType(deviceType.getId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
deviceService.addDevice(deviceForm);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析原始JSON数据
|
||||||
|
JSONObject originalData = new JSONObject();
|
||||||
|
originalData.put("code", 200);
|
||||||
|
// 发送到MQTT
|
||||||
|
String topic = "regis/" + imei;
|
||||||
|
mqttGateway.sendMsgToMqtt(topic, originalData.toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -67,7 +67,6 @@ public class BjqActiveReportingDeviceDataRule implements MqttMessageRule {
|
|||||||
*/
|
*/
|
||||||
public void asyncSendDeviceDataToRedisWithFuture(String deviceImei, String mainLightMode, String laserLightMode,
|
public void asyncSendDeviceDataToRedisWithFuture(String deviceImei, String mainLightMode, String laserLightMode,
|
||||||
String batteryPercentage, String chargeState, String batteryRemainingTime) {
|
String batteryPercentage, String chargeState, String batteryRemainingTime) {
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
try {
|
||||||
// 构造设备状态信息对象
|
// 构造设备状态信息对象
|
||||||
Map<String, Object> deviceInfo = new LinkedHashMap<>();
|
Map<String, Object> deviceInfo = new LinkedHashMap<>();
|
||||||
@ -91,7 +90,6 @@ public class BjqActiveReportingDeviceDataRule implements MqttMessageRule {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -121,7 +121,6 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
|||||||
* @param longitude 经度
|
* @param longitude 经度
|
||||||
*/
|
*/
|
||||||
public void asyncSendLocationToRedisWithFuture(String deviceImei, String latitude, String longitude) {
|
public void asyncSendLocationToRedisWithFuture(String deviceImei, String latitude, String longitude) {
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
try {
|
||||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||||
return;
|
return;
|
||||||
@ -177,7 +176,6 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("异步发送位置信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
log.error("异步发送位置信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,7 +187,6 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
|||||||
* @param longitude 经度
|
* @param longitude 经度
|
||||||
*/
|
*/
|
||||||
public void asyncSaveLocationToMySQLWithFuture(String deviceImei, String latitude, String longitude) {
|
public void asyncSaveLocationToMySQLWithFuture(String deviceImei, String latitude, String longitude) {
|
||||||
CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
try {
|
||||||
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
if (StringUtils.isBlank(latitude) || StringUtils.isBlank(longitude)) {
|
||||||
return;
|
return;
|
||||||
@ -202,7 +199,6 @@ public class BjqLocationDataRule implements MqttMessageRule {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("异步保存位置信息到MySQL时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
log.error("异步保存位置信息到MySQL时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,8 @@ public class BjqModeRule implements MqttMessageRule {
|
|||||||
public void execute(MqttRuleContext context) {
|
public void execute(MqttRuleContext context) {
|
||||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||||
try {
|
try {
|
||||||
|
log.info("处理灯光模式命令");
|
||||||
|
log.info("MQTT消息负载字典:{}", context.getPayloadDict());
|
||||||
Object[] convertArr = context.getConvertArr();
|
Object[] convertArr = context.getConvertArr();
|
||||||
|
|
||||||
String mainLightMode = convertArr[1].toString();
|
String mainLightMode = convertArr[1].toString();
|
||||||
|
|||||||
@ -34,8 +34,8 @@ public class BjqPersonnelInfoDataRule implements MqttMessageRule {
|
|||||||
public void execute(MqttRuleContext context) {
|
public void execute(MqttRuleContext context) {
|
||||||
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei();
|
||||||
try {
|
try {
|
||||||
Object[] convertArr = context.getConvertArr();
|
// Object[] convertArr = context.getConvertArr();
|
||||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
// RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("处理定位数据命令时出错", e);
|
log.error("处理定位数据命令时出错", e);
|
||||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(30));
|
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(30));
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪模式开启/关闭
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType10StrobeMode implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_10";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J爆闪模式开启/关闭,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":strobeMode";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J爆闪模式开启/关闭失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改警示灯爆闪频率
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType11Frequency implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_11";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J修改警示灯爆闪频率,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":frequency";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J修改警示灯爆闪频率失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制声光报警开启/关闭
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType12ForceAudio implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_12";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J强制声光报警开启/关闭,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 构建强制声光报警开关的Redis键
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":forceAudio";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
// 存储强制声光报警开关状态到Redis
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J强制声光报警开启/关闭失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 警示灯LED亮度调节
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType13Brightness implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_13";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J警示灯LED亮度调节,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":brightness";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J警示灯LED亮度调节失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取警示灯的当前工作方式(设备下发返回响应数据、设备定时主动上报)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType14Report implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_14";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J设备定时主动上报,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":report";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J设备定时主动上报失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备复位
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType1Rest implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_1";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("开始处理设备复位,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 构建强制声光报警开关的Redis键
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":rest";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
// 存储强制声光报警开关状态到Redis
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
log.info("设备复位,设备ID:{}", context.getDeviceImei());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理设备复位失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备基础信息
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType2BaseInfo implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_2";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("开始处理强制声光报警开关,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 构建强制声光报警开关的Redis键
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":force_audio_visual_alarm_switch";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
// 存储强制声光报警开关状态到Redis
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
log.info("强制声光报警开关处理完成,设备ID:{}", context.getDeviceImei());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理强制声光报警开关失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,208 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||||
|
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil;
|
||||||
|
import com.fuyuanshen.equipment.utils.map.LngLonUtil;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
|
import com.fuyuanshen.global.mqtt.rule.hby100j.domin.FunctionType3LocationReport;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备位置信息(设备下发返回响应数据、设备定时主动上报)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType3Location implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_3";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J获取设备位置信息,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":location";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
// RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
String jsonString = JSONObject.toJSONString(payloadDict);
|
||||||
|
FunctionType3LocationReport data = JSONObject.parseObject(jsonString, FunctionType3LocationReport.class);
|
||||||
|
FunctionType3LocationReport.Data data1 = data.getData();
|
||||||
|
if (data1 != null) {
|
||||||
|
Double latitude = data1.getLatitude();
|
||||||
|
Double longitude = data1.getLongitude();
|
||||||
|
asyncSendLocationToRedisWithFuture(context.getDeviceImei(), latitude.toString(), longitude.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J获取设备位置信息失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 位置未发生明显变化的距离阈值(米),可通过配置中心动态调整 */
|
||||||
|
private final double MOVEMENT_THRESHOLD_METER = 10.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步发送位置信息到Redis(使用CompletableFuture)
|
||||||
|
*
|
||||||
|
* @param deviceImei 设备IMEI
|
||||||
|
* @param latitude 纬度
|
||||||
|
* @param longitude 经度
|
||||||
|
*/
|
||||||
|
public void asyncSendLocationToRedisWithFuture(String deviceImei, String latitude, String longitude) {
|
||||||
|
try {
|
||||||
|
if (latitude == null || longitude == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isAnyBlank(deviceImei, latitude, longitude)) {
|
||||||
|
log.warn("位置上报参数为空,deviceImei={}", deviceImei);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//log.info("位置上报,deviceImei={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||||
|
// 1. 解析当前上报的经纬度
|
||||||
|
Double curLat = parseDoubleSafe(latitude.trim());
|
||||||
|
Double curLon = parseDoubleSafe(longitude.trim());
|
||||||
|
if (curLat == null || curLon == null) {
|
||||||
|
log.warn("经纬度格式错误,直接更新,deviceImei={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||||
|
// doSaveLocation(deviceImei, latitude, longitude);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 读取 Redis 中缓存的上一次位置
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
|
||||||
|
String cachedJson = RedisUtils.getCacheObject(redisKey);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(cachedJson)) {
|
||||||
|
com.alibaba.fastjson2.JSONObject cachedObj = com.alibaba.fastjson2.JSONObject.parseObject(cachedJson);
|
||||||
|
String cachedWgs84Lat = cachedObj.getString("wgs84_latitude");
|
||||||
|
String cachedWgs84Lon = cachedObj.getString("wgs84_longitude");
|
||||||
|
|
||||||
|
Double oldLat = parseDoubleSafe(cachedWgs84Lat);
|
||||||
|
Double oldLon = parseDoubleSafe(cachedWgs84Lon);
|
||||||
|
|
||||||
|
if (oldLat != null && oldLon != null) {
|
||||||
|
double distance = haversine(oldLat, oldLon, curLat, curLon);
|
||||||
|
if (distance <= MOVEMENT_THRESHOLD_METER) {
|
||||||
|
log.info("位置未发生明显变化({}米 <= {}米),不更新 Redis,deviceImei={}, lat={}, lon={}",
|
||||||
|
distance, MOVEMENT_THRESHOLD_METER, deviceImei, latitude, longitude);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// String[] latArr = latitude.split("\\.");
|
||||||
|
// String[] lonArr = longitude.split("\\.");
|
||||||
|
// // 将位置信息存储到Redis中
|
||||||
|
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX;
|
||||||
|
// String redisObj = RedisUtils.getCacheObject(redisKey);
|
||||||
|
// JSONObject jsonOBj = JSONObject.parseObject(redisObj);
|
||||||
|
// if(jsonOBj != null){
|
||||||
|
// String str1 = latArr[0] +"."+ latArr[1].substring(0,4);
|
||||||
|
// String str2 = lonArr[0] +"."+ lonArr[1].substring(0,4);
|
||||||
|
//
|
||||||
|
// String cacheLatitude = jsonOBj.getString("wgs84_latitude");
|
||||||
|
// String cacheLongitude = jsonOBj.getString("wgs84_longitude");
|
||||||
|
// String[] latArr1 = cacheLatitude.split("\\.");
|
||||||
|
// String[] lonArr1 = cacheLongitude.split("\\.");
|
||||||
|
//
|
||||||
|
// String cacheStr1 = latArr1[0] +"."+ latArr1[1].substring(0,4);
|
||||||
|
// String cacheStr2 = lonArr1[0] +"."+ lonArr1[1].substring(0,4);
|
||||||
|
// if(str1.equals(cacheStr1) && str2.equals(cacheStr2)){
|
||||||
|
// log.info("位置信息未发生变化: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 构造位置信息对象
|
||||||
|
Map<String, Object> locationInfo = new LinkedHashMap<>();
|
||||||
|
double[] doubles = LngLonUtil.gps84_To_Gcj02(Double.parseDouble(latitude), Double.parseDouble(longitude));
|
||||||
|
locationInfo.put("deviceImei", deviceImei);
|
||||||
|
locationInfo.put("latitude", doubles[0]);
|
||||||
|
locationInfo.put("longitude", doubles[1]);
|
||||||
|
locationInfo.put("wgs84_latitude", latitude);
|
||||||
|
locationInfo.put("wgs84_longitude", longitude);
|
||||||
|
|
||||||
|
|
||||||
|
String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0]));
|
||||||
|
locationInfo.put("address", address);
|
||||||
|
locationInfo.put("timestamp", System.currentTimeMillis());
|
||||||
|
|
||||||
|
|
||||||
|
String locationJson = JsonUtils.toJsonString(locationInfo);
|
||||||
|
|
||||||
|
// 存储到Redis
|
||||||
|
RedisUtils.setCacheObject(redisKey, locationJson);
|
||||||
|
|
||||||
|
// 存储到一个列表中,保留历史位置信息
|
||||||
|
// String locationHistoryKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX + deviceImei;
|
||||||
|
// RedisUtils.addCacheList(locationHistoryKey, locationJson);
|
||||||
|
// RedisUtils.expire(locationHistoryKey, Duration.ofDays(90));
|
||||||
|
storeDeviceTrajectoryWithSortedSet(deviceImei, locationJson);
|
||||||
|
log.info("位置信息已异步发送到Redis: device={}, lat={}, lon={}", deviceImei, latitude, longitude);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("异步发送位置信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** 安全解析 double,解析失败返回 null */
|
||||||
|
private Double parseDoubleSafe(String str) {
|
||||||
|
if (StringUtils.isBlank(str)) return null;
|
||||||
|
try {
|
||||||
|
return Double.parseDouble(str.trim());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Haversine 公式计算两点球面距离(米) */
|
||||||
|
private double haversine(double lat1, double lon1, double lat2, double lon2) {
|
||||||
|
double dLat = Math.toRadians(lat2 - lat1);
|
||||||
|
double dLon = Math.toRadians(lon2 - lon1);
|
||||||
|
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||||
|
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
|
||||||
|
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||||
|
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||||
|
/** 地球平均半径(米) */
|
||||||
|
double EARTH_RADIUS = 6371_393.0;
|
||||||
|
return EARTH_RADIUS * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储设备30天历史轨迹到Redis (使用Sorted Set)
|
||||||
|
*/
|
||||||
|
public void storeDeviceTrajectoryWithSortedSet(String deviceImei, String locationJson) {
|
||||||
|
try {
|
||||||
|
String trajectoryKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_LOCATION_HISTORY_KEY_PREFIX;
|
||||||
|
// String trajectoryKey = "device:trajectory:zset:" + deviceImei;
|
||||||
|
// String locationJson = JsonUtils.toJsonString(locationInfo);
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// 添加到Sorted Set,使用时间戳作为score
|
||||||
|
RedisUtils.zAdd(trajectoryKey, locationJson, timestamp);
|
||||||
|
|
||||||
|
// // 设置30天过期时间
|
||||||
|
// RedisUtils.expire(trajectoryKey, Duration.ofDays(30));
|
||||||
|
|
||||||
|
// 清理30天前的数据(冗余保护)
|
||||||
|
long thirtyDaysAgo = System.currentTimeMillis() - (7L * 24 * 60 * 60 * 1000);
|
||||||
|
RedisUtils.zRemoveRangeByScore(trajectoryKey, 0, thirtyDaysAgo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("存储设备轨迹到Redis(ZSet)失败: device={}, error={}", deviceImei, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
|
import com.fuyuanshen.global.mqtt.rule.hby100j.domin.FunctionType4PowerStatusReport;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备电源状态(设备下发返回响应数据、设备定时主动上报)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType4PowerStatus implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_4";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J获取设备电源状态,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
|
||||||
|
// String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
// context.getDeviceImei() + ":powerStatus";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
|
||||||
|
String str = JSONObject.toJSONString(payloadDict);
|
||||||
|
FunctionType4PowerStatusReport powerStatusReport =JSONObject.parseObject(str,FunctionType4PowerStatusReport.class);
|
||||||
|
|
||||||
|
FunctionType4PowerStatusReport.Data data = powerStatusReport.getData();
|
||||||
|
if(data != null){
|
||||||
|
// 构造设备状态信息对象
|
||||||
|
Map<String, Object> deviceInfo = new LinkedHashMap<>();
|
||||||
|
deviceInfo.put("batteryPercentage", data.getLevel());
|
||||||
|
deviceInfo.put("chargeState", data.getCharge());
|
||||||
|
deviceInfo.put("batteryRemainingTime", data.getBatteryRemainingTime());
|
||||||
|
|
||||||
|
// 将设备状态信息存储到Redis中
|
||||||
|
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX;
|
||||||
|
String deviceInfoJson = JsonUtils.toJsonString(deviceInfo);
|
||||||
|
|
||||||
|
// 存储到Redis
|
||||||
|
RedisUtils.setCacheObject(deviceRedisKey, deviceInfoJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J获取设备电源状态失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新语音
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType5UpdateVoice implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_5";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J更新语音,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":updateVoice";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J更新语音失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音播报开启/关闭
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType6VoicePlay implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_6";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J语音播报开启/关闭,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":voicePlay";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J语音播报开启/关闭失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttMessageRule;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改音量
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class FuncType9UpdateVolume implements NewMqttMessageRule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandType() {
|
||||||
|
return "HBY100_9";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(NewMqttRuleContext context) {
|
||||||
|
log.info("HBY100J修改音量,消息负载:{}", context.getPayloadDict());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String redisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
context.getDeviceImei() + ":updateVolume";
|
||||||
|
|
||||||
|
Map<String, Object> payloadDict = context.getPayloadDict();
|
||||||
|
if (payloadDict != null) {
|
||||||
|
RedisUtils.setCacheObject(redisKey, JSONObject.toJSONString(payloadDict));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("HBY100J修改音量失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪模式开启/关闭
|
||||||
|
* 对应 funcType="10"
|
||||||
|
* mode:
|
||||||
|
* 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType10StrobeModeRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪模式是否启用
|
||||||
|
* 0 - 禁用
|
||||||
|
* 1 - 启用
|
||||||
|
*/
|
||||||
|
private Integer enable;
|
||||||
|
/**
|
||||||
|
* 爆闪模式类型 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||||
|
**/
|
||||||
|
private Integer mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改警示灯爆闪频率
|
||||||
|
* 对应 funcType="11"
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType11FrequencyRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
//"frequency": 1-12
|
||||||
|
private Integer frequency;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制声光报警开启/关闭
|
||||||
|
* 对应 funcType="12"
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType12ForceAudioRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
/**
|
||||||
|
* 语音报警0关闭,1开启
|
||||||
|
*/
|
||||||
|
@JsonProperty("voice_strobe_alarm")
|
||||||
|
private Integer voiceStrobeAlarm;
|
||||||
|
//语音模式0公安,1消防,2应急,3交警,4市政,5铁路,6医疗,7部队,8水利
|
||||||
|
private Integer mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 警示灯LED亮度调节
|
||||||
|
* 对应 funcType="13"
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType13BrightnessRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
/**
|
||||||
|
* 红色LED亮度值0-100
|
||||||
|
*/
|
||||||
|
private Integer red;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝色LED亮度值0-100
|
||||||
|
*/
|
||||||
|
private Integer blue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 黄色LED亮度值0-100
|
||||||
|
*/
|
||||||
|
private Integer yellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备状态上报数据DTO
|
||||||
|
* 对应MQTT消息中设备上报的完整状态数据结构
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType14StatusReport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码(如"14"表示特定功能指令)
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应状态码(如"200"表示成功)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备详细状态数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备详细状态数据内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音播报开关:0-关闭,1-开启
|
||||||
|
*/
|
||||||
|
@JsonProperty("voice_broadcast")
|
||||||
|
private Integer voiceBroadcast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 警报器(警笛)设置
|
||||||
|
*/
|
||||||
|
@JsonProperty("siren_alarm")
|
||||||
|
private SirenAlarm sirenAlarm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LED爆闪设置
|
||||||
|
*/
|
||||||
|
@JsonProperty("led_strobe")
|
||||||
|
private LedStrobe ledStrobe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音量设置(0-100范围)
|
||||||
|
*/
|
||||||
|
@JsonProperty("volume")
|
||||||
|
private Integer volume;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 亮度设置(RGB三色亮度值)
|
||||||
|
*/
|
||||||
|
@JsonProperty("brightness")
|
||||||
|
private Brightness brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 警报器(警笛)设置
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class SirenAlarm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用:0-禁用,1-启用
|
||||||
|
*/
|
||||||
|
@JsonProperty("enable")
|
||||||
|
private Integer enable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作模式:0-默认模式,其他值表示不同报警模式
|
||||||
|
*/
|
||||||
|
@JsonProperty("mode")
|
||||||
|
private Integer mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LED爆闪设置
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class LedStrobe {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用:0-禁用,1-启用
|
||||||
|
*/
|
||||||
|
@JsonProperty("enable")
|
||||||
|
private Integer enable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作模式:0-默认模式,其他值表示不同爆闪模式
|
||||||
|
*/
|
||||||
|
@JsonProperty("mode")
|
||||||
|
private Integer mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪频率(单位:Hz或自定义单位)
|
||||||
|
*/
|
||||||
|
@JsonProperty("frequency")
|
||||||
|
private Integer frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 亮度设置(RGB三色)
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Brightness {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 红色通道亮度值(0-255或百分比)
|
||||||
|
*/
|
||||||
|
@JsonProperty("red")
|
||||||
|
private Integer red;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绿色通道亮度值(0-255或百分比)
|
||||||
|
*/
|
||||||
|
@JsonProperty("green")
|
||||||
|
private Integer green;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝色通道亮度值(0-255或百分比)
|
||||||
|
*/
|
||||||
|
@JsonProperty("blue")
|
||||||
|
private Integer blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新设备语音
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType5UpdateVoiceReport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码("5" 表示操作状态上报)
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应状态码("200" 表示请求成功)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作详细状态数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作状态数据内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作执行状态:
|
||||||
|
* 0 - 未开始 / 失败
|
||||||
|
* 1 - 执行中
|
||||||
|
* 2 - 成功完成
|
||||||
|
* (具体含义需结合业务协议定义)
|
||||||
|
*/
|
||||||
|
@JsonProperty("status")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作进度百分比(0-100),仅在 status=1(执行中)时有效
|
||||||
|
*/
|
||||||
|
@JsonProperty("progress")
|
||||||
|
private Integer progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音资源配置请求DTO
|
||||||
|
* 对应 funcType="5" 的语音资源下发指令(如语音播报文件配置)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType5UpdateVoiceRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码("5" 表示语音资源配置)
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音类型:
|
||||||
|
* 0 - 默认语音(如标准提示音)
|
||||||
|
* 1 - 自定义语音
|
||||||
|
* 2 - 紧急语音
|
||||||
|
* (具体含义需依据设备协议定义)
|
||||||
|
*/
|
||||||
|
@JsonProperty("voice_type")
|
||||||
|
private Integer voiceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音资源URL(MP3等音频文件地址)
|
||||||
|
* 示例:http://8.129.5.250:10001/voice/01.mp3
|
||||||
|
*/
|
||||||
|
@JsonProperty("voice_resource")
|
||||||
|
private String voiceResource;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音播报开启/关闭
|
||||||
|
* 对应 funcType="6"
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType6VoicePlayRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
/**
|
||||||
|
* 语音报警0关闭,1开启
|
||||||
|
*/
|
||||||
|
@JsonProperty("voice_broadcast")
|
||||||
|
private Integer voiceBroadcast;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改音量
|
||||||
|
* 对应 funcType="9"
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FuncType9UpdateVolumeRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求唯一标识符(用于链路追踪或幂等处理)
|
||||||
|
*/
|
||||||
|
@JsonProperty("requestId")
|
||||||
|
private String requestId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音配置详情内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
//"volume": 1-100(app端可根据需求把40作为低音量, 70作为中音量,100作为高音量)
|
||||||
|
private Integer volume;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备位置上报DTO
|
||||||
|
* 对应MQTT消息中设备上报的地理位置数据
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FunctionType3LocationReport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码(如"3"表示位置上报)
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应状态码(如"200"表示成功)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置详细数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置详细数据内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经度(WGS-84坐标系,如22.543100)
|
||||||
|
*/
|
||||||
|
@JsonProperty("longitude")
|
||||||
|
private Double longitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纬度(WGS-84坐标系,如114.057900)
|
||||||
|
*/
|
||||||
|
@JsonProperty("latitude")
|
||||||
|
private Double latitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.rule.hby100j.domin;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备电源状态上报DTO
|
||||||
|
* 对应MQTT消息中设备上报的电源相关状态数据
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FunctionType4PowerStatusReport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI号(国际移动设备识别码)
|
||||||
|
*/
|
||||||
|
private String imei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能类型编码(如"4"表示电源状态上报)
|
||||||
|
*/
|
||||||
|
private String funcType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应状态码(如"200"表示成功)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(毫秒级Unix时间戳)
|
||||||
|
*/
|
||||||
|
private Long timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电源详细状态数据
|
||||||
|
*/
|
||||||
|
private Data data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电源详细状态数据内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
public static class Data {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电池容量(如"5000mAh")
|
||||||
|
*/
|
||||||
|
@JsonProperty("capacity")
|
||||||
|
private String capacity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电压值(单位:V,0表示未检测或无电)
|
||||||
|
*/
|
||||||
|
@JsonProperty("voltage")
|
||||||
|
private Integer voltage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电量百分比(0-100,0表示低电量或未检测)
|
||||||
|
*/
|
||||||
|
@JsonProperty("level")
|
||||||
|
private Integer level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电状态:0-未充电,1-正在充电
|
||||||
|
*/
|
||||||
|
@JsonProperty("charge")
|
||||||
|
private Integer charge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 12V电源状态:0-关闭/无输出,1-开启/有输出
|
||||||
|
*/
|
||||||
|
@JsonProperty("12v_power")
|
||||||
|
private Integer twelveVPower;
|
||||||
|
|
||||||
|
@JsonProperty("battery_remaining_time")
|
||||||
|
private Integer batteryRemainingTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.utils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
public class FfmpegVolumeUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用FFmpeg增加MP3文件的音量
|
||||||
|
*
|
||||||
|
* @param inputFilePath 输入MP3文件路径
|
||||||
|
* @param outputFilePath 输出MP3文件路径
|
||||||
|
* @param volumeGain 音量增益(例如:1.5表示增加50%音量,2.0表示翻倍)
|
||||||
|
*/
|
||||||
|
public static void increaseMp3Volume(String inputFilePath, String outputFilePath, int volumeGain) {
|
||||||
|
boolean ffmpegAvailable = isFfmpegAvailable();
|
||||||
|
if (!ffmpegAvailable) {
|
||||||
|
System.err.println("FFmpeg未安装或未找到!请安装FFmpeg并确保在系统路径中。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查输入文件
|
||||||
|
File inputFile = new File(inputFilePath);
|
||||||
|
if (!inputFile.exists()) {
|
||||||
|
System.err.println("输入文件不存在:" + inputFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!inputFile.canRead()) {
|
||||||
|
System.err.println("输入文件不可读:" + inputFilePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建输出目录
|
||||||
|
File outputFile = new File(outputFilePath);
|
||||||
|
File parentDir = outputFile.getParentFile();
|
||||||
|
if (parentDir != null) {
|
||||||
|
parentDir.mkdirs();
|
||||||
|
if (!parentDir.canWrite()) {
|
||||||
|
System.err.println("输出目录不可写:" + parentDir.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
String command = String.format(
|
||||||
|
"ffmpeg -y -i \"%s\" -af \"volume=%sdB\" \"%s\"",
|
||||||
|
inputFilePath,
|
||||||
|
volumeGain,
|
||||||
|
outputFilePath
|
||||||
|
);
|
||||||
|
|
||||||
|
System.out.println("执行命令: " + command);
|
||||||
|
|
||||||
|
// 使用 ProcessBuilder 提供更好的控制
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder("ffmpeg", "-y",
|
||||||
|
"-i", inputFilePath, "-af", "volume=" + volumeGain + "dB", outputFilePath);
|
||||||
|
processBuilder.redirectErrorStream(false);
|
||||||
|
process = processBuilder.start();
|
||||||
|
|
||||||
|
// 同时读取标准输出和错误输出
|
||||||
|
Process finalProcess = process;
|
||||||
|
Thread stdOutThread = new Thread(() -> {
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(finalProcess.getInputStream()))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
System.out.println("[FFmpeg STDOUT] " + line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("读取标准输出时出错: " + e.getMessage());
|
||||||
|
}finally {
|
||||||
|
finalProcess.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Process finalProcess1 = process;
|
||||||
|
Thread stdErrThread = new Thread(() -> {
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(finalProcess1.getErrorStream()))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
System.err.println("[FFmpeg STDERR] " + line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.err.println("读取错误输出时出错: " + e.getMessage());
|
||||||
|
}finally {
|
||||||
|
finalProcess1.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stdOutThread.start();
|
||||||
|
stdErrThread.start();
|
||||||
|
|
||||||
|
int exitCode = process.waitFor();
|
||||||
|
stdOutThread.join();
|
||||||
|
stdErrThread.join();
|
||||||
|
|
||||||
|
if (exitCode == 0) {
|
||||||
|
System.out.println("音量调整成功!输出文件:" + outputFilePath);
|
||||||
|
} else {
|
||||||
|
System.err.println("FFmpeg命令执行失败,退出码:" + exitCode);
|
||||||
|
}
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
System.err.println("执行FFmpeg命令时发生错误: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (process != null) {
|
||||||
|
System.out.println("已销毁进程");
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// 示例用法
|
||||||
|
String inputPath = "/app/input.mp3";
|
||||||
|
String outputPath = "/app/output17.mp3";
|
||||||
|
int volumeGain = 12;
|
||||||
|
|
||||||
|
increaseMp3Volume(inputPath, outputPath, volumeGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFfmpegAvailable() {
|
||||||
|
try {
|
||||||
|
Process process = Runtime.getRuntime().exec("ffmpeg -version");
|
||||||
|
int exitCode = process.waitFor();
|
||||||
|
return exitCode == 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.utils;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
public class FfmpegVolumeUtil3 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用FFmpeg增加MP3文件的音量
|
||||||
|
*
|
||||||
|
* @param inputFilePath 输入MP3文件路径
|
||||||
|
* @param outputFilePath 输出MP3文件路径
|
||||||
|
* @param volumeGain 音量增益(例如:1.5表示增加50%音量,2.0表示翻倍)
|
||||||
|
*/
|
||||||
|
public static void increaseMp3Volume(String inputFilePath, String outputFilePath, int volumeGain) {
|
||||||
|
boolean ffmpegAvailable = isFfmpegAvailable();
|
||||||
|
if (!ffmpegAvailable) {
|
||||||
|
System.err.println("FFmpeg未安装或未找到!请安装FFmpeg并确保在系统路径中。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 创建输出文件的父目录
|
||||||
|
File outputFile = new File(outputFilePath);
|
||||||
|
File parentDir = outputFile.getParentFile();
|
||||||
|
if (parentDir != null && !parentDir.exists()) {
|
||||||
|
boolean created = parentDir.mkdirs();
|
||||||
|
if (!created) {
|
||||||
|
System.err.println("无法创建输出目录:" + parentDir.getAbsolutePath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
// 构建FFmpeg命令
|
||||||
|
String command = String.format(
|
||||||
|
"ffmpeg -y -i \"%s\" -af \"volume=%sdB\" \"%s\"",
|
||||||
|
inputFilePath,
|
||||||
|
volumeGain,
|
||||||
|
outputFilePath
|
||||||
|
);
|
||||||
|
|
||||||
|
System.out.println("执行命令: " + command);
|
||||||
|
|
||||||
|
// 执行FFmpeg命令
|
||||||
|
process = Runtime.getRuntime().exec(command);
|
||||||
|
|
||||||
|
// 读取命令执行结果
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待命令执行完成
|
||||||
|
int exitCode = process.waitFor();
|
||||||
|
if (exitCode == 0) {
|
||||||
|
System.out.println("音量调整成功!输出文件:" + outputFilePath);
|
||||||
|
} else {
|
||||||
|
System.err.println("FFmpeg命令执行失败,退出码:" + exitCode);
|
||||||
|
}
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (process != null) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// 示例用法
|
||||||
|
String inputPath = "/app/input.mp3";
|
||||||
|
String outputPath = "/app/output18.mp3";
|
||||||
|
int volumeGain = 12;
|
||||||
|
|
||||||
|
increaseMp3Volume(inputPath, outputPath, volumeGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFfmpegAvailable() {
|
||||||
|
try {
|
||||||
|
Process process = Runtime.getRuntime().exec("ffmpeg -version");
|
||||||
|
int exitCode = process.waitFor();
|
||||||
|
return exitCode == 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.fuyuanshen.global.mqtt.utils;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class GenerateIdUtil {
|
||||||
|
/**
|
||||||
|
* 生成数字唯一ID - 基于UUID
|
||||||
|
*/
|
||||||
|
public static String generateNumericId() {
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
return Math.abs(uuid.toString().hashCode()) + "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成数字唯一ID - 基于时间戳+随机数
|
||||||
|
*/
|
||||||
|
public static long generateTimestampBasedId() {
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
int random = new Random().nextInt(1000); // 0-999随机数
|
||||||
|
return timestamp * 1000 + random;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -7,14 +7,18 @@ import com.fuyuanshen.common.core.utils.StringUtils;
|
|||||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
import com.fuyuanshen.equipment.domain.Device;
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||||
|
import com.fuyuanshen.global.mqtt.base.NewMqttRuleContext;
|
||||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import jakarta.annotation.PreDestroy;
|
import jakarta.annotation.PreDestroy;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -95,40 +99,18 @@ public class MqttMessageConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理具体业务逻辑的方法
|
// 处理具体业务逻辑的方法
|
||||||
private void processMessage(String message) {
|
private void processMessage(String imei) {
|
||||||
String threadName = Thread.currentThread().getName();
|
String threadName = Thread.currentThread().getName();
|
||||||
try {
|
try {
|
||||||
log.info("业务处理线程 {} 开始处理消息: {}", threadName, message);
|
// 执行业务逻辑
|
||||||
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ message + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ;
|
|
||||||
// String deviceOnlineStatusRedis = RedisUtils.getCacheObject(deviceOnlineStatusRedisKey);
|
|
||||||
// if(StringUtils.isBlank(deviceOnlineStatusRedis)){
|
|
||||||
// UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
|
||||||
// updateWrapper.eq("device_imei", message)
|
|
||||||
// .set("online_status", 1);
|
|
||||||
// deviceMapper.update(updateWrapper);
|
|
||||||
// }
|
|
||||||
// QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
|
|
||||||
// queryWrapper.eq("device_imei", message);
|
|
||||||
// queryWrapper.eq("online_status", 1);
|
|
||||||
// Long count = deviceMapper.selectCount(queryWrapper);
|
|
||||||
// if(count == 0){
|
|
||||||
// UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
|
||||||
// updateWrapper.eq("device_imei", message)
|
|
||||||
// .eq("online_status", 0)
|
|
||||||
// .set("online_status", 1);
|
|
||||||
// deviceMapper.update(updateWrapper);
|
|
||||||
// }
|
|
||||||
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||||
updateWrapper.eq("device_imei", message)
|
updateWrapper.eq("device_imei", imei)
|
||||||
.in("online_status", 0,2)
|
.in("online_status", 0,2)
|
||||||
.set("online_status", 1);
|
.set("online_status", 1);
|
||||||
int update = deviceMapper.update(updateWrapper);
|
int update = deviceMapper.update(updateWrapper);
|
||||||
// 模拟业务处理耗时
|
|
||||||
// Thread.sleep(200);
|
|
||||||
|
|
||||||
log.info("业务处理线程 {} 完成消息处理: {}", threadName, message);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("业务处理线程 {} 处理消息时发生错误: {}", threadName, message, e);
|
log.error("业务处理线程 {} 处理消息时发生错误: {}", threadName, imei, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
package com.fuyuanshen.web.controller.device;
|
package com.fuyuanshen.web.controller.device;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
|
||||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
|
||||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||||
import com.fuyuanshen.common.core.domain.R;
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||||
import com.fuyuanshen.common.log.annotation.Log;
|
import com.fuyuanshen.common.log.annotation.Log;
|
||||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
|
||||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||||
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation;
|
||||||
import com.fuyuanshen.common.web.core.BaseController;
|
import com.fuyuanshen.common.web.core.BaseController;
|
||||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
|
||||||
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugEditDto;
|
import com.fuyuanshen.web.domain.Dto.DeviceDebugEditDto;
|
||||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||||
@ -28,8 +24,6 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 联调中心
|
* 联调中心
|
||||||
@ -125,7 +119,7 @@ public class DeviceDebugController extends BaseController {
|
|||||||
}
|
}
|
||||||
deviceDebugService.delFile(bo.getFileIds());
|
deviceDebugService.delFile(bo.getFileIds());
|
||||||
// 修改操作视频
|
// 修改操作视频
|
||||||
if (bo.getVideoUrl().isEmpty()) {
|
if (!bo.getVideoUrl().isEmpty()) {
|
||||||
AppOperationVideoBo appOperationVideoBo = new AppOperationVideoBo();
|
AppOperationVideoBo appOperationVideoBo = new AppOperationVideoBo();
|
||||||
appOperationVideoBo.setDeviceIds(new Long[]{ bo.getDeviceId() });
|
appOperationVideoBo.setDeviceIds(new Long[]{ bo.getDeviceId() });
|
||||||
appOperationVideoBo.setVideoUrl(bo.getVideoUrl());
|
appOperationVideoBo.setVideoUrl(bo.getVideoUrl());
|
||||||
|
|||||||
@ -0,0 +1,106 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.bjq;
|
||||||
|
|
||||||
|
import com.fuyuanshen.app.domain.vo.AppDeviceHBY100JDetailVo;
|
||||||
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
|
import com.fuyuanshen.common.web.core.BaseController;
|
||||||
|
import com.fuyuanshen.web.controller.device.domain.dto.*;
|
||||||
|
import com.fuyuanshen.web.service.device.DeviceHBY100JBizService;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HBY100J设备控制类
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/hby100j/device")
|
||||||
|
public class WebDeviceHBY100JController extends BaseController {
|
||||||
|
|
||||||
|
private final DeviceHBY100JBizService deviceHBY100JBizService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备详细信息
|
||||||
|
*
|
||||||
|
* @param id 主键
|
||||||
|
*/
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public R<AppDeviceHBY100JDetailVo> getInfo(@NotNull(message = "主键不能为空")
|
||||||
|
@PathVariable Long id) {
|
||||||
|
return R.ok(deviceHBY100JBizService.getInfo(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新语音
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateVoice")
|
||||||
|
public R<Void> updateVoice(@RequestBody HBY100JUpdateVoiceDto dto) {
|
||||||
|
deviceHBY100JBizService.updateVoice(dto);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制报警
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@PostMapping("/forceAlarmActivation")
|
||||||
|
public R<Void> forceAlarmActivation(@RequestBody HBY100JForceAlarmActivationDto bo) {
|
||||||
|
deviceHBY100JBizService.forceAlarmActivation(bo);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音播报
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@PostMapping("/voiceBroadcast")
|
||||||
|
public R<Void> voiceBroadcast(@RequestBody HBY100JVoiceBroadcastDto params) {
|
||||||
|
deviceHBY100JBizService.voiceBroadcast(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪模式
|
||||||
|
*/
|
||||||
|
@PostMapping("/strobeMode")
|
||||||
|
public R<Void> strobeMode(@RequestBody HBY100JStrobeModeDto params) {
|
||||||
|
deviceHBY100JBizService.strobeMode(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 灯光调节
|
||||||
|
*/
|
||||||
|
@PostMapping("/lightAdjustment")
|
||||||
|
public R<Void> lightAdjustment(@RequestBody HBY100JLightAdjustmentDto params) {
|
||||||
|
deviceHBY100JBizService.lightAdjustment(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪频率
|
||||||
|
*/
|
||||||
|
@PostMapping("/strobeFrequency")
|
||||||
|
public R<Void> strobeFrequency(@RequestBody HBY100JStrobeFrequencyDto params) {
|
||||||
|
deviceHBY100JBizService.strobeFrequency(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改音量
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateVolume")
|
||||||
|
public R<Void> updateVolume(@RequestBody HBY100JUpdateVolumeDto params) {
|
||||||
|
deviceHBY100JBizService.updateVolume(params);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JForceAlarmActivationDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
List<Long> deviceIds;
|
||||||
|
/**
|
||||||
|
* 0 关闭, 1开启
|
||||||
|
*/
|
||||||
|
private Integer voiceStrobeAlarm;
|
||||||
|
/**
|
||||||
|
* 0 公安,1消防,2应急,3交警,4 市政,5 铁路,6 医疗,7语音
|
||||||
|
*/
|
||||||
|
private Integer mode;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JLightAdjustmentDto{
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 亮度值0-100
|
||||||
|
*/
|
||||||
|
private Integer brightness;
|
||||||
|
// /**
|
||||||
|
// * 红色LED亮度值0-100
|
||||||
|
// */
|
||||||
|
// private Integer red;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 蓝色LED亮度值0-100
|
||||||
|
// */
|
||||||
|
// private Integer blue;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 黄色LED亮度值0-100
|
||||||
|
// */
|
||||||
|
// private Integer yellow;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JStrobeFrequencyDto{
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
private Long deviceId;
|
||||||
|
/**
|
||||||
|
* "frequency": 1-12
|
||||||
|
*/
|
||||||
|
private Integer frequency;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JStrobeModeDto{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
private Long deviceId;
|
||||||
|
/**
|
||||||
|
* 0 关闭 1 开启
|
||||||
|
*/
|
||||||
|
private Integer enable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||||
|
*/
|
||||||
|
private Integer mode;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JUpdateVoiceDto {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JUpdateVolumeDto{
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
private Long deviceId;
|
||||||
|
/**
|
||||||
|
* "volume": 1-100(app端可根据需求把40作为低音量, 70作为中音量,100作为高音量)
|
||||||
|
*/
|
||||||
|
private Integer volume;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package com.fuyuanshen.web.controller.device.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HBY100JVoiceBroadcastDto {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
Long deviceId;
|
||||||
|
/**
|
||||||
|
* 0 关闭, 1开启
|
||||||
|
*/
|
||||||
|
private Integer voiceBroadcast;
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,10 +1,7 @@
|
|||||||
package com.fuyuanshen.web.domain.vo;
|
package com.fuyuanshen.web.domain.vo;
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
import com.fuyuanshen.equipment.domain.vo.AppFileVo;
|
||||||
import com.fuyuanshen.app.domain.vo.AppFileVo;
|
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
|
||||||
import com.fuyuanshen.equipment.domain.Device;
|
|
||||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@ -86,7 +86,7 @@ public class DeviceBizService {
|
|||||||
List<AppDeviceVo> records = result.getRecords();
|
List<AppDeviceVo> records = result.getRecords();
|
||||||
if (records != null && !records.isEmpty()) {
|
if (records != null && !records.isEmpty()) {
|
||||||
records.forEach(item -> {
|
records.forEach(item -> {
|
||||||
if (item.getCommunicationMode() != null && item.getCommunicationMode() == 0) {
|
if (item.getCommunicationMode() != null && (item.getCommunicationMode() == 0 || item.getCommunicationMode() == 2)) {
|
||||||
|
|
||||||
// 设备在线状态
|
// 设备在线状态
|
||||||
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
|
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
|
||||||
@ -97,6 +97,7 @@ public class DeviceBizService {
|
|||||||
} else {
|
} else {
|
||||||
item.setOnlineStatus(0);
|
item.setOnlineStatus(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
|
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX);
|
||||||
// 获取电量
|
// 获取电量
|
||||||
if (StringUtils.isNotBlank(deviceStatus)) {
|
if (StringUtils.isNotBlank(deviceStatus)) {
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
package com.fuyuanshen.web.service.device;
|
package com.fuyuanshen.web.service.device;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||||
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
import com.fuyuanshen.app.domain.dto.AppFileDto;
|
||||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||||
import com.fuyuanshen.equipment.service.DeviceService;
|
import com.fuyuanshen.equipment.service.DeviceService;
|
||||||
|
|||||||
@ -0,0 +1,420 @@
|
|||||||
|
package com.fuyuanshen.web.service.device;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.fuyuanshen.app.domain.vo.AppDeviceHBY100JDetailVo;
|
||||||
|
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
||||||
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
|
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
||||||
|
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||||
|
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||||
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
|
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||||
|
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||||
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
|
import com.fuyuanshen.equipment.domain.DeviceType;
|
||||||
|
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||||
|
import com.fuyuanshen.equipment.mapper.AppBusinessFileMapper;
|
||||||
|
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
||||||
|
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||||
|
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
||||||
|
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||||
|
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
||||||
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
|
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
|
||||||
|
import com.fuyuanshen.global.mqtt.rule.hby100j.domin.*;
|
||||||
|
import com.fuyuanshen.global.mqtt.utils.GenerateIdUtil;
|
||||||
|
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
||||||
|
import com.fuyuanshen.system.mapper.SysOssMapper;
|
||||||
|
import com.fuyuanshen.web.controller.device.domain.dto.*;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
||||||
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DeviceHBY100JBizService {
|
||||||
|
|
||||||
|
private final DeviceMapper deviceMapper;
|
||||||
|
private final DeviceTypeMapper deviceTypeMapper;
|
||||||
|
private final MqttGateway mqttGateway;
|
||||||
|
private final DeviceLogMapper deviceLogMapper;
|
||||||
|
private final IAppBusinessFileService appBusinessFileService;
|
||||||
|
private final AppBusinessFileMapper appBusinessFileMapper;
|
||||||
|
private final SysOssMapper sysOssMapper;
|
||||||
|
private final AppDeviceShareMapper appDeviceShareMapper;
|
||||||
|
|
||||||
|
|
||||||
|
private static final String DEVICE_TYPE = "HBY100/";
|
||||||
|
/**
|
||||||
|
* 记录设备操作日志
|
||||||
|
*
|
||||||
|
* @param deviceId 设备ID
|
||||||
|
* @param content 日志内容
|
||||||
|
* @param operator 操作人
|
||||||
|
*/
|
||||||
|
private void recordDeviceLog(Long deviceId, String deviceName, String deviceAction, String content, Long operator) {
|
||||||
|
try {
|
||||||
|
// 创建设备日志实体
|
||||||
|
com.fuyuanshen.equipment.domain.DeviceLog deviceLog = new com.fuyuanshen.equipment.domain.DeviceLog();
|
||||||
|
deviceLog.setDeviceId(deviceId);
|
||||||
|
deviceLog.setDeviceAction(deviceAction);
|
||||||
|
deviceLog.setContent(content);
|
||||||
|
deviceLog.setCreateBy(operator);
|
||||||
|
deviceLog.setDeviceName(deviceName);
|
||||||
|
deviceLog.setCreateTime(new Date());
|
||||||
|
|
||||||
|
// 插入日志记录
|
||||||
|
deviceLogMapper.insert(deviceLog);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("记录设备操作日志失败: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AppDeviceHBY100JDetailVo getInfo(Long id) {
|
||||||
|
Device device = deviceMapper.selectById(id);
|
||||||
|
if (device == null) {
|
||||||
|
throw new RuntimeException("请先将设备入库!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppDeviceHBY100JDetailVo vo = new AppDeviceHBY100JDetailVo();
|
||||||
|
vo.setDeviceId(device.getId());
|
||||||
|
vo.setDeviceName(device.getDeviceName());
|
||||||
|
vo.setDevicePic(device.getDevicePic());
|
||||||
|
vo.setDeviceImei(device.getDeviceImei());
|
||||||
|
vo.setDeviceMac(device.getDeviceMac());
|
||||||
|
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
|
||||||
|
if (deviceType != null) {
|
||||||
|
vo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode()));
|
||||||
|
vo.setTypeName(deviceType.getTypeName());
|
||||||
|
}
|
||||||
|
vo.setBluetoothName(device.getBluetoothName());
|
||||||
|
|
||||||
|
// 设备在线状态
|
||||||
|
String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX);
|
||||||
|
// 设备在线状态
|
||||||
|
if ("1".equals(onlineStatus)) {
|
||||||
|
vo.setOnlineStatus(1);
|
||||||
|
} else if ("2".equals(onlineStatus)) {
|
||||||
|
vo.setOnlineStatus(2);
|
||||||
|
} else {
|
||||||
|
vo.setOnlineStatus(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX);
|
||||||
|
// 获取电量
|
||||||
|
if (StringUtils.isNotBlank(deviceStatus)) {
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(deviceStatus);
|
||||||
|
vo.setBatteryPercentage(jsonObject.getInteger("batteryPercentage"));
|
||||||
|
vo.setChargeState(jsonObject.getInteger("chargeState"));
|
||||||
|
vo.setBatteryRemainingTime(jsonObject.getInteger("batteryRemainingTime"));
|
||||||
|
} else {
|
||||||
|
vo.setBatteryPercentage(0);
|
||||||
|
vo.setBatteryRemainingTime(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
String reportStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + ":report");
|
||||||
|
if (StringUtils.isNotBlank(reportStatus)) {
|
||||||
|
FuncType14StatusReport report = JSONObject.parseObject(reportStatus,FuncType14StatusReport.class);
|
||||||
|
FuncType14StatusReport.Data data = report.getData();
|
||||||
|
FuncType14StatusReport.Brightness brightness = data.getBrightness();
|
||||||
|
if(brightness != null){
|
||||||
|
vo.setLightBrightness(brightness.getRed());
|
||||||
|
}
|
||||||
|
|
||||||
|
vo.setVolume(data.getVolume());
|
||||||
|
FuncType14StatusReport.LedStrobe ledStrobe = data.getLedStrobe();
|
||||||
|
if(ledStrobe != null){
|
||||||
|
vo.setStrobeFrequency(ledStrobe.getFrequency());
|
||||||
|
vo.setStrobeMode(ledStrobe.getMode());
|
||||||
|
vo.setStrobeEnable(ledStrobe.getEnable());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Integer voiceBroadcast = data.getVoiceBroadcast();
|
||||||
|
if(voiceBroadcast != null){
|
||||||
|
vo.setVoiceBroadcast(voiceBroadcast);
|
||||||
|
}
|
||||||
|
FuncType14StatusReport.SirenAlarm sirenAlarm = data.getSirenAlarm();
|
||||||
|
if(sirenAlarm != null){
|
||||||
|
vo.setVoiceStrobeAlarm(sirenAlarm.getEnable());
|
||||||
|
vo.setAlarmMode(sirenAlarm.getMode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String strobeModeRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
device.getDeviceImei() + ":strobeMode";
|
||||||
|
String strobeModeStatus = RedisUtils.getCacheObject(strobeModeRedisKey);
|
||||||
|
if(StringUtils.isNotBlank(strobeModeStatus)){
|
||||||
|
FuncType10StrobeModeRequest strobeModeRequest = JSONObject.parseObject(strobeModeStatus, FuncType10StrobeModeRequest.class);
|
||||||
|
FuncType10StrobeModeRequest.Data data = strobeModeRequest.getData();
|
||||||
|
if(data != null){
|
||||||
|
vo.setStrobeMode(strobeModeRequest.getData().getMode());
|
||||||
|
vo.setStrobeEnable(strobeModeRequest.getData().getEnable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String updateVolumeRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
device.getDeviceImei() + ":updateVolume";
|
||||||
|
String updateVolumeStatus = RedisUtils.getCacheObject(updateVolumeRedisKey);
|
||||||
|
if(StringUtils.isNotBlank(updateVolumeStatus)){
|
||||||
|
FuncType9UpdateVolumeRequest updateVolumeRequest = JSONObject.parseObject(updateVolumeStatus, FuncType9UpdateVolumeRequest.class);
|
||||||
|
if(updateVolumeRequest.getData() != null){
|
||||||
|
vo.setVolume(updateVolumeRequest.getData().getVolume());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String frequencyRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
device.getDeviceImei() + ":frequency";
|
||||||
|
String frequencyStatus = RedisUtils.getCacheObject(frequencyRedisKey);
|
||||||
|
if(StringUtils.isNotBlank(frequencyStatus)){
|
||||||
|
FuncType11FrequencyRequest frequencyRequest = JSONObject.parseObject(frequencyStatus, FuncType11FrequencyRequest.class);
|
||||||
|
if(frequencyRequest.getData() != null){
|
||||||
|
vo.setStrobeFrequency(frequencyRequest.getData().getFrequency());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String forceAudioRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX +
|
||||||
|
device.getDeviceImei() + ":forceAudio";
|
||||||
|
String forceAudioStatus = RedisUtils.getCacheObject(forceAudioRedisKey);
|
||||||
|
if(StringUtils.isNotBlank(forceAudioStatus)){
|
||||||
|
FuncType12ForceAudioRequest forceAudioRequest = JSONObject.parseObject(forceAudioStatus, FuncType12ForceAudioRequest.class);
|
||||||
|
if(forceAudioRequest.getData() != null){
|
||||||
|
vo.setVoiceStrobeAlarm(forceAudioRequest.getData().getVoiceStrobeAlarm());
|
||||||
|
vo.setAlarmMode(forceAudioRequest.getData().getMode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 获取经度纬度
|
||||||
|
|
||||||
|
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX);
|
||||||
|
if (StringUtils.isNotBlank(location)) {
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(location);
|
||||||
|
vo.setLatitude(jsonObject.getString("latitude"));
|
||||||
|
vo.setLongitude(jsonObject.getString("longitude"));
|
||||||
|
vo.setAddress(jsonObject.getString("address"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<AppBusinessFile> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("business_id", device.getId());
|
||||||
|
queryWrapper.eq("file_type", 3);
|
||||||
|
queryWrapper.eq("use_status", 1);
|
||||||
|
List<AppBusinessFile> appBusinessFiles = appBusinessFileMapper.selectList(queryWrapper);
|
||||||
|
if(appBusinessFiles != null && appBusinessFiles.size() > 0){
|
||||||
|
AppBusinessFile appBusinessFile = appBusinessFiles.get(0);
|
||||||
|
SysOssVo sysOssVo = sysOssMapper.selectVoById(appBusinessFile.getFileId());
|
||||||
|
if(sysOssVo != null){
|
||||||
|
vo.setVoiceResource(sysOssVo.getUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean getDeviceStatus(String deviceImei) {
|
||||||
|
String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX;
|
||||||
|
return RedisUtils.getCacheObject(deviceOnlineStatusRedisKey) == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void forceAlarmActivation(HBY100JForceAlarmActivationDto bo) {
|
||||||
|
List<Long> deviceIds = bo.getDeviceIds();
|
||||||
|
if (deviceIds == null || deviceIds.isEmpty()) {
|
||||||
|
throw new ServiceException("请选择设备");
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
bo.getDeviceIds().forEach(deviceId -> {
|
||||||
|
Device deviceObj = deviceMapper.selectById(deviceId);
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncType12ForceAudioRequest request = new FuncType12ForceAudioRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("12");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType12ForceAudioRequest.Data data = new FuncType12ForceAudioRequest.Data();
|
||||||
|
data.setVoiceStrobeAlarm(bo.getVoiceStrobeAlarm());
|
||||||
|
data.setMode(bo.getMode());
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J强制报警,下发设备参数:{}", request);
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
|
||||||
|
|
||||||
|
recordDeviceLog(deviceId, deviceObj.getDeviceName(), "强制报警激活", "强制报警激活", loginUser.getUserId());
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateVoice(HBY100JUpdateVoiceDto dto) {
|
||||||
|
AppBusinessFileVo appBusinessFileVo = appBusinessFileMapper.selectVoById(dto.getId());
|
||||||
|
if(appBusinessFileVo == null){
|
||||||
|
throw new ServiceException("文件不存在");
|
||||||
|
}
|
||||||
|
Device deviceObj = deviceMapper.selectById(appBusinessFileVo.getBusinessId());
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
SysOssVo sysOssVo = sysOssMapper.selectVoById(appBusinessFileVo.getFileId());
|
||||||
|
FuncType5UpdateVoiceRequest request = new FuncType5UpdateVoiceRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("5");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType5UpdateVoiceRequest.Data data = new FuncType5UpdateVoiceRequest.Data();
|
||||||
|
data.setVoiceResource(sysOssVo.getUrl());
|
||||||
|
data.setVoiceType(0);
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J更新语音,参数:{}", request);
|
||||||
|
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
|
||||||
|
UpdateWrapper<AppBusinessFile> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("business_id", appBusinessFileVo.getBusinessId());
|
||||||
|
updateWrapper.set("use_status", 0);
|
||||||
|
appBusinessFileMapper.update(updateWrapper);
|
||||||
|
|
||||||
|
UpdateWrapper<AppBusinessFile> updateWrapper2 = new UpdateWrapper<>();
|
||||||
|
updateWrapper2.eq("id", appBusinessFileVo.getId());
|
||||||
|
updateWrapper2.set("use_status", 1);
|
||||||
|
appBusinessFileMapper.update(updateWrapper2);
|
||||||
|
|
||||||
|
recordDeviceLog(deviceObj.getId(), deviceObj.getDeviceName(), "更新语音", "更新语音", loginUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildMqttTopic(String deviceImei) {
|
||||||
|
String tenantId = LoginHelper.getTenantId();
|
||||||
|
return MqttConstants.GLOBAL_PUB_KEY2 +tenantId + "/" + DEVICE_TYPE + deviceImei;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void strobeMode(HBY100JStrobeModeDto params) {
|
||||||
|
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
FuncType10StrobeModeRequest request = new FuncType10StrobeModeRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("10");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType10StrobeModeRequest.Data data = new FuncType10StrobeModeRequest.Data();
|
||||||
|
data.setMode(params.getMode());
|
||||||
|
data.setEnable(params.getEnable());
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J爆闪模式开启/关闭,下发设备参数:{}", request);
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
String content = params.getEnable() != null && params.getEnable() == 1 ? "爆闪模式开启" : "爆闪模式关闭";
|
||||||
|
recordDeviceLog(deviceObj.getId(), deviceObj.getDeviceName(), content, content, loginUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lightAdjustment(HBY100JLightAdjustmentDto params) {
|
||||||
|
log.info("HBY100J灯光调节,请求参数:{}", params);
|
||||||
|
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||||
|
if (deviceObj == null) {
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
FuncType13BrightnessRequest request = new FuncType13BrightnessRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("13");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType13BrightnessRequest.Data data = new FuncType13BrightnessRequest.Data();
|
||||||
|
data.setRed(params.getBrightness());
|
||||||
|
data.setBlue(params.getBrightness());
|
||||||
|
data.setYellow(params.getBrightness());
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J灯光调节,下发设备参数:{}", request);
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
recordDeviceLog(deviceObj.getId(), deviceObj.getDeviceName(), "灯光调节", "灯光调节", loginUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void strobeFrequency(HBY100JStrobeFrequencyDto params) {
|
||||||
|
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||||
|
if (deviceObj == null) {
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
FuncType11FrequencyRequest request = new FuncType11FrequencyRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("11");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType11FrequencyRequest.Data data = new FuncType11FrequencyRequest.Data();
|
||||||
|
data.setFrequency(params.getFrequency());
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J爆闪频率,下发设备参数:{}", request);
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
recordDeviceLog(deviceObj.getId(), deviceObj.getDeviceName(), "爆闪频率", "爆闪频率", loginUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateVolume(HBY100JUpdateVolumeDto params) {
|
||||||
|
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||||
|
if (deviceObj == null) {
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
FuncType9UpdateVolumeRequest request = new FuncType9UpdateVolumeRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("9");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType9UpdateVolumeRequest.Data data = new FuncType9UpdateVolumeRequest.Data();
|
||||||
|
data.setVolume(params.getVolume());
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J更新音量,下发设备参数:{}", JSON.toJSONString(request));
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
recordDeviceLog(deviceObj.getId(), deviceObj.getDeviceName(), "更新音量", "更新音量", loginUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void voiceBroadcast(HBY100JVoiceBroadcastDto params) {
|
||||||
|
Device deviceObj = deviceMapper.selectById(params.getDeviceId());
|
||||||
|
if (deviceObj == null) {
|
||||||
|
throw new ServiceException("设备不存在");
|
||||||
|
}
|
||||||
|
if (getDeviceStatus(deviceObj.getDeviceImei())) {
|
||||||
|
throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接");
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser();
|
||||||
|
FuncType6VoicePlayRequest request = new FuncType6VoicePlayRequest();
|
||||||
|
request.setRequestId(GenerateIdUtil.generateNumericId());
|
||||||
|
request.setImei(deviceObj.getDeviceImei());
|
||||||
|
request.setFuncType("6");
|
||||||
|
request.setTimestamp(System.currentTimeMillis());
|
||||||
|
FuncType6VoicePlayRequest.Data data = new FuncType6VoicePlayRequest.Data();
|
||||||
|
data.setVoiceBroadcast(params.getVoiceBroadcast());
|
||||||
|
request.setData(data);
|
||||||
|
log.info("HBY100J语音播报,下发设备参数:{}", request);
|
||||||
|
mqttGateway.sendMsgToMqtt(buildMqttTopic(deviceObj.getDeviceImei()), 1, JSON.toJSONString(request));
|
||||||
|
recordDeviceLog(deviceObj.getId(), deviceObj.getDeviceName(), "语音播报", "语音播报", loginUser.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
package com.fuyuanshen.web.service.device;
|
package com.fuyuanshen.web.service.device;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
|
||||||
import cn.hutool.core.lang.UUID;
|
import cn.hutool.core.lang.UUID;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
@ -15,20 +15,17 @@ import com.fuyuanshen.app.domain.AppPersonnelInfo;
|
|||||||
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
||||||
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
|
||||||
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto;
|
||||||
import com.fuyuanshen.app.domain.dto.DeviceInstructDto;
|
|
||||||
import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo;
|
|
||||||
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
|
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
|
||||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
||||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper;
|
import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper;
|
||||||
|
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||||
|
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||||
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
import com.fuyuanshen.common.core.constant.GlobalConstants;
|
||||||
import com.fuyuanshen.common.core.domain.R;
|
|
||||||
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
|
||||||
import com.fuyuanshen.common.core.domain.model.LoginUser;
|
|
||||||
import com.fuyuanshen.common.core.exception.BadRequestException;
|
import com.fuyuanshen.common.core.exception.BadRequestException;
|
||||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||||
import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
|
import com.fuyuanshen.common.core.utils.ImageToCArrayConverter;
|
||||||
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
import com.fuyuanshen.common.core.utils.MapstructUtils;
|
||||||
import com.fuyuanshen.common.core.utils.ObjectUtils;
|
|
||||||
import com.fuyuanshen.common.core.utils.StringUtils;
|
import com.fuyuanshen.common.core.utils.StringUtils;
|
||||||
import com.fuyuanshen.common.json.utils.JsonUtils;
|
import com.fuyuanshen.common.json.utils.JsonUtils;
|
||||||
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
import com.fuyuanshen.common.redis.utils.RedisUtils;
|
||||||
@ -40,7 +37,6 @@ import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo;
|
|||||||
import com.fuyuanshen.equipment.domain.form.DeviceForm;
|
import com.fuyuanshen.equipment.domain.form.DeviceForm;
|
||||||
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
|
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
|
||||||
import com.fuyuanshen.equipment.enums.DeviceActiveStatusEnum;
|
import com.fuyuanshen.equipment.enums.DeviceActiveStatusEnum;
|
||||||
import com.fuyuanshen.equipment.enums.LightModeEnum;
|
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceTypeGrantsMapper;
|
import com.fuyuanshen.equipment.mapper.DeviceTypeGrantsMapper;
|
||||||
@ -51,26 +47,23 @@ import com.fuyuanshen.global.mqtt.base.MqttXinghanJson;
|
|||||||
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
||||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
|
import com.fuyuanshen.global.mqtt.constants.MqttConstants;
|
||||||
import com.fuyuanshen.system.domain.vo.SysOssVo;
|
|
||||||
import com.fuyuanshen.system.domain.vo.SysRoleVo;
|
|
||||||
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto;
|
||||||
import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto;
|
import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto;
|
||||||
import com.fuyuanshen.web.domain.vo.DeviceXinghanDetailVo;
|
import com.fuyuanshen.web.domain.vo.DeviceXinghanDetailVo;
|
||||||
import com.fuyuanshen.web.enums.AlarmTypeEnum;
|
import com.fuyuanshen.web.enums.AlarmTypeEnum;
|
||||||
|
import com.fuyuanshen.web.util.AliyunVoiceUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
|
||||||
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
|
import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal;
|
||||||
@ -91,8 +84,11 @@ public class DeviceXinghanBizService {
|
|||||||
private final IDeviceAlarmService deviceAlarmService;
|
private final IDeviceAlarmService deviceAlarmService;
|
||||||
private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;
|
private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;
|
||||||
private final DeviceAssignmentsService deviceAssignmentsService;
|
private final DeviceAssignmentsService deviceAssignmentsService;
|
||||||
|
private final IAppBusinessFileService appBusinessFileService;
|
||||||
|
private final IAppOperationVideoService appOperationVideoService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
private final AliyunVoiceUtil voiceUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有档位的描述表
|
* 所有档位的描述表
|
||||||
@ -135,7 +131,6 @@ public class DeviceXinghanBizService {
|
|||||||
public void upSOSGradeSettings(DeviceXinghanInstructDto dto) {
|
public void upSOSGradeSettings(DeviceXinghanInstructDto dto) {
|
||||||
if(dto.getIsBluetooth()){
|
if(dto.getIsBluetooth()){
|
||||||
long deviceId = dto.getDeviceId();
|
long deviceId = dto.getDeviceId();
|
||||||
|
|
||||||
// 1. 使用Optional简化空值检查,使代码更简洁
|
// 1. 使用Optional简化空值检查,使代码更简洁
|
||||||
Device device = Optional.ofNullable(deviceMapper.selectById(deviceId))
|
Device device = Optional.ofNullable(deviceMapper.selectById(deviceId))
|
||||||
.orElseThrow(() -> new ServiceException("设备不存在"));
|
.orElseThrow(() -> new ServiceException("设备不存在"));
|
||||||
@ -147,6 +142,24 @@ public class DeviceXinghanBizService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发异步报警
|
||||||
|
* Spring 会自动调用 AsyncConfig.getAsyncExecutor() 来执行此方法
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
public void executeSosCall(String phone) {
|
||||||
|
log.info("[SOS业务] 准备发起语音拨号 -> 目标: {}", phone);
|
||||||
|
Map<String, String> params = Map.of("device", "670");
|
||||||
|
String callId = voiceUtil.sendTtsSync(phone, "TTS_328730104", params);
|
||||||
|
|
||||||
|
if (callId != null) {
|
||||||
|
log.info("[SOS业务] 拨号指令下发成功, callId: {}", callId);
|
||||||
|
// 这里可以记录拨打日志到数据库
|
||||||
|
} else {
|
||||||
|
log.error("[SOS业务] 拨号指令下发失败,请检查配置或余额");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置强制报警
|
* 设置强制报警
|
||||||
*/
|
*/
|
||||||
@ -701,20 +714,31 @@ public class DeviceXinghanBizService {
|
|||||||
return deviceTypeMapper.findAll(criteria);
|
return deviceTypeMapper.findAll(criteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Log("新增设备")
|
/**
|
||||||
public void addDevice(DeviceForm deviceForm) {
|
* 校验唯一性约束
|
||||||
if (deviceForm.getDeviceMac() != null && deviceForm.getBluetoothName() == null) {
|
*/
|
||||||
|
private void validateDeviceUnique(DeviceForm form) {
|
||||||
|
if (form.getDeviceMac() != null && form.getBluetoothName() == null) {
|
||||||
throw new BadRequestException("请填写蓝牙名称!!!");
|
throw new BadRequestException("请填写蓝牙名称!!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Device device1 = deviceMapper.selectOne(new QueryWrapper<Device>().eq("device_mac", deviceForm.getDeviceMac()));
|
// 使用 QueryWrapper 替代 lambdaQuery()
|
||||||
if (device1 != null) {
|
Long macCount = deviceMapper.selectCount(new LambdaQueryWrapper<Device>()
|
||||||
|
.eq(Device::getDeviceMac, form.getDeviceMac()));
|
||||||
|
if (macCount > 0) {
|
||||||
throw new BadRequestException("设备MAC已存在!!!");
|
throw new BadRequestException("设备MAC已存在!!!");
|
||||||
}
|
}
|
||||||
Device device2 = deviceMapper.selectOne(new QueryWrapper<Device>().eq("device_imei", deviceForm.getDeviceImei()));
|
|
||||||
if (device2 != null) {
|
Long imeiCount = deviceMapper.selectCount(new LambdaQueryWrapper<Device>()
|
||||||
|
.eq(Device::getDeviceImei, form.getDeviceImei()));
|
||||||
|
if (imeiCount > 0) {
|
||||||
throw new BadRequestException("设备IMEI已存在!!!");
|
throw new BadRequestException("设备IMEI已存在!!!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Log("新增设备")
|
||||||
|
public void addDevice(DeviceForm deviceForm) {
|
||||||
|
validateDeviceUnique(deviceForm);
|
||||||
|
|
||||||
DeviceTypeQueryCriteria queryCriteria = new DeviceTypeQueryCriteria();
|
DeviceTypeQueryCriteria queryCriteria = new DeviceTypeQueryCriteria();
|
||||||
queryCriteria.setDeviceTypeId(deviceForm.getDeviceType());
|
queryCriteria.setDeviceTypeId(deviceForm.getDeviceType());
|
||||||
@ -739,6 +763,7 @@ public class DeviceXinghanBizService {
|
|||||||
device.setCreateByName(loginUser.getNickname());
|
device.setCreateByName(loginUser.getNickname());
|
||||||
device.setTypeName(deviceTypes.getTypeName());
|
device.setTypeName(deviceTypes.getTypeName());
|
||||||
device.setDeviceType(deviceTypes.getId());
|
device.setDeviceType(deviceTypes.getId());
|
||||||
|
device.setDevicePic(deviceTypes.getDevicePic());
|
||||||
if (device.getDeviceImei() != null) {
|
if (device.getDeviceImei() != null) {
|
||||||
device.setPubTopic("A/" + device.getDeviceImei());
|
device.setPubTopic("A/" + device.getDeviceImei());
|
||||||
device.setSubTopic("B/" + device.getDeviceImei());
|
device.setSubTopic("B/" + device.getDeviceImei());
|
||||||
@ -747,6 +772,14 @@ public class DeviceXinghanBizService {
|
|||||||
device.setBindingStatus(0);
|
device.setBindingStatus(0);
|
||||||
deviceMapper.insert(device);
|
deviceMapper.insert(device);
|
||||||
|
|
||||||
|
Long deviceId = device.getDeviceId();
|
||||||
|
|
||||||
|
// 查询设备类型的文件列表
|
||||||
|
// 4. 核心优化:同步设备类型的文件列表 (一行代码)
|
||||||
|
appBusinessFileService.cloneFiles(deviceTypes.getId(), device.getId());
|
||||||
|
//同步设备类型的视频列表
|
||||||
|
appOperationVideoService.cloneFiles(deviceTypes.getId(), device.getId());
|
||||||
|
|
||||||
// 新增设备类型记录
|
// 新增设备类型记录
|
||||||
DeviceAssignments assignments = new DeviceAssignments();
|
DeviceAssignments assignments = new DeviceAssignments();
|
||||||
assignments.setDeviceId(device.getId());
|
assignments.setDeviceId(device.getId());
|
||||||
@ -767,4 +800,23 @@ public class DeviceXinghanBizService {
|
|||||||
return uuidStr.replaceAll("-", "");
|
return uuidStr.replaceAll("-", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> GetDeviceByName(DeviceForm deviceForm){
|
||||||
|
List<Map<String, Object>> list= deviceMapper.GetDeviceByName(deviceForm);
|
||||||
|
Map<String, Object> device=null;
|
||||||
|
if(list!=null && list.size()>0){
|
||||||
|
device=list.get(0);
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEquipCountByType(DeviceForm form){
|
||||||
|
var res=deviceMapper.getEquipCountByType(form);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String,Object>> getEquipAllByType(DeviceForm deviceForm){
|
||||||
|
List<Map<String, Object>> list= deviceMapper.getEquipAllByType(deviceForm);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
package com.fuyuanshen.web.util;
|
||||||
|
|
||||||
|
import com.aliyun.dyvmsapi20170525.Client;
|
||||||
|
import com.aliyun.dyvmsapi20170525.models.SingleCallByTtsRequest;
|
||||||
|
import com.aliyun.dyvmsapi20170525.models.SingleCallByTtsResponse;
|
||||||
|
import com.aliyun.teaopenapi.models.Config;
|
||||||
|
import com.aliyun.teautil.models.RuntimeOptions;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class AliyunVoiceUtil {
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Value("${alibaba.tts.akId}")
|
||||||
|
private String akId;
|
||||||
|
@Value("${alibaba.tts.akSecret}")
|
||||||
|
private String akSecret;
|
||||||
|
// @Value("${alibaba.tts.calledShowNumber:}")
|
||||||
|
private String calledShowNumber;
|
||||||
|
|
||||||
|
// ========== 核心:单例客户端(类似 OkHttpClient) ==========
|
||||||
|
private volatile Client client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取客户端(双重检查锁实现单例)
|
||||||
|
* 只有在第一次调用时才会根据配置实例化,后续直接返回复用
|
||||||
|
*/
|
||||||
|
private Client getClient() throws Exception {
|
||||||
|
if (client == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (client == null) {
|
||||||
|
log.info("[AliyunVoice] 正在初始化阿里云语音客户端...");
|
||||||
|
Config config = new Config()
|
||||||
|
.setAccessKeyId(akId)
|
||||||
|
.setAccessKeySecret(akSecret)
|
||||||
|
.setEndpoint("dyvmsapi.aliyuncs.com");
|
||||||
|
this.client = new Client(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步发送方法:由异步架构调用
|
||||||
|
*/
|
||||||
|
public String sendTtsSync(String phone, String templateCode, Map<String, String> params) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 获取(或初始化)单例客户端
|
||||||
|
Client voiceClient = getClient();
|
||||||
|
|
||||||
|
SingleCallByTtsRequest request = new SingleCallByTtsRequest()
|
||||||
|
.setCalledNumber(phone)
|
||||||
|
.setTtsCode(templateCode)
|
||||||
|
.setTtsParam(objectMapper.writeValueAsString(params));
|
||||||
|
|
||||||
|
if (StringUtils.hasText(calledShowNumber)) {
|
||||||
|
request.setCalledShowNumber(calledShowNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生产级超时配置
|
||||||
|
RuntimeOptions runtime = new RuntimeOptions();
|
||||||
|
runtime.setConnectTimeout(5000);
|
||||||
|
runtime.setReadTimeout(10000);
|
||||||
|
|
||||||
|
SingleCallByTtsResponse response = voiceClient.singleCallByTtsWithOptions(request, runtime);
|
||||||
|
|
||||||
|
if ("OK".equalsIgnoreCase(response.getBody().getCode())) {
|
||||||
|
return response.getBody().getCallId();
|
||||||
|
} else {
|
||||||
|
log.error("[AliyunVoice] 拨号失败: {}", response.getBody().getMessage());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[AliyunVoice] 接口异常", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -279,11 +279,13 @@ justauth:
|
|||||||
# MQTT配置
|
# MQTT配置
|
||||||
mqtt:
|
mqtt:
|
||||||
username: admin
|
username: admin
|
||||||
password: fys123456
|
password: #YtvpSfCNG
|
||||||
url: tcp://47.107.152.87:1883
|
url: tcp://47.120.79.150:2883
|
||||||
subClientId: fys_subClient
|
subClientId: fys_subClient
|
||||||
subTopic: A/#,status/tenantCode/#,report/tenantCode/#
|
subTopic: A/#,status/#
|
||||||
pubTopic: B/#,command/tenantCode/#
|
pubTopic: B/#,command/#
|
||||||
|
subTopic2: regis/equip/#
|
||||||
|
pubTopic2: regis/#
|
||||||
pubClientId: fys_pubClient
|
pubClientId: fys_pubClient
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -283,14 +283,16 @@ mqtt:
|
|||||||
password: #YtvpSfCNG
|
password: #YtvpSfCNG
|
||||||
url: tcp://47.120.79.150:3883
|
url: tcp://47.120.79.150:3883
|
||||||
subClientId: fys_subClient
|
subClientId: fys_subClient
|
||||||
subTopic: A/#,status/tenantCode/#,report/tenantCode/#
|
subTopic: A/#,status/#
|
||||||
pubTopic: B/#,command/tenantCode/#
|
pubTopic: B/#,command/#
|
||||||
|
subTopic2: regis/equip/#
|
||||||
|
pubTopic2: regis/#
|
||||||
pubClientId: fys_pubClient
|
pubClientId: fys_pubClient
|
||||||
|
|
||||||
# TTS语音交互配置
|
# TTS语音交互配置
|
||||||
alibaba:
|
alibaba:
|
||||||
tts:
|
tts:
|
||||||
appKey: KTwSUKMrf2olFfjC
|
appKey: lbGuq5K5bEH4uxmT
|
||||||
akId: LTAI5t6RsfCvQh57qojzbEoe
|
akId: LTAI5t66moCkhNC32TDJ5ReP
|
||||||
akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R
|
akSecret: 2F3sdoBJ08bYvJcuDgSkLnJwGXsvYH
|
||||||
|
|
||||||
|
|||||||
@ -39,8 +39,8 @@ public class EncryptUtilsTest {
|
|||||||
loginBody.setClientId("e5cd7e4891bf95d1d19206ce24a7b32e");
|
loginBody.setClientId("e5cd7e4891bf95d1d19206ce24a7b32e");
|
||||||
loginBody.setGrantType("password");
|
loginBody.setGrantType("password");
|
||||||
loginBody.setTenantId("894078");
|
loginBody.setTenantId("894078");
|
||||||
loginBody.setCode("15");
|
loginBody.setCode("6");
|
||||||
loginBody.setUuid("28ecf3d396ce4e6db8eb414992235fad");
|
loginBody.setUuid("399d45194f3d4c7e9cbfb3294b198a9b");
|
||||||
// loginBody.setUsername("admin");
|
// loginBody.setUsername("admin");
|
||||||
// loginBody.setPassword("admin123");
|
// loginBody.setPassword("admin123");
|
||||||
loginBody.setUsername("dyf");
|
loginBody.setUsername("dyf");
|
||||||
|
|||||||
@ -17,9 +17,9 @@ import com.fuyuanshen.common.core.validate.AddGroup;
|
|||||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||||
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
|
import com.fuyuanshen.equipment.domain.vo.AppBusinessFileVo;
|
||||||
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
|
import com.fuyuanshen.equipment.domain.bo.AppBusinessFileBo;
|
||||||
import com.fuyuanshen.app.service.IAppBusinessFileService;
|
import com.fuyuanshen.equipment.service.IAppBusinessFileService;
|
||||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -17,9 +17,9 @@ import com.fuyuanshen.common.core.validate.AddGroup;
|
|||||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||||
import com.fuyuanshen.common.log.enums.BusinessType;
|
import com.fuyuanshen.common.log.enums.BusinessType;
|
||||||
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
import com.fuyuanshen.common.excel.utils.ExcelUtil;
|
||||||
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
|
import com.fuyuanshen.equipment.domain.vo.AppOperationVideoVo;
|
||||||
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
|
import com.fuyuanshen.equipment.domain.bo.AppOperationVideoBo;
|
||||||
import com.fuyuanshen.app.service.IAppOperationVideoService;
|
import com.fuyuanshen.equipment.service.IAppOperationVideoService;
|
||||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,145 @@
|
|||||||
|
package com.fuyuanshen.app.domain.vo;
|
||||||
|
|
||||||
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AppDeviceHBY100JDetailVo implements Serializable {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
@ExcelProperty(value = "设备ID")
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备名称
|
||||||
|
*/
|
||||||
|
private String deviceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备IMEI
|
||||||
|
*/
|
||||||
|
private String deviceImei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备MAC
|
||||||
|
*/
|
||||||
|
private String deviceMac;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
|
||||||
|
*/
|
||||||
|
private Integer communicationMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备图片
|
||||||
|
*/
|
||||||
|
private String devicePic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
|
private String typeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蓝牙名称
|
||||||
|
*/
|
||||||
|
private String bluetoothName;
|
||||||
|
|
||||||
|
//电量百分比
|
||||||
|
/**
|
||||||
|
* 电量百分比
|
||||||
|
*/
|
||||||
|
private Integer batteryPercentage;
|
||||||
|
|
||||||
|
//充电状态(0没有充电,1正在充电,2为已充满)
|
||||||
|
/**
|
||||||
|
* 充电状态(0没有充电,1正在充电,2为已充满)
|
||||||
|
*/
|
||||||
|
private Integer chargeState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线状态(0离线,1在线)
|
||||||
|
*/
|
||||||
|
private Integer onlineStatus;
|
||||||
|
|
||||||
|
// 经度
|
||||||
|
/**
|
||||||
|
* 经度
|
||||||
|
*/
|
||||||
|
private String longitude;
|
||||||
|
|
||||||
|
// 纬度
|
||||||
|
/**
|
||||||
|
* 纬度
|
||||||
|
*/
|
||||||
|
private String latitude;
|
||||||
|
|
||||||
|
// 逆解析地址
|
||||||
|
/**
|
||||||
|
* 逆解析地址
|
||||||
|
*/
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
// 亮度
|
||||||
|
/**
|
||||||
|
* 亮度
|
||||||
|
*/
|
||||||
|
private Integer lightBrightness;
|
||||||
|
|
||||||
|
// 音量
|
||||||
|
/**
|
||||||
|
* 音量
|
||||||
|
*/
|
||||||
|
private Integer volume;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音资源URL(MP3等音频文件地址)
|
||||||
|
*/
|
||||||
|
private String voiceResource;
|
||||||
|
|
||||||
|
// 报警模式 0公安,1 消防,2应急,3交警,4 市政,5 铁路,6 医疗,7 自定义语音
|
||||||
|
/**
|
||||||
|
* 报警模式 0公安,1 消防,2应急,3交警,4 市政,5 铁路,6 医疗,7 自定义语音
|
||||||
|
*/
|
||||||
|
private Integer alarmMode;
|
||||||
|
|
||||||
|
// 强制报警开关: 0 关闭, 1开启
|
||||||
|
/**
|
||||||
|
* 强制报警开关: 0 关闭, 1开启
|
||||||
|
*/
|
||||||
|
private Integer voiceStrobeAlarm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 红色爆闪,1 蓝色爆闪,2 黄色爆闪,3,红色顺时针旋转爆闪,4黄色顺时针旋转爆闪,5,红蓝顺时针旋转爆闪,6 红蓝交替爆闪
|
||||||
|
*/
|
||||||
|
private Integer strobeMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "enable": 0爆闪关闭, 1爆闪开启
|
||||||
|
*/
|
||||||
|
private Integer strobeEnable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 爆闪频率
|
||||||
|
*/
|
||||||
|
private Integer strobeFrequency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音播报0 关闭, 1开启
|
||||||
|
*/
|
||||||
|
private Integer voiceBroadcast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 续航时间(分钟)
|
||||||
|
*/
|
||||||
|
private Integer batteryRemainingTime;
|
||||||
|
}
|
||||||
@ -51,6 +51,11 @@ public class AppDeviceShareVo implements Serializable {
|
|||||||
@ExcelProperty(value = "设备名称")
|
@ExcelProperty(value = "设备名称")
|
||||||
private String deviceName;
|
private String deviceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备mac地址
|
||||||
|
*/
|
||||||
|
private String deviceMac;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手机号
|
* 手机号
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -16,10 +16,8 @@ import com.fuyuanshen.customer.domain.vo.ConsumerVo;
|
|||||||
import com.fuyuanshen.customer.mapper.CustomerMapper;
|
import com.fuyuanshen.customer.mapper.CustomerMapper;
|
||||||
import com.fuyuanshen.customer.service.CustomerService;
|
import com.fuyuanshen.customer.service.CustomerService;
|
||||||
import com.fuyuanshen.system.domain.SysUserRole;
|
import com.fuyuanshen.system.domain.SysUserRole;
|
||||||
import com.fuyuanshen.system.domain.bo.SysUserBo;
|
|
||||||
import com.fuyuanshen.system.mapper.SysRoleMapper;
|
import com.fuyuanshen.system.mapper.SysRoleMapper;
|
||||||
import com.fuyuanshen.system.mapper.SysUserRoleMapper;
|
import com.fuyuanshen.system.mapper.SysUserRoleMapper;
|
||||||
import com.fuyuanshen.system.service.ISysUserService;
|
|
||||||
import com.fuyuanshen.system.service.impl.SysUserServiceImpl;
|
import com.fuyuanshen.system.service.impl.SysUserServiceImpl;
|
||||||
import io.undertow.util.BadRequestException;
|
import io.undertow.util.BadRequestException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
@ -18,6 +18,12 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org</groupId>
|
||||||
|
<artifactId>jaudiotagger</artifactId>
|
||||||
|
<version>2.0.3</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<!-- <dependency> -->
|
<!-- <dependency> -->
|
||||||
<!-- <groupId>com.fuyuanshen</groupId> -->
|
<!-- <groupId>com.fuyuanshen</groupId> -->
|
||||||
<!-- <artifactId>fys-app</artifactId> -->
|
<!-- <artifactId>fys-app</artifactId> -->
|
||||||
@ -140,6 +146,18 @@
|
|||||||
<version>3.3.1</version>
|
<version>3.3.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 电话语音通知 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>dyvmsapi20170525</artifactId>
|
||||||
|
<version>4.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>tea-openapi</artifactId>
|
||||||
|
<version>0.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- fastjson2 -->
|
<!-- fastjson2 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
|||||||
@ -317,8 +317,7 @@ public class DeviceController extends BaseController {
|
|||||||
// 定义必需的表头
|
// 定义必需的表头
|
||||||
Set<String> requiredHeaders = new HashSet<>(Arrays.asList(
|
Set<String> requiredHeaders = new HashSet<>(Arrays.asList(
|
||||||
"设备名称", "设备类型名称", "设备图片", "设备MAC", "蓝牙名称", "设备IMEI",
|
"设备名称", "设备类型名称", "设备图片", "设备MAC", "蓝牙名称", "设备IMEI",
|
||||||
"备注", "是否支持蓝牙", "定位方式", "通讯方式",
|
"备注"
|
||||||
"型号字典用于APP页面跳转", "型号字典用于PC页面跳转"
|
|
||||||
));
|
));
|
||||||
|
|
||||||
// 检查必需的表头是否都存在
|
// 检查必需的表头是否都存在
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,7 +51,7 @@ public class DeviceTypeController {
|
|||||||
// @Log("新增设备类型")
|
// @Log("新增设备类型")
|
||||||
@Operation(summary = "新增设备类型")
|
@Operation(summary = "新增设备类型")
|
||||||
@PostMapping(value = "/add")
|
@PostMapping(value = "/add")
|
||||||
public R<Void> createDeviceType(@Validated @RequestBody DeviceType resources) {
|
public R<Void> createDeviceType(@Validated @ModelAttribute DeviceTypeForm resources) throws IOException {
|
||||||
deviceTypeService.create(resources);
|
deviceTypeService.create(resources);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
@ -59,7 +60,7 @@ public class DeviceTypeController {
|
|||||||
// @Log("修改设备类型")
|
// @Log("修改设备类型")
|
||||||
@Operation(summary = "修改设备类型")
|
@Operation(summary = "修改设备类型")
|
||||||
@PutMapping(value = "/update")
|
@PutMapping(value = "/update")
|
||||||
public R<Void> updateDeviceType(@Validated @RequestBody DeviceTypeForm resources) {
|
public R<Void> updateDeviceType(@Validated @ModelAttribute DeviceTypeForm resources) throws IOException {
|
||||||
deviceTypeService.update(resources);
|
deviceTypeService.update(resources);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package com.fuyuanshen.app.domain;
|
package com.fuyuanshen.equipment.domain;
|
||||||
|
|
||||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
@ -47,5 +47,18 @@ public class AppBusinessFile extends TenantEntity {
|
|||||||
*/
|
*/
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件时长
|
||||||
|
*/
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重命名
|
||||||
|
*/
|
||||||
|
private String reName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用语音播报(0-否,1-是)
|
||||||
|
*/
|
||||||
|
private Integer useStatus;
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.fuyuanshen.app.domain;
|
package com.fuyuanshen.equipment.domain;
|
||||||
|
|
||||||
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
import com.fuyuanshen.common.tenant.core.TenantEntity;
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
@ -10,32 +10,36 @@ import lombok.EqualsAndHashCode;
|
|||||||
/**
|
/**
|
||||||
* 设备维修图片对象 device_repair_images
|
* 设备维修图片对象 device_repair_images
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @date 2025-09-02
|
* @date 2025-09-02
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@TableName("device_repair_images")
|
@TableName("device_repair_images")
|
||||||
public class DeviceRepairImages extends TenantEntity {
|
public class DeviceRepairImages extends TenantEntity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 维修图片ID
|
* 维修图片ID
|
||||||
*/
|
*/
|
||||||
@TableId(value = "image_id", type = IdType.AUTO)
|
@TableId(value = "image_id", type = IdType.AUTO)
|
||||||
@TableField(insertStrategy = FieldStrategy.NEVER)
|
@TableField(insertStrategy = FieldStrategy.NEVER)
|
||||||
private Long imageId;
|
private Long imageId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 维修记录ID
|
* 维修记录ID
|
||||||
*/
|
*/
|
||||||
@Schema(title = "维修记录ID")
|
@Schema(title = "维修记录ID")
|
||||||
private Long recordId;
|
private Long recordId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图片类型(维修前/维修后)
|
* 图片类型(维修前/维修后)
|
||||||
*/
|
*/
|
||||||
@Schema(title = "图片类型(维修前/维修后)")
|
@Schema(title = "图片类型(维修前/维修后)")
|
||||||
private RepairImageType imageType;
|
private RepairImageType imageType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图片存储路径
|
* 图片存储路径
|
||||||
*/
|
*/
|
||||||
@Schema(title = "图片存储路径")
|
@Schema(title = "图片存储路径")
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,5 +85,8 @@ public class DeviceType extends TenantEntity {
|
|||||||
@Schema(title = "型号字典用于PC页面跳转")
|
@Schema(title = "型号字典用于PC页面跳转")
|
||||||
private String pcModelDictionary;
|
private String pcModelDictionary;
|
||||||
|
|
||||||
|
@Schema(title = "设备图片")
|
||||||
|
private String devicePic;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.fuyuanshen.app.domain.bo;
|
package com.fuyuanshen.equipment.domain.bo;
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.AppBusinessFile;
|
import com.fuyuanshen.equipment.domain.AppBusinessFile;
|
||||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
@ -38,7 +38,7 @@ public class AppBusinessFileBo extends BaseEntity {
|
|||||||
private Long businessId;
|
private Long businessId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件类型(1:操作说明,2:产品参数)
|
* 文件类型(1:操作说明,2:产品参数,3:语音管理)
|
||||||
*/
|
*/
|
||||||
private Long fileType;
|
private Long fileType;
|
||||||
|
|
||||||
@ -49,4 +49,13 @@ public class AppBusinessFileBo extends BaseEntity {
|
|||||||
|
|
||||||
|
|
||||||
private List<Long> ids;
|
private List<Long> ids;
|
||||||
|
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用语音播报(0-否,1-是)
|
||||||
|
*/
|
||||||
|
private Integer useStatus;
|
||||||
|
|
||||||
|
private Long createBy;
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package com.fuyuanshen.app.domain.bo;
|
package com.fuyuanshen.equipment.domain.bo;
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.AppOperationVideo;
|
import com.fuyuanshen.equipment.domain.AppOperationVideo;
|
||||||
import com.fuyuanshen.common.core.validate.EditGroup;
|
import com.fuyuanshen.common.core.validate.EditGroup;
|
||||||
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
|
||||||
import io.github.linpeilie.annotations.AutoMapper;
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package com.fuyuanshen.equipment.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定设备参数
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Hby100jForceAlarmBo {
|
||||||
|
|
||||||
|
private Long deviceId;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -54,6 +54,9 @@ public class DeviceForm {
|
|||||||
@Schema(title = "备注")
|
@Schema(title = "备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
@Schema(title = "商户号")
|
||||||
|
private Long tenant_id;
|
||||||
|
|
||||||
|
|
||||||
// 设备类型相关字段
|
// 设备类型相关字段
|
||||||
@Schema(title = "设备类型名称")
|
@Schema(title = "设备类型名称")
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.fuyuanshen.equipment.domain.form;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description: 设备类型
|
* @Description: 设备类型
|
||||||
@ -48,5 +49,10 @@ public class DeviceTypeForm {
|
|||||||
*/
|
*/
|
||||||
@Schema(title = "型号字典用于PC页面跳转")
|
@Schema(title = "型号字典用于PC页面跳转")
|
||||||
private String pcModelDictionary;
|
private String pcModelDictionary;
|
||||||
|
@Schema(title = "设备图片")
|
||||||
|
private String devicePic;
|
||||||
|
|
||||||
|
@Schema(title = "设备图片")
|
||||||
|
private MultipartFile file;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user