This commit is contained in:
2026-07-29 13:08:49 +08:00
parent 29ecbf321f
commit 6be6d5d333
59 changed files with 1396 additions and 304 deletions

View File

@@ -11,7 +11,7 @@ import com.maibu.domain.AppPreferences;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.enums.BusinessType;
import com.maibu.enums.SourceType;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.service.IAppPreferencesService;
import com.maibu.service.ISysMenuService;
import com.maibu.service.ISysUserService;

View File

@@ -4,8 +4,8 @@ spring:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/maibu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: fastbee
password: maibu520
username: satabot
password: satabot
# redis 配置
redis:

View File

@@ -0,0 +1,20 @@
package com.maibu.constant;
public class CommandConstant {
public static byte remoteControl = (byte) 0x00;
public static byte heartbeat = (byte) 0xff;
public static byte path = (byte) 0x01;
public static byte status = (byte) 0x02;
public static byte connect = (byte) 0x03;
public static byte interaction = (byte) 0x12; //主要用于推送状态消息等
public static byte readConfig = (byte) 0x05; //读取配置的参数
public static byte writeConfig = (byte) 0x06; //写配置参数
}

View File

@@ -1,17 +1,25 @@
package com.maibu.common;
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;
@Data
public class Constant {
public static final AttributeKey<String> ATT_DEVICE_ID = AttributeKey.valueOf("deviceId");
public static final AttributeKey<CompletableFuture<DeviceRunParam>> READ_CONFIG_KEY =
AttributeKey.valueOf("READ_CONFIG");
public static final AttributeKey<ConnectionCloseReason> ATT_CLOSE_REASON = AttributeKey.valueOf("closeReason");
public static final AttributeKey<String> ATT_ORG_ID = AttributeKey.valueOf("orgId");
public static final AttributeKey<String> ATT_SITE_ID = AttributeKey.valueOf("siteId");
public static final String WheelGainCoefficients = "WheelGainCoefficients";
}

View File

@@ -20,21 +20,23 @@ public class DevicePlanTask extends OrgBaseDO {
@TableId(type = IdType.AUTO)
private Long id;
private Long planId; //归属于某个计划任务
private Long planId; // 归属于某个计划任务
private String deviceId;
private DeviceTaskStaus taskStaus; //任务状态
private DeviceTaskStaus taskStaus; // 任务状态
@TableField(exist = false)
private String taskStausTranslate; //任务状态
private String taskStausTranslate; // 任务状态
private Long routeId; // 线路id
private LocalDateTime finishTime;
private LocalDateTime startTime; //开始时间 时分秒
private LocalDateTime startTime; // 开始时间 时分秒
private String taskType; //任务类型分类
private String taskType; // 任务类型分类
private LocalDateTime canExecuteTime; // 这个时间之前都不能执行
}

View File

