智能充电(新能源电动车,电单车)云管理系统的定制解决方案

一 系统简介

智能充电(新能源电动车,电单车)云管理系统 是一套能够实现对充电站/桩的实时通讯、状态监控、故障检测、运营分析、数据统计、策略设置的智能化多任务管理系统。

二 平台概览

智能充电云管理系统  
https://chongdianzhuang.itgcs.tech/  账号:demo 密码:demo123

b753b814019042eb99afc43ff9e4d556.png
三 通信协议

  • Http+SSL协议:运维管理平台
  • TCP协议:与充电桩通信
  • Websocket+SSL协议:与微信小程序实时双向通信

四 支持的充电桩

  • 新能源汽车充电:包括直流桩和交流桩,云快充平台协议V1.6
  • 两轮电单车充电
  • 桩企业私有协议等(定制开发)

五 运行环境

Windows 或 类Linux系统,Mysql,Redis,RabbitMQ等服务

六 通信代码

1 TCP Server:与充电桩通信,CRC校验

func TCPServer() {//以下是TCP ServerlistenAddrs := []string{GlobalConfig.TCPAddr1,GlobalConfig.TCPAddr2,}for _, addr := range listenAddrs {go func(addr string) {listener, err := net.Listen("tcp", addr)if err != nil {fmtPrintf("[TCP] Failed to listen on %s: %v", addr, err)return}defer listener.Close()fmtPrintf("[TCP] Server listening on %s", addr)for {conn, err := listener.Accept()if err != nil {fmtPrintf("[TCP] Error accepting connection: %v", err)continue}go handleConn(conn)}}(addr)}
}

1.1 充电桩登录消息定义


// 0x01 MsgLogin 登录消息
type MsgLogin struct {MsgHeader                // 继承 MsgHeaderChargePileID    [7]byte  `json:"ChargePileID"`    // 充电桩IDChargePileType  byte     `json:"ChargePileType"`  // 充电桩类型ChargeShotNum   byte     `json:"ChargeShotNum"`   // 充电枪数量ProtocolVersion byte     `json:"ProtocolVersion"` // 协议版本ProgramVersion  [8]byte  `json:"ProgramVersion"`  // 程序版本NetType         byte     `json:"NetType"`         // 网络类型SIM             [10]byte `json:"SIM"`             // SIM卡信息NetCarrier      byte     `json:"NetCarrier"`      // 网络运营商// CheckSum        [2]byte  `json:"CheckSum"`        // 校验和
}// 0x02 MsgLoginRsp 登录响应消息
type MsgLoginRsp struct {MsgHeader            // 继承 MsgHeaderChargePileID [7]byte `json:"ChargePileID"` // 充电桩IDRet          byte    `json:"Ret"`          // 登录结果
}

1.2 充电桩启停充电消息定义


// 0x33
type MsgStartChargeRspToServer struct {MsgHeader              // 继承 MsgHeaderTransactionID [16]byte `json:"TransactionID"` // 交易流水号ChargePileID  [7]byte  `json:"ChargePileID"`  // 桩编号ChargeGunID   byte     `json:"ChargeGunID"`   // 枪号Ret           byte     `json:"Ret"`           // 启动结果 0x00失败 0x01成功FailCode      byte     `json:"FailCode"`      // 失败原因
}// 0x34
type MsgStartChargeToDevice struct {MsgHeader               // 继承 MsgHeaderTransactionID  [16]byte `json:"TransactionID"`  // 交易流水号ChargePileID   [7]byte  `json:"ChargePileID"`   // 桩编号ChargeGunID    byte     `json:"ChargeGunID"`    // 枪号LogicalCardID  [8]byte  `json:"LogicalCardID"`  // 显示在屏幕上,不足补零,逻辑卡号为卡面印刷卡号PhysicalCardID [8]byte  `json:"PhysicalCardID"` // 不足补零,桩与平台交互需使用的物理卡号Balance        [4]byte  `json:"Balance"`        // 账户余额,保留到小数点两位
}

