This commit is contained in:
2026-06-17 09:14:42 +08:00
parent 3879cd0067
commit a68a670ecb
27 changed files with 1053 additions and 392 deletions

View File

@@ -20,22 +20,24 @@ spring:
max-idle: 8 # 连接池中的最大空闲连接 max-idle: 8 # 连接池中的最大空闲连接
max-active: 8 # 连接池的最大数据库连接数 max-active: 8 # 连接池的最大数据库连接数
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
# mqtt 配置
mqtt:
username: fastbee # 账号
password: fastbee # 密码
host-url: tcp://localhost:1883 # mqtt连接tcp地址
client-id: ${random.int} # 客户端Id,不能相同,采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 30 # 超时时间
keepalive: 30 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
servlet: servlet:
multipart: multipart:
enabled: true enabled: true
max-file-size: 10MB max-file-size: 10MB
max-request-size: 10MB max-request-size: 10MB
# mqtt 配置
mqtt:
username: maibu # 账号
password: jsmbzn520 # 密码
host-url: tcp://localhost:1883 # mqtt连接tcp地址
client-id: maibu-mqtt-client # 客户端Id,不能相同,采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 30 # 超时时间
keepalive: 30 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
logging: logging:
level: level:
com.maibu: debug com.maibu: debug
@@ -81,3 +83,4 @@ influxdb:
bucket: device_data bucket: device_data
org: maibu org: maibu
token: maibu-token token: maibu-token
url: http://localhost:8086

View File