@@ -1,13 +1,19 @@
package com.maibu.core.business;
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.constant.CommandConstant;
import com.maibu.core.domain.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "iot_device_run_param", autoResultMap = true)
@@ -22,6 +28,432 @@ public class DeviceRunParam extends BaseDO {
private Long orgId;
private Double runSpeed;
private Integer runSpeed; //不下发到设备自己用
@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 static byte[] toWriteBytes(DeviceRunParam p) {
//
// ByteBuffer buffer = ByteBuffer.allocate(178);
// buffer.order(ByteOrder.LITTLE_ENDIAN);
//
// // 包头
// buffer.put((byte) 0xAB);
// buffer.put((byte) 0xAA);
//
// // 指令
// buffer.put(CommandConstant.writeConfig);
//
// // UID固化标志
// buffer.put(p.getChipUidSign());
//
// // UID
// putFixedString(buffer, p.getChipUid(), 45);
//
// // Byte68
// byte remote = 0;
// remote |= (p.getKnifeMotorMode() & 0x03);
// remote |= (p.getWalkMotorMode() & 0x03) << 2;
// remote |= (p.getLeftMotorReverse() & 0x01) << 4;
// remote |= (p.getRightMotorReverse() & 0x01) << 5;
// remote |= (p.getSwapChannel() & 0x01) << 6;
// remote |= (p.getUse4G() & 0x01) << 7;
// buffer.put(remote);
//
// // 69~72
// buffer.putShort((short) p.getForwardSpeedLimit());
// buffer.putShort((short) p.getTurnSpeedLimit());
//
// //73
// byte b73 = 0;
// b73 |= (p.getKnifePolarity() & 1);
// b73 |= (p.getFanPolarity() & 1) << 1;
// b73 |= (p.getThrottlePolarity() & 1) << 2;
// b73 |= (p.getLiftProtectTime() & 0x0F) << 3;
// b73 |= (p.getDualRtk() & 1) << 7;
// buffer.put(b73);
//
// //74
// byte b74 = 0;
// b74 |= (p.getKnifeChannel() & 0x0F);
// b74 |= (p.getFanChannel() & 0x0F) << 4;
// buffer.put(b74);
//
// //75
// byte b75 = 0;
// b75 |= (p.getThrottleChannel() & 0x0F);
// b75 |= (p.getRemoteType() & 0x07) << 4;
// if (p.isRelayBoard()) {
// b75 |= 1 << 7;
// }
// buffer.put(b75);
//
// //76
// byte b76 = 0;
// b76 |= (p.getLiftChannel() & 0x0F);
// b76 |= (p.getChassisChannel() & 0x0F) << 4;
// buffer.put(b76);
//
// //77
// byte b77 = 0;
// b77 |= (p.getArmChannel() & 0x0F);
// b77 |= (p.getFuelPumpChannel() & 0x0F) << 4;
// buffer.put(b77);
//
// //wifi
// putFixedString(buffer, p.getWifiName(), 20);
// putFixedString(buffer, p.getWifiPassword(), 20);
//
// //118
// byte b118 = 0;
// b118 |= (p.getBatteryType() & 0x03);
// b118 |= (p.getDriveType() & 0x03) << 2;
// buffer.put(b118);
//
// //119~158 float
// buffer.putFloat(p.getGearRatio());
// buffer.putFloat(p.getRobotLength());
// buffer.putFloat(p.getRobotWidth());
// buffer.putFloat(p.getRobotHeight());
// buffer.putFloat(p.getKnifeWidth());
// buffer.putFloat(p.getTyreSize());
// buffer.putFloat(p.getLeftForwardGain());
// buffer.putFloat(p.getLeftBackwardGain());
// buffer.putFloat(p.getRightForwardGain());
// buffer.putFloat(p.getRightBackwardGain());
//
// //159~173
// putFixedString(buffer, p.getFirmwareVersion(), 15);
//
// //CRC
//
// / / byte[] bytes = buffer.array();
// / / int crc = CRC16Util.crc16(bytes, 0, 174);
// buffer.putShort((short) 0);
//
// //Tail
// 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.setHeader1(buffer.get());
p.setHeader2(buffer.get());
p.setCmd(buffer.get());
p.setChipUidSign(buffer.get());
p.setChipUid(readString(buffer, 45));
// 跳过字节49-67(共19字节,预留不用)
buffer.position(buffer.position() + 19);
byte remote = buffer.get();
// p.setRemoteConfig(remote);
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.setForwardSpeedLimit(buffer.getShort());
p.setTurnSpeedLimit(buffer.getShort());
byte b73 = buffer.get();
p.setKnifePolarity(b73 & 1);
p.setFanPolarity((b73 >> 1) & 1);
p.setThrottlePolarity((b73 >> 2) & 1);
p.setLiftProtectTime((b73 >> 3) & 0x0F);
p.setDualRtk((b73 >> 7) & 1);
byte b74 = buffer.get();
p.setKnifeChannel(b74 & 0x0F);
p.setFanChannel((b74 >> 4) & 0x0F);
byte b75 = buffer.get();
p.setThrottleChannel(b75 & 0x0F);
p.setRemoteType((b75 >> 4) & 0x07);
p.setRelayBoard(((b75 >> 7) & 1) == 1);
byte b76 = buffer.get();
p.setLiftChannel(b76 & 0x0F);
p.setChassisChannel((b76 >> 4) & 0x0F);
byte b77 = buffer.get();
p.setArmChannel(b77 & 0x0F);
p.setFuelPumpChannel((b77 >> 4) & 0x0F);
p.setWifiName(readString(buffer, 20));
p.setWifiPassword(readString(buffer, 20));
byte b118 = buffer.get();
p.setBatteryType(b118 & 0x03);
p.setDriveType((b118 >> 2) & 0x03);
// 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.setFirmwareVersion(readString(buffer, 15));
p.setCrc16(Short.toUnsignedInt(buffer.getShort()));
p.setTail1(buffer.get());
p.setTail2(buffer.get());
return p;
}
public static String readString(ByteBuffer buffer, int len) {
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

@@ -2,10 +2,14 @@ package com.maibu.core.business;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
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.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maibu.core.domain.OrgNoUserDO;
import com.maibu.core.enums.ErrorLevel;
import com.maibu.core.enums.ErrorSource;
@@ -15,10 +19,11 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("iot_work_order")
@TableName(value = "iot_work_order", autoResultMap = true)
@ApiModel("工单记录")
public class IOTWorkOrder extends OrgNoUserDO {
@@ -64,21 +69,31 @@ public class IOTWorkOrder extends OrgNoUserDO {
private String collaboratorNames;
@ApiModelProperty("计划开始时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime planStartTime;
@ApiModelProperty("计划结束时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime planEndTime;
@ApiModelProperty("截止时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime deadlineTime;
@ApiModelProperty("实际开始时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime actualStartTime;
@ApiModelProperty("实际完成时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime actualEndTime;
@ApiModelProperty("工单状态:1-待处理 2-已派发 3-执行中 4-已完成 5-已挂起")
@ApiModelProperty("工单状态:1-待处理 2-执行中 3-已完成 4-已挂起")
private Integer orderStatus;
@ApiModelProperty("关联告警 ID")
@@ -105,7 +120,23 @@ public class IOTWorkOrder extends OrgNoUserDO {
@ApiModelProperty("处理备注")
private String handleRemark;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> imgUrl; //创建时候的照片
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> videoUrl;//创建时候的视频
private Long modelId;
private Long taskId;
private String taskId;
private boolean autoCreate = false; //自动创建
private String failureCause; //故障原因
private String handleMeasures; //处理措施
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> images; //现场图片 处理后的照片
}

View File

@@ -3,6 +3,8 @@ package com.maibu.core.business.alarm_center;
import com.baomidou.mybatisplus.annotation.*;
import com.maibu.annotation.Excel;
import com.maibu.core.domain.TenantBaseDO;
import com.maibu.core.enums.AlarmHandleResult;
import com.maibu.core.enums.AlarmType;
import com.maibu.core.enums.ErrorLevel;
import com.maibu.core.enums.ErrorSource;
@@ -34,7 +36,7 @@ public class Alarm extends TenantBaseDO {
@ApiModelProperty("告警类型:1-设备故障 2-数据异常 3-通信中断 4-性能告警 5-安全告警 6-环境告警")
@Excel(name = "告警类型", readConverterExp = "1=设备故障,2=数据异常,3=通信中断,4=性能告警,5=安全告警,6=环境告警")
private Integer alarmType;
private AlarmType alarmType;
@ApiModelProperty("告警标题")
@Excel(name = "告警标题")
@@ -44,6 +46,8 @@ public class Alarm extends TenantBaseDO {
@Excel(name = "告警内容")
private String alarmContent;
private String timeValues; //告警时上报的值
@ApiModelProperty("设备ID")
@Excel(name = "设备ID", cellType = Excel.ColumnType.NUMERIC)
private String deviceId;
@@ -68,8 +72,8 @@ public class Alarm extends TenantBaseDO {
@Excel(name = "持续时长(秒)", cellType = Excel.ColumnType.NUMERIC)
private Integer duration;
@ApiModelProperty("处理状态:1-待处理 2-处理中 3-已关闭 4-已忽略")
@Excel(name = "处理状态", readConverterExp = "1=待处理,2=处理中,3=已关闭,4=已忽略")
@ApiModelProperty("处理状态:1-待处理 2已关闭")
@Excel(name = "处理状态", readConverterExp = "1=待处理,2=已关闭")
private Integer handleStatus;
@ApiModelProperty("处理人ID")
@@ -111,4 +115,6 @@ public class Alarm extends TenantBaseDO {
private Long siteId;
private Long orgId;
private AlarmHandleResult handleResult;
}

View File

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.maibu.core.enums.ErrorLevel;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
@Data
public class AlarmMessage {
@@ -21,6 +22,7 @@ public class AlarmMessage {
/** 告警时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime time;
/** 设备名称 */
@@ -45,4 +47,6 @@ public class AlarmMessage {
private Long orgId;
private String timeValues;
}

View File

@@ -1,9 +1,12 @@
package com.maibu.core.business.device;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.Queue;
import com.maibu.utils.json.JsonUtils;
import org.springframework.util.CollectionUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -74,7 +77,7 @@ public class NettyDevice extends Connector {
this.deviceType = deviceType;
}
// todo 重发
// todo 如何确定命令已收到?
public void sendNextPoint() {
if (task.getTaskStaus().equals(DeviceTaskStaus.PAUSE))
return;
@@ -139,9 +142,9 @@ public class NettyDevice extends Connector {
return true;
}
public void sendPathCommand(byte coommadnType, short pointCounts, double lat, double lng, short speed) {
public void sendPathCommand(byte commandType, short pointCounts, double lat, double lng, short speed) {
RoutePlanSendEntity routePlanSendEntity = new RoutePlanSendEntity();
routePlanSendEntity.setCommandType(coommadnType);
routePlanSendEntity.setCommandType(commandType);
routePlanSendEntity.setPointCounts(pointCounts);
routePlanSendEntity.setTargetLatitude(lat);
routePlanSendEntity.setTargetLongitude(lng);
@@ -153,6 +156,57 @@ public class NettyDevice extends Connector {
}
}
//配置左右轮增益系数
public void sendWheelGainCoefficientsCommand(double leftForwardGain, double leftBackwardGain, double rightForwardGain, double rightBackwardGain) {
ByteBuffer buffer = ByteBuffer.allocate(39);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put((byte) 0xAB);
buffer.put((byte) 0xAA);
buffer.put((byte) 0x13);
long leftForward = Double.doubleToLongBits(leftForwardGain);
buffer.putLong(leftForward);
long leftBackward = Double.doubleToLongBits(leftBackwardGain);
buffer.putLong(leftBackward);
long rightForward = Double.doubleToLongBits(rightForwardGain);
buffer.putLong(rightForward);
long rightBackward = Double.doubleToLongBits(rightBackwardGain);
buffer.putLong(rightBackward);
buffer.putShort((short) 0);
buffer.put((byte) 0xAA);
buffer.put((byte) 0xAB);
log.debug("下发设置左右轮增益系数报文:{}", toHexString(buffer.array()));
if (this.getChannel() != null && this.getChannel().isActive()) {
this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(buffer.array()));
}
}
public void readConfigCommand() {
byte[] bytes = DeviceRunParam.toReadBytes();
log.debug("下发读取配置的报文:{}", toHexString(bytes));
if (this.getChannel() != null && this.getChannel().isActive()) {
this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
}
}
public void writeConfigCommand(DeviceRunParam deviceRunParam) {
log.debug("下发修改配置的属性:{}", JsonUtils.toJsonString(deviceRunParam));
byte[] bytes = deviceRunParam.toWriteBytes();
log.debug("下发修改配置的报文:{}", toHexString(bytes));
if (this.getChannel() != null && this.getChannel().isActive()) {
this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
}
}
// todo 优化
public synchronized boolean pauseTask() {
if (executingTask) {

View File

@@ -1,5 +1,6 @@
package com.maibu.core.business.dto;
import com.maibu.core.enums.AlarmHandleResult;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -11,7 +12,7 @@ public class AlarmHandleDTO {
@ApiModelProperty("告警ID")
private Long alarmId;
@ApiModelProperty("处理状态:2-处理中 3-已关闭 4-已忽略")
@ApiModelProperty("处理状态:1-待处理 2已关闭")
private Integer handleStatus;
@ApiModelProperty("处理备注")
@@ -19,4 +20,7 @@ public class AlarmHandleDTO {
@ApiModelProperty("根因分析")
private String rootCause;
@ApiModelProperty("处理结果")
private AlarmHandleResult handleResult;
}

View File

@@ -39,4 +39,6 @@ public class AlarmQueryDTO extends BaseEntity {
@ApiModelProperty("场站ID")
private Long siteId;
private Integer handleStatus;
}

View File

@@ -6,8 +6,10 @@ import lombok.Data;
import java.time.LocalDateTime;
import javax.lang.model.type.ErrorType;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maibu.core.enums.ErrorLevel;
import com.maibu.core.enums.OrderType;
@Data
@@ -27,7 +29,7 @@ public class WorkOrderQueryDTO {
private OrderType orderType;
@ApiModelProperty("优先级")
private ErrorType priorityLevel;
private ErrorLevel priorityLevel;
@ApiModelProperty("负责人 ID")
private Long assigneeId;
@@ -44,10 +46,12 @@ public class WorkOrderQueryDTO {
@ApiModelProperty("工单状态")
private Integer orderStatus;
@ApiModelProperty("开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime startTime;
@ApiModelProperty("结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime endTime;
@ApiModelProperty("搜索关键词")

View File

@@ -15,12 +15,14 @@ public class MowerCommandDispather {
@Resource
private ApplicationContext applicationContext;
public void dispathDeviceTask(DeviceTaskCommandDTO dto) {
public Long dispathDeviceTask(DeviceTaskCommandDTO dto) {
Map<String, MowerCommandInter> beanMap = applicationContext.getBeansOfType(MowerCommandInter.class);
// 遍历
beanMap.values().forEach(x -> {
x.createDeviceTask(dto);
});
Long id = null;
for (MowerCommandInter value : beanMap.values()) {
id = value.createDeviceTask(dto);
}
return id;
}
}

View File

@@ -4,6 +4,6 @@ import com.maibu.core.business.dto.DeviceTaskCommandDTO;
public interface MowerCommandInter {
void createDeviceTask(DeviceTaskCommandDTO dto);
Long createDeviceTask(DeviceTaskCommandDTO dto);
}

View File

@@ -15,12 +15,14 @@ public class UAVCommandDispather {
@Resource
private ApplicationContext applicationContext;
public void dispathFightTask(FlightTaskCreateDTO dto) {
public String dispathFightTask(FlightTaskCreateDTO dto) {
Map<String, UAVCommandInter> beanMap = applicationContext.getBeansOfType(UAVCommandInter.class);
// 遍历
beanMap.values().forEach(x -> {
x.createFlightTask(dto);
});
String taskId = null;
for (UAVCommandInter value : beanMap.values()) {
taskId = value.createFlightTask(dto);
}
return taskId;
}
}

View File

@@ -4,6 +4,6 @@ import com.maibu.core.business.dto.uav.FlightTaskCreateDTO;
public interface UAVCommandInter {
void createFlightTask(FlightTaskCreateDTO dto);
String createFlightTask(FlightTaskCreateDTO dto);
}

View File

@@ -41,4 +41,6 @@ public class SysSite extends BaseDO {
private String dingTalkToken; // 钉钉推送token
private boolean dingTalkOrderPush = false;// 工单是否推送
}

View File

@@ -0,0 +1,31 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum AlarmHandleResult {
Handled("Handled", "已处理"),
Restored("Restored", "已恢复"),
Ignored("Ignored", "已忽略"),
UnableToHandle("UnableToHandle", "无法处理"),
ManufacturerHandling("ManufacturerHandling", "厂家处理中"),
FalseAlarm("FalseAlarm", "误报");
/**
* 错误来源值(存储在数据库中)
*/
private final String value;
/**
* 错误来源名称(用于前端显示)
*/
private final String name;
}

View File

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

View File

@@ -1,11 +1,11 @@
package com.maibu.manager;
package com.maibu.memory;
import cn.hutool.core.util.ObjectUtil;
import com.maibu.core.enums.ConnectorStatus;
import com.maibu.core.enums.ConnectorType;
import com.maibu.core.business.device.Connector;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.enums.ConnectorStatus;
import com.maibu.core.enums.ConnectorType;
import io.netty.channel.Channel;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

View File

@@ -35,6 +35,8 @@ public class GlobalMemory {
public static MqttClientUtil mqttClientUtil;
public static SiteMemory getSiteMemory(Long orgId, Long siteId) {
if (orgId != null && siteId != null) {
Map<Long, SiteMemory> siteMemories = orgAttrs.get(orgId);

View File

@@ -35,7 +35,7 @@ public class SiteMemory {
public SysSite sysSite;
public static final ConcurrentHashMap<Long, OrderModel> ordrModelMap = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<Long, OrderModel> orderModelMap = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<String, AlarmOrderConfig> orderConfigMap = new ConcurrentHashMap<>();
@@ -87,7 +87,19 @@ public class SiteMemory {
if (CollectionUtils.isEmpty(list)) {
list = new ArrayList<>();
}
// 替换已存在的记录,兼容后续保存
int index = -1;
for (int i = 0; i < list.size(); i++) {
if (Objects.equals(list.get(i).getErrorCode(), errorIdentificationStandard.getErrorCode())){
index = i;
break;
}
}
if (index >= 0) {
list.set(index, errorIdentificationStandard);
} else {
list.add(errorIdentificationStandard);
}
standards.put(errorIdentificationStandard.getErrorSource(), list);
}
@@ -108,19 +120,19 @@ public class SiteMemory {
}
public void saveOrderModel(OrderModel orderModel) {
ordrModelMap.put(orderModel.getId(), orderModel);
orderModelMap.put(orderModel.getId(), orderModel);
}
public OrderModel getOrderModel(Long id) {
if (id != null) {
return ordrModelMap.get(id);
return orderModelMap.get(id);
}
return null;
}
public void removeOrderModel(Long id) {
if (id != null) {
ordrModelMap.remove(id);
orderModelMap.remove(id);
}
}

View File

@@ -1,15 +1,108 @@
package com.maibu.mqtt;
public class MqttTopic {
public static final String DEVICE_STATUS_TOPIC = "device/%s/realTimeMessage"; // 实时消息
/** @deprecated 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_STATUS_TOPIC = "device/%s/realTimeMessage";
/** @deprecated 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_TASK_STATUS_TOPIC = "task/%s/status";
/** @deprecated 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_TASK_ARRIVE_TOPIC = "task/%s/arrive";
/** @deprecated 通用设备主题,建议使用 MOWER_* 系列主题 */
public static final String DEVICE_ERROR_PUSH_TOPIC = "device/%s/error";
public static final String DEVICE_TASK_STATUS_TOPIC = "task/%s/status"; // 任务状态 完成、取消、暂停、继续
/** 产品标识:割草机 */
public static final String MOWER_PRODUCT = "mower";
public static final String DEVICE_TASK_ARRIVE_TOPIC = "task/%s/arrive"; // 任务到达
// ==================== 设备连接与状态 ====================
/** 设备上线/下线事件上报(设备->平台),对应 TCP 0x03 connect */
public static final String MOWER_STATUS_POST = "mower/%s/event/status/post";
/** 状态变更确认回复(平台->设备) */
// public static final String MOWER_STATUS_REPLY = "mower/%s/event/status/reply";
public static final String DEVICE_ERROR_PUSH_TOPIC = "device/%s/error"; // 设备错误推送
// ==================== 实时运行数据 ====================
/** 实时运行数据上报:电压/速度/温度/位置等(设备->平台),对应 TCP 0x02 status */
public static final String MOWER_REALTIME_POST = "mower/%s/property/realtime/post";
// ==================== 心跳保活 ====================
/** 设备心跳上报(设备->平台),对应 TCP 0xFF heartbeat */
public static final String MOWER_HEARTBEAT_POST = "mower/%s/event/heartbeat/post";
/** 心跳确认回复(平台->设备) */
public static final String MOWER_HEARTBEAT_REPLY = "mower/%s/event/heartbeat/reply";
// ==================== 参数配置 ====================
/** 下发读取配置请求(平台->设备),对应 TCP 0x05 readConfig */
public static final String MOWER_CONFIG_GET = "mower/%s/action/config/get";
/** 下发配置修改指令(平台->设备),对应 TCP 0x06 writeConfig */
public static final String MOWER_CONFIG_SET = "mower/%s/action/config/set";
/** 配置读取/修改响应(设备->平台) */
public static final String MOWER_CONFIG_REPLY = "mower/%s/action/config/reply";
// ==================== 远程控制 ====================
/** 远程控制指令下发:前进/后退/转向/割草等(平台->设备),对应 TCP 0x00 remoteControl */
public static final String MOWER_CONTROL_SET = "mower/%s/action/control/set";
// /** 控制指令响应(设备->平台) */
// public static final String MOWER_CONTROL_REPLY = "mower/%s/action/control/reply";
// ==================== 任务管理 ====================
/** 路径规划下发(平台->设备),对应 TCP 0x01 path */
public static final String MOWER_TASK_ROUTE_SET = "mower/%s/task/route/set";
public static final String MOWER_TASK_ROUTE_POST = "mower/%s/task/route/post";
/** 启动任务执行(平台->设备),对应 TCP 0x12 interaction */
public static final String MOWER_TASK_STATUS_SET = "mower/%s/task/status/set";
// /** 暂停任务(平台->设备) */
// public static final String MOWER_TASK_PAUSE_SET = "mower/%s/task/pause/set";
// /** 继续任务(平台->设备) */
// public static final String MOWER_TASK_RESUME_SET = "mower/%s/task/resume/set";
// /** 取消任务(平台->设备) */
// public static final String MOWER_TASK_CANCEL_SET = "mower/%s/task/cancel/set";
// /** 到达路径点上报(设备->平台) */
public static final String MOWER_TASK_POINT_POST = "mower/%s/task/point/post";
/** 任务状态变更上报:执行中/暂停/完成等(设备->平台) */
public static final String MOWER_TASK_STATUS_POST = "mower/%s/task/status/post";
/** 任务完成上报(设备->平台) */
public static final String MOWER_TASK_FINISH_POST = "mower/%s/task/finish/post";
// ==================== 错误告警 ====================
/** 设备错误告警上报:电机故障/传感器异常等(设备->平台) */
public static final String MOWER_ERROR_POST = "mower/%s/event/error/post";
// ==================== OTA 固件升级 ====================
// /** 下发 OTA 升级指令(平台->设备) */
// public static final String MOWER_OTA_UPGRADE_SET = "mower/%s/ota/upgrade/set";
// /** OTA 升级进度上报(设备->平台) */
// public static final String MOWER_OTA_PROGRESS_POST = "mower/%s/ota/progress/post";
// /** OTA 升级结果上报(设备->平台) */
// public static final String MOWER_OTA_RESULT_POST = "mower/%s/ota/result/post";
// ==================== 设备信息 ====================
// /** 查询设备信息(平台->设备) */
// public static final String MOWER_INFO_DEVICE_GET = "mower/%s/info/device/get";
// /** 设备信息响应(设备->平台) */
// public static final String MOWER_INFO_DEVICE_REPLY = "mower/%s/info/device/reply";
/** 设备版本信息上报(设备->平台) */
// public static final String MOWER_INFO_VERSION_POST = "mower/%s/info/version/post";
// ==================== 通配符订阅 ====================
/** 订阅所有设备的状态变更事件 */
public static final String MOWER_WILDCARD_STATUS = "mower/+/event/status/post";
/** 订阅所有设备的实时运行数据 */
public static final String MOWER_WILDCARD_REALTIME = "mower/+/property/realtime/post";
/** 订阅所有设备的错误告警 */
public static final String MOWER_WILDCARD_ERROR = "mower/+/event/error/post";
/** 订阅所有设备的任务状态变更 */
public static final String MOWER_WILDCARD_TASK_STATUS = "mower/+/task/status/post";
/**
* 格式化 Topic 模板,将 %s 替换为设备ID
*
* @param template Topic 模板,如 {@link #MOWER_REALTIME_POST}
* @param deviceId 设备ID
* @return 格式化后的完整 Topic
*/
public static String formatTopic(String template, String deviceId) {
return String.format(template, deviceId);
}
}

View File

@@ -17,6 +17,7 @@ import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* JSON 工具类
@@ -87,7 +88,8 @@ public class JsonUtils {
/**
* 将字符串解析成指定类型的对象
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,
* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use =
* JsonTypeInfo.Id.CLASS) 的场景下,
* 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。
*
* @param text 字符串
@@ -127,7 +129,8 @@ public class JsonUtils {
return new ArrayList<>();
}
try {
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
return objectMapper.readValue(text,
objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
} catch (IOException e) {
log.error("json parse err,json:{}", text, e);
throw new RuntimeException(e);

View File

@@ -1,10 +1,15 @@
package com.maibu.uav.service;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.maibu.core.business.dto.uav.FlightTaskCreateDTO;
import com.maibu.core.business.inter.uav.UAVCommandInter;
import com.maibu.uav.dto.SK2ResultDTO;
import com.maibu.utils.json.JsonUtils;
@Component
public class UAVCommamdHandler implements UAVCommandInter {
@@ -13,8 +18,18 @@ public class UAVCommamdHandler implements UAVCommandInter {
private UAVService uService;
@Override
public void createFlightTask(FlightTaskCreateDTO dto){
uService.createFlightTask(dto);
public String createFlightTask(FlightTaskCreateDTO dto) {
String json = uService.createFlightTask(dto);
SK2ResultDTO res = JsonUtils.parseObject(json, SK2ResultDTO.class);
String taskId = null;
if (res != null && res.getData() != null) {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.convertValue(
res.getData(),
Map.class);
taskId = (String) map.get("task_uuid");
}
return taskId;
}
}

View File

@@ -11,7 +11,7 @@ import com.maibu.core.business.DeviceRunningStatusHistory;
import com.maibu.core.business.DeviceStatusRecordDTO;
import com.maibu.core.redis.RedisCache;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.utils.spring.SpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@@ -1,16 +0,0 @@
package com.maibu.common;
public class CommandConstant {
public static byte remoteControl = (byte)0x00;
public static byte heartbeat = (byte)0xff;
public static byte path = (byte)0x01;
public static byte status = (byte)0x02;
public static byte connect = (byte)0x03;
public static byte interaction = (byte)0x12; //主要用于推送状态消息等
}

View File

@@ -1,11 +1,11 @@
package com.maibu.controller;
import com.maibu.common.CommandConstant;
import com.maibu.constant.CommandConstant;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.dto.ObstacleData;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.utils.CommandUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

View File

@@ -1,6 +1,6 @@
package com.maibu.controller;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;

View File

@@ -5,6 +5,7 @@ import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.page.TableDataInfo;
import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.dto.SendCommandDTO;
import com.maibu.service.NettyDeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -19,26 +20,29 @@ public class NettyDeviceController extends BaseController {
private NettyDeviceService nettyDeviceService;
@GetMapping("/statusHistory")
public TableDataInfo statusHistory(DeviceRunningStatusHistory history)
{
public TableDataInfo statusHistory(DeviceRunningStatusHistory history) {
startPage();
List<DeviceRunningStatusHistory> list = nettyDeviceService.statusHistory(history);
return getDataTable(list);
}
@GetMapping("/getErrorIdentification")
public TableDataInfo getErrorIdentification()
{
public TableDataInfo getErrorIdentification() {
startPage();
List<ErrorIdentificationStandard> list = nettyDeviceService.allErrorIdentificationStandard();
return getDataTable(list);
}
@PostMapping("/updateErrorIdentification")
public AjaxResult updateErrorIdentification(@RequestBody ErrorIdentificationStandard standard)
{
public AjaxResult updateErrorIdentification(@RequestBody ErrorIdentificationStandard standard) {
int i = nettyDeviceService.updateErrorIdentification(standard);
return AjaxResult.success(i);
}
@PostMapping("/sendCommand")
public AjaxResult sendCommand(@RequestBody SendCommandDTO command) {
nettyDeviceService.sendCommand(command);
return AjaxResult.success();
}
}

View File

@@ -0,0 +1,16 @@
package com.maibu.dto;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class SendCommandDTO {
private String commandType;
private Map<String,Object> params;
private List<String> deviceIds;
}

View File

@@ -4,9 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.maibu.core.business.dto.DeviceTaskCommandDTO;
import com.maibu.core.business.dto.uav.FlightTaskCreateDTO;
import com.maibu.core.business.inter.mower.MowerCommandInter;
import com.maibu.core.business.inter.uav.UAVCommandInter;
import com.maibu.service.DeviceTaskService;
@Component
@@ -16,8 +14,8 @@ public class MowerCommamdHandler implements MowerCommandInter {
private DeviceTaskService dService;
@Override
public void createDeviceTask(DeviceTaskCommandDTO dto) {
dService.createDeviceTask(dto, "system");
public Long createDeviceTask(DeviceTaskCommandDTO dto) {
return dService.createDeviceTask(dto, "system");
}
}

View File

@@ -162,7 +162,7 @@ public class InitThread implements ApplicationRunner {
if (!CollectionUtils.isEmpty(deviceRunParamList)) {
deviceRunParamList.forEach(x -> {
Long orgId = x.getOrgId();
Long siteId = x.getId();
Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory != null) {
siteMemory.saveDeviceRunParam(x);
@@ -174,7 +174,7 @@ public class InitThread implements ApplicationRunner {
if (!CollectionUtils.isEmpty(standadList)) {
standadList.forEach(x -> {
Long orgId = x.getOrgId();
Long siteId = x.getId();
Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory != null) {
siteMemory.saveErrorIdentificationStandard(x);
@@ -186,7 +186,7 @@ public class InitThread implements ApplicationRunner {
if (!CollectionUtils.isEmpty(orderModelList)) {
orderModelList.forEach(x -> {
Long orgId = x.getOrgId();
Long siteId = x.getId();
Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory != null) {
siteMemory.saveOrderModel(x);
@@ -198,7 +198,7 @@ public class InitThread implements ApplicationRunner {
if (!CollectionUtils.isEmpty(alarmOrderList)) {
alarmOrderList.forEach(x -> {
Long orgId = x.getOrgId();
Long siteId = x.getId();
Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory != null) {
siteMemory.saveAlarmOrderConfig(x);

View File

@@ -3,6 +3,7 @@ package com.maibu.netty.handler;
import java.util.List;
import java.util.Set;
import com.maibu.memory.DeviceSessionManager;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -10,11 +11,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.common.CommandConstant;
import com.maibu.constant.CommandConstant;
import com.maibu.core.business.device.Connector;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.enums.ConnectorType;
import com.maibu.manager.DeviceSessionManager;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
@@ -36,7 +36,10 @@ public class CommandForwardHandler extends SimpleChannelInboundHandler<String> {
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel currentChannel = ctx.channel();
byte[] bytes = Hex.decodeHex(msg.toCharArray());
if (bytes.length > 3 && (bytes[2] == CommandConstant.remoteControl || bytes[2] == CommandConstant.path || bytes[2] == CommandConstant.status)) {
if (bytes.length > 3 && (bytes[2] == CommandConstant.remoteControl
|| bytes[2] == CommandConstant.path
|| bytes[2] == CommandConstant.status
)) {
String senderDeviceId = deviceSessionManager.getDeviceIdByChannel(currentChannel);
NettyDevice senderNettyDevice =

View File

@@ -7,7 +7,13 @@ import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.maibu.constant.Constant;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.mapper.DeviceRunParamMapper;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.SiteMemory;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
@@ -17,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.common.CommandConstant;
import com.maibu.constant.CommandConstant;
import com.maibu.common.NettyCacheKey;
import com.maibu.core.business.DeviceRunStatistics;
import com.maibu.core.business.DeviceRunningStatusHistory;
@@ -30,7 +36,6 @@ import com.maibu.core.redis.RedisCache;
import com.maibu.dto.WebStatusMessageDTO;
import com.maibu.influxdb.MowerRealTimeData;
import com.maibu.influxdb.util.InfluxSqlBuilder;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.mqtt.MqttTopic;
import com.maibu.utils.json.JsonUtils;
@@ -55,6 +60,9 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
@Autowired
private WebsocketMesDispather websocketMesDispather;
@Autowired
private DeviceRunParamMapper deviceRunParamMapper;
private static final Long recordInterval = 5000L; // 5秒记录一次
// private static final Long pushInterval = 500L; // 0.5秒推送一次
@@ -136,6 +144,15 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
latestStatus.setWorkArea(Double.valueOf(workArea));
nettyDevice.setLatestStatus(latestStatus);
}
} else if (bytes[2] == CommandConstant.readConfig) {
DeviceRunParam runParam = DeviceRunParam.fromBytes(bytes);
logger.debug("收到返回的设备运行参数: {}", JsonUtils.toJsonString(runParam));
CompletableFuture<DeviceRunParam> future =
ctx.channel().attr(Constant.READ_CONFIG_KEY).get();
if (future != null) {
future.complete(runParam);
ctx.channel().attr(Constant.READ_CONFIG_KEY).set(null);
}
}
ctx.fireChannelRead(msg);
} catch (Exception e) {
@@ -143,6 +160,7 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
}
}
public WebStatusMessageDTO createWebDeviceStatusMessage(String[] split) {
WebStatusMessageDTO webStatusMessageDTO = new WebStatusMessageDTO();
List<DeviceStatusDetail> transferData = transferStatusData(split);

View File

@@ -8,6 +8,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource;
import com.maibu.memory.DeviceSessionManager;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
@@ -17,8 +18,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.common.CommandConstant;
import com.maibu.common.Constant;
import com.maibu.constant.CommandConstant;
import com.maibu.constant.Constant;
import com.maibu.core.business.Device;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.inter.WebsocketMesDispather;
@@ -37,7 +38,6 @@ import com.maibu.dto.DeviceRequestDTO;
import com.maibu.dto.DeviceRespondDTO;
import com.maibu.dto.DeviceStatusChangeDTO;
import com.maibu.dto.DeviceTaskStatusMessageDTO;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.mapper.DeviceRunStatisticsMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.mqtt.MqttTopic;

View File

@@ -1,8 +1,8 @@
package com.maibu.netty.handler;
import com.maibu.common.Constant;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.constant.Constant;
import com.maibu.memory.DeviceSessionManager;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;

View File

@@ -1,7 +1,7 @@
package com.maibu.netty.handler;
import com.maibu.common.CommandConstant;
import com.maibu.common.Constant;
import com.maibu.constant.CommandConstant;
import com.maibu.constant.Constant;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;

View File

@@ -2,10 +2,14 @@ package com.maibu.scheduled;
import com.maibu.common.NettyCacheKey;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.DeviceStatusRecordDTO;
import com.maibu.core.redis.RedisCache;
import com.maibu.mapper.DeviceStatusHistoryMapper;
import com.maibu.memory.SiteMemory;
import com.maibu.utils.json.JsonUtils;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -70,4 +74,21 @@ public class ScheduledTask {
}
System.out.println("0点定时刷新状态执行完成");
}
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 cleanHex = hex.replaceAll("\\s+", ""); // 移除所有空白字符
byte[] bytes = Hex.decodeHex(cleanHex);
DeviceRunParam runParam = DeviceRunParam.fromBytes(bytes);
System.out.println(JsonUtils.toJsonString(runParam));
runParam.setLeftBackwardGain(0.2f);
runParam.setLeftForwardGain(0.2f);
runParam.setRightForwardGain(0.2f);
runParam.setRightBackwardGain(0.2f);
byte[] newB = runParam.toWriteBytes();
System.out.println(Hex.encodeHexString(newB));
}
}

View File

@@ -11,6 +11,8 @@ import java.util.concurrent.TimeUnit;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.maibu.core.business.alarm_center.Alarm;
import com.maibu.memory.DeviceSessionManager;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -26,7 +28,6 @@ import com.maibu.core.business.alarm_center.AlarmMessage;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.redis.RedisCache;
import com.maibu.dto.DeviceErrorPushDTO;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import com.maibu.service.impl.AlarmServiceImpl;
@@ -93,25 +94,37 @@ public class AlertPushService {
Boolean exists = redisCache.hasKey(pushKey);
if (exists != null && !exists) {
newList.add(detail);
redisCache.setCacheObject(pushKey, JsonUtils.toJsonString(detail), 10,
TimeUnit.MINUTES);
}
}
redisCache.setCacheObject(pushKey, JsonUtils.toJsonString(detail));
AlarmOrderConfig config = siteMemory.getAlarmOrderConfig(detail.getNo());
log.debug("compare config:{}", JsonUtils.toJsonString(config));
if (config != null && config.isAutoGenerateOrder()) {
IOTWorkOrder workOrder = wService.generateWorkOrders(siteId, deviceId, orgId, orgId);
IOTWorkOrder workOrder = wService.generateWorkOrders(siteId, deviceId, orgId, config.getModelId(), detail.getNo());
workOrders.add(workOrder);
}
});
if (alertPush == 1) {
alarmService.pushAlertMes(dto.getDetails());
}
}
});
//todo 后续添加配置推送的告警等级
if (alertPush == 1) {
List<Alarm> alarms = alarmService.pushAlertMes(newList);
log.debug("alarms : {}", JsonUtils.toJsonString(alarms));
log.debug("workOrders : {}", JsonUtils.toJsonString(workOrders));
if (!CollectionUtils.isEmpty(workOrders)) {
if (!CollectionUtils.isEmpty(alarms)) {
workOrders.forEach(x -> {
alarms.forEach(y -> {
if (x.getAlarmNo().equals(y.getAlarmNo())) {
x.setAlarmId(y.getId());
x.setTaskDescription(y.getAlarmContent());
}
});
});
}
wService.saveAll(workOrders);
}
}
}
});
}
}
}

View File

@@ -4,14 +4,13 @@ package com.maibu.service;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DevicePlanTask;
import com.maibu.core.business.DeviceTaskPlanRule;
import com.maibu.core.business.WorkRecord;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.enums.DeviceTaskPlanRepeatType;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.WorkRecordMapper;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import lombok.extern.slf4j.Slf4j;

View File

@@ -9,6 +9,7 @@ import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import com.maibu.memory.DeviceSessionManager;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -29,7 +30,6 @@ import com.maibu.dto.DevicePlanStatisticsDTO;
import com.maibu.dto.DevicePlanTaskStatisticsDTO;
import com.maibu.dto.DeviceTaskQueryDTO;
import com.maibu.dto.DeviceWorkStatisticsDTO;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.mapper.DeviceMapper;
import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DevicePlanTaskMapper;
@@ -454,7 +454,7 @@ public class DeviceTaskService {
return list;
}
public boolean createDeviceTask(DeviceTaskCommandDTO dto, String username) {
public Long createDeviceTask(DeviceTaskCommandDTO dto, String username) {
DevicePlanTask task = new DevicePlanTask();
task.setOrgId(dto.getOrgId());
task.setSiteId(dto.getSiteId());
@@ -464,7 +464,7 @@ public class DeviceTaskService {
task.setCreateTime(LocalDateTime.now());
task.setRouteId(dto.getRouteId());
task.setStartTime(dto.getStartTime());
boolean result = devicePlanTaskMapper.saveOrUpdate(task);
devicePlanTaskMapper.saveOrUpdate(task);
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
@@ -473,7 +473,7 @@ public class DeviceTaskService {
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
siteMemory.addDevicePlanPrepare(task);
return result;
return task.getId();
}
public boolean cancelTask(DeviceTaskCommandDTO dto, String username) {

View File

@@ -14,6 +14,7 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.maibu.memory.DeviceSessionManager;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -36,7 +37,6 @@ import com.maibu.core.enums.ErrorSource;
import com.maibu.core.enums.RespondCode;
import com.maibu.core.redis.RedisCache;
import com.maibu.dto.DeviceErrorPushDTO;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.mapper.ErrorIdentificationStandardMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
@@ -92,13 +92,14 @@ public class DeviceThreadService {
String[] parts = k.split(":");
String deviceId = parts[1];
NettyDevice slaveDevice = sessionManager.getDevice(deviceId);
Long siteId = slaveDevice != null ? slaveDevice.getDevice().getSiteId() : null;
Long orgId = slaveDevice != null ? slaveDevice.getDevice().getOrgId() : null;
if (slaveDevice != null && slaveDevice.isOnline()) {
Long siteId = slaveDevice.getDevice().getSiteId();
Long orgId = slaveDevice.getDevice().getOrgId();
log.debug("compare siteId:{},orgId:{}", siteId, orgId);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory != null) {
List<AlarmMessage> compared = compareErrorStandard(siteId, orgId, history,
siteMemory.standards.get(ErrorSource.MOWER));
DeviceErrorPushDTO pushDTO = new DeviceErrorPushDTO();
pushDTO.setDeviceId(deviceId);
pushDTO.setTime(System.currentTimeMillis());
@@ -106,6 +107,8 @@ public class DeviceThreadService {
pushDTO.setEvent(RespondCode.device_error_push);
pushList.add(pushDTO);
}
}
}
});
// 按实际deviceId分组,推送错误信息
Map<String, List<DeviceErrorPushDTO>> pushMap = pushList.stream()
@@ -204,9 +207,11 @@ public class DeviceThreadService {
String compareValues = standard.getCompareValues();
CompareEnum compareType = standard.getCompareType();
String targetValue = knownClassFieldFinding(fieldName, history);
log.debug("compare2 compareType:{} compareValues:{},targetValue:{}", compareType, compareValues, targetValue);
if (!StringUtils.isEmpty(compareValues) && !StringUtils.isEmpty(targetValue)) {
boolean result = CompareUtils.compare(compareType, compareValues, targetValue);
if (!result) {
boolean result = CompareUtils.compare(compareType, targetValue, compareValues);
log.debug("compare3 result:{}", result);
if (result) {
AlarmMessage alarm = new AlarmMessage();
alarm.setContent(standard.getErrorDescription());
alarm.setDeviceSn(history.getDeviceId());
@@ -217,6 +222,7 @@ public class DeviceThreadService {
alarm.setNo(standard.getErrorCode());
alarm.setSuggestion(standard.getSuggestion());
alarm.setStatus("未处理");
alarm.setTimeValues(targetValue);
alarm.setTime(LocalDateTime.now());
alarm.setOrgId(orgId);
alarm.setSiteId(siteId);

View File

@@ -1,14 +1,19 @@
package com.maibu.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.constant.Constant;
import com.maibu.core.business.DeviceRunningStatusHistory;
import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.dto.SendCommandDTO;
import com.maibu.mapper.DeviceStatusHistoryMapper;
import com.maibu.mapper.ErrorIdentificationStandardMapper;
import com.maibu.memory.DeviceSessionManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
@@ -19,6 +24,9 @@ public class NettyDeviceService {
@Autowired
private DeviceStatusHistoryMapper deviceStatusHistoryMapper;
@Autowired
private DeviceSessionManager deviceSessionManager;
@Autowired
private ErrorIdentificationStandardMapper errorIdentificationStandardMapper;
@@ -40,5 +48,25 @@ public class NettyDeviceService {
return errorIdentificationStandardMapper.updateById(standard);
}
public void sendCommand(SendCommandDTO command) {
if (command == null || command.getCommandType() == null || CollectionUtils.isEmpty(command.getDeviceIds()))
return;
command.getDeviceIds().forEach(deviceId -> {
NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceId);
if (nettyDevice != null && !nettyDevice.isExecutingTask()) {
if (nettyDevice.getChannel() != null && nettyDevice.getChannel().isActive()) {
if (Constant.WheelGainCoefficients.equals(command.getCommandType())) {
double leftForwardGain = (double) command.getParams().get("leftForwardGain");
double leftBackwardGain = (double) command.getParams().get("leftBackwardGain");
double rightForwardGain = (double) command.getParams().get("rightForwardGain");
double rightBackwardGain = (double) command.getParams().get("rightBackwardGain");
nettyDevice.sendWheelGainCoefficientsCommand(leftForwardGain, leftBackwardGain, rightForwardGain, rightBackwardGain);
}
}
}
});
}
}

View File

@@ -7,9 +7,9 @@ import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.entity.UserClient;
import com.maibu.core.domain.model.LoginUser;
import com.maibu.core.enums.ConnectorStatus;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.mapper.DeviceMapper;
import com.maibu.mapper.SysUserClientMapper;
import com.maibu.memory.DeviceSessionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

View File

@@ -31,38 +31,38 @@ public class CompareUtils {
return !compareValue.equals(targetValue);
case GT:
return isNumeric(compareValue) && isNumeric(targetValue) &&
Double.parseDouble(compareValue) > Double.parseDouble(targetValue);
Double.parseDouble(targetValue) > Double.parseDouble(compareValue);
case LT:
return isNumeric(compareValue) && isNumeric(targetValue) &&
Double.parseDouble(compareValue) < Double.parseDouble(targetValue);
Double.parseDouble(targetValue) < Double.parseDouble(compareValue);
case GTE:
return isNumeric(compareValue) && isNumeric(targetValue) &&
Double.parseDouble(compareValue) >= Double.parseDouble(targetValue);
Double.parseDouble(targetValue) >= Double.parseDouble(compareValue);
case LTE:
return isNumeric(compareValue) && isNumeric(targetValue) &&
Double.parseDouble(compareValue) <= Double.parseDouble(targetValue);
Double.parseDouble(targetValue) <= Double.parseDouble(compareValue);
case BETWEEN:
// 范围值用英文中划线分割
String[] rangeValues = targetValue.split("-");
String[] rangeValues = compareValue.split("-");
if (rangeValues.length != 2) {
return false;
}
return isNumeric(compareValue) && isNumeric(rangeValues[0]) && isNumeric(rangeValues[1]) &&
Double.parseDouble(compareValue) >= Double.parseDouble(rangeValues[0]) &&
Double.parseDouble(compareValue) <= Double.parseDouble(rangeValues[1]);
Double.parseDouble(targetValue) >= Double.parseDouble(rangeValues[0]) &&
Double.parseDouble(targetValue) <= Double.parseDouble(rangeValues[1]);
case NOT_BETWEEN:
// 范围值用英文中划线分割
String[] notRangeValues = targetValue.split("-");
String[] notRangeValues = compareValue.split("-");
if (notRangeValues.length != 2) {
return false;
}
return isNumeric(compareValue) && isNumeric(notRangeValues[0]) && isNumeric(notRangeValues[1]) &&
(Double.parseDouble(compareValue) < Double.parseDouble(notRangeValues[0]) ||
Double.parseDouble(compareValue) > Double.parseDouble(notRangeValues[1]));
(Double.parseDouble(targetValue) < Double.parseDouble(notRangeValues[0]) ||
Double.parseDouble(targetValue) > Double.parseDouble(notRangeValues[1]));
case CONTAIN:
return compareValue.contains(targetValue);
return targetValue.contains(compareValue);
case NOT_CONTAIN:
return !compareValue.contains(targetValue);
return !targetValue.contains(compareValue);
default:
return false;
}

View File

@@ -12,6 +12,7 @@ public class DingTalkTemplate {
"告警时间:%s\n\n" +
"设备名称:%s\n\n" +
"设备编号:%s\n\n" +
"当前值:%s\n\n" +
"告警内容:\n%s\n\n" +
"发生位置:\n%s\n\n" +
"处理建议:\n%s\n\n" +
@@ -21,6 +22,7 @@ public class DingTalkTemplate {
alarm.getTime(),
alarm.getDeviceName(),
alarm.getDeviceSn(),
alarm.getTimeValues(),
alarm.getContent(),
alarm.getLocation(),
alarm.getSuggestion(),

View File

@@ -75,7 +75,7 @@ public class AlarmController extends BaseController {
//@PreAuthorize("@ss.hasPermi('iot:alarm:handle')")
@Log(title = "告警处理", businessType = BusinessType.UPDATE)
@PutMapping("/handle")
@PostMapping("/handle")
@ApiOperation("处理告警")
public AjaxResult handle(@RequestBody AlarmHandleDTO handleDTO) {
return toAjax(alarmService.handleAlarm(handleDTO));

View File

@@ -1,6 +1,8 @@
package com.maibu.controller;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -25,7 +27,7 @@ public class DeviceRunParamController extends BaseController {
private DeviceRunParamService service;
@PostMapping("/save")
public AjaxResult save(@RequestBody DeviceRunParam deviceRunParam) {
public AjaxResult save(@RequestBody DeviceRunParam deviceRunParam) throws ExecutionException, InterruptedException, TimeoutException {
return AjaxResult.success(service.save(deviceRunParam));
}
@@ -37,7 +39,7 @@ public class DeviceRunParamController extends BaseController {
}
@GetMapping("/selectByDeviceId")
public AjaxResult selectByDeviceId(@RequestParam String deviceId) {
public AjaxResult selectByDeviceId(@RequestParam String deviceId) throws ExecutionException, InterruptedException, TimeoutException {
return AjaxResult.success(service.selectByDeviceId(deviceId));
}

View File

@@ -1,11 +1,16 @@
package com.maibu.controller;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import com.maibu.service.impl.AlarmServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -13,7 +18,9 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.maibu.annotation.Log;
import com.maibu.core.business.IOTWorkOrder;
@@ -25,6 +32,7 @@ import com.maibu.core.domain.AjaxResult;
import com.maibu.core.page.TableDataInfo;
import com.maibu.enums.BusinessType;
import com.maibu.service.IWorkOrderService;
import com.maibu.utils.MinioUtil;
import com.maibu.utils.poi.ExcelUtil;
import io.swagger.annotations.Api;
@@ -40,6 +48,12 @@ public class IOTWorkOrderController extends BaseController {
@Autowired
private IWorkOrderService workOrderService;
@Autowired
private AlarmServiceImpl alarmServiceImpl;
@Autowired
private MinioUtil minioUtil;
// @PreAuthorize("@ss.hasPermi('iot:workOrder:list')")
@GetMapping("/list")
@ApiOperation("工单分页列表")
@@ -47,22 +61,90 @@ public class IOTWorkOrderController extends BaseController {
return workOrderService.selectWorkOrderPage(queryDTO);
}
//@PreAuthorize("@ss.hasPermi('iot:workOrder:query')")
// @PreAuthorize("@ss.hasPermi('iot:workOrder:query')")
@GetMapping("/{id}")
@ApiOperation("获取工单详情")
public AjaxResult getInfo(@PathVariable Long id) {
return AjaxResult.success(workOrderService.selectWorkOrderById(id));
}
// @PreAuthorize("@ss.hasPermi('iot:workOrder:add')")
@Log(title = "工单管理", businessType = BusinessType.INSERT)
@PostMapping
@ApiOperation("新增工单")
public AjaxResult add(@RequestBody IOTWorkOrder workOrder) {
if (workOrder != null && workOrder.getAlarmId() != null) {
if (alarmServiceImpl.existWorkOrder(workOrder.getAlarmId())) {
return AjaxResult.error("当前告警已存在创建的工单!");
}
}
return toAjax(workOrderService.insertWorkOrder(workOrder));
}
//@PreAuthorize("@ss.hasPermi('iot:workOrder:edit')")
@PostMapping(value = "/add", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AjaxResult addWorkRecord(
@RequestPart(value = "file", required = false) MultipartFile[] files, // 接收上传的图片
@RequestPart(value = "video", required = false) MultipartFile[] videos, // 接收上传的视频
@RequestPart("workOrder") IOTWorkOrder workOrder // 接收表单里的 JSON 对象
) {
// try (InputStream inputStream = file.getInputStream()) {
// String fileName = "workOrder/img_" + workOrder.getOrderTitle() + System.currentTimeMillis() + ".png";
// // 上传到 MinIO
// minioUtil.uploadFile(fileName, inputStream, "image/png");
// // 获取访问 URL
// String url = minioUtil.getPublicUrl(fileName);
// System.out.println("✅ 图片上传成功,访问地址: " + url);
// // 这里可以把 URL 存到 workRecord 里
// workOrder.setImgUrl(url);
// } catch (Exception e) {
// return AjaxResult.error(e.getMessage());
// }
if (workOrder != null && workOrder.getAlarmId() != null) {
if (alarmServiceImpl.existWorkOrder(workOrder.getAlarmId())) {
return AjaxResult.error("当前告警已存在创建的工单!");
}
}
List<String> imgUrls = new ArrayList<>();
if (files != null) {
for (MultipartFile file : files) {
String suffix = file.getOriginalFilename()
.substring(file.getOriginalFilename().lastIndexOf("."));
String fileName = "workOrder/img_" + UUID.randomUUID() + suffix + file.getContentType();
try (InputStream inputStream = file.getInputStream()) {
minioUtil.uploadFile(fileName, inputStream, file.getContentType());
imgUrls.add(minioUtil.getPublicUrl(fileName));
} catch (Exception e) {
return AjaxResult.error("图片上传失败:" + e.getMessage());
}
}
}
// 保存图片URL(建议数据库存JSON或逗号分隔)
workOrder.setImgUrl(imgUrls);
List<String> videoUrls = new ArrayList<>();
if (videos != null) {
for (MultipartFile video : videos) {
String suffix = video.getOriginalFilename()
.substring(video.getOriginalFilename().lastIndexOf("."));
String fileName = "workOrder/video_" + UUID.randomUUID() + suffix + video.getContentType();
;
try (InputStream inputStream = video.getInputStream()) {
minioUtil.uploadFile(fileName, inputStream, video.getContentType());
videoUrls.add(minioUtil.getPublicUrl(fileName));
} catch (Exception e) {
return AjaxResult.error("视频上传失败:" + e.getMessage());
}
}
}
workOrder.setVideoUrl(videoUrls);
return AjaxResult.success(workOrderService.insertWorkOrder(workOrder));
}
// @PreAuthorize("@ss.hasPermi('iot:workOrder:edit')")
@Log(title = "工单管理", businessType = BusinessType.UPDATE)
@PutMapping
@ApiOperation("修改工单")
@@ -78,10 +160,10 @@ public class IOTWorkOrderController extends BaseController {
return toAjax(workOrderService.dispatchWorkOrder(dispatchDTO));
}
@PostMapping("/start")
@ApiOperation("开始执行工单")
public AjaxResult start(@RequestBody WorkOrderStartDTO dto) {
public AjaxResult start(
@RequestBody WorkOrderStartDTO dto) {
return toAjax(workOrderService.startWorkOrder(dto));
}
@@ -89,11 +171,30 @@ public class IOTWorkOrderController extends BaseController {
@Log(title = "工单完成", businessType = BusinessType.UPDATE)
@PostMapping("/complete")
@ApiOperation("完成工单")
public AjaxResult complete(@RequestBody IOTWorkOrder workOrder) {
return toAjax(workOrderService.completeWorkOrder(workOrder));
public AjaxResult complete(@RequestPart(value = "files", required = false) MultipartFile[] files,
@RequestPart("workOrder") IOTWorkOrder workOrder
) {
List<String> imgUrls = new ArrayList<>();
if (files != null) {
for (MultipartFile file : files) {
String suffix = file.getOriginalFilename()
.substring(file.getOriginalFilename().lastIndexOf("."));
String fileName = "workOrder/img_" + UUID.randomUUID() + suffix + file.getContentType();
try (InputStream inputStream = file.getInputStream()) {
minioUtil.uploadFile(fileName, inputStream, file.getContentType());
imgUrls.add(minioUtil.getPublicUrl(fileName));
} catch (Exception e) {
return AjaxResult.error("图片上传失败:" + e.getMessage());
}
}
}
return toAjax(workOrderService.completeWorkOrder(workOrder, imgUrls));
}
//@PreAuthorize("@ss.hasPermi('iot:workOrder:suspend')")
// @PreAuthorize("@ss.hasPermi('iot:workOrder:suspend')")
@Log(title = "工单挂起", businessType = BusinessType.UPDATE)
@PostMapping("/suspend/{id}")
@ApiOperation("挂起工单")
@@ -101,7 +202,7 @@ public class IOTWorkOrderController extends BaseController {
return toAjax(workOrderService.suspendWorkOrder(id));
}
//@PreAuthorize("@ss.hasPermi('iot:workOrder:remove')")
// @PreAuthorize("@ss.hasPermi('iot:workOrder:remove')")
@Log(title = "工单管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@ApiOperation("删除工单")
@@ -117,7 +218,7 @@ public class IOTWorkOrderController extends BaseController {
return AjaxResult.success(statistics);
}
//@PreAuthorize("@ss.hasPermi('iot:workOrder:export')")
// @PreAuthorize("@ss.hasPermi('iot:workOrder:export')")
@Log(title = "工单管理", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@ApiOperation("导出工单")

View File

@@ -19,9 +19,9 @@ public interface IAlarmService extends IService<Alarm> {
int insertAlarm(Alarm alarm);
int updateAlarm(Alarm alarm);
boolean updateAlarm(Alarm alarm);
int handleAlarm(AlarmHandleDTO handleDTO);
boolean handleAlarm(AlarmHandleDTO handleDTO);
int deleteAlarmById(Long id);

View File

@@ -26,7 +26,7 @@ public interface IWorkOrderService extends IService<IOTWorkOrder> {
boolean startWorkOrder(WorkOrderStartDTO dto);
int completeWorkOrder(IOTWorkOrder workOrder);
int completeWorkOrder(IOTWorkOrder workOrder, List<String> imgUrls);
int suspendWorkOrder(Long id);

View File

@@ -6,8 +6,11 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.maibu.core.enums.AlarmType;
import com.maibu.core.redis.RedisCache;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -45,6 +48,9 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
@Autowired
private AlarmMapper alarmMapper;
@Autowired
private RedisCache redisCache;
@Override
public List<Alarm> selectAlarmPage(AlarmQueryDTO queryDTO) {
// validateQueryParams(queryDTO);
@@ -71,8 +77,8 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
Map<String, Object> statistics = new HashMap<>();
statistics.put("total", alarms.size());
statistics.put("pending", alarms.stream().filter(a -> a.getHandleStatus() == 1).count());
statistics.put("processing", alarms.stream().filter(a -> a.getHandleStatus() == 2).count());
statistics.put("closed", alarms.stream().filter(a -> a.getHandleStatus() == 3).count());
// statistics.put("processing", alarms.stream().filter(a -> a.getHandleStatus() == 2).count());
statistics.put("closed", alarms.stream().filter(a -> a.getHandleStatus() == 2).count());
statistics.put("levelStats",
alarms.stream().collect(Collectors.groupingBy(Alarm::getAlarmLevel, Collectors.counting())));
@@ -196,6 +202,9 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
if (!StringUtils.isEmpty(queryDTO.getAlarmNo())) {
wrapper.like(Alarm::getAlarmNo, queryDTO.getAlarmNo());
}
if (queryDTO.getHandleStatus() != null) {
wrapper.eq(Alarm::getHandleStatus, queryDTO.getHandleStatus());
}
if (!StringUtils.isEmpty(queryDTO.getDeviceId())) {
wrapper.eq(Alarm::getDeviceId, queryDTO.getDeviceId());
}
@@ -226,11 +235,10 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
Alarm alarm = alarmMapper.selectById(id);
if (alarm == null)
throw new ServiceException("告警不存在");
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId) && alarm.getDeviceId() != null) {
validateDeviceAccess(alarm.getDeviceId());
}
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId) && alarm.getDeviceId() != null) {
// validateDeviceAccess(alarm.getDeviceId());
// }
return alarm;
}
@@ -247,40 +255,65 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
}
@Override
public int updateAlarm(Alarm alarm) {
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId) && alarm.getId() != null) {
Alarm existAlarm = alarmMapper.selectById(alarm.getId());
if (existAlarm != null && existAlarm.getDeviceId() != null) {
validateDeviceAccess(existAlarm.getDeviceId());
}
}
return alarmMapper.updateById(alarm);
public boolean updateAlarm(Alarm alarm) {
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId) && alarm.getId() != null) {
// Alarm existAlarm = alarmMapper.selectById(alarm.getId());
// if (existAlarm != null && existAlarm.getDeviceId() != null) {
// validateDeviceAccess(existAlarm.getDeviceId());
// }
// }
return alarmMapper.saveOrUpdate(alarm);
}
@Override
public int handleAlarm(AlarmHandleDTO handleDTO) {
public boolean handleAlarm(AlarmHandleDTO handleDTO) {
Alarm alarm = alarmMapper.selectById(handleDTO.getAlarmId());
if (alarm == null)
throw new ServiceException("告警不存在");
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId) && alarm.getDeviceId() != null) {
validateDeviceAccess(alarm.getDeviceId());
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId) && alarm.getDeviceId() != null) {
// validateDeviceAccess(alarm.getDeviceId());
// }
// Alarm updateAlarm = new Alarm();
// updateAlarm.setId(handleDTO.getAlarmId());
alarm.setHandleStatus(handleDTO.getHandleStatus());
alarm.setHandleUserId(SecurityUtils.getUserId());
alarm.setHandleUserName(SecurityUtils.getLoginUser().getUser().getNickName());
alarm.setHandleTime(LocalDateTime.now());
alarm.setHandleRemark(handleDTO.getHandleRemark());
alarm.setHandleResult(handleDTO.getHandleResult());
removeRedisAlarm(alarm.getDeviceId(), alarm.getAlarmNo());
return alarmMapper.saveOrUpdate(alarm);
}
Alarm updateAlarm = new Alarm();
updateAlarm.setId(handleDTO.getAlarmId());
updateAlarm.setHandleStatus(handleDTO.getHandleStatus());
updateAlarm.setHandleUserId(SecurityUtils.getUserId());
updateAlarm.setHandleUserName(SecurityUtils.getLoginUser().getUser().getNickName());
updateAlarm.setHandleTime(LocalDateTime.now());
updateAlarm.setHandleRemark(handleDTO.getHandleRemark());
public void removeRedisAlarm(String deviceId, String alarmNo) {
if (StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(alarmNo)) return;
String pushKey = "alarm:" + "dingtalk:" + deviceId + ":" + alarmNo;
// Boolean exists = redisCache.hasKey(pushKey);
// if (exists != null && exists) {
// redisCache.deleteObject(pushKey);
// }
String pushKey2 = "alarm:" + "email:" + deviceId + ":" + alarmNo;
// Boolean exists2 = redisCache.hasKey(pushKey2);
// if (exists2 != null && exists2) {
// redisCache.deleteObject(pushKey2);
// }
String pushKey3 = "alarm:" + "mqtt:" + deviceId + ":" + alarmNo;
// Boolean exists3 = redisCache.hasKey(pushKey3);
// if (exists3 != null && exists3) {
// redisCache.deleteObject(pushKey3);
// }
redisCache.deleteObject(pushKey);
redisCache.deleteObject(pushKey2);
redisCache.deleteObject(pushKey3);
if (handleDTO.getHandleStatus() == 3) {
updateAlarm.setRecoverTime(LocalDateTime.now());
}
return alarmMapper.updateById(updateAlarm);
}
@Override
@@ -344,16 +377,16 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
return statistics;
}
public void pushAlertMes(List<AlarmMessage> alarmMessages) {
public List<Alarm> pushAlertMes(List<AlarmMessage> alarmMessages) {
if (alarmMessages == null || alarmMessages.isEmpty()) {
return;
return null;
}
List<Alarm> list = new ArrayList<>();
for (AlarmMessage alarmMessage : alarmMessages) {
Alarm alarm = new Alarm();
alarm.setAlarmNo(alarmMessage.getNo());
alarm.setAlarmLevel(alarmMessage.getLevel());
alarm.setAlarmType(1);
alarm.setAlarmType(AlarmType.MOWER_FAULT);
alarm.setAlarmTitle(alarmMessage.getName());
alarm.setAlarmContent(alarmMessage.getContent());
alarm.setDeviceId(alarmMessage.getDeviceName());
@@ -361,12 +394,14 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
alarm.setDeviceType(ErrorSource.MOWER);
alarm.setAlarmTime(LocalDateTime.now());
alarm.setOrgId(alarmMessage.getOrgId());
alarm.setTimeValues(alarmMessage.getTimeValues());
alarm.setSiteId(alarmMessage.getSiteId());
alarm.setAlarmTime(LocalDateTime.now());
pushErrorMessage(alarmMessage.getDeviceName(), JsonUtils.toJsonString(alarm));
list.add(alarm);
}
alarmMapper.saveOrUpdateBatch(list);
return list;
// todo 推送websocket?
}
@@ -386,4 +421,12 @@ public class AlarmServiceImpl extends ServiceImpl<AlarmMapper, Alarm> implements
}
}
public boolean existWorkOrder(Long alarmId) {
boolean b = false;
if (alarmId != null) {
b = alarmMapper.selectById(alarmId) != null;
}
return b;
}
}

View File

@@ -1,31 +1,74 @@
package com.maibu.service.impl;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.constant.Constant;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.dto.BaseQueryDTO;
import com.maibu.exception.ServiceException;
import com.maibu.mapper.DeviceRunParamMapper;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.business.DeviceRunParam;
import com.maibu.dto.BaseQueryDTO;
import com.maibu.mapper.DeviceRunParamMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@Service
@Slf4j
public class DeviceRunParamService {
@Autowired
private DeviceRunParamMapper deviceRunParamMapper;
public boolean save(DeviceRunParam deviceRunParam) {
@Autowired
private DeviceSessionManager sessionManager;
public boolean save(DeviceRunParam deviceRunParam) throws ExecutionException, InterruptedException, TimeoutException {
NettyDevice nettyDevice = sessionManager.getDevice(deviceRunParam.getDeviceId());
if (nettyDevice == null || !nettyDevice.getChannel().isActive()) {
throw new ServiceException("设备不在线,无法操作!");
}
CompletableFuture<DeviceRunParam> future = new CompletableFuture<>();
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(future);
try {
nettyDevice.readConfigCommand();
DeviceRunParam param = future.get(5, TimeUnit.SECONDS);
if (param == null) {
throw new ServiceException("获取设备当前属性失败!");
}
param.setLeftForwardGain(deviceRunParam.getLeftForwardGain());
param.setLeftBackwardGain(deviceRunParam.getLeftBackwardGain());
param.setRightForwardGain(deviceRunParam.getRightForwardGain());
param.setRightBackwardGain(deviceRunParam.getRightBackwardGain());
nettyDevice.writeConfigCommand(param);
if (deviceRunParam.getRunSpeed() != null) {
param.setRunSpeed(deviceRunParam.getRunSpeed());
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(deviceRunParam.getOrgId(), deviceRunParam.getSiteId());
if (siteMemory != null) {
siteMemory.saveDeviceRunParam(deviceRunParam);
siteMemory.saveDeviceRunParam(param);
}
return deviceRunParamMapper.saveOrUpdate(param);
} finally {
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(null);
}
return deviceRunParamMapper.saveOrUpdate(deviceRunParam);
}
public List<DeviceRunParam> list(BaseQueryDTO dto) {
@@ -34,19 +77,44 @@ public class DeviceRunParamService {
if (dto.getSiteId() != null) {
queryWrapper.eq(DeviceRunParam::getSiteId, dto.getSiteId());
}
if (StringUtils.isEmpty(dto.getDeviceId())) {
if (!StringUtils.isEmpty(dto.getDeviceId())) {
queryWrapper.eq(DeviceRunParam::getDeviceId, dto.getDeviceId());
}
}
return deviceRunParamMapper.selectList(queryWrapper);
}
public DeviceRunParam selectByDeviceId(String deviceId) {
public DeviceRunParam selectByDeviceId(String deviceId) throws ExecutionException, InterruptedException, TimeoutException {
LambdaQueryWrapper<DeviceRunParam> queryWrapper = new LambdaQueryWrapper<>();
if (!StringUtils.isEmpty(deviceId)) {
queryWrapper.eq(DeviceRunParam::getDeviceId, deviceId);
}
return deviceRunParamMapper.selectOne(queryWrapper);
DeviceRunParam result = deviceRunParamMapper.selectOne(queryWrapper);
if (result == null) {
NettyDevice nettyDevice = sessionManager.getDevice(deviceId);
CompletableFuture<DeviceRunParam> future = new CompletableFuture<>();
if (nettyDevice != null && nettyDevice.getChannel().isActive()) {
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(future);
try {
nettyDevice.readConfigCommand();
DeviceRunParam param = future.get(5, TimeUnit.SECONDS);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(nettyDevice.getDevice().getOrgId(), nettyDevice.getDevice().getSiteId());
if (siteMemory != null) {
param.setDeviceId(deviceId);
param.setOrgId(nettyDevice.getDevice().getOrgId());
param.setSiteId(nettyDevice.getDevice().getSiteId());
siteMemory.saveDeviceRunParam(param);
}
if (param != null) {
deviceRunParamMapper.saveOrUpdate(param);
return param;
}
} finally {
nettyDevice.getChannel().attr(Constant.READ_CONFIG_KEY).set(null);
}
}
}
return result;
}
public int delete(List<Long> ids) {

View File

@@ -73,11 +73,12 @@ public class OrderModelService {
return i;
}
public void createTask(String deviceId, Long siteId, Long orgId, Long modelId) {
public String createTask(String deviceId, Long siteId, Long orgId, Long modelId) {
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
OrderModel orderModel = siteMemory.getOrderModel(modelId);
OrderType orderType = orderModel.getOrderType();
// 割草机
String taskId = null;
if (orderType != null && orderType.getType() == 1) {
Long routeId = orderModel.getRouteId();
DeviceTaskCommandDTO dto = new DeviceTaskCommandDTO();
@@ -86,7 +87,7 @@ public class OrderModelService {
dto.setOrgId(orgId);
dto.setSiteId(siteId);
dto.setStartTime(LocalDateTime.now());
mowerDispather.dispathDeviceTask(dto);
taskId = String.valueOf(mowerDispather.dispathDeviceTask(dto));
}
// 无人机
if (orderType != null && orderType.getType() == 2) {
@@ -99,12 +100,13 @@ public class OrderModelService {
dto.setName(name);
dto.setRth_altitude(orderModel.getRthAltitude());
dto.setRth_mode(orderModel.getRthMode());
dispather.dispathFightTask(dto);
taskId = dispather.dispathFightTask(dto);
}
// 其他
if (orderType != null && orderType.getType() == 3) {
}
return taskId;
}

View File

@@ -2,13 +2,20 @@ package com.maibu.service.impl;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import com.maibu.core.business.alarm_center.Alarm;
import com.maibu.core.domain.entity.SysRole;
import com.maibu.core.enums.AlarmHandleResult;
import com.maibu.mapper.AlarmMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import com.maibu.service.ISysRoleService;
import com.maibu.utils.MinioUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -34,6 +41,7 @@ import com.maibu.utils.SecurityUtils;
import com.maibu.utils.StringUtils;
@Service
@Slf4j
public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWorkOrder> implements IWorkOrderService {
@Autowired
@@ -42,17 +50,30 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
@Autowired
private IAlarmService alarmService;
@Autowired
private AlarmServiceImpl alarmServiceImpl;
@Autowired
private IotWorkOrderMapper iotWorkOrderMapper;
@Autowired
private AlarmMapper alarmMapper;
@Autowired
private OrderModelMapper orderModelMapper;
@Autowired
private OrderModelService orderModelService;
@Autowired
private MinioUtil minioUtil;
@Autowired
private ISysRoleService roleService;
@Override
public TableDataInfo selectWorkOrderPage(WorkOrderQueryDTO queryDTO) {
validateQueryParams(queryDTO);
LambdaQueryWrapper<IOTWorkOrder> wrapper = buildQueryWrapper(queryDTO);
@@ -150,43 +171,26 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
private LambdaQueryWrapper<IOTWorkOrder> buildQueryWrapper(WorkOrderQueryDTO queryDTO) {
LambdaQueryWrapper<IOTWorkOrder> wrapper = new LambdaQueryWrapper<>();
Long userId = SecurityUtils.getUserId();
LoginUser loginUser = SecurityUtils.getLoginUser();
Long userOrgId = loginUser.getOrgId();
Long userSiteId = loginUser.getSiteId();
if (!SecurityUtils.isAdmin(userId)) {
if (queryDTO.getSiteId() != null) {
wrapper.eq(IOTWorkOrder::getSiteId, queryDTO.getSiteId());
if (userOrgId != null) {
wrapper.eq(IOTWorkOrder::getOrgId, userOrgId);
}
} else if (userSiteId != null) {
wrapper.eq(IOTWorkOrder::getSiteId, userSiteId);
} else if (userOrgId != null) {
wrapper.eq(IOTWorkOrder::getOrgId, userOrgId);
}
if (queryDTO.getAssigneeId() != null) {
wrapper.eq(IOTWorkOrder::getAssigneeId, queryDTO.getAssigneeId());
if (loginUser != null && loginUser.getRoleId() != null) {
SysRole sysRole = roleService.selectRoleById(loginUser.getRoleId());
if (sysRole != null) {
String roleKey = sysRole.getRoleKey();
if (!StringUtils.isEmpty(roleKey)) {
if ("manager".equals(roleKey) || "siteManager".equals(roleKey) || "admin".equals(roleKey)) {
// device.setSiteId(siteId);
} else {
wrapper.and(w -> w.eq(IOTWorkOrder::getAssigneeId, userId)
.or()
.apply("FIND_IN_SET({0}, collaborator_ids)", userId));
wrapper.eq(IOTWorkOrder::getAssigneeId, loginUser.getUserId());
}
}
}
}
} else {
if (queryDTO.getSiteId() != null) {
wrapper.eq(IOTWorkOrder::getSiteId, queryDTO.getSiteId());
}
if (queryDTO.getOrgId() != null) {
wrapper.eq(IOTWorkOrder::getOrgId, queryDTO.getOrgId());
}
if (queryDTO.getAssigneeId() != null) {
wrapper.eq(IOTWorkOrder::getAssigneeId, queryDTO.getAssigneeId());
}
}
if (queryDTO.getOrderNo() != null && !queryDTO.getOrderNo().isEmpty()) {
wrapper.like(IOTWorkOrder::getOrderNo, queryDTO.getOrderNo());
}
@@ -226,14 +230,14 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
@Override
public IOTWorkOrder selectWorkOrderById(Long id) {
IOTWorkOrder workOrder = baseMapper.selectById(id);
IOTWorkOrder workOrder = iotWorkOrderMapper.selectById(id);
if (workOrder == null)
throw new ServiceException("工单不存在");
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
validateWorkOrderAccess(workOrder);
}
// if (!SecurityUtils.isAdmin(userId)) {
// validateWorkOrderAccess(workOrder);
// }
return workOrder;
}
@@ -293,13 +297,13 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
throw new ServiceException("工单ID不能为空");
}
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
IOTWorkOrder existWorkOrder = baseMapper.selectById(workOrder.getId());
if (existWorkOrder != null) {
validateWorkOrderAccess(existWorkOrder);
}
}
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId)) {
// IOTWorkOrder existWorkOrder = baseMapper.selectById(workOrder.getId());
// if (existWorkOrder != null) {
// validateWorkOrderAccess(existWorkOrder);
// }
// }
IOTWorkOrder updateEntity = new IOTWorkOrder();
updateEntity.setId(workOrder.getId());
@@ -336,10 +340,10 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
if (workOrder == null)
throw new ServiceException("工单不存在");
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
validateWorkOrderAccess(workOrder);
}
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId)) {
// validateWorkOrderAccess(workOrder);
// }
IOTWorkOrder updateWorkOrder = new IOTWorkOrder();
updateWorkOrder.setId(dispatchDTO.getOrderId());
@@ -366,7 +370,10 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
Long userId = SecurityUtils.getUserId();
String userName = SecurityUtils.getUsername();
workOrders.forEach(workOrder -> {
workOrder.setOrderStatus(3);
workOrder.setOrderStatus(2);
if (workOrder.getPlanStartTime() == null) {
workOrder.setPlanStartTime(LocalDateTime.now());
}
workOrder.setActualStartTime(LocalDateTime.now());
workOrder.setUpdateTime(LocalDateTime.now());
workOrder.setUpdateBy(userName);
@@ -377,30 +384,46 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
if (modelId == null) return;
Long siteId = workOrder.getSiteId();
Long orgId = workOrder.getOrgId();
orderModelService.createTask(dto.getDeviceId(), siteId, orgId, modelId);
String id = orderModelService.createTask(dto.getDeviceId(), siteId, orgId, modelId);
workOrder.setTaskId(id);
});
return baseMapper.saveOrUpdateBatch(workOrders);
}
@Override
public int completeWorkOrder(IOTWorkOrder workOrder) {
IOTWorkOrder existWorkOrder = baseMapper.selectById(workOrder.getId());
@Transactional
public int completeWorkOrder(IOTWorkOrder workOrder, List<String> imgUrls) {
IOTWorkOrder existWorkOrder = iotWorkOrderMapper.selectById(workOrder.getId());
if (existWorkOrder == null)
throw new ServiceException("工单不存在");
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
validateWorkOrderAccess(existWorkOrder);
}
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId)) {
// validateWorkOrderAccess(existWorkOrder);
// }
IOTWorkOrder updateWorkOrder = new IOTWorkOrder();
updateWorkOrder.setId(workOrder.getId());
updateWorkOrder.setOrderStatus(4);
updateWorkOrder.setOrderStatus(3);
updateWorkOrder.setImages(imgUrls);
updateWorkOrder.setActualEndTime(LocalDateTime.now());
updateWorkOrder.setHandleResult(workOrder.getHandleResult());
updateWorkOrder.setHandleRemark(workOrder.getHandleRemark());
updateWorkOrder.setUpdateTime(LocalDateTime.now());
updateWorkOrder.setUpdateBy(SecurityUtils.getLoginUser().getUser().getNickName());
if (existWorkOrder.getAlarmId() != null) {
Alarm alarm = alarmMapper.selectById(existWorkOrder.getAlarmId());
if (alarm != null) {
// alarm.setHandleResult(AlarmHandleResult.Handled);
alarm.setHandleStatus(2);
alarm.setUpdateTime(LocalDateTime.now());
alarm.setUpdateBy("system");
alarmMapper.saveOrUpdate(alarm);
alarmServiceImpl.removeRedisAlarm(alarm.getDeviceId(), alarm.getAlarmNo());
}
}
return baseMapper.updateById(updateWorkOrder);
}
@@ -417,7 +440,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
IOTWorkOrder updateWorkOrder = new IOTWorkOrder();
updateWorkOrder.setId(id);
updateWorkOrder.setOrderStatus(5);
updateWorkOrder.setOrderStatus(4);
updateWorkOrder.setUpdateTime(LocalDateTime.now());
updateWorkOrder.setUpdateBy(SecurityUtils.getLoginUser().getUser().getNickName());
return baseMapper.updateById(updateWorkOrder);
@@ -437,16 +460,16 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
@Override
public int deleteWorkOrderByIds(Long[] ids) {
Long userId = SecurityUtils.getUserId();
if (!SecurityUtils.isAdmin(userId)) {
for (Long id : ids) {
IOTWorkOrder workOrder = baseMapper.selectById(id);
if (workOrder != null) {
validateWorkOrderAccess(workOrder);
}
}
}
return baseMapper.deleteBatchIds(Arrays.asList(ids));
// Long userId = SecurityUtils.getUserId();
// if (!SecurityUtils.isAdmin(userId)) {
// for (Long id : ids) {
// IOTWorkOrder workOrder = baseMapper.selectById(id);
// if (workOrder != null) {
// validateWorkOrderAccess(workOrder);
// }
// }
// }
return iotWorkOrderMapper.deleteBatchIds(Arrays.asList(ids));
}
@Override
@@ -566,24 +589,27 @@ public class WorkOrderServiceImpl extends ServiceImpl<IotWorkOrderMapper, IOTWor
}
// 生成工单的方法
public IOTWorkOrder generateWorkOrders(Long siteId, String deviceId, Long orgId, Long modelId) {
OrderModel orderModel = orderModelMapper.selectById(modelId);
public IOTWorkOrder generateWorkOrders(Long siteId, String deviceId, Long orgId, Long modelId, String alarmNo) {
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
OrderModel orderModel = siteMemory.getOrderModel(modelId);
if (orderModel == null) {
throw new ServiceException("工单模板不存在");
}
IOTWorkOrder workOrder = new IOTWorkOrder();
workOrder.setOrderNo(generateOrderNo(orderModel.getOrderType().getValue()));
workOrder.setOrderTitle(workOrder.getOrderNo());
// workOrder.setSourceType(orderModel.ge());
workOrder.setSourceType(7);
workOrder.setOrderType(orderModel.getOrderType());
workOrder.setPriorityLevel(orderModel.getErrorLevel());
workOrder.setAlarmNo(alarmNo);
workOrder.setDeviceId(deviceId);
workOrder.setSiteId(siteId);
workOrder.setOrgId(orgId);
workOrder.setOrderStatus(1);
workOrder.setAutoCreate(true);
workOrder.setCreateTime(LocalDateTime.now());
workOrder.setCreateBy(SecurityUtils.getLoginUser().getUser().getNickName());
workOrder.setCreateBy("system");
log.debug("generateWorkOrders, alarmNo:{}", alarmNo);
return workOrder;
}

View File

@@ -2,7 +2,8 @@ package com.maibu.controller;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.MiddleGlobalMemory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -65,6 +66,7 @@ public class WebMiddlewareController extends BaseController {
}
});
res.put("nettyClientMap", nettyClients);
res.put("siteMemory", GlobalMemory.getAllSiteMemory());
return AjaxResult.success(res);
}

View File

@@ -1,6 +1,6 @@
package com.maibu.websocket;
import com.maibu.common.CommandConstant;
import com.maibu.constant.CommandConstant;
import com.maibu.common.MiddleConstant;
import com.maibu.core.enums.CommandRequestType;
import com.maibu.core.enums.MesType;