update 预约充电

This commit is contained in:
Guoqs
2024-07-31 14:38:06 +08:00
parent 9ea58fda7b
commit 50cab02eb7
7 changed files with 276 additions and 85 deletions

View File

@@ -85,6 +85,8 @@ import com.jsowell.wxpay.common.WeChatPayParameter;
import com.jsowell.wxpay.dto.AppletTemplateMessageSendDTO;
import com.jsowell.wxpay.response.WechatPayRefundRequest;
import com.jsowell.wxpay.service.WxAppletRemoteService;
import demo.ChargingPileServerHandler;
import demo.ProtocolUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
@@ -104,6 +106,8 @@ import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ActiveProfiles("dev")

View File

@@ -1,85 +0,0 @@
import com.google.common.collect.Lists;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @program: com.cjml.service.partitem
* @description:
* @author: dc
* @create: 2023-09-09 13:46
**/
public class Test {
public static void main(String[] args) {
List<Category> testList = Lists.newArrayList();
testList.add(new Category("100-50-10", 100, 50, 10));
testList.add(new Category("110-30-8", 110, 30, 8));
testList.add(new Category("0-10-12", 0, 10, 12));
testList = testList.stream().sorted(
Comparator.comparing(Category::getCategoryGroupSort, Comparator.reverseOrder())
.thenComparing(Category::getCategorySort, Comparator.reverseOrder())
.thenComparing(Category::getPartSort)
)
.collect(Collectors.toList());
System.out.println(testList.get(0).getCategoryName());
System.out.println(testList.get(1).getCategoryName());
System.out.println(testList.get(2).getCategoryName());
}
static class Category {
private String categoryName;
private int categoryGroupSort;
private int categorySort;
private int partSort;
public Category() {
}
public Category(String categoryName, int categoryGroupSort, int categorySort, int partSort) {
this.categoryName = categoryName;
this.categoryGroupSort = categoryGroupSort;
this.categorySort = categorySort;
this.partSort = partSort;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public int getCategoryGroupSort() {
return categoryGroupSort;
}
public void setCategoryGroupSort(int categoryGroupSort) {
this.categoryGroupSort = categoryGroupSort;
}
public int getCategorySort() {
return categorySort;
}
public void setCategorySort(int categorySort) {
this.categorySort = categorySort;
}
public int getPartSort() {
return partSort;
}
public void setPartSort(int partSort) {
this.partSort = partSort;
}
}
}

View File

@@ -0,0 +1,80 @@
package demo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
public class ChargingPileClient {
private final String host;
private final int port;
public ChargingPileClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ByteArrayDecoder());
pipeline.addLast(new ByteArrayEncoder());
pipeline.addLast(new ChargingPileClientHandler());
}
});
ChannelFuture f = b.connect(host, port).sync();
System.out.println("充电桩客户端已连接到服务器");
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
String host = "localhost";
int port = 9011;
new ChargingPileClient(host, port).start();
}
}
class ChargingPileClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
byte[] command = (byte[]) msg;
System.out.println("收到服务器指令: " + ProtocolUtil.bytesToHex(command));
// 处理工作参数设置指令
if (command[5] == 0x52) {
String pileId = ProtocolUtil.bytesToHex(command).substring(12, 26);
boolean allowWork = (command[19] == 0x00);
int maxPower = command[20] & 0xFF;
System.out.println("收到工作参数设置:");
System.out.println("桩编号: " + pileId);
System.out.println("是否允许工作: " + (allowWork ? "允许" : "不允许"));
System.out.println("最大允许输出功率: " + maxPower + "%");
// 模拟设置成功
byte[] response = ProtocolUtil.createSetWorkParamsResponseFrame(pileId, true);
ctx.writeAndFlush(response);
System.out.println("发送响应: " + ProtocolUtil.bytesToHex(response));
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

View File

@@ -0,0 +1,34 @@
package demo;
import org.springframework.web.bind.annotation.*;
import io.netty.channel.ChannelHandlerContext;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/api/charging")
public class ChargingPileController {
private final ChannelHandlerContext chargingPileChannel;
public ChargingPileController(ChannelHandlerContext chargingPileChannel) {
this.chargingPileChannel = chargingPileChannel;
}
@PostMapping("/setWorkParams")
public String setWorkParams(@RequestParam String pileId,
@RequestParam boolean allowWork,
@RequestParam int maxPower) {
try {
byte[] command = ProtocolUtil.createSetWorkParamsFrame(pileId, allowWork, maxPower);
CompletableFuture<byte[]> future = ChargingPileServerHandler.sendCommand(chargingPileChannel, command);
byte[] response = future.get(5, TimeUnit.SECONDS);
// 解析响应
boolean success = (response[18] == 0x01);
return "设置" + (success ? "成功" : "失败");
} catch (Exception e) {
return "发送指令失败: " + e.getMessage();
}
}
}

View File

@@ -0,0 +1,50 @@
package demo;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
public class ChargingPileServer {
private final int port;
public ChargingPileServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ByteArrayDecoder());
pipeline.addLast(new ByteArrayEncoder());
pipeline.addLast(new ChargingPileServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync();
System.out.println("充电桩服务器启动,监听端口: " + port);
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 9011;
new ChargingPileServer(port).start();
}
}