// 0x35
type MsgStopChargeRspToServer struct {MsgHeader            // 继承 MsgHeaderChargePileID [7]byte `json:"ChargePileID"` // 桩编号ChargeGunID  byte    `json:"ChargeGunID"`  // 枪号Ret          byte    `json:"Ret"`          // 启动结果 0x00失败 0x01成功FailCode     byte    `json:"FailCode"`     // 0x00 无 0x01 设备编号不匹配 0x02 枪未处于充电状态 0x03 其他
}// 0x36
type MsgStopChargeToDevice struct {MsgHeader            // 继承 MsgHeaderChargePileID [7]byte `json:"ChargePileID"` // 桩编号ChargeGunID  byte    `json:"ChargeGunID"`  // 枪号
}

1.3 ModBusCRC校验实现


func ModbusCRC(pData []byte, lenData byte) (byte, byte) {var (crcHi byte = 0xFFcrcLo byte = 0xFFidx   byte)crchi := []byte{0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41,0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,0x80, 0x41, 0x00, 0xc1, 0x81, 0x40}crclow := []byte{0x00, 0xc0, 0xc1, 0x01, 0xc3, 0x03, 0x02, 0xc2, 0xc6, 0x06,0x07, 0xc7, 0x05, 0xc5, 0xc4, 0x04, 0xcc, 0x0c, 0x0d, 0xcd,0x0f, 0xcf, 0xce, 0x0e, 0x0a, 0xca, 0xcb, 0x0b, 0xc9, 0x09,0x08, 0xc8, 0xd8, 0x18, 0x19, 0xd9, 0x1b, 0xdb, 0xda, 0x1a,0x1e, 0xde, 0xdf, 0x1f, 0xdd, 0x1d, 0x1c, 0xdc, 0x14, 0xd4,0xd5, 0x15, 0xd7, 0x17, 0x16, 0xd6, 0xd2, 0x12, 0x13, 0xd3,0x11, 0xd1, 0xd0, 0x10, 0xf0, 0x30, 0x31, 0xf1, 0x33, 0xf3,0xf2, 0x32, 0x36, 0xf6, 0xf7, 0x37, 0xf5, 0x35, 0x34, 0xf4,0x3c, 0xfc, 0xfd, 0x3d, 0xff, 0x3f, 0x3e, 0xfe, 0xfa, 0x3a,0x3b, 0xfb, 0x39, 0xf9, 0xf8, 0x38, 0x28, 0xe8, 0xe9, 0x29,0xeb, 0x2b, 0x2a, 0xea, 0xee, 0x2e, 0x2f, 0xef, 0x2d, 0xed,0xec, 0x2c, 0xe4, 0x24, 0x25, 0xe5, 0x27, 0xe7, 0xe6, 0x26,0x22, 0xe2, 0xe3, 0x23, 0xe1, 0x21, 0x20, 0xe0, 0xa0, 0x60,0x61, 0xa1, 0x63, 0xa3, 0xa2, 0x62, 0x66, 0xa6, 0xa7, 0x67,0xa5, 0x65, 0x64, 0xa4, 0x6c, 0xac, 0xad, 0x6d, 0xaf, 0x6f,0x6e, 0xae, 0xaa, 0x6a, 0x6b, 0xab, 0x69, 0xa9, 0xa8, 0x68,0x78, 0xb8, 0xb9, 0x79, 0xbb, 0x7b, 0x7a, 0xba, 0xbe, 0x7e,0x7f, 0xbf, 0x7d, 0xbd, 0xbc, 0x7c, 0xb4, 0x74, 0x75, 0xb5,0x77, 0xb7, 0xb6, 0x76, 0x72, 0xb2, 0xb3, 0x73, 0xb1, 0x71,0x70, 0xb0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9c, 0x5c,0x5d, 0x9d, 0x5f, 0x9f, 0x9e, 0x5e, 0x5a, 0x9a, 0x9b, 0x5b,0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4b, 0x8b,0x8a, 0x4a, 0x4e, 0x8e, 0x8f, 0x4f, 0x8d, 0x4d, 0x4c, 0x8c,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,0x43, 0x83, 0x41, 0x81, 0x80, 0x40}for ; lenData > 0; lenData-- {idx = crcHi ^ pData[0]pData = pData[1:]crcHi = crcLo ^ crchi[idx]crcLo = crclow[idx]}// return uint16(crcHi)<<8 | uint16(crcLo)return crcHi, crcLo
}

 2 Websocket Server + SSL证书:提供小程序端通信服务

