• ocpp-远程启动(RemoteStartTransaction)、远程停止(RemoteStopTransaction)


    目录

    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


    1、介绍

             远程启动与停止一般是在小程序或者App端发起;

             启动的支付方式可以用余额支付、优惠劵支付、微信支付、支付宝支付等等,当前主流的支付方式;

            启动时创建充电桩-枪对应的充电记录信息;

    2、远程启动-RemoteStartTransaction

    @Autowired
    OcppRechongFeign ocppRechongFeign;

    /**
    * 开始充电
    *
    * @param map 充电订单的信息
    * @return
    */
    public ReturnData startRecharge(Map map, String AppId,Object userId) {

            ReturnData returnData = new ReturnData();

            log.info("startRecharge=参数{}", JSON.toJSONString(map));

            returnData = ocppRechongFeign.startRecharge();

    }

    3、远程停止-RemoteStopTransaction

    /**
    * 结束充电
    *
    * @param map
    * @return
    */
    public ReturnData endRecharge(Map 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;
    }

    4、代码

    4.1 OcppRechongFeign

    public interface OcppRechongFeign {

    /**
    * 开始充电
    * @param map
    * @return
    */
    @PostMapping("/cmd/equStartRecharge.jk")
    ReturnData startRecharge(@RequestBody Map map);

    /**
    * 停止充电
    * @param map
    * @return
    */
    @PostMapping("/cmd/equEndRecharge.jk")
    ReturnData equEndRecharge(@RequestBody Map map);

    }

    4.2 CmdController

    @RestController
    @Slf4j
    @RequestMapping("cmd")

    public class CmdController {

    /**
    * 开始充电
    * @param map
    * @return
    */
    @RequestMapping("equStartRecharge.jk")
    public ReturnData equStartRecharge(@RequestBody Map map){
        log.info("接收到的参数{}", JSON.toJSONString(map));
        ReturnData returnData=cmdService.equStartRecharge(map);
        return returnData;
    }
    /**
    * 停止充电
    * @param map
    * @return
    */
    @RequestMapping("equEndRecharge.jk")
    public ReturnData equEndRecharge(@RequestBody Map map){
        log.info("停止充电接收到的参数{}", JSON.toJSONString(map));
        ReturnData returnData=cmdService.equEndRecharge(map);
        return returnData;
    }

    }

    4.3 CmdService

    @Slf4j
    @Service
    public class CmdService {

    /**
    * 开始充电
    * @param
    * @return

    * [2,"4f08e280-b5b2-4197-82ef-f10a1f351fcb","RemoteStartTransaction",{"connectorId":1,"idTag":"C35CEA09"}]
    */
    public ReturnData equStartRecharge(Map map){
    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(Map map){
    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;
    }

    }

    4.4 RemoteStartTransactionReq

    import lombok.Data;
    /**
    * 远程启动充电 6.33. RemoteStartTransaction.req
    */
    @Data
    public class RemoteStartTransactionReq {
        private Integer connectorId; //可选。要启动事务的连接器的编号。连接器Id应为>值0
        private String idTag;// 必填。收费点在启动事务处理时必须使用的标识符
    }

    4.5 接收报文-DataAnalysisController

    /**
    * 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;
     }
    }

    4.6 接收报文实现类-DataAnalysisService

    @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;
    }

    4.7 StartTransactionReq

    /**
    * 开启充电事务
    */
    @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;
    }

    4.8 StartTransactionConfig

    /**
    * 开始充电事务
    */

    @Data
    public class StartTransactionConfig {

    // idtag信息
    // private IdTagInfo info;
    private IdTagInfo idTagInfo;

    //中央平台控制的事务ID
    private Integer transactionId;


    }

    4.9 AuthorizeConfig

    import lombok.Data;

    /**
    * 授权配置
    */
    @Data
    public class AuthorizeConfig {

    private IdTagInfo idTagInfo;
    }

    4.10 IdTagInfo

    /**
    *
    * 授权token回复详细信息
    */
    @Data
    public class IdTagInfo {
    // Accepted 允许使用可充电的标识符
    // Blocked 标识符已被阻止。不允许充电。
    // Expired 标识符已过期。不允许充电。
    // Invalid 标识符未知。不允许充电。
    // ConcurrentTx 标识符已涉及到另一个事务中,并且不允许有多个事务。(仅与StartTransaction.req相关。)
    private String status;
    // 这其中包含idTag应该从授权缓存中删除的日期。
    private String expiryDate;
    //private IdToken idToken;//父级标识符。
    }

    4.11 DateUtil

    /**
    * 得到 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;
    }

  • 相关阅读:
    nginx的正则回溯和灾难性回溯
    微信小程序测试策略和注意事项?
    09【Set 和 Map 数据结构】
    Docker 镜像管理
    大数据——Spark SQL
    元宇宙技术在几年后质变,迎来体验终端世界
    算法系列一:顺序查找、二分查找、分块查找
    MATLAB基础应用精讲-【基础知识篇】MATLAB特点及应用领域
    SparkSQL系列-8、分布式SQL引擎和Catalyst 优化器
    【Java】人工智能交互智慧导诊系统源码
  • 原文地址:https://blog.csdn.net/zw899004/article/details/133881851