6 Commits

Author SHA1 Message Date
372b1a2d11 #实时消息和参数 2026-10-23 09:12:53 +08:00
e57699dbdf #更新实时消息具体字段 2026-10-20 09:04:57 +08:00
9e3ec6a1dd #修改远程遥控控制方式 将左右轮速改成线速度和角速度 2026-10-16 09:19:31 +08:00
11984316d4 #一键寻车接口预留 2026-10-14 09:08:33 +08:00
11e209bcb3 #任务下发状态推送 2026-10-13 12:57:29 +08:00
bde6b89965 #增加系统参数配置模块 2026-10-12 15:40:23 +08:00
41 changed files with 1729 additions and 719 deletions

View File

@@ -0,0 +1,53 @@
package com.maibu.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.entity.SysParam;
import com.maibu.service.SysParamService;
/**
* 系统参数管理
*
* @author ruoyi
*/
@RestController
@RequestMapping("/system/param")
public class SysParamController extends BaseController {
@Autowired
private SysParamService sysParamService;
/**
* 查询系统参数列表
*/
@GetMapping("/list")
public AjaxResult list() {
try {
return AjaxResult.success(sysParamService.list());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 新增或者修改系统参数
*/
@PostMapping("/save")
public AjaxResult save(@RequestBody List<SysParam> sysParams) {
try {
return AjaxResult.success(sysParamService.save(sysParams));
} catch (Exception e) {
return AjaxResult.error("新增修改系统参数出错", e.getMessage());
}
}
}

View File

@@ -1,3 +1,28 @@
system.param.systemName.name = 系统名称
system.param.systemName.desc = 系统名称
system.param.defaultStationName.name = 默认场站
system.param.defaultStationName.desc = "默认场站
system.param.defaultLanguage.name = 默认语言
system.param.defaultLanguage.desc = 默认语言
system.param.defaultZoneId.name = 默认时区
system.param.defaultZoneId.desc = 默认时区
system.param.daylightSavingTime.name = 夏令时
system.param.daylightSavingTime.desc = 夏令时
system.param.defaultUnit.name = 默认单位
system.param.defaultUnit.desc = 默认单位
system.param.defaultDateFormat.name = 默认日期格式
system.param.defaultDateFormat.desc = 默认日期格式
#\u9519\u8BEF\u6D88\u606F #\u9519\u8BEF\u6D88\u606F
not.null=* \u5FC5\u987B\u586B\u5199 not.null=* \u5FC5\u987B\u586B\u5199
user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF

View File

@@ -1,3 +1,32 @@
system.param.systemName.name = System Name
system.param.systemName.desc = System Name
system.param.defaultStationName.name = Default Station
system.param.defaultStationName.desc = Default Station
system.param.defaultLanguage.name = Default Language
system.param.defaultLanguage.desc = Default Language
system.param.defaultZoneId.name = Default Zone
system.param.defaultZoneId.desc = Default Zone
system.param.daylightSavingTime.name = Daylight Saving Time
system.param.daylightSavingTime.desc = Daylight Saving Time
system.param.defaultUnit.name = Default Unit
system.param.defaultUnit.desc = Default Unit
system.param.defaultDateFormat.name = Default Date Format
system.param.defaultDateFormat.desc = Default Date Format
#\u9519\u8BEF\u6D88\u606F #\u9519\u8BEF\u6D88\u606F
not.null=* \u5FC5\u987B\u586B\u5199 not.null=* \u5FC5\u987B\u586B\u5199
user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF

View File

@@ -1,3 +1,31 @@
system.param.systemName.name = 系统名称
system.param.systemName.desc = 系统名称
system.param.defaultStationName.name = 默认场站
system.param.defaultStationName.desc = "默认场站
system.param.defaultLanguage.name = 默认语言
system.param.defaultLanguage.desc = 默认语言
system.param.defaultZoneId.name = 默认时区
system.param.defaultZoneId.desc = 默认时区
system.param.daylightSavingTime.name = 夏令时
system.param.daylightSavingTime.desc = 夏令时
system.param.defaultUnit.name = 默认单位
system.param.defaultUnit.desc = 默认单位
system.param.defaultDateFormat.name = 默认日期格式
system.param.defaultDateFormat.desc = 默认日期格式
#\u9519\u8BEF\u6D88\u606F #\u9519\u8BEF\u6D88\u606F
not.null=* \u5FC5\u987B\u586B\u5199 not.null=* \u5FC5\u987B\u586B\u5199
user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF

View File

@@ -1,19 +1,19 @@
package com.maibu.constant; package com.maibu.constant;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.enums.ConnectionCloseReason;
import io.netty.util.AttributeKey;
import lombok.Data;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Data import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.enums.ConnectionCloseReason;
import io.netty.util.AttributeKey;
public class Constant { public class Constant {
public static final AttributeKey<String> ATT_DEVICE_ID = AttributeKey.valueOf("deviceId"); public static final AttributeKey<String> ATT_DEVICE_ID = AttributeKey.valueOf("deviceId");
public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY = public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY = AttributeKey
AttributeKey.valueOf("READ_CONFIG"); .valueOf("READ_CONFIG");
public static final AttributeKey<ConnectionCloseReason> ATT_CLOSE_REASON = AttributeKey.valueOf("closeReason"); public static final AttributeKey<ConnectionCloseReason> ATT_CLOSE_REASON = AttributeKey.valueOf("closeReason");
@@ -27,5 +27,10 @@ public class Constant {
public static final String mqttHandleKey = "hostHandle"; public static final String mqttHandleKey = "hostHandle";
public static final Long hostOfflineInterval = 10000L; //单位毫秒 public static final Long hostOfflineInterval = 10000L; // 单位毫秒
// ==================== 远程控制 ====================
public static final String protocol_version = "1.4.3";
public static final String remote_control_msg_prefix = "remote-msg";
public static final String remote_control_cmd_prefix = "remote-cmd";
} }

View File

@@ -1,22 +1,19 @@
package com.maibu.core.business; package com.maibu.core.business;
import java.time.LocalDate;
import java.util.List;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.maibu.annotation.Excel; import com.maibu.annotation.Excel;
import com.maibu.constant.CommandConstant;
import com.maibu.core.domain.BaseDO; import com.maibu.core.domain.BaseDO;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.List;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@TableName(value = "iot_device_run_param", autoResultMap = true) @TableName(value = "iot_device_run_param", autoResultMap = true)
@@ -25,366 +22,440 @@ public class DeviceRunParam extends BaseDO {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private Long id;
// private String deviceId; // private String deviceId;
private Long siteId; private Long siteId;
private Long orgId; private Long orgId;
private Integer runSpeed; //不下发到设备自己用 private Integer runSpeed; // 不下发到设备自己用
@Excel(name = "设备序列号", cellType = Excel.ColumnType.STRING, prompt = "设备序列号") @Excel(name = "设备序列号", cellType = Excel.ColumnType.STRING, prompt = "设备序列号")
private String deviceId;//设备序列号 private String deviceId;// 设备序列号
@Excel(name = "产品型号", cellType = Excel.ColumnType.STRING, prompt = "产品型号") @Excel(name = "产品型号", cellType = Excel.ColumnType.STRING, prompt = "产品型号")
private String productModel;//产品型号 private String productModel;// 产品型号
@Excel(name = "设备类型", cellType = Excel.ColumnType.STRING, prompt = "设备类型") @Excel(name = "设备类型", cellType = Excel.ColumnType.STRING, prompt = "设备类型")
private String deviceType;//设备类型:mower-割草机器人 private String deviceType;// 设备类型:mower-割草机器人
@Excel(name = "RTK模式", cellType = Excel.ColumnType.STRING, prompt = "RTK模式") @Excel(name = "RTK模式", cellType = Excel.ColumnType.STRING, prompt = "RTK模式")
private String rtkMode;//RTK模式:network-4G网络差分 private String rtkMode;// RTK模式:network-4G网络差分
@Excel(name = "摄像头数量", cellType = Excel.ColumnType.STRING, prompt = "摄像头数量") @Excel(name = "摄像头数量", cellType = Excel.ColumnType.STRING, prompt = "摄像头数量")
private Integer cameraNum;//摄像头数量 private Integer cameraNum;// 摄像头数量
@Excel(name = "动力类型", cellType = Excel.ColumnType.STRING, prompt = "动力类型") @Excel(name = "动力类型", cellType = Excel.ColumnType.STRING, prompt = "动力类型")
private String powerType;//动力类型:hybrid-混动 private String powerType;// 动力类型:hybrid-混动
@Excel(name = "车轮类型", cellType = Excel.ColumnType.STRING, prompt = "车轮类型") @Excel(name = "车轮类型", cellType = Excel.ColumnType.STRING, prompt = "车轮类型")
private String wheelType;//车轮类型:track-履带式 private String wheelType;// 车轮类型:track-履带式
@Excel(name = "发动机类型", cellType = Excel.ColumnType.STRING, prompt = "发动机类型") @Excel(name = "发动机类型", cellType = Excel.ColumnType.STRING, prompt = "发动机类型")
private String engineType;//发动机类型:honda-本田发动机 private String engineType;// 发动机类型:honda-本田发动机
@Excel(name = "是否搭载上位机",cellType = Excel.ColumnType.NUMERIC) @Excel(name = "是否搭载上位机", cellType = Excel.ColumnType.NUMERIC)
private Integer hasHost = 1;//是否搭载上位机 private Integer hasHost = 1;// 是否搭载上位机
@Excel(name = "设备能力列表") @Excel(name = "设备能力列表")
@TableField(exist = false) @TableField(exist = false)
private String capabilities; private String capabilities;
private String factoryCode; // 工厂码
private String lineNum;// 产线号
private LocalDate productionDate;// 生产日期
private String serialNumber;// 流水号
@Excel(name = "电池类型", cellType = Excel.ColumnType.STRING, prompt = "电池类型")
private String batteryType;// 电池类型
@Excel(name = "行走驱动类型", cellType = Excel.ColumnType.STRING, prompt = "行走驱动类型")
private String walkingDriveType;// 行走驱动类型
@Excel(name = "割刀驱动类型", cellType = Excel.ColumnType.STRING, prompt = "割刀驱动类型")
private String cutterDriveType;// 割刀驱动类型
@Excel(name = "RTK天线数", cellType = Excel.ColumnType.STRING, prompt = "RTK天线数")
private String rtkAntennasNum;// RTK天线数
@Excel(name = "手柄类型", cellType = Excel.ColumnType.STRING, prompt = "手柄类型")
private String handleType;// 手柄类型
@Excel(name = "PCB硬件版本", cellType = Excel.ColumnType.STRING, prompt = "PCB硬件版本")
private String pcbVersion;// PCB硬件版本
@Excel(name = "长宽高", cellType = Excel.ColumnType.STRING, prompt = "长宽高")
private String dimensions;// 长宽高
@Excel(name = "割刀宽度", cellType = Excel.ColumnType.STRING, prompt = "割刀宽度")
private String bladeWidth;// 割刀宽度
@Excel(name = "轮胎尺寸", cellType = Excel.ColumnType.STRING, prompt = "轮胎尺寸")
private String tyreSize;// 轮胎尺寸
@Excel(name = "转速比", cellType = Excel.ColumnType.STRING, prompt = "转速比")
private String speedRatio;// 转速比
@Excel(name = "蜂窝网络通信信息", cellType = Excel.ColumnType.STRING, prompt = "蜂窝网络通信信息")
private String cellularInfo;// 蜂窝网络通信信息
@Excel(name = "wifi名称", cellType = Excel.ColumnType.STRING, prompt = "wifi名称")
private String wifiName;// wifi名称
@Excel(name = "蓝牙广播名", cellType = Excel.ColumnType.STRING, prompt = "蓝牙广播名")
private String bluetoothName;// 蓝牙广播名
@Excel(name = "硬件标识信息", cellType = Excel.ColumnType.STRING, prompt = "硬件标识信息")
private String hardwareIdentifiers;// 硬件标识信息
@Excel(name = "IMU型号", cellType = Excel.ColumnType.STRING, prompt = "IMU型号")
private String imuModel;// IMU型号
@Excel(name = "温湿度传感器", cellType = Excel.ColumnType.STRING, prompt = "温湿度传感器")
private String tempHumiditySensor;// 温湿度传感器
@Excel(name = "气压计在位", cellType = Excel.ColumnType.STRING, prompt = "气压计在位")
private String barometerPresent;// 气压计在位
@Excel(name = "超声波在位", cellType = Excel.ColumnType.STRING, prompt = "超声波在位")
private String ultrasonicPresent;// 超声波在位
@Excel(name = "DAC在位", cellType = Excel.ColumnType.STRING, prompt = "DAC在位")
private String dacPresent;// DAC在位
@Excel(name = "质检员", cellType = Excel.ColumnType.STRING, prompt = "质检员")
private String operator;// 质检员
@Excel(name = "检测报告号", cellType = Excel.ColumnType.STRING, prompt = "检测报告号")
private String inspectionNo;// 检测报告号
@Excel(name = "固件版本", cellType = Excel.ColumnType.STRING, prompt = "固件版本")
private String firmwareVersion;// 固件版本
@Excel(name = "经销商", cellType = Excel.ColumnType.STRING, prompt = "经销商")
private String dealer;// DAC在位
@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = JacksonTypeHandler.class)
private List<String> capabilityList;//设备能力列表:heartbeat-上报心跳/location-上报位置/vehicle_status-上报整机状态/task_control-任务控制/single_point-单点作业/coverage-全覆盖割草作业/path_upload-作业路径上传 private List<String> capabilityList;// 设备能力列表:heartbeat-上报心跳/location-上报位置/vehicle_status-上报整机状态/task_control-任务控制/single_point-单点作业/coverage-全覆盖割草作业/path_upload-作业路径上传
// @TableField(exist = false)
// public byte header1;
// @TableField(exist = false)
// public byte header2;
// @TableField(exist = false)
// public byte cmd;
// public byte chipUidSign;// 芯片UID固化标志位
// public String chipUid;// 芯片UID
// public byte[] remoteConfig;// 遥控器通道配置
// public int knifeMotorMode;// 割刀电机模式
// public int walkMotorMode;// 行走电机模式
// public int leftMotorReverse;// 左轮电机方向极性
// public int rightMotorReverse;// 右轮电机方向极性
// public int swapChannel;// 左右轮通道互换标志位
// public int use4G;// 联网标志位
// public short forwardSpeedLimit;// 前进速度限制
// public short turnSpeedLimit;// 转向速度限制
// public int knifePolarity;// 割刀通道极性
// public int fanPolarity;// 风门通道极性
// public int throttlePolarity;// 油门通道极性
// public int liftProtectTime;// 底盘升降电机保护时间
// public int dualRtk;// RTK配置
// public int knifeChannel;// 割刀通道配置
// public int fanChannel;// 风门通道配置
// public int throttleChannel;// 油门通道配置
// public int remoteType;// 遥控器类型
// public boolean relayBoard;// 是否搭载继电器板
// public int liftChannel;// 底盘升通道配置
// public int chassisChannel;// 底盘降通道配置
// public int armChannel;// 抱闸通道配置
// public int fuelPumpChannel;// 燃油励磁通道配置
// public String wifiName;// wifi名称
// public String wifiPassword;// wifi密码
// public int batteryType;// 电池类型
// public int driveType;// 行走驱动配置
// public float gearRatio;// 转速比
// public float robotLength;// 机器人长度
// public float robotWidth;// 机器人宽度
// public float robotHeight;// 机器人高度
// public float knifeWidth;// 割刀宽度
// public float tyreSize;// 轮胎尺寸
// public float leftForwardGain;// 左轮前进增益
// public float leftBackwardGain;// 左轮后退增益
// public float rightForwardGain;// 右轮前进增益
// public float rightBackwardGain;// 右轮后退增益
// public String firmwareVersion;// 固件版本
// @TableField(exist = false)
// public int crc16;
// @TableField(exist = false)
// public byte tail1;
// @TableField(exist = false)
// public byte tail2;
// @TableField(exist = false)
// private byte[] originalData;
// public static byte[] toReadBytes() {
// ByteBuffer buffer = ByteBuffer.allocate(7); // 修改为27字节
// buffer.order(ByteOrder.LITTLE_ENDIAN);
// buffer.put((byte) 0xAB);
// buffer.put((byte) 0xAA);
// buffer.put(CommandConstant.readConfig);
// buffer.putShort((short) 0);
// buffer.put((byte) 0xAA);
// buffer.put((byte) 0xAB);
// return buffer.array();
// }
// public byte[] toWriteBytes() {
// // 如果没有原始数据,使用静态方法重新构建
// if (originalData == null || originalData.length < 178) {
// return null;
// }
// // 克隆原始数据,避免修改原始数据
// byte[] result = originalData.clone();
// ByteBuffer buffer = ByteBuffer.wrap(result);
// buffer.order(ByteOrder.LITTLE_ENDIAN);
// // 修改指令为写配置(字节2)
// buffer.put(2, CommandConstant.writeConfig);
// // 修改字节68:遥控器配置
// byte remote = 0;
// remote |= (getKnifeMotorMode() & 0x03);
// remote |= (getWalkMotorMode() & 0x03) << 2;
// remote |= (getLeftMotorReverse() & 0x01) << 4;
// remote |= (getRightMotorReverse() & 0x01) << 5;
// remote |= (getSwapChannel() & 0x01) << 6;
// remote |= (getUse4G() & 0x01) << 7;
// buffer.put(68, remote);
// // 修改字节69-72:速度限制
// buffer.putShort(69, getForwardSpeedLimit());
// buffer.putShort(71, getTurnSpeedLimit());
// // 修改字节73:通道极性
// byte b73 = 0;
// b73 |= (getKnifePolarity() & 1);
// b73 |= (getFanPolarity() & 1) << 1;
// b73 |= (getThrottlePolarity() & 1) << 2;
// b73 |= (getLiftProtectTime() & 0x0F) << 3;
// b73 |= (getDualRtk() & 1) << 7;
// buffer.put(73, b73);
// // 修改字节74-77:通道配置
// byte b74 = 0;
// b74 |= (getKnifeChannel() & 0x0F);
// b74 |= (getFanChannel() & 0x0F) << 4;
// buffer.put(74, b74);
// byte b75 = 0;
// b75 |= (getThrottleChannel() & 0x0F);
// b75 |= (getRemoteType() & 0x07) << 4;
// if (isRelayBoard())
// b75 |= 1 << 7;
// buffer.put(75, b75);
// byte b76 = 0;
// b76 |= (getLiftChannel() & 0x0F);
// b76 |= (getChassisChannel() & 0x0F) << 4;
// buffer.put(76, b76);
// byte b77 = 0;
// b77 |= (getArmChannel() & 0x0F);
// b77 |= (getFuelPumpChannel() & 0x0F) << 4;
// buffer.put(77, b77);
// // // 修改字节78-117:WiFi信息
// // byte[] wifiNameBytes = new byte[20];
// // if (getWifiName() != null) {
// // byte[] src = getWifiName().getBytes(StandardCharsets.UTF_8);
// // System.arraycopy(src, 0, wifiNameBytes, 0, Math.min(src.length, 20));
// // }
// // System.arraycopy(wifiNameBytes, 0, result, 78, 20);
// //
// // byte[] wifiPwdBytes = new byte[20];
// // if (getWifiPassword() != null) {
// // byte[] src = getWifiPassword().getBytes(StandardCharsets.UTF_8);
// // System.arraycopy(src, 0, wifiPwdBytes, 0, Math.min(src.length, 20));
// // }
// // System.arraycopy(wifiPwdBytes, 0, result, 98, 20);
// // // 修改字节118:电池和驱动配置
// // byte b118 = 0;
// // b118 |= (getBatteryType() & 0x03);
// // b118 |= (getDriveType() & 0x03) << 2;
// // buffer.put(118, b118);
// // 修改字节119-158:float参数
// buffer.putFloat(119, getGearRatio());
// buffer.putFloat(123, getRobotLength());
// buffer.putFloat(127, getRobotWidth());
// buffer.putFloat(131, getRobotHeight());
// buffer.putFloat(135, getKnifeWidth());
// buffer.putFloat(139, getTyreSize());
// buffer.putFloat(143, getLeftForwardGain());
// buffer.putFloat(147, getLeftBackwardGain());
// buffer.putFloat(151, getRightForwardGain());
// buffer.putFloat(155, getRightBackwardGain());
// // 修改字节159-173:固件版本
// // byte[] fwBytes = new byte[15];
// // if (getFirmwareVersion() != null) {
// // byte[] src = getFirmwareVersion().getBytes(StandardCharsets.UTF_8);
// // System.arraycopy(src, 0, fwBytes, 0, Math.min(src.length, 15));
// // }
// // System.arraycopy(fwBytes, 0, result, 159, 15);
// // 保留原始的 CRC 和尾部,不强制修改
// // 移除以下强制修改:
// // buffer.putShort(174, (short) 0);
// // buffer.put(176, (byte) 0xAA);
// // buffer.put(177, (byte) 0xAB);
// return result;
// }
// public static void putFixedString(ByteBuffer buffer, String value, int len) {
// byte[] bytes = new byte[len];
// if (value != null) {
// byte[] src = value.getBytes(StandardCharsets.UTF_8);
// System.arraycopy(src, 0, bytes, 0, Math.min(src.length, len));
// }
// buffer.put(bytes);
// }
// public static DeviceRunParam fromBytes(byte[] data) {
// // 183
// if (data == null || data.length < 178) {
// throw new IllegalArgumentException("数据长度不足");
// }
// ByteBuffer buffer = ByteBuffer.wrap(data);
// buffer.order(ByteOrder.LITTLE_ENDIAN);
// DeviceRunParam p = new DeviceRunParam();
// p.setOriginalData(data);
@TableField(exist = false) // p.setHeader1(buffer.get());
public byte header1; // p.setHeader2(buffer.get());
@TableField(exist = false)
public byte header2;
@TableField(exist = false)
public byte cmd;
public byte chipUidSign;//芯片UID固化标志位
public String chipUid;//芯片UID
public byte[] remoteConfig;//遥控器通道配置
public int knifeMotorMode;//割刀电机模式
public int walkMotorMode;//行走电机模式
public int leftMotorReverse;//左轮电机方向极性
public int rightMotorReverse;//右轮电机方向极性
public int swapChannel;//左右轮通道互换标志位
public int use4G;//联网标志位
public short forwardSpeedLimit;//前进速度限制
public short turnSpeedLimit;//转向速度限制
public int knifePolarity;//割刀通道极性
public int fanPolarity;//风门通道极性
public int throttlePolarity;//油门通道极性
public int liftProtectTime;//底盘升降电机保护时间
public int dualRtk;//RTK配置
public int knifeChannel;//割刀通道配置
public int fanChannel;//风门通道配置
public int throttleChannel;//油门通道配置
public int remoteType;//遥控器类型
public boolean relayBoard;//是否搭载继电器板
public int liftChannel;//底盘升通道配置
public int chassisChannel;//底盘降通道配置
public int armChannel;//抱闸通道配置
public int fuelPumpChannel;//燃油励磁通道配置
public String wifiName;//wifi名称
public String wifiPassword;//wifi密码
public int batteryType;//电池类型
public int driveType;//行走驱动配置
public float gearRatio;//转速比
public float robotLength;//机器人长度
public float robotWidth;//机器人宽度
public float robotHeight;//机器人高度
public float knifeWidth;//割刀宽度
public float tyreSize;//轮胎尺寸
public float leftForwardGain;//左轮前进增益
public float leftBackwardGain;//左轮后退增益
public float rightForwardGain;//右轮前进增益
public float rightBackwardGain;//右轮后退增益
public String firmwareVersion;//固件版本
@TableField(exist = false)
public int crc16;
@TableField(exist = false)
public byte tail1;
@TableField(exist = false)
public byte tail2;
@TableField(exist = false)
private byte[] originalData;
public static byte[] toReadBytes() {
ByteBuffer buffer = ByteBuffer.allocate(7); // 修改为27字节
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put((byte) 0xAB);
buffer.put((byte) 0xAA);
buffer.put(CommandConstant.readConfig);
buffer.putShort((short) 0);
buffer.put((byte) 0xAA);
buffer.put((byte) 0xAB);
return buffer.array();
}
public byte[] toWriteBytes() {
// 如果没有原始数据,使用静态方法重新构建
if (originalData == null || originalData.length < 178) {
return null;
}
// 克隆原始数据,避免修改原始数据
byte[] result = originalData.clone();
ByteBuffer buffer = ByteBuffer.wrap(result);
buffer.order(ByteOrder.LITTLE_ENDIAN);
// 修改指令为写配置(字节2)
buffer.put(2, CommandConstant.writeConfig);
// 修改字节68:遥控器配置
byte remote = 0;
remote |= (getKnifeMotorMode() & 0x03);
remote |= (getWalkMotorMode() & 0x03) << 2;
remote |= (getLeftMotorReverse() & 0x01) << 4;
remote |= (getRightMotorReverse() & 0x01) << 5;
remote |= (getSwapChannel() & 0x01) << 6;
remote |= (getUse4G() & 0x01) << 7;
buffer.put(68, remote);
// 修改字节69-72:速度限制
buffer.putShort(69, getForwardSpeedLimit());
buffer.putShort(71, getTurnSpeedLimit());
// 修改字节73:通道极性
byte b73 = 0;
b73 |= (getKnifePolarity() & 1);
b73 |= (getFanPolarity() & 1) << 1;
b73 |= (getThrottlePolarity() & 1) << 2;
b73 |= (getLiftProtectTime() & 0x0F) << 3;
b73 |= (getDualRtk() & 1) << 7;
buffer.put(73, b73);
// 修改字节74-77:通道配置
byte b74 = 0;
b74 |= (getKnifeChannel() & 0x0F);
b74 |= (getFanChannel() & 0x0F) << 4;
buffer.put(74, b74);
byte b75 = 0;
b75 |= (getThrottleChannel() & 0x0F);
b75 |= (getRemoteType() & 0x07) << 4;
if (isRelayBoard()) b75 |= 1 << 7;
buffer.put(75, b75);
byte b76 = 0;
b76 |= (getLiftChannel() & 0x0F);
b76 |= (getChassisChannel() & 0x0F) << 4;
buffer.put(76, b76);
byte b77 = 0;
b77 |= (getArmChannel() & 0x0F);
b77 |= (getFuelPumpChannel() & 0x0F) << 4;
buffer.put(77, b77);
// // 修改字节78-117:WiFi信息
// byte[] wifiNameBytes = new byte[20];
// if (getWifiName() != null) {
// byte[] src = getWifiName().getBytes(StandardCharsets.UTF_8);
// System.arraycopy(src, 0, wifiNameBytes, 0, Math.min(src.length, 20));
// }
// System.arraycopy(wifiNameBytes, 0, result, 78, 20);
//
// byte[] wifiPwdBytes = new byte[20];
// if (getWifiPassword() != null) {
// byte[] src = getWifiPassword().getBytes(StandardCharsets.UTF_8);
// System.arraycopy(src, 0, wifiPwdBytes, 0, Math.min(src.length, 20));
// }
// System.arraycopy(wifiPwdBytes, 0, result, 98, 20);
// // 修改字节118:电池和驱动配置
// byte b118 = 0;
// b118 |= (getBatteryType() & 0x03);
// b118 |= (getDriveType() & 0x03) << 2;
// buffer.put(118, b118);
// 修改字节119-158:float参数
buffer.putFloat(119, getGearRatio());
buffer.putFloat(123, getRobotLength());
buffer.putFloat(127, getRobotWidth());
buffer.putFloat(131, getRobotHeight());
buffer.putFloat(135, getKnifeWidth());
buffer.putFloat(139, getTyreSize());
buffer.putFloat(143, getLeftForwardGain());
buffer.putFloat(147, getLeftBackwardGain());
buffer.putFloat(151, getRightForwardGain());
buffer.putFloat(155, getRightBackwardGain());
// 修改字节159-173:固件版本
// byte[] fwBytes = new byte[15];
// if (getFirmwareVersion() != null) {
// byte[] src = getFirmwareVersion().getBytes(StandardCharsets.UTF_8);
// System.arraycopy(src, 0, fwBytes, 0, Math.min(src.length, 15));
// }
// System.arraycopy(fwBytes, 0, result, 159, 15);
// 保留原始的 CRC 和尾部,不强制修改
// 移除以下强制修改:
// buffer.putShort(174, (short) 0);
// buffer.put(176, (byte) 0xAA);
// buffer.put(177, (byte) 0xAB);
return result;
}
public static void putFixedString(ByteBuffer buffer, String value, int len) {
byte[] bytes = new byte[len];
if (value != null) {
byte[] src = value.getBytes(StandardCharsets.UTF_8);
System.arraycopy(src, 0, bytes, 0, Math.min(src.length, len));
}
buffer.put(bytes);
}
public static DeviceRunParam fromBytes(byte[] data) {
// 183
if (data == null || data.length < 178) {
throw new IllegalArgumentException("数据长度不足");
}
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.order(ByteOrder.LITTLE_ENDIAN);
DeviceRunParam p = new DeviceRunParam();
p.setOriginalData(data); // p.setCmd(buffer.get());
p.setHeader1(buffer.get()); // p.setChipUidSign(buffer.get());
p.setHeader2(buffer.get());
p.setCmd(buffer.get()); // p.setChipUid(readString(buffer, 45));
p.setChipUidSign(buffer.get()); // // 跳过字节49-67(共19字节,预留不用)
// buffer.position(buffer.position() + 19);
p.setChipUid(readString(buffer, 45)); // byte remote = buffer.get();
// 跳过字节49-67(共19字节,预留不用) // // p.setRemoteConfig(remote);
buffer.position(buffer.position() + 19);
byte remote = buffer.get(); // p.setKnifeMotorMode(remote & 0x03);
// p.setWalkMotorMode((remote >> 2) & 0x03);
// p.setLeftMotorReverse((remote >> 4) & 0x01);
// p.setRightMotorReverse((remote >> 5) & 0x01);
// p.setSwapChannel((remote >> 6) & 0x01);
// p.setUse4G((remote >> 7) & 0x01);
// p.setRemoteConfig(remote); // p.setForwardSpeedLimit(buffer.getShort());
// p.setTurnSpeedLimit(buffer.getShort());
p.setKnifeMotorMode(remote & 0x03); // byte b73 = buffer.get();
p.setWalkMotorMode((remote >> 2) & 0x03);
p.setLeftMotorReverse((remote >> 4) & 0x01);
p.setRightMotorReverse((remote >> 5) & 0x01);
p.setSwapChannel((remote >> 6) & 0x01);
p.setUse4G((remote >> 7) & 0x01);
p.setForwardSpeedLimit(buffer.getShort()); // p.setKnifePolarity(b73 & 1);
p.setTurnSpeedLimit(buffer.getShort()); // p.setFanPolarity((b73 >> 1) & 1);
// p.setThrottlePolarity((b73 >> 2) & 1);
// p.setLiftProtectTime((b73 >> 3) & 0x0F);
// p.setDualRtk((b73 >> 7) & 1);
byte b73 = buffer.get(); // byte b74 = buffer.get();
p.setKnifePolarity(b73 & 1); // p.setKnifeChannel(b74 & 0x0F);
p.setFanPolarity((b73 >> 1) & 1); // p.setFanChannel((b74 >> 4) & 0x0F);
p.setThrottlePolarity((b73 >> 2) & 1);
p.setLiftProtectTime((b73 >> 3) & 0x0F);
p.setDualRtk((b73 >> 7) & 1);
byte b74 = buffer.get(); // byte b75 = buffer.get();
p.setKnifeChannel(b74 & 0x0F); // p.setThrottleChannel(b75 & 0x0F);
p.setFanChannel((b74 >> 4) & 0x0F); // p.setRemoteType((b75 >> 4) & 0x07);
// p.setRelayBoard(((b75 >> 7) & 1) == 1);
byte b75 = buffer.get(); // byte b76 = buffer.get();
p.setThrottleChannel(b75 & 0x0F); // p.setLiftChannel(b76 & 0x0F);
p.setRemoteType((b75 >> 4) & 0x07); // p.setChassisChannel((b76 >> 4) & 0x0F);
p.setRelayBoard(((b75 >> 7) & 1) == 1);
byte b76 = buffer.get(); // byte b77 = buffer.get();
p.setLiftChannel(b76 & 0x0F); // p.setArmChannel(b77 & 0x0F);
p.setChassisChannel((b76 >> 4) & 0x0F); // p.setFuelPumpChannel((b77 >> 4) & 0x0F);
byte b77 = buffer.get(); // p.setWifiName(readString(buffer, 20));
// p.setWifiPassword(readString(buffer, 20));
p.setArmChannel(b77 & 0x0F); // byte b118 = buffer.get();
p.setFuelPumpChannel((b77 >> 4) & 0x0F);
p.setWifiName(readString(buffer, 20)); // p.setBatteryType(b118 & 0x03);
p.setWifiPassword(readString(buffer, 20)); // p.setDriveType((b118 >> 2) & 0x03);
byte b118 = buffer.get(); // // float
// p.setGearRatio(buffer.getFloat());
// p.setRobotLength(buffer.getFloat());
// p.setRobotWidth(buffer.getFloat());
// p.setRobotHeight(buffer.getFloat());
// p.setKnifeWidth(buffer.getFloat());
// p.setTyreSize(buffer.getFloat());
// p.setLeftForwardGain(buffer.getFloat());
// p.setLeftBackwardGain(buffer.getFloat());
// p.setRightForwardGain(buffer.getFloat());
// p.setRightBackwardGain(buffer.getFloat());
p.setBatteryType(b118 & 0x03); // p.setFirmwareVersion(readString(buffer, 15));
p.setDriveType((b118 >> 2) & 0x03);
// float // p.setCrc16(Short.toUnsignedInt(buffer.getShort()));
p.setGearRatio(buffer.getFloat());
p.setRobotLength(buffer.getFloat());
p.setRobotWidth(buffer.getFloat());
p.setRobotHeight(buffer.getFloat());
p.setKnifeWidth(buffer.getFloat());
p.setTyreSize(buffer.getFloat());
p.setLeftForwardGain(buffer.getFloat());
p.setLeftBackwardGain(buffer.getFloat());
p.setRightForwardGain(buffer.getFloat());
p.setRightBackwardGain(buffer.getFloat());
p.setFirmwareVersion(readString(buffer, 15)); // p.setTail1(buffer.get());
// p.setTail2(buffer.get());
p.setCrc16(Short.toUnsignedInt(buffer.getShort())); // return p;
// }
p.setTail1(buffer.get()); // public static String readString(ByteBuffer buffer, int len) {
p.setTail2(buffer.get()); // byte[] bytes = new byte[len];
// buffer.get(bytes);
return p; // int end = 0;
} // while (end < bytes.length && bytes[end] != 0) {
// end++;
// }
public static String readString(ByteBuffer buffer, int len) { // return new String(bytes, 0, end, StandardCharsets.UTF_8);
byte[] bytes = new byte[len]; // }
buffer.get(bytes);
int end = 0;
while (end < bytes.length && bytes[end] != 0) {
end++;
}
return new String(bytes, 0, end, StandardCharsets.UTF_8);
}
} }

View File

@@ -1,4 +1,4 @@
package com.maibu.dto; package com.maibu.core.business;
import lombok.Data; import lombok.Data;
@@ -42,13 +42,13 @@ public class LawnMoverProtocolEntity {
} }
public byte[] toBytes() { public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(15); ByteBuffer buffer = ByteBuffer.allocate(27);
buffer.order(ByteOrder.LITTLE_ENDIAN); // 根据协议决定字节序 buffer.order(ByteOrder.LITTLE_ENDIAN); // 根据协议决定字节序
buffer.put(Header1); buffer.put(Header1);
buffer.put(Header2); buffer.put(Header2);
buffer.put(CommandType); buffer.put(CommandType);
buffer.putShort(LeftWheelSpeed); buffer.putDouble(linearSpeed);
buffer.putShort(RightWheelSpeed); buffer.putDouble(angularSpeed);
buffer.put(ChassisLiftFlag); buffer.put(ChassisLiftFlag);
buffer.put(MowerSpeedFlag); buffer.put(MowerSpeedFlag);
buffer.put(IgnitionFlag); buffer.put(IgnitionFlag);
@@ -67,7 +67,46 @@ public class LawnMoverProtocolEntity {
return sb.toString().trim(); return sb.toString().trim();
} }
/**
* 将控制指令字节数组解析为实体对象
*/
public static LawnMoverProtocolEntity parseControlCommand(byte[] data) {
if (data == null || data.length != 27) {
throw new IllegalArgumentException("控制指令长度必须为15字节");
}
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.order(ByteOrder.LITTLE_ENDIAN);
LawnMoverProtocolEntity entity = new LawnMoverProtocolEntity();
// 帧头
entity.setHeader1(buffer.get());
entity.setHeader2(buffer.get());
// 命令类型
entity.setCommandType(buffer.get());
// 左右轮速度:int16
entity.setLinearSpeed(buffer.getDouble());
entity.setAngularSpeed(buffer.getDouble());
// 控制标志:uint8
entity.setChassisLiftFlag(buffer.get());
entity.setMowerSpeedFlag(buffer.get());
entity.setIgnitionFlag(buffer.get());
entity.setEmergencyStopFlag(buffer.get());
// 预留字段
buffer.get();
buffer.get();
// 帧尾
entity.setEndFlag1(buffer.get());
entity.setEndFlag2(buffer.get());
return entity;
}
// 包头起始字节1 // 包头起始字节1
private byte Header1; private byte Header1;
@@ -79,6 +118,10 @@ public class LawnMoverProtocolEntity {
private short LeftWheelSpeed; private short LeftWheelSpeed;
// 右轮速度:16位有符号 // 右轮速度:16位有符号
private short RightWheelSpeed; private short RightWheelSpeed;
private double linearSpeed;
private double angularSpeed;
// 底盘升降标志位 // 底盘升降标志位
private byte ChassisLiftFlag; private byte ChassisLiftFlag;
// 割刀速度标志位 // 割刀速度标志位

View File

@@ -1,6 +1,7 @@
package com.maibu.core.business.device; package com.maibu.core.business.device;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.maibu.constant.Constant;
import com.maibu.core.business.*; import com.maibu.core.business.*;
import com.maibu.core.business.path.LatAndLngEntity; import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.business.path.RoutePlanSendEntity; import com.maibu.core.business.path.RoutePlanSendEntity;
@@ -136,7 +137,6 @@ public class NettyDevice extends Connector {
return finishId; return finishId;
} }
public synchronized boolean cancelingTask() throws MqttException { public synchronized boolean cancelingTask() throws MqttException {
if (task != null) { if (task != null) {
WorkRecord workRecord = workRecordMapper.selectById(task.getRouteId()); WorkRecord workRecord = workRecordMapper.selectById(task.getRouteId());
@@ -149,7 +149,7 @@ public class NettyDevice extends Connector {
dto.setMode(workRecord.getMode()); dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis()); dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis()); dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version("1.4"); dto.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()), String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
@@ -214,7 +214,7 @@ public class NettyDevice extends Connector {
// 配置左右轮增益系数 // 配置左右轮增益系数
public void sendWheelGainCoefficientsCommand(double leftForwardGain, double leftBackwardGain, public void sendWheelGainCoefficientsCommand(double leftForwardGain, double leftBackwardGain,
double rightForwardGain, double rightBackwardGain) { double rightForwardGain, double rightBackwardGain) {
ByteBuffer buffer = ByteBuffer.allocate(39); ByteBuffer buffer = ByteBuffer.allocate(39);
buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -246,24 +246,24 @@ public class NettyDevice extends Connector {
} }
} }
public void readConfigCommand() { // public void readConfigCommand() {
byte[] bytes = DeviceRunParam.toReadBytes(); // byte[] bytes = DeviceRunParam.toReadBytes();
log.debug("下发读取配置的报文:{}", toHexString(bytes)); // log.debug("下发读取配置的报文:{}", toHexString(bytes));
if (this.getChannel() != null && this.getChannel().isActive()) { // if (this.getChannel() != null && this.getChannel().isActive()) {
this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes)); // this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
} // }
log.debug("下发读取配置的报文完成:{}", toHexString(bytes)); // log.debug("下发读取配置的报文完成:{}", toHexString(bytes));
} // }
public void writeConfigCommand(DeviceRunParam deviceRunParam) { // public void writeConfigCommand(DeviceRunParam deviceRunParam) {
log.debug("下发修改配置的属性:{}", JsonUtils.toJsonString(deviceRunParam)); // log.debug("下发修改配置的属性:{}", JsonUtils.toJsonString(deviceRunParam));
byte[] bytes = deviceRunParam.toWriteBytes(); // byte[] bytes = deviceRunParam.toWriteBytes();
log.debug("下发修改配置的报文:{}", toHexString(bytes)); // log.debug("下发修改配置的报文:{}", toHexString(bytes));
if (this.getChannel() != null && this.getChannel().isActive()) { // if (this.getChannel() != null && this.getChannel().isActive()) {
this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes)); // this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
} // }
log.debug("下发修改配置的报文完成:{}", toHexString(bytes)); // log.debug("下发修改配置的报文完成:{}", toHexString(bytes));
} // }
// todo 优化 // todo 优化
public synchronized boolean pauseTask() { public synchronized boolean pauseTask() {
@@ -294,7 +294,6 @@ public class NettyDevice extends Connector {
} }
} }
public void startTask() { public void startTask() {
try { try {
if (executingTask) if (executingTask)
@@ -363,7 +362,7 @@ public class NettyDevice extends Connector {
dto.setMode(workRecord.getMode()); dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis()); dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis()); dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version("1.4"); dto.setProtocol_version(Constant.protocol_version);
PointEntity point = new PointEntity(); PointEntity point = new PointEntity();
if (!StringUtils.isEmpty(workRecord.getMode())) { if (!StringUtils.isEmpty(workRecord.getMode())) {
@@ -414,8 +413,19 @@ public class NettyDevice extends Connector {
GlobalMemory.customMqttDeviceMonitor.publish( GlobalMemory.customMqttDeviceMonitor.publish(
mqttClientId, mqttClientId,
String.format(MqttTopic.MOWER_OTA_UPGRADE_SET, deviceId), String.format(MqttTopic.MOWER_OTA_UPGRADE_SET, deviceId),
JsonUtils.toJsonString(payload) JsonUtils.toJsonString(payload));
); }
public void searchDevice(String deviceId) throws MqttException {
Map<String, Object> payload = new HashMap<>();
payload.put("action", "search_device");
payload.put("timestamp", System.currentTimeMillis());
payload.put("message_id", "search_device_" + System.currentTimeMillis());
GlobalMemory.customMqttDeviceMonitor.publish(
mqttClientId,
String.format(MqttTopic.MOWER_SEARCH_DEVICE_SET, deviceId),
JsonUtils.toJsonString(payload));
} }
} }

View File

@@ -7,12 +7,14 @@ public class DeviceMapPushDTO {
private String id; private String id;
private double lat; private double lat;
private double lng; private double lng;
private double y; //yaw private double y; // yaw
private String f; //fix_status private String f; // fix_status
private double a; //altitude private double a; // altitude
private String s;//status 运行状态 private String s;// status 运行状态
private Long t; //taskId 任务id private Long t; // taskId 任务id
private double b; //电量 private double b; // 电量
private boolean ha = false;//hasAlarm 有无告警 private boolean ha = false;// hasAlarm 有无告警
private String cm;// 控制模式 manual_remote|auto
} }

View File

@@ -1,4 +1,4 @@
package com.maibu.dto; package com.maibu.core.business.dto;
import com.maibu.core.enums.MesType; import com.maibu.core.enums.MesType;
@@ -12,4 +12,6 @@ public class WebOlineStatusMessageDTO {
private String errorCode; private String errorCode;
private String description; private String description;
private MesType type; private MesType type;
private Long time;
} }