func WssServer() {http.HandleFunc("/websocket", handleClient)fmtPrintf("[WebSocket] Server listening on %s", GlobalConfig.WebSocketAddr)fmtPrintf("[WebSocket] Cert: %s, Key: %s ", GlobalConfig.ProtocolCert, GlobalConfig.ProtocolPrivateKey)err := http.ListenAndServeTLS(GlobalConfig.WebSocketAddr, GlobalConfig.ProtocolCert, GlobalConfig.ProtocolPrivateKey, nil)if err != nil {fmtPrintf("WebSocket server err:%v", err)}go wsClientsKeepalive()
}

3 Websocket Client 小程序端:含断线重连,保证客户端一个始终一个连接

// utils/webSocketManager.js
import util from 'util.js';
const webSocketManager = (() => {let socket;let reconnectTimer; // 用于存储定时器ID,用于重连const MAX_RECONNECT_TIMES = 10; // 最大重连次数const RECONNECT_INTERVAL = 3000; // 重连间隔时间,单位毫秒const initWebSocket = (url) => {util.log('WebSocket【initWebSocket】 连接:', url);if (socket && socket.readyState === 1) {util.log('WebSocket【initWebSocket】已连接,无需重新初始化 ');return;}socket = wx.connectSocket({ url: url });socket.onOpen(() => {util.log('WebSocket 【onOpen】');// 连接成功后发送loginwx.getStorage({key: "openid",success(res) {if(res.data == null) {util.log("initWebSocket close socket openid null ")close()}let dataObj = {  cmd: 'login',  src: 'wx',dst: 'wx',uid:  res.data,  msg: null,  }; send(dataObj);},fail (res) {   util.log("initWebSocket close socket wx.getStorage err: ", res)close()},})});socket.onMessage((res) => {util.log('WebSocket 【onMessage】:', res.data);// 在这里处理接收到的消息var obj = JSON.parse(res.data)// if (obj.cmd == "wx_requestPayment"){//   var msg = JSON.parse(obj.msg)//   wx.requestPayment({//     "timeStamp": msg.timeStamp,//     "nonceStr": msg.nonceStr,//     "package": msg.package,//     "signType": msg.signType,//     "paySign": msg.paySign,//     "success":function(res){//       util.log("requestPayment ok")//     },//     "fail":function(res){//       util.log("requestPayment fail",res)//     }//   })// }});socket.onError((err) => {// 这里可以处理错误情况,例如关闭socketutil.log('WebSocket 【onError】连接已已出错,',err);});socket.onClose(() => {// 这里可以处理错误情况,例如关闭socketutil.log('WebSocket 【onClose】连接已关闭,尝试重连...');// 当连接关闭时,也尝试重连if (!reconnectTimer && socket.readyState !== 1) {reconnectTimer = setInterval(() => {if (socket.readyState !== 1) {initWebSocket(url);} else {clearInterval(reconnectTimer);reconnectTimer = null;}}, RECONNECT_INTERVAL);}});};const send = (data) => {if (socket && socket.readyState === 1) {var messageStr = JSON.stringify(data);util.log('WebSocket 【send】:', messageStr);socket.send({data: messageStr});} else {util.warn('WebSocket未连接,无法发送消息');}};const close = () => {if (socket) {socket.close();// 清除重连定时器if (reconnectTimer) {clearInterval(reconnectTimer);reconnectTimer = null;}}};return {initWebSocket,send,close,};
})();export default webSocketManager;

4 HTTP+SSL证书服务:提供小程端通信服务


