45 Commits

Author SHA1 Message Date
c3a2aee8fb #更新 2026-11-10 16:40:15 +08:00
99c7a3ab87 #区域连续作业相关 2026-11-03 16:06:58 +08:00
f25a0b5018 #添加了设备类型查询显示 2026-10-30 09:07:08 +08:00
e501d58563 #消息推送相关 2026-10-29 09:10:26 +08:00
965b38158f #update 2026-10-27 17:08:27 +08:00
372b1a2d11 #实时消息和参数 2026-10-23 09:12:53 +08:00
e57699dbdf #更新实时消息具体字段 2026-10-20 09:04:57 +08:00
9e3ec6a1dd #修改远程遥控控制方式 将左右轮速改成线速度和角速度 2026-10-16 09:19:31 +08:00
11984316d4 #一键寻车接口预留 2026-10-14 09:08:33 +08:00
11e209bcb3 #任务下发状态推送 2026-10-13 12:57:29 +08:00
bde6b89965 #增加系统参数配置模块 2026-10-12 15:40:23 +08:00
13eefaf152 #角色菜单查询去重 2026-10-10 10:31:37 +08:00
4fad6cc929 #注释调整 2026-09-24 14:47:26 +08:00
99d4be4ee4 #ota 接口调整 2026-09-24 12:50:02 +08:00
eb1884b972 #调整在线升级 2026-09-24 09:58:49 +08:00
c69e89fa7d #update 设备在线升级的功能 2026-09-24 08:52:26 +08:00
9cd3b8e496 #update 设备在线升级的功能 2026-09-23 15:24:49 +08:00
25a05ae9d8 #update 设备在线升级的功能 2026-09-23 14:38:12 +08:00
5c0ee1f811 #temp 2026-09-23 13:17:39 +08:00
fce873b662 #update ota 在线升级 2026-09-23 09:55:05 +08:00
1d2636f641 #优化设备下线推送 2026-09-22 13:50:19 +08:00
40c6edda36 Merge branch 'dev_map' into dev_new_connect
# Conflicts:
#	maibu-common/src/main/java/com/maibu/mqtt/HostMessageHandler.java
#	maibu-netty-server/src/main/java/com/maibu/service/DeviceThreadService.java
2026-09-21 10:30:03 +08:00
64f54c4191 #地图相关推送修改 2026-09-21 10:25:49 +08:00
be27d2b56e #修改更新状态 2026-09-20 13:40:25 +08:00
f690786847 #接受路径规划接口日志 2026-09-14 13:06:08 +08:00
4f7f32eeb2 #update 地图统一推送功能 2026-09-14 10:37:27 +08:00
cfd2906b71 #位置信息增加当前设备任务执行情况 2026-09-11 09:29:06 +08:00
985f501e76 #更新计算累计路程相关 2026-09-10 14:35:02 +08:00
a6f662b15b #老板的上位机登录 2026-09-09 13:00:31 +08:00
4ee3f6be90 #优化更新 连接上位机相关 2026-09-09 09:01:54 +08:00
fda1060b38 # update 更新导入 设备属性的功能 2026-09-03 10:32:57 +08:00
5f369a159d #更新优化 2026-09-02 05:03:10 +00:00
a92ec91cd2 #优化路径规划下发 任务状态接收相关 2026-08-28 06:32:11 +00:00
9ff685e0c1 # 测试调整路径规划消息下发处理 2026-08-25 08:36:45 +00:00
544efbd0f9 # update 权限相关 2026-08-25 12:36:10 +08:00
33df2ff0f7 # update 权限相关 2026-08-25 09:19:12 +08:00
27f4796c55 # update 2026-08-21 09:20:08 +08:00
16ec98e36a # 上位机心跳 以及定位信息发送部分 2026-08-19 16:57:55 +08:00
2f94639f0a Merge branch 'dev_control' into dev_new_connect
# Conflicts:
#	.idea/workspace.xml
2026-08-19 11:05:09 +08:00
3eb7f7bc31 #update 2026-08-19 11:03:00 +08:00
1b19e32aa5 #update 2026-08-19 11:02:52 +08:00
80bfdd134d #update mqtt 上位机 2026-08-17 11:49:33 +08:00
ffd9720939 #update mqtt 上位机 2026-08-07 10:22:03 +08:00
5f3929ae16 #update mqtt 上位机 2026-08-07 09:46:55 +08:00
3ba32b19ce #update mqtt 上位机 2026-08-07 08:45:43 +08:00
173 changed files with 7422 additions and 2190 deletions

105
.idea/workspace.xml generated
View File

@@ -6,21 +6,14 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="84ac1b15-3cfa-4375-9957-45b7b581d04e" name="Changes" comment="# commit"> <list default="true" id="84ac1b15-3cfa-4375-9957-45b7b581d04e" name="Changes" comment="# commit">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-admin/src/main/resources/application-dev.yml" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-admin/src/main/resources/application-dev.yml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/core/business/device/NettyDevice.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/core/business/device/NettyDevice.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/core/business/Device.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/core/business/Device.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/memory/DeviceSessionManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-common/src/main/java/com/maibu/memory/DeviceSessionManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/controller/UAVController.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/controller/UAVController.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/dto/DeviceBindDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/dto/DeviceBindDTO.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/dto/UavDeviceStateResponseDetailDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/dto/UavDeviceStateResponseDetailDTO.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/CommandForwardHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/CommandForwardHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/service/UAVService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-external/src/main/java/com/maibu/uav/service/UAVService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-framework/src/main/java/com/maibu/config/SecurityConfig.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/NettyServer.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/NettyServer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DeviceConnectHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DeviceConnectHandler.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DeviceConnectHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/DeviceConnectHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HeaderFooterDecoder.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HeaderFooterDecoder.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/service/TransferDeviceService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/service/TransferDeviceService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HexEncoder.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-netty-server/src/main/java/com/maibu/netty/handler/HexEncoder.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/dto/NettySwitchDeviceDTO.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/dto/NettySwitchDeviceDTO.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/DeviceController.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/DeviceController.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/netty/handler/ClientHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/netty/handler/ClientHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/IDeviceService.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/IDeviceService.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/service/impl/DeviceServiceImpl.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/resources/mapper/iot/DeviceMapper.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/common/MiddleConstant.java" beforeDir="false" afterPath="$PROJECT_DIR$/maibu-web-middleware/src/main/java/com/maibu/common/MiddleConstant.java" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -40,6 +33,11 @@
</option> </option>
</component> </component>
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="main" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="HttpClientEndpointsTabState"> <component name="HttpClientEndpointsTabState">
@@ -79,40 +77,40 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;ASKED_SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;, "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
&quot;Application.test.executor&quot;: &quot;Debug&quot;, "Application.test.executor": "Debug",
&quot;HTTP Request.MiddlePlatformApplication | #1.executor&quot;: &quot;Run&quot;, "HTTP Request.MiddlePlatformApplication | #1.executor": "Run",
&quot;HTTP Request.MiddlePlatformApplication | #2.executor&quot;: &quot;Run&quot;, "HTTP Request.MiddlePlatformApplication | #2.executor": "Run",
&quot;HTTP Request.MiddlePlatformApplication | #3.executor&quot;: &quot;Run&quot;, "HTTP Request.MiddlePlatformApplication | #3.executor": "Run",
&quot;Maven.MiddlePlatform [clean].executor&quot;: &quot;Run&quot;, "Maven.MiddlePlatform [clean].executor": "Run",
&quot;Maven.MiddlePlatform [install].executor&quot;: &quot;Run&quot;, "Maven.MiddlePlatform [install].executor": "Run",
&quot;Maven.maibu-netty-server [clean].executor&quot;: &quot;Run&quot;, "Maven.maibu-netty-server [clean].executor": "Run",
&quot;ModuleVcsDetector.initialDetectionPerformed&quot;: &quot;true&quot;, "ModuleVcsDetector.initialDetectionPerformed": "true",
&quot;RequestMappingsPanelOrder0&quot;: &quot;0&quot;, "RequestMappingsPanelOrder0": "0",
&quot;RequestMappingsPanelOrder1&quot;: &quot;1&quot;, "RequestMappingsPanelOrder1": "1",
&quot;RequestMappingsPanelWidth0&quot;: &quot;75&quot;, "RequestMappingsPanelWidth0": "75",
&quot;RequestMappingsPanelWidth1&quot;: &quot;75&quot;, "RequestMappingsPanelWidth1": "75",
&quot;RunOnceActivity.MCP Project settings loaded&quot;: &quot;true&quot;, "RunOnceActivity.MCP Project settings loaded": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252&quot;: &quot;true&quot;, "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;, "RunOnceActivity.git.unshallow": "true",
&quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;, "RunOnceActivity.typescript.service.memoryLimit.init": "true",
&quot;Spring Boot.MiddlePlatformApplication.executor&quot;: &quot;Debug&quot;, "Spring Boot.MiddlePlatformApplication.executor": "Debug",
&quot;git-widget-placeholder&quot;: &quot;main&quot;, "git-widget-placeholder": "dev__control",
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;, "kotlin-language-version-configured": "true",
&quot;last_opened_file_path&quot;: &quot;/home/maibu/Test/MiddlePlatform/maibu-external/src/main/java/com/maibu/uav&quot;, "last_opened_file_path": "/home/maibu/Test/MiddlePlatform/maibu-external/src/main/java/com/maibu/uav",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "node.js.detected.package.eslint": "true",
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, "node.js.detected.package.tslint": "true",
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.eslint": "(autodetect)",
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.tslint": "(autodetect)",
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, "nodejs_package_manager_path": "npm",
&quot;onboarding.tips.debug.path&quot;: &quot;D:/code/MiddlePlatform/maibu-service/maibu-system-service/src/main/java/com/maibu/Main.java&quot;, "onboarding.tips.debug.path": "D:/code/MiddlePlatform/maibu-service/maibu-system-service/src/main/java/com/maibu/Main.java",
&quot;settings.editor.selected.configurable&quot;: &quot;project.propVCSSupport.CommitDialog&quot;, "settings.editor.selected.configurable": "project.propVCSSupport.CommitDialog",
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; "vue.rearranger.settings.migration": "true"
} }
}</component> }]]></component>
<component name="RdControllerToolWindowsLayoutState" isNewUi="true"> <component name="RdControllerToolWindowsLayoutState" isNewUi="true">
<layout> <layout>
<window_info id="Bookmarks" side_tool="true" /> <window_info id="Bookmarks" side_tool="true" />
@@ -190,17 +188,6 @@
<configuration name="MiddlePlatformApplication | #3" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" temporary="true" nameIsGenerated="true" path="$APPLICATION_CONFIG_DIR$/scratches/MiddlePlatformApplication.http" executionIdentifier="#3" index="3" runType="Run single request"> <configuration name="MiddlePlatformApplication | #3" type="HttpClient.HttpRequestRunConfigurationType" factoryName="HTTP Request" temporary="true" nameIsGenerated="true" path="$APPLICATION_CONFIG_DIR$/scratches/MiddlePlatformApplication.http" executionIdentifier="#3" index="3" runType="Run single request">
<method v="2" /> <method v="2" />
</configuration> </configuration>
<configuration default="true" type="JetRunConfigurationType">
<module name="maibu-iot-service" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType">
<module name="maibu-iot-service" />
<option name="filePath" />
<method v="2" />
</configuration>
<configuration name="MiddlePlatformApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true"> <configuration name="MiddlePlatformApplication" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
<option name="FRAME_DEACTIVATION_UPDATE_POLICY" value="UpdateClassesAndResources" /> <option name="FRAME_DEACTIVATION_UPDATE_POLICY" value="UpdateClassesAndResources" />
<module name="maibu-admin" /> <module name="maibu-admin" />
@@ -725,7 +712,7 @@
<line-breakpoint enabled="true" type="java-method"> <line-breakpoint enabled="true" type="java-method">
<url>file://$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/IOTWorkOrderController.java</url> <url>file://$PROJECT_DIR$/maibu-service/maibu-iot-service/src/main/java/com/maibu/controller/IOTWorkOrderController.java</url>
<line>58</line> <line>58</line>
<properties class="com.maibu.controller.IOTWorkOrderController" method="edit"> <properties class="com.maibu.controller.IOTWorkOrderController" method="list">
<option name="EMULATED" value="true" /> <option name="EMULATED" value="true" />
<option name="WATCH_EXIT" value="false" /> <option name="WATCH_EXIT" value="false" />
</properties> </properties>

