This commit is contained in:
2026-10-27 17:08:27 +08:00
parent 372b1a2d11
commit 965b38158f
50 changed files with 1416 additions and 174 deletions

View File

@@ -0,0 +1,67 @@
package com.maibu.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.map.SiteMapInfo;
import com.maibu.service.SiteMapInfoService;
/**
* 区域/场站
*
* @author ruoyi
*/
@RestController
@RequestMapping("/system/siteMapInfo")
public class SiteMapInfoController extends BaseController {
@Autowired
private SiteMapInfoService siteMapInfoService;
/**
* 新增或者修改组织
*/
@PostMapping("/save")
public AjaxResult save(@RequestBody SiteMapInfo siteMapInfo) {
try {
return AjaxResult.success(siteMapInfoService.save(siteMapInfo));
} catch (Exception e) {
return AjaxResult.error("新增修改场站出错", e.getMessage());
}
}
/**
* 查询场站详情
*/
@GetMapping("/selectById")
public AjaxResult selectById(@RequestParam Long id) {
try {
return AjaxResult.success(siteMapInfoService.selectById(id));
} catch (Exception e) {
return AjaxResult.error("查询场站详情出错", e.getMessage());
}
}
/**
* 查询组织下所有的区域场站
*/
@GetMapping("/selectBySiteId")
public AjaxResult selectBySiteId(@RequestParam Long siteId) {
try {
return AjaxResult.success(siteMapInfoService.selectBySiteId(siteId));
} catch (Exception e) {
return AjaxResult.error("查询组织下所有场站出错", e.getMessage());
}
}
}

View File