func HttpsServer() {// 加载证书和私钥cert, err := tls.LoadX509KeyPair(GlobalConfig.ProtocolCert, GlobalConfig.ProtocolPrivateKey)if err != nil {fmtPrintf("HttpsServer %v", err)}// 配置TLSconfig := &tls.Config{Certificates: []tls.Certificate{cert},}// 创建一个新的ServerMux实例(默认情况下,http.HandleFunc就是使用这个实例)mux := http.NewServeMux()// 注册处理程序// mux.HandleFunc("/", handler)mux.HandleFunc("/wx_notify_url", handle_wx_notify_url)// 监听端口并启动服务器srv := &http.Server{Addr:      GlobalConfig.HttpsAddr, // 或者使用其他端口,但443是HTTPS的标准端口Handler:   mux,TLSConfig: config,}fmtPrintf("[Https] Server listening on %s", GlobalConfig.HttpsAddr)fmtPrintf("[Https] WXNotifyURL: %s", GlobalConfig.WXNotifyURL)if err := srv.ListenAndServeTLS("", ""); err != nil { // 空字符串意味着使用上面定义的config中的证书和私钥log.Fatal(err)}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868666.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式Linux系统编程 — 7.4 fork、vfork函数创建子进程

目录 1 父进程与子进程概念 2 fork创建子进程 3 系统调用 vfork()函数 4 vfork与 fork函数如何选择 1 父进程与子进程概念 进程与子进程是操作系统中的一个基本概念&#xff0c;用于描述进程之间的层级关系。下面是对这一概念的简要说明&#xff1a; 父进程&#xff1a;在…

从项目中初识Autosar状态机转换

目录 0 前言 1 状态转换 1.1 BSM TO RMS 1.2 RMS TO RSS 1.3 RMS TO NOS 1.4 RSS TO PBSM 1.5 PBSM TO BSM 1.6 RSS TO NOS 1.7 RSS TO RMS 2 结尾 0 前言 之前在这篇《从项目中初识Autosar网络管理》已经和大家讲了Autosar网络管理的几个状态机以及定时器的大致概念&a…

【网安播报】CocoaPods 曝关键漏洞,应用程序面临供应链攻击风险

1、CocoaPods 曝关键漏洞&#xff0c;数百万 macOS 和 iOS 应用程序面临供应链攻击风险 开源依赖管理器 CocoaPods 中的安全漏洞暴露了数千个软件包&#xff0c;利用这些漏洞的攻击者可以将恶意代码注入合法应用&#xff0c;通过受信任的渠道分发恶意软件&#xff0c;并破坏用户…

Qt QWizard新建向导实例

使用QWizard做新建向导&#xff0c;最简单的实例 class MyWizard : public QWizard { public: MyWizard(QWidget* parent nullptr); QWizardPage* createFirstPage(); QWizardPage* createSecondPage(); QWizardPage* createThirdPage(); }; MyWizard::MyWizard(QWidget* par…

最近点对问题(算法与数据结构设计)

课题内容和要求 最近点对问题&#xff0c;在二维平面上输入n个点列P。其中任一点pi&#xff08;xi&#xff0c;yi&#xff09;&#xff0c;编写程序求出最近的两个点。使用穷举法实现&#xff0c;算法复杂度O(n2)&#xff1b;优化算法&#xff0c;以O(nlog2n)实现这一问题 数…

静脉分割YOLOV8-SEG

静脉分割&#xff0c;YOLOV8*SEG资源-CSDN文库 首先使用YOLOV8-SEG训练&#xff0c;得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV的DNN调用&#xff0c;从而摆脱PYTORCH依赖&#xff0c;支持C,PYTHON,ANDROID调用

Java信号量semaphore的原理与使用方法

Semaphore的基本概念 在Java中&#xff0c;Semaphore是位于java.util.concurrent包下的一个类。它的核心就是维护了一个许可集。简单来说&#xff0c;就是有一定数量的许可&#xff0c;线程需要先获取到许可&#xff0c;才能执行&#xff0c;执行完毕后再释放许可。 那么&…

尚品汇-(十五)

&#xff08;1&#xff09;快速入门 SpringBoot形式创建 Maven形式创建&#xff1a; 加入依赖&#xff1a; 创建启动类&#xff1a; 设置头文件 就想Jsp的<%Page %>一样 &#xff0c;Thymeleaf的也要引入标签规范。不加这个虽然不影响程序运行&#xff0c;但是你的idea…

顶会FAST24最佳论文|阿里云块存储架构演进的得与失-4.EBS不同架构性能提升思路

3.1 平均延迟与长尾延迟 虚拟磁盘&#xff08;VD&#xff09;的延迟是由其底层架构决定的&#xff0c;具体而言&#xff0c;取决于请求所经历的路径。以EBS2为例&#xff0c;VD的延迟受制于两跳网络&#xff08;从BlockClient到BlockServer&#xff0c;再至ChunkServer&#x…

Xilinx FPGA:vivado关于IIC的一些零碎知识点

一、简介 IlC(inter-Integrated circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信&#xff0c;在小数据量场合使用&#xff0c;传输距离短&#xff0c;任意时刻只能有一个主机等特性…

13 协程设计原理与汇编实现

协程的问题 为什么要有协程?协程的原语操作?协程的切换?协程的struct如何定义?协程的scheduler(调度)如何定义?调度策略如何实现?协程如何与posix,api兼容?协程多核模式?协程的性能如何测试?为什么要有协程 同步的编程方式,异步的性能。同步编程时,我们需要等待io就…

信息技术课堂纪律管理:从混乱到秩序的智慧转型

引言&#xff1a; 在信息爆炸的时代&#xff0c;信息技术课程如同一把开启未来世界大门的钥匙&#xff0c;为学生们搭建起探索科技奥秘的桥梁。然而&#xff0c;面对着屏幕背后的无限诱惑&#xff0c;维持课堂纪律&#xff0c;确保学生们专注于学习&#xff0c;成为了每位信息…

C/C++内存分布

1.内存分布简略图 2.全局变量和静态变量的区别 (1)局部静态变量&#xff1a;存储在数据段中&#xff0c;局部静态变量的作用域在当前函数中&#xff0c;出了函数就不能使用该变量&#xff0c;但局部静态变量的生命周期是在整个程序间&#xff0c;局部静态变量要运行到这一行才…

【Java14】构造器

Java中的构造器在创建对象&#xff08;实例&#xff09;的时候执行初始化。Java类必须包含一个或一个以上的构造器。 Java中的构造器类似C中的构造函数。 Java中对象&#xff08;object&#xff09;的默认初始化规则是&#xff1a; 数值型变量初始化为0&#xff1b;布尔型变量…

【CSAPP】-cachelab实验

目录 实验目的与要求 实验设备与软件环境 实验过程与结果&#xff08;可贴图&#xff09; 操作异常问题与解决方案 实验总结 实验目的与要求 1、掌握应用程序性能的优化方法&#xff1b; 2、理解存储器层次结构在程序运行过程中所起的重要作用&#xff1b; 3、让学生更好…

高考志愿填报的六个不要

在高考志愿填报这个关键时刻&#xff0c;确实需要谨慎行事&#xff0c;避免一些常见的错误。以下是高考志愿填报的六个“不要”&#xff0c;希望能为你提供一些有用的建议&#xff1a; 1、不要盲目跟风 每个人的兴趣、能力和未来规划都不同&#xff0c;不要仅仅因为某个专业或…

Gradle基础:从入门到掌握

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 在现代软件开发中&#xff0c;自动化构建工具是提高效率和管理依赖的重要手段。而Gradle作为一种灵活且强大的构…

python基础篇(9):模块

1 模块简介 Python 模块(Module)&#xff0c;是一个 Python 文件&#xff0c;以 .py 结尾. 模块能定义函数&#xff0c;类和变量&#xff0c;模块里也能包含可执行的代码. 模块的作用: python中有很多各种不同的模块, 每一个模块都可以帮助我们快速的实现一些功能, 比如实现…

工业4.0视角下:PLC转OPC UA网关的作用

在工业自动化领域&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;是常见的控制设备&#xff0c;而OPC UA&#xff08;开放型工业自动化统一架构&#xff09;协议则是一种现代化的通信协议&#xff0c;用在工厂自动化系统中实现设备之间的数据交换和通信。PLC转OPC U…

TensorRT动态形状(Dynamic Shape)出错,官方demo+自己模型运行时出错

(2024.7.2) 使用TensorRT处理动态输入形状推理时出现的错误&#xff0c;本案基于官方demo文件&#xff0c;已解决&#xff1a; TensorRT版本10.0&#xff0c;官方例子使用的是这个https://github.com/NVIDIA/trt-samples-for-hackathon-cn/blob/master/cookbook/01-SimpleDem…