@@ -5,6 +5,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.influxdb.MowerRealTimeData;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@@ -220,9 +222,8 @@ public class Device extends BaseDO {
@TableField(exist = false) @TableField(exist = false)
private DeviceRunningStatusHistory lastRunningStatus; private DeviceRunningStatusHistory lastRunningStatus;
public DeviceRunningStatusHistory getLastRunningStatus() { @TableField(exist = false)
return lastRunningStatus != null ? lastRunningStatus : new DeviceRunningStatusHistory(); private MowerRealTimeData lastMowerRealTimeData;
}
@TableField(exist = false) @TableField(exist = false)
private Map<Integer,Integer> statusStatistics; private Map<Integer,Integer> statusStatistics;

View File

@@ -6,11 +6,10 @@ 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 lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.io.Serializable;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName(value = "iot_work_record", autoResultMap = true) @TableName(value = "iot_work_record", autoResultMap = true)

View File

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

View File

@@ -98,6 +98,8 @@ public class NettyDevice extends Connector {
siteMemory.removeDevicePlanExecute(task.getDeviceId()); siteMemory.removeDevicePlanExecute(task.getDeviceId());
task = null; task = null;
currentTaskId = null; currentTaskId = null;
currentPoint = null;
locationQueue.clear();
executingTask = false; executingTask = false;
return finishId; return finishId;
} }
@@ -113,6 +115,7 @@ public class NettyDevice extends Connector {
siteMemory.removeDevicePlanExecute(task.getDeviceId()); siteMemory.removeDevicePlanExecute(task.getDeviceId());
task = null; task = null;
currentTaskId = null; currentTaskId = null;
currentPoint = null;
locationQueue.clear(); locationQueue.clear();
executingTask = false; executingTask = false;
} }
@@ -152,8 +155,9 @@ public class NettyDevice extends Connector {
task.setTaskStaus(DeviceTaskStaus.EXECUTING); task.setTaskStaus(DeviceTaskStaus.EXECUTING);
executingTask = true; executingTask = true;
sendPathCommand((byte) 0x01, (short) 3, 0.00d, 0.00d, (short) 0); sendPathCommand((byte) 0x01, (short) 3, 0.00d, 0.00d, (short) 0);
Thread.sleep(1000); // Thread.sleep(1000);
sendPathCommand((byte) 0x01, (short) 1, currentPoint.getLat(), currentPoint.getLng(), (short) 0); // sendPathCommand((byte) 0x01, (short) 1, currentPoint.getLat(),
// currentPoint.getLng(), (short) 0);
// sendNextPoint(); // sendNextPoint();
return true; return true;
} else { } else {

View File

@@ -1,29 +0,0 @@
package com.maibu.influxdb;
import com.maibu.influxdb.inter.InfluxField;
import com.maibu.influxdb.inter.InfluxTag;
import com.maibu.influxdb.inter.InfluxTime;
import com.maibu.influxdb.inter.InfluxMeasurement;
import lombok.Data;
import java.time.Instant;
//@Measurement(name = "device_data")
@Data
@InfluxMeasurement("device_data")
public class DeviceData {
// @Column(tag = true)
@InfluxTag
private String deviceId;
@InfluxField
private Double temperature;
@InfluxField
private Double voltage;
@InfluxTime
private Instant time;
}

View File

@@ -0,0 +1,155 @@
package com.maibu.influxdb;
import java.time.Instant;
import java.util.List;
import org.springframework.util.CollectionUtils;
import com.influxdb.query.FluxRecord;
import com.maibu.influxdb.inter.InfluxField;
import com.maibu.influxdb.inter.InfluxMeasurement;
import com.maibu.influxdb.inter.InfluxTag;
import com.maibu.influxdb.inter.InfluxTime;
import lombok.Data;
//@Measurement(name = "device_data")
@Data
@InfluxMeasurement("mower_realTime_data")
public class MowerRealTimeData {
// @Column(tag = true)
@InfluxTag
private String deviceId;
@InfluxField
private String voltage;// 电压
@InfluxField
private String leftTargetSpeed; // 左轮目标速度
@InfluxField
private String rightTargetSpeed;// 右轮目标速度
@InfluxField
private String leftMeasureSpeed;// 左轮测量速度
@InfluxField
private String rightMeasureSpeed;// 右轮测量速度
@InfluxField
private String leftCurrent;// 左轮电流
@InfluxField
private String rightCurrent;// 右轮电流
@InfluxField
private String leftMotorTemp;// 左轮温度
@InfluxField
private String rightMotorTemp;// 右轮温度
@InfluxField
private String chipTemp;// 芯片温度
@InfluxField
private String yaw;// 偏航角
@InfluxField
private String pitch;// 仰俯角
@InfluxField
private String roll;// 翻滚角
@InfluxField
private String satelliteCnt;// 跟踪的卫星数
@InfluxField
private String qual;// 定位质量
@InfluxField
private String headingStatus;// 航向角状态
@InfluxField
private String latitude;// 纬度
@InfluxField
private String longitude;// 经度
@InfluxField
private String cuttingSpeed;// 割刀速度
@InfluxField
private String controlMode;// 控制模式
@InfluxField
private String battery;// 电池电量
@InfluxField
private String workingArea;// 作业面积
@InfluxField
private String obstacleSign;// 障碍物标志位
@InfluxTime
private Instant time;
public static MowerRealTimeData transferLatestInfluxData(FluxRecord record) {
if (record == null || record.getValue() == null) {
return null;
}
MowerRealTimeData data = new MowerRealTimeData();
data.setDeviceId((String) record.getValueByKey("deviceId"));
data.setVoltage((String) record.getValueByKey("voltage"));
data.setLeftTargetSpeed((String) record.getValueByKey("leftTargetSpeed"));
data.setRightTargetSpeed((String) record.getValueByKey("rightTargetSpeed"));
data.setLeftMeasureSpeed((String) record.getValueByKey("leftMeasureSpeed"));
data.setRightMeasureSpeed((String) record.getValueByKey("rightMeasureSpeed"));
data.setLeftMotorTemp((String) record.getValueByKey("leftMotorTemp"));
data.setRightMotorTemp((String) record.getValueByKey("rightMotorTemp"));
data.setLeftCurrent((String) record.getValueByKey("leftCurrent"));
data.setRightCurrent((String) record.getValueByKey("rightCurrent"));
data.setChipTemp((String) record.getValueByKey("chipTemp"));
data.setYaw((String) record.getValueByKey("yaw"));
data.setPitch((String) record.getValueByKey("pitch"));
data.setRoll((String) record.getValueByKey("roll"));
data.setSatelliteCnt((String) record.getValueByKey("satelliteCnt"));
data.setQual((String) record.getValueByKey("qual"));
data.setHeadingStatus((String) record.getValueByKey("headingStatus"));
data.setLatitude((String) record.getValueByKey("latitude"));
data.setLongitude((String) record.getValueByKey("longitude"));
data.setCuttingSpeed((String) record.getValueByKey("cuttingSpeed"));
data.setControlMode((String) record.getValueByKey("controlMode"));
data.setBattery((String) record.getValueByKey("battery"));
data.setWorkingArea((String) record.getValueByKey("workingArea"));
data.setObstacleSign((String) record.getValueByKey("obstacleSign"));
return data;
}
}

View File

@@ -1,65 +0,0 @@
package com.maibu.influxdb;
import com.influxdb.query.FluxRecord;
import com.influxdb.query.FluxTable;
import com.maibu.influxdb.util.InfluxDBUtil;
import com.maibu.influxdb.util.InfluxSqlBuilder;
import org.springframework.beans.factory.annotation.Value;
import java.time.Instant;
import java.util.List;
import java.util.Map;
public class test {
@Value("${ioTDA.serverIp}")
private String serverIp;
// @Value("${ioTDA.deviceId}")
// private String deviceId;
@Value("${ioTDA.secret}")
private String secret;
@Value("${ioTDA.serviceId}")
private String serviceId;
public static void main(String[] args) {
String url = "http://localhost:8086";
String token = "maibu-token";
String org = "maibu";
String bucket = "device_data";
//
// InfluxDBClient client = InfluxDBClientFactory.create(url, token.toCharArray(), org, bucket);
//
//
// WriteApiBlocking writeApi = client.getWriteApiBlocking();
InfluxDBUtil dbUtil = new InfluxDBUtil(url,token,org,bucket);
DeviceData data = new DeviceData();
data.setDeviceId("AGV_001");
data.setTemperature(36.522);
data.setVoltage(48.222);
data.setTime(Instant.now());
String line = InfluxSqlBuilder.buildLine(data);
dbUtil.write(line);
Map<String, String> map = InfluxSqlBuilder.buildTagMap(data,DeviceData::getDeviceId);
String flux = InfluxSqlBuilder.buildQuery(bucket,bucket,10,map,"temperature");
List<FluxTable> tables = dbUtil.query(flux);
for (FluxTable table : tables) {
for (FluxRecord record : table.getRecords()) {
System.out.println(record.getValue());
}
}
}
}

View File

@@ -14,15 +14,15 @@ public class InfluxDBUtil {
private InfluxDBClient client; private InfluxDBClient client;
private WriteApi writeApi; private WriteApi writeApi;
private String bucket; public String bucket;
private String org; public String org;
public InfluxDBUtil(String url, String token, String org, String bucket) { public InfluxDBUtil(String url, String token, String org, String bucket) {
this.client = InfluxDBClientFactory.create(url, token.toCharArray(), org, bucket); this.client = InfluxDBClientFactory.create(url, token.toCharArray(), org, bucket);
this.bucket = bucket; this.bucket = bucket;
this.org = org; this.org = org;
// ✅ 异步批量写入(核心) // 异步批量写入(核心)
this.writeApi = client.makeWriteApi( this.writeApi = client.makeWriteApi(
WriteOptions.builder() WriteOptions.builder()
.batchSize(5000) // 每5000条写一次 .batchSize(5000) // 每5000条写一次
@@ -32,20 +32,20 @@ public class InfluxDBUtil {
.build() .build()
); );
// ✅ 监听写入成功 // 监听写入成功
this.writeApi.listenEvents(WriteSuccessEvent.class, event -> { this.writeApi.listenEvents(WriteSuccessEvent.class, event -> {
// 可关闭或打debug日志 // 可关闭或打debug日志
// System.out.println("写入成功"); // System.out.println("写入成功");
}); });
// ✅ 监听异常 // 监听异常
this.writeApi.listenEvents(WriteErrorEvent.class, event -> { this.writeApi.listenEvents(WriteErrorEvent.class, event -> {
System.err.println("InfluxDB写入失败: " + event.getThrowable().getMessage()); System.err.println("InfluxDB写入失败: " + event.getThrowable().getMessage());
}); });
} }
// ========================= // =========================
// ✅ 批量写入(推荐 Line Protocol) // 批量写入(推荐 Line Protocol)
// ========================= // =========================
public void writeBatch(List<String> lines) { public void writeBatch(List<String> lines) {
for (String line : lines) { for (String line : lines) {
@@ -54,14 +54,14 @@ public class InfluxDBUtil {
} }
// ========================= // =========================
// ✅ 单条写入 // 单条写入
// ========================= // =========================
public void write(String line) { public void write(String line) {
writeApi.writeRecord(bucket, org, WritePrecision.MS, line); writeApi.writeRecord(bucket, org, WritePrecision.MS, line);
} }
// ========================= // =========================
// ✅ 查询(返回原始结果) // 查询(返回原始结果)
// ========================= // =========================
public List<FluxTable> query(String flux) { public List<FluxTable> query(String flux) {
QueryApi queryApi = client.getQueryApi(); QueryApi queryApi = client.getQueryApi();
@@ -69,7 +69,7 @@ public class InfluxDBUtil {
} }
// ========================= // =========================
// ✅ 查询(转List<Map>) // 查询(转List<Map>)
// ========================= // =========================
public List<String> queryValues(String flux) { public List<String> queryValues(String flux) {
List<String> resultList = new ArrayList<>(); List<String> resultList = new ArrayList<>();
@@ -86,14 +86,14 @@ public class InfluxDBUtil {
} }
// ========================= // =========================
// ✅ 手动flush(重要) // 手动flush(重要)
// ========================= // =========================
public void flush() { public void flush() {
writeApi.flush(); writeApi.flush();
} }
// ========================= // =========================
// ✅ 关闭资源(必须) // 关闭资源(必须)
// ========================= // =========================
public void close() { public void close() {
try { try {

View File

@@ -6,6 +6,7 @@ import com.maibu.influxdb.inter.InfluxTime;
import com.maibu.influxdb.inter.InfluxMeasurement; import com.maibu.influxdb.inter.InfluxMeasurement;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.StringJoiner; import java.util.StringJoiner;
@@ -13,6 +14,7 @@ import java.util.StringJoiner;
public class InfluxSqlBuilder { public class InfluxSqlBuilder {
/** /**
* 插入语句拼接 * 插入语句拼接
*
* @param obj * @param obj
* @return * @return
*/ */
@@ -41,7 +43,8 @@ public class InfluxSqlBuilder {
field.setAccessible(true); field.setAccessible(true);
Object value = field.get(obj); Object value = field.get(obj);
if (value == null) continue; if (value == null)
continue;
String key = escapeKey(field.getName()); String key = escapeKey(field.getName());
@@ -89,49 +92,130 @@ public class InfluxSqlBuilder {
} }
} }
// ========================= // =========================
// ✅ 构建 Flux 查询 // ✅ 构建 Flux 查询
// ========================= // =========================
// public static String buildQuery(
// String bucket,
// String measurement,
// long startHoursAgo,
// Map<String, String> tagFilters,
// String field) {
// StringBuilder flux = new StringBuilder();
// flux.append("from(bucket:\"").append(bucket).append("\")")
// .append(" |> range(start: -").append(startHoursAgo).append("h)")
// .append(" |> filter(fn: (r) => r._measurement == \"")
// .append(measurement).append("\")");
// // tag过滤
// if (tagFilters != null && !tagFilters.isEmpty()) {
// for (Map.Entry<String, String> entry : tagFilters.entrySet()) {
// flux.append(" |> filter(fn: (r) => r.")
// .append(entry.getKey())
// .append(" == \"")
// .append(entry.getValue())
// .append("\")");
// }
// }
// // field过滤
// if (field != null) {
// flux.append(" |> filter(fn: (r) => r._field == \"")
// .append(field)
// .append("\")");
// }
// // 按时间倒序
// flux.append(" |> sort(columns:[\"_time\"], desc:true)");
// return flux.toString();
// }
public static String buildQuery( public static String buildQuery(
String bucket, String bucket,
String measurement, String measurement,
long startSecondsAgo, long startHoursAgo,
Map<String, String> tagFilters, Map<String, ? extends Collection<String>> tagFilters,
String field String field,
) { boolean latestPerDevice,
String groupColumn) {
StringBuilder flux = new StringBuilder(); StringBuilder flux = new StringBuilder();
flux.append("from(bucket:\"").append(bucket).append("\")") flux.append("from(bucket:\"")
.append(" |> range(start: -").append(startSecondsAgo).append("h)") .append(bucket)
.append("\")")
.append(" |> range(start: -")
.append(startHoursAgo)
.append("h)")
.append(" |> filter(fn: (r) => r._measurement == \"") .append(" |> filter(fn: (r) => r._measurement == \"")
.append(measurement).append("\")"); .append(measurement)
.append("\")");
// tag过滤 // Tag过滤
if (tagFilters != null && !tagFilters.isEmpty()) { if (tagFilters != null && !tagFilters.isEmpty()) {
for (Map.Entry<String, String> entry : tagFilters.entrySet()) {
flux.append(" |> filter(fn: (r) => r.") for (Map.Entry<String, ? extends Collection<String>> entry : tagFilters.entrySet()) {
.append(entry.getKey())
.append(" == \"") Collection<String> values = entry.getValue();
.append(entry.getValue())
.append("\")"); if (values == null || values.isEmpty()) {
continue;
}
flux.append(" |> filter(fn: (r) => ");
boolean first = true;
for (String value : values) {
if (!first) {
flux.append(" or ");
}
flux.append("r.")
.append(entry.getKey())
.append(" == \"")
.append(value)
.append("\"");
first = false;
}
flux.append(")");
} }
} }
// field过滤 // Field过滤
if (field != null) { if (field != null && !field.isEmpty()) {
flux.append(" |> filter(fn: (r) => r._field == \"") flux.append(" |> filter(fn: (r) => r._field == \"")
.append(field) .append(field)
.append("\")"); .append("\")");
} }
// 每个设备最新一条
if (latestPerDevice) {
if (groupColumn == null || groupColumn.isEmpty()) {
groupColumn = "deviceId";
}
flux.append(" |> group(columns:[\"")
.append(groupColumn)
.append("\"])")
.append(" |> last()");
} else {
flux.append(" |> sort(columns:[\"_time\"], desc:true)");
}
return flux.toString(); return flux.toString();
} }
/** /**
* 类的某些属性转换成map * 类的某些属性转换成map
*
* @param obj * @param obj
* @param functions * @param functions
* @return * @return
@@ -139,8 +223,7 @@ public class InfluxSqlBuilder {
*/ */
public static <T> Map<String, String> buildTagMap( public static <T> Map<String, String> buildTagMap(
T obj, T obj,
SFunction<T, ?>... functions SFunction<T, ?>... functions) {
) {
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
try { try {
@@ -190,5 +273,4 @@ public class InfluxSqlBuilder {
return value.toString(); // double/float return value.toString(); // double/float
} }
} }

View File

@@ -4,6 +4,8 @@ import java.beans.Introspector;
import java.lang.invoke.SerializedLambda; import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import com.maibu.influxdb.inter.InfluxMeasurement;
public class LambdaUtils { public class LambdaUtils {
public static <T> String getFieldName(SFunction<T, ?> fn) { public static <T> String getFieldName(SFunction<T, ?> fn) {
@@ -26,4 +28,16 @@ public class LambdaUtils {
throw new RuntimeException("解析字段失败", e); throw new RuntimeException("解析字段失败", e);
} }
} }
public static String getMeasurement(Class<?> clazz) {
InfluxMeasurement annotation = clazz.getAnnotation(InfluxMeasurement.class);
if (annotation == null) {
throw new IllegalArgumentException(
clazz.getName() + " 未配置 @InfluxMeasurement");
}
return annotation.value();
}
} }

View File

@@ -1,30 +1,26 @@
package com.maibu.memory; package com.maibu.memory;
import com.maibu.core.business.Device;
import com.maibu.core.business.IoTCommonDevice;
import com.maibu.core.business.IoTCommonProduct;
import com.maibu.core.business.uav.IotUAVDevice;
import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.core.business.Device;
import com.maibu.core.business.IoTCommonDevice;
import com.maibu.core.business.IoTCommonProduct;
import com.maibu.influxdb.util.InfluxDBUtil;
import com.maibu.mqtt.MqttClientUtil;
import lombok.Data;
@Component @Component
@Data @Data
public class GlobalMemory { public class GlobalMemory {
// orgId - siteId - deviceId
// public static ConcurrentHashMap<Long, IoTCommonDevice> unRegisterCommonDeviceMap = new ConcurrentHashMap<>();
//
// public static ConcurrentHashMap<Long, Device> unRegisterDeviceMap = new ConcurrentHashMap<>();
// orgId - siteId - deviceId // orgId - siteId - deviceId
public static ConcurrentHashMap<String, IoTCommonDevice> unRegisterCommonDeviceMap = new ConcurrentHashMap<>(); public static ConcurrentHashMap<String, IoTCommonDevice> unRegisterCommonDeviceMap = new ConcurrentHashMap<>();
@@ -35,6 +31,9 @@ public class GlobalMemory {
public static ConcurrentHashMap<Long, IoTCommonProduct> productMap = new ConcurrentHashMap<>(); public static ConcurrentHashMap<Long, IoTCommonProduct> productMap = new ConcurrentHashMap<>();
public static InfluxDBUtil influxDBUtil;
public static MqttClientUtil mqttClientUtil;
public static SiteMemory getSiteMemory(Long orgId, Long siteId) { public static SiteMemory getSiteMemory(Long orgId, Long siteId) {
if (orgId != null && siteId != null) { if (orgId != null && siteId != null) {
@@ -56,11 +55,12 @@ public class GlobalMemory {
/** /**
* 新增场站内存 * 新增场站内存
*
* @param orgId * @param orgId
* @param siteId * @param siteId
* @param siteMemory * @param siteMemory
*/ */
//todo 初始化 // todo 初始化
public static void addSiteMemory(Long orgId, Long siteId, SiteMemory siteMemory) { public static void addSiteMemory(Long orgId, Long siteId, SiteMemory siteMemory) {
if (orgId != null && siteId != null) { if (orgId != null && siteId != null) {
@@ -75,6 +75,7 @@ public class GlobalMemory {
/** /**
* 删除 * 删除
*
* @param orgId * @param orgId
* @param siteId * @param siteId
*/ */

View File

@@ -1,22 +1,23 @@
package com.maibu.memory; package com.maibu.memory;
import cn.hutool.core.util.ObjectUtil; import java.util.ArrayList;
import com.maibu.core.business.*; import java.util.List;
import com.maibu.core.business.device.Connector; import java.util.Objects;
import com.maibu.core.business.device.NettyDevice; import java.util.concurrent.ConcurrentHashMap;
import com.maibu.core.enums.ConnectorStatus;
import com.maibu.core.enums.ConnectorType;
import io.netty.channel.Channel;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.*; import com.maibu.core.business.Device;
import java.util.concurrent.ConcurrentHashMap; import com.maibu.core.business.DevicePlan;
import java.util.stream.Collectors; import com.maibu.core.business.DevicePlanTask;
import com.maibu.core.business.ErrorIdentificationStandard;
import com.maibu.core.business.IoTCommonDevice;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Component @Component
@Data @Data

View File

@@ -0,0 +1,135 @@
package com.maibu.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
@Slf4j
public class MqttClientUtil {
private final MqttClient client;
public MqttClientUtil(
String broker,
String clientId,
String username,
String password) throws MqttException {
this.client = new MqttClient(
broker,
clientId,
new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
options.setAutomaticReconnect(true);
options.setConnectionTimeout(10);
options.setKeepAliveInterval(60);
if (username != null) {
options.setUserName(username);
}
if (password != null) {
options.setPassword(password.toCharArray());
}
client.connect(options);
log.info("MQTT连接成功: {}", broker);
}
/**
* 订阅
*/
public void subscribe(String topic) throws MqttException {
client.subscribe(topic);
log.info("订阅成功: {}", topic);
}
/**
* 订阅并监听
*/
public void subscribe(
String topic,
IMqttMessageListener listener)
throws MqttException {
client.subscribe(topic, listener);
log.info("订阅成功: {}", topic);
}
/**
* 发布消息
*/
public void publish(
String topic,
String payload)
throws MqttException {
publish(topic, payload, 1);
}
/**
* 发布消息
*/
public void publish(
String topic,
String payload,
int qos)
throws MqttException {
MqttMessage message =
new MqttMessage(payload.getBytes());
message.setQos(qos);
client.publish(topic, message);
}
/**
* 设置全局监听器
*/
public void setCallback() {
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
log.error("MQTT断开连接", cause);
}
@Override
public void messageArrived(
String topic,
MqttMessage message) {
log.info(
"收到消息 topic={} payload={}",
topic,
new String(message.getPayload()));
}
@Override
public void deliveryComplete(
IMqttDeliveryToken token) {
log.debug("消息发送成功");
}
});
}
public boolean isConnected() {
return client.isConnected();
}
public void disconnect() throws MqttException {
client.disconnect();
client.close();
}
}

View File

@@ -0,0 +1,10 @@
package com.maibu.mqtt;
public class MqttTopic {
public static final String DEVICE_STATUS_TOPIC = "device/%s/realTimeMessage"; // 实时消息
public static final String DEVICE_TASK_STATUS_TOPIC = "task/%s/status"; // 任务状态 完成、取消、暂停、继续
public static final String DEVICE_TASK_ARRIVE_TOPIC = "task/%s/arrive"; // 任务到达
}

View File

@@ -1,5 +1,8 @@
package com.maibu.dto; package com.maibu.dto;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.maibu.core.domain.BaseEntity; import com.maibu.core.domain.BaseEntity;
import com.maibu.core.enums.DeviceTaskStaus; import com.maibu.core.enums.DeviceTaskStaus;
@@ -11,8 +14,10 @@ import lombok.EqualsAndHashCode;
public class DeviceTaskQueryDTO extends BaseEntity { public class DeviceTaskQueryDTO extends BaseEntity {
private Long userId; private Long userId;
// private LocalDateTime startTime; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
// private LocalDateTime endTime; private LocalDateTime startTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime endTime;
private DeviceTaskStaus taskStaus; private DeviceTaskStaus taskStaus;
private String planName; private String planName;
private Long planId; private Long planId;

View File

@@ -4,6 +4,7 @@ import lombok.Data;
import java.util.List; import java.util.List;
import com.maibu.core.business.device.DeviceStatusDetail;
import com.maibu.core.enums.MesType; import com.maibu.core.enums.MesType;
@Data @Data

View File

@@ -1,20 +1,13 @@
package com.maibu.init; package com.maibu.init;
import com.maibu.constant.FastBeeConstant; import java.io.IOException;
import com.maibu.core.business.DevicePlan; import java.util.Arrays;
import com.maibu.core.business.DevicePlanTask; import java.util.List;
import com.maibu.core.domain.entity.SysSite; import java.util.concurrent.Executor;
import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.mapper.DevicePlanMapper; import javax.annotation.Resource;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.SysSiteMapper; import org.eclipse.paho.client.mqttv3.MqttException;
import com.maibu.mapper.SysUserClientMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import com.maibu.mybatis.LambdaQueryWrapperX;
import com.maibu.service.DevicePlanTaskMonitorService;
import com.maibu.service.DeviceThreadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
@@ -22,19 +15,29 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.annotation.Resource; import com.maibu.constant.FastBeeConstant;
import java.io.IOException; import com.maibu.core.business.DevicePlan;
import java.util.Arrays; import com.maibu.core.business.DevicePlanTask;
import java.util.List; import com.maibu.core.domain.entity.SysSite;
import java.util.concurrent.Executor; import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.influxdb.util.InfluxDBUtil;
import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.SysSiteMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.memory.SiteMemory;
import com.maibu.mqtt.MqttClientUtil;
import com.maibu.mybatis.LambdaQueryWrapperX;
import com.maibu.service.DevicePlanTaskMonitorService;
import com.maibu.service.DeviceThreadService;
import org.springframework.beans.factory.annotation.Value;
import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@Component @Component
@Order(20) @Order(20)
public class InitThread implements ApplicationRunner { public class InitThread implements ApplicationRunner {
@Resource(name = FastBeeConstant.TASK.DEVICE_ERROR_MONITOR) @Resource(name = FastBeeConstant.TASK.DEVICE_ERROR_MONITOR)
private Executor deviceErrorMonitorExecutor; private Executor deviceErrorMonitorExecutor;
@@ -56,15 +59,48 @@ public class InitThread implements ApplicationRunner {
@Autowired @Autowired
private SysSiteMapper sysSiteMapper; private SysSiteMapper sysSiteMapper;
@Value("${influxdb.url}")
private String influxDBUrl;
@Value("${influxdb.username}")
private String influxDBUsername;
@Value("${influxdb.password}")
private String influxDBPassword;
@Value("${influxdb.bucket}")
private String influxDBBucket;
@Value("${influxdb.org}")
private String influxDBOrg;
@Value("${influxdb.token}")
private String influxDBToken;
@Value("${mqtt.username}")
private String mqttUsername;
@Value("${mqtt.password}")
private String mqttPassword;
@Value("${mqtt.host-url}")
private String mqttHostUrl;
@Value("${mqtt.client-id}")
private String mqttClientId;
@Override @Override
public void run(ApplicationArguments args) { public void run(ApplicationArguments args) throws MqttException {
recoverMemory(); recoverMemory();
init(); init();
} }
private void init() throws MqttException {
private void init() { // 初始化InfluxDBUtil
//设备错误监听线程 GlobalMemory.influxDBUtil = new InfluxDBUtil(influxDBUrl, influxDBToken, influxDBOrg, influxDBBucket);
// 初始化MqttClientUtil
GlobalMemory.mqttClientUtil = new MqttClientUtil(mqttHostUrl, mqttClientId, mqttUsername, mqttPassword);
// 设备错误监听线程
deviceErrorMonitorExecutor.execute(() -> { deviceErrorMonitorExecutor.execute(() -> {
try { try {
deviceThreadService.deviceErrorMonitor(); deviceThreadService.deviceErrorMonitor();
@@ -72,14 +108,14 @@ public class InitThread implements ApplicationRunner {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}); });
//设备任务处理线程 // 设备任务处理线程
deviceTaskHandlerExecutor.execute(() -> { deviceTaskHandlerExecutor.execute(() -> {
//任务下发 // 任务下发
try { try {
devicePlanTaskMonitorService.generatePlanTask(); devicePlanTaskMonitorService.generatePlanTask();
//执行准备队列 // 执行准备队列
devicePlanTaskMonitorService.doLoop(); devicePlanTaskMonitorService.doLoop();
//执行任务 // 执行任务
devicePlanTaskMonitorService.doExecute(); devicePlanTaskMonitorService.doExecute();
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@@ -91,9 +127,9 @@ public class InitThread implements ApplicationRunner {
* 恢复内存 * 恢复内存
*/ */
public void recoverMemory() { public void recoverMemory() {
//todo 启动时清除当前登录记录 // todo 启动时清除当前登录记录
// System.out.println("开始清除登录信息"); // System.out.println("开始清除登录信息");
// sysUserClientMapper.clearDeviceName(); // sysUserClientMapper.clearDeviceName();
List<SysSite> siteList = sysSiteMapper.selectList(); List<SysSite> siteList = sysSiteMapper.selectList();
if (!CollectionUtils.isEmpty(siteList)) { if (!CollectionUtils.isEmpty(siteList)) {
siteList.forEach(x -> { siteList.forEach(x -> {
@@ -108,7 +144,8 @@ public class InitThread implements ApplicationRunner {
} }
// 未执行完的重复计划 // 未执行完的重复计划
LambdaQueryWrapperX<DevicePlan> query = new LambdaQueryWrapperX<>(); LambdaQueryWrapperX<DevicePlan> query = new LambdaQueryWrapperX<>();
List<String> list = Arrays.asList(DeviceTaskStaus.NEW.getCode(), DeviceTaskStaus.EXECUTING.getCode(), DeviceTaskStaus.PAUSE.getCode()); List<String> list = Arrays.asList(DeviceTaskStaus.NEW.getCode(), DeviceTaskStaus.EXECUTING.getCode(),
DeviceTaskStaus.PAUSE.getCode());
query.in(DevicePlan::getTaskStaus, list); query.in(DevicePlan::getTaskStaus, list);
List<DevicePlan> devicePlanList = devicePlanMapper.selectList(query); List<DevicePlan> devicePlanList = devicePlanMapper.selectList(query);
if (!CollectionUtils.isEmpty(devicePlanList)) { if (!CollectionUtils.isEmpty(devicePlanList)) {
@@ -116,7 +153,7 @@ public class InitThread implements ApplicationRunner {
Long orgId = x.getOrgId(); Long orgId = x.getOrgId();
Long siteId = x.getSiteId(); Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId); SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if(siteMemory!=null){ if (siteMemory != null) {
siteMemory.addDevicePlan(x); siteMemory.addDevicePlan(x);
} }
}); });
@@ -131,7 +168,7 @@ public class InitThread implements ApplicationRunner {
Long orgId = x.getOrgId(); Long orgId = x.getOrgId();
Long siteId = x.getSiteId(); Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId); SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if(siteMemory!=null){ if (siteMemory != null) {
siteMemory.addDevicePlanPrepare(x); siteMemory.addDevicePlanPrepare(x);
} }
}); });
@@ -145,7 +182,7 @@ public class InitThread implements ApplicationRunner {
Long orgId = x.getOrgId(); Long orgId = x.getOrgId();
Long siteId = x.getSiteId(); Long siteId = x.getSiteId();
SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId); SiteMemory siteMemory = GlobalMemory.getSiteMemory(orgId, siteId);
if(siteMemory!=null){ if (siteMemory != null) {
siteMemory.addDevicePlanExecute(x); siteMemory.addDevicePlanExecute(x);
} }
}); });

View File

@@ -1,102 +1,333 @@
package com.maibu.netty.handler; package com.maibu.netty.handler;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.maibu.common.CommandConstant; import com.maibu.common.CommandConstant;
import com.maibu.common.NettyCacheKey; import com.maibu.common.NettyCacheKey;
import com.maibu.core.business.DeviceRunStatistics; import com.maibu.core.business.DeviceRunStatistics;
import com.maibu.core.business.DeviceRunningStatusHistory; import com.maibu.core.business.DeviceRunningStatusHistory;
import com.maibu.core.business.DeviceStatusRecordDTO; import com.maibu.core.business.DeviceStatusRecordDTO;
import com.maibu.core.redis.RedisCache; import com.maibu.core.business.device.DeviceStatusDetail;
import com.maibu.core.business.device.NettyDevice; import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.inter.WebsocketMesDispather;
import com.maibu.core.enums.MesType;
import com.maibu.core.redis.RedisCache;
import com.maibu.dto.WebStatusMessageDTO;
import com.maibu.influxdb.MowerRealTimeData;
import com.maibu.influxdb.util.InfluxSqlBuilder;
import com.maibu.manager.DeviceSessionManager; import com.maibu.manager.DeviceSessionManager;
import com.maibu.memory.GlobalMemory;
import com.maibu.mqtt.MqttTopic;
import com.maibu.utils.json.JsonUtils;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Component @Component
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> { public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
private static final Logger logger = LoggerFactory.getLogger(DataToDataBaseHandler.class);
@Autowired @Autowired
private DeviceSessionManager deviceSessionManager; private DeviceSessionManager deviceSessionManager;
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
private static final Long interval = 5000L; @Autowired
private WebsocketMesDispather websocketMesDispather;
private static final Long interval = 5000L;
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel(); try {
String deviceID = deviceSessionManager.getDeviceIdByChannel(channel); Channel channel = ctx.channel();
if (StringUtils.isEmpty(deviceID)) return; String deviceID = deviceSessionManager.getDeviceIdByChannel(channel);
if (StringUtils.isEmpty(deviceID))
return;
byte[] bytes = Hex.decodeHex(msg.toCharArray()); byte[] bytes = Hex.decodeHex(msg.toCharArray());
if (bytes[2] == CommandConstant.status) { if (bytes[2] == CommandConstant.status) {
String key = NettyCacheKey.deviceRunningStatusKey + deviceID; String key = NettyCacheKey.deviceRunningStatusKey + deviceID;
DeviceStatusRecordDTO recordDTO = redisCache.getCacheObject(key); DeviceStatusRecordDTO recordDTO = redisCache.getCacheObject(key);
boolean record = false; boolean record = false;
List<DeviceRunningStatusHistory> histories; List<DeviceRunningStatusHistory> histories;
if (recordDTO == null) { if (recordDTO == null) {
recordDTO = new DeviceStatusRecordDTO(); recordDTO = new DeviceStatusRecordDTO();
histories = new ArrayList<>();
record = true;
} else {
long lastRecordTime = recordDTO.getLastRecordTime();
histories = recordDTO.getHistories();
if (System.currentTimeMillis() - lastRecordTime >= interval) {
record = true;
}
}
if (record) {
String deviceStatus = new String(bytes, 2, bytes.length - 4, StandardCharsets.UTF_8).trim();
String[] split = deviceStatus.split(",");
DeviceRunningStatusHistory deviceRunningStatus = getDeviceRunningStatusHistory(deviceID, split);
if (histories == null) {
histories = new ArrayList<>(); histories = new ArrayList<>();
record = true;
} else {
long lastRecordTime = recordDTO.getLastRecordTime();
histories = recordDTO.getHistories();
if (System.currentTimeMillis() - lastRecordTime >= interval) {
record = true;
}
} }
histories.add(deviceRunningStatus); if (record) {
recordDTO.setHistories(histories); // 推送websocket实时消息给前端 todo mqtt推送
recordDTO.setLastRecordTime(System.currentTimeMillis());
redisCache.setCacheObject(key, recordDTO); String deviceStatus = new String(bytes, 2, bytes.length - 4, StandardCharsets.UTF_8).trim();
// 判断整点 记录到数据库 String[] split = deviceStatus.split(",");
// deviceStatusHistoryMapper.insert(deviceRunningStatus); WebStatusMessageDTO dto = createWebDeviceStatusMessage(split);
NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceID); try {
String workArea = deviceRunningStatus.getWorkingArea(); GlobalMemory.mqttClientUtil.publish(
DeviceRunStatistics latestStatus; String.format(MqttTopic.DEVICE_STATUS_TOPIC, deviceID),
if(nettyDevice.getLatestStatus() == null){ JsonUtils.toJsonString(dto));
latestStatus = new DeviceRunStatistics(); } catch (MqttException e) {
latestStatus.setStartTime(LocalDateTime.now()); logger.error("发送实时状态数据错误: {}", e.getMessage());
latestStatus.setDeviceId(deviceID); }
}else { List<NettyDevice> controlMasters = deviceSessionManager
latestStatus = nettyDevice.getLatestStatus(); .getAllSlaveControl(deviceID);
// 使用Duration.between计算两个时间点之间的持续时间 if (!CollectionUtils.isEmpty(controlMasters)) {
Duration duration = Duration.between(latestStatus.getStartTime(), LocalDateTime.now()); controlMasters.forEach(x -> {
long minutes = duration.toMinutes(); websocketMesDispather.dispather(x.getConnectorId(), JsonUtils.toJsonString(dto));
latestStatus.setTime(minutes); });
}
DeviceRunningStatusHistory deviceRunningStatus = getDeviceRunningStatusHistory(deviceID, split);
if (histories == null) {
histories = new ArrayList<>();
}
histories.add(deviceRunningStatus);
recordDTO.setHistories(histories);
recordDTO.setLastRecordTime(System.currentTimeMillis());
redisCache.setCacheObject(key, recordDTO);
// todo 记录到InfluxDB 是否删除redis中的记录 目前先保留最近一次的记录在redis中
MowerRealTimeData data = processInfluxData(deviceID, split);
String line = InfluxSqlBuilder.buildLine(data);
GlobalMemory.influxDBUtil.write(line);
// 判断整点 记录到数据库
// deviceStatusHistoryMapper.insert(deviceRunningStatus);
NettyDevice nettyDevice = deviceSessionManager.getDevice(deviceID);
String workArea = deviceRunningStatus.getWorkingArea();
DeviceRunStatistics latestStatus;
if (nettyDevice.getLatestStatus() == null) {
latestStatus = new DeviceRunStatistics();
latestStatus.setStartTime(LocalDateTime.now());
latestStatus.setDeviceId(deviceID);
} else {
latestStatus = nettyDevice.getLatestStatus();
// 使用Duration.between计算两个时间点之间的持续时间
Duration duration = Duration.between(latestStatus.getStartTime(), LocalDateTime.now());
long minutes = duration.toMinutes();
latestStatus.setTime(minutes);
}
latestStatus.setWorkArea(Double.valueOf(workArea));
nettyDevice.setLatestStatus(latestStatus);
} }
latestStatus.setWorkArea(Double.valueOf(workArea));
nettyDevice.setLatestStatus(latestStatus);
} }
// else{ ctx.fireChannelRead(msg);
// System.out.println(false); } catch (Exception e) {
// } logger.error("处理数据异常: {}", e.getMessage());
} }
ctx.fireChannelRead(msg); }
public WebStatusMessageDTO createWebDeviceStatusMessage(String[] split) {
WebStatusMessageDTO webStatusMessageDTO = new WebStatusMessageDTO();
List<DeviceStatusDetail> transferData = transferStatusData(split);
webStatusMessageDTO.setData(transferData);
webStatusMessageDTO.setType(MesType.deviceInfo);
return webStatusMessageDTO;
}
private List<DeviceStatusDetail> transferStatusData(String[] split) {
List<DeviceStatusDetail> transferData = new ArrayList<>();
DeviceStatusDetail detail0 = new DeviceStatusDetail();
detail0.setName("voltage");
detail0.setValue(split[0]);
detail0.setUnit("");
transferData.add(detail0);
DeviceStatusDetail detail1 = new DeviceStatusDetail();
detail1.setName("leftTargetSpeed");
detail1.setValue(split[1]);
detail1.setUnit("");
transferData.add(detail1);
DeviceStatusDetail detail2 = new DeviceStatusDetail();
detail2.setName("rightTargetSpeed");
detail2.setValue(split[2]);
detail2.setUnit("");
transferData.add(detail2);
DeviceStatusDetail detail3 = new DeviceStatusDetail();
detail3.setName("leftMeasureSpeed");
detail3.setValue(split[3]);
detail3.setUnit("");
transferData.add(detail3);
DeviceStatusDetail detail4 = new DeviceStatusDetail();
detail4.setName("rightMeasureSpeed");
detail4.setValue(split[4]);
detail4.setUnit("");
transferData.add(detail4);
DeviceStatusDetail detail5 = new DeviceStatusDetail();
detail5.setName("leftCurrent");
detail5.setValue(split[5]);
detail5.setUnit("");
transferData.add(detail5);
DeviceStatusDetail detail6 = new DeviceStatusDetail();
detail6.setName("rightCurrent");
detail6.setValue(split[6]);
detail6.setUnit("");
transferData.add(detail6);
DeviceStatusDetail detail7 = new DeviceStatusDetail();
detail7.setName("leftMotorTemp");
detail7.setValue(split[7]);
detail7.setUnit("");
transferData.add(detail7);
DeviceStatusDetail detail8 = new DeviceStatusDetail();
detail8.setName("rightMotorTemp");
detail8.setValue(split[8]);
detail8.setUnit("");
transferData.add(detail8);
DeviceStatusDetail detail9 = new DeviceStatusDetail();
detail9.setName("chipTemp");
detail9.setValue(split[9]);
detail9.setUnit("");
transferData.add(detail9);
DeviceStatusDetail detail10 = new DeviceStatusDetail();
detail10.setName("yaw");
detail10.setValue(split[10]);
detail10.setUnit("");
transferData.add(detail10);
DeviceStatusDetail detail11 = new DeviceStatusDetail();
detail11.setName("pitch");
detail11.setValue(split[11]);
detail11.setUnit("");
transferData.add(detail11);
DeviceStatusDetail detail12 = new DeviceStatusDetail();
detail12.setName("roll");
detail12.setValue(split[12]);
detail12.setUnit("");
transferData.add(detail12);
DeviceStatusDetail detail13 = new DeviceStatusDetail();
detail13.setName("satelliteCnt");
detail13.setValue(split[13]);
detail13.setUnit("");
transferData.add(detail13);
DeviceStatusDetail detail14 = new DeviceStatusDetail();
detail14.setName("qual");
detail14.setValue(split[14]);
detail14.setUnit("");
transferData.add(detail14);
DeviceStatusDetail detail15 = new DeviceStatusDetail();
detail15.setName("headingStatus");
detail15.setValue(split[15]);
detail15.setUnit("");
transferData.add(detail15);
DeviceStatusDetail detail16 = new DeviceStatusDetail();
detail16.setName("latitude");
detail16.setValue(split[16]);
detail16.setUnit("");
transferData.add(detail16);
DeviceStatusDetail detail17 = new DeviceStatusDetail();
detail17.setName("longitude");
detail17.setValue(split[17]);
detail17.setUnit("");
transferData.add(detail17);
// 18 时间暂未给值
DeviceStatusDetail detail19 = new DeviceStatusDetail();
detail19.setName("cuttingSpeed");
detail19.setValue(split[19]);
detail19.setUnit("");
transferData.add(detail19);
DeviceStatusDetail detail20 = new DeviceStatusDetail();
detail20.setName("controlMode");
detail20.setValue(split[20]);
detail20.setUnit("");
transferData.add(detail20);
DeviceStatusDetail detail21 = new DeviceStatusDetail();
detail21.setName("battery");
detail21.setValue(split[21]);
detail21.setUnit("");
transferData.add(detail21);
DeviceStatusDetail detail22 = new DeviceStatusDetail();
detail22.setName("workingArea");
detail22.setValue(split[22]);
detail22.setUnit("");
transferData.add(detail22);
DeviceStatusDetail detail23 = new DeviceStatusDetail();
detail23.setName("obstacleSign");
detail23.setValue(split[23]);
detail23.setUnit("");
transferData.add(detail23);
return transferData;
}
private MowerRealTimeData processInfluxData(String deviceID, String[] split) {
MowerRealTimeData data = new MowerRealTimeData();
data.setDeviceId(deviceID);
data.setVoltage(split[0]);
data.setLeftTargetSpeed(split[1]);
data.setRightTargetSpeed(split[2]);
data.setLeftMeasureSpeed(split[3]);
data.setRightMeasureSpeed(split[4]);
data.setLeftCurrent(split[5]);
data.setRightCurrent(split[6]);
data.setLeftMotorTemp(split[7]);
data.setRightMotorTemp(split[8]);
data.setChipTemp(split[9]);
data.setYaw(split[10]);
data.setPitch(split[11]);
data.setRoll(split[12]);
data.setSatelliteCnt(split[13]);
data.setQual(split[14]);
data.setHeadingStatus(split[15]);
data.setLatitude(split[16]);
data.setLongitude(split[17]);
// 18 时间暂未给值
data.setCuttingSpeed(split[19]);
data.setControlMode(split[20]);
data.setBattery(split[21]);
data.setWorkingArea(split[22]);
data.setObstacleSign(split[23]);
data.setTime(Instant.now());
return data;
} }
private DeviceRunningStatusHistory getDeviceRunningStatusHistory(String deviceID, String[] split) { private DeviceRunningStatusHistory getDeviceRunningStatusHistory(String deviceID, String[] split) {
@@ -121,7 +352,7 @@ public class DataToDataBaseHandler extends SimpleChannelInboundHandler<String> {
deviceRunningStatus.setLatitude(split[16]); deviceRunningStatus.setLatitude(split[16]);
deviceRunningStatus.setLongitude(split[17]); deviceRunningStatus.setLongitude(split[17]);
//18 时间暂未给值 // 18 时间暂未给值
deviceRunningStatus.setCuttingSpeed(split[19]); deviceRunningStatus.setCuttingSpeed(split[19]);
deviceRunningStatus.setControlMode(split[20]); deviceRunningStatus.setControlMode(split[20]);

View File

@@ -4,17 +4,16 @@ import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -22,9 +21,7 @@ import com.maibu.common.CommandConstant;
import com.maibu.common.Constant; import com.maibu.common.Constant;
import com.maibu.core.business.Device; import com.maibu.core.business.Device;
import com.maibu.core.business.device.NettyDevice; import com.maibu.core.business.device.NettyDevice;
import com.maibu.core.business.inter.DeviceWebSocketInterace;
import com.maibu.core.business.inter.WebsocketMesDispather; import com.maibu.core.business.inter.WebsocketMesDispather;
import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.domain.entity.SysUser; import com.maibu.core.domain.entity.SysUser;
import com.maibu.core.domain.entity.UserClient; import com.maibu.core.domain.entity.UserClient;
import com.maibu.core.enums.CommandRequestType; import com.maibu.core.enums.CommandRequestType;
@@ -39,10 +36,11 @@ import com.maibu.dto.DeviceLoginResponseDTO;
import com.maibu.dto.DeviceRequestDTO; import com.maibu.dto.DeviceRequestDTO;
import com.maibu.dto.DeviceRespondDTO; import com.maibu.dto.DeviceRespondDTO;
import com.maibu.dto.DeviceStatusChangeDTO; import com.maibu.dto.DeviceStatusChangeDTO;
import com.maibu.dto.DeviceTaskReportDTO;
import com.maibu.dto.DeviceTaskStatusMessageDTO; import com.maibu.dto.DeviceTaskStatusMessageDTO;
import com.maibu.manager.DeviceSessionManager; import com.maibu.manager.DeviceSessionManager;
import com.maibu.mapper.DeviceRunStatisticsMapper; import com.maibu.mapper.DeviceRunStatisticsMapper;
import com.maibu.memory.GlobalMemory;
import com.maibu.mqtt.MqttTopic;
import com.maibu.service.IDeviceService; import com.maibu.service.IDeviceService;
import com.maibu.service.ISysUserClientService; import com.maibu.service.ISysUserClientService;
import com.maibu.service.ISysUserService; import com.maibu.service.ISysUserService;
@@ -363,9 +361,13 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
changeDTO.setStatus(DeviceTaskStaus.FINISH.toString()); changeDTO.setStatus(DeviceTaskStaus.FINISH.toString());
changeDTO.setType(MesType.device_task_change); changeDTO.setType(MesType.device_task_change);
changeDTO.setTaskId(taskId); changeDTO.setTaskId(taskId);
// ByteBuf buf = ctx.alloc().buffer();
// ByteBuf buf = Unpooled.buffer(); try {
// CommandUtils.buildCommand(buf, changeDTO, CommandConstant.interaction); GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_TASK_STATUS_TOPIC, taskId),
JsonUtils.toJsonString(changeDTO));
} catch (MqttException e) {
logger.error("任务完成状态推送失败 task:{},device:{}error:{}", taskId, deviceId, e.getMessage());
}
List<NettyDevice> controlMasters = sessionManager List<NettyDevice> controlMasters = sessionManager
.getAllSlaveControl(deviceId); .getAllSlaveControl(deviceId);
if (!CollectionUtils.isEmpty(controlMasters)) { if (!CollectionUtils.isEmpty(controlMasters)) {
@@ -373,14 +375,8 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
websocketMesDispather.dispather(x.getConnectorId(), websocketMesDispather.dispather(x.getConnectorId(),
JsonUtils.toJsonString(changeDTO)); JsonUtils.toJsonString(changeDTO));
// String content = buf.toString(CharsetUtil.UTF_8); // String content = buf.toString(CharsetUtil.UTF_8);
logger.info("任务完成状态推送 task:{},device:{},content:{}", taskId, deviceId, logger.info("任务完成状态推送 task:{},device:{},content:{}", taskId, deviceId,
JsonUtils.toJsonString(changeDTO)); JsonUtils.toJsonString(changeDTO));
// if (x.getChannel() != null && x.getChannel().isActive()) {
// x.getChannel().writeAndFlush(buf);
// String content = buf.toString(CharsetUtil.UTF_8);
// logger.info("任务完成状态推送 task:{},device:{},content:{}", taskId, deviceId,
// content);
// }
}); });
} }
} }
@@ -393,9 +389,14 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
reportDTO.setTaskId(taskId); reportDTO.setTaskId(taskId);
reportDTO.setEntity(device.getCurrentPoint()); reportDTO.setEntity(device.getCurrentPoint());
reportDTO.setType(MesType.device_task_arrive_point); reportDTO.setType(MesType.device_task_arrive_point);
// ByteBuf buf = ctx.alloc().buffer(); try {
// ByteBuf buf = Unpooled.buffer();
// CommandUtils.buildCommand(buf, reportDTO, CommandConstant.interaction); GlobalMemory.mqttClientUtil.publish(String.format(MqttTopic.DEVICE_TASK_ARRIVE_TOPIC, taskId),
JsonUtils.toJsonString(reportDTO));
} catch (MqttException e) {
logger.error("任务点位到达推送失败 task:{},device:{}error:{}", taskId, deviceId, e.getMessage());
}
List<NettyDevice> controlMasters = sessionManager List<NettyDevice> controlMasters = sessionManager
.getAllSlaveControl(deviceId); .getAllSlaveControl(deviceId);
if (!CollectionUtils.isEmpty(controlMasters)) { if (!CollectionUtils.isEmpty(controlMasters)) {
@@ -404,12 +405,6 @@ public class DeviceConnectHandler extends SimpleChannelInboundHandler<String> {
JsonUtils.toJsonString(reportDTO)); JsonUtils.toJsonString(reportDTO));
logger.info("任务点位到达推送 task:{},device:{},content:{}", taskId, deviceId, logger.info("任务点位到达推送 task:{},device:{},content:{}", taskId, deviceId,
JsonUtils.toJsonString(reportDTO)); JsonUtils.toJsonString(reportDTO));
// if (x.getChannel() != null && x.getChannel().isActive()) {
// x.getChannel().writeAndFlush(buf);
// String content = buf.toString(CharsetUtil.UTF_8);
// logger.info("任务点位到达推送 task:{},device:{},content:{}", taskId, deviceId,
// content);
// }
}); });
} }
} }

View File

@@ -44,6 +44,7 @@ public class ScheduledTask {
// recordDTO.getHistories().forEach(x -> { // recordDTO.getHistories().forEach(x -> {
// deviceStatusHistoryMapper.insert(x); // deviceStatusHistoryMapper.insert(x);
// }); // });
deviceStatusHistoryMapper.insertBatch(recordDTO.getHistories()); deviceStatusHistoryMapper.insertBatch(recordDTO.getHistories());
} }
redisCache.deleteObject(k); redisCache.deleteObject(k);

View File

@@ -375,6 +375,18 @@ public class DeviceTaskService {
if (!StringUtils.isEmpty(dto.getDeviceId())) { if (!StringUtils.isEmpty(dto.getDeviceId())) {
list = list.stream().filter(x -> x.getDeviceId().equals(dto.getDeviceId())).collect(Collectors.toList()); list = list.stream().filter(x -> x.getDeviceId().equals(dto.getDeviceId())).collect(Collectors.toList());
} }
if (dto.getStartTime() != null) {
list = list.stream()
.filter(x -> x.getCreateTime() != null
&& !x.getCreateTime().isBefore(dto.getStartTime()))
.collect(Collectors.toList());
}
if (dto.getEndTime() != null) {
list = list.stream()
.filter(x -> x.getCreateTime() != null
&& !x.getCreateTime().isAfter(dto.getEndTime()))
.collect(Collectors.toList());
}
return transferDeviceTaskData(list); return transferDeviceTaskData(list);
} }
@@ -395,6 +407,12 @@ public class DeviceTaskService {
if (!StringUtils.isEmpty(dto.getDeviceId())) { if (!StringUtils.isEmpty(dto.getDeviceId())) {
queryWrapper.eq(DevicePlanTask::getDeviceId, dto.getDeviceId()); queryWrapper.eq(DevicePlanTask::getDeviceId, dto.getDeviceId());
} }
if (dto.getStartTime() != null) {
queryWrapper.ge(DevicePlanTask::getCreateTime, dto.getStartTime());
}
if (dto.getEndTime() != null) {
queryWrapper.le(DevicePlanTask::getCreateTime, dto.getEndTime());
}
return transferDeviceTaskData(devicePlanTaskMapper.selectList(queryWrapper)); return transferDeviceTaskData(devicePlanTaskMapper.selectList(queryWrapper));
} }
@@ -446,24 +464,32 @@ public class DeviceTaskService {
} }
public boolean cancelTask(DeviceTaskCommandDTO dto, String username) { public boolean cancelTask(DeviceTaskCommandDTO dto, String username) {
if (!StringUtils.isEmpty(dto.getDeviceId())) { String deviceId = dto.getDeviceId();
NettyDevice device = deviceSessionManager.getDevice(dto.getDeviceId()); DevicePlanTask devicePlanTask = null;
if (device != null) { if (StringUtils.isEmpty(dto.getDeviceId())) {
return device.cancelTask();
}
} else {
Long taskId = dto.getTaskId(); Long taskId = dto.getTaskId();
// Long siteId = dto.getSiteId(); devicePlanTask = devicePlanTaskMapper.selectById(taskId);
// Long orgId = dto.getOrgId();
DevicePlanTask devicePlanTask = devicePlanTaskMapper.selectById(taskId);
if (devicePlanTask != null) { if (devicePlanTask != null) {
NettyDevice device = deviceSessionManager.getDevice(devicePlanTask.getDeviceId()); deviceId = devicePlanTask.getDeviceId();
if (device != null) { }
return device.cancelTask(); }
} NettyDevice device = deviceSessionManager.getDevice(deviceId);
if (device != null && device.getTask() != null) {
return device.cancelTask();
} else {
if (devicePlanTask != null) {
devicePlanTask.setTaskStaus(DeviceTaskStaus.CANCELED);
devicePlanTask.setUpdateTime(LocalDateTime.now());
devicePlanTaskMapper.saveOrUpdate(devicePlanTask);
SiteMemory siteMemory = GlobalMemory.getSiteMemory(devicePlanTask.getOrgId(),
devicePlanTask.getSiteId());
siteMemory.removeDevicePlanPrepare(devicePlanTask);
siteMemory.removeDevicePlanExecute(devicePlanTask.getDeviceId());
return true;
} else {
return false;
} }
} }
return false;
} }
// todo 完善 // todo 完善

View File

@@ -136,13 +136,13 @@ public class TransferDeviceService {
if (device == null) { if (device == null) {
return AjaxResult.error("设备不存在"); return AjaxResult.error("设备不存在");
} else { } else {
Long tenantId = device.getTenantId(); // Long tenantId = device.getTenantId();
if (tenantId == -1) { // if (tenantId == -1) {
return AjaxResult.error("设备未绑定"); // return AjaxResult.error("设备未绑定");
} // }
if (!tenantId.equals(user.getUserId())) { // if (!tenantId.equals(user.getUserId())) {
return AjaxResult.error("无操作权限"); // return AjaxResult.error("无操作权限");
} // }
device.setDeviceAlias(bindDTO.getDeviceAlias()); device.setDeviceAlias(bindDTO.getDeviceAlias());
device.setUpdateTime(LocalDateTime.now()); device.setUpdateTime(LocalDateTime.now());
device.setCreateBy(user.getUsername()); device.setCreateBy(user.getUsername());

View File

@@ -1,21 +1,24 @@
package com.maibu.controller; package com.maibu.controller;
import com.maibu.core.business.WorkRecord; import com.maibu.core.business.WorkRecord;
import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.controller.BaseController;
import com.maibu.core.domain.R; import com.maibu.core.domain.R;
import com.maibu.service.impl.WorkRecordService; import com.maibu.service.impl.WorkRecordService;
import com.maibu.utils.MinioUtil; import com.maibu.utils.MinioUtil;
import com.maibu.utils.json.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.http.MediaType;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
@RestController @RestController
@RequestMapping("/iot/workRecord") @RequestMapping("/iot/workRecord")
public class WorkRecordController { public class WorkRecordController extends BaseController {
@Autowired @Autowired
private MinioUtil minioUtil; private MinioUtil minioUtil;
@@ -23,15 +26,16 @@ public class WorkRecordController {
@Autowired @Autowired
private WorkRecordService workRecordService; private WorkRecordService workRecordService;
@PostMapping(value = "/add", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PostMapping("/add")
public R addWorkRecord( public R addWorkRecord(
@RequestPart("file") MultipartFile file, // 接收上传的图片 @RequestPart("file") MultipartFile file, // 接收上传的图片
@RequestPart("workRecord") WorkRecord workRecord // 接收表单里的 JSON 对象 @RequestPart("workRecord") WorkRecord workRecord // 接收表单里的 JSON 对象
) { ) {
int i = -1; int i = -1;
WorkRecord workRecord1 = workRecordService.selectWorkRecordByWorkName(workRecord.getWorkName()); // WorkRecord workRecordObj = JsonUtils.parseObject(workRecord, WorkRecord.class);
WorkRecord workRecord1 = workRecordService.selectWorkRecordByWorkNameAndSiteId(workRecord.getWorkName(), workRecord.getSiteId());
if (workRecord1 != null) { if (workRecord1 != null) {
return R.fail("该任务已存在"); return R.fail("该任务已存在");
} }
@@ -49,7 +53,8 @@ public class WorkRecordController {
// 这里可以把 URL 存到 workRecord 里 // 这里可以把 URL 存到 workRecord 里
workRecord.setImgUrl(url); workRecord.setImgUrl(url);
workRecord.setUserId(getUserId());
workRecord.setOrgId(getLoginUser().getOrgId());
i = workRecordService.addWorkRecord(workRecord); i = workRecordService.addWorkRecord(workRecord);
} catch (Exception e) { } catch (Exception e) {
return R.fail("新增失败: " + e.getMessage()); return R.fail("新增失败: " + e.getMessage());
@@ -58,7 +63,6 @@ public class WorkRecordController {
return i <= 0 ? R.fail("新增失败") : R.ok("新增成功"); return i <= 0 ? R.fail("新增失败") : R.ok("新增成功");
} }
@GetMapping("/selectByUserId") @GetMapping("/selectByUserId")
public R selectWorkRecordByUserId(String userId) { public R selectWorkRecordByUserId(String userId) {
List<WorkRecord> workRecords = workRecordService.selectWorkRecordByUserId(userId); List<WorkRecord> workRecords = workRecordService.selectWorkRecordByUserId(userId);
@@ -89,4 +93,16 @@ public class WorkRecordController {
return R.ok(workRecords); return R.ok(workRecords);
} }
@GetMapping("/selectById")
public R selectById(@RequestParam Long id) {
WorkRecord workRecord = workRecordService.selectById(id);
return R.ok(workRecord);
}
@GetMapping("/selectByTaskId")
public R selectByTaskId(@RequestParam Long taskId) {
List<LatAndLngEntity> path = workRecordService.selectByTaskId(taskId);
return R.ok(path);
}
} }

View File

@@ -1,7 +1,30 @@
package com.maibu.service.impl; package com.maibu.service.impl;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.core.business.*; import com.influxdb.query.FluxRecord;
import com.influxdb.query.FluxTable;
import com.maibu.core.business.Device;
import com.maibu.core.business.DevicePlan;
import com.maibu.core.business.DeviceRunningStatusHistory;
import com.maibu.core.business.DeviceStatusRecordDTO;
import com.maibu.core.business.dto.DeviceBindDTO; import com.maibu.core.business.dto.DeviceBindDTO;
import com.maibu.core.domain.AjaxResult; import com.maibu.core.domain.AjaxResult;
import com.maibu.core.domain.entity.SysRole; import com.maibu.core.domain.entity.SysRole;
@@ -9,6 +32,9 @@ import com.maibu.core.domain.entity.SysSite;
import com.maibu.core.domain.model.LoginUser; import com.maibu.core.domain.model.LoginUser;
import com.maibu.core.enums.DeviceTaskStaus; import com.maibu.core.enums.DeviceTaskStaus;
import com.maibu.core.redis.RedisCache; import com.maibu.core.redis.RedisCache;
import com.maibu.influxdb.MowerRealTimeData;
import com.maibu.influxdb.util.InfluxSqlBuilder;
import com.maibu.influxdb.util.LambdaUtils;
import com.maibu.mapper.DeviceMapper; import com.maibu.mapper.DeviceMapper;
import com.maibu.mapper.DevicePlanMapper; import com.maibu.mapper.DevicePlanMapper;
import com.maibu.mapper.DeviceStatusHistoryMapper; import com.maibu.mapper.DeviceStatusHistoryMapper;
@@ -19,19 +45,6 @@ import com.maibu.service.IDeviceService;
import com.maibu.service.ISysRoleService; import com.maibu.service.ISysRoleService;
import com.maibu.utils.SecurityUtils; import com.maibu.utils.SecurityUtils;
import com.maibu.utils.StringUtils; import com.maibu.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/** /**
* 设备Service业务层处理 * 设备Service业务层处理
@@ -59,7 +72,6 @@ public class DeviceServiceImpl implements IDeviceService {
@Autowired @Autowired
private SysSiteMapper sysSiteMapper; private SysSiteMapper sysSiteMapper;
/** /**
* 根据设备编号查询设备 * 根据设备编号查询设备
* *
@@ -88,7 +100,6 @@ public class DeviceServiceImpl implements IDeviceService {
return device; return device;
} }
/** /**
* 查询设备列表 * 查询设备列表
* *
@@ -130,46 +141,38 @@ public class DeviceServiceImpl implements IDeviceService {
.map(DevicePlan::getDeviceId) .map(DevicePlan::getDeviceId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Map<String, List<DeviceRunningStatusHistory>> statusMap = Map<String, List<DeviceRunningStatusHistory>> statusMap = allStatusList.stream()
allStatusList.stream() .collect(Collectors.groupingBy(DeviceRunningStatusHistory::getDeviceId));
.collect(Collectors.groupingBy(DeviceRunningStatusHistory::getDeviceId));
deviceList.forEach(x -> { deviceList.forEach(x -> {
Integer s = x.getOnlineStatus() == null ? 0 : x.getOnlineStatus(); Integer s = x.getOnlineStatus() == null ? 0 : x.getOnlineStatus();
if (0 == s) { if (0 == s) {
x.setFeStatus(3); //离线 x.setFeStatus(3); // 离线
} else { } else {
if (!CollectionUtils.isEmpty(taskDeviceIds) && taskDeviceIds.contains(x.getDeviceName())) { if (!CollectionUtils.isEmpty(taskDeviceIds) && taskDeviceIds.contains(x.getDeviceName())) {
x.setFeStatus(1); x.setFeStatus(1);
} else { } else {
x.setFeStatus(2); //空闲 x.setFeStatus(2); // 空闲
} }
// if (!CollectionUtils.isEmpty(planTasks)) {
// long count = planTasks.stream().filter(y -> y.getDeviceId().equals(x.getDeviceName())).count();
// if (count > 0) {
// x.setFeStatus(1); //任务中
// } else {
// x.setFeStatus(2); //空闲
// }
// } else {
// x.setFeStatus(2); //空闲
// }
} }
//经纬度 // 经纬度
String key = "running_status:" + x.getDeviceName(); String key = "running_status:" + x.getDeviceName();
DeviceStatusRecordDTO recordDTO = redisCache.getCacheObject(key); DeviceStatusRecordDTO recordDTO = redisCache.getCacheObject(key);
DeviceRunningStatusHistory lastRunningStatus = null; DeviceRunningStatusHistory lastRunningStatus = null;
if (recordDTO != null && !CollectionUtils.isEmpty(recordDTO.getHistories())) { if (recordDTO != null && !CollectionUtils.isEmpty(recordDTO.getHistories())) {
List<DeviceRunningStatusHistory> list = recordDTO.getHistories().stream().filter(y -> !"0".equals(y.getQual())).collect(Collectors.toList()); List<DeviceRunningStatusHistory> list = recordDTO.getHistories().stream()
.filter(y -> !"0".equals(y.getQual())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(list)) { if (!CollectionUtils.isEmpty(list)) {
lastRunningStatus = list.get(list.size() - 1); lastRunningStatus = list.get(list.size() - 1);
} }
} else { } else {
if (!CollectionUtils.isEmpty(allStatusList)) { if (!CollectionUtils.isEmpty(allStatusList)) {
List<DeviceRunningStatusHistory> list = statusMap.get(x.getDeviceName()); List<DeviceRunningStatusHistory> list = statusMap.get(x.getDeviceName());
// List<DeviceRunningStatusHistory> list = allStatusList.stream().filter(z->z.getDeviceId().equals(x.getDeviceName())).collect(Collectors.toList()); // List<DeviceRunningStatusHistory> list =
// allStatusList.stream().filter(z->z.getDeviceId().equals(x.getDeviceName())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(list)) { if (!CollectionUtils.isEmpty(list)) {
List<DeviceRunningStatusHistory> l = list.stream().filter(y -> !"0".equals(y.getQual())).collect(Collectors.toList()); List<DeviceRunningStatusHistory> l = list.stream().filter(y -> !"0".equals(y.getQual()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(l)) { if (!CollectionUtils.isEmpty(l)) {
lastRunningStatus = l.get(l.size() - 1); lastRunningStatus = l.get(l.size() - 1);
} }
@@ -183,7 +186,6 @@ public class DeviceServiceImpl implements IDeviceService {
return deviceList; return deviceList;
} }
@Override @Override
public List<String> selectSerialNumberByProductId(Long productId) { public List<String> selectSerialNumberByProductId(Long productId) {
return deviceMapper.selectSerialNumberByProductId(productId); return deviceMapper.selectSerialNumberByProductId(productId);
@@ -205,7 +207,6 @@ public class DeviceServiceImpl implements IDeviceService {
return deviceMapper.getDeviceNumsByProductId(productId); return deviceMapper.getDeviceNumsByProductId(productId);
} }
/** /**
* 重置设备状态 * 重置设备状态
* *
@@ -227,7 +228,6 @@ public class DeviceServiceImpl implements IDeviceService {
return deviceMapper.selectSerialNumbersByProductId(productId); return deviceMapper.selectSerialNumbersByProductId(productId);
} }
@Override @Override
public boolean bind(DeviceBindDTO bindDTO, String username) { public boolean bind(DeviceBindDTO bindDTO, String username) {
try { try {
@@ -288,7 +288,7 @@ public class DeviceServiceImpl implements IDeviceService {
String roleKey = sysRole.getRoleKey(); String roleKey = sysRole.getRoleKey();
if (!StringUtils.isEmpty(roleKey)) { if (!StringUtils.isEmpty(roleKey)) {
if ("manager".equals(roleKey) || "siteManager".equals(roleKey) || "admin".equals(roleKey)) { if ("manager".equals(roleKey) || "siteManager".equals(roleKey) || "admin".equals(roleKey)) {
// device.setSiteId(siteId); // device.setSiteId(siteId);
} else { } else {
device.setTenantId(loginUser.getUserId()); device.setTenantId(loginUser.getUserId());
} }
@@ -321,19 +321,20 @@ public class DeviceServiceImpl implements IDeviceService {
DeviceStatusRecordDTO recordDTO = redisCache.getCacheObject(key); DeviceStatusRecordDTO recordDTO = redisCache.getCacheObject(key);
DeviceRunningStatusHistory lastRunningStatus = null; DeviceRunningStatusHistory lastRunningStatus = null;
if (recordDTO != null && !CollectionUtils.isEmpty(recordDTO.getHistories())) { if (recordDTO != null && !CollectionUtils.isEmpty(recordDTO.getHistories())) {
List<DeviceRunningStatusHistory> list = recordDTO.getHistories().stream().filter(y -> !"0".equals(y.getQual())).collect(Collectors.toList()); List<DeviceRunningStatusHistory> list = recordDTO.getHistories().stream()
.filter(y -> !"0".equals(y.getQual())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(list)) { if (!CollectionUtils.isEmpty(list)) {
lastRunningStatus = list.get(list.size() - 1); lastRunningStatus = list.get(list.size() - 1);
} }
} }
if (lastRunningStatus == null) { if (lastRunningStatus == null) {
if (!CollectionUtils.isEmpty(allStatusList)) { if (!CollectionUtils.isEmpty(allStatusList)) {
Map<String, List<DeviceRunningStatusHistory>> statusMap = Map<String, List<DeviceRunningStatusHistory>> statusMap = allStatusList.stream()
allStatusList.stream() .collect(Collectors.groupingBy(DeviceRunningStatusHistory::getDeviceId));
.collect(Collectors.groupingBy(DeviceRunningStatusHistory::getDeviceId));
List<DeviceRunningStatusHistory> list = statusMap.get(x.getDeviceName()); List<DeviceRunningStatusHistory> list = statusMap.get(x.getDeviceName());
if (!CollectionUtils.isEmpty(list)) { if (!CollectionUtils.isEmpty(list)) {
List<DeviceRunningStatusHistory> l = list.stream().filter(y -> !"0".equals(y.getQual())).collect(Collectors.toList()); List<DeviceRunningStatusHistory> l = list.stream().filter(y -> !"0".equals(y.getQual()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(l)) { if (!CollectionUtils.isEmpty(l)) {
lastRunningStatus = l.get(l.size() - 1); lastRunningStatus = l.get(l.size() - 1);
} }
@@ -367,16 +368,15 @@ public class DeviceServiceImpl implements IDeviceService {
} else if (!"admin".equals(roleKey)) { } else if (!"admin".equals(roleKey)) {
device.setTenantId(loginUser.getUserId()); device.setTenantId(loginUser.getUserId());
} }
// if ("admin".equals(roleKey)) { // if ("admin".equals(roleKey)) {
// deviceList = deviceMapper.selectList(); // deviceList = deviceMapper.selectList();
// } else { // } else {
// deviceList = deviceMapper.selectDeviceList(device); // deviceList = deviceMapper.selectDeviceList(device);
// } // }
deviceList = deviceMapper.selectDeviceList(device); deviceList = deviceMapper.selectDeviceList(device);
} }
} }
return deviceList; return deviceList;
} }
} }

View File

@@ -1,10 +1,14 @@
package com.maibu.service.impl; package com.maibu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maibu.core.business.DevicePlanTask;
import com.maibu.core.business.WorkRecord; import com.maibu.core.business.WorkRecord;
import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.mapper.DevicePlanTaskMapper;
import com.maibu.mapper.WorkRecordMapper; import com.maibu.mapper.WorkRecordMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List; import java.util.List;
@@ -14,10 +18,12 @@ public class WorkRecordService {
@Autowired @Autowired
private WorkRecordMapper workRecordMapper; private WorkRecordMapper workRecordMapper;
@Autowired
private DevicePlanTaskMapper devicePlanTaskMapper;
public int addWorkRecord(WorkRecord workRecord) throws Exception { public int addWorkRecord(WorkRecord workRecord) throws Exception {
int i = workRecordMapper.insert(workRecord); int i = workRecordMapper.insert(workRecord);
// int i = workRecordMapper.insertWorkRecord(workRecord); // int i = workRecordMapper.insertWorkRecord(workRecord);
return i; return i;
} }
@@ -27,28 +33,55 @@ public class WorkRecordService {
return workRecordMapper.selectOne(queryWrapper); return workRecordMapper.selectOne(queryWrapper);
} }
public WorkRecord selectWorkRecordByWorkNameAndSiteId(String workName, Long siteId) {
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(WorkRecord::getWorkName, workName);
queryWrapper.eq(WorkRecord::getSiteId, siteId);
return workRecordMapper.selectOne(queryWrapper);
}
public List<WorkRecord> selectWorkRecordByUserId(String userId) { public List<WorkRecord> selectWorkRecordByUserId(String userId) {
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(WorkRecord::getUserId, userId); queryWrapper.eq(WorkRecord::getUserId, userId);
return workRecordMapper.selectList(queryWrapper); return workRecordMapper.selectList(queryWrapper);
} }
public int deleteWorkRecordByWorkName(String workName) { public int deleteWorkRecordByWorkName(String workName) {
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(WorkRecord::getWorkName, workName); queryWrapper.eq(WorkRecord::getWorkName, workName);
return workRecordMapper.delete(queryWrapper); return workRecordMapper.delete(queryWrapper);
} }
public boolean updateWorkRecord(WorkRecord workRecord) { public boolean updateWorkRecord(WorkRecord workRecord) {
return workRecordMapper.saveOrUpdate(workRecord); return workRecordMapper.saveOrUpdate(workRecord);
} }
public List<WorkRecord> selectBySiteId(Long siteId) { public List<WorkRecord> selectBySiteId(Long siteId) {
LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<WorkRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(WorkRecord::getSiteId, siteId); queryWrapper.eq(WorkRecord::getSiteId, siteId);
return workRecordMapper.selectList(queryWrapper); List<WorkRecord> list = workRecordMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(list)) {
list.forEach(workRecord -> {
workRecord.setJsonData(null);
});
}
return list;
}
public WorkRecord selectById(Long id) {
return workRecordMapper.selectById(id);
}
public List<LatAndLngEntity> selectByTaskId(Long taskId) {
DevicePlanTask devicePlanTask = devicePlanTaskMapper.selectById(taskId); // 先查询设备任务,确认任务存在
if (devicePlanTask == null) {
return null;
}
Long routeId = devicePlanTask.getRouteId(); // 获取任务关联的路线ID
WorkRecord workRecord = workRecordMapper.selectById(routeId); // 查询路线ID对应的工作记录
if (workRecord != null && workRecord.getJsonData() != null) {
return workRecord.getJsonData().getPath(); // 返回路线数据
}
return null; // 如果没有找到对应的工作记录或路线数据,返回 null
} }
} }

View File

@@ -3,6 +3,8 @@ package com.maibu.netty.handler;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import com.maibu.common.MiddleCommandConstant; import com.maibu.common.MiddleCommandConstant;
import com.maibu.common.MiddleConstant; import com.maibu.common.MiddleConstant;
import com.maibu.core.business.device.DeviceStatusDetail;
import com.maibu.core.business.inter.WebsocketMesDispather;
import com.maibu.core.business.path.LatAndLngEntity; import com.maibu.core.business.path.LatAndLngEntity;
import com.maibu.core.enums.MesType; import com.maibu.core.enums.MesType;
import com.maibu.core.enums.RespondCode; import com.maibu.core.enums.RespondCode;
@@ -37,6 +39,8 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
private static final HttpService httpService = SpringUtils.getBean(HttpService.class); private static final HttpService httpService = SpringUtils.getBean(HttpService.class);
private final WebsocketMesDispather websocketMesDispather = SpringUtils.getBean(WebsocketMesDispather.class);
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) { public void channelRead(ChannelHandlerContext ctx, Object msg) {
try { try {
@@ -113,7 +117,7 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
dto.setTaskId(Long.valueOf(taskId)); dto.setTaskId(Long.valueOf(taskId));
dto.setStatus(status); dto.setStatus(status);
WebsocketHandler.sendMessageToClient(webSocket, JsonUtils.toJsonString(dto)); WebsocketHandler.sendMessageToClient(webSocket, JsonUtils.toJsonString(dto));
}else if ("device_task_arrive_point".equals(eventType)) { } else if ("device_task_arrive_point".equals(eventType)) {
String taskId = obj.get("taskId").toString(); String taskId = obj.get("taskId").toString();
LatAndLngEntity position = JsonUtils.parseObject(obj.get("entity").toString(), LatAndLngEntity position = JsonUtils.parseObject(obj.get("entity").toString(),
LatAndLngEntity.class); LatAndLngEntity.class);
@@ -179,13 +183,14 @@ public class ClientHandler extends ChannelInboundHandlerAdapter {
} }
} else if (isStatusDate(data)) { } else if (isStatusDate(data)) {
// 状态消息推送给前端 // 状态消息推送给前端
WebStatusMessageDTO dto = createWebDeviceStatusMessage(data); // WebStatusMessageDTO dto = createWebDeviceStatusMessage(data);
WebsocketHandler.sendMessageToClient(webSocket, JsonUtils.toJsonString(dto)); // WebsocketHandler.sendMessageToClient(webSocket, JsonUtils.toJsonString(dto));
// String[] k = key.split(":");
// String deviceId = k[0] + ":" + k[1];
// websocketMesDispather.dispather(deviceId,JsonUtils.toJsonString(dto));
} else if (isPath(data)) { } else if (isPath(data)) {
// 已到达 // 已到达
if (data[5] == (byte) 0x01) {
}
} }
} catch (Exception e) { } catch (Exception e) {
logger.error("channelRead error:{}", e.getMessage()); logger.error("channelRead error:{}", e.getMessage());