指令下发接口开发

This commit is contained in:
wangshilong 2024-11-27 02:00:58 +08:00
parent e8b61641de
commit 4ab1df8cba
16 changed files with 732 additions and 1 deletions

View File

@ -0,0 +1,38 @@
package com.isu.gaswellwatch.controller;
import com.isu.gaswellwatch.annotation.OperationLog;
import com.isu.gaswellwatch.entity.Response;
import com.isu.gaswellwatch.enums.LogType;
import com.isu.gaswellwatch.modbus.CommandService;
import com.isu.gaswellwatch.vo.command.CollectCommand;
import com.isu.gaswellwatch.vo.command.Command;
import lombok.RequiredArgsConstructor;
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;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/27 0:23
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/command")
public class CommandController {
private final CommandService commandService;
@PostMapping(value = "/control")
@OperationLog(description = "下发控制指令", type = LogType.ADD)
public Response<String> control(@RequestBody Command command) {
return this.commandService.control(command);
}
@PostMapping(value = "/collect")
@OperationLog(description = "下发采集指令", type = LogType.ADD)
public Response<String> collect(@RequestBody CollectCommand command) {
return this.commandService.collect(command);
}
}

View File

@ -0,0 +1,4 @@
package com.isu.gaswellwatch.dto.modbus;
public interface CommandDto {
}

View File

@ -0,0 +1,42 @@
package com.isu.gaswellwatch.dto.modbus;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class CommandTypeComparable implements Comparable {
private CommandType type;
private long timestamp;
@Override
public int compareTo(Object o) {
CommandTypeComparable commandTypeComparable = (CommandTypeComparable) o;
if (this.getType() == commandTypeComparable.getType()) {
return this.timestamp > commandTypeComparable.timestamp ? 1 : -1;
} else if (this.getType() == CommandType.CONTROL) {
return -1;
} else if (this.getType() == CommandType.COLLECTION) {
return 1;
} else {
throw new RuntimeException("无法排序");
}
}
@Getter
public enum CommandType {
CONTROL("控制"), COLLECTION("采集");
private final String name;
CommandType(String name) {
this.name = name;
}
}
}

View File

@ -0,0 +1,34 @@
package com.isu.gaswellwatch.dto.modbus;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class ModbusCommandDto extends CommandTypeComparable implements CommandDto {
/**
* 12位十六进制的命令
*/
private String command;
/**
* 采集长度
*/
private int length;
/**
* 自定义标识
* 采集情况下会推送到MQ的内容格式为自定义标识+设备反馈报文
*/
private String key;
/**
* 网关唯一标识符
*/
private String identifier;
}

View File

@ -0,0 +1,16 @@
package com.isu.gaswellwatch.modbus;
import com.isu.gaswellwatch.entity.Response;
import com.isu.gaswellwatch.vo.command.Command;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/27 0:24
*/
public interface CommandService {
Response<String> control(Command command);
Response<String> collect(Command command);
}

View File