@@ -1,16 +1,19 @@
package com.maibu.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.entity.SysRegion;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.page.TableDataInfo;
import com.maibu.service.SysRegionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 区域/场站
@@ -23,20 +26,6 @@ public class SysRegionController extends BaseController {
@Autowired
private SysRegionService sysRegionService;
/**
* 查询组织列表
*/
@GetMapping("/list")
public TableDataInfo list(SysRegion region) {
try {
startPage();
return getDataTable(sysRegionService.list(region));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 新增或者修改组织
*/
@@ -81,9 +70,9 @@ public class SysRegionController extends BaseController {
*/
@GetMapping("/selectBySiteId")
public AjaxResult selectBySiteId(@RequestParam Long id) {
public AjaxResult selectBySiteId(@RequestParam Long siteId) {
try {
return AjaxResult.success(sysRegionService.selectBySiteId(id));
return AjaxResult.success(sysRegionService.selectBySiteId(siteId));
} catch (Exception e) {
return AjaxResult.error("保存组织出错", e.getMessage());
}

View File

@@ -102,6 +102,11 @@ public class DeviceTask {
return builder(FastBeeConstant.TASK.DEVICE_HEARTBEAT_MONITOR);
}
@Bean(FastBeeConstant.TASK.AUTO_RULE)
public Executor autoRule() {
return builder(FastBeeConstant.TASK.AUTO_RULE);
}
@Bean(FastBeeConstant.TASK.MAP_MESSAGE_PUSH)
public Executor mapMessagePush() {
return builder(FastBeeConstant.TASK.MAP_MESSAGE_PUSH);

View File

@@ -11,7 +11,6 @@ public interface FastBeeConstant {
String UFT8 = "UTF-8";
String GB2312 = "GB2312";
String MQTT = "mqtt";
String PORT = "port";
String ADAPTER = "adapter";
@@ -27,16 +26,16 @@ public interface FastBeeConstant {
String WM_PREFIX = "server-";
String FAST_PHONE = "phone-";
/*MQTT平台判定离线时间 keepAlive*1.5 */
/* MQTT平台判定离线时间 keepAlive*1.5 */
Long DEVICE_PING_EXPIRED = 90000L;
}
interface CLIENT {
//加盐
// 加盐
String TOKEN = "fastbee-smart!@#$123";
}
/*webSocket配置*/
/* webSocket配置 */
interface WS {
String HEART_BEAT = "heartbeat";
String HTTP_SERVER_CODEC = "httpServerCodec";
@@ -87,13 +86,13 @@ public interface FastBeeConstant {
* 消息消费线程
*/
String MESSAGE_CONSUME_TASK = "messageConsumeTask";
/*内部消费线程publish*/
/* 内部消费线程publish */
String MESSAGE_CONSUME_TASK_PUB = "messageConsumeTaskPub";
/*内部消费线程Fetch*/
/* 内部消费线程Fetch */
String MESSAGE_CONSUME_TASK_FETCH = "messageConsumeTaskFetch";
/*OTA升级延迟队列*/
/* OTA升级延迟队列 */
String DELAY_UPGRADE_TASK = "delayUpgradeTask";
/*OTA升级线程池*/
/* OTA升级线程池 */
String OTA_THREAD_POOL = "otaThreadPoolTaskExecutor";
/**
@@ -111,6 +110,10 @@ public interface FastBeeConstant {
*/
String MAP_MESSAGE_PUSH = "mapMessagePush";
/**
* 规则触发任务
*/
String AUTO_RULE = "autoRule";
/**
* 设备任务处理线程
@@ -128,67 +131,66 @@ public interface FastBeeConstant {
String PREDIX = "/+/+";
/*OTA消息回复*/
/* OTA消息回复 */
String OTA_REPLY = "upgrade/reply";
}
/*集群,全局发布的消息类型*/
/* 集群,全局发布的消息类型 */
interface CHANNEL {
/*设备状态*/
/* 设备状态 */
String DEVICE_STATUS = "device_status";
/*平台读取属性*/
/* 平台读取属性 */
String PROP_READ = "prop_read";
/*推送消息*/
/* 推送消息 */
String PUBLISH = "publish";
/*服务下发*/
/* 服务下发 */
String FUNCTION_INVOKE = "function_invoke";
/*事件*/
/* 事件 */
String EVENT = "event";
/*other*/
/* other */
String OTHER = "other";
/*Qos1 推送应答*/
/* Qos1 推送应答 */
String PUBLISH_ACK = "publish_ack";
/*Qos2 发布消息收到*/
/* Qos2 发布消息收到 */
String PUB_REC = "pub_rec";
/*Qos 发布消息释放*/
/* Qos 发布消息释放 */
String PUB_REL = "pub_rel";
/*Qos2 发布消息完成*/
/* Qos2 发布消息完成 */
String PUB_COMP = "pub_comp";
String UPGRADE = "upgrade";
/*-------------------------ROCKETMQ-------------------------*/
String SUFFIX = "group";
/*设备状态*/
/* 设备状态 */
String DEVICE_STATUS_GROUP = DEVICE_STATUS + SUFFIX;
String PROP_READ_GROUP = PROP_READ + SUFFIX;
/*服务下发*/
/* 服务下发 */
String FUNCTION_INVOKE_GROUP = FUNCTION_INVOKE + SUFFIX;
/*推送消息*/
/* 推送消息 */
String PUBLISH_GROUP = PUBLISH + SUFFIX;
/*Qos1 推送应答*/
/* Qos1 推送应答 */
String PUBLISH_ACK_GROUP = PUBLISH_ACK + SUFFIX;
/*Qos2 发布消息收到*/
/* Qos2 发布消息收到 */
String PUB_REC_GROUP = PUB_REC + SUFFIX;
/*Qos 发布消息释放*/
/* Qos 发布消息释放 */
String PUB_REL_GROUP = PUB_REL + SUFFIX;
/*Qos2 发布消息完成*/
/* Qos2 发布消息完成 */
String PUB_COMP_GROUP = PUB_COMP + SUFFIX;
/*OTA升级*/
/* OTA升级 */
String UPGRADE_GROUP = UPGRADE + SUFFIX;
}
/**
* redisKey 定义
*/
interface REDIS {
/*在线设备列表*/
/* 在线设备列表 */
String DEVICE_ONLINE_LIST = "device:online:list";
/*设备实时状态key*/
/* 设备实时状态key */
String DEVICE_RUNTIME_DATA = "device:runtime:";
/*通讯协议参数*/
/* 通讯协议参数 */
String DEVICE_PROTOCOL_PARAM = "device:param:";
/**
* 设备消息id缓存key
@@ -227,11 +229,11 @@ public interface FastBeeConstant {
*/
String MESSAGE_RETAIN_TOTAL = "message:retain:total";
/*发送消息数*/
/* 发送消息数 */
String MESSAGE_SEND_TOTAL = "message:send:total";
/*接收消息数*/
/* 接收消息数 */
String MESSAGE_RECEIVE_TOTAL = "message:receive:total";
/*连接次数*/
/* 连接次数 */
String MESSAGE_CONNECT_TOTAL = "message:connect:total";
/**
* 认证次数
@@ -316,7 +318,6 @@ public interface FastBeeConstant {
String CH = "CH";
String ModbusTcp = "MODBUS-TCP";
}
interface URL {

View File

@@ -7,7 +7,9 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.maibu.core.domain.OrgBaseDO;
import com.maibu.core.domain.map.RestPoint;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.enums.RouteType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -40,6 +42,11 @@ public class DevicePlanTask extends OrgBaseDO {
private LocalDateTime canExecuteTime; // 这个时间之前都不能执行
@TableField(exist = false)
private volatile boolean taskAccepted = false; //任务被上位机接收
private volatile boolean taskAccepted = false; // 任务被上位机接收
private RouteType routeType;
@TableField(exist = false)
private RestPoint backTaskPoint;
}

View File

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.maibu.core.domain.OrgBaseDO;
import com.maibu.core.enums.RouteType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -20,12 +21,14 @@ public class WorkRecord extends OrgBaseDO {
private String workName;
private Long userId;
private String mode;//导航任务模式 single_point|coverage
private String mode;// 导航任务模式 single_point|coverage
// private String jsonData;
// private String jsonData;
private RouteType routeType;
@TableField(typeHandler = JacksonTypeHandler.class)
private PlanPath jsonData; //计划
private PlanPath jsonData; // 计划
private String imgUrl;
}

View File

@@ -7,6 +7,7 @@ import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.business.path.RoutePlanSendEntity;
import com.maibu.core.enums.ConnectorType;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.enums.RouteType;
import com.maibu.core.host.HostWorkRecordCreateDTO;
import com.maibu.core.host.MutiPointEntity;
import com.maibu.core.host.PointEntity;
@@ -247,22 +248,22 @@ public class NettyDevice extends Connector {
}
// public void readConfigCommand() {
// byte[] bytes = DeviceRunParam.toReadBytes();
// log.debug("下发读取配置的报文:{}", toHexString(bytes));
// if (this.getChannel() != null && this.getChannel().isActive()) {
// this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
// }
// log.debug("下发读取配置的报文完成:{}", toHexString(bytes));
// byte[] bytes = DeviceRunParam.toReadBytes();
// log.debug("下发读取配置的报文:{}", toHexString(bytes));
// if (this.getChannel() != null && this.getChannel().isActive()) {
// this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
// }
// log.debug("下发读取配置的报文完成:{}", toHexString(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));
// }
// log.debug("下发修改配置的报文完成:{}", toHexString(bytes));
// 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));
// }
// log.debug("下发修改配置的报文完成:{}", toHexString(bytes));
// }
// todo 优化
@@ -365,32 +366,38 @@ public class NettyDevice extends Connector {
dto.setProtocol_version(Constant.protocol_version);
PointEntity point = new PointEntity();
if (!StringUtils.isEmpty(workRecord.getMode())) {
if (workRecord.getMode().equals("single_point")) {
point.setLongitude(workRecord.getJsonData().getPath().get(0).getLng());
point.setLatitude(workRecord.getJsonData().getPath().get(0).getLat());
}
if (workRecord.getMode().equals("coverage")) {
List<MutiPointEntity> boundary_points = new ArrayList<>();
// workRecord.getJsonData().getPath().forEach(x -> {
// MutiPointEntity mutiPoint = new MutiPointEntity();
// mutiPoint.setLongitude(x.getLng());
// mutiPoint.setLatitude(x.getLat());
// mutiPoint.setIndex();
// boundary_points.add(mutiPoint);
// });
List<LatAndLngEntity> path = workRecord.getJsonData().getPath();
for (int i = 0; i < path.size(); i++) {
LatAndLngEntity x = path.get(i);
MutiPointEntity mutiPoint = new MutiPointEntity();
mutiPoint.setLongitude(x.getLng());
mutiPoint.setLatitude(x.getLat());
mutiPoint.setIndex(i);
boundary_points.add(mutiPoint);
//TODO 增加其他系统任务类型 写死的code
if (RouteType.BACK_TO_REST_POINT.equals(task.getRouteType())) {
point.setLongitude(task.getBackTaskPoint().getPosition().getLng());
point.setLatitude(task.getBackTaskPoint().getPosition().getLat());
} else {
if (!StringUtils.isEmpty(workRecord.getMode())) {
if (workRecord.getMode().equals("single_point")) {
point.setLongitude(workRecord.getJsonData().getPath().get(0).getLng());
point.setLatitude(workRecord.getJsonData().getPath().get(0).getLat());
}
if (workRecord.getMode().equals("coverage")) {
List<MutiPointEntity> boundary_points = new ArrayList<>();
// workRecord.getJsonData().getPath().forEach(x -> {
// MutiPointEntity mutiPoint = new MutiPointEntity();
// mutiPoint.setLongitude(x.getLng());
// mutiPoint.setLatitude(x.getLat());
// mutiPoint.setIndex();
// boundary_points.add(mutiPoint);
// });
List<LatAndLngEntity> path = workRecord.getJsonData().getPath();
for (int i = 0; i < path.size(); i++) {
LatAndLngEntity x = path.get(i);
MutiPointEntity mutiPoint = new MutiPointEntity();
mutiPoint.setLongitude(x.getLng());
mutiPoint.setLatitude(x.getLat());
mutiPoint.setIndex(i);
boundary_points.add(mutiPoint);
}
point.setBoundary_points(boundary_points);
}
point.setBoundary_points(boundary_points);
}
}
dto.setData(point);

View File

@@ -17,4 +17,6 @@ public class DeviceMapPushDTO {
private String cm;// 控制模式 manual_remote|auto
private String ms; // 运动状态 moving|stopped|blocked
}

View File

@@ -1,5 +1,6 @@
package com.maibu.core.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -14,6 +15,7 @@ import java.util.Map;
/**
* 基类,时间类型改为LocalDateTime
*
* @author fastb
* @date 2023-08-22 9:11
*/
@@ -23,20 +25,24 @@ public class BaseDO implements Serializable {
/** 创建者 */
@ApiModelProperty("创建者")
@TableField(fill = FieldFill.INSERT)
private String createBy;
/** 创建时间 */
@ApiModelProperty("创建时间")
@TableField(fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/** 更新者 */
@ApiModelProperty("更新者")
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/** 更新时间 */
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/** 逻辑删除 */

View File

@@ -3,16 +3,20 @@ package com.maibu.core.domain.entity;
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.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.domain.BaseDO;
import com.maibu.utils.LongListTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "sys_region")
@TableName(value = "sys_region", autoResultMap = true)
public class SysRegion extends BaseDO {
@TableId(type = IdType.AUTO)
@@ -28,8 +32,14 @@ public class SysRegion extends BaseDO {
private String remark;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<LatAndLngEntity> scope; // 区域范围
private Integer status;
private Long bindRoute;// 绑定的线路id
private Long defaultRoute;// 绑定的线路id
@TableField(typeHandler = LongListTypeHandler.class)
private List<Long> bindRoutes;// 绑定的线路id
}

View File

@@ -1,17 +1,20 @@
package com.maibu.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.maibu.core.domain.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.maibu.core.domain.BaseDO;
import com.maibu.core.domain.map.SiteMapInfo;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "sys_site")
@TableName(value = "sys_site", autoResultMap = true)
public class SysSite extends BaseDO {
@TableId(type = IdType.AUTO)
@@ -45,4 +48,10 @@ public class SysSite extends BaseDO {
private String siteMapName; // geoserver 地图名称
/**
* 场站相关的地图信息 比如停车点,充电点,临时不可走点 等等 待拓展
*/
@TableField(exist = false)
private SiteMapInfo siteMapInfo;
}

View File

@@ -0,0 +1,16 @@
package com.maibu.core.domain.map;
import com.maibu.core.business.path.LatAndLngEntity;
import lombok.Data;
@Data
public class RestPoint {
private LatAndLngEntity position;
private String bindDeviceId;
private String alias;
}

View File

@@ -0,0 +1,31 @@
package com.maibu.core.domain.map;
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.maibu.core.domain.OrgNoUserDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "sys_site_map_info", autoResultMap = true)
public class SiteMapInfo extends OrgNoUserDO {
@TableId(type = IdType.AUTO)
private Long id;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<RestPoint> restPoints; // 休息点
@TableField(typeHandler = JacksonTypeHandler.class)
private List<TempObstaclePoint> tempObstaclePoints; // 临时不可走点
// todo 拓展 安全区 充电区?
}

View File

@@ -0,0 +1,16 @@
package com.maibu.core.domain.map;
import com.maibu.core.business.path.LatAndLngEntity;
import lombok.Data;
@Data
public class TempObstaclePoint {
private LatAndLngEntity position;
private Double radius;
private String alias;
}

View File

@@ -0,0 +1,25 @@
package com.maibu.core.domain.rule;
import java.util.Map;
import com.maibu.core.enums.ActionType;
import lombok.Data;
@Data
public class ActionConfig {
/**
* 触发任务类型
*/
private ActionType actionType;
/**
* 参数值
*/
private Map<String, Object> args;
private Long routeId;
}

View File

@@ -0,0 +1,64 @@
package com.maibu.core.domain.rule;
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.maibu.core.domain.OrgNoUserDO;
import com.maibu.core.enums.DeviceScope;
import com.maibu.core.enums.RuleType;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 自动化规则配置
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "iot_auto_rule", autoResultMap = true)
public class IotAutoRule extends OrgNoUserDO {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 规则名称
*/
private String ruleName;
/**
* 规则类型,如 LOW_BATTERY_RETURN
*/
private RuleType ruleType;
/**
* 适用设备、分组、全部
*/
private DeviceScope deviceScope;
/**
* 触发条件
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private TriggerConditions conditions;
/**
* 执行动作及参数
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private ActionConfig actionConfig;
/**
* 是否启用:0-禁用,1-启用
*/
private Boolean enabled = false;
// 是否强制执行 比如车子当前有任务
private Boolean ForceExecute = false;
}

View File

@@ -0,0 +1,63 @@
package com.maibu.core.domain.rule;
import java.time.LocalDateTime;
import java.util.Date;
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.maibu.core.domain.OrgNoUserDO;
import com.maibu.core.enums.RuleType;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 自动化规则触发记录
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "iot_auto_rule_record", autoResultMap = true)
public class IotAutoRuleRecord extends OrgNoUserDO {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 规则 ID
*/
private Long ruleId;
private RuleType ruleType;
/**
* 触发设备 ID
*/
private String deviceId;
/**
* 触发时的指标快照
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Object triggerValue;
/**
* 触发时间
*/
private LocalDateTime triggerTime;
/**
* 关联的返航任务 ID
*/
private String taskId;
/**
* 执行失败原因
*/
private String errorMessage;
}

View File

@@ -0,0 +1,28 @@
package com.maibu.core.domain.rule;
import java.math.BigDecimal;
import com.maibu.core.enums.CompareEnum;
import lombok.Data;
@Data
public class TriggerConditions {
/**
* 触发条件判断的字段key 电量 battery /temperature/offline_duration/voltage
*/
private String key;
/**
* 比较运算符:GT、GTE、LT、LTE、EQ、NE
*/
private CompareEnum operator;
/**
* 比较阈值
*/
private String value;
}

View File

@@ -0,0 +1,26 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ActionType {
AUTO_TASK("AUTO_TASK", "路径规划任务"),
BACK_TO_REST("BACK_TO_REST", "回休息区"),
SEND_COMMAND("SEND_COMMAND", "下发指令"),
ALARM("ALARM", "告警"),
WORK_ORDER("WORK_ORDER", "工单下发");
/** 订单类型值(存储在数据库中) */
private final String value;
/** 订单类型名称(用于前端显示) */
private final String name;
}

View File

@@ -0,0 +1,22 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum DeviceScope {
ALL("ALL", "所有设备"),
GROUP("GROUP", "设备组"),
SOME("SOME", "特定的");
/** 订单类型值(存储在数据库中) */
private final String value;
/** 订单类型名称(用于前端显示) */
private final String name;
}

View File

@@ -0,0 +1,24 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum RouteType {
MOWING_TASK("MOWING_TASK", "割草任务"),
INSPECTION_TASK("INSPECTION_TASK", "巡检任务"),
BACK_TO_REST_POINT("BACK_TO_REST_POINT", "返航任务"),
OTHER("OTHER", "其他类型");
/** 订单类型值(存储在数据库中) */
private final String value;
/** 订单类型名称(用于前端显示) */
private final String name;
}

View File

@@ -0,0 +1,18 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum RuleType {
LOW_BATTERY_RETURN("LOW_BATTERY_RETURN", "低电量返航");
/** 错误来源值(存储在数据库中) */
private final String value;
/** 错误来源名称(用于前端显示) */
private final String name;
}

View File

@@ -0,0 +1,10 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class DetectionStamp {
private Long sec;
private Long nanosec;
}

View File

@@ -0,0 +1,34 @@
package com.maibu.core.host;
import java.util.List;
import com.maibu.core.enums.MesType;
import lombok.Data;
@Data
public class ObstacleDetectionData {
private MesType mesType;
/**
* 融合状态
*/
private String fusion_status;
/**
* 障碍物检测状态
*/
private String obstacle_status;
/**
* 检测目标数量
*/
private Integer object_count;
/**
* 检测目标列表
*/
private List<ObstacleObject> objects;
}

View File

@@ -0,0 +1,34 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class ObstacleObject {
private Integer class_id;
private String class_name;
private Double confidence;
private Integer x1;
private Integer y1;
private Integer x2;
private Integer y2;
private Double x;
private Double y;
private Double z;
private Double distance;
private Double angle;
private Double latitude;
private Double longitude;
private Integer track_id;
private Double size_x;
private Double size_y;
private Double size_z;
private DetectionStamp det_stamp;
}

View File

@@ -0,0 +1,13 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class ObstaclePostDTO extends HostBase {
private ObstacleDetectionData fusion_obstacle;
}

View File

@@ -5,6 +5,8 @@ import lombok.Data;
@Data
public class VehicleMessage {
private String deviceId;
private double battery_percentage;// 实时电量百分比
private double battery_voltage;// 实时电压

View File

@@ -6,16 +6,27 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import com.maibu.core.business.*;
import com.maibu.core.business.dto.DeviceMapPushDTO;
import com.maibu.mqtt.CustomMqttDeviceMonitor;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.core.business.AlarmOrderConfig;
import com.maibu.core.business.Device;
import com.maibu.core.business.DeviceModel;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DevicePlanTask;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.DeviceRunStatistics;
import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.core.business.IoTCommonDevice;
import com.maibu.core.business.OrderModel;
import com.maibu.core.business.Product;
import com.maibu.core.business.dto.DeviceMapPushDTO;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.rule.IotAutoRule;
import com.maibu.core.enums.ErrorSource;
import com.maibu.core.enums.RuleType;
import com.maibu.core.host.VehicleMessage;
import lombok.Data;
@@ -62,11 +73,34 @@ public class SiteMemory {
public static ConcurrentHashMap<String, VehicleMessage> vehicleMessageMap = new ConcurrentHashMap<>();
public static ConcurrentHashMap<RuleType, IotAutoRule> iotAutoRuleMap = new ConcurrentHashMap<>();
public List<IotAutoRule> getAllIotAutoRule() {
return new ArrayList<>(iotAutoRuleMap.values());
}
public IotAutoRule getIotAutoRule(RuleType ruleType) {
return iotAutoRuleMap.get(ruleType);
}
public void saveIotAutoRule(RuleType ruleType, IotAutoRule iotAutoRule) {
iotAutoRuleMap.put(ruleType, iotAutoRule);
}
public void removeIotAutoRule(RuleType ruleType) {
iotAutoRuleMap.remove(ruleType);
}
public List<VehicleMessage> getAllVehicleMessage() {
return new ArrayList<>(vehicleMessageMap.values());
}
public VehicleMessage getVehicleMessage(String deviceId) {
return vehicleMessageMap.get(deviceId);
}
public void saveVehicleMessage(String deviceId, VehicleMessage vehicleMessage) {
vehicleMessage.setDeviceId(deviceId);
vehicleMessageMap.put(deviceId, vehicleMessage);
}

View File

@@ -8,6 +8,7 @@ import com.maibu.core.business.device.DeviceStatusDetail;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.dto.DeviceMapPushDTO;
import com.maibu.core.business.dto.WebDeviceTaskStatusMessageDTO;
import com.maibu.core.business.dto.WebMapMessageDTO;
import com.maibu.core.business.dto.WebStatusMessageDTO;
import com.maibu.core.business.inter.WebsocketMesDispather;
import com.maibu.core.enums.DeviceTaskStaus;
@@ -107,6 +108,10 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
case "upgrade_reply":
handleUpgradeReply(deviceId, topic, payload);
break;
case "obstacle_post":
handleObstaclePost(deviceId, topic, payload);
break;
default:
log.debug("割草机消息: deviceId={}, topic={}, action={}", deviceId, topic, action);
break;
@@ -247,6 +252,7 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
VehicleMessage vehicleMessage = siteMemory.getVehicleMessage(deviceId);
if (vehicleMessage != null) {
dto.setCm(vehicleMessage.getControl_mode());
dto.setMs(vehicleMessage.getMotion());
dto.setB(vehicleMessage.getBattery_percentage());
}
siteMemory.saveMapPushDTO(deviceId, dto);
@@ -634,6 +640,49 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
// }
}
/**
* 处理控障碍物提示
*/
private void handleObstaclePost(String deviceId, String topic, String payload) {
log.debug("【障碍物提示】deviceId={}, payload={}", deviceId, payload);
ObstacleDetectionData data = JsonUtils.parseObject(payload, ObstacleDetectionData.class);
List<NettyDevice> controlMasters = deviceSessionManager
.getAllSlaveControl(deviceId);
data.setMesType(MesType.detectionReport);
if (!CollectionUtils.isEmpty(controlMasters)) {
for (NettyDevice x : controlMasters) {
try {
websocketMesDispather.dispather(x.getConnectorId(), JsonUtils.toJsonString(data));
} catch (Exception e) {
log.error("实时数据websocket推送失败: connectorId={}, error={}", x.getConnectorId(),
e.getMessage(), e);
}
}
}
try {
NettyDevice device = deviceSessionManager.getDevice(deviceId);
if (device != null && device.getDevice() != null) {
Long siteId = device.getDevice().getSiteId();
websocketMesDispather.mapMessageDispather(siteId,
JsonUtils.toJsonString(data));
}
} catch (Exception e) {
log.error("实时地图数据websocket推送失败: siteId={}, error={}", e);
}
try {
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.DEVICE_OBSTACLE_PUSH_TOPIC, deviceId),
JsonUtils.toJsonString(data));
} catch (MqttException e) {
log.error("实时数据websocket推送失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
}
}
/**
* 从 Topic 中解析 deviceId
* Topic 格式:mower/{deviceId}/...
@@ -686,6 +735,8 @@ public class HostMessageHandler implements CustomMqttMessageHandler {
return "route_reply";
if (remaining.equals("/ota/result/post"))
return "upgrade_reply";
if (remaining.equals("/perception/obstacle/post"))
return "obstacle_post";
return null;
}

View File

@@ -17,6 +17,8 @@ public class MqttTopic {
public static final String DEVICE_ROUTE_PUSH_TOPIC = "device/%s/route/post";
public static final String DEVICE_STATUS_PUSH_TOPIC = "device/%s/status/change";
// 障碍物信息
public static final String DEVICE_OBSTACLE_PUSH_TOPIC = "device/%s/obstacle/post";
/** 产品标识:割草机 */
public static final String MOWER_PRODUCT = "mower";

View File

@@ -0,0 +1,40 @@
package com.maibu.utils;
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
public class LongListTypeHandler extends AbstractJsonTypeHandler<List<Long>> {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final JavaType LIST_TYPE =
OBJECT_MAPPER.getTypeFactory()
.constructCollectionType(List.class, Long.class);
public LongListTypeHandler(Class<?> type) {
// 兼容 MyBatis-Plus 通过反射传入字段类型的方式
}
@Override
protected List<Long> parse(String json) {
try {
return OBJECT_MAPPER.readValue(json, LIST_TYPE);
} catch (IOException e) {
throw new RuntimeException("bindRoutes JSON 解析失败", e);
}
}
@Override
protected String toJson(List<Long> obj) {
try {
return OBJECT_MAPPER.writeValueAsString(obj);
} catch (IOException e) {
throw new RuntimeException("bindRoutes JSON 序列化失败", e);
}
}
}

View File

@@ -1,14 +1,14 @@
package com.maibu.own.entity;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor

View File

@@ -124,7 +124,7 @@ public class DeviceTaskController extends BaseController {
return AjaxResult.success(deviceTaskService.createDeviceTask(dto, getLoginUser().getUsername()));
}
@PostMapping("/createRegionDeviceTask")
@PostMapping("/createRegionDefaultTask")
public AjaxResult createRegionDeviceTask(@RequestBody DeviceTaskCommandDTO dto) {
String deviceId = dto.getDeviceId();
Long siteId = dto.getSiteId();
@@ -176,4 +176,25 @@ public class DeviceTaskController extends BaseController {
return AjaxResult.success(deviceTaskService.recoveryTask(dto, getUsername()));
}
@PostMapping("/backToRestPoint")
public AjaxResult backToRestPoint(@RequestBody DeviceTaskCommandDTO dto) {
String deviceId = dto.getDeviceId();
Long siteId = dto.getSiteId();
Long orgId = dto.getOrgId();
if (StringUtils.isEmpty(deviceId)) {
return AjaxResult.error("deviceId为空!");
}
if (siteId == null) {
return AjaxResult.error("siteId为空!");
}
if (orgId == null) {
return AjaxResult.error("orgId为空!");
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory.hasTask(deviceId)) {
return AjaxResult.error("当前设备存在任务!");
}
return AjaxResult.success(deviceTaskService.backToRestPoint(dto, getLoginUser().getUsername()));
}
}

View File

@@ -5,14 +5,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.checkerframework.checker.units.qual.s;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
@@ -26,7 +24,6 @@ import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.constant.FastBeeConstant;
import com.maibu.core.business.AlarmOrderConfig;
import com.maibu.core.business.Device;
import com.maibu.core.business.DeviceModel;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DevicePlanTask;
@@ -35,9 +32,12 @@ import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.core.business.IoTCommonDevice;
import com.maibu.core.business.OrderModel;
import com.maibu.core.business.Product;
import com.maibu.core.business.WorkRecord;
import com.maibu.core.domain.entity.SysParam;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.map.SiteMapInfo;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.enums.RouteType;
import com.maibu.influxdb.util.InfluxDBUtil;
import com.maibu.mapper.AlarmOrderConfigMapper;
import com.maibu.mapper.DevicePlanMapper;
@@ -47,9 +47,11 @@ import com.maibu.mapper.DeviceRunParamMapper;
import com.maibu.mapper.ErrorIdentificationStandardMapper;
import com.maibu.mapper.IotDeviceCommonMapper;
import com.maibu.mapper.OrderModelMapper;
import com.maibu.mapper.SiteMapInfoMapper;
import com.maibu.mapper.SysDeviceModelMapper;
import com.maibu.mapper.SysParamMapper;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.mapper.WorkRecordMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import com.maibu.mybatis.LambdaQueryWrapperX;
@@ -57,7 +59,6 @@ import com.maibu.service.DevicePlanTaskMonitorService;
import com.maibu.service.DeviceThreadService;
import com.maibu.service.impl.IotDeviceCommonService;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import lombok.extern.slf4j.Slf4j;
@@ -75,6 +76,9 @@ public class InitThread implements ApplicationRunner {
@Resource(name = FastBeeConstant.TASK.MAP_MESSAGE_PUSH)
private Executor mapMessagePushExecutor;
@Resource(name = FastBeeConstant.TASK.AUTO_RULE)
private Executor autoRuleExecutor;
@Resource(name = FastBeeConstant.TASK.COMMON_DEVICE_MONITOR)
private Executor commonDeviceMonitorExecutor;
@@ -96,6 +100,9 @@ public class InitThread implements ApplicationRunner {
@Autowired
private SysSiteMapper sysSiteMapper;
@Autowired
private SiteMapInfoMapper siteMapInfoMapper;
@Autowired
private DeviceRunParamMapper deviceRunParamMapper;
@@ -111,7 +118,7 @@ public class InitThread implements ApplicationRunner {
@Autowired
private ErrorIdentificationStandardMapper errorIdentificationStandardMapper;
@Autowired
private OrderModelMapper orderModelMapper;
@Autowired
private AlarmOrderConfigMapper alarmOrderConfigMapper;
@@ -125,6 +132,9 @@ public class InitThread implements ApplicationRunner {
@Autowired
private SysParamMapper sysParamMapper;
@Autowired
private WorkRecordMapper workRecordMapper;
@Value("${influxdb.url}")
private String influxDBUrl;
@@ -162,14 +172,21 @@ public class InitThread implements ApplicationRunner {
}
private void init() throws Exception {
//初始化系统参数
// 初始化系统参数
initSystemParam();
initDefaultWorkRecord();
// 初始化InfluxDBUtil
GlobalMemory.influxDBUtil = new InfluxDBUtil(influxDBUrl, influxDBToken, influxDBOrg, influxDBBucket);
GlobalMemory.initMqttDeviceMonitor(mqttHostUrl, mqttClientId, mqttUsername, mqttPassword);
// 规则触发线程
autoRuleExecutor.execute(() -> {
deviceThreadService.autoRule();
});
// 地图监控推送
mapMessagePushExecutor.execute(() -> {
deviceThreadService.mapMessagePush();
@@ -225,6 +242,19 @@ public class InitThread implements ApplicationRunner {
});
}
// 场站的 地图配置信息
List<SiteMapInfo> siteMapInfoList = siteMapInfoMapper.selectList();
if (!CollectionUtils.isEmpty(siteMapInfoList)) {
siteMapInfoList.forEach(x -> {
Long orgId = x.getOrgId();
Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if (siteMemory != null) {
siteMemory.getSysSite().setSiteMapInfo(x);
}
});
}
// 外部设备
List<IoTCommonDevice> ioTCommonDeviceList = iotDeviceCommonMapper.selectList();
if (!CollectionUtils.isEmpty(ioTCommonDeviceList)) {
@@ -391,4 +421,40 @@ public class InitThread implements ApplicationRunner {
}
}
public void initDefaultWorkRecord() throws IOException {
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
List<WorkRecord> list = workRecordMapper.selectList(queryWrapper);
try {
// 读取resource目录下的dsystemParam.json文件
org.springframework.core.io.Resource resource = resourceLoader
.getResource("classpath:workRecordTemplete.json");
// 使用fastjson2转换为DeviceConfig对象
String jsonContent;
jsonContent = IoUtil.readUtf8(resource.getInputStream());
List<WorkRecord> records = JSON.parseArray(jsonContent, WorkRecord.class);
List<WorkRecord> saveList = new ArrayList<>();
if (CollectionUtils.isEmpty(list)) {
saveList.addAll(records);
} else {
Map<String, List<WorkRecord>> map = list.stream()
.filter(Objects::nonNull)
.filter(workRecord -> workRecord.getRouteType() != null)
.collect(Collectors.groupingBy(
workRecord -> workRecord.getRouteType().toString()));
if (!CollectionUtils.isEmpty(records)) {
records.forEach(x -> {
if (!map.containsKey(x.getRouteType())) {
x.setUserId(1L);
saveList.add(x);
}
});
}
}
workRecordMapper.saveOrUpdateBatch(saveList);
} catch (Exception e) {
log.error("初始化系统参数失败", e);
}
}
}

View File

@@ -17,6 +17,8 @@ import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.maibu.core.business.Device;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DevicePlanTask;
@@ -26,20 +28,26 @@ import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.dto.DeviceTaskCommandDTO;
import com.maibu.core.domain.entity.SysRegion;
import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.map.RestPoint;
import com.maibu.core.domain.map.SiteMapInfo;
import com.maibu.core.domain.model.LoginUser;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.enums.RouteType;
import com.maibu.dto.DevicePlanStatisticsDTO;
import com.maibu.dto.DevicePlanTaskStatisticsDTO;
import com.maibu.dto.DeviceTaskQueryDTO;
import com.maibu.dto.DeviceWorkStatisticsDTO;
import com.maibu.exception.ServiceException;
import com.maibu.mapper.DeviceMapper;
import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.SiteMapInfoMapper;
import com.maibu.mapper.SysRegionMapper;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.mapper.WorkRecordMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import com.maibu.utils.MessageUtils;
import lombok.extern.slf4j.Slf4j;
@@ -68,6 +76,8 @@ public class DeviceTaskService {
@Autowired
private SysRegionMapper sysRegionMapper;
private static final ObjectMapper objectMapper = new ObjectMapper();
public int insertOrUpdate(DevicePlan devicePlan, LoginUser loginUser) {
Long id = devicePlan.getId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(devicePlan.getOrgId(), devicePlan.getSiteId());
@@ -470,6 +480,12 @@ public class DeviceTaskService {
task.setCreateTime(LocalDateTime.now());
task.setRouteId(dto.getRouteId());
task.setStartTime(dto.getStartTime());
WorkRecord workRecord = workRecordMapper.selectById(dto.getRouteId());
if (workRecord != null) {
task.setRouteType(workRecord.getRouteType());
}
devicePlanTaskMapper.saveOrUpdate(task);
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
@@ -487,11 +503,22 @@ public class DeviceTaskService {
queryWrapper.eq(SysRegion::getId, dto.getRegionId());
SysRegion region = sysRegionMapper.selectOne(queryWrapper);
if (region == null || region.getBindRoute() == null) {
throw new RuntimeException("区域未绑定线路!");
if (region == null) {
throw new RuntimeException("区域未找到!");
}
Long routeId = dto.getRouteId();
if (routeId == null) {
routeId = region.getDefaultRoute();
}
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
dto.setOrgId(site.getOrgId());
}
}
DevicePlanTask task = new DevicePlanTask();
task.setRouteId(region.getBindRoute());
task.setRouteId(routeId);
task.setOrgId(dto.getOrgId());
task.setSiteId(dto.getSiteId());
task.setTaskStaus(DeviceTaskStaus.NEW);
@@ -499,13 +526,14 @@ public class DeviceTaskService {
task.setCreateBy(username);
task.setCreateTime(LocalDateTime.now());
task.setStartTime(dto.getStartTime());
devicePlanTaskMapper.saveOrUpdate(task);
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
dto.setOrgId(site.getOrgId());
}
WorkRecord workRecord = workRecordMapper.selectById(region.getDefaultRoute());
if (workRecord != null) {
task.setRouteType(workRecord.getRouteType());
}
devicePlanTaskMapper.saveOrUpdate(task);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
siteMemory.addDevicePlanPrepare(task);
return task.getId();
@@ -584,4 +612,60 @@ public class DeviceTaskService {
return false;
}
public Long backToRestPoint(DeviceTaskCommandDTO dto, String username) {
if (dto.getOrgId() == null) {
SysSite site = sysSiteMapper.selectById(dto.getSiteId());
if (site != null) {
dto.setOrgId(site.getOrgId());
}
}
SiteMemory siteMemory = GlobalMemory.getSiteMemory(dto.getOrgId(), dto.getSiteId());
SiteMapInfo siteMapInfo;
if (siteMemory == null) {
throw new ServiceException(MessageUtils.message("任务下发出错!"));
}
siteMapInfo = siteMemory.getSysSite().getSiteMapInfo();
if (siteMapInfo == null || CollectionUtils.isEmpty(siteMapInfo.getRestPoints())) {
throw new ServiceException(MessageUtils.message("当前机器未配置返回点!"));
}
List<RestPoint> restPoints = objectMapper.convertValue(
siteMapInfo.getRestPoints(),
new TypeReference<List<RestPoint>>() {
});
RestPoint switchRestPoint = restPoints.stream()
.filter(x -> dto.getDeviceId().equals(x.getBindDeviceId())).findFirst().orElse(null);
if (switchRestPoint == null) {
throw new ServiceException(MessageUtils.message("当前机器未配置返回点!"));
}
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(WorkRecord::getRouteType, RouteType.BACK_TO_REST_POINT);
WorkRecord workRecord = workRecordMapper.selectOne(queryWrapper);
DevicePlanTask task = new DevicePlanTask();
task.setRouteId(workRecord.getId());
task.setRouteType(workRecord.getRouteType());
task.setBackTaskPoint(switchRestPoint);
task.setOrgId(dto.getOrgId());
task.setSiteId(dto.getSiteId());
task.setTaskStaus(DeviceTaskStaus.NEW);
task.setDeviceId(dto.getDeviceId());
task.setCreateBy(username);
task.setCreateTime(LocalDateTime.now());
task.setStartTime(dto.getStartTime());
devicePlanTaskMapper.saveOrUpdate(task);
siteMemory.addDevicePlanPrepare(task);
return task.getId();
}
}

View File

@@ -15,6 +15,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.maibu.core.business.dto.DeviceMapPushDTO;
import com.maibu.core.business.dto.DeviceTaskCommandDTO;
import com.maibu.core.business.dto.WebMapMessageDTO;
import com.maibu.core.business.dto.WebOlineStatusMessageDTO;
import com.maibu.core.enums.*;
@@ -40,8 +41,13 @@ import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.core.business.alarm_center.AlarmMessage;
import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.inter.WebsocketMesDispather;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.rule.ActionConfig;
import com.maibu.core.domain.rule.IotAutoRule;
import com.maibu.core.domain.rule.TriggerConditions;
import com.maibu.core.host.HeartBeatDTO;
import com.maibu.core.host.LocationMessage;
import com.maibu.core.host.VehicleMessage;
import com.maibu.core.redis.RedisCache;
import com.maibu.dto.DeviceErrorPushDTO;
import com.maibu.dto.DeviceTaskStatusMessageDTO;
@@ -95,6 +101,9 @@ public class DeviceThreadService {
@Autowired
private DeviceRunStatisticsMapper deviceRunStatisticsMapper;
@Autowired
private DeviceTaskService deviceTaskService;
public void deviceErrorMonitor() throws InterruptedException, IOException {
initStandard();
@@ -456,4 +465,101 @@ public class DeviceThreadService {
}, 0, 100, TimeUnit.MILLISECONDS);
}
/**
* 规则触发自动判断
*/
public void autoRule() {
executor.scheduleWithFixedDelay(() -> {
try {
List<SiteMemory> list = GlobalMemory.getAllSiteMemory();
if (!CollectionUtils.isEmpty(list)) {
list.forEach(x -> {
List<IotAutoRule> rules = x.getAllIotAutoRule();
if (!CollectionUtils.isEmpty(rules)) {
rules.forEach(rule -> {
// 根据不同的 类型区分处理方式
handleAutoRule(rule, x);
});
}
});
}
} catch (Exception e) {
log.error("执行规则出发线程错误:{}", e.getMessage());
}
}, 0, 500, TimeUnit.MILLISECONDS);
}
public void handleAutoRule(IotAutoRule rule, SiteMemory siteMemory) {
if (RuleType.LOW_BATTERY_RETURN.equals(rule.getRuleType())) {
TriggerConditions conditions = rule.getConditions();
String key = conditions.getKey();
CompareEnum compareType = conditions.getOperator();
String compareValue = conditions.getValue();
List<VehicleMessage> vList = siteMemory.getAllVehicleMessage();
if (!CollectionUtils.isEmpty(vList)) {
vList.forEach(x -> {
String deviceId = x.getDeviceId();
String value = classFieldFinding(key, x);
boolean result = CompareUtils.compare(compareType, value, compareValue);
if (result) {
ActionConfig aConfig = rule.getActionConfig();
if (aConfig != null && aConfig.getActionType() != null) {
ActionType actionType = aConfig.getActionType();
if (ActionType.BACK_TO_REST.equals(actionType)) {
if (siteMemory.hasTask(deviceId)) {
return;
}
DeviceTaskCommandDTO dto = new DeviceTaskCommandDTO();
dto.setDeviceId(deviceId);
dto.setOrgId(siteMemory.getSysSite().getOrgId());
dto.setSiteId(siteMemory.getSysSite().getId());
deviceTaskService.backToRestPoint(dto, "system");
}
if (ActionType.AUTO_TASK.equals(actionType)) {
if (siteMemory.hasTask(deviceId)) {
return;
}
Long routeId = aConfig.getRouteId();
DeviceTaskCommandDTO dto = new DeviceTaskCommandDTO();
dto.setDeviceId(deviceId);
dto.setOrgId(siteMemory.getSysSite().getOrgId());
dto.setSiteId(siteMemory.getSysSite().getId());
dto.setRouteId(routeId);
deviceTaskService.createDeviceTask(dto, "system");
}
if (ActionType.ALARM.equals(actionType)) {
}
if (ActionType.SEND_COMMAND.equals(actionType)) {
}
if (ActionType.WORK_ORDER.equals(actionType)) {
}
}
}
});
}
}
}
private static String classFieldFinding(String fieldName, VehicleMessage history) {
try {
// 1. 获取类的Class对象
Class<?> vehicleClass = VehicleMessage.class;
Field field = vehicleClass.getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(history);
return (String) value;
} catch (NoSuchFieldException | IllegalAccessException e) {
System.out.println("获取字段失败: " + e.getMessage());
log.error("获取属性值失败:{}", e.getMessage());
}
return null;
}
}

View File

@@ -0,0 +1,8 @@
[
{
"workName": "返航任务",
"jsonData": {},
"mode": "single_point",
"routeType": "BACK_TO_REST_POINT"
}
]

View File

@@ -0,0 +1,98 @@
package com.maibu.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.entity.SysMenu;
import com.maibu.core.domain.rule.IotAutoRule;
import com.maibu.core.domain.rule.IotAutoRuleRecord;
import com.maibu.core.page.TableDataInfo;
import com.maibu.dto.IotAutoRuleRecordQueryDTO;
import com.maibu.service.IotAutoRuleService;
/**
* 区域/场站
*
* @author ruoyi
*/
@RestController
@RequestMapping("/system/autoRule")
public class IotAutoRuleController extends BaseController {
@Autowired
private IotAutoRuleService iotAutoRuleService;
/**
* 新增或者修改组织
*/
@PostMapping("/save")
public AjaxResult save(@RequestBody IotAutoRule iotAutoRule) {
try {
return AjaxResult.success(iotAutoRuleService.save(iotAutoRule));
} catch (Exception e) {
return AjaxResult.error("新增修改场站出错", e.getMessage());
}
}
/**
* 查询场站详情
*/
@GetMapping("/selectById")
public AjaxResult selectById(@RequestParam Long id) {
try {
return AjaxResult.success(iotAutoRuleService.selectById(id));
} catch (Exception e) {
return AjaxResult.error("查询场站详情出错", e.getMessage());
}
}
/**
* 查询组织下所有的规则
*/
@GetMapping("/selectBySiteId")
public AjaxResult selectBySiteId(@RequestParam Long siteId) {
try {
return AjaxResult.success(iotAutoRuleService.selectBySiteId(siteId));
} catch (Exception e) {
return AjaxResult.error("查询组织下所有场站出错", e.getMessage());
}
}
/**
* 查询组织下所有的规则
*/
@PostMapping("/selectAllRecord")
public TableDataInfo selectAllRecord(@RequestBody IotAutoRuleRecordQueryDTO QueryDto) {
try {
startPage();
List<IotAutoRuleRecord> menus = iotAutoRuleService.selectAllRecord(QueryDto);
return getDataTable(menus);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 删除组织
*/
@PostMapping("/delete")
public AjaxResult delete(@RequestBody List<Long> ids) {
try {
return AjaxResult.success(iotAutoRuleService.delete(ids));
} catch (Exception e) {
return AjaxResult.error("保存组织出错", e.getMessage());
}
}
}

View File

@@ -4,6 +4,7 @@ import com.maibu.core.business.WorkRecord;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.R;
import com.maibu.core.enums.RouteType;
import com.maibu.memory.GlobalMemory;
import com.maibu.service.impl.WorkRecordService;
import com.maibu.utils.MinioUtil;
@@ -35,6 +36,14 @@ public class WorkRecordController extends BaseController {
// WorkRecord workRecordObj = JsonUtils.parseObject(workRecord,
// WorkRecord.class);
if (workRecord == null || workRecord.getRouteType() == null) {
return R.fail("未选择规划类型");
}
if (RouteType.BACK_TO_REST_POINT.equals(workRecord.getRouteType())) {
return R.fail("无法添加返航任务类型的路径规划");
}
WorkRecord workRecord1 = workRecordService.selectWorkRecordByWorkNameAndSiteId(workRecord.getWorkName(),
workRecord.getSiteId());
if (workRecord1 != null) {
@@ -100,6 +109,12 @@ public class WorkRecordController extends BaseController {
return R.ok(workRecord);
}
@PostMapping("/selectByIds")
public R selectByIds(@RequestBody List<Long> ids) {
List<WorkRecord> workRecords = workRecordService.selectByIds(ids);
return R.ok(workRecords);
}
@GetMapping("/selectByTaskId")
public R selectByTaskId(@RequestParam Long taskId) {
WorkRecord workRecord = workRecordService.selectByTaskId(taskId);

View File

@@ -0,0 +1,17 @@
package com.maibu.dto;
import com.maibu.core.domain.BaseEntity;
import com.maibu.core.enums.RuleType;
import lombok.Data;
@Data
public class IotAutoRuleRecordQueryDTO extends BaseEntity {
private RuleType ruleType;
private Long ruleId;
private String deviceId;
private Long siteId;
}

View File

@@ -0,0 +1,82 @@
package com.maibu.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.core.domain.map.SiteMapInfo;
import com.maibu.core.domain.rule.IotAutoRule;
import com.maibu.core.domain.rule.IotAutoRuleRecord;
import com.maibu.dto.IotAutoRuleRecordQueryDTO;
import com.maibu.exception.ServiceException;
import com.maibu.mapper.IotAutoRuleMapper;
import com.maibu.mapper.IotAutoRuleRecordMapper;
import com.maibu.mapper.SiteMapInfoMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import io.micrometer.core.instrument.util.StringUtils;
@Service
public class IotAutoRuleService {
@Autowired
private IotAutoRuleMapper iotAutoRuleMapper;
@Autowired
private IotAutoRuleRecordMapper iotAutoRuleRecordMapper;
public boolean save(IotAutoRule iotAutoRule) {
try {
boolean b = iotAutoRuleMapper.saveOrUpdate(iotAutoRule);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(iotAutoRule.getOrgId(), iotAutoRule.getId());
if (siteMemory != null && siteMemory.sysSite != null) {
siteMemory.saveIotAutoRule(iotAutoRule.getRuleType(), iotAutoRule);
return b;
}
} catch (Exception e) {
// TODO: handle exception
throw new ServiceException("地图信息保存失败");
}
return false;
}
public IotAutoRule selectById(Long id) {
return iotAutoRuleMapper.selectById(id);
}
public IotAutoRule selectBySiteId(Long siteId) {
LambdaQueryWrapper<IotAutoRule> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(IotAutoRule::getSiteId, siteId);
return iotAutoRuleMapper.selectOne(queryWrapper);
}
public List<IotAutoRuleRecord> selectAllRecord(IotAutoRuleRecordQueryDTO queryDto) {
LambdaQueryWrapper<IotAutoRuleRecord> queryWrapper = new LambdaQueryWrapper<>();
if (queryDto != null && queryDto.getRuleType() != null) {
queryWrapper.eq(IotAutoRuleRecord::getRuleType, queryDto.getRuleType());
}
if (queryDto != null && queryDto.getRuleId() != null) {
queryWrapper.eq(IotAutoRuleRecord::getRuleId, queryDto.getRuleId());
}
if (queryDto != null && !StringUtils.isEmpty(queryDto.getDeviceId())) {
queryWrapper.eq(IotAutoRuleRecord::getDeviceId, queryDto.getDeviceId());
}
if (queryDto != null && queryDto.getSiteId() != null) {
queryWrapper.eq(IotAutoRuleRecord::getSiteId, queryDto.getSiteId());
}
return iotAutoRuleRecordMapper.selectList(queryWrapper);
}
public int delete(List<Long> ids) {
return iotAutoRuleRecordMapper.deleteBatchIds(ids);
}
}

View File

@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -73,6 +74,15 @@ public class WorkRecordService {
return workRecordMapper.selectById(id);
}
public List<WorkRecord> selectByIds(List<Long> ids) {
if (!CollectionUtils.isEmpty(ids)) {
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(WorkRecord::getId, ids);
return workRecordMapper.selectList(queryWrapper);
}
return new ArrayList<>();
}
public WorkRecord selectByTaskId(Long taskId) {
DevicePlanTask devicePlanTask = devicePlanTaskMapper.selectById(taskId); // 先查询设备任务,确认任务存在
if (devicePlanTask == null) {

View File

@@ -0,0 +1,11 @@
package com.maibu.mapper;
import org.springframework.stereotype.Repository;
import com.maibu.core.domain.rule.IotAutoRule;
import com.maibu.mybatis.mapper.BaseMapperX;
@Repository
public interface IotAutoRuleMapper extends BaseMapperX<IotAutoRule> {
}

View File

@@ -0,0 +1,12 @@
package com.maibu.mapper;
import org.springframework.stereotype.Repository;
import com.maibu.core.domain.rule.IotAutoRuleRecord;
import com.maibu.mybatis.mapper.BaseMapperX;
@Repository
public interface IotAutoRuleRecordMapper extends BaseMapperX<IotAutoRuleRecord> {
}

View File

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

View File

@@ -0,0 +1,44 @@
package com.maibu.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.core.domain.map.SiteMapInfo;
import com.maibu.exception.ServiceException;
import com.maibu.mapper.SiteMapInfoMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
@Service
public class SiteMapInfoService {
@Autowired
private SiteMapInfoMapper siteMapInfoMapper;
public boolean save(SiteMapInfo siteMapInfo) {
try {
boolean b = siteMapInfoMapper.saveOrUpdate(siteMapInfo);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(siteMapInfo.getOrgId(), siteMapInfo.getId());
if (siteMemory != null && siteMemory.sysSite != null) {
siteMemory.sysSite.setSiteMapInfo(siteMapInfo);
}
return b;
} catch (Exception e) {
// TODO: handle exception
throw new ServiceException("地图信息保存失败");
}
}
public SiteMapInfo selectById(Long id) {
return siteMapInfoMapper.selectById(id);
}
public SiteMapInfo selectBySiteId(Long siteId) {
LambdaQueryWrapper<SiteMapInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SiteMapInfo::getSiteId, siteId);
return siteMapInfoMapper.selectOne(queryWrapper);
}
}

View File

@@ -12,7 +12,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class SysRegionService {
@@ -20,14 +19,6 @@ public class SysRegionService {
private SysRegionMapper sysRegionMapper;
public List<SysRegion> list(SysRegion region) {
LambdaQueryWrapper<SysRegion> queryWrapper = new LambdaQueryWrapper<>();
if (region != null && !StringUtils.isEmpty(region.getRegionName())) {
queryWrapper.like(SysRegion::getRegionName, region.getRegionName());
}
return sysRegionMapper.selectList(queryWrapper);
}
public boolean save(SysRegion org) {
return sysRegionMapper.saveOrUpdate(org);
}
@@ -37,8 +28,8 @@ public class SysRegionService {
}
public void deleteAll(List<Long> ids) {
List<Long> regionIds = getIdsBySiteIds(ids);
if(!CollectionUtils.isEmpty(regionIds)){
List<Long> regionIds = getIdsBySiteIds(ids);
if (!CollectionUtils.isEmpty(regionIds)) {
delete(regionIds);
}
}
@@ -47,9 +38,9 @@ public class SysRegionService {
LambdaQueryWrapper<SysRegion> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(SysRegion::getSiteId, ids);
List<SysRegion> list = sysRegionMapper.selectList(queryWrapper);
if(!CollectionUtils.isEmpty(list)){
if (!CollectionUtils.isEmpty(list)) {
return list.stream().map(SysRegion::getId).collect(Collectors.toList());
}else{
} else {
return new ArrayList<>();
}
}

View File

@@ -2,7 +2,7 @@ package com.maibu.control;
import lombok.Data;
@Data
@Data
public class DiffSteer {
public static final int Polarity_High = 0; // 0

View File

@@ -75,8 +75,8 @@ public class ControlUtils {
// buffer.putShort(entity.getLeftWheelSpeed());//左轮速度
// buffer.putShort(entity.getRightWheelSpeed());//右轮速度
buffer.putDouble(entity.getAngularSpeed());// 左轮速度
buffer.putDouble(entity.getLinearSpeed());// 右轮速度
buffer.putDouble(entity.getLinearSpeed());//
buffer.putDouble(entity.getAngularSpeed());// 右轮速度
buffer.put(entity.getChassisLiftFlag());// 底盘升降
buffer.put(entity.getMowerSpeedFlag());// 割刀加减速

View File

@@ -1,19 +1,13 @@
package com.maibu.websocket;
import com.maibu.constant.CommandConstant;
import com.maibu.common.MiddleConstant;
import com.maibu.core.business.LawnMoverProtocolEntity;
import com.maibu.core.enums.CommandRequestType;
import com.maibu.core.enums.MesType;
import com.maibu.dto.*;
import com.maibu.memory.MiddleGlobalMemory;
import com.maibu.netty.NettyClient;
import com.maibu.utils.CommandUtils;
import com.maibu.utils.ControlUtils;
import com.maibu.utils.json.JsonUtils;
import com.maibu.utils.spring.SpringUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
@@ -21,14 +15,24 @@ import org.java_websocket.server.WebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.maibu.common.MiddleConstant;
import com.maibu.constant.CommandConstant;
import com.maibu.core.business.LawnMoverProtocolEntity;
import com.maibu.core.enums.CommandRequestType;
import com.maibu.core.enums.MesType;
import com.maibu.dto.DeviceRequestDTO;
import com.maibu.dto.DeviceRespondDTO;
import com.maibu.dto.RemoteData;
import com.maibu.dto.WebMessageBaseDTO;
import com.maibu.memory.MiddleGlobalMemory;
import com.maibu.netty.NettyClient;
import com.maibu.utils.CommandUtils;
import com.maibu.utils.ControlUtils;
import com.maibu.utils.json.JsonUtils;
import com.maibu.utils.spring.SpringUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* WebSocket服务器实现类
@@ -110,7 +114,7 @@ public class WebsocketHandler extends WebSocketServer {
List<Double> axes = remoteData.getAxes();
List<Boolean> buttons = remoteData.getButtons();
Double y = axes.get(1) * 1000 * -1; // 前后值反了
Double x = axes.get(2) * 1000;
Double x = axes.get(2) * 1000 * -1;
int intX = (int) x.doubleValue();
int intY = (int) y.doubleValue();
// todo 计算线速度和角速度 还需要根据车型来给线速度 角速度范围最大值