View File

@@ -0,0 +1,31 @@
package demo;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.CompletableFuture;
public class ChargingPileServerHandler extends ChannelInboundHandlerAdapter {
private static CompletableFuture<byte[]> responseFuture;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
byte[] response = (byte[]) msg;
System.out.println("接收到充电桩响应: " + ProtocolUtil.bytesToHex(response));
if (responseFuture != null) {
responseFuture.complete(response);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
public static CompletableFuture<byte[]> sendCommand(ChannelHandlerContext ctx, byte[] command) {
responseFuture = new CompletableFuture<>();
ctx.writeAndFlush(command);
System.out.println("发送指令到充电桩: " + ProtocolUtil.bytesToHex(command));
return responseFuture;
}
}

View File

@@ -0,0 +1,77 @@
package demo;
import java.nio.ByteBuffer;
public class ProtocolUtil {
public static byte[] createSetWorkParamsFrame(String pileId, boolean allowWork, int maxPower) {
ByteBuffer buffer = ByteBuffer.allocate(21);
buffer.put((byte) 0x68); // 起始标志
buffer.put((byte) 0x0D); // 数据长度
buffer.putShort((short) 0x0008); // 序列号域
buffer.put((byte) 0x00); // 加密标志
buffer.put((byte) 0x52); // 帧类型码
// 桩编码
buffer.put(hexStringToByteArray(pileId));
// 是否允许工作
buffer.put((byte) (allowWork ? 0x00 : 0x01));
// 充电桩最大允许输出功率
buffer.put((byte) maxPower);
// 计算校验和
short checksum = calculateChecksum(buffer.array(), 1, 19);
buffer.putShort(checksum);
return buffer.array();
}
public static byte[] createSetWorkParamsResponseFrame(String pileId, boolean success) {
ByteBuffer buffer = ByteBuffer.allocate(20);
buffer.put((byte) 0x68); // 起始标志
buffer.put((byte) 0x0C); // 数据长度
buffer.putShort((short) 0x0008); // 序列号域
buffer.put((byte) 0x00); // 加密标志
buffer.put((byte) 0x51); // 帧类型码
// 桩编码
buffer.put(hexStringToByteArray(pileId));
// 设置结果
buffer.put((byte) (success ? 0x01 : 0x00));
// 计算校验和
short checksum = calculateChecksum(buffer.array(), 1, 18);
buffer.putShort(checksum);
return buffer.array();
}
public static short calculateChecksum(byte[] data, int offset, int length) {
int sum = 0;
for (int i = offset; i < offset + length; i++) {
sum += (data[i] & 0xFF);
}
return (short) (sum & 0xFFFF);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
}