@ -111,7 +111,7 @@ public class Redis2DBPersistenceService {
private Map<Long, String> getOnlineGateway() {
try {
RequestEntity request = RequestEntity.get("http://127.0.0.1:9999/modbus-tcp/online").build();
RequestEntity request = RequestEntity.get("http://localhost:9999/modbus-tcp/online").build();
ResponseEntity<Response<List<String>>> response = this.restTemplate.exchange(request,
new ParameterizedTypeReference<Response<List<String>>>() {
});

View File

@ -0,0 +1,75 @@
package com.isu.gaswellwatch.modbus.impl;
import com.isu.gaswellwatch.dao.DeviceDao;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.entity.Response;
import com.isu.gaswellwatch.modbus.CommandService;
import com.isu.gaswellwatch.vo.command.Command;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.Objects;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/27 0:25
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CommandServiceImpl implements CommandService {
private final DeviceDao deviceDao;
private final RestTemplate restTemplate = new RestTemplate();
@Override
public Response<String> control(Command command) {
return this.sendCommand("control", command);
}
@Override
public Response<String> collect(Command command) {
return this.sendCommand("collect", command);
}
private Response<String> sendCommand(String type, Command command) {
try {
Collection<ModbusCommandDto> modbusCommands = Objects.requireNonNull(command).buildModbusCommand();
if (ObjectUtils.isEmpty(modbusCommands)) {
return Response.failed("Modbus command is empty");
}
this.deviceDao.getDeviceById(command.getDeviceId());
modbusCommands.forEach(item -> {
// .key(StringUtils.joinWith("/", identifier,
// MapUtil.getStr(item, "deviceId"),
// MapUtil.getStr(item, "commandId"),
// timestamp))
item.setKey("");
item.setIdentifier("");
});
RequestEntity<Collection<ModbusCommandDto>> request = RequestEntity
.post("http://localhost:9999/modbus-tcp/" + type)
.body(modbusCommands);
ResponseEntity<Response<String>> response = this.restTemplate.exchange(request,
new ParameterizedTypeReference<Response<String>>() {
});
if (Objects.isNull(response.getBody())) {
return Response.failed("Nothing message");
}
return response.getBody();
} catch (Exception e) {
log.error("Send command fail", e);
return Response.failed("Send command fail");
}
}
}

View File

@ -0,0 +1,22 @@
package com.isu.gaswellwatch.vo.command;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import java.io.Serial;
import java.util.Collection;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/27 1:13
*/
public class CollectCommand extends Command {
@Serial
private static final long serialVersionUID = 1246632076719201751L;
@Override
protected Collection<ModbusCommandDto> builderModbusCommand() {
return null;
}
}

View File

@ -0,0 +1,75 @@
package com.isu.gaswellwatch.vo.command;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.knpcv1.TurnOff;
import com.isu.gaswellwatch.vo.command.knpcv1.TurnOn;
import com.isu.gaswellwatch.vo.command.knpcv1.mode.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.StringUtils;
import java.io.Serial;
import java.io.Serializable;
import java.security.InvalidParameterException;
import java.util.Collection;
import java.util.Objects;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 19:59
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "code")
@JsonSubTypes(value = {
@JsonSubTypes.Type(value = TurnOn.class, name = Command.KNPCV1_TURN_ON_THE_WELL),
@JsonSubTypes.Type(value = TurnOff.class, name = Command.KNPCV1_TURN_OFF_THE_WELL),
@JsonSubTypes.Type(value = TimerMode.class, name = Command.KNPCV1_RUN_TIMER),
@JsonSubTypes.Type(value = TimingMode.class, name = Command.KNPCV1_RUN_TIMING),
@JsonSubTypes.Type(value = ManualMode.class, name = Command.KNPCV1_RUN_MANUAL),
@JsonSubTypes.Type(value = PlungerMode.class, name = Command.KNPCV1_RUN_PLUNGER),
@JsonSubTypes.Type(value = PressureMode.class, name = Command.KNPCV1_RUN_TIME_PRESSURE),
})
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public abstract class Command implements Serializable {
@Serial
private static final long serialVersionUID = -2590497444442160271L;
/* 点表类型KNPCV1 start */
/* 开关井 */
public static final String KNPCV1_TURN_ON_THE_WELL = "KNPCV1.TURN_ON_THE_WELL";
public static final String KNPCV1_TURN_OFF_THE_WELL = "KNPCV1.TURN_OFF_THE_WELL";
/* 运行模式*/
public static final String KNPCV1_RUN_TIMER = "KNPCV1.RUN.TIMER";
public static final String KNPCV1_RUN_TIMING = "KNPCV1.RUN.TIMING";
public static final String KNPCV1_RUN_MANUAL = "KNPCV1.RUN.MANUAL";
public static final String KNPCV1_RUN_PLUNGER = "KNPCV1.RUN.PLUNGER";
public static final String KNPCV1_RUN_TIME_PRESSURE = "KNPCV1.RUN.TIME_PRESSURE";
/* 点表类型KNPCV1 end */
private String code;
private Long deviceId;
public Collection<ModbusCommandDto> buildModbusCommand() {
if (this.validate()) {
throw new InvalidParameterException("Invalid command");
}
return this.builderModbusCommand();
}
public boolean validate() {
return Objects.nonNull(this.deviceId) && StringUtils.isNotBlank(this.code);
}
protected abstract Collection<ModbusCommandDto> builderModbusCommand();
}

View File

@ -0,0 +1,56 @@
package com.isu.gaswellwatch.vo.command.knpcv1;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.Command;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.ObjectUtils;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 运行模式
* 0手动模式
* 1定时器模式
* 2计时器模式
* 3压力模式
* 4柱塞模式
* 5时压模式
*
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 20:09
*/
@Getter
@Setter
@SuperBuilder
@AllArgsConstructor
public abstract class ChangeRunMode extends Command {
@Serial
private static final long serialVersionUID = 7882661805502297673L;
private int runMode;
@Override
public boolean validate() {
return super.validate() && this.runMode >= 0 && this.runMode <= 5;
}
@Override
protected final Collection<ModbusCommandDto> builderModbusCommand() {
Collection<ModbusCommandDto> subCommands = this.builderSubModbusCommand();
List<ModbusCommandDto> resultCommands = new ArrayList<>();
if (ObjectUtils.isNotEmpty(subCommands)) {
resultCommands.addAll(subCommands);
}
resultCommands.add(ModbusCommandDto.builder().command("01060064000" + this.runMode).length(16).build());
return resultCommands;
}
protected abstract Collection<ModbusCommandDto> builderSubModbusCommand();
}

View File

@ -0,0 +1,83 @@
package com.isu.gaswellwatch.vo.command.knpcv1;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import java.security.InvalidParameterException;
import java.time.LocalTime;
import java.util.Objects;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 21:08
*/
public interface Timing {
default String timeValidate(String time, String name, int maxHours) {
if (StringUtils.isBlank(time)) {
throw new NullPointerException(name + " cannot be empty");
}
if (!StringUtils.contains(time, ":")) {
throw new InvalidParameterException(name + " is invalid. Valid format: [0-" + maxHours + "]:[0-59]:[0-59]");
}
String[] times = StringUtils.split(time, ":");
int hour = 0, minute = 0, second = 0;
if (times.length == 1) {
hour = NumberUtils.createInteger(times[0]);
} else if (times.length == 2) {
hour = NumberUtils.createInteger(times[0]);
minute = NumberUtils.createInteger(times[1]);
} else if (times.length == 3) {
hour = NumberUtils.createInteger(times[0]);
minute = NumberUtils.createInteger(times[1]);
second = NumberUtils.createInteger(times[2]);
} else {
throw new InvalidParameterException(name + " is invalid. Valid format: [0-" + maxHours + "]:[0-59]:[0-59]");
}
if (!(hour >= 0 && hour <= maxHours && minute >= 0 && minute <= 59 && second >= 0 && second <= 59)) {
throw new InvalidParameterException(name + " is invalid. Valid format: [0-" + maxHours + "]:[0-59]:[0-59]");
}
return StringUtils.joinWith(":", StringUtils.leftPad(String.valueOf(hour), 2, "0"),
StringUtils.leftPad(String.valueOf(minute), 2, "0"),
StringUtils.leftPad(String.valueOf(minute), 2, "0"));
}
default String timerValidate(String time, String name) {
return this.timeValidate(time, name, 23);
}
default String timingValidate(String time, String name) {
return this.timeValidate(time, name, 999);
}
default String toHexString(LocalTime time) {
return Objects.equals(LocalTime.MIN, time) ? "000000000000" :
Objects.equals(LocalTime.MAX, time) ? "0017003B003B" :
this.toHexString(time.toString());
}
/**
* 支持[0-999]:[0-59]:[0-59]
*
* @param stringTime
* @return
*/
default String toHexString(String stringTime) {
if (StringUtils.equals(stringTime, "00:00:00")) {
return "000000000000";
}
if (StringUtils.equals(stringTime, "23:59:59")) {
return "0017003B003B";
}
if (StringUtils.equals(stringTime, "999:59:59")) {
return "03E7003B003B";
}
String[] items = StringUtils.split(stringTime, ":");
int hours = NumberUtils.createInteger(items[0]);
int minutes = NumberUtils.createInteger(items[1]);
int seconds = NumberUtils.createInteger(items[2]);
return StringUtils.leftPad(Integer.toHexString(hours), 4, "0") +
StringUtils.leftPad(Integer.toHexString(minutes), 4, "0") +
StringUtils.leftPad(Integer.toHexString(seconds), 4, "0");
}
}

View File

@ -0,0 +1,26 @@
package com.isu.gaswellwatch.vo.command.knpcv1;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.Command;
import java.io.Serial;
import java.util.Collection;
import java.util.List;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 19:57
*/
public class TurnOff extends Command {
@Serial
private static final long serialVersionUID = 6386819878187686032L;
public TurnOff() {
this.setCode("KNPCV1.TURN_OFF_THE_WELL");
}
@Override
protected Collection<ModbusCommandDto> builderModbusCommand() {
return List.of(ModbusCommandDto.builder().command("010500010000").length(16).build());
}
}

View File

@ -0,0 +1,27 @@
package com.isu.gaswellwatch.vo.command.knpcv1;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.Command;
import java.io.Serial;
import java.util.Collection;
import java.util.List;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 19:57
*/
public class TurnOn extends Command {
@Serial
private static final long serialVersionUID = 6386819878187686032L;
public TurnOn() {
this.setCode("KNPCV1.TURN_ON_THE_WELL");
}
@Override
protected Collection<ModbusCommandDto> builderModbusCommand() {
return List.of(ModbusCommandDto.builder().command("01050001FF00").length(16).build());
}
}

View File

@ -0,0 +1,28 @@
package com.isu.gaswellwatch.vo.command.knpcv1.mode;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.knpcv1.ChangeRunMode;
import java.io.Serial;
import java.util.Collection;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 20:24
*/
public class ManualMode extends ChangeRunMode {
@Serial
private static final long serialVersionUID = 9127026055666073752L;
public ManualMode() {
super(0);
this.setCode("KNPCV1.RUN.MANUAL");
}
@Override
protected Collection<ModbusCommandDto> builderSubModbusCommand() {
return null;
}
}

View File

@ -0,0 +1,125 @@
package com.isu.gaswellwatch.vo.command.knpcv1.mode;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.knpcv1.ChangeRunMode;
import com.isu.gaswellwatch.vo.command.knpcv1.Timing;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.time.LocalTime;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 20:12
*/
@Getter
@Setter
@SuperBuilder
public class TimerMode extends ChangeRunMode implements Timing {
@Serial
private static final long serialVersionUID = 1612870503947873375L;
/**
* 定时器1使能开关
*/
@Builder.Default
private boolean enable1 = false;
/**
* 定时器2使能开关
*/
@Builder.Default
private boolean enable2 = false;
/**
* 定时器3使能开关
*/
@Builder.Default
private boolean enable3 = false;
/**
* 定时器4使能开关
*/
@Builder.Default
private boolean enable4 = false;
/**
* 定时器1开井时间
*/
@Builder.Default
private LocalTime openTimer1 = LocalTime.MIN;
/**
* 定时器1关井时间
*/
@Builder.Default
private LocalTime closeTimer1 = LocalTime.MIN;
/**
* 定时器2开井时间
*/
@Builder.Default
private LocalTime openTimer2 = LocalTime.MIN;
/**
* 定时器2关井时间
*/
@Builder.Default
private LocalTime closeTimer2 = LocalTime.MIN;
/**
* 定时器3开井时间
*/
@Builder.Default
private LocalTime openTimer3 = LocalTime.MIN;
/**
* 定时器3关井时间
*/
@Builder.Default
private LocalTime closeTimer3 = LocalTime.MIN;
/**
* 定时器4开井时间
*/
@Builder.Default
private LocalTime openTimer4 = LocalTime.MIN;
/**
* 定时器4关井时间
*/
@Builder.Default
private LocalTime closeTimer4 = LocalTime.MIN;
public TimerMode() {
super(1);
this.setCode("KNPCV1.RUN.TIMER");
}
@Override
public boolean validate() {
return super.validate()
&& Objects.nonNull(this.openTimer1) && Objects.nonNull(this.closeTimer1)
&& Objects.nonNull(this.openTimer2) && Objects.nonNull(this.closeTimer2)
&& Objects.nonNull(this.openTimer3) && Objects.nonNull(this.closeTimer3)
&& Objects.nonNull(this.openTimer4) && Objects.nonNull(this.closeTimer4);
}
@Override
protected Collection<ModbusCommandDto> builderSubModbusCommand() {
StringBuilder command = new StringBuilder(150);
command.append("0110006E001C38");
command.append("000").append(this.enable1 ? "1" : "0");
command.append("000").append(this.enable2 ? "1" : "0");
command.append("000").append(this.enable3 ? "1" : "0");
command.append("000").append(this.enable4 ? "1" : "0");
command.append(this.toHexString(this.openTimer1)).append(this.toHexString(this.closeTimer1))
.append(this.toHexString(this.openTimer2)).append(this.toHexString(this.closeTimer2))
.append(this.toHexString(this.openTimer3)).append(this.toHexString(this.closeTimer3))
.append(this.toHexString(this.openTimer4)).append(this.toHexString(this.closeTimer4));
return List.of(ModbusCommandDto.builder()
.command(command.toString())
.length(16).build());
}
}

View File

@ -0,0 +1,80 @@
package com.isu.gaswellwatch.vo.command.knpcv1.mode;
import com.isu.gaswellwatch.dto.modbus.ModbusCommandDto;
import com.isu.gaswellwatch.vo.command.knpcv1.ChangeRunMode;
import com.isu.gaswellwatch.vo.command.knpcv1.Timing;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.StringUtils;
import java.io.Serial;
import java.util.Collection;
import java.util.List;
/**
* @author <a href="mailto:scwsl@foxmail.com">王仕龙</a>
* 2024/11/26 20:23
*/
@Getter
@Setter
@SuperBuilder
public class TimingMode extends ChangeRunMode implements Timing {
@Serial
private static final long serialVersionUID = 5065742825844725267L;
/**
* 计时器开井时长[0-999]:[0-59]:[0-59]
*/
@Builder.Default
private String openTiming = "00:00:00";
/**
* 计时器关井时长[0-999]:[0-59]:[0-59]
*/
@Builder.Default
private String closeTiming = "00:00:00";
/**
* 计时器延时时长[0-999]:[0-59]:[0-59]
*/
@Builder.Default
private String delayTiming = "00:00:00";
public TimingMode() {
super(2);
this.setCode("KNPCV1.RUN.TIMING");
}
@Override
public boolean validate() {
return super.validate()
&& StringUtils.isNotBlank(this.openTiming) && StringUtils.isNotBlank(this.closeTiming) && StringUtils.isNotBlank(this.delayTiming);
}
public void setOpenTiming(String openTiming) {
this.openTiming = this.timingValidate(openTiming, "openTiming");
}
public void setCloseTiming(String closeTiming) {
this.closeTiming = this.timingValidate(this.openTiming, "closeTiming");
}
public void setDelayTiming(String delayTiming) {
this.delayTiming = this.timingValidate(delayTiming, "delayTiming");
}
@Override
protected Collection<ModbusCommandDto> builderSubModbusCommand() {
StringBuilder command = new StringBuilder(60);
command.append("01100096000A14")
.append(this.toHexString(this.openTiming))
.append(this.toHexString(this.closeTiming))
.append("0000") // 地址位0154值为空
.append(this.toHexString(this.delayTiming));
return List.of(ModbusCommandDto.builder()
.command(command.toString())
.length(16).build());
}
}