目录
1、介绍
2、远程启动-RemoteStartTransaction
3、远程停止-RemoteStopTransaction
4、代码
4.1 OcppRechongFeign
4.2 CmdController
4.3 CmdService
4.4 RemoteStartTransactionReq
4.5 接收报文-DataAnalysisController
4.6 接收报文实现类-DataAnalysisService
4.7 StartTransactionReq
4.8 StartTransactionConfig
4.9 AuthorizeConfig
4.10 IdTagInfo
4.11 DateUtil
远程启动与停止一般是在小程序或者App端发起;
启动的支付方式可以用余额支付、优惠劵支付、微信支付、支付宝支付等等,当前主流的支付方式;
启动时创建充电桩-枪对应的充电记录信息;
@Autowired
OcppRechongFeign ocppRechongFeign;/**
* 开始充电
*
* @param map 充电订单的信息
* @return
*/
public ReturnData startRecharge(Mapmap, String AppId,Object userId) { ReturnData returnData = new ReturnData();
log.info("startRecharge=参数{}", JSON.toJSONString(map));returnData = ocppRechongFeign.startRecharge();
}
/**
* 结束充电
*
* @param map
* @return
*/
public ReturnData endRecharge(Map
ReturnData returnData = new ReturnData();
try {
log.info("测试小程序结束充电");
// 订单号
Object orderNumber = map.get("orderNumber");
log.info("订单编号"+orderNumber);
}
// 调用结束充电
log.info("调用结束充电");
returnData = ocppRechongFeign.equEndRecharge(map);
if (returnData.isResult()==true){
// 自己的业务处理
}
log.info("结果======"+JSON.toJSONString(returnData));
return returnData;
} catch (Exception e) {
log.error("结束充电异常", e);
returnData.setCode("111111");
returnData.setResult(false);
returnData.setMsg("结束充电失败" + e.getMessage());
}
return returnData;
}
public interface OcppRechongFeign {
/**
* 开始充电
* @param map
* @return
*/
@PostMapping("/cmd/equStartRecharge.jk")
ReturnData startRecharge(@RequestBody Mapmap);
/**
* 停止充电
* @param map
* @return
*/
@PostMapping("/cmd/equEndRecharge.jk")
ReturnData equEndRecharge(@RequestBody Mapmap);
}
@RestController
@Slf4j
@RequestMapping("cmd")public class CmdController {
/**
* 开始充电
* @param map
* @return
*/
@RequestMapping("equStartRecharge.jk")
public ReturnData equStartRecharge(@RequestBody Mapmap){
log.info("接收到的参数{}", JSON.toJSONString(map));
ReturnData returnData=cmdService.equStartRecharge(map);
return returnData;
}
/**
* 停止充电
* @param map
* @return
*/
@RequestMapping("equEndRecharge.jk")
public ReturnData equEndRecharge(@RequestBody Mapmap){
log.info("停止充电接收到的参数{}", JSON.toJSONString(map));
ReturnData returnData=cmdService.equEndRecharge(map);
return returnData;
}}
@Slf4j
@Service
public class CmdService {/**
* 开始充电
* @param
* @return* [2,"4f08e280-b5b2-4197-82ef-f10a1f351fcb","RemoteStartTransaction",{"connectorId":1,"idTag":"C35CEA09"}]
*/
public ReturnData equStartRecharge(Mapmap){
ReturnData returnData=new ReturnData();
try {
String orderId=map.get("id")+"";
// 设备sn
String sn=map.get("equSn")+"";
// 抢号
String socketNo=map.get("socketNo")+"";
//充电编号
String chargingNumber=map.get("chargingNumber")+"";
String ocppChargingNumber=String.valueOf(map.get("ocppChargingNumber"));
// String ip=map.get("ip")+"";
JSONObject resultJSONObj=new JSONObject();
String cmdStr="";
ArrayList arrayList=new ArrayList();
arrayList.add(2);
String msgId=UuidUtil.get32UUID();
arrayList.add(msgId);
String actiion="RemoteStartTransaction";
arrayList.add(actiion);
RemoteStartTransactionReq remoteStartTransactionReq =new RemoteStartTransactionReq();
// 抢号
remoteStartTransactionReq.setConnectorId(Integer.parseInt(socketNo));
// 自动生成的卡号
remoteStartTransactionReq.setIdTag(ocppChargingNumber);
// 卡号
// remoteStartTransactionReq.setIdTag("43AA3CA6");
arrayList.add(remoteStartTransactionReq);
cmdStr=JSON.toJSONString(arrayList);
resultJSONObj.put("ip",ip);
resultJSONObj.put("data",cmdStr);
log.info("开始充电发的报文{}",cmdStr);// 发送报文
nettyFeign.A4OutMessage(resultJSONObj.toJSONString());
returnData.setResult(true);
}catch (Exception e){
log.error("开始充电异常{}",e.getMessage());
e.printStackTrace();
returnData.setResult(false);
returnData.setMsg(e.getMessage());
}
return returnData;
}/**
* 停止充电
* @param
* @return
*/
public ReturnData equEndRecharge(Mapmap){
ReturnData returnData=new ReturnData();
try {
log.info("结束充电==========");
Long msgId=getRandom.nextNumber(2,"equEndRecharge");//消息ID
// String msgIdStr=HaxUtils.addZore(msgId+"",4);
// [2,"28f7d946-c019-4071-8800-8e07426836f2","RemoteStopTransaction",{"transactionId":12023}]
String cmdStr="";
ArrayList arrayList=new ArrayList();
arrayList.add(2);
// arrayList.add(OrderUtil.getOrderId());
String msgIdStr=UuidUtil.get32UUID();
arrayList.add(msgIdStr);
String actiion="RemoteStopTransaction";
arrayList.add(actiion);
// 订单编号
String orderId=map.get("id")+"";
RemoteStopTransaction remoteStopTransaction =new RemoteStopTransaction();
remoteStopTransaction.setTransactionId(Integer.parseInt(orderId));
redis.setex("sendData"+msgId,20,JSON.toJSONString(remoteStopTransaction));
arrayList.add(remoteStopTransaction);
cmdStr=JSON.toJSONString(arrayList);
log.info("停止充电发的报文{}",cmdStr);
// 业务逻辑处理
if (ip==null){
log.info("结束充电,结算订单,ip不存在,设备未连接");
returnData.setResult(false);
returnData.setMsg("设备未连接");
}else {
//结束充电
log.info("操作执行结束充电");
JSONObject resultJSONObj=new JSONObject();
resultJSONObj.put("ip",ip);
resultJSONObj.put("data",cmdStr);
MqttPushClient.publish(BusinessType.topIc,JSON.toJSONString(resultJSONObj));
boolean end=false;
}
returnData.setResult(end);
if (end){
returnData.setMsg("成功结束充电");
}else {
returnData.setMsg("结束充电失败");
}
}
}catch (Exception e){
log.error("结束充电异常{}",e.getMessage());
e.printStackTrace();
returnData.setMsg(e.getMessage()+"");
}
return returnData;
}}
import lombok.Data;
/**
* 远程启动充电 6.33. RemoteStartTransaction.req
*/
@Data
public class RemoteStartTransactionReq {
private Integer connectorId; //可选。要启动事务的连接器的编号。连接器Id应为>值0
private String idTag;// 必填。收费点在启动事务处理时必须使用的标识符
}
/**
* ocpp协议
*/
@Slf4j
@RestController
@RequestMapping("ocpp")
public class DataAnalysisController {
@Autowired
DataAnalysisService zhenwankejiDataAnalysisService;
@RequestMapping("/dataAnalysis")
public ReturnData dataAnalysis(@RequestBody String body){
ReturnData returnData=zhenwankejiDataAnalysisService.dataAnalysisService(body);
return returnData;
}
}
@Slf4j
@Service
public class DataAnalysisService {public ReturnData dataAnalysisService(String body) {
ReturnData returnData = new ReturnData();
try {
Cache redis=Redis.use();
String inputStr = "";
JSONObject inputJson = JSON.parseObject(body);
inputStr = inputJson.getString("data");
String ip = inputJson.getString("ip");
log.info("ocpp收到的上报信息报文{}", inputStr);
if(null!=inputStr && !"".equals(inputStr)){
// 获取消息状态
JSONArray jsonArray=JSON.parseArray(inputStr);
String msgType=jsonArray.getString(0);//消息类型
//消息ID
String msgId=jsonArray.getString(1); //消息ID
JSONObject actionJSON=new JSONObject();
String action="";
String sendData="";
if (jsonArray.size()==4){
action=jsonArray.getString(2);//action类型
//加密标识
actionJSON=jsonArray.getJSONObject(3);
}else if (jsonArray.size()==3){
actionJSON=jsonArray.getJSONObject(2);
action=redis.get("action"+msgId);
sendData=redis.get("sendData"+msgId);
if (sendData!=null){
log.info("下发的消息信息:{}"+sendData);
}
}
//帧类型标识
String cmd=action;
log.info("ocpp-cmd命令{}",cmd);
String data =actionJSON.toJSONString();
log.info("消息体{}", data);
String des3="";
if(null!=cmd && !"".equals(cmd)){
switch (cmd) {
// 开始充电事务
case "RemoteStartTransaction":
returnData = RemoteStartTransaction(data,msgId,msgType,action,
sendData,ip,body);
break;// 充电桩事务开启
case "StartTransaction":
returnData = StartTransaction(data,msgType,msgId,action,ip,body);
break;// 停止
case "StopTransaction":
returnData=stopTransaction(data,msgId,msgType,body);
}
if (returnData.isResult()) {//需要返回
JSONObject resultJsonObj = new JSONObject();
resultJsonObj.put("ip", inputJson.getString("ip"));
resultJsonObj.put("data", (returnData.getData()));
MqttPushClient.publish(BusinessType.topIc,JSON.toJSONString(resultJsonObj));
}
}else{
returnData=defaultInfos(data,msgId,msgType,ip,action,body);
}
}
} catch (Exception e) {
log.error("ocpp设备上报报文解析异常",e);
returnData.setResult(false);
returnData.setCode("111111");
returnData.setMsg("ocpp设备上报报文解析异常"+e.getLocalizedMessage());
}
return returnData;
}}
/**
* 开始充电事务
* 启动充点电返回
* @param data
* @param msgId
* @param msgType
* @param action
* @param sendData
* @return
*/
public ReturnData RemoteStartTransaction(String data,String msgId,
String msgType,String action,
String sendData,String ip,String body){
ReturnData returnData=new ReturnData();
try {
RemoteStartTransactionReq req= JSON.parseObject(sendData,RemoteStartTransactionReq.class);
JSONObject jsonObject=JSON.parseObject(data);
String status=jsonObject.getString("status");
if(OcppStatus.PREPARING.getCode().equals(status)){
returnData.setResult(true);
}
// 未插枪
else if(OcppStatus.AVALIABLE.getCode().equals(status)){
returnData.setResult(false);
returnData.setMsg("请先插枪");
}else if(OcppStatus.CHARGING.getCode().equals(status)){
returnData.setResult(false);
returnData.setMsg("请先插枪");
}else if(OcppStatus.ACCEPTED.getCode().equals(status)){
returnData.setResult(false);
returnData.setMsg("请先插枪");
}
}catch (Exception e){
log.error("收到充电点反馈,并且开启事务异常",e);
returnData.setResult(false);
}
return returnData;
}/**
* 充电桩事务开启
* 开始充电事务 data,msgType,msgId,action
* @param data
* @param msgType
* @param msgId
* @param action
* @return
*/
public ReturnData StartTransaction(String data, String msgType,String msgId,String action,String ip,String body) {
ReturnData returnData = new ReturnData();
try {
// [2,"QyVbJb28BEZfws6C","StartTransaction",{"connectorId":1,"idTag":"43AA3CA6","meterStart":0,"timestamp":"2023-08-14T05:54:03Z"}]
log.info("充电桩开启充电事务{}",data);
StartTransactionReq startTransactionReq=JSON.parseObject(data,StartTransactionReq.class);
String idTag=startTransactionReq.getIdTag();
// 抢号
int connectorId=startTransactionReq.getConnectorId();
log.info("idTag{} :",idTag);
StartTransactionConfig config=new StartTransactionConfig();
config.setTransactionId(transactionId);
IdTagInfo info=new IdTagInfo();
info.setStatus("Accepted");
config.setIdTagInfo(info);
List resultList=new ArrayList();
resultList.add(Integer.parseInt(msgType)+1);
resultList.add(msgId);
resultList.add(config);
log.info("开始事务配置数据:{}",JSON.toJSONString(resultList));
returnData.setData(JSON.toJSONString(resultList));
returnData.setResult(true);
return returnData;
}
returnData.setData("发起充电失败");
returnData.setResult(false);
return returnData;
}catch (Exception e){
log.error("开始充电事务异常{}",e);
returnData.setResult(false);
}
return returnData;
}
/**
* 开启充电事务
*/
@Data
public class StartTransactionReq {
private Integer connectorId;//充电枪号
private String idTag; //id标识
private Integer meterStart=0; // 这包含了事务开始时连接器的表值,单位为Wh。
private String timestamp;//时间戳
}/**
* 停止
* 停止操作
* @param data
* @param msgType
* @param msgId
* @return
*/
@Transactional
public ReturnData stopTransaction(String data,String msgId,String msgType,String body) {
ReturnData returnData=new ReturnData();
try {
IdTagInfo info=new IdTagInfo();
info.setStatus("Accepted");// 时间推迟60分钟
Date endDate=DateUtil.getAfterMinute(new Date(),60);// 转换为utc格式
String utcStr=DateUtil.localToUTC(endDate);
info.setExpiryDate(utcStr);
List resultList=new ArrayList();
resultList.add(Integer.parseInt(msgType)+1);
resultList.add(msgId);
AuthorizeConfig authorizeConfig=new AuthorizeConfig();
authorizeConfig.setIdTagInfo(info);
resultList.add(authorizeConfig);
returnData.setResult(true);
log.info("停止返回信息:{}",JSON.toJSONString(resultList));
String json=new ObjectMapper().writeValueAsString(resultList);
returnData.setData(json);
returnData=stopOrderInfo(JSON.parseObject(data),returnData,body);
}catch (Exception e){
log.error("停止点反馈,并且开启事务异常",e);
returnData.setResult(false);
}
return returnData;
}
/**
* 开始充电事务
*/
@Data
public class StartTransactionConfig {
// idtag信息
// private IdTagInfo info;
private IdTagInfo idTagInfo;
//中央平台控制的事务ID
private Integer transactionId;
}
import lombok.Data;
/**
* 授权配置
*/
@Data
public class AuthorizeConfig {
private IdTagInfo idTagInfo;
}
/**
*
* 授权token回复详细信息
*/
@Data
public class IdTagInfo {
// Accepted 允许使用可充电的标识符
// Blocked 标识符已被阻止。不允许充电。
// Expired 标识符已过期。不允许充电。
// Invalid 标识符未知。不允许充电。
// ConcurrentTx 标识符已涉及到另一个事务中,并且不允许有多个事务。(仅与StartTransaction.req相关。)
private String status;
// 这其中包含idTag应该从授权缓存中删除的日期。
private String expiryDate;
//private IdToken idToken;//父级标识符。
}
/**
* 得到 n分钟后的时间
*
* @param date
* @param minute
* @return
*/
public static Date getAfterMinute(Date date, Integer minute) {
long time = date.getTime();
time += minute * 1000 * 60;//在当前系统时间的基础上往后加minute分钟
return new Date(time);
}
/**
*
*Description: 本地时间转化为UTC时间
* @param localDate
* @return
* @author wgs
* @date 2018年10月19日 下午2:23:43
*
*/
public static String localToUTC(Date localDate) {
long localTimeInMillis=localDate.getTime();
/** long时间转换成Calendar */
Calendar calendar= Calendar.getInstance();
calendar.setTimeInMillis(localTimeInMillis);
/** 取得时间偏移量 */
int zoneOffset = calendar.get(java.util.Calendar.ZONE_OFFSET);
/** 取得夏令时差 */
int dstOffset = calendar.get(java.util.Calendar.DST_OFFSET);
/** 从本地时间里扣除这些差量,即可以取得UTC时间*/
calendar.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
/** 取得的时间就是UTC标准时间 */
Date utcDate=new Date(calendar.getTimeInMillis());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
String timeStr=df.format(utcDate);
return timeStr;
}