View File

@@ -0,0 +1,68 @@
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

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

View File

@@ -1,16 +1,19 @@
package com.maibu.web.controller.system; 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.controller.BaseController;
import com.maibu.core.domain.AjaxResult; import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.entity.SysRegion; 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 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 @Autowired
private SysRegionService sysRegionService; 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") @GetMapping("/selectBySiteId")
public AjaxResult selectBySiteId(@RequestParam Long id) { public AjaxResult selectBySiteId(@RequestParam Long siteId) {
try { try {
return AjaxResult.success(sysRegionService.selectBySiteId(id)); return AjaxResult.success(sysRegionService.selectBySiteId(siteId));
} catch (Exception e) { } catch (Exception e) {
return AjaxResult.error("保存组织出错", e.getMessage()); return AjaxResult.error("保存组织出错", e.getMessage());
} }

View File

@@ -84,3 +84,6 @@ influxdb:
org: maibu org: maibu
token: maibu-token token: maibu-token
url: http://localhost:8086 url: http://localhost:8086
minio:
endpoint : https://oss.satabot.com

View File

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

View File

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

View File

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

View File

@@ -30,37 +30,37 @@ public class DeviceTask {
private int keepAlive; private int keepAlive;
/*设备状态池*/ /* 设备状态池 */
@Bean(FastBeeConstant.TASK.DEVICE_STATUS_TASK) @Bean(FastBeeConstant.TASK.DEVICE_STATUS_TASK)
public Executor deviceStatusTaskExecutor() { public Executor deviceStatusTaskExecutor() {
return builder(FastBeeConstant.TASK.DEVICE_STATUS_TASK); return builder(FastBeeConstant.TASK.DEVICE_STATUS_TASK);
} }
/*平台自动获取线程池(例如定时获取设备信息)*/ /* 平台自动获取线程池(例如定时获取设备信息) */
@Bean(FastBeeConstant.TASK.DEVICE_FETCH_PROP_TASK) @Bean(FastBeeConstant.TASK.DEVICE_FETCH_PROP_TASK)
public Executor deviceFetchTaskExecutor() { public Executor deviceFetchTaskExecutor() {
return builder(FastBeeConstant.TASK.DEVICE_FETCH_PROP_TASK); return builder(FastBeeConstant.TASK.DEVICE_FETCH_PROP_TASK);
} }
/*设备回调信息(下发指令(服务)设备应答信息)*/ /* 设备回调信息(下发指令(服务)设备应答信息) */
@Bean(FastBeeConstant.TASK.DEVICE_REPLY_MESSAGE_TASK) @Bean(FastBeeConstant.TASK.DEVICE_REPLY_MESSAGE_TASK)
public Executor deviceReplyTaskExecutor() { public Executor deviceReplyTaskExecutor() {
return builder(FastBeeConstant.TASK.DEVICE_REPLY_MESSAGE_TASK); return builder(FastBeeConstant.TASK.DEVICE_REPLY_MESSAGE_TASK);
} }
/*设备主动上报(设备数据有变化主动上报)*/ /* 设备主动上报(设备数据有变化主动上报) */
@Bean(FastBeeConstant.TASK.DEVICE_UP_MESSAGE_TASK) @Bean(FastBeeConstant.TASK.DEVICE_UP_MESSAGE_TASK)
public Executor deviceUpMessageTaskExecutor() { public Executor deviceUpMessageTaskExecutor() {
return builder(FastBeeConstant.TASK.DEVICE_UP_MESSAGE_TASK); return builder(FastBeeConstant.TASK.DEVICE_UP_MESSAGE_TASK);
} }
/*指令下发(服务下发)*/ /* 指令下发(服务下发) */
@Bean(FastBeeConstant.TASK.FUNCTION_INVOKE_TASK) @Bean(FastBeeConstant.TASK.FUNCTION_INVOKE_TASK)
public Executor functionInvokeTaskExecutor() { public Executor functionInvokeTaskExecutor() {
return builder(FastBeeConstant.TASK.FUNCTION_INVOKE_TASK); return builder(FastBeeConstant.TASK.FUNCTION_INVOKE_TASK);
} }
/*内部消费线程*/ /* 内部消费线程 */
@Bean(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK) @Bean(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK)
public Executor messageConsumeTaskExecutor() { public Executor messageConsumeTaskExecutor() {
return builder(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK); return builder(FastBeeConstant.TASK.MESSAGE_CONSUME_TASK);
@@ -81,7 +81,7 @@ public class DeviceTask {
return builder(FastBeeConstant.TASK.DELAY_UPGRADE_TASK); return builder(FastBeeConstant.TASK.DELAY_UPGRADE_TASK);
} }
/*设备其他消息处理*/ /* 设备其他消息处理 */
@Bean(FastBeeConstant.TASK.DEVICE_OTHER_TASK) @Bean(FastBeeConstant.TASK.DEVICE_OTHER_TASK)
public Executor deviceOtherTaskExecutor() { public Executor deviceOtherTaskExecutor() {
return builder(FastBeeConstant.TASK.DEVICE_OTHER_TASK); return builder(FastBeeConstant.TASK.DEVICE_OTHER_TASK);
@@ -97,6 +97,26 @@ public class DeviceTask {
return builder(FastBeeConstant.TASK.DEVICE_ERROR_MONITOR); return builder(FastBeeConstant.TASK.DEVICE_ERROR_MONITOR);
} }
@Bean(FastBeeConstant.TASK.DEVICE_HEARTBEAT_MONITOR)
public Executor deviceHeartBeatMonitor() {
return builder(FastBeeConstant.TASK.DEVICE_HEARTBEAT_MONITOR);
}
@Bean(FastBeeConstant.TASK.AUTO_RULE)
public Executor autoRule() {
return builder(FastBeeConstant.TASK.AUTO_RULE);
}
@Bean(FastBeeConstant.TASK.REGION_CONSECUTIVE_TASK)
public Executor regionConsecutiveTask() {
return builder(FastBeeConstant.TASK.REGION_CONSECUTIVE_TASK);
}
@Bean(FastBeeConstant.TASK.MAP_MESSAGE_PUSH)
public Executor mapMessagePush() {
return builder(FastBeeConstant.TASK.MAP_MESSAGE_PUSH);
}
@Bean(FastBeeConstant.TASK.DEVICE_TASK_HANDLER) @Bean(FastBeeConstant.TASK.DEVICE_TASK_HANDLER)
public Executor deviceTaskHandler() { public Executor deviceTaskHandler() {
return builder(FastBeeConstant.TASK.DEVICE_TASK_HANDLER); return builder(FastBeeConstant.TASK.DEVICE_TASK_HANDLER);
@@ -107,8 +127,7 @@ public class DeviceTask {
return builder(FastBeeConstant.TASK.COMMON_DEVICE_MONITOR); return builder(FastBeeConstant.TASK.COMMON_DEVICE_MONITOR);
} }
/* 组装线程池 */
/*组装线程池*/
private ThreadPoolTaskExecutor builder(String threadNamePrefix) { private ThreadPoolTaskExecutor builder(String threadNamePrefix) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(coreSize); executor.setCorePoolSize(coreSize);
@@ -117,7 +136,7 @@ public class DeviceTask {
executor.setQueueCapacity(queueCapacity); executor.setQueueCapacity(queueCapacity);
// 线程池对拒绝任务的处理策略 // 线程池对拒绝任务的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
//线程池名的前缀 // 线程池名的前缀
executor.setThreadNamePrefix(threadNamePrefix); executor.setThreadNamePrefix(threadNamePrefix);
executor.initialize(); executor.initialize();
return executor; return executor;

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
package com.maibu.common; package com.maibu.constant;
import lombok.Data;
public class NettyCacheKey { public class NettyCacheKey {
public static final String deviceRunningStatusKey = "running_status:"; public static final String deviceRunningStatusKey = "running_status:";
public static final String latestPositonKey = "latest_position:";
} }

View File

@@ -13,6 +13,8 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.maibu.annotation.Excel; import com.maibu.annotation.Excel;
import com.maibu.core.domain.BaseDO; import com.maibu.core.domain.BaseDO;
import com.maibu.core.host.LocationMessage;
import com.maibu.core.host.VehicleMessage;
import com.maibu.influxdb.MowerRealTimeData; import com.maibu.influxdb.MowerRealTimeData;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
@@ -72,7 +74,6 @@ public class Device extends BaseDO {
@Excel(name = "产品名称") @Excel(name = "产品名称")
private String productName; private String productName;
/** /**
* 租户名称 * 租户名称
*/ */
@@ -85,8 +86,7 @@ public class Device extends BaseDO {
*/ */
@ApiModelProperty("固件版本") @ApiModelProperty("固件版本")
@Excel(name = "固件版本") @Excel(name = "固件版本")
private BigDecimal firmwareVersion; private String firmwareVersion;
/** /**
* WIFI固件版本 * WIFI固件版本
@@ -95,7 +95,6 @@ public class Device extends BaseDO {
@Excel(name = "HTTP推送固件版本") @Excel(name = "HTTP推送固件版本")
private BigDecimal wirelessVersion; private BigDecimal wirelessVersion;
/** /**
* 设备状态(1-未激活,2-禁用,3-在线,4-离线) * 设备状态(1-未激活,2-禁用,3-在线,4-离线)
*/ */
@@ -106,12 +105,12 @@ public class Device extends BaseDO {
/** /**
* 设备在线状态(1-在线,2-离线) * 设备在线状态(1-在线,2-离线)
*/ */
@ApiModelProperty("设备状态(1-在线,2-离线)") @ApiModelProperty("设备状态(1-在线,0-离线)")
@Excel(name = "设备在线状态") @Excel(name = "设备在线状态")
private Integer onlineStatus; private Integer onlineStatus;
@TableField(exist = false) @TableField(exist = false)
private Integer feStatus; //前端大屏显示 1任务中/2空闲 private Integer feStatus; // 前端大屏显示 1任务中/2空闲
/** /**
* wifi信号强度(信号极好4格[-55— 0],信号好3格[-70— -55],信号一般2格[-85— -70],信号差1格[-100— -85]) * wifi信号强度(信号极好4格[-55— 0],信号好3格[-70— -55],信号一般2格[-85— -70],信号差1格[-100— -85])
@@ -194,7 +193,6 @@ public class Device extends BaseDO {
@ApiModelProperty("设备摘要") @ApiModelProperty("设备摘要")
private String summary; private String summary;
/** /**
* 是否是模拟设备 * 是否是模拟设备
*/ */
@@ -206,12 +204,12 @@ public class Device extends BaseDO {
@ApiModelProperty("子设备地址") @ApiModelProperty("子设备地址")
private Integer slaveId; private Integer slaveId;
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED)
private Long siteId; private Long siteId;
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED)
private Long orgId; private Long orgId;
/** /**
* 租户ID * 租户ID
*/ */
@@ -220,7 +218,6 @@ public class Device extends BaseDO {
@TableField(updateStrategy = FieldStrategy.IGNORED) @TableField(updateStrategy = FieldStrategy.IGNORED)
private Long tenantId; private Long tenantId;
@TableField(exist = false) @TableField(exist = false)
private DeviceRunningStatusHistory lastRunningStatus; private DeviceRunningStatusHistory lastRunningStatus;
@@ -228,12 +225,25 @@ public class Device extends BaseDO {
private MowerRealTimeData lastMowerRealTimeData; private MowerRealTimeData lastMowerRealTimeData;
@TableField(exist = false) @TableField(exist = false)
private Map<Integer,Integer> statusStatistics; private Map<Integer, Integer> statusStatistics;
@TableField(exist = false) @TableField(exist = false)
private DeviceRunParam runParam; private DeviceRunParam runParam;
private Boolean hasRegistered;
private boolean hasRegistered = false; private Boolean hasHost;
@TableField(exist = false)
private String productModel;// 产品型号
@TableField(exist = false)
private String deviceType;
@TableField(exist = false)
private LocationMessage locationMessage;
@TableField(exist = false)
private VehicleMessage vehicleMessage;
} }

View File

@@ -1,18 +1,14 @@
package com.maibu.core.business; package com.maibu.core.business;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.maibu.core.domain.BaseDO; import com.maibu.core.domain.BaseDO;
import com.maibu.core.enums.ConnectType;
import io.swagger.annotations.ApiModel;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.util.List;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)

View File

@@ -1,17 +1,19 @@
package com.maibu.core.business; package com.maibu.core.business;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.maibu.core.domain.BaseDO;
import com.maibu.core.domain.OrgBaseDO; import com.maibu.core.domain.OrgBaseDO;
import com.maibu.core.domain.map.RestPoint;
import com.maibu.core.enums.DeviceTaskStaus; import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.enums.RouteType;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@TableName("iot_device_task") @TableName("iot_device_task")
@@ -24,6 +26,12 @@ public class DevicePlanTask extends OrgBaseDO {
private String deviceId; private String deviceId;
@TableField(exist = false)
private String deviceAlias; // 别名
@TableField(exist = false)
private String workName; // 路径规划名称
private DeviceTaskStaus taskStaus; // 任务状态 private DeviceTaskStaus taskStaus; // 任务状态
@TableField(exist = false) @TableField(exist = false)
@@ -39,4 +47,12 @@ public class DevicePlanTask extends OrgBaseDO {
private LocalDateTime canExecuteTime; // 这个时间之前都不能执行 private LocalDateTime canExecuteTime; // 这个时间之前都不能执行
@TableField(exist = false)
private volatile boolean taskAccepted = false; // 任务被上位机接收
private RouteType routeType;
@TableField(exist = false)
private RestPoint backTaskPoint;
} }

View File

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

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

View File

@@ -0,0 +1,41 @@
package com.maibu.core.business;
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.maibu.core.domain.OrgNoUserDO;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.utils.LongListTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("iot_region_consecutive_task_record")
public class RegionConsecutiveTaskRecord extends OrgNoUserDO {
@TableId(type = IdType.AUTO)
private Long id;
private String deviceId;
private Long regionId;
@TableField(exist = false)
private String deviceAlias; // 别名
@TableField(typeHandler = LongListTypeHandler.class)
private List<Long> routeIds; // 线路id
@TableField(typeHandler = LongListTypeHandler.class)
private List<Long> taskIds; // 线路id
private DeviceTaskStaus taskStatus; // 任务状态
private int currentIndex; // 当前执行到哪一个
}

View File

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

View File

@@ -1,35 +1,41 @@
package com.maibu.core.business.device; 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; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.maibu.core.business.Device; import com.maibu.constant.Constant;
import com.maibu.core.business.DevicePlanTask; import com.maibu.core.business.*;
import com.maibu.core.business.DeviceRunParam;
import com.maibu.core.business.DeviceRunStatistics;
import com.maibu.core.business.PlanPath;
import com.maibu.core.business.WorkRecord;
import com.maibu.core.business.path.LatAndLngEntity; import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.business.path.RoutePlanSendEntity; import com.maibu.core.business.path.RoutePlanSendEntity;
import com.maibu.core.enums.ConnectorType; import com.maibu.core.enums.ConnectorType;
import com.maibu.core.enums.DeviceTaskStaus; import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.enums.RouteType;
import com.maibu.core.host.HostModeChangeDTO;
import com.maibu.core.host.HostWorkRecordCreateDTO;
import com.maibu.core.host.MutiPointEntity;
import com.maibu.core.host.PointEntity;
import com.maibu.core.ota.DeviceOtaFirmware;
import com.maibu.mapper.DevicePlanTaskMapper; import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.RegionConsecutiveTaskRecordMapper;
import com.maibu.mapper.WorkRecordMapper; import com.maibu.mapper.WorkRecordMapper;
import com.maibu.memory.GlobalMemory; import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory; import com.maibu.memory.SiteMemory;
import com.maibu.mqtt.MqttTopic;
import com.maibu.utils.StringUtils;
import com.maibu.utils.json.JsonUtils;
import com.maibu.utils.spring.SpringUtils; import com.maibu.utils.spring.SpringUtils;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j @Slf4j
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@@ -58,15 +64,24 @@ public class NettyDevice extends Connector {
// todo 注册的时候更新 siteId // todo 注册的时候更新 siteId
private Device device; private Device device;
//todo 假如设置一个当前控制的token // todo 当前登录的账号的token 以token为控制的权限
private String currentControlToken; private String token;
@JsonIgnore @JsonIgnore
private DevicePlanTaskMapper devicePlanTaskMapper = SpringUtils.getBean(DevicePlanTaskMapper.class); private DevicePlanTaskMapper devicePlanTaskMapper = SpringUtils.getBean(DevicePlanTaskMapper.class);
@JsonIgnore
private RegionConsecutiveTaskRecordMapper regionConsecutiveTaskRecordMapper = SpringUtils
.getBean(RegionConsecutiveTaskRecordMapper.class);
@JsonIgnore @JsonIgnore
private WorkRecordMapper workRecordMapper = SpringUtils.getBean(WorkRecordMapper.class); private WorkRecordMapper workRecordMapper = SpringUtils.getBean(WorkRecordMapper.class);
@JsonIgnore
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
private static final String mqttClientId = "maibu-mqtt-client";
public NettyDevice(String connectorId) { public NettyDevice(String connectorId) {
super(connectorId); super(connectorId);
this.deviceType = ConnectorType.MASTER; // 默认上位机角色 this.deviceType = ConnectorType.MASTER; // 默认上位机角色
@@ -77,6 +92,10 @@ public class NettyDevice extends Connector {
this.deviceType = deviceType; this.deviceType = deviceType;
} }
public void status(Integer onlineStatus) {
this.onlineStatus = onlineStatus;
}
// todo 如何确定命令已收到? // todo 如何确定命令已收到?
public void sendNextPoint() { public void sendNextPoint() {
if (task.getTaskStaus().equals(DeviceTaskStaus.PAUSE)) if (task.getTaskStaus().equals(DeviceTaskStaus.PAUSE))
@@ -109,13 +128,30 @@ public class NettyDevice extends Connector {
} }
public synchronized Long finishTask() { public synchronized Long finishTask() {
sendPathCommand((byte) 0x01, (short) 0, 0.00d, 0.00d, (short) 0); // sendPathCommand((byte) 0x01, (short) 0, 0.00d, 0.00d, (short) 0);
long finishId = task.getId(); long finishId = task.getId();
task.setTaskStaus(DeviceTaskStaus.FINISH); task.setTaskStaus(DeviceTaskStaus.FINISH);
task.setFinishTime(LocalDateTime.now()); task.setFinishTime(LocalDateTime.now());
devicePlanTaskMapper.saveOrUpdate(task); devicePlanTaskMapper.saveOrUpdate(task);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId()); SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
// 更新当前任务的执行索引
RegionConsecutiveTaskRecord record = siteMemory.getRegionConsecutiveTask(device.getSerialNumber());
if (record != null && DeviceTaskStaus.EXECUTING.equals(record.getTaskStatus())) {
int maxIndex = record.getRouteIds().size() - 1;
int currentIndex = record.getCurrentIndex();
record.setUpdateTime(LocalDateTime.now());
if (currentIndex >= maxIndex) {
record.setTaskStatus(DeviceTaskStaus.FINISH);
siteMemory.removeRegionConsecutiveTask(device.getSerialNumber());
} else {
record.setCurrentIndex(currentIndex + 1);
}
regionConsecutiveTaskRecordMapper.saveOrUpdate(record);
}
siteMemory.removeDevicePlanExecute(task.getDeviceId()); siteMemory.removeDevicePlanExecute(task.getDeviceId());
GlobalMemory.taskPathMap.remove(task.getId());
task = null; task = null;
currentTaskId = null; currentTaskId = null;
currentPoint = null; currentPoint = null;
@@ -124,22 +160,69 @@ public class NettyDevice extends Connector {
return finishId; return finishId;
} }
public synchronized boolean cancelTask() { public synchronized boolean cancelingTask() throws MqttException {
if (task != null) { if (task != null) {
sendPathCommand((byte) 0x01, (short) 0, 0.00d, 0.00d, (short) 0); WorkRecord workRecord = workRecordMapper.selectById(task.getRouteId());
if (workRecord != null) {
HostWorkRecordCreateDTO dto = new HostWorkRecordCreateDTO();
dto.setAction("cancel");
dto.setCommand_id(task.getId() + "_" + System.currentTimeMillis());
dto.setTask_id(String.valueOf(task.getId()));
dto.setSn(task.getDeviceId());
dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
JsonUtils.toJsonString(dto));
task.setTaskStaus(DeviceTaskStaus.CANCELING);
task.setUpdateTime(LocalDateTime.now());
devicePlanTaskMapper.saveOrUpdate(task);
}
}
return true;
}
public synchronized Long canceledTask() {
if (task != null) {
Long taskId = task.getId();
task.setTaskStaus(DeviceTaskStaus.CANCELED); task.setTaskStaus(DeviceTaskStaus.CANCELED);
task.setUpdateTime(LocalDateTime.now()); task.setUpdateTime(LocalDateTime.now());
devicePlanTaskMapper.saveOrUpdate(task); devicePlanTaskMapper.saveOrUpdate(task);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId()); SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
siteMemory.removeDevicePlanPrepare(task); siteMemory.removeDevicePlanPrepare(task);
siteMemory.removeDevicePlanExecute(task.getDeviceId()); siteMemory.removeDevicePlanExecute(task.getDeviceId());
GlobalMemory.taskPathMap.remove(task.getId());
task = null; task = null;
currentTaskId = null; currentTaskId = null;
currentPoint = null; currentPoint = null;
locationQueue.clear(); locationQueue.clear();
executingTask = false; executingTask = false;
return taskId;
} }
return true; return null;
}
public synchronized Long failedTask() {
if (task != null) {
Long taskId = task.getId();
task.setTaskStaus(DeviceTaskStaus.FAILED);
task.setUpdateTime(LocalDateTime.now());
devicePlanTaskMapper.saveOrUpdate(task);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(task.getOrgId(), task.getSiteId());
siteMemory.removeDevicePlanPrepare(task);
siteMemory.removeDevicePlanExecute(task.getDeviceId());
GlobalMemory.taskPathMap.remove(task.getId());
task = null;
currentTaskId = null;
currentPoint = null;
locationQueue.clear();
executingTask = false;
return taskId;
}
return null;
} }
public void sendPathCommand(byte commandType, short pointCounts, double lat, double lng, short speed) { public void sendPathCommand(byte commandType, short pointCounts, double lat, double lng, short speed) {
@@ -156,8 +239,9 @@ public class NettyDevice extends Connector {
} }
} }
//配置左右轮增益系数 // 配置左右轮增益系数
public void sendWheelGainCoefficientsCommand(double leftForwardGain, double leftBackwardGain, double rightForwardGain, double rightBackwardGain) { public void sendWheelGainCoefficientsCommand(double leftForwardGain, double leftBackwardGain,
double rightForwardGain, double rightBackwardGain) {
ByteBuffer buffer = ByteBuffer.allocate(39); ByteBuffer buffer = ByteBuffer.allocate(39);
buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -189,32 +273,46 @@ 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));
// }
public void readConfigCommand() { // public void writeConfigCommand(DeviceRunParam deviceRunParam) {
byte[] bytes = DeviceRunParam.toReadBytes(); // log.debug("下发修改配置的属性:{}", JsonUtils.toJsonString(deviceRunParam));
log.debug("下发读取配置的报文:{}", toHexString(bytes)); // byte[] bytes = deviceRunParam.toWriteBytes();
if (this.getChannel() != null && this.getChannel().isActive()) { // log.debug("下发修改配置的报文:{}", toHexString(bytes));
this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes)); // if (this.getChannel() != null && this.getChannel().isActive()) {
} // this.getChannel().writeAndFlush(Unpooled.wrappedBuffer(bytes));
log.debug("下发读取配置的报文完成:{}", toHexString(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));
}
// todo 优化 // todo 优化
public synchronized boolean pauseTask() { public synchronized boolean pauseTask() throws MqttException {
if (executingTask) { if (executingTask) {
task.setTaskStaus(DeviceTaskStaus.PAUSE); task.setTaskStaus(DeviceTaskStaus.PAUSE);
sendPathCommand((byte) 0x01, (short) 2, 0.00d, 0.00d, (short) 0); HostWorkRecordCreateDTO dto = new HostWorkRecordCreateDTO();
// executingTask = false; dto.setAction("pause");
dto.setCommand_id(task.getId() + "_" + System.currentTimeMillis());
dto.setTask_id(String.valueOf(task.getId()));
dto.setSn(task.getDeviceId());
// TODO 存内存
WorkRecord workRecord = workRecordMapper.selectById(task.getRouteId());
log.debug("发送开始任务 workRecord {}", workRecord);
if (workRecord != null) {
dto.setMode(workRecord.getMode());
}
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
JsonUtils.toJsonString(dto));
return true; return true;
} else { } else {
return false; return false;
@@ -223,15 +321,26 @@ public class NettyDevice extends Connector {
} }
// todo 优化 // todo 优化
public synchronized boolean recoveryTask() throws InterruptedException { public synchronized boolean recoveryTask() throws InterruptedException, MqttException {
if (task.getTaskStaus().equals(DeviceTaskStaus.PAUSE)) { if (task.getTaskStaus().equals(DeviceTaskStaus.PAUSE)) {
task.setTaskStaus(DeviceTaskStaus.EXECUTING); task.setTaskStaus(DeviceTaskStaus.PAUSE);
executingTask = true; HostWorkRecordCreateDTO dto = new HostWorkRecordCreateDTO();
sendPathCommand((byte) 0x01, (short) 3, 0.00d, 0.00d, (short) 0); dto.setAction("resume");
// Thread.sleep(1000); dto.setCommand_id(task.getId() + "_" + System.currentTimeMillis());
// sendPathCommand((byte) 0x01, (short) 1, currentPoint.getLat(), dto.setTask_id(String.valueOf(task.getId()));
// currentPoint.getLng(), (short) 0); dto.setSn(task.getDeviceId());
// sendNextPoint(); // TODO 存内存
WorkRecord workRecord = workRecordMapper.selectById(task.getRouteId());
log.debug("发送开始任务 workRecord {}", workRecord);
if (workRecord != null) {
dto.setMode(workRecord.getMode());
}
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version(Constant.protocol_version);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
JsonUtils.toJsonString(dto));
return true; return true;
} else { } else {
return false; return false;
@@ -242,24 +351,208 @@ public class NettyDevice extends Connector {
try { try {
if (executingTask) if (executingTask)
return; return;
if (task != null) {
Long routeId = task.getRouteId();
WorkRecord workRecord = workRecordMapper.selectById(routeId);
if (workRecord != null) {
PlanPath planPath = workRecord.getJsonData();
if (planPath != null && !CollectionUtils.isEmpty(planPath.getPath())) {
planPath.getPath().forEach(x -> {
locationQueue.offer(x);
});
}
}
task.setStartTime(LocalDateTime.now());
}
executingTask = true; executingTask = true;
sendNextPoint(); if (task != null) {
// startTime 在启动前记录
task.setStartTime(LocalDateTime.now());
AtomicInteger count = new AtomicInteger(0);
ScheduledFuture<?>[] futureHolder = new ScheduledFuture<?>[1];
futureHolder[0] = executor.scheduleWithFixedDelay(() -> {
int current = count.incrementAndGet();
try {
if (task.isTaskAccepted()) {
// 成功,停止后续执行
futureHolder[0].cancel(false);
log.info("任务执行成功,停止重试,执行次数={}", current);
return;
}
sendNavigationCommand();
// 达到最大次数
if (current >= 10) {
futureHolder[0].cancel(false);
log.warn("任务执行达到最大次数,停止执行");
executingTask = false;
task.setTaskStaus(DeviceTaskStaus.FAILED);
devicePlanTaskMapper.saveOrUpdate(task);
task = null;
}
} catch (Exception e) {
log.error("任务执行异常,次数={}", current, e);
// 异常是否算一次,可以根据你的业务决定
if (current >= 10) {
futureHolder[0].cancel(false);
}
executingTask = false;
task.setTaskStaus(DeviceTaskStaus.FAILED);
devicePlanTaskMapper.saveOrUpdate(task);
task = null;
}
}, 0, 5, TimeUnit.SECONDS);
}
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); log.error("发送开始任务:error {} ", e.getMessage());
} }
} }
public synchronized void sendNavigationCommand() throws MqttException {
log.debug("发送开始任务 taskStatus:{},routeId:{}", task.getTaskStaus(), task.getRouteId());
if (!task.getTaskStaus().equals(DeviceTaskStaus.EXECUTING))
return;
WorkRecord workRecord = workRecordMapper.selectById(task.getRouteId());
log.debug("发送开始任务 workRecord {}", workRecord);
if (workRecord != null) {
HostWorkRecordCreateDTO dto = new HostWorkRecordCreateDTO();
dto.setAction("start");
dto.setCommand_id(task.getId() + "_" + System.currentTimeMillis());
dto.setTask_id(String.valueOf(task.getId()));
dto.setSn(task.getDeviceId());
dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id(task.getId() + "_" + System.currentTimeMillis());
dto.setProtocol_version(Constant.protocol_version);
PointEntity point = new PointEntity();
// 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<>();
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);
}
if (workRecord.getMode().equals("predefined_path")) {
point.setPath_id(workRecord.getId());
point.setUrl(workRecord.getFileUrl());
point.setVersion("v2");
}
}
}
point.setExecute(true);
dto.setData(point);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
JsonUtils.toJsonString(dto));
}
}
public synchronized void sendPredefined(WorkRecord workRecord) throws MqttException {
log.debug("发送开始任务 taskStatus:{},routeId:{}", task.getTaskStaus(), task.getRouteId());
if (task != null)
return;
if (workRecord != null) {
HostWorkRecordCreateDTO dto = new HostWorkRecordCreateDTO();
dto.setAction("start");
dto.setCommand_id(task.getId() + "_" + System.currentTimeMillis());
dto.setTask_id(String.valueOf(task.getId()));
dto.setSn(task.getDeviceId());
dto.setMode(workRecord.getMode());
dto.setTimestamp(System.currentTimeMillis());
dto.setMessage_id("predefined" + "_" + System.currentTimeMillis());
dto.setProtocol_version(Constant.protocol_version);
PointEntity point = new PointEntity();
List<MutiPointEntity> boundary_points = new ArrayList<>();
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.setPath_id(workRecord.getId());
point.setVersion("v2");
point.setExecute(false);
dto.setData(point);
GlobalMemory.customMqttDeviceMonitor.publish(mqttClientId,
String.format(MqttTopic.MOWER_TASK_ROUTE_SET, task.getDeviceId()),
JsonUtils.toJsonString(dto));
}
}
public void upgrade(String deviceId, DeviceOtaFirmware firmware) throws MqttException {
Map<String, Object> payload = new HashMap<>();
payload.put("action", "ota_upgrade");
payload.put("version", firmware.getVersion());
payload.put("file_url", firmware.getFileUrl());
payload.put("firmware_id", firmware.getId());
payload.put("sn", deviceId);
payload.put("timestamp", System.currentTimeMillis());
payload.put("message_id", firmware.getId() + "_" + System.currentTimeMillis());
GlobalMemory.customMqttDeviceMonitor.publish(
mqttClientId,
String.format(MqttTopic.MOWER_OTA_UPGRADE_SET, deviceId),
JsonUtils.toJsonString(payload));
}
public void searchDevice(String deviceId) throws MqttException {
Map<String, Object> payload = new HashMap<>();
payload.put("action", "search_device");
payload.put("timestamp", System.currentTimeMillis());
payload.put("message_id", "search_device_" + System.currentTimeMillis());
GlobalMemory.customMqttDeviceMonitor.publish(
mqttClientId,
String.format(MqttTopic.MOWER_SEARCH_DEVICE_SET, deviceId),
JsonUtils.toJsonString(payload));
}
/**
* 下发模式切换指令
*
* @param deviceId
* @param controlMode
* @throws MqttException
*/
public void modeChage(String deviceId, Integer controlMode) throws MqttException {
HostModeChangeDTO payload = new HostModeChangeDTO();
payload.setSn(deviceId);
payload.setTimestamp(System.currentTimeMillis());
payload.setMessage_id("modeChange_" + System.currentTimeMillis());
payload.setCommand_id("modeChangeCommand_ " + System.currentTimeMillis());
payload.setProtocol_version(Constant.protocol_version);
Map<String, Object> data = new HashMap<>();
data.put("control_mode", controlMode);
payload.setData(data);
GlobalMemory.customMqttDeviceMonitor.publish(
mqttClientId,
String.format(MqttTopic.MOWER_MODE_CHANGE_SET, deviceId),
JsonUtils.toJsonString(payload));
}
} }

View File

@@ -0,0 +1,20 @@
package com.maibu.core.business.dto;
import java.util.List;
import lombok.Data;
@Data
public class ConsecutiveTaskDTO {
private String deviceId;
private List<Long> routeIds; // 线路id
private Long orgId;
private Long siteId;
private Long regionId;
}

View File

@@ -0,0 +1,29 @@
package com.maibu.core.business.dto;
import java.time.LocalDateTime;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maibu.core.enums.DeviceTaskStaus;
import lombok.Data;
@Data
public class ConsecutiveTaskQueryDTO {
private Long siteId;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime startTime;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime endTime;
private String deviceId;
private DeviceTaskStaus taskStatus;
}

View File

@@ -0,0 +1,24 @@
package com.maibu.core.business.dto;
import lombok.Data;
@Data
public class DeviceMapPushDTO {
private String id;
private double lat;
private double lng;
private double y; // yaw
private String f; // fix_status
private double a; // altitude
private String s;// status 运行状态
private Long t; // taskId 任务id
private double p; // 任务进度
private String wk; // 任务进度
private double b; // 电量
private boolean ha = false;// hasAlarm 有无告警
private Integer cm;// 控制模式 manual_remote|auto
private String ms; // 运动状态 moving|stopped|blocked
}

View File

@@ -20,4 +20,8 @@ public class DeviceTaskCommandDTO {
private Long taskId; private Long taskId;
private Long regionId;
private boolean forceCancel = false; //强制取消 不等回复
} }

View File

@@ -1,4 +1,4 @@
package com.maibu.dto; package com.maibu.core.business.dto;
import com.maibu.core.business.path.LatAndLngEntity; import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.enums.MesType; import com.maibu.core.enums.MesType;

View File

@@ -0,0 +1,12 @@
package com.maibu.core.business.dto;
import com.maibu.core.enums.MesType;
import lombok.Data;
import java.util.List;
@Data
public class WebMapMessageDTO {
private List<DeviceMapPushDTO> data;
private MesType type;
}

View File

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

View File

@@ -0,0 +1,16 @@
package com.maibu.core.business.dto;
import java.util.List;
import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.enums.MesType;
import lombok.Data;
@Data
public class WebRouteStatusMessageDTO {
private List<LatAndLngEntity> data;
private String deviceId;
private Long taskId;
private MesType type;
}

View File

@@ -1,4 +1,4 @@
package com.maibu.dto; package com.maibu.core.business.dto;
import lombok.Data; import lombok.Data;

View File

@@ -1,7 +0,0 @@
package com.maibu.core.business.inter;
public interface DeviceWebSocketInterace {
void sendWebsoketMes(String key, String data);
}

View File

@@ -0,0 +1,10 @@
package com.maibu.core.business.inter;
public interface DeviceWebSocketInterface {
void sendWebsocketMes(String key, String data);
void sendMapWebsocketMes(Long siteId,String data);
}

View File

@@ -14,10 +14,19 @@ public class WebsocketMesDispather {
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
public void dispather(String key, String data) { public void dispather(String key, String data) {
Map<String, DeviceWebSocketInterace> beanMap = applicationContext.getBeansOfType(DeviceWebSocketInterace.class); Map<String, DeviceWebSocketInterface> beanMap = applicationContext.getBeansOfType(DeviceWebSocketInterface.class);
// 遍历 // 遍历
beanMap.values().forEach(x -> { beanMap.values().forEach(x -> {
x.sendWebsoketMes(key, data); x.sendWebsocketMes(key, data);
});
}
public void mapMessageDispather(Long siteId, String data) {
Map<String, DeviceWebSocketInterface> beanMap = applicationContext.getBeansOfType(DeviceWebSocketInterface.class);
// 遍历
beanMap.values().forEach(x -> {
x.sendMapWebsocketMes(siteId, data);
}); });
} }

View File

@@ -15,7 +15,7 @@ public class MowerCommandDispather {
@Resource @Resource
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
public Long dispathDeviceTask(DeviceTaskCommandDTO dto) { public Long dispathDeviceTask(DeviceTaskCommandDTO dto) throws Exception {
Map<String, MowerCommandInter> beanMap = applicationContext.getBeansOfType(MowerCommandInter.class); Map<String, MowerCommandInter> beanMap = applicationContext.getBeansOfType(MowerCommandInter.class);
// 遍历 // 遍历
Long id = null; Long id = null;

View File

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

View File

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

View File

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

View File

@@ -1,17 +1,22 @@
package com.maibu.core.domain.entity; package com.maibu.core.domain.entity;
import java.util.List;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.domain.BaseDO; import com.maibu.core.domain.BaseDO;
import com.maibu.utils.LongListTypeHandler;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@TableName(value = "sys_region") @TableName(value = "sys_region", autoResultMap = true)
public class SysRegion extends BaseDO { public class SysRegion extends BaseDO {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
@@ -27,6 +32,14 @@ public class SysRegion extends BaseDO {
private String remark; private String remark;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<LatAndLngEntity> scope; // 区域范围
private Integer status; private Integer status;
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; 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 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) @EqualsAndHashCode(callSuper = true)
@Data @Data
@TableName(value = "sys_site") @TableName(value = "sys_site", autoResultMap = true)
public class SysSite extends BaseDO { public class SysSite extends BaseDO {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
@@ -43,4 +46,12 @@ public class SysSite extends BaseDO {
private boolean dingTalkOrderPush = false;// 工单是否推送 private boolean dingTalkOrderPush = false;// 工单是否推送
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,22 @@
package com.maibu.core.domain.map;
import com.maibu.core.business.path.LatAndLngEntity;
import lombok.Data;
@Data
public class TempObstaclePoint {
private LatAndLngEntity center;
private String alias;
private double radius; // 半径
private double size_x; // x方向的长度
private double size_y; // y方向的长度
private String source = "platform"; // 数据来源 默认给平台
}

View File

@@ -48,6 +48,12 @@ public class LoginUser implements UserDetails {
*/ */
private String token; private String token;
/**
* 用户唯一标识 用户控制设备
*/
private String realToken;
/** /**
* 登录时间 * 登录时间
*/ */
@@ -108,7 +114,7 @@ public class LoginUser implements UserDetails {
this.permissions = permissions; this.permissions = permissions;
} }
public LoginUser(Long userId, Long deptId, Long orgId, Long siteId, Long roleId,String language, SysUser user, Set<String> permissions) { public LoginUser(Long userId, Long deptId, Long orgId, Long siteId, Long roleId, String language, SysUser user, Set<String> permissions) {
this.userId = userId; this.userId = userId;
this.deptId = deptId; this.deptId = deptId;
this.orgId = orgId; this.orgId = orgId;

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,59 @@
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;
private String 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

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

View File

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

View File

@@ -7,12 +7,13 @@ import lombok.Getter;
@AllArgsConstructor @AllArgsConstructor
public enum DeviceTaskStaus { public enum DeviceTaskStaus {
NEW("NEW","新建"), NEW("NEW", "新建"),
EXECUTING("EXECUTING","执行中"), EXECUTING("EXECUTING", "执行中"),
PAUSE("PAUSE","暂停中"), PAUSE("PAUSE", "暂停中"),
CANCELED("CANCELED","已取消"), CANCELED("CANCELED", "已取消"),
FINISH("FINISH","执行成功"), CANCELING("CANCELING", "取消中"),
FAILED("FAILED","执行失败"); FINISH("FINISH", "执行成功"),
FAILED("FAILED", "执行失败");
private final String code; private final String code;

View File

@@ -3,6 +3,7 @@ package com.maibu.core.enums;
public enum MesType { public enum MesType {
AUTH, // 登录连接权限web->be AUTH, // 登录连接权限web->be
deviceInfo, // 设备状态 be->web deviceInfo, // 设备状态 be->web
locationInfo,
path, // 路径下发 web->be path, // 路径下发 web->be
have_logged_in, // 消息 have_logged_in, // 消息
device_status_changed, // 上下线状态变化 device_status_changed, // 上下线状态变化
@@ -13,5 +14,7 @@ public enum MesType {
remoteControl, remoteControl,
detectionReport, // 障碍物消息 detectionReport, // 障碍物消息
switchPermission, // 切换控制申请 switchPermission, // 切换控制申请
switchResult;// 切换结果 switchResult,// 切换结果
route_post,// 路径规划 点位推送
mapPush;
} }

View File

@@ -0,0 +1,18 @@
package com.maibu.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum OtaOperate {
upload("upload", "上传"),
upgrade("upgrade", "升级"),
rollback("rollback", "回滚"),
reboot("reboot", "重启");
private final String name;
private final String value;
}

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

View File

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

View File

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

View File

@@ -0,0 +1,12 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HeartBeatDTO extends HostBase {
private String status;
private Long sysTimestamp; //服务器的时间
}

View File

@@ -0,0 +1,13 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class HostBase {
private String protocol_version;
private String message_id;
private String sn;
private Long timestamp; //上位机的时间
}

View File

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

View File

@@ -0,0 +1,16 @@
package com.maibu.core.host;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HostModeChangeDTO extends HostBase {
private String command_id;
private Map<String, Object> data; // map key control_mode 2=自动任务,3=远程遥控
}

View File

@@ -0,0 +1,16 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HostModeChangeReplyDTO extends HostBase {
private Boolean accepted;
private String code;
private String message;
}

View File

@@ -0,0 +1,18 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HostNavigationReplyDTO extends HostBase {
private String task_id; //任务唯一编号
private String command_id;//指令唯一编号
private boolean accepted;//是否接收
private String code;//任务动作 OK|INVALID|BUSY|ERROR
private String message;
}

View File

@@ -0,0 +1,19 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HostTaskStatusDTO extends HostBase{
private String task_id; //任务唯一编号
private String command_id;//指令唯一编号
private String mode;//导航任务模式 single_point|coverage
private String status;//任务动作 accepted|running|paused|completed|cancelled|failed
private HostTaskStatusDetailDTO data;
}

View File

@@ -0,0 +1,25 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class HostTaskStatusDetailDTO {
private double progress;// 已完成作业路径比例,转移段持平且任务内不回退。规划完成前的 0 不代表已开始覆盖。
private double distance_remaining; // 整任务剩余作业路径
private Integer number_of_recoveries;// 恢复行为次数,不代表障碍数量。
private double elapsed_s;
private double eta_s;
private Integer current_cell_index;
private Integer total_cells;
private double distance_traveled;
private double speed;
private Integer task_phase;
private String error_code;
private String error_message;
private double total_distance_m;
private double distance_traveled_m;
private double execution_time_s;
private Integer cells_completed;
}

View File

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

View File

@@ -0,0 +1,20 @@
package com.maibu.core.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class HostWorkRecordCreateDTO extends HostBase {
private String task_id; // 任务唯一编号
private String command_id;// 指令唯一编号
private String mode;// 导航任务模式 single_point|coverage
private String action;// 任务动作 start/pause/resume/cancel
// private String frame_id; //WGS84
private PointEntity data;
}

View File

@@ -0,0 +1,27 @@
package com.maibu.core.host;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.maibu.core.domain.OrgNoUserDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("iot_host_location_message")
public class LocationMessage extends OrgNoUserDO {
@TableId(type = IdType.AUTO)
private Long id;
private String deviceId;
private double latitude;
private double longitude;
private double yaw;// 目标航向,正北0°、顺时针正、0-360°
private String fix_status;
private double altitude;
}

View File

@@ -0,0 +1,14 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class MutiPointEntity {
private int index;
private double latitude;
private double longitude;
private double yaw;//目标航向,正北0°、顺时针正、0-360°
}

View File

@@ -0,0 +1,37 @@
package com.maibu.core.host;
import java.util.List;
import com.maibu.core.enums.MesType;
import lombok.Data;
@Data
public class ObstacleDetectionData {
private MesType type;
/**
* 融合状态
*/
private String fusion_status;
private String fusion_status_code;
private String fusion_status_reason;
/**
* 障碍物检测状态
*/
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

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

View File

@@ -0,0 +1,24 @@
package com.maibu.core.host;
import lombok.Data;
import java.util.List;
@Data
public class PointEntity {
private double latitude;
private double longitude;
private double yaw;// 目标航向,正北0°、顺时针正、0-360°
private List<MutiPointEntity> boundary_points;
private double cell_size;// 覆盖分辨率,单位m
private double angle;// 覆盖作业方向,单位度
private String url; // minio 存放文件的地址
private Long path_id; // 路径id 系统保存用的routeId;
private String version;
private boolean execute = true; // 是直接执行还是创建自定义任务
}

View File

@@ -0,0 +1,44 @@
package com.maibu.core.host;
import lombok.Data;
@Data
public class VehicleMessage {
private String deviceId;
private double cutter_speed;// 割刀实际转速
private double battery_percentage;// 实时电量百分比
private double battery_voltage;// 实时电压
private double left_motor_current;// 实时左电机电流
private double right_motor_current;// 实时右电机电流
private double left_motor_temperature;// 实时左电机温度
private double right_motor_temperature;// 实时右电机温度
private double main_temperature;// 实时主温度
private String mcu_time; // 下位机状态中的 MCU 时间
private double yaw;// 实时航向角度
private double pitch;// 实时俯仰角度
private String heading_status;// 实时航向状态
private double total_work_area;// 累计作业面积
private double total_work_duration;// 累计作业时长
private double total_work_distance;// 累计作业里程
private String motion;// moving|stopped|blocked 运动状态
private Boolean emergency_stop; // 急停状态
private double left_target_rpm; // 实时左电机目标转速
private double right_target_rpm;// 实时右电机目标转速
private double left_measured_rpm;// 实时左电机测量转速
private double right_measured_rpm;// 实时右电机测量转速
private double left_motor_rpm;// 实时左电机转速
private double right_motor_rpm;// 实时右电机转速
private double roll;// 实时翻滚角度
private Integer control_mode;// 遥控器拨杆对应的当前控制模式 0=无控制|1=本地遥控|2=自动任务|3=远程遥控
private double linear_speed; // 实时线速度
private double angular_speed; // 实时角速度
}

View File

@@ -1,43 +0,0 @@
package com.maibu.core.mq.message;
import com.maibu.core.ota.OtaPackageCode;
import com.maibu.core.protocol.Message;
import com.maibu.core.protocol.modbus.ModbusCode;
import io.netty.buffer.ByteBuf;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 消息解析model
* @author gsb
* @date 2022/10/10 15:53
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
public class DeviceData extends Message {
/*topic*/
private String topicName;
/*设备编号*/
private String serialNumber;
/*原数据*/
private byte[] data;
private ByteBuf buf;
private Object body;
/*MQTT OR 其他*/
private int type;
/*Modbus*/
private ModbusCode code;
/**产品id*/
private Long productId;
private OtaPackageCode netModbusCode;
private int bitCount;
}

View File

@@ -1,59 +0,0 @@
package com.maibu.core.mq.message;
import com.maibu.core.protocol.modbus.ModbusCode;
import com.maibu.enums.ServerType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 设备下发指令model
*
* @author gsb
* @date 2022/10/10 16:18
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeviceDownMessage {
private String messageId;
/**
* 时间戳,单位毫秒
*/
private Long timestamp;
/**
* 消息体
*/
private Object body;
/*下发的指令,服务调用的时候就是服务标识符*/
private String identifier;
/*产品id*/
private Long productId;
/**
* 设备编码
*/
private String serialNumber;
/**
* 从机编号
*/
private Integer slaveId;
private ModbusCode code;
private String protocolCode;
private List<PropRead> values;
private String topic;
private String subCode;
private ServerType serverType;
public DeviceDownMessage(List<PropRead> values, String topic, String subCode,String transport) {
this.values = values;
this.topic = topic;
this.subCode = subCode;
this.serverType = ServerType.explain(transport);
}
}

View File

@@ -1,33 +0,0 @@
package com.maibu.core.mq.message;
import lombok.Data;
/**
* 平台下发指令数据model
* @author bill
*/
@Data
public class DeviceFunctionMessage {
/*流水号,兼容modbus标准协议没有消息流水号*/
private String seqNo;
/*平台时间*/
private Long pfTimestamp;
/*下发的消息体*/
private Object body;
/*下发的指令物模型标识符*/
private String identifier;
/*下发的数据寄存器地址*/
private String hexAddress;
/*产品ID*/
private Long productId;
/*设备编号*/
private String serialNumber;
/*网关设备编号*/
private String protocolCode;
/*是否有子设备 0-否,1-是*/
private Integer hasSub;
/*子设备从机编号 例如 02 编号从机。通过主机集控下发的指定从机编号*/
private String subDeviceCode;
}

View File

@@ -1,31 +0,0 @@
package com.maibu.core.mq.message;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.Date;
/**
* 设备消息
* @author bill
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DeviceMessage {
/** 下发的数据*/
private Object message;
/** 下发的topic*/
private String topicName;
/** 设备编号*/
private String serialNumber;
private String dataType;
/** 时间 */
@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss:SSS")
private Date time;
}

View File

@@ -1,24 +0,0 @@
package com.maibu.core.mq.message;
import lombok.Data;
/**
* 指令下发组将的model
* @author bill
*/
@Data
public class FunctionCallBackBo {
/*下发的数据*/
private byte[] message;
/*MQTt-下发的topic*/
private String topicName;
/*设备编号*/
private String serialNumber;
/**
* 原数据包
*/
private String sources;
}

View File

@@ -1,20 +0,0 @@
package com.maibu.core.mq.message;
import lombok.Data;
/**
* 指令下发组将的model
* @author bill
*/
@Data
public class InstructionsMessage {
/*下发的数据*/
private byte[] message;
/*MQTt-下发的topic*/
private String topicName;
/*设备编号*/
private String serialNumber;
}

View File

@@ -1,32 +0,0 @@
package com.maibu.core.mq.message;
import lombok.Data;
import java.util.List;
/**
* @author gsb
* @date 2024/6/20 10:53
*/
@Data
public class ModbusPollMsg {
/**
* 下发指令
*/
private List<String> commandList;
/**
* 服务端类型
*/
private Integer serverType;
/**
* 产品id
*/
private Long productId;
/**
* 设备编码
*/
private String serialNumber;
private String transport;
}

View File

@@ -1,26 +0,0 @@
package com.maibu.core.mq.message;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
/**
* @author bill
*/
@Data
public class MqttBo {
/*主题*/
private String topic;
/*数据*/
private String data;
/*消息质量*/
private int qos = 1;
/*发送方向*/
private String direction;
/*时间*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date ts;
}

View File

@@ -1,39 +0,0 @@
package com.maibu.core.mq.message;
import com.maibu.core.protocol.modbus.ModbusCode;
import lombok.Data;
/**
* @author gsb
* @date 2022/12/9 10:15
*/
@Data
public class PropRead {
/**设备编号*/
private String serialNumber;
/**寄存器起始地址*/
private int address;
/**
* 读取寄存器个数
*/
private int count;
/**数据结果长度计算值*/
private int length;
/**
* 从机地址
*/
private int slaveId;
/**
* 读取个数
*/
private int quantity;
/**
* 数据
*/
private String data;
/**
* 功能码
*/
private ModbusCode code;
}

View File

@@ -1,21 +0,0 @@
package com.maibu.core.mq.message;
import lombok.Data;
/**
* 协议bean
* @author gsb
* @date 2022/10/25 14:54
*/
@Data
public class ProtocolDto {
/**协议编号*/
private String code;
private String name;
/*外部协议url*/
private String protocolUrl;
private String description;
/**协议类型 协议类型 0:系统协议 1:jar,2.js,3.c*/
private Integer protocolType;
}

View File

@@ -1,18 +0,0 @@
package com.maibu.core.mq.message;
import lombok.Data;
/**
* 网关子设备model
* @author gsb
* @date 2022/10/10 10:18
*/
@Data
public class SubDeviceMessage {
/*子设备编号或编码*/
private String serialNumber;
/*数据*/
private byte[] data;
/*消息id*/
private String messageId;
}

View File

@@ -1,21 +0,0 @@
package com.maibu.core.mq.ota;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.math.BigDecimal;
/**
* OTA升级回复model
* @author gsb
* @date 2022/10/24 17:20
*/
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class OtaReplyMessage {
private Long taskId;
private BigDecimal version;
private int status;
private int progress;
}

View File

@@ -1,40 +0,0 @@
package com.maibu.core.mq.ota;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
/**
* OTA远程升级
* @author gsb
* @date 2022/10/10 10:22
*/
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class OtaUpgradeBo {
// 设备编码
private String serialNumber;
// 升级任务ID
private Long taskId;
// 消息内容
private byte[] msg;
// 设备状态
private int status;
// topic
private String topicName;
// 固件包版本
private BigDecimal version;
// 固件包http地址
private String url;
// 固件包分包传输大小
private int packageSize;
// 固件包传输偏移量
private int offset;
// 升级进度
private int progress;
}

View File

@@ -1,63 +0,0 @@
package com.maibu.core.mq.ota;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maibu.utils.DateUtils;
import lombok.Data;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* ota升级发送,实现Delayed延时接口
*
* @author bill
*/
@Data
public class OtaUpgradeDelayTask implements Delayed {
/**
* 固件id
*/
private Long firmwareId;
/**
* 1:指定产品 2:指定设备
*/
private Long upgradeType;
private List<String> devices;
/**
* 任务id
*/
private Long taskId;
/**
* 开始升级时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date startTime;
/**
* 设置延迟执行时间 开始升级时间 -当前时间
*
* @param unit
* @return
*/
@Override
public long getDelay(TimeUnit unit) {
return startTime.getTime() - DateUtils.getTimestamp();
}
@Override
public int compareTo(Delayed o) {
OtaUpgradeDelayTask delayTask = (OtaUpgradeDelayTask) o;
//比较
long diff = this.startTime.getTime() - delayTask.startTime.getTime();
if (diff <= 0) {
return -1;
} else {
return 1;
}
}
}

View File

@@ -0,0 +1,36 @@
package com.maibu.core.ota;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.maibu.core.domain.BaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@TableName("iot_ota_firmware")
public class DeviceOtaFirmware extends BaseDO {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Long id;
private String version; //版本号
private String fileName; //文件名
private String minioObjectName; //服务器文件名
private String fileUrl; //存放地址
private String deviceType;
private String fileSize;
private String description;
}

View File

@@ -0,0 +1,37 @@
package com.maibu.core.ota;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.maibu.core.domain.BaseDO;
import com.maibu.core.enums.OtaOperate;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@TableName(value = "iot_ota_operate_record", autoResultMap = true)
public class DeviceOtaOperateRecord extends BaseDO {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Long id;
private OtaOperate operateType; // 操作类型
private String fileName; // 名称
private Long firmwareId; // id
private String deviceId; // 名称
private String deviceType;
private String preVersion;
private String nowVersion;
}

View File

@@ -1,45 +0,0 @@
package com.maibu.core.ota;
import com.maibu.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum OtaPackageCode {
OTA_01("查询产品工装号",(byte) 0x01),
OTA_0A("OTA升级启动",(byte) 0x0A),
OTA_0B("OTA升级包传输",(byte) 0x0B)
;
private String desc;
private byte code;
public static OtaPackageCode getInstance(int code) {
switch ((byte)code) {
case 0x01:
return OTA_01;
case 0x0A:
return OTA_0A;
case 0x0B:
return OTA_0B;
default:
throw new ServiceException("功能码[" + code + "],未定义");
}
}
public static String getDes(int code){
switch ((byte)code) {
case 0x01:
return OTA_01.desc;
case 0x0A:
return OTA_0A.desc;
case 0x0B:
return OTA_0B.desc;
default:
return "UNKOWN";
}
}
}

View File

@@ -0,0 +1,24 @@
package com.maibu.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 设备回调状态
*
* @author bill
*/
@Getter
@AllArgsConstructor
public enum DeviceStatusEnum {
working("1", "工作中"),
idle("2", "空闲中"),
offline("3", "离线"),
charging("4", "充电中"),
error("5", "故障");
String code;
String message;
}

View File

@@ -6,8 +6,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.util.CollectionUtils;
import com.influxdb.query.FluxRecord; import com.influxdb.query.FluxRecord;
import com.influxdb.query.FluxTable; import com.influxdb.query.FluxTable;
import com.maibu.influxdb.inter.InfluxField; import com.maibu.influxdb.inter.InfluxField;

View File

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

View File

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

View File

@@ -1,8 +1,15 @@
package com.maibu.mapper; package com.maibu.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.maibu.core.business.DevicePlanTask; import com.maibu.core.business.DevicePlanTask;
import com.maibu.mybatis.mapper.BaseMapperX; import com.maibu.mybatis.mapper.BaseMapperX;
import org.springframework.stereotype.Repository;
/** /**
* 设备历史状态 * 设备历史状态
@@ -10,4 +17,12 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public interface DevicePlanTaskMapper extends BaseMapperX<DevicePlanTask> { public interface DevicePlanTaskMapper extends BaseMapperX<DevicePlanTask> {
@Select("SELECT t.*, iwr.work_name,d.device_alias " +
"FROM iot_device_task t " +
"LEFT JOIN iot_device d ON d.serial_number = t.device_id " +
"left join iot_work_record iwr on t.route_id = iwr.id " +
"${ew.customSqlSegment}")
List<DevicePlanTask> selectTaskHistoryWithDeviceAlias(
@Param(Constants.WRAPPER) Wrapper<DevicePlanTask> wrapper);
} }

View File

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

View File

@@ -0,0 +1,14 @@
package com.maibu.mapper;
import org.springframework.stereotype.Repository;
import com.maibu.core.business.RegionConsecutiveTaskRecord;
import com.maibu.mybatis.mapper.BaseMapperX;
/**
* 区域连续任务下发记录
*/
@Repository
public interface RegionConsecutiveTaskRecordMapper extends BaseMapperX<RegionConsecutiveTaskRecord> {
}

View File

@@ -1,13 +1,16 @@
package com.maibu.memory; package com.maibu.memory;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.maibu.core.business.device.Connector; import com.maibu.core.business.device.Connector;
import com.maibu.core.business.device.NettyDevice; import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.enums.ConnectorStatus; import com.maibu.core.enums.ConnectorStatus;
import com.maibu.core.enums.ConnectorType; import com.maibu.core.enums.ConnectorType;
import com.maibu.utils.json.JsonUtils;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -24,19 +27,22 @@ import java.util.stream.Collectors;
*/ */
@Component @Component
@Data @Data
@Slf4j
public class DeviceSessionManager { public class DeviceSessionManager {
private static final Logger logger = LoggerFactory.getLogger(DeviceSessionManager.class); private static final Logger logger = LoggerFactory.getLogger(DeviceSessionManager.class);
// 设备ID -> 设备对象(业务实体) // 设备ID -> 设备对象(业务实体)
private final ConcurrentHashMap<String, NettyDevice> deviceMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, NettyDevice> deviceMap = new ConcurrentHashMap<>();
// 当前设备的控制权在哪 登录的账号 deviceId(下位机) -> token key 唯一保证一个deviceId 只有一个控制权
private final ConcurrentHashMap<String, String> controllerMap = new ConcurrentHashMap<>();
// 设备ID -> Channel(通信通道) // 设备ID -> Channel(通信通道)
private final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
// Channel -> 设备ID(反查) // Channel -> 设备ID(反查)
private final ConcurrentHashMap<Channel, String> channelToDeviceIdMap = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Channel, String> channelToDeviceIdMap = new ConcurrentHashMap<>();
public void clearChannelToDeviceIdMap(String deviceId) { public void clearChannelToDeviceIdMap(String deviceId) {
if (StringUtils.isEmpty(deviceId) || CollectionUtils.isEmpty(channelToDeviceIdMap)) { if (StringUtils.isEmpty(deviceId) || CollectionUtils.isEmpty(channelToDeviceIdMap)) {
return; return;
@@ -64,7 +70,6 @@ public class DeviceSessionManager {
} }
} }
/** /**
* 注册设备连接(设备上线) * 注册设备连接(设备上线)
* *
@@ -72,7 +77,8 @@ public class DeviceSessionManager {
* @param channel 通信通道 * @param channel 通信通道
* @param deviceType 设备类型(MASTER/SLAVE) * @param deviceType 设备类型(MASTER/SLAVE)
*/ */
public void registerDevice(String deviceId, Channel channel, ConnectorType deviceType, ConnectorStatus status, String slaveId) { public void registerDevice(String deviceId, Channel channel, ConnectorType deviceType, ConnectorStatus status,
String slaveId) {
NettyDevice nettyDevice = deviceMap.computeIfAbsent(deviceId, id -> new NettyDevice(id, deviceType)); NettyDevice nettyDevice = deviceMap.computeIfAbsent(deviceId, id -> new NettyDevice(id, deviceType));
nettyDevice.setChannel(channel); nettyDevice.setChannel(channel);
nettyDevice.setConnectorStatus(status); // 默认上线即ACTIVE nettyDevice.setConnectorStatus(status); // 默认上线即ACTIVE
@@ -84,6 +90,20 @@ public class DeviceSessionManager {
System.out.println("Registered device: " + deviceId + " type: " + deviceType); System.out.println("Registered device: " + deviceId + " type: " + deviceType);
} }
/**
* 注册下位机设备
*
* @param deviceId 设备ID
*/
public void registerSlaveDevice(String deviceId, ConnectorStatus status, String slaveId) {
NettyDevice nettyDevice = deviceMap.computeIfAbsent(deviceId, id -> new NettyDevice(id, ConnectorType.SLAVE));
nettyDevice.setConnectorStatus(status); // 默认上线即ACTIVE
nettyDevice.setCurrentSlaveId(slaveId);
nettyDevice.setLatestLoginTime(System.currentTimeMillis());
deviceMap.put(deviceId, nettyDevice);
logger.debug("Registered slave device:{},type:{}", deviceId, ConnectorType.SLAVE);
}
/** /**
* 上位机绑定下位机,建立双向绑定关系 * 上位机绑定下位机,建立双向绑定关系
* *
@@ -92,7 +112,8 @@ public class DeviceSessionManager {
*/ */
public void bindConnector(String masterId, String slaveId) { public void bindConnector(String masterId, String slaveId) {
NettyDevice master = deviceMap.get(masterId); NettyDevice master = deviceMap.get(masterId);
if (master == null) return; if (master == null)
return;
NettyDevice slave = deviceMap.computeIfAbsent(slaveId, id -> new NettyDevice(id, ConnectorType.SLAVE)); NettyDevice slave = deviceMap.computeIfAbsent(slaveId, id -> new NettyDevice(id, ConnectorType.SLAVE));
master.addConnectedDevice(slave); master.addConnectedDevice(slave);
System.out.println("Bind connectors for master " + masterId + " and slave " + slaveId); System.out.println("Bind connectors for master " + masterId + " and slave " + slaveId);
@@ -105,6 +126,62 @@ public class DeviceSessionManager {
return deviceMap.get(deviceId); return deviceMap.get(deviceId);
} }
/**
* 获取有控制权的 客户端
*/
public String getMaster(String deviceId) {
return controllerMap.get(deviceId);
}
/**
* 获取客户端当前 控制的设备
*/
public String getControl(String token) {
for (String key : controllerMap.keySet()) {
if (controllerMap.get(key).equals(token)) {
return controllerMap.get(token);
}
}
return null;
}
public void lock(String deviceId, String token) {
if (!StringUtils.isEmpty(deviceId) && !StringUtils.isEmpty(token)) {
controllerMap.put(deviceId, token);
}
}
public boolean unLock(String token) {
if (!StringUtils.isEmpty(token)) {
Iterator<String> iterator = controllerMap.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
if (controllerMap.get(key).equals(token)) {
iterator.remove();
}
}
}
return true;
}
public boolean unLock(String deviceId, String token, boolean force) {
if (!StringUtils.isEmpty(deviceId)) {
if (force) {
controllerMap.remove(deviceId);
return true;
} else {
String nowToken = controllerMap.get(deviceId);
if (!StringUtils.isEmpty(token) && nowToken.equals(token)) {
controllerMap.remove(deviceId);
return true;
}
}
}
return false;
}
// 模糊匹配 // 模糊匹配
public List<NettyDevice> getDevicesLike(String query) { public List<NettyDevice> getDevicesLike(String query) {
return deviceMap.values().stream() return deviceMap.values().stream()
@@ -112,32 +189,31 @@ public class DeviceSessionManager {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public List<NettyDevice> getSlaveControl(String slaveId) { public List<NettyDevice> getSlaveControl(String slaveId) {
// 获取所有连接的主机 且是active状态的 // 获取所有连接的主机 且是active状态的
return deviceMap.values().stream() return deviceMap.values().stream()
.filter(device -> ObjectUtil.equals(device.getCurrentSlaveId(), slaveId) .filter(device -> Objects.equals(device.getCurrentSlaveId(), slaveId)
&& ConnectorStatus.ACTIVE.equals(device.getConnectorStatus())) && ConnectorStatus.ACTIVE.equals(device.getConnectorStatus()))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public List<NettyDevice> getAllSlaveControl(String slaveId) { public List<NettyDevice> getAllSlaveControl(String slaveId) {
// 获取所有连接的主机 不区分状态 // 获取所有连接的主机 不区分状态
return deviceMap.values().stream() return deviceMap.values().stream()
.filter(device -> ObjectUtil.equals(device.getCurrentSlaveId(), slaveId)) .filter(device -> !StringUtils.isEmpty(device.getCurrentSlaveId())
&& Objects.equals(device.getCurrentSlaveId(), slaveId)
&& device.getDeviceType().equals(ConnectorType.MASTER))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public NettyDevice getCurrentControl(String slaveId) { public NettyDevice getCurrentControl(String slaveId) {
// 获取所有连接的主机 不区分状态 // 获取所有连接的主机 不区分状态
return deviceMap.values().stream() return deviceMap.values().stream()
.filter(device -> ObjectUtil.equals(device.getCurrentSlaveId(), slaveId) .filter(device -> Objects.equals(device.getCurrentSlaveId(), slaveId)
&& ConnectorStatus.ACTIVE.equals(device.getConnectorStatus())) && ConnectorStatus.ACTIVE.equals(device.getConnectorStatus()))
.findFirst().orElse(null); .findFirst().orElse(null);
} }
/// 模糊匹配 /// 模糊匹配
public NettyDevice getUserControl(String userName) { public NettyDevice getUserControl(String userName) {
return deviceMap.values().stream() return deviceMap.values().stream()
@@ -146,7 +222,6 @@ public class DeviceSessionManager {
.findFirst().orElse(null); .findFirst().orElse(null);
} }
/** /**
* 根据设备ID获取Channel * 根据设备ID获取Channel
*/ */
@@ -161,7 +236,6 @@ public class DeviceSessionManager {
return channelToDeviceIdMap.get(channel); return channelToDeviceIdMap.get(channel);
} }
/** /**
* 根据从机查控制的主机 * 根据从机查控制的主机
*/ */
@@ -174,7 +248,8 @@ public class DeviceSessionManager {
* 根据从机查所有主机 * 根据从机查所有主机
*/ */
public List<NettyDevice> getMastersBySlaveId(String slaveId) { public List<NettyDevice> getMastersBySlaveId(String slaveId) {
return deviceMap.values().stream().filter(x -> Objects.equals(x.getCurrentSlaveId(), slaveId)).collect(Collectors.toList()); return deviceMap.values().stream().filter(x -> Objects.equals(x.getCurrentSlaveId(), slaveId))
.collect(Collectors.toList());
} }
/** /**
@@ -182,18 +257,25 @@ public class DeviceSessionManager {
*/ */
public void removeDevice(String deviceId) { public void removeDevice(String deviceId) {
NettyDevice nettyDevice = deviceMap.remove(deviceId); NettyDevice nettyDevice = deviceMap.remove(deviceId);
// Channel channel = channelMap.remove(deviceId); // Channel channel = channelMap.remove(deviceId);
clearChannelToDeviceIdMap(deviceId); clearChannelToDeviceIdMap(deviceId);
// if (channel != null) { // if (channel != null) {
// channelToDeviceIdMap.remove(channel); // channelToDeviceIdMap.remove(channel);
// channel.close(); // channel.close();
// } // }
if (nettyDevice != null) { if (nettyDevice != null) {
// 仅当设备是上位机时,才解绑绑定关系 // 仅当设备是上位机时,才解绑绑定关系
if (nettyDevice.getDeviceType() == ConnectorType.MASTER) { if (nettyDevice.getDeviceType() == ConnectorType.MASTER) {
for (Connector connected : new HashSet<>(nettyDevice.getConnectedConnectors())) { for (Connector connected : new HashSet<>(nettyDevice.getConnectedConnectors())) {
nettyDevice.removeConnectedDevice(connected); nettyDevice.removeConnectedDevice(connected);
} }
// 清理channel和状态
nettyDevice.setChannel(null);
Channel channel = channelMap.remove(deviceId);
if (channel != null) {
channelToDeviceIdMap.remove(channel);
channel.close();
}
} else { } else {
// 如果是下位机,则保留绑定关系,只清理channel和状态 // 如果是下位机,则保留绑定关系,只清理channel和状态
nettyDevice.setChannel(null); nettyDevice.setChannel(null);
@@ -206,7 +288,6 @@ public class DeviceSessionManager {
} }
} }
/** /**
* 判断设备是否在线 * 判断设备是否在线
*/ */
@@ -231,5 +312,23 @@ public class DeviceSessionManager {
return nettyDevice != null && nettyDevice.canReceive(); return nettyDevice != null && nettyDevice.canReceive();
} }
/**
* 获取客户端当前 控制的设备
*/
public String getDeviceByTaskId(Long taskId) {
if (taskId == null) {
return null;
}
log.debug("sendMessage deviceMap:{},taskId={}", JsonUtils.toJsonString(deviceMap), taskId);
for (String key : deviceMap.keySet()) {
NettyDevice nettyDevice = deviceMap.get(key);
log.debug("sendMessage currentTaskId:{},equal {}", JsonUtils.toJsonString(nettyDevice.getCurrentTaskId()),
Objects.equals(nettyDevice.getCurrentTaskId(), taskId));
if (nettyDevice != null && Objects.equals(nettyDevice.getCurrentTaskId(), taskId)) {
return nettyDevice.getConnectorId();
}
}
return null;
}
} }

Some files were not shown because too many files have changed in this diff Show More