View File

@@ -0,0 +1,40 @@
package com.maibu.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.maibu.core.domain.OrgNoUserDO;
import com.maibu.core.enums.SysParamType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "sys_param")
public class SysParam extends OrgNoUserDO {
@TableId(type = IdType.AUTO)
private Long id;
private SysParamType paramType;
private String paramKey;
private String nameTranslateKey;
private String paramValue;
private String descTranslateKey;
@TableField(exist = false)
private String nameTranslate;
@TableField(exist = false)
private String descTranslate;
private String valueRange;
private String dataType;
}

View File

@@ -1,27 +1,26 @@
package com.maibu.core.enums; package com.maibu.core.enums;
import com.maibu.annotation.Excel; import lombok.AllArgsConstructor;
import lombok.AllArgsConstructor; import lombok.Getter;
import lombok.Getter;
@Getter
@Getter @AllArgsConstructor
@AllArgsConstructor public enum AlarmType {
public enum AlarmType {
UAV_FAULT("UAV_FAULT", "无人机故障"),
UAV_FAULT("UAV_FAULT", "无人机故障"),
MOWER_FAULT("MOWER_FAULT", "割草机故障"),
MOWER_FAULT("MOWER_FAULT", "割草机故障"),
OTHER_DEVICE_FAULT("OTHER_DEVICE_FAULT", "其他设备故障"),
OTHER_DEVICE_FAULT("OTHER_DEVICE_FAULT", "其他设备故障"),
SERVER_FAILURE("SERVER_FAILURE", "服务器故障"),
SERVER_FAILURE("SERVER_FAILURE", "服务器故障"),
SYSTEM_ERROR("SYSTEM_ERROR", "系统错误");
SYSTEM_ERROR("SYSTEM_ERROR", "系统错误");
/** 错误来源值(存储在数据库中) */
/** 错误来源值(存储在数据库中) */ private final String value;
private final String value;
/** 错误来源名称(用于前端显示) */
/** 错误来源名称(用于前端显示) */ private final String name;
private final String name;
}
}

View File

@@ -0,0 +1,22 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum SysParamType {
site("site", "场站维度"),
org("org", "组织维度"),
global("global", "全局维度"),
personal("personal", "个人维度");
private final String value;
private final String name;
}

View File

@@ -0,0 +1,15 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 上位机远程控制参数
* DeviceRemoteControlDTO
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class DeviceRemoteControlDTO extends HostBase {
private String command_id;
private ParamDetail data;
}

View File

@@ -0,0 +1,18 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class ParamDetail {
// private short left_wheel_rpm; // 左轮转速
// private short right_wheel_rpm; // 右轮转速
private double linear_x; // 线速度
private double angular_z; // 角速度
private int chassis_lift; // 底盘升降 0:停止 1:升 2:降
private int cutter; // 割刀加减速 0:停止 1:加速 2:减速
private int ignition; // 点火熄火 0:停止 1:点火 2:熄火
private int emergency_stop; // 急停 0:正常 1:急停
private int valid_for_ms; // 指令有效时间,单位毫秒
}

View File

@@ -5,12 +5,33 @@ import lombok.Data;
@Data @Data
public class VehicleMessage { public class VehicleMessage {
private double speed; private double battery_percentage;// 实时电量百分比
private double battery_percentage;// 电量 private double battery_voltage;// 实时电压
private double battery_voltage;// 电压
private String motion;// moving|stopped|blocked
private boolean emergency_stop; // 急停状态
private double distance; // 里程数 private double left_motor_current;// 实时左电机电流
private double right_motor_current;// 实时右电机电流
private double left_motor_temperature;// 实时左电机温度
private double right_motor_temperature;// 实时右电机温度
private double main_temperature;// 实时主温度
private double yaw;// 实时航向角度
private double pitch;// 实时俯仰角度
private String heading_status;// 实时航向状态
private double total_work_area;// 累计作业面积
private double total_work_duration;// 累计作业时长
private double total_work_distance;// 累计作业里程
private String motion;// moving|stopped|blocked 运动状态
private Boolean emergency_stop; // 急停状态
private double left_target_rpm; // 实时左电机目标转速
private double right_target_rpm;// 实时右电机目标转速
private double left_measured_rpm;// 实时左电机测量转速
private double right_measured_rpm;// 实时右电机测量转速
private double left_motor_rpm;// 实时左电机转速
private double right_motor_rpm;// 实时右电机转速
private double roll;// 实时翻滚角度
private String control_mode;// 遥控器拨杆对应的当前控制模式
private double linear_speed; // 实时线速度
private double angular_speed; // 实时角速度
} }

View File

@@ -16,6 +16,7 @@ import org.springframework.util.CollectionUtils;
import com.maibu.core.domain.entity.SysSite; import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.enums.ErrorSource; import com.maibu.core.enums.ErrorSource;
import com.maibu.core.host.VehicleMessage;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -59,6 +60,20 @@ public class SiteMemory {
public static ConcurrentHashMap<String, DeviceMapPushDTO> deviceMapPushMap = new ConcurrentHashMap<>(); public static ConcurrentHashMap<String, DeviceMapPushDTO> deviceMapPushMap = new ConcurrentHashMap<>();
public static ConcurrentHashMap<String, VehicleMessage> vehicleMessageMap = new ConcurrentHashMap<>();
public VehicleMessage getVehicleMessage(String deviceId) {
return vehicleMessageMap.get(deviceId);
}
public void saveVehicleMessage(String deviceId, VehicleMessage vehicleMessage) {
vehicleMessageMap.put(deviceId, vehicleMessage);
}
public void removeVehicleMessage(String deviceId) {
vehicleMessageMap.remove(deviceId);
}
public Map<String, DeviceMapPushDTO> getAllDeviceMapPush() { public Map<String, DeviceMapPushDTO> getAllDeviceMapPush() {
return deviceMapPushMap; return deviceMapPushMap;
} }

View File

@@ -33,7 +33,7 @@ import java.util.List;
*/ */
@Slf4j @Slf4j
public class HostMessageHandler implements CustomMqttMessageHandler { public class HostMessageHandler implements CustomMqttMessageHandler {
private final DeviceSessionManager deviceSessionManager = SpringUtils.getBean(DeviceSessionManager.class); private final DeviceSessionManager deviceSessionManager = SpringUtils.getBean(DeviceSessionManager.class);
private final WebsocketMesDispather websocketMesDispather = SpringUtils.getBean(WebsocketMesDispather.class); private final WebsocketMesDispather websocketMesDispather = SpringUtils.getBean(WebsocketMesDispather.class);
@@ -148,6 +148,15 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
locationMessage.setDeviceId(deviceId); locationMessage.setDeviceId(deviceId);
redisCache.setCacheObject(key, locationMessage); redisCache.setCacheObject(key, locationMessage);
// todo 推送实时位置和状态消息到外部
try {
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.DEVICE_LOCATION_MESSAGE_TOPIC, deviceId),
JsonUtils.toJsonString(locationRelTimeDTO));
} catch (MqttException e) {
log.error("位置实时数据推送失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
} }
} catch (Exception e) { } catch (Exception e) {
log.error("位置消息解析失败: deviceId={}, payload={}, error={}", deviceId, payload, e); log.error("位置消息解析失败: deviceId={}, payload={}, error={}", deviceId, payload, e);
@@ -155,7 +164,7 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
} }
public WebStatusMessageDTO createWebDeviceLocationMessage(HostLocationRelTimeDTO locationRelTimeDTO, public WebStatusMessageDTO createWebDeviceLocationMessage(HostLocationRelTimeDTO locationRelTimeDTO,
String deviceId) { String deviceId) {
WebStatusMessageDTO webStatusMessageDTO = new WebStatusMessageDTO(); WebStatusMessageDTO webStatusMessageDTO = new WebStatusMessageDTO();
List<DeviceStatusDetail> transferData = new ArrayList<>(); List<DeviceStatusDetail> transferData = new ArrayList<>();
@@ -227,7 +236,6 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
DeviceMapPushDTO dto = new DeviceMapPushDTO(); DeviceMapPushDTO dto = new DeviceMapPushDTO();
dto.setA(Double.parseDouble(altitude.getValue())); dto.setA(Double.parseDouble(altitude.getValue()));
dto.setId(deviceId); dto.setId(deviceId);
// dto.setB();
// dto.setHa(); // dto.setHa();
dto.setF(fix_status.getValue()); dto.setF(fix_status.getValue());
dto.setS(status.getValue()); dto.setS(status.getValue());
@@ -235,6 +243,12 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
dto.setLng(Double.parseDouble(lng.getValue())); dto.setLng(Double.parseDouble(lng.getValue()));
dto.setT(nettyDevice.getCurrentTaskId()); dto.setT(nettyDevice.getCurrentTaskId());
dto.setY(Double.parseDouble(yaw.getValue())); dto.setY(Double.parseDouble(yaw.getValue()));
siteMemory.getVehicleMessage(deviceId);
VehicleMessage vehicleMessage = siteMemory.getVehicleMessage(deviceId);
if (vehicleMessage != null) {
dto.setCm(vehicleMessage.getControl_mode());
dto.setB(vehicleMessage.getBattery_percentage());
}
siteMemory.saveMapPushDTO(deviceId, dto); siteMemory.saveMapPushDTO(deviceId, dto);
} }
} }
@@ -248,17 +262,82 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
WebStatusMessageDTO webStatusMessageDTO = new WebStatusMessageDTO(); WebStatusMessageDTO webStatusMessageDTO = new WebStatusMessageDTO();
List<DeviceStatusDetail> transferData = new ArrayList<>(); List<DeviceStatusDetail> transferData = new ArrayList<>();
DeviceStatusDetail voltage = new DeviceStatusDetail(); DeviceStatusDetail voltage = new DeviceStatusDetail();
voltage.setName("voltage"); voltage.setName("battery_percentage");
voltage.setValue(String.valueOf(vehicleRelTimeDTO.getData().getBattery_voltage())); voltage.setValue(String.valueOf(vehicleRelTimeDTO.getData().getBattery_percentage()));
voltage.setUnit(""); voltage.setUnit("");
transferData.add(voltage); transferData.add(voltage);
DeviceStatusDetail speed = new DeviceStatusDetail(); DeviceStatusDetail battery_voltage = new DeviceStatusDetail();
speed.setName("speed"); battery_voltage.setName("battery_voltage");
speed.setValue(String.valueOf(vehicleRelTimeDTO.getData().getSpeed())); battery_voltage.setValue(String.valueOf(vehicleRelTimeDTO.getData().getBattery_voltage()));
speed.setUnit(""); battery_voltage.setUnit("");
transferData.add(speed); transferData.add(battery_voltage);
DeviceStatusDetail left_motor_current = new DeviceStatusDetail();
left_motor_current.setName("left_motor_current");
left_motor_current.setValue(String.valueOf(vehicleRelTimeDTO.getData().getLeft_motor_current()));
left_motor_current.setUnit("");
transferData.add(left_motor_current);
DeviceStatusDetail right_motor_current = new DeviceStatusDetail();
right_motor_current.setName("right_motor_current");
right_motor_current.setValue(String.valueOf(vehicleRelTimeDTO.getData().getRight_motor_current()));
right_motor_current.setUnit("");
transferData.add(right_motor_current);
DeviceStatusDetail left_motor_temperature = new DeviceStatusDetail();
left_motor_temperature.setName("left_motor_temperature");
left_motor_temperature.setValue(String.valueOf(vehicleRelTimeDTO.getData().getLeft_motor_temperature()));
left_motor_temperature.setUnit("");
transferData.add(left_motor_temperature);
DeviceStatusDetail right_motor_temperature = new DeviceStatusDetail();
right_motor_temperature.setName("right_motor_temperature");
right_motor_temperature.setValue(String.valueOf(vehicleRelTimeDTO.getData().getRight_motor_temperature()));
right_motor_temperature.setUnit("");
transferData.add(right_motor_temperature);
DeviceStatusDetail main_temperature = new DeviceStatusDetail();
main_temperature.setName("main_temperature");
main_temperature.setValue(String.valueOf(vehicleRelTimeDTO.getData().getMain_temperature()));
main_temperature.setUnit("");
transferData.add(main_temperature);
DeviceStatusDetail yaw = new DeviceStatusDetail();
yaw.setName("yaw");
yaw.setValue(String.valueOf(vehicleRelTimeDTO.getData().getYaw()));
yaw.setUnit("");
transferData.add(yaw);
DeviceStatusDetail pitch = new DeviceStatusDetail();
pitch.setName("pitch");
pitch.setValue(String.valueOf(vehicleRelTimeDTO.getData().getPitch()));
pitch.setUnit("");
transferData.add(pitch);
DeviceStatusDetail heading_status = new DeviceStatusDetail();
heading_status.setName("heading_status");
heading_status.setValue(String.valueOf(vehicleRelTimeDTO.getData().getHeading_status()));
heading_status.setUnit("");
transferData.add(heading_status);
DeviceStatusDetail total_work_area = new DeviceStatusDetail();
total_work_area.setName("total_work_area");
total_work_area.setValue(String.valueOf(vehicleRelTimeDTO.getData().getTotal_work_area()));
total_work_area.setUnit("");
transferData.add(total_work_area);
DeviceStatusDetail total_work_duration = new DeviceStatusDetail();
total_work_duration.setName("total_work_duration");
total_work_duration.setValue(String.valueOf(vehicleRelTimeDTO.getData().getTotal_work_duration()));
total_work_duration.setUnit("");
transferData.add(total_work_duration);
DeviceStatusDetail total_work_distance = new DeviceStatusDetail();
total_work_distance.setName("total_work_distance");
total_work_distance.setValue(String.valueOf(vehicleRelTimeDTO.getData().getTotal_work_distance()));
total_work_distance.setUnit("");
transferData.add(total_work_distance);
DeviceStatusDetail motion = new DeviceStatusDetail(); DeviceStatusDetail motion = new DeviceStatusDetail();
motion.setName("motion"); motion.setName("motion");
@@ -266,11 +345,71 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
motion.setUnit(""); motion.setUnit("");
transferData.add(motion); transferData.add(motion);
DeviceStatusDetail percentage = new DeviceStatusDetail(); DeviceStatusDetail emergency_stop = new DeviceStatusDetail();
percentage.setName("percentage"); emergency_stop.setName("emergency_stop");
percentage.setValue(String.valueOf(vehicleRelTimeDTO.getData().getBattery_percentage())); emergency_stop.setValue(String.valueOf(vehicleRelTimeDTO.getData().getEmergency_stop()));
percentage.setUnit(""); emergency_stop.setUnit("");
transferData.add(percentage); transferData.add(emergency_stop);
DeviceStatusDetail left_target_rpm = new DeviceStatusDetail();
left_target_rpm.setName("left_target_rpm");
left_target_rpm.setValue(String.valueOf(vehicleRelTimeDTO.getData().getLeft_target_rpm()));
left_target_rpm.setUnit("");
transferData.add(left_target_rpm);
DeviceStatusDetail right_target_rpm = new DeviceStatusDetail();
right_target_rpm.setName("right_target_rpm");
right_target_rpm.setValue(String.valueOf(vehicleRelTimeDTO.getData().getRight_target_rpm()));
right_target_rpm.setUnit("");
transferData.add(right_target_rpm);
DeviceStatusDetail left_measured_rpm = new DeviceStatusDetail();
left_measured_rpm.setName("left_measured_rpm");
left_measured_rpm.setValue(String.valueOf(vehicleRelTimeDTO.getData().getLeft_measured_rpm()));
left_measured_rpm.setUnit("");
transferData.add(left_measured_rpm);
DeviceStatusDetail right_measured_rpm = new DeviceStatusDetail();
right_measured_rpm.setName("right_measured_rpm");
right_measured_rpm.setValue(String.valueOf(vehicleRelTimeDTO.getData().getRight_measured_rpm()));
right_measured_rpm.setUnit("");
transferData.add(right_measured_rpm);
DeviceStatusDetail left_motor_rpm = new DeviceStatusDetail();
left_motor_rpm.setName("left_motor_rpm");
left_motor_rpm.setValue(String.valueOf(vehicleRelTimeDTO.getData().getLeft_motor_rpm()));
left_motor_rpm.setUnit("");
transferData.add(left_motor_rpm);
DeviceStatusDetail right_motor_rpm = new DeviceStatusDetail();
right_motor_rpm.setName("right_motor_rpm");
right_motor_rpm.setValue(String.valueOf(vehicleRelTimeDTO.getData().getRight_motor_rpm()));
right_motor_rpm.setUnit("");
transferData.add(right_motor_rpm);
DeviceStatusDetail roll = new DeviceStatusDetail();
roll.setName("roll");
roll.setValue(String.valueOf(vehicleRelTimeDTO.getData().getRoll()));
roll.setUnit("");
transferData.add(roll);
DeviceStatusDetail control_mode = new DeviceStatusDetail();
control_mode.setName("control_mode");
control_mode.setValue(String.valueOf(vehicleRelTimeDTO.getData().getControl_mode()));
control_mode.setUnit("");
transferData.add(control_mode);
DeviceStatusDetail linear_speed = new DeviceStatusDetail();
linear_speed.setName("linear_speed");
linear_speed.setValue(String.valueOf(vehicleRelTimeDTO.getData().getLinear_speed()));
linear_speed.setUnit("");
transferData.add(linear_speed);
DeviceStatusDetail angular_speed = new DeviceStatusDetail();
angular_speed.setName("angular_speed");
angular_speed.setValue(String.valueOf(vehicleRelTimeDTO.getData().getAngular_speed()));
angular_speed.setUnit("");
transferData.add(angular_speed);
webStatusMessageDTO.setData(transferData); webStatusMessageDTO.setData(transferData);
webStatusMessageDTO.setType(MesType.deviceInfo); webStatusMessageDTO.setType(MesType.deviceInfo);
@@ -287,7 +426,7 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
if (vehicleRelTimeDTO != null) { if (vehicleRelTimeDTO != null) {
// todo 更新里程数 里程数 * 割幅0.8 // todo 更新里程数 里程数 * 割幅0.8
vehicleRelTimeDTO.getData().getDistance(); vehicleRelTimeDTO.getData().getTotal_work_distance();
NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceId); NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceId);
if (nettyDevice != null) { if (nettyDevice != null) {
Long orgId = nettyDevice.getDevice().getOrgId(); Long orgId = nettyDevice.getDevice().getOrgId();
@@ -299,9 +438,11 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
deviceRunStatistics = new DeviceRunStatistics(); deviceRunStatistics = new DeviceRunStatistics();
} }
deviceRunStatistics.setDeviceId(deviceId); deviceRunStatistics.setDeviceId(deviceId);
deviceRunStatistics.setDistance(vehicleRelTimeDTO.getData().getDistance()); deviceRunStatistics.setDistance(vehicleRelTimeDTO.getData().getTotal_work_distance());
deviceRunStatistics.setWorkArea(vehicleRelTimeDTO.getData().getDistance() * 0.8); deviceRunStatistics.setWorkArea(vehicleRelTimeDTO.getData().getTotal_work_distance() * 0.8);
siteMemory.saveRunStatistics(deviceRunStatistics); siteMemory.saveRunStatistics(deviceRunStatistics);
siteMemory.saveVehicleMessage(deviceId, vehicleRelTimeDTO.getData());
} }
} }
@@ -318,6 +459,14 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
} }
} }
} }
// todo 推送实时位置和状态消息到外部
try {
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.DEVICE_VEHICLE_MESSAGE_TOPIC, deviceId),
JsonUtils.toJsonString(vehicleRelTimeDTO));
} catch (MqttException e) {
log.error("位置实时数据推送失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
} }
} catch (Exception e) { } catch (Exception e) {
log.error("实时消息解析失败: deviceId={}, payload={}, error={}", deviceId, payload, e.getMessage()); log.error("实时消息解析失败: deviceId={}, payload={}, error={}", deviceId, payload, e.getMessage());
@@ -371,7 +520,7 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
try { try {
websocketMesDispather.dispather(x.getConnectorId(), JsonUtils.toJsonString(sendDto)); websocketMesDispather.dispather(x.getConnectorId(), JsonUtils.toJsonString(sendDto));
} catch (Exception e) { } catch (Exception e) {
log.error("实时数据websocket推送失败: connectorId={}, error={}", x.getConnectorId(), log.error("实时数据websocket任务状态推送失败: connectorId={}, error={}", x.getConnectorId(),
e.getMessage()); e.getMessage());
} }
} }
@@ -382,8 +531,7 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, taskId), String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, taskId),
JsonUtils.toJsonString(sendDto)); JsonUtils.toJsonString(sendDto));
} catch (MqttException e) { } catch (MqttException e) {
// TODO Auto-generated catch block log.error("实时数据websocket任务状态推送失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
e.printStackTrace();
} }
} }
@@ -397,7 +545,7 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
if ("failed".equals(dto.getStatus())) { if ("failed".equals(dto.getStatus())) {
nettyDevice.failedTask(); nettyDevice.failedTask();
} }
// if("accepted".equals(dto.getStatus())){ // if ("accepted".equals(dto.getStatus())) {
// NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceId); // NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceId);
// nettyDevice.finishTask(); // nettyDevice.finishTask();
// } // }
@@ -436,6 +584,34 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
if (device != null && device.getTask() != null if (device != null && device.getTask() != null
&& String.valueOf(device.getTask().getId()).equals(replyDTO.getTask_id())) { && String.valueOf(device.getTask().getId()).equals(replyDTO.getTask_id())) {
device.getTask().setTaskAccepted(true); device.getTask().setTaskAccepted(true);
WebDeviceTaskStatusMessageDTO sendDto = new WebDeviceTaskStatusMessageDTO();
sendDto.setDeviceId(deviceId);
sendDto.setTaskId(device.getTask().getId());
sendDto.setStatus(DeviceTaskStaus.EXECUTING.toString());
sendDto.setType(MesType.device_task_change);
List<NettyDevice> controlMasters = deviceSessionManager
.getAllSlaveControl(deviceId);
if (!CollectionUtils.isEmpty(controlMasters)) {
for (NettyDevice x : controlMasters) {
try {
websocketMesDispather.dispather(x.getConnectorId(), JsonUtils.toJsonString(sendDto));
} catch (Exception e) {
log.error("实时数据websocket推送失败: connectorId={}, error={}", x.getConnectorId(),
e.getMessage(), e);
}
}
}
// todo 推送实时位置和状态消息到外部
try {
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, device.getTask().getId()),
JsonUtils.toJsonString(sendDto));
} catch (MqttException e) {
log.error("实时数据websocket推送失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
} }
} }
} }
@@ -444,17 +620,18 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
* 处理控制指令响应 * 处理控制指令响应
*/ */
private void handleUpgradeReply(String deviceId, String topic, String payload) { private void handleUpgradeReply(String deviceId, String topic, String payload) {
// log.debug("【路径任务下发响应】deviceId={}, payload={}", deviceId, payload); // log.debug("【路径任务下发响应】deviceId={}, payload={}", deviceId, payload);
// //
// // todo 更新任务接收状态 // // todo 更新任务接收状态
// HostNavigationReplyDTO replyDTO = JsonUtils.parseObject(payload, HostNavigationReplyDTO.class); // HostNavigationReplyDTO replyDTO = JsonUtils.parseObject(payload,
// NettyDevice device = deviceSessionManager.getDevice(deviceId); // HostNavigationReplyDTO.class);
// if (replyDTO.isAccepted()) { // NettyDevice device = deviceSessionManager.getDevice(deviceId);
// if (device != null && device.getTask() != null // if (replyDTO.isAccepted()) {
// && String.valueOf(device.getTask().getId()).equals(replyDTO.getTask_id())) { // if (device != null && device.getTask() != null
// device.getTask().setTaskAccepted(true); // && String.valueOf(device.getTask().getId()).equals(replyDTO.getTask_id())) {
// } // device.getTask().setTaskAccepted(true);
// } // }
// }
} }
/** /**
@@ -510,7 +687,6 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
if (remaining.equals("/ota/result/post")) if (remaining.equals("/ota/result/post"))
return "upgrade_reply"; return "upgrade_reply";
return null; return null;
} }

View File

@@ -2,18 +2,22 @@ package com.maibu.mqtt;
public class MqttTopic { public class MqttTopic {
/** 通用设备主题,建议使用 MOWER_* 系列主题 */ /** 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_STATUS_TOPIC = "device/%s/realTimeMessage"; public static final String DEVICE_STATUS_TOPIC = "device/%s/realTimeMessage";
public static final String DEVICE_LOCATION_TOPIC = "device/%s/locationMessage"; public static final String DEVICE_VEHICLE_MESSAGE_TOPIC = "device/%s/host/realTime/message";
/** 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_LOCATION_MESSAGE_TOPIC = "device/%s/host/location/message";
/** 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_TASK_STATUS_TOPIC = "task/%s/status"; public static final String DEVICE_TASK_STATUS_TOPIC = "task/%s/status";
/** 通用设备主题,建议使用 MOWER_* 系列主题 */ /** 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_TASK_ARRIVE_TOPIC = "task/%s/arrive"; public static final String DEVICE_TASK_ARRIVE_TOPIC = "task/%s/arrive";
/** 通用设备主题,建议使用 MOWER_* 系列主题 */ /** 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_ERROR_PUSH_TOPIC = "device/%s/error"; public static final String DEVICE_ERROR_PUSH_TOPIC = "device/%s/error";
public static final String DEVICE_ROUTE_PUSH_TOPIC = "device/%s/route/post"; public static final String DEVICE_ROUTE_PUSH_TOPIC = "device/%s/route/post";
public static final String DEVICE_STATUS_PUSH_TOPIC = "device/%s/status/change";
/** 产品标识:割草机 */ /** 产品标识:割草机 */
public static final String MOWER_PRODUCT = "mower"; public static final String MOWER_PRODUCT = "mower";
@@ -43,7 +47,7 @@ public class MqttTopic {
// ==================== 远程控制 ==================== // ==================== 远程控制 ====================
/** 远程控制指令下发:前进/后退/转向/割草等(平台->设备),对应 TCP 0x00 remoteControl */ /** 远程控制指令下发:前进/后退/转向/割草等(平台->设备),对应 TCP 0x00 remoteControl */
public static final String MOWER_CONTROL_SET = "mower/%s/action/control/set"; public static final String MOWER_CONTROL_SET = "mower/%s/control/remote/set";
// ==================== 任务管理 ==================== // ==================== 任务管理 ====================
/** 路径规划下发(平台->设备),对应 TCP 0x01 path */ /** 路径规划下发(平台->设备),对应 TCP 0x01 path */
@@ -71,6 +75,9 @@ public class MqttTopic {
/** OTA 升级结果上报(设备->平台) */ /** OTA 升级结果上报(设备->平台) */
public static final String MOWER_OTA_RESULT_POST = "mower/+/ota/result/post"; public static final String MOWER_OTA_RESULT_POST = "mower/+/ota/result/post";
/** 寻车指令(平台->设备) */
public static final String MOWER_SEARCH_DEVICE_SET = "mower/%s/action/search/set";
// ==================== 设备信息 ==================== // ==================== 设备信息 ====================
// /** 查询设备信息(平台->设备) */ // /** 查询设备信息(平台->设备) */
// public static final String MOWER_INFO_DEVICE_GET = // public static final String MOWER_INFO_DEVICE_GET =

View File

@@ -116,7 +116,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
// 过滤请求 // 过滤请求
.authorizeRequests() .authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/iot/host/upload-path-csv","/api/thermal/**","/iotDA/device/**", "/websocket/allMemory", "/iot/UAV/**", "/iot/api/**", "/iot/device/userDevice", "/external/sms/sendAliSmsCode", "/login", "/register", "/captchaImage", "/iot/tool/register", "/iot/tool/ntp", .antMatchers("/system/param/list","/iot/host/upload-path-csv","/api/thermal/**","/iotDA/device/**", "/websocket/allMemory", "/iot/UAV/**", "/iot/api/**", "/iot/device/userDevice", "/external/sms/sendAliSmsCode", "/login", "/register", "/captchaImage", "/iot/tool/register", "/iot/tool/ntp",
"/iot/tool/mqtt/auth", "/iot/workRecord/**", "/iot/tool/mqtt/authv5", "/iot/tool/mqtt/webhook", "/iot/tool/mqtt/webhookv5", "/auth/**/**", "/iot/tool/mqtt/auth", "/iot/workRecord/**", "/iot/tool/mqtt/authv5", "/iot/tool/mqtt/webhook", "/iot/tool/mqtt/webhookv5", "/auth/**/**",
"/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll() "/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll()
.antMatchers("/zlmhook/**").permitAll() .antMatchers("/zlmhook/**").permitAll()

View File

@@ -44,5 +44,4 @@ public class NettyDeviceController extends BaseController {
nettyDeviceService.sendCommand(command); nettyDeviceService.sendCommand(command);
return AjaxResult.success(); return AjaxResult.success();
} }
} }

View File

@@ -1,34 +1,64 @@
package com.maibu.init; package com.maibu.init;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import com.maibu.core.business.*; import org.checkerframework.checker.units.qual.s;
import com.maibu.mapper.*;
import com.maibu.service.impl.IotDeviceCommonService;
import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.constant.FastBeeConstant; import com.maibu.constant.FastBeeConstant;
import com.maibu.core.business.AlarmOrderConfig;
import com.maibu.core.business.Device;
import com.maibu.core.business.DeviceModel;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DevicePlanTask;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.core.business.IoTCommonDevice;
import com.maibu.core.business.OrderModel;
import com.maibu.core.business.Product;
import com.maibu.core.domain.entity.SysParam;
import com.maibu.core.domain.entity.SysSite; import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.enums.DeviceTaskStaus; import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.influxdb.util.InfluxDBUtil; import com.maibu.influxdb.util.InfluxDBUtil;
import com.maibu.mapper.AlarmOrderConfigMapper;
import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.DeviceProductMapper;
import com.maibu.mapper.DeviceRunParamMapper;
import com.maibu.mapper.ErrorIdentificationStandardMapper;
import com.maibu.mapper.IotDeviceCommonMapper;
import com.maibu.mapper.OrderModelMapper;
import com.maibu.mapper.SysDeviceModelMapper;
import com.maibu.mapper.SysParamMapper;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.memory.GlobalMemory; import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory; import com.maibu.memory.SiteMemory;
import com.maibu.mqtt.MqttClientUtil;
import com.maibu.mybatis.LambdaQueryWrapperX; import com.maibu.mybatis.LambdaQueryWrapperX;
import com.maibu.service.DevicePlanTaskMonitorService; import com.maibu.service.DevicePlanTaskMonitorService;
import com.maibu.service.DeviceThreadService; import com.maibu.service.DeviceThreadService;
import org.springframework.beans.factory.annotation.Value; import com.maibu.service.impl.IotDeviceCommonService;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@@ -81,6 +111,7 @@ public class InitThread implements ApplicationRunner {
@Autowired @Autowired
private ErrorIdentificationStandardMapper errorIdentificationStandardMapper; private ErrorIdentificationStandardMapper errorIdentificationStandardMapper;
@Autowired @Autowired
private OrderModelMapper orderModelMapper; private OrderModelMapper orderModelMapper;
@Autowired @Autowired
private AlarmOrderConfigMapper alarmOrderConfigMapper; private AlarmOrderConfigMapper alarmOrderConfigMapper;
@@ -88,6 +119,12 @@ public class InitThread implements ApplicationRunner {
@Autowired @Autowired
private IotDeviceCommonService commonService; private IotDeviceCommonService commonService;
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private SysParamMapper sysParamMapper;
@Value("${influxdb.url}") @Value("${influxdb.url}")
private String influxDBUrl; private String influxDBUrl;
@@ -119,12 +156,15 @@ public class InitThread implements ApplicationRunner {
private String mqttClientId; private String mqttClientId;
@Override @Override
public void run(ApplicationArguments args) throws MqttException { public void run(ApplicationArguments args) throws Exception {
recoverMemory(); recoverMemory();
init(); init();
} }
private void init() throws MqttException { private void init() throws Exception {
//初始化系统参数
initSystemParam();
// 初始化InfluxDBUtil // 初始化InfluxDBUtil
GlobalMemory.influxDBUtil = new InfluxDBUtil(influxDBUrl, influxDBToken, influxDBOrg, influxDBBucket); GlobalMemory.influxDBUtil = new InfluxDBUtil(influxDBUrl, influxDBToken, influxDBOrg, influxDBBucket);
@@ -185,7 +225,7 @@ public class InitThread implements ApplicationRunner {
}); });
} }
//外部设备 // 外部设备
List<IoTCommonDevice> ioTCommonDeviceList = iotDeviceCommonMapper.selectList(); List<IoTCommonDevice> ioTCommonDeviceList = iotDeviceCommonMapper.selectList();
if (!CollectionUtils.isEmpty(ioTCommonDeviceList)) { if (!CollectionUtils.isEmpty(ioTCommonDeviceList)) {
ioTCommonDeviceList.forEach(x -> { ioTCommonDeviceList.forEach(x -> {
@@ -197,7 +237,7 @@ public class InitThread implements ApplicationRunner {
} }
}); });
} }
//产品 // 产品
List<Product> productList = deviceProductMapper.selectList(); List<Product> productList = deviceProductMapper.selectList();
if (!CollectionUtils.isEmpty(productList)) { if (!CollectionUtils.isEmpty(productList)) {
productList.forEach(x -> { productList.forEach(x -> {
@@ -209,7 +249,7 @@ public class InitThread implements ApplicationRunner {
} }
}); });
} }
//设备模型 // 设备模型
List<DeviceModel> deviceModelList = deviceModelMapper.selectList(); List<DeviceModel> deviceModelList = deviceModelMapper.selectList();
if (!CollectionUtils.isEmpty(deviceModelList)) { if (!CollectionUtils.isEmpty(deviceModelList)) {
deviceModelList.forEach(x -> { deviceModelList.forEach(x -> {
@@ -221,7 +261,7 @@ public class InitThread implements ApplicationRunner {
} }
}); });
} }
//车辆参数 // 车辆参数
List<DeviceRunParam> deviceRunParamList = deviceRunParamMapper.selectList(); List<DeviceRunParam> deviceRunParamList = deviceRunParamMapper.selectList();
if (!CollectionUtils.isEmpty(deviceRunParamList)) { if (!CollectionUtils.isEmpty(deviceRunParamList)) {
deviceRunParamList.forEach(x -> { deviceRunParamList.forEach(x -> {
@@ -233,7 +273,7 @@ public class InitThread implements ApplicationRunner {
} }
}); });
} }
//错误标准 // 错误标准
List<ErrorIdentificationStandard> standadList = errorIdentificationStandardMapper.selectList(); List<ErrorIdentificationStandard> standadList = errorIdentificationStandardMapper.selectList();
if (!CollectionUtils.isEmpty(standadList)) { if (!CollectionUtils.isEmpty(standadList)) {
standadList.forEach(x -> { standadList.forEach(x -> {
@@ -245,7 +285,7 @@ public class InitThread implements ApplicationRunner {
} }
}); });
} }
//订单模型 // 订单模型
List<OrderModel> orderModelList = orderModelMapper.selectList(); List<OrderModel> orderModelList = orderModelMapper.selectList();
if (!CollectionUtils.isEmpty(orderModelList)) { if (!CollectionUtils.isEmpty(orderModelList)) {
orderModelList.forEach(x -> { orderModelList.forEach(x -> {
@@ -257,7 +297,7 @@ public class InitThread implements ApplicationRunner {
} }
}); });
} }
//告警订单配置 // 告警订单配置
List<AlarmOrderConfig> alarmOrderList = alarmOrderConfigMapper.selectList(); List<AlarmOrderConfig> alarmOrderList = alarmOrderConfigMapper.selectList();
if (!CollectionUtils.isEmpty(alarmOrderList)) { if (!CollectionUtils.isEmpty(alarmOrderList)) {
alarmOrderList.forEach(x -> { alarmOrderList.forEach(x -> {
@@ -317,4 +357,38 @@ public class InitThread implements ApplicationRunner {
} }
} }
public void initSystemParam() throws IOException {
LambdaQueryWrapper<SysParam> queryWrapper = new LambdaQueryWrapper<>();
List<SysParam> list = sysParamMapper.selectList(queryWrapper);
try {
// 读取resource目录下的dsystemParam.json文件
org.springframework.core.io.Resource resource = resourceLoader
.getResource("classpath:systemParam.json");
// 使用fastjson2转换为DeviceConfig对象
String jsonContent;
jsonContent = IoUtil.readUtf8(resource.getInputStream());
List<SysParam> params = JSON.parseArray(jsonContent, SysParam.class);
List<SysParam> saveList = new ArrayList<>();
if (CollectionUtils.isEmpty(list)) {
saveList.addAll(params);
} else {
Map<String, SysParam> map = list.stream()
.collect(Collectors.toMap(
SysParam::getParamKey,
sysParam -> sysParam));
if (!CollectionUtils.isEmpty(params)) {
params.forEach(x -> {
if (!map.containsKey(x.getParamKey())) {
saveList.add(x);
}
});
}
}
sysParamMapper.saveOrUpdateBatch(saveList);
} catch (Exception e) {
log.error("初始化系统参数失败", e);
}
}
} }

View File

@@ -1,11 +1,15 @@
package com.maibu.netty.handler; package com.maibu.netty.handler;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import com.maibu.memory.DeviceSessionManager; import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.GlobalMemory; import com.maibu.memory.GlobalMemory;
import com.maibu.mqtt.MqttTopic; import com.maibu.mqtt.MqttTopic;
import com.maibu.utils.json.JsonUtils;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -15,9 +19,13 @@ import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.maibu.constant.CommandConstant; import com.maibu.constant.CommandConstant;
import com.maibu.constant.Constant;
import com.maibu.core.business.LawnMoverProtocolEntity;
import com.maibu.core.business.device.Connector; import com.maibu.core.business.device.Connector;
import com.maibu.core.business.device.NettyDevice; import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.enums.ConnectorType; import com.maibu.core.enums.ConnectorType;
import com.maibu.core.host.DeviceRemoteControlDTO;
import com.maibu.core.host.ParamDetail;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel; import io.netty.channel.Channel;
@@ -29,7 +37,6 @@ import io.netty.channel.SimpleChannelInboundHandler;
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class CommandForwardHandler extends SimpleChannelInboundHandler<String> { public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
private static final Logger logger = LoggerFactory.getLogger(CommandForwardHandler.class); private static final Logger logger = LoggerFactory.getLogger(CommandForwardHandler.class);
@Autowired @Autowired
@@ -44,12 +51,11 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
byte[] bytes = Hex.decodeHex(msg.toCharArray()); byte[] bytes = Hex.decodeHex(msg.toCharArray());
if (bytes.length > 3 && (bytes[2] == CommandConstant.remoteControl if (bytes.length > 3 && (bytes[2] == CommandConstant.remoteControl
|| bytes[2] == CommandConstant.path || bytes[2] == CommandConstant.path
|| bytes[2] == CommandConstant.status || bytes[2] == CommandConstant.status)) {
)) {
String senderDeviceId = deviceSessionManager.getDeviceIdByChannel(currentChannel); String senderDeviceId = deviceSessionManager.getDeviceIdByChannel(currentChannel);
NettyDevice senderNettyDevice = NettyDevice senderNettyDevice = senderDeviceId != null ? deviceSessionManager.getDevice(senderDeviceId)
senderDeviceId != null ? deviceSessionManager.getDevice(senderDeviceId) : null; : null;
if (senderNettyDevice == null) { if (senderNettyDevice == null) {
logger.debug("发送拒绝,设备:{}未发送上线指令", senderDeviceId); logger.debug("发送拒绝,设备:{}未发送上线指令", senderDeviceId);
@@ -76,22 +82,73 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
return; return;
} }
for (Connector target : connectedDevices) { for (Connector target : connectedDevices) {
if (!target.isOnline()) {
logger.debug("发送拒绝master:{},消息到达的salve设备:{},已离线", senderDeviceId, target.getConnectorId()); if (target == null || !target.canReceive()) {
continue;
}
if (!target.canReceive()) {
logger.debug("发送拒绝master:{},消息到达的slave设备:{},处于禁止接收状态", senderDeviceId, target.getConnectorId()); logger.debug("发送拒绝master:{},消息到达的slave设备:{},处于禁止接收状态", senderDeviceId, target.getConnectorId());
continue; continue;
} }
// todo 向上位机发送控制消息 NettyDevice targetDevice = deviceSessionManager.getDevice(target.getConnectorId());
if (targetDevice == null)
continue;
// 区分有上位机的还有无上位机的 有上位机的通过上位机下发 没有上位机的按照原来的方式下发
if (targetDevice.getDevice().getHasHost()) {
if (bytes[2] == CommandConstant.remoteControl) {
// todo 转换 原先的报文重新组装成上位机的报文格式
DeviceRemoteControlDTO deviceRemoteControlDTO = new DeviceRemoteControlDTO();
LawnMoverProtocolEntity pEntity = LawnMoverProtocolEntity.parseControlCommand(bytes);
if (pEntity != null) {
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId, String.format(MqttTopic.MOWER_CONTROL_SET, target.getConnectorId()), msg); ParamDetail data = new ParamDetail();
// Channel targetChannel = target.getChannel(); // data.setLeft_wheel_rpm(pEntity.getLeftWheelSpeed());
// if (targetChannel != null && targetChannel.isActive()) { // data.setRight_wheel_rpm(pEntity.getRightWheelSpeed());
// targetChannel.writeAndFlush(msg);
// logger.debug("从master:{},向slave:{}, 转发消息:{}", senderDeviceId, target.getConnectorId(), msg); double angularSpeed = BigDecimal.valueOf(pEntity.getAngularSpeed())
// } .setScale(2, RoundingMode.HALF_UP)
.doubleValue();
double linearSpeed = BigDecimal.valueOf(pEntity.getLinearSpeed())
.setScale(2, RoundingMode.HALF_UP)
.doubleValue();
data.setLinear_x(linearSpeed);
data.setAngular_z(angularSpeed);
data.setChassis_lift(pEntity.getChassisLiftFlag());
data.setCutter(pEntity.getMowerSpeedFlag());
data.setIgnition(pEntity.getIgnitionFlag());
data.setEmergency_stop(pEntity.getEmergencyStopFlag());
data.setValid_for_ms(500);
deviceRemoteControlDTO.setData(data);
deviceRemoteControlDTO
.setCommand_id(Constant.remote_control_cmd_prefix + System.currentTimeMillis());
deviceRemoteControlDTO.setSn(target.getConnectorId());
deviceRemoteControlDTO.setTimestamp(System.currentTimeMillis());
deviceRemoteControlDTO
.setMessage_id(Constant.remote_control_msg_prefix + System.currentTimeMillis());
deviceRemoteControlDTO.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_CONTROL_SET, target.getConnectorId()),
JsonUtils.toJsonString(deviceRemoteControlDTO));
logger.debug("master:{},向slave:{} 有上位机, 转发遥控指令:{}", senderDeviceId,
target.getConnectorId(),
JsonUtils.toJsonString(deviceRemoteControlDTO));
}
}
} else {
if (!target.isOnline()) {
logger.debug("发送拒绝master:{},消息到达的salve设备:{},已离线", senderDeviceId,
target.getConnectorId());
continue;
}
Channel targetChannel = target.getChannel();
if (targetChannel != null && targetChannel.isActive()) {
targetChannel.writeAndFlush(msg);
logger.debug("从master:{},向slave:{} 无上位机, 转发消息:{}", senderDeviceId,
target.getConnectorId(), msg);
}
}
} }
} else if (ConnectorType.SLAVE.equals(senderNettyDevice.getDeviceType())) { } else if (ConnectorType.SLAVE.equals(senderNettyDevice.getDeviceType())) {
List<NettyDevice> masters = deviceSessionManager.getMastersBySlaveId(senderDeviceId); List<NettyDevice> masters = deviceSessionManager.getMastersBySlaveId(senderDeviceId);

View File

@@ -140,13 +140,13 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
nettyDevice.setLatestStatus(latestStatus); nettyDevice.setLatestStatus(latestStatus);
} }
} else if (bytes[2] == CommandConstant.readConfig) { } else if (bytes[2] == CommandConstant.readConfig) {
DeviceRunParam runParam = DeviceRunParam.fromBytes(bytes); // DeviceRunParam runParam = DeviceRunParam.fromBytes(bytes);
logger.debug("收到返回的设备运行参数: {}", JsonUtils.toJsonString(runParam)); // logger.debug("收到返回的设备运行参数: {}", JsonUtils.toJsonString(runParam));
CompletableFuture<DeviceRunParam> future = ctx.channel().attr(Constant.READ_CONFIG_KEY).get(); // CompletableFuture<DeviceRunParam> future = ctx.channel().attr(Constant.READ_CONFIG_KEY).get();
if (future != null) { // if (future != null) {
future.complete(runParam); // future.complete(runParam);
ctx.channel().attr(Constant.READ_CONFIG_KEY).set(null); // ctx.channel().attr(Constant.READ_CONFIG_KEY).set(null);
} // }
} }
ctx.fireChannelRead(msg); ctx.fireChannelRead(msg);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -75,20 +75,20 @@ public class ScheduledTask {
System.out.println("0点定时刷新状态执行完成"); System.out.println("0点定时刷新状态执行完成");
} }
public static void main(String[] args) throws DecoderException { // public static void main(String[] args) throws DecoderException {
String hex = "AB AA 05 88 4D 43 37 30 30 50 4C 55 53 2D 43 4E 2D 4A 53 2D 31 37 38 34 38 37 31 39 37 39 31 39 30 2D 30 30 30 30 30 30 30 41 2D 36 30 00 B1 FB 7F FE FE FE 00 00 00 00 00 00 00 00 00 00 00 00 00 12 01 48 95 E8 03 E8 03 28 32 91 53 24 4D 43 37 30 30 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 CD CC A4 41 00 00 80 3F 33 33 33 3F B8 1E 05 3F 33 33 33 3F 9A 99 19 3E 00 00 80 3F 00 00 80 3F 00 00 80 3F 32 36 2D 34 2D 32 37 00 2D 32 37 00 50 B1 BF 00 00 AA AB"; // String hex = "AB AA 05 88 4D 43 37 30 30 50 4C 55 53 2D 43 4E 2D 4A 53 2D 31 37 38 34 38 37 31 39 37 39 31 39 30 2D 30 30 30 30 30 30 30 41 2D 36 30 00 B1 FB 7F FE FE FE 00 00 00 00 00 00 00 00 00 00 00 00 00 12 01 48 95 E8 03 E8 03 28 32 91 53 24 4D 43 37 30 30 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 31 32 33 34 35 36 37 38 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 CD CC A4 41 00 00 80 3F 33 33 33 3F B8 1E 05 3F 33 33 33 3F 9A 99 19 3E 00 00 80 3F 00 00 80 3F 00 00 80 3F 32 36 2D 34 2D 32 37 00 2D 32 37 00 50 B1 BF 00 00 AA AB";
String cleanHex = hex.replaceAll("\\s+", ""); // 移除所有空白字符 // String cleanHex = hex.replaceAll("\\s+", ""); // 移除所有空白字符
byte[] bytes = Hex.decodeHex(cleanHex); // byte[] bytes = Hex.decodeHex(cleanHex);
DeviceRunParam runParam = DeviceRunParam.fromBytes(bytes); // DeviceRunParam runParam = DeviceRunParam.fromBytes(bytes);
System.out.println(JsonUtils.toJsonString(runParam)); // System.out.println(JsonUtils.toJsonString(runParam));
runParam.setLeftBackwardGain(0.2f); // runParam.setLeftBackwardGain(0.2f);
runParam.setLeftForwardGain(0.2f); // runParam.setLeftForwardGain(0.2f);
runParam.setRightForwardGain(0.2f); // runParam.setRightForwardGain(0.2f);
runParam.setRightBackwardGain(0.2f); // runParam.setRightBackwardGain(0.2f);
byte[] newB = runParam.toWriteBytes(); // byte[] newB = runParam.toWriteBytes();
System.out.println(Hex.encodeHexString(newB)); // System.out.println(Hex.encodeHexString(newB));
} // }
} }

View File

@@ -16,6 +16,7 @@ import java.util.stream.Collectors;
import com.maibu.core.business.dto.DeviceMapPushDTO; import com.maibu.core.business.dto.DeviceMapPushDTO;
import com.maibu.core.business.dto.WebMapMessageDTO; import com.maibu.core.business.dto.WebMapMessageDTO;
import com.maibu.core.business.dto.WebOlineStatusMessageDTO;
import com.maibu.core.enums.*; import com.maibu.core.enums.*;
import com.maibu.utils.json.JsonUtils; import com.maibu.utils.json.JsonUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -43,6 +44,7 @@ import com.maibu.core.host.HeartBeatDTO;
import com.maibu.core.host.LocationMessage; import com.maibu.core.host.LocationMessage;
import com.maibu.core.redis.RedisCache; import com.maibu.core.redis.RedisCache;
import com.maibu.dto.DeviceErrorPushDTO; import com.maibu.dto.DeviceErrorPushDTO;
import com.maibu.dto.DeviceTaskStatusMessageDTO;
import com.maibu.mapper.DeviceRunStatisticsMapper; import com.maibu.mapper.DeviceRunStatisticsMapper;
import com.maibu.mapper.ErrorIdentificationStandardMapper; import com.maibu.mapper.ErrorIdentificationStandardMapper;
import com.maibu.mapper.HostLocationMapper; import com.maibu.mapper.HostLocationMapper;
@@ -297,7 +299,7 @@ public class DeviceThreadService {
} }
if (nowTime - lastActiveTime >= Constant.hostOfflineInterval) { if (nowTime - lastActiveTime >= Constant.hostOfflineInterval) {
// 超时了判断离线 // 超时了判断离线
if (nettyDevice != null) { if (nettyDevice != null && nettyDevice.getOnlineStatus() == 1) {
nettyDevice.status(DeviceStatus.offline.getType()); nettyDevice.status(DeviceStatus.offline.getType());
// todo 推送设备离线 // todo 推送设备离线
String key = NettyCacheKey.latestPositonKey + deviceId; String key = NettyCacheKey.latestPositonKey + deviceId;
@@ -309,7 +311,10 @@ public class DeviceThreadService {
LocationMessage existing = hostLocationMapper.selectOne(queryWrapper); LocationMessage existing = hostLocationMapper.selectOne(queryWrapper);
if (existing != null) { if (existing != null) {
locationMessage.setId(existing.getId()); locationMessage.setId(existing.getId());
} else {
locationMessage.setCreateTime(LocalDateTime.now());
} }
locationMessage.setUpdateTime(LocalDateTime.now());
hostLocationMapper.saveOrUpdate(locationMessage); hostLocationMapper.saveOrUpdate(locationMessage);
} }
Device device = deviceService.selectDeviceBySerialNumber(deviceId); Device device = deviceService.selectDeviceBySerialNumber(deviceId);
@@ -345,8 +350,10 @@ public class DeviceThreadService {
} }
// todo 删除实时消息推送里面的数据 // todo 删除实时消息推送里面的数据
siteMemory.removeMapPushDTO(deviceId); siteMemory.removeMapPushDTO(deviceId);
siteMemory.removeVehicleMessage(deviceId);
} }
statusChangePush(deviceId, siteId, 0);
sessionManager.removeDevice(deviceId); sessionManager.removeDevice(deviceId);
// TODO 统计总里程、总作业面积 // TODO 统计总里程、总作业面积
@@ -380,11 +387,14 @@ public class DeviceThreadService {
if (slaveDevice != null) { if (slaveDevice != null) {
slaveDevice.setOnlineStatus(1); slaveDevice.setOnlineStatus(1);
slaveDevice.setDevice(device); slaveDevice.setDevice(device);
statusChangePush(deviceId, device.getSiteId(), 1);
} }
} else { } else {
// todo 推送设备上线 // todo 推送设备上线
nettyDevice.status(1); nettyDevice.status(1);
nettyDevice.setDevice(device); nettyDevice.setDevice(device);
nettyDevice.setConnectorStatus(ConnectorStatus.ACTIVE);
statusChangePush(deviceId, device.getSiteId(), 1);
} }
} }
}); });
@@ -395,8 +405,30 @@ public class DeviceThreadService {
}, 0, 500, TimeUnit.MILLISECONDS); }, 0, 500, TimeUnit.MILLISECONDS);
} }
public void statusChangePush(String deviceId, Long siteId, Integer status) {
// todo 推送设备离线
WebOlineStatusMessageDTO dto = new WebOlineStatusMessageDTO();
dto.setDeviceId(deviceId);
dto.setType(MesType.device_status_changed);
dto.setOnlineStatus(status);
try {
// 当前控制的web端
websocketMesDispather.dispather(deviceId, JsonUtils.toJsonString(dto));
// 地图监控页面推送
websocketMesDispather.mapMessageDispather(siteId,
JsonUtils.toJsonString(dto));
// 推送到mqtt服务器
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.DEVICE_STATUS_PUSH_TOPIC, deviceId), JsonUtils.toJsonString(dto));
} catch (Exception e) {
log.error("机器状态变化推送失败: siteId={}, error={}", siteId,
e.getMessage(), e);
}
}
/** /**
* 监控心跳 * 地图监控
*/ */
public void mapMessagePush() { public void mapMessagePush() {
executor.scheduleWithFixedDelay(() -> { executor.scheduleWithFixedDelay(() -> {

View File

@@ -43,12 +43,11 @@ public class TransferDeviceService {
@Autowired @Autowired
private DeviceMapper deviceMapper; private DeviceMapper deviceMapper;
public AjaxResult bind(DeviceBindDTO bindDTO, LoginUser user) { public AjaxResult bind(DeviceBindDTO bindDTO, LoginUser user) {
try { try {
String deviceId = bindDTO.getDeviceId(); String deviceId = bindDTO.getDeviceId();
String deviceAlias = bindDTO.getDeviceAlias(); String deviceAlias = bindDTO.getDeviceAlias();
//判断当前设备是否存 // 判断当前设备是否存
Device device = iDeviceService.selectDeviceBySerialNumber(deviceId); Device device = iDeviceService.selectDeviceBySerialNumber(deviceId);
if (device == null) { if (device == null) {
return AjaxResult.error("设备不存在"); return AjaxResult.error("设备不存在");
@@ -65,7 +64,7 @@ public class TransferDeviceService {
device.setDeviceAlias(deviceAlias); device.setDeviceAlias(deviceAlias);
device.setActiveTime(new Date()); device.setActiveTime(new Date());
iDeviceService.updateDeviceBySelf(device); iDeviceService.updateDeviceBySelf(device);
// deviceMapper.updateById(device); // deviceMapper.updateById(device);
return AjaxResult.success(true); return AjaxResult.success(true);
} }
} catch (Exception e) { } catch (Exception e) {
@@ -77,7 +76,7 @@ public class TransferDeviceService {
public AjaxResult unbind(DeviceBindDTO bindDTO, LoginUser user) { public AjaxResult unbind(DeviceBindDTO bindDTO, LoginUser user) {
try { try {
String deviceId = bindDTO.getDeviceId(); String deviceId = bindDTO.getDeviceId();
//判断当前设备是否存 // 判断当前设备是否存
Device device = iDeviceService.selectDeviceBySerialNumber(deviceId); Device device = iDeviceService.selectDeviceBySerialNumber(deviceId);
if (device == null) { if (device == null) {
return AjaxResult.error("设备不存在"); return AjaxResult.error("设备不存在");
@@ -93,9 +92,9 @@ public class TransferDeviceService {
device.setTenantName(""); device.setTenantName("");
device.setUpdateTime(LocalDateTime.now()); device.setUpdateTime(LocalDateTime.now());
device.setDeviceAlias(""); device.setDeviceAlias("");
// deviceMapper.updateById(device); // deviceMapper.updateById(device);
iDeviceService.updateDeviceBySelf(device); iDeviceService.updateDeviceBySelf(device);
//判断是否正在控制 如果正在控制,删除控制状态 // 判断是否正在控制 如果正在控制,删除控制状态
LambdaQueryWrapper<UserClient> lambdaWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserClient> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.eq(UserClient::getDeviceName, deviceId); lambdaWrapper.eq(UserClient::getDeviceName, deviceId);
List<UserClient> users = userClientMapper.selectList(lambdaWrapper); List<UserClient> users = userClientMapper.selectList(lambdaWrapper);
@@ -108,12 +107,15 @@ public class TransferDeviceService {
NettyDevice deviceMaster = sessionManager.getDevice(masterId); NettyDevice deviceMaster = sessionManager.getDevice(masterId);
if (deviceMaster != null) { if (deviceMaster != null) {
String oldSlave = userClient.getDeviceName(); String oldSlave = userClient.getDeviceName();
//删除主的连接关系 // 删除主的连接关系
deviceMaster.getConnectedConnectors().removeIf(x -> x.getConnectorId().equals(oldSlave)); deviceMaster.getConnectedConnectors()
//删除从的连接关系 .removeIf(x -> x.getConnectorId().equals(oldSlave));
// 删除从的连接关系
NettyDevice oldSlaveDevice = sessionManager.getDevice(oldSlave); NettyDevice oldSlaveDevice = sessionManager.getDevice(oldSlave);
if (oldSlaveDevice != null && !CollectionUtils.isEmpty(oldSlaveDevice.getConnectedConnectors())) { if (oldSlaveDevice != null
Set<com.maibu.core.business.device.Connector> connectedDevices = oldSlaveDevice.getConnectedConnectors(); && !CollectionUtils.isEmpty(oldSlaveDevice.getConnectedConnectors())) {
Set<com.maibu.core.business.device.Connector> connectedDevices = oldSlaveDevice
.getConnectedConnectors();
connectedDevices.removeIf(x -> x.getConnectorId().equals(masterId)); connectedDevices.removeIf(x -> x.getConnectorId().equals(masterId));
} }
} }
@@ -130,21 +132,20 @@ public class TransferDeviceService {
} }
} }
public AjaxResult updateDeviceAlias(DeviceBindDTO bindDTO, LoginUser user) { public AjaxResult updateDeviceAlias(DeviceBindDTO bindDTO, LoginUser user) {
try { try {
String deviceId = bindDTO.getDeviceId(); String deviceId = bindDTO.getDeviceId();
//判断当前设备是否存 // 判断当前设备是否存
Device device = iDeviceService.selectDeviceBySerialNumber(deviceId); Device device = iDeviceService.selectDeviceBySerialNumber(deviceId);
if (device == null) { if (device == null) {
return AjaxResult.error("设备不存在"); return AjaxResult.error("设备不存在");
} else { } else {
// Long tenantId = device.getTenantId(); // Long tenantId = device.getTenantId();
// if (tenantId == -1) { // if (tenantId == -1) {
// return AjaxResult.error("设备未绑定"); // return AjaxResult.error("设备未绑定");
// } // }
// if (!tenantId.equals(user.getUserId())) { // if (!tenantId.equals(user.getUserId())) {
// return AjaxResult.error("无操作权限"); // return AjaxResult.error("无操作权限");
// } // }
device.setDeviceAlias(bindDTO.getDeviceAlias()); device.setDeviceAlias(bindDTO.getDeviceAlias());
device.setUpdateTime(LocalDateTime.now()); device.setUpdateTime(LocalDateTime.now());
@@ -158,76 +159,76 @@ public class TransferDeviceService {
} }
} }
// public synchronized boolean switchDevice(DeviceBindDTO bindDTO, LoginUser user) { // public synchronized boolean switchDevice(DeviceBindDTO bindDTO, LoginUser
// try { // user) {
// String slaveId = bindDTO.getDeviceId(); // try {
// String platform = bindDTO.getPlatform(); // String slaveId = bindDTO.getDeviceId();
// String userName = user.getUsername(); // String platform = bindDTO.getPlatform();
// String masterId = userName + ":" + platform; // String userName = user.getUsername();
// //todo 判断是否有权限 正在控制才能切 // String masterId = userName + ":" + platform;
// //todo 离线没有控制权的怎么切 // //todo 判断是否有权限 正在控制才能切
// log.info("switchDevice:{}", masterId); // //todo 离线没有控制权的怎么切
// NettyDevice deviceMaster = sessionManager.getDevice(masterId); // log.info("switchDevice:{}", masterId);
// log.info("deviceMaster:{}", deviceMaster); // NettyDevice deviceMaster = sessionManager.getDevice(masterId);
// if (deviceMaster != null) { // log.info("deviceMaster:{}", deviceMaster);
// log.info("ConnectorStatus:{}", deviceMaster.getConnectorStatus()); // if (deviceMaster != null) {
// if (ConnectorStatus.RECEIVER.equals(deviceMaster.getConnectorStatus())) { // log.info("ConnectorStatus:{}", deviceMaster.getConnectorStatus());
// //当前账号没有控制则可以切换为控制? // if (ConnectorStatus.RECEIVER.equals(deviceMaster.getConnectorStatus())) {
// NettyDevice activeDevice = sessionManager.getUserControl(userName); // //当前账号没有控制则可以切换为控制?
// deviceMaster.getConnectedConnectors().clear(); // NettyDevice activeDevice = sessionManager.getUserControl(userName);
// if (activeDevice == null) { // deviceMaster.getConnectedConnectors().clear();
// log.info("bindConnector ACTIVE :{}", masterId); // if (activeDevice == null) {
// sessionManager.bindConnector(masterId, slaveId); // log.info("bindConnector ACTIVE :{}", masterId);
// deviceMaster.setConnectorStatus(ConnectorStatus.ACTIVE); // sessionManager.bindConnector(masterId, slaveId);
// deviceMaster.setCurrentSlaveId(slaveId); // deviceMaster.setConnectorStatus(ConnectorStatus.ACTIVE);
// sysUserClientService.updateAliveStatus(masterId, slaveId, 1); // deviceMaster.setCurrentSlaveId(slaveId);
// } else { // sysUserClientService.updateAliveStatus(masterId, slaveId, 1);
// log.info("bindConnector RECEIVER :{}", masterId); // } else {
// sessionManager.bindConnector(masterId, slaveId); // log.info("bindConnector RECEIVER :{}", masterId);
// deviceMaster.setConnectorStatus(ConnectorStatus.RECEIVER); // sessionManager.bindConnector(masterId, slaveId);
// deviceMaster.setCurrentSlaveId(slaveId); // deviceMaster.setConnectorStatus(ConnectorStatus.RECEIVER);
// sysUserClientService.updateAliveStatus(masterId, slaveId, 2); // deviceMaster.setCurrentSlaveId(slaveId);
// } // sysUserClientService.updateAliveStatus(masterId, slaveId, 2);
// } else { // }
// //从关联其他设备切换到 当前禁言 假如有控制且不是当前更新为2 // } else {
// List<NettyDevice> controls = sessionManager.getSlaveControl(slaveId); // //从关联其他设备切换到 当前禁言 假如有控制且不是当前更新为2
// if (CollectionUtils.isEmpty(controls)) { // List<NettyDevice> controls = sessionManager.getSlaveControl(slaveId);
// deviceMaster.getConnectedConnectors().clear(); // if (CollectionUtils.isEmpty(controls)) {
// log.info("bindConnector 1:{}", masterId); // deviceMaster.getConnectedConnectors().clear();
// sessionManager.bindConnector(masterId, slaveId); // log.info("bindConnector 1:{}", masterId);
// deviceMaster.setConnectorStatus(ConnectorStatus.ACTIVE); // sessionManager.bindConnector(masterId, slaveId);
// deviceMaster.setCurrentSlaveId(slaveId); // deviceMaster.setConnectorStatus(ConnectorStatus.ACTIVE);
// sysUserClientService.updateAliveStatus(masterId, slaveId, 1); // deviceMaster.setCurrentSlaveId(slaveId);
// } else { // sysUserClientService.updateAliveStatus(masterId, slaveId, 1);
// NettyDevice controlDevice = controls.get(0); // } else {
// if (!masterId.equals(controlDevice.getConnectorId())) { // NettyDevice controlDevice = controls.get(0);
// //当前的设备有控制 的主机 // if (!masterId.equals(controlDevice.getConnectorId())) {
// deviceMaster.getConnectedConnectors().clear(); // //当前的设备有控制 的主机
// log.info("bindConnector RECEIVER 2:{}", masterId); // deviceMaster.getConnectedConnectors().clear();
// sessionManager.bindConnector(masterId, slaveId); // log.info("bindConnector RECEIVER 2:{}", masterId);
// deviceMaster.setConnectorStatus(ConnectorStatus.RECEIVER); // sessionManager.bindConnector(masterId, slaveId);
// deviceMaster.setCurrentSlaveId(slaveId); // deviceMaster.setConnectorStatus(ConnectorStatus.RECEIVER);
// sysUserClientService.updateAliveStatus(masterId, slaveId, 2); // deviceMaster.setCurrentSlaveId(slaveId);
// } // sysUserClientService.updateAliveStatus(masterId, slaveId, 2);
// //当前 切当前不做操作 // }
// } // //当前 切当前不做操作
// } // }
// return true; // }
// } // return true;
// } catch (Exception e) { // }
// log.error("切换设备失败: {}", e.getMessage(), e); // } catch (Exception e) {
// } // log.error("切换设备失败: {}", e.getMessage(), e);
// return false; // }
// } // return false;
// }
public synchronized boolean switchDevice(DeviceBindDTO bindDTO) { public synchronized boolean switchDevice(DeviceBindDTO bindDTO) {
try { try {
String slaveId = bindDTO.getDeviceId(); String slaveId = bindDTO.getDeviceId();
// String platform = bindDTO.getPlatform(); // String platform = bindDTO.getPlatform();
// String userName = user.getUsername(); // String userName = user.getUsername();
// String masterId = userName + ":" + platform;
// String masterId = userName + ":" + platform;
String token = bindDTO.getToken(); String token = bindDTO.getToken();
@@ -247,9 +248,10 @@ public class TransferDeviceService {
sessionManager.lock(slaveId, token); sessionManager.lock(slaveId, token);
log.info("switchDevice bindConnector slaveId:{},token:{}", slaveId, token); log.info("switchDevice bindConnector slaveId:{},token:{}", slaveId, token);
} else { } else {
List<String> connectorIds = controls.stream().map(NettyDevice::getConnectorId).collect(Collectors.toList()); List<String> connectorIds = controls.stream().map(NettyDevice::getConnectorId)
.collect(Collectors.toList());
if (!connectorIds.contains(token)) { if (!connectorIds.contains(token)) {
//当前的设备有控制 的主机 // 当前的设备有控制 的主机
deviceMaster.getConnectedConnectors().clear(); deviceMaster.getConnectedConnectors().clear();
sessionManager.bindConnector(token, slaveId); sessionManager.bindConnector(token, slaveId);
deviceMaster.setConnectorStatus(ConnectorStatus.RECEIVER); deviceMaster.setConnectorStatus(ConnectorStatus.RECEIVER);
@@ -260,16 +262,15 @@ public class TransferDeviceService {
deviceMaster.setCurrentSlaveId(slaveId); deviceMaster.setCurrentSlaveId(slaveId);
sessionManager.lock(slaveId, token); sessionManager.lock(slaveId, token);
} }
//当前 切当前不做操作 // 当前 切当前不做操作
} }
return true; return true;
} catch (Exception e) { } catch (Exception e) {
log.error("切换设备失败: {}", e.getMessage(), e); log.error("切换设备失败", e);
} }
return false; return false;
} }
public DeviceControlDTO remoteControl(DeviceBindDTO bindDTO) { public DeviceControlDTO remoteControl(DeviceBindDTO bindDTO) {
try { try {
String token = bindDTO.getToken(); String token = bindDTO.getToken();
@@ -290,7 +291,6 @@ public class TransferDeviceService {
return null; return null;
} }
public DeviceSwitchControlDTO switchControl(DeviceBindDTO bindDTO, LoginUser user) { public DeviceSwitchControlDTO switchControl(DeviceBindDTO bindDTO, LoginUser user) {
try { try {
String slaveId = bindDTO.getDeviceId(); String slaveId = bindDTO.getDeviceId();
@@ -299,11 +299,11 @@ public class TransferDeviceService {
String masterId = userName + ":" + platform; String masterId = userName + ":" + platform;
DeviceSwitchControlDTO dto = new DeviceSwitchControlDTO(); DeviceSwitchControlDTO dto = new DeviceSwitchControlDTO();
//收到明确的切换设备请求了 从哪边切换到另一边 // 收到明确的切换设备请求了 从哪边切换到另一边
//判断当前是否有控制的设备 // 判断当前是否有控制的设备
NettyDevice masterDevice = sessionManager.getDevice(masterId); NettyDevice masterDevice = sessionManager.getDevice(masterId);
if (masterDevice == null || !masterDevice.getChannel().isActive()) { if (masterDevice == null || !masterDevice.getChannel().isActive()) {
//主机已离线 // 主机已离线
dto.setSwitchControl(false); dto.setSwitchControl(false);
dto.setReason("主机已离线"); dto.setReason("主机已离线");
return dto; return dto;
@@ -311,8 +311,8 @@ public class TransferDeviceService {
NettyDevice slaveDevice = sessionManager.getDevice(slaveId); NettyDevice slaveDevice = sessionManager.getDevice(slaveId);
if (slaveDevice == null || !masterDevice.getChannel().isActive()) { if (slaveDevice == null || !masterDevice.getChannel().isActive()) {
//从机已离线 // 从机已离线
//主机已离线 // 主机已离线
dto.setSwitchControl(false); dto.setSwitchControl(false);
dto.setReason("从机已离线"); dto.setReason("从机已离线");
return dto; return dto;
@@ -321,7 +321,7 @@ public class TransferDeviceService {
List<NettyDevice> controlList = sessionManager.getSlaveControl(slaveId); List<NettyDevice> controlList = sessionManager.getSlaveControl(slaveId);
if (!CollectionUtils.isEmpty(controlList)) { if (!CollectionUtils.isEmpty(controlList)) {
//如果当前设备有控制 // 如果当前设备有控制
controlList.forEach(c -> { controlList.forEach(c -> {
if (!c.getConnectorId().equals(masterId)) { if (!c.getConnectorId().equals(masterId)) {
c.setCurrentSlaveId(null); c.setCurrentSlaveId(null);
@@ -333,7 +333,8 @@ public class TransferDeviceService {
} }
masterDevice.setCurrentSlaveId(slaveId); masterDevice.setCurrentSlaveId(slaveId);
masterDevice.setConnectorStatus(ConnectorStatus.ACTIVE); masterDevice.setConnectorStatus(ConnectorStatus.ACTIVE);
// sysUserClientService.updateAliveStatus(masterDevice.getConnectorId(), slaveId, 1); // sysUserClientService.updateAliveStatus(masterDevice.getConnectorId(),
// slaveId, 1);
dto.setSwitchControl(true); dto.setSwitchControl(true);
dto.setHolder(platform); dto.setHolder(platform);

View File

@@ -0,0 +1,65 @@
[
{
"paramType": "global",
"paramKey": "systemName",
"nameTranslateKey": "system.param.systemName.name",
"paramValue": "光伏机器人环境感知服务平台",
"descTranslateKey": "system.param.systemName.desc",
"dataType": "String",
"range": ""
},
{
"paramType": "global",
"paramKey": "defaultStationName",
"nameTranslateKey": "system.param.defaultStationName.name",
"paramValue": "",
"descTranslateKey": "system.param.defaultStationName.desc",
"dataType": "String",
"range": ""
},
{
"paramType": "global",
"paramKey": "defaultLanguage",
"nameTranslateKey": "system.param.defaultLanguage.name",
"paramValue": "zh_CN",
"descTranslateKey": "system.param.defaultLanguage.desc",
"dataType": "String",
"range": ""
},
{
"paramType": "global",
"paramKey": "defaultZoneId",
"nameTranslateKey": "system.param.defaultZoneId.name",
"paramValue": "Asia/Shanghai",
"descTranslateKey": "system.param.defaultZoneId.desc",
"dataType": "String",
"range": ""
},
{
"paramType": "global",
"paramKey": "daylightSavingTime",
"nameTranslateKey": "system.param.daylightSavingTime.name",
"paramValue": "true",
"descTranslateKey": "system.param.daylightSavingTime.desc",
"dataType": "Boolean",
"range": ""
},
{
"paramType": "global",
"paramKey": "defaultUnit",
"nameTranslateKey": "system.param.defaultUnit.name",
"paramValue": "公制",
"descTranslateKey": "system.param.defaultUnit.desc",
"dataType": "String",
"range": ""
},
{
"paramType": "global",
"paramKey": "defaultDateFormat",
"nameTranslateKey": "system.param.defaultDateFormat.name",
"paramValue": "YYYY-MM-DD HH:mm:ss",
"descTranslateKey": "system.param.defaultDateFormat.desc",
"dataType": "String",
"range": ""
}
]

View File

@@ -8,13 +8,20 @@ import com.maibu.dto.BaseQueryDTO;
import com.maibu.service.impl.DeviceRunParamService; import com.maibu.service.impl.DeviceRunParamService;
import com.maibu.utils.poi.ExcelUtil; import com.maibu.utils.poi.ExcelUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*; 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.InputStream;
import java.net.URLEncoder;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
@RestController @RestController
@RequestMapping("/iot/deviceRunParam") @RequestMapping("/iot/deviceRunParam")
public class DeviceRunParamController extends BaseController { public class DeviceRunParamController extends BaseController {
@@ -23,7 +30,7 @@ public class DeviceRunParamController extends BaseController {
private DeviceRunParamService service; private DeviceRunParamService service;
@PostMapping("/save") @PostMapping("/save")
public AjaxResult save(@RequestBody DeviceRunParam deviceRunParam) throws ExecutionException, InterruptedException, TimeoutException { public AjaxResult save(@RequestBody DeviceRunParam deviceRunParam) {
return AjaxResult.success(service.save(deviceRunParam)); return AjaxResult.success(service.save(deviceRunParam));
} }
@@ -35,7 +42,8 @@ public class DeviceRunParamController extends BaseController {
} }
@GetMapping("/selectByDeviceId") @GetMapping("/selectByDeviceId")
public AjaxResult selectByDeviceId(@RequestParam String deviceId) throws ExecutionException, InterruptedException, TimeoutException { public AjaxResult selectByDeviceId(@RequestParam String deviceId)
throws ExecutionException, InterruptedException, TimeoutException {
return AjaxResult.success(service.selectByDeviceId(deviceId)); return AjaxResult.success(service.selectByDeviceId(deviceId));
} }
@@ -43,7 +51,7 @@ public class DeviceRunParamController extends BaseController {
public AjaxResult delete(@RequestBody List<Long> ids) { public AjaxResult delete(@RequestBody List<Long> ids) {
return AjaxResult.success(service.delete(ids)); return AjaxResult.success(service.delete(ids));
} }
@PostMapping("/importData") @PostMapping("/importData")
public AjaxResult importData(MultipartFile file) throws Exception { public AjaxResult importData(MultipartFile file) throws Exception {
ExcelUtil<DeviceRunParam> util = new ExcelUtil<DeviceRunParam>(DeviceRunParam.class); ExcelUtil<DeviceRunParam> util = new ExcelUtil<DeviceRunParam>(DeviceRunParam.class);
@@ -51,4 +59,31 @@ public class DeviceRunParamController extends BaseController {
boolean message = service.importParam(paramList); boolean message = service.importParam(paramList);
return success(message); return success(message);
} }
/**
* 下载机器属性导入模板
*/
@GetMapping("/downloadTemplate")
public void downloadTemplate(HttpServletResponse response) throws IOException {
String fileName = "机器属性导入模板.xlsx";
try (InputStream inputStream = new ClassPathResource("机器属性导入模板.xlsx").getInputStream()) {
response.setContentType(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("UTF-8");
response.setHeader(
"Content-Disposition",
"attachment; filename*=UTF-8''" +
URLEncoder.encode(fileName, "UTF-8").replace("+", "%20"));
ServletOutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[8192];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
outputStream.flush();
}
}
} }

View File

@@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
@@ -18,11 +19,13 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.device.NettyDevice; import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.dto.WebRouteStatusMessageDTO; import com.maibu.core.business.dto.WebRouteStatusMessageDTO;
import com.maibu.core.business.inter.WebsocketMesDispather; import com.maibu.core.business.inter.WebsocketMesDispather;
import com.maibu.core.business.path.LatAndLngEntity; import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.controller.BaseController; import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.R; import com.maibu.core.domain.R;
import com.maibu.core.enums.MesType; import com.maibu.core.enums.MesType;
import com.maibu.memory.DeviceSessionManager; import com.maibu.memory.DeviceSessionManager;
@@ -245,4 +248,12 @@ public class HostComputerController extends BaseController {
String.format("%.6f", minLng), String.format("%.6f", maxLng)); String.format("%.6f", minLng), String.format("%.6f", maxLng));
} }
@GetMapping("/searchDevice")
public AjaxResult searchDevice(@RequestParam String deviceId) throws Exception {
hostComputerService.searchDevice(deviceId);
return success();
}
} }

View File

@@ -3,14 +3,11 @@ package com.maibu.controller;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.OrderModel; import com.maibu.core.business.OrderModel;
import com.maibu.core.controller.BaseController; import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult; import com.maibu.core.domain.AjaxResult;

View File

@@ -1,7 +1,10 @@
package com.maibu.service.impl; package com.maibu.service.impl;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -39,47 +42,55 @@ public class DeviceRunParamService {
@Autowired @Autowired
private DeviceSessionManager sessionManager; private DeviceSessionManager sessionManager;
public boolean save(DeviceRunParam deviceRunParam) // public boolean save(DeviceRunParam deviceRunParam)
throws ExecutionException, InterruptedException, TimeoutException { // throws ExecutionException, InterruptedException, TimeoutException {
NettyDevice nettyDevice = sessionManager.getDevice(deviceRunParam.getDeviceId()); // NettyDevice nettyDevice =
if (nettyDevice == null || !nettyDevice.getChannel().isActive()) { // sessionManager.getDevice(deviceRunParam.getDeviceId());
throw new ServiceException("设备不在线,无法操作!"); // if (nettyDevice == null || !nettyDevice.getChannel().isActive()) {
} // throw new ServiceException("设备不在线,无法操作!");
// }
CompletableFuture<DeviceRunParam> future = new CompletableFuture<>(); // CompletableFuture<DeviceRunParam> future = new CompletableFuture<>();
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(future); // nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(future);
try { // try {
nettyDevice.readConfigCommand(); // nettyDevice.readConfigCommand();
DeviceRunParam param = future.get(5, TimeUnit.SECONDS); // DeviceRunParam param = future.get(5, TimeUnit.SECONDS);
if (param == null) { // if (param == null) {
throw new ServiceException("获取设备当前属性失败!"); // throw new ServiceException("获取设备当前属性失败!");
} // }
param.setLeftForwardGain(deviceRunParam.getLeftForwardGain()); // param.setLeftForwardGain(deviceRunParam.getLeftForwardGain());
param.setLeftBackwardGain(deviceRunParam.getLeftBackwardGain()); // param.setLeftBackwardGain(deviceRunParam.getLeftBackwardGain());
param.setRightForwardGain(deviceRunParam.getRightForwardGain()); // param.setRightForwardGain(deviceRunParam.getRightForwardGain());
param.setRightBackwardGain(deviceRunParam.getRightBackwardGain()); // param.setRightBackwardGain(deviceRunParam.getRightBackwardGain());
nettyDevice.writeConfigCommand(param); // nettyDevice.writeConfigCommand(param);
param.setRunSpeed(deviceRunParam.getRunSpeed()); // param.setRunSpeed(deviceRunParam.getRunSpeed());
param.setDeviceId(deviceRunParam.getDeviceId()); // param.setDeviceId(deviceRunParam.getDeviceId());
param.setSiteId(deviceRunParam.getSiteId()); // param.setSiteId(deviceRunParam.getSiteId());
param.setOrgId(deviceRunParam.getOrgId()); // param.setOrgId(deviceRunParam.getOrgId());
param.setId(deviceRunParam.getId()); // param.setId(deviceRunParam.getId());
// SiteMemory siteMemory = GlobalMemory.getSiteMemory(deviceRunParam.getOrgId(),
// deviceRunParam.getSiteId());
// if (siteMemory != null) {
// siteMemory.saveDeviceRunParam(param);
// }
// return deviceRunParamMapper.saveOrUpdate(param);
// } finally {
// nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(null);
// }
// }
public boolean save(DeviceRunParam deviceRunParam) {
return deviceRunParamMapper.saveOrUpdate(deviceRunParam);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(deviceRunParam.getOrgId(), deviceRunParam.getSiteId());
if (siteMemory != null) {
siteMemory.saveDeviceRunParam(param);
}
return deviceRunParamMapper.saveOrUpdate(param);
} finally {
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(null);
}
} }
public List<DeviceRunParam> list(BaseQueryDTO dto) { public List<DeviceRunParam> list(BaseQueryDTO dto) {
@@ -127,6 +138,49 @@ public class DeviceRunParamService {
// return null; // return null;
// } // }
// public DeviceRunParam selectByDeviceId(String deviceId)
// throws ExecutionException, InterruptedException, TimeoutException {
// LambdaQueryWrapper<DeviceRunParam> queryWrapper = new LambdaQueryWrapper<>();
// if (!StringUtils.isEmpty(deviceId)) {
// queryWrapper.eq(DeviceRunParam::getDeviceId, deviceId);
// }
// DeviceRunParam result = deviceRunParamMapper.selectOne(queryWrapper);
// if (result != null && result.getHasHost() != null && result.getHasHost() ==
// 1) {
// return result;
// } else {
// NettyDevice nettyDevice = sessionManager.getDevice(deviceId);
// CompletableFuture<DeviceRunParam> future = new CompletableFuture<>();
// if (nettyDevice != null && nettyDevice.getChannel() != null &&
// nettyDevice.getChannel().isActive()) {
// nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(future);
// try {
// nettyDevice.readConfigCommand();
// DeviceRunParam param = future.get(5, TimeUnit.SECONDS);
// // LambdaQueryWrapper<DeviceRunParam> queryWrapper = new
// LambdaQueryWrapper<>();
// // if (!StringUtils.isEmpty(deviceId)) {
// // queryWrapper.eq(DeviceRunParam::getDeviceId, deviceId);
// // }
// // DeviceRunParam result = deviceRunParamMapper.selectOne(queryWrapper);
// if (result != null) {
// param.setId(result.getId());
// param.setDeviceId(result.getDeviceId());
// param.setRunSpeed(result.getRunSpeed());
// param.setOrgId(nettyDevice.getDevice().getOrgId());
// param.setSiteId(nettyDevice.getDevice().getSiteId());
// }
// return param;
// } finally {
// nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(null);
// }
// }
// }
// return null;
// }
public DeviceRunParam selectByDeviceId(String deviceId) public DeviceRunParam selectByDeviceId(String deviceId)
throws ExecutionException, InterruptedException, TimeoutException { throws ExecutionException, InterruptedException, TimeoutException {
@@ -135,36 +189,7 @@ public class DeviceRunParamService {
queryWrapper.eq(DeviceRunParam::getDeviceId, deviceId); queryWrapper.eq(DeviceRunParam::getDeviceId, deviceId);
} }
DeviceRunParam result = deviceRunParamMapper.selectOne(queryWrapper); DeviceRunParam result = deviceRunParamMapper.selectOne(queryWrapper);
if (result != null && result.getHasHost() != null && result.getHasHost() == 1) { return result;
return result;
} else {
NettyDevice nettyDevice = sessionManager.getDevice(deviceId);
CompletableFuture<DeviceRunParam> future = new CompletableFuture<>();
if (nettyDevice != null && nettyDevice.getChannel() != null && nettyDevice.getChannel().isActive()) {
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(future);
try {
nettyDevice.readConfigCommand();
DeviceRunParam param = future.get(5, TimeUnit.SECONDS);
// LambdaQueryWrapper<DeviceRunParam> queryWrapper = new LambdaQueryWrapper<>();
// if (!StringUtils.isEmpty(deviceId)) {
// queryWrapper.eq(DeviceRunParam::getDeviceId, deviceId);
// }
// DeviceRunParam result = deviceRunParamMapper.selectOne(queryWrapper);
if (result != null) {
param.setId(result.getId());
param.setDeviceId(result.getDeviceId());
param.setRunSpeed(result.getRunSpeed());
param.setOrgId(nettyDevice.getDevice().getOrgId());
param.setSiteId(nettyDevice.getDevice().getSiteId());
}
return param;
} finally {
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(null);
}
}
}
return null;
} }
public int delete(List<Long> ids) { public int delete(List<Long> ids) {
@@ -211,19 +236,51 @@ public class DeviceRunParamService {
} }
if (deviceRunParam != null) { if (deviceRunParam != null) {
deviceRunParam.setCapabilityList(x.getCapabilityList()); deviceRunParam.setCapabilityList(x.getCapabilityList());
deviceRunParam.setDeviceId(x.getDeviceId());
parseSn(x.getDeviceId(), deviceRunParam);
deviceRunParam.setProductModel(x.getProductModel()); deviceRunParam.setProductModel(x.getProductModel());
deviceRunParam.setRtkMode(x.getRtkMode());
deviceRunParam.setDeviceType(x.getDeviceType()); deviceRunParam.setDeviceType(x.getDeviceType());
deviceRunParam.setPowerType(x.getPowerType()); deviceRunParam.setRtkMode(x.getRtkMode());
deviceRunParam.setCameraNum(x.getCameraNum()); deviceRunParam.setCameraNum(x.getCameraNum());
deviceRunParam.setPowerType(x.getPowerType());
deviceRunParam.setWheelType(x.getWheelType()); deviceRunParam.setWheelType(x.getWheelType());
deviceRunParam.setEngineType(x.getEngineType()); deviceRunParam.setEngineType(x.getEngineType());
deviceRunParam.setHasHost(x.getHasHost()); deviceRunParam.setHasHost(x.getHasHost());
deviceRunParam.setBatteryType(x.getBatteryType());
deviceRunParam.setWalkingDriveType(x.getWalkingDriveType());
deviceRunParam.setCutterDriveType(x.getCutterDriveType());
deviceRunParam.setRtkAntennasNum(x.getRtkAntennasNum());
deviceRunParam.setHandleType(x.getHandleType());
deviceRunParam.setPcbVersion(x.getPcbVersion());
deviceRunParam.setDimensions(x.getDimensions());
deviceRunParam.setBladeWidth(x.getBladeWidth());
deviceRunParam.setTyreSize(x.getTyreSize());
deviceRunParam.setSpeedRatio(x.getSpeedRatio());
deviceRunParam.setCellularInfo(x.getCellularInfo());
deviceRunParam.setWifiName(x.getWifiName());
deviceRunParam.setBluetoothName(x.getBluetoothName());
deviceRunParam.setHardwareIdentifiers(x.getHardwareIdentifiers());
deviceRunParam.setImuModel(x.getImuModel());
deviceRunParam.setTempHumiditySensor(x.getTempHumiditySensor());
deviceRunParam.setBarometerPresent(x.getBarometerPresent());
deviceRunParam.setUltrasonicPresent(x.getUltrasonicPresent());
deviceRunParam.setDacPresent(x.getDacPresent());
deviceRunParam.setOperator(x.getOperator());
deviceRunParam.setInspectionNo(x.getInspectionNo());
deviceRunParam.setFirmwareVersion(x.getFirmwareVersion());
deviceRunParam.setDealer(x.getDealer());
saveList.add(deviceRunParam); saveList.add(deviceRunParam);
} else { } else {
parseSn(x.getDeviceId(), x);
saveList.add(x); saveList.add(x);
} }
}); });
// todo 增加 解析sn码的功能
return deviceRunParamMapper.saveOrUpdateBatch(saveList); return deviceRunParamMapper.saveOrUpdateBatch(saveList);
} }
} }
@@ -233,4 +290,21 @@ public class DeviceRunParamService {
} }
} }
public static void parseSn(String sn, DeviceRunParam deviceRunParam) {
if (sn == null || sn.length() != 21) {
throw new IllegalArgumentException("SN 必须是 21 位字符串");
}
deviceRunParam.setProductModel(sn.substring(0, 2));
deviceRunParam.setFactoryCode(sn.substring(2, 4));
deviceRunParam.setLineNum(sn.substring(4, 6));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMdd");
LocalDate date = LocalDate.parse(sn.substring(6, 12), formatter);
deviceRunParam.setProductionDate(date);
deviceRunParam.setSerialNumber(sn.substring(12, 17));
}
} }

View File

@@ -1,18 +1,25 @@
package com.maibu.service.impl; package com.maibu.service.impl;
import com.maibu.core.business.WorkRecord;
import com.maibu.memory.GlobalMemory;
import lombok.extern.slf4j.Slf4j;
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 com.maibu.core.business.device.NettyDevice;
import com.maibu.memory.DeviceSessionManager;
import lombok.extern.slf4j.Slf4j;
@Service @Service
@Slf4j @Slf4j
public class HostComputerService { public class HostComputerService {
@Autowired @Autowired
private WorkRecordService workRecordService; private DeviceSessionManager deviceSessionManager;
public void searchDevice(String deviceId) throws Exception {
NettyDevice device = deviceSessionManager.getDevice(deviceId);
if (device != null && device.getOnlineStatus() == 1) {
device.searchDevice(deviceId);
}
}
} }

View File

@@ -0,0 +1,14 @@
package com.maibu.mapper;
import org.springframework.stereotype.Repository;
import com.maibu.core.domain.entity.SysParam;
import com.maibu.mybatis.mapper.BaseMapperX;
/**
* 设备历史状态
*/
@Repository
public interface SysParamMapper extends BaseMapperX<SysParam> {
}

View File

@@ -0,0 +1,46 @@
package com.maibu.service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.core.domain.entity.SysParam;
import com.maibu.core.enums.SysParamType;
import com.maibu.mapper.SysParamMapper;
import com.maibu.utils.MessageUtils;
@Service
public class SysParamService {
@Autowired
private SysParamMapper sysParamMapper;
public Map<SysParamType, List<SysParam>> list() {
LambdaQueryWrapper<SysParam> queryWrapper = new LambdaQueryWrapper<>();
List<SysParam> sysParams = sysParamMapper.selectList(queryWrapper);
translateSysParam(sysParams);
Map<SysParamType, List<SysParam>> result = sysParams.stream()
.collect(Collectors.groupingBy(SysParam::getParamType));
return result;
}
public void translateSysParam(List<SysParam> sysParams) {
if (!CollectionUtils.isEmpty(sysParams)) {
sysParams.forEach(x -> {
x.setNameTranslate(MessageUtils.message(x.getNameTranslateKey()));
x.setDescTranslate(MessageUtils.message(x.getDescTranslateKey()));
});
}
}
public boolean save(List<SysParam> sysParam) {
return sysParamMapper.saveOrUpdateBatch(sysParam);
}
}

View File

@@ -1,15 +1,6 @@
package com.maibu.service; package com.maibu.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import java.util.List;
import com.maibu.core.business.Device;
import com.maibu.core.domain.entity.SysRole;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.model.LoginUser;
import com.maibu.exception.ServiceException;
import com.maibu.mapper.SysRegionMapper;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -17,8 +8,13 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.List; import com.maibu.core.domain.entity.SysRole;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.model.LoginUser;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
@Service @Service
public class SysSiteService { public class SysSiteService {

View File

@@ -1,9 +1,12 @@
package com.maibu.control; package com.maibu.control;
import lombok.Data;
@Data
public class DiffSteer { public class DiffSteer {
public static final int Polarity_High = 0; //0 public static final int Polarity_High = 0; // 0
public static final int Polarity_Low = 0; //1 public static final int Polarity_Low = 0; // 1
private float turnSpeedScale; private float turnSpeedScale;
private float forwardSpeedScale; private float forwardSpeedScale;
@@ -15,6 +18,9 @@ public class DiffSteer {
private int leftWheelSpeed; private int leftWheelSpeed;
private int rightWheelSpeed; private int rightWheelSpeed;
private double linearSpeed;
private double angularSpeed;
public int getLeftWheelSpeed() { public int getLeftWheelSpeed() {
return leftWheelSpeed; return leftWheelSpeed;
} }
@@ -63,6 +69,14 @@ public class DiffSteer {
rightWheelSpeed = clamp(rightWheelSpeed, -speedAmplLimit, speedAmplLimit); rightWheelSpeed = clamp(rightWheelSpeed, -speedAmplLimit, speedAmplLimit);
} }
// 计算线速度和轮速度
public void calcLinearAngularSpeed(int x, int y, int maxLinear, int maxAngular) {
this.linearSpeed = y * maxLinear / 1000.0;
this.angularSpeed = x * maxAngular / 1000.0;
}
// 设置前向速比 // 设置前向速比
public void setTurnSpeedScale(int turnSpeedMax, int xMax) { public void setTurnSpeedScale(int turnSpeedMax, int xMax) {
this.turnSpeedScale = (float) turnSpeedMax / (float) xMax; this.turnSpeedScale = (float) turnSpeedMax / (float) xMax;
@@ -88,5 +102,4 @@ public class DiffSteer {
return (val < min) ? min : ((val > max) ? max : val); return (val < min) ? min : ((val > max) ? max : val);
} }
} }

View File

@@ -8,6 +8,7 @@ import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.maibu.core.business.dto.WebDeviceTaskStatusMessageDTO; import com.maibu.core.business.dto.WebDeviceTaskStatusMessageDTO;
import com.maibu.core.business.dto.WebOlineStatusMessageDTO;
import com.maibu.core.business.dto.WebStatusMessageDTO; import com.maibu.core.business.dto.WebStatusMessageDTO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.java_websocket.WebSocket; import org.java_websocket.WebSocket;
@@ -24,7 +25,6 @@ import com.maibu.dto.DeviceRespondDTO;
import com.maibu.dto.NettySwitchDeviceDTO; import com.maibu.dto.NettySwitchDeviceDTO;
import com.maibu.dto.ResultDTO; import com.maibu.dto.ResultDTO;
import com.maibu.dto.WebAuthResponseDTO; import com.maibu.dto.WebAuthResponseDTO;
import com.maibu.dto.WebOlineStatusMessageDTO;
import com.maibu.dto.WebSwitchControlResponseDTO; import com.maibu.dto.WebSwitchControlResponseDTO;
import com.maibu.memory.MiddleGlobalMemory; import com.maibu.memory.MiddleGlobalMemory;
import com.maibu.netty.NettyClient; import com.maibu.netty.NettyClient;

View File

@@ -1,9 +1,8 @@
package com.maibu.utils; package com.maibu.utils;
import com.maibu.common.MiddleCommandConstant; import com.maibu.common.MiddleCommandConstant;
import com.maibu.control.DiffSteer; import com.maibu.control.DiffSteer;
import com.maibu.dto.LawnMoverProtocolEntity; import com.maibu.core.business.LawnMoverProtocolEntity;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
@@ -11,24 +10,29 @@ import java.util.List;
public class ControlUtils { public class ControlUtils {
public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY,
public static LawnMoverProtocolEntity getCarControlMessage(DiffSteer diffSteer, int originX, int originY, List<Boolean> buttons) { List<Boolean> buttons, int maxLinear, int maxAngular) {
LawnMoverProtocolEntity state = new LawnMoverProtocolEntity(); LawnMoverProtocolEntity state = new LawnMoverProtocolEntity();
diffSteer.calcWheelSpeed(originX, originY); diffSteer.calcWheelSpeed(originX, originY);
diffSteer.calcLinearAngularSpeed(originX, originY, maxLinear, maxAngular);
state.setCommandType(MiddleCommandConstant.remoteControl); state.setCommandType(MiddleCommandConstant.remoteControl);
state.setLeftWheelSpeed((short) diffSteer.getLeftWheelSpeed()); state.setLeftWheelSpeed((short) diffSteer.getLeftWheelSpeed());
state.setRightWheelSpeed((short) diffSteer.getRightWheelSpeed()); state.setRightWheelSpeed((short) diffSteer.getRightWheelSpeed());
//对应的 button数组 L1 button【4】 R1 button【5】 A对应的button【0】 B对应button【1】 X对应button【2】 Y对应button【3】 button[7]急停 state.setLinearSpeed(diffSteer.getLinearSpeed());
//A升B降底盘 X割刀加速Y减速 L1点火 R1熄火 state.setAngularSpeed(diffSteer.getAngularSpeed());
// 对应的 button数组 L1 button【4】 R1 button【5】 A对应的button【0】 B对应button【1】
// X对应button【2】 Y对应button【3】 button[7]急停
// A升B降底盘 X割刀加速Y减速 L1点火 R1熄火
Boolean A = buttons.get(0); Boolean A = buttons.get(0);
Boolean B = buttons.get(1); Boolean B = buttons.get(1);
Boolean X = buttons.get(2); Boolean X = buttons.get(2);
Boolean Y = buttons.get(3); Boolean Y = buttons.get(3);
Boolean L1 = buttons.get(4); Boolean L1 = buttons.get(4);
Boolean R1 = buttons.get(5); Boolean R1 = buttons.get(5);
Boolean eStop = buttons.get(8); //急停 Boolean eStop = buttons.get(8); // 急停
//底盘升降 // 底盘升降
int chassisLiftFlag = 0; int chassisLiftFlag = 0;
if (A & !B) { if (A & !B) {
chassisLiftFlag = 1; chassisLiftFlag = 1;
@@ -36,7 +40,7 @@ public class ControlUtils {
chassisLiftFlag = 2; chassisLiftFlag = 2;
} }
state.setChassisLiftFlag((byte) chassisLiftFlag); state.setChassisLiftFlag((byte) chassisLiftFlag);
//割刀加减速 // 割刀加减速
int mowerSpeedFlag = 0; int mowerSpeedFlag = 0;
if (X & !Y) { if (X & !Y) {
mowerSpeedFlag = 1; mowerSpeedFlag = 1;
@@ -44,7 +48,7 @@ public class ControlUtils {
mowerSpeedFlag = 2; mowerSpeedFlag = 2;
} }
state.setMowerSpeedFlag((byte) mowerSpeedFlag); state.setMowerSpeedFlag((byte) mowerSpeedFlag);
//点火熄火 // 点火熄火
int ignitionFlag = 0; int ignitionFlag = 0;
if (L1 & !R1) { if (L1 & !R1) {
ignitionFlag = 1; ignitionFlag = 1;
@@ -55,26 +59,29 @@ public class ControlUtils {
int emergencyStopFlag = eStop ? 1 : 0; int emergencyStopFlag = eStop ? 1 : 0;
state.setEmergencyStopFlag((byte) emergencyStopFlag); state.setEmergencyStopFlag((byte) emergencyStopFlag);
// val toBytes = state.toBytes() // val toBytes = state.toBytes()
// println("toBytes==" + LawnMoverProtocolEntity.printBytesToHex(toBytes)) // println("toBytes==" + LawnMoverProtocolEntity.printBytesToHex(toBytes))
return state; return state;
} }
public static byte[] buildControlCommand(LawnMoverProtocolEntity entity) { public static byte[] buildControlCommand(LawnMoverProtocolEntity entity) {
ByteBuffer buffer = ByteBuffer.allocate(15); ByteBuffer buffer = ByteBuffer.allocate(27); // 15
buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put(entity.getHeader1()); buffer.put(entity.getHeader1());
buffer.put(entity.getHeader2()); buffer.put(entity.getHeader2());
buffer.put(entity.getCommandType()); buffer.put(entity.getCommandType());
buffer.putShort(entity.getLeftWheelSpeed());//左轮速度 // buffer.putShort(entity.getLeftWheelSpeed());//左轮速度
buffer.putShort(entity.getRightWheelSpeed());//右轮速度 // buffer.putShort(entity.getRightWheelSpeed());//右轮速度
buffer.put(entity.getChassisLiftFlag());//底盘升降 buffer.putDouble(entity.getAngularSpeed());// 左轮速度
buffer.put(entity.getMowerSpeedFlag());//割刀加减速 buffer.putDouble(entity.getLinearSpeed());// 右轮速度
buffer.put(entity.getIgnitionFlag());//点火状态
buffer.put(entity.getEmergencyStopFlag());//急停 buffer.put(entity.getChassisLiftFlag());// 底盘升降
buffer.put(entity.getMowerSpeedFlag());// 割刀加减速
buffer.put(entity.getIgnitionFlag());// 点火状态
buffer.put(entity.getEmergencyStopFlag());// 急停
buffer.put((byte) 0x00); buffer.put((byte) 0x00);
buffer.put((byte) 0x00); buffer.put((byte) 0x00);

View File

@@ -2,6 +2,7 @@ package com.maibu.websocket;
import com.maibu.constant.CommandConstant; import com.maibu.constant.CommandConstant;
import com.maibu.common.MiddleConstant; import com.maibu.common.MiddleConstant;
import com.maibu.core.business.LawnMoverProtocolEntity;
import com.maibu.core.enums.CommandRequestType; import com.maibu.core.enums.CommandRequestType;
import com.maibu.core.enums.MesType; import com.maibu.core.enums.MesType;
import com.maibu.dto.*; import com.maibu.dto.*;
@@ -36,7 +37,6 @@ import java.util.concurrent.TimeUnit;
public class WebsocketHandler extends WebSocketServer { public class WebsocketHandler extends WebSocketServer {
private static final Logger logger = LoggerFactory.getLogger(WebsocketHandler.class); private static final Logger logger = LoggerFactory.getLogger(WebsocketHandler.class);
// 存储客户端连接:key=WebSocket连接对象,value=最后一次活跃时间(毫秒) // 存储客户端连接:key=WebSocket连接对象,value=最后一次活跃时间(毫秒)
private final Map<WebSocket, Long> clientActiveTimeMap = new ConcurrentHashMap<>(); private final Map<WebSocket, Long> clientActiveTimeMap = new ConcurrentHashMap<>();
// 空闲超时时间(10秒):超过10秒无消息则判定为断开 // 空闲超时时间(10秒):超过10秒无消息则判定为断开
@@ -44,17 +44,17 @@ public class WebsocketHandler extends WebSocketServer {
// 定时检测线程池(每隔10秒检测一次空闲连接) // 定时检测线程池(每隔10秒检测一次空闲连接)
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
public WebsocketHandler(int port) { public WebsocketHandler(int port) {
super(new InetSocketAddress(port)); super(new InetSocketAddress(port));
// 启动空闲连接检测任务 // 启动空闲连接检测任务
// startIdleCheckTask(); // startIdleCheckTask();
} }
@Override @Override
public void onOpen(WebSocket conn, ClientHandshake handshake) { public void onOpen(WebSocket conn, ClientHandshake handshake) {
logger.info("客户端连接成功: remoteAddress={}, 当前在线数: {}", conn.getRemoteSocketAddress(), MiddleGlobalMemory.onlineSockets.size()); logger.info("客户端连接成功: remoteAddress={}, 当前在线数: {}", conn.getRemoteSocketAddress(),
MiddleGlobalMemory.onlineSockets.size());
} }
@Override @Override
@@ -62,7 +62,8 @@ public class WebsocketHandler extends WebSocketServer {
String key = MiddleGlobalMemory.findBySocket(conn); String key = MiddleGlobalMemory.findBySocket(conn);
if (key != null) { if (key != null) {
releaseResource(key); releaseResource(key);
logger.info("客户端断开连接: remoteAddress={}, code={}, reason={}, 当前在线数: {}", conn.getRemoteSocketAddress(), code, reason, MiddleGlobalMemory.onlineSockets.size()); logger.info("客户端断开连接: remoteAddress={}, code={}, reason={}, 当前在线数: {}", conn.getRemoteSocketAddress(), code,
reason, MiddleGlobalMemory.onlineSockets.size());
} }
MiddleGlobalMemory.removeByWebSocket(conn); MiddleGlobalMemory.removeByWebSocket(conn);
} }
@@ -100,32 +101,34 @@ public class WebsocketHandler extends WebSocketServer {
client.initConnect(MiddleConstant.vertxIp, 9001); client.initConnect(MiddleConstant.vertxIp, 9001);
} }
} else if (MesType.path.equals(type)) { } else if (MesType.path.equals(type)) {
//todo下发路径 预留 // todo下发路径 预留
pathDistribute(); pathDistribute();
} else if (MesType.remoteControl.equals(type)) { } else if (MesType.remoteControl.equals(type)) {
//遥控 // 遥控
RemoteData remoteData = webMessageBaseDTO.getRemoteData(); RemoteData remoteData = webMessageBaseDTO.getRemoteData();
if (remoteData != null) { if (remoteData != null) {
List<Double> axes = remoteData.getAxes(); List<Double> axes = remoteData.getAxes();
List<Boolean> buttons = remoteData.getButtons(); List<Boolean> buttons = remoteData.getButtons();
Double y = axes.get(1) * 1000 * -1; //前后值反了 Double y = axes.get(1) * 1000 * -1; // 前后值反了
Double x = axes.get(2) * 1000; Double x = axes.get(2) * 1000;
int intX = (int) x.doubleValue(); int intX = (int) x.doubleValue();
int intY = (int) y.doubleValue(); int intY = (int) y.doubleValue();
// todo 计算线速度和角速度 还需要根据车型来给线速度 角速度范围最大值
MiddleGlobalMemory.initDiff(); MiddleGlobalMemory.initDiff();
LawnMoverProtocolEntity entity = ControlUtils.getCarControlMessage(MiddleGlobalMemory.diffSteer, intX, intY, buttons); LawnMoverProtocolEntity entity = ControlUtils.getCarControlMessage(MiddleGlobalMemory.diffSteer,
intX, intY, buttons, 1, 2);
byte[] buf = ControlUtils.buildControlCommand(entity); byte[] buf = ControlUtils.buildControlCommand(entity);
logger.debug("Netty客户端:{}发送遥控数据: {}", userName, JsonUtils.toJsonString(entity)); logger.debug("Netty客户端:{}发送遥控数据: {}", userName, JsonUtils.toJsonString(entity));
NettyClient nettyClient = MiddleGlobalMemory.nettyClientMap.get(key); NettyClient nettyClient = MiddleGlobalMemory.nettyClientMap.get(key);
if (nettyClient != null && nettyClient.isConnected()) { if (nettyClient != null && nettyClient.isConnected()) {
// if (!nettyClient.isConnected()) nettyClient.connect(); // if (!nettyClient.isConnected()) nettyClient.connect();
nettyClient.sendData(buf); nettyClient.sendData(buf);
} }
} }
} }
// else if(MesType.heartbeat.equals(type)){ // else if(MesType.heartbeat.equals(type)){
// clientActiveTimeMap.put(conn,System.currentTimeMillis()); // clientActiveTimeMap.put(conn,System.currentTimeMillis());
// } // }
else if (MesType.switchPermission.equals(type)) { else if (MesType.switchPermission.equals(type)) {
DeviceRequestDTO requestDTO = new DeviceRequestDTO(); DeviceRequestDTO requestDTO = new DeviceRequestDTO();
requestDTO.setRequest(CommandRequestType.switch_control); requestDTO.setRequest(CommandRequestType.switch_control);
@@ -138,7 +141,7 @@ public class WebsocketHandler extends WebSocketServer {
ByteBuf buf = Unpooled.buffer(); ByteBuf buf = Unpooled.buffer();
CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction); CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction);
if (nettyClient != null && nettyClient.isConnected()) { if (nettyClient != null && nettyClient.isConnected()) {
// if (!nettyClient.isConnected()) nettyClient.connect(); // if (!nettyClient.isConnected()) nettyClient.connect();
nettyClient.sendData(buf.array()); nettyClient.sendData(buf.array());
} }
} else if (MesType.switchResult.equals(type)) { } else if (MesType.switchResult.equals(type)) {
@@ -156,7 +159,7 @@ public class WebsocketHandler extends WebSocketServer {
ByteBuf buf = Unpooled.buffer(); ByteBuf buf = Unpooled.buffer();
CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction); CommandUtils.buildCommand(buf, requestDTO, CommandConstant.interaction);
if (nettyClient != null && nettyClient.isConnected()) { if (nettyClient != null && nettyClient.isConnected()) {
// if (!nettyClient.isConnected()) nettyClient.connect(); // if (!nettyClient.isConnected()) nettyClient.connect();
nettyClient.sendData(buf.array()); nettyClient.sendData(buf.array());
} }
} }
@@ -186,7 +189,8 @@ public class WebsocketHandler extends WebSocketServer {
@Override @Override
public void onError(WebSocket conn, Exception ex) { public void onError(WebSocket conn, Exception ex) {
String key = MiddleGlobalMemory.findBySocket(conn); String key = MiddleGlobalMemory.findBySocket(conn);
logger.error("WebSocket错误: clientId={}, remoteAddress={}, error={}", key, conn != null ? conn.getRemoteSocketAddress() : null, ex.getMessage(), ex); logger.error("WebSocket错误: clientId={}, remoteAddress={}, error={}", key,
conn != null ? conn.getRemoteSocketAddress() : null, ex.getMessage(), ex);
// 发生错误时清理连接 // 发生错误时清理连接
if (key != null) { if (key != null) {
releaseResource(key); releaseResource(key);
@@ -222,7 +226,6 @@ public class WebsocketHandler extends WebSocketServer {
logger.debug("广播消息给所有客户端: message={}, 客户端数量: {}", message, connections.size()); logger.debug("广播消息给所有客户端: message={}, 客户端数量: {}", message, connections.size());
} }
// 核心:定时检测空闲连接(每隔10秒执行一次) // 核心:定时检测空闲连接(每隔10秒执行一次)
private void startIdleCheckTask() { private void startIdleCheckTask() {
executor.scheduleAtFixedRate(() -> { executor.scheduleAtFixedRate(() -> {
@@ -261,21 +264,21 @@ public class WebsocketHandler extends WebSocketServer {
} }
} }
} }
// clientActiveTimeMap.clear(); // 清空空闲记录 // clientActiveTimeMap.clear(); // 清空空闲记录
// //
// // 2. 关闭定时检测线程池(核心:终止非守护线程) // // 2. 关闭定时检测线程池(核心:终止非守护线程)
// if (!idleCheckExecutor.isShutdown()) { // if (!idleCheckExecutor.isShutdown()) {
// idleCheckExecutor.shutdownNow(); // 立即关闭线程池 // idleCheckExecutor.shutdownNow(); // 立即关闭线程池
// try { // try {
// // 等待线程池终止,最多等3秒 // // 等待线程池终止,最多等3秒
// if (!idleCheckExecutor.awaitTermination(3, TimeUnit.SECONDS)) { // if (!idleCheckExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
// logger.warn("空闲检测线程池未正常终止"); // logger.warn("空闲检测线程池未正常终止");
// } // }
// } catch (InterruptedException e) { // } catch (InterruptedException e) {
// idleCheckExecutor.shutdownNow(); // idleCheckExecutor.shutdownNow();
// Thread.currentThread().interrupt(); // Thread.currentThread().interrupt();
// } // }
// } // }
// 3. 批量关闭所有Netty客户端连接 // 3. 批量关闭所有Netty客户端连接
for (NettyClient client : MiddleGlobalMemory.nettyClientMap.values()) { for (NettyClient client : MiddleGlobalMemory.nettyClientMap.values()) {
@@ -300,5 +303,3 @@ public class WebsocketHandler extends WebSocketServer {
} }
} }
} }