# OCPP [toc] # Interface standards for electric vehicles ![](https://cdn-ak.f.st-hatena.com/images/fotolife/y/yomon8/20210308/20210308084448.png) ![](https://www.incibe-cert.es/sites/default/files/blog/2020/ComunicacionesEstacionesCarga/estandar-vehiculos-electricos-eng.jpg) [嘗試在 Python 和 OSS 中與 SteVe 一起使用 OCPP(開放充電點協議)](https://yomon.hatenablog.com/entry/try_ocpp_with_steve) # 第四、五章 Operations Initiated by Charge Point&Central System(Message) 檔案名稱==ocpp_def.h== `include OCPP16JAPP.h` Charge Point: <span style= "background:lightblue" >XXXXXX</span> Central System: <span style= "background:orange" >XXXXXX</span> | | Abbreviations |request(.req)|configuration(.conf) |:------------:|:-------------:| :-------------:| :-------------:| | <span style= "background:lightblue">Authorize</span>| sAuth |O|O| |<span style= "background:lightblue">Start Transaction</span>|sStartTxn|O|O| |<span style= "background:lightblue">Stop Transaction</span>| sStopTxn |O|O| |<span style= "background:lightblue">Status Notification</span>|sStatusNotif|O|X| |<span style= "background:lightblue">Diagnostics Status Notification</span>|sDiagStatusNotif |O|X| |<span style= "background:lightblue">Firmware Status Notification</span>|sFwStatusNotif|O|X| | <span style= "background:orange" > Cancel Reservation</span> | sCancelRsrv |O|O| | <span style= "background:orange" > Change Availability</span> | sChngAvail |O|O| | <span style= "background:orange" > Change Configuration</span> | sChngConfig |O|O| | <span style= "background:orange" > Clear Cache</span> | sClrCache |X|O| | <span style= "background:orange" > Data Transfer</span> | sDataTxfer |O|O| | <span style= "background:orange" >Get Configuration</span>| sGetConfig |O|O| | <span style= "background:orange" >Get Diagnostics</span>| sGetDiag |O|O| | <span style= "background:orange" >Get Local List Version| sGetLocalListVer |X|O| | <span style= "background:orange" >Remote Start Transaction</span>| sRemoteStartTxn |O|O| | <span style= "background:orange" >Remote Stop Transaction</span>| sRemoteStopTxn |O|O| | <span style= "background:orange" >Reserve Now</span>| sRsrvNow |O|O| | <span style= "background:orange" >Reset</span>| sRst |O|O| | <span style= "background:orange" >Send Local List</span>| sSendLocalList |X|O| | <span style= "background:orange" >Unlock Connector Transaction</span>| sUnlockConntr |O|O| | <span style= "background:orange" >Update Firmware</span>| sUpdateFW |O|O| :::info <font color="#f00">紅色代表:uint8_t</font> <font color="#0f0">綠色代表:int8_t</font> <font color="#00f">藍色代表:uint32_t</font> <font color="#f0f">粉色代表:int32_t</font> <font color="#ff0">黃色代表:double</font> ::: 結構 tOCPPShM_t >sOCPP >><font color="#f00">InitNOK、InitMemErr、IsUp2ndFW、IsChgrLocked、CmdSend[4]</font>、<font color="#f0f">ConfStatus、OutCurrLimit</font>、 <font color="#ff0">OutPwrLimit</font> >>##########以下為Charge Point相關########## >>sAuth >>>sReq:{<font color="#f00">IdTag[20]</font>} >>>sConf:{<font color="#f00">ParentIdTag[20]、Status</font>、<font color="#f0f">ExpDate</font>} >>sStartTxn >>>sReq:{<font color="#f00">IdTag[20]</font>、<font color="#f0f">ConnID、Time、MeterStart、RsrvID</font>} >>>sConf:{<font color="#f00">ParentIdTag[20]、Status</font>、<font color="#f0f">TransID、ExpDate</font>} >>sStopTxn >>>sReq:{<font color="#f00">IdTag[20]</font>、<font color="#f0f">TransID、Time、MeterStop</font>} >>>sConf:{<font color="#f00">ParentIdTag[20]、Status</font>、<font color="#f0f">ExpDate</font>} >>sStatusNotif >>>sReq:{<font color="#f00">Status、ErrCode、Info[50]、VendorID[255]、VendorErrCode[50]</font>、<font color="#f0f">ConnID、Time</font>} >>sDiagStatusNotif >>>sReq:{<font color="#f00">status</font>} >>sFwStatusNotif >>>sReq:{<font color="#f00">Status</font>} >>##########以下為Central System相關########## >>sCancelRsrv >>>sReq:{<font color="#f0f">RsrvID</font>} >>>sConf:{<font color="#f00">Status</font>} >>sChngAvail >>>sReq:{<font color="#f00">Type</font>、<font color="#f0f">ConnID</font>} >>>sConf:{<font color="#f00">Status</font>} >>sChngConfig >>>sReq:{<font color="#f00">Key[50]、Value[500]</font>} >>>sConf:{<font color="#f00">Status</font>} >>sClrCache >>>sConf:{<font color="#f00">Status</font>} >>sDataTxfer >>>sReq:{<font color="#f00">VendorID[255]、MsgID[50]</font>} >>>sConf:{<font color="#f00">Status</font>} >>sGetConfig >>>sReq:{<font color="#f00">Key[10][32]</font>、<font color="#f0f">SizeKey</font>} >>>sConf:{<font color="#f00">SizeKey、SizeUnkey、KeyValue[19]:{Key[32]、RO、Value[64]}</font>} >>sGetDiag >>>sReq:{<font color="#f00">Location[500]、CmdUpDiag</font>、<font color="#f0f">Retries、RetryInterval、StartTime、StopTime</font>} >>>sConf:{<font color="#f00">FileName[255]</font>} >>sGetLocalListVer >>>sConf:{<font color="#f0f">Version</font>} >>sRemoteStartTxn >>>sReq:{<font color="#f00">IdTag[20]</font>、<font color="#f0f">ConnID</font>} >>>sConf:{<font color="#f00">Status</font>} >>sRemoteStopTxn >>>sReq:{<font color="#f0f">TransID</font>} >>>sConf:{<font color="#f00">Status</font>} >>sRsrvNow >>>sReq:{<font color="#f00">IdTag[20]、ParentID[20]</font>、<font color="#f0f">ConnID、ExpiryDate、RsrvID</font>} >>>sConf:{<font color="#f00">Status、Occupied</font>} >>sRst >>>sReq:{<font color="#f00">Type</font>} >>>sConf:{<font color="#f00">Status</font>} >>sSendLocalList >>>sConf:{<font color="#f00">Status</font>} >>sUnlockConntr >>>sReq:{<font color="#f0f">ConnID</font>} >>>sConf:{<font color="#f00">Status</font>} >>sUpdateFW >>>sReq:{<font color="#f00">Location[500]</font>、<font color="#f0f">RetrieveDate、Retries、RetryInterval</font>} >>>sConf:{<font color="#f0f">Update</font>} >sAuth >><font color="#f00">InitNOK、DevNOK、FwUpNOK、InitMemErr、IsWaitTimeUp、Authed、Ok2Chg、CmdRst、CmdRemoteStart、NtfUnplug、ChgUsrID[64]、StopReason、GunSelect</font>、<font color="#00f">CardMoney、InAcWh</font>、<font color="#f0f">TransID、TransID_Up</font> --- ## 參考資料 [啟動 docker-compose 發生 ERROR](https://oranwind.org/-solution-qi-dong-docker-compose-fa-sheng-error-couldnt-connect-to-docker-daemon-at-httpdockerlocalunixsocket-is-it-running-cuo-wu/) ![](https://cdn-ak.f.st-hatena.com/images/fotolife/y/yomon8/20210310/20210310221753.png) [SteVe 和 Charge Point](https://yomon.hatenablog.com/entry/try_ocpp_with_steve) [最簡單完整的libwebsockets的例子](https://www.twblogs.net/a/5e6b1590bd9eee211685ec6d) ## MessageType process ```c #include <stdio.h> #include <string.h> static unsigned char MessageType(unsigned char *str) { unsigned char *Sptr,*Eptr; int i,len; if((Sptr=strstr(str,"["))==NULL) return 0; if((Eptr=strstr(Sptr,","))==NULL) return 0; len=Eptr-Sptr; printf("str: %s\nSptr: %s\nEptr: %s\nlen: %d\n",str,Sptr,Eptr,len); printf("Sptr: 0x%x\n",*Sptr); Sptr++; printf("Sptr++: 0x%x\n",*Sptr); for(i=0;i<len;i++) { if((*(Sptr+i)>=0x32)&&(*(Sptr+i)<=0x34)) return (*(Sptr+i)&0x0F); } return 0; } int main() { char pu8SendBuf[1024*10]; unsigned char MsgType=0; sprintf(pu8SendBuf, "[2,\"%s\",{\"status\":\"%s\"}]" , "19223201" , "Accepted"); MsgType = MessageType(pu8SendBuf); printf("MsgType: %d\n",MsgType); return 0; } ``` ## UniqueID ```c #include <stdio.h> #include <string.h> static int UniqueID(unsigned char *str,unsigned char *UniID) { unsigned char *Sptr,*Eptr; int i,len; if((Sptr=strstr(str,","))==NULL) return 0; printf("Sptr: 0x%x\n",*Sptr);//, Sptr++; printf("Sptr++: 0x%x\n",*Sptr);//" if((Eptr=strstr(Sptr,","))==NULL) return 0; len=Eptr-Sptr; printf("len: %d\n",len); for(i=0;i<len;i++) { if(*(Sptr+i)==0x22) { Sptr+=i; break; } } if(i==len) return 0; memset(UniID,0,strlen(UniID)); Sptr++; len-=i; for(i=0;i<len;i++) { if(*(Sptr+i)==0x22) { *(UniID+i)=0x00; printf("UniID+%d: %s\n", i,(UniID+i)); break; } *(UniID+i)=*(Sptr+i); printf("UniID+%d: %s\n", i,(UniID+i)); } return i; } int main() { char pu8SendBuf[1024*10]; char pu8UniqID[64]; sprintf(pu8SendBuf, "[2,\"%s\",{\"status\":\"%s\"}]" , "19223201" , "Accepted"); UniqueID(pu8SendBuf, pu8UniqID); printf("pu8UniqID: %s\n", pu8UniqID); return 0; } ``` ## GetPayloadString ```c #include <stdio.h> #include <string.h> static int GetPayloadString(unsigned char *str,unsigned char *Pattern, unsigned char *Data) { unsigned char *Sptr,*Eptr,Flag=0; int i,k=0; if(strlen(str)<=0) return 0; if((Sptr=strstr(str,Pattern))==NULL) return 0; printf("Sptr: %s\n", Sptr); Sptr+=strlen(Pattern); for(i=0;;i++) { if(*(Sptr+i)==':') break; if(*(Sptr+i)==0x00) return 0; } Sptr+=(i+1); printf("Sptr+=(%d+1): %s\n", i, Sptr); for(i=0;;i++) { if(Flag==1) { *(Data+k)=*(Sptr+i); printf("Flag_%d=>(Data+%d): %c\n", Flag, k, *(Sptr+i)); k++; } if(*(Sptr+i)==0x22)//0x22=> " Flag++; if(Flag==2) { *(Data+(k-1))=0x00; printf("Flag_%d: %s\n", Flag, Data); return Sptr+i-str; } if(*(Sptr+i)==0x00) return 0; } } int main() { char pu8SendBuf[1024*10]; char pu8UniqID[64]; sprintf(pu8SendBuf, "[2,\"%s\",{\"status\":\"%s\"}]" , "19223201" , "Accepted"); GetPayloadString(pu8SendBuf,"status", pu8UniqID); printf("GetPayloadString: %s\n", pu8UniqID); return 0; } ``` ## UtcToEpoch ```c #include <stdio.h> #include <string.h> #include <time.h> static int GetPayloadString(unsigned char *str,unsigned char *Pattern, unsigned char *Data) { unsigned char *Sptr,*Eptr,Flag=0; int i,k=0; if(strlen(str)<=0) return 0; if((Sptr=strstr(str,Pattern))==NULL) return 0; printf("Sptr: %s\n", Sptr); Sptr+=strlen(Pattern); for(i=0;;i++) { if(*(Sptr+i)==':') break; if(*(Sptr+i)==0x00) return 0; } Sptr+=(i+1); printf("Sptr+=(%d+1): %s\n", i, Sptr); for(i=0;;i++) { if(Flag==1) { *(Data+k)=*(Sptr+i); printf("Flag_%d=>(Data+%d): %c\n", Flag, k, *(Sptr+i)); k++; } if(*(Sptr+i)==0x22)//0x22=> " Flag++; if(Flag==2) { *(Data+(k-1))=0x00; printf("Flag_%d: %s\n", Flag, Data); return Sptr+i-str; } if(*(Sptr+i)==0x00) return 0; } } void show(unsigned char *O, unsigned char *F) { unsigned char TmpData[8]; memset(TmpData,0,sizeof(TmpData)); printf("-----------------------\naddr: O(%p) F(%p) \n", O, F); printf("S: %s\n", O); printf("F: %s\n", F); memcpy(TmpData,O,F-O); printf("TmpData: %s\n", TmpData); } static unsigned int UtcToEpoch(unsigned char *UtcDataTime) { //YYYY-MM-DDTHH:MM:SS , return UTC+00:00 unsigned char TmpData[8],*Sptr,*Eptr; struct tm tm; unsigned int TimeZone=0,EpochTime=0; memset(&tm,0,sizeof(struct tm)); //year memset(TmpData,0,sizeof(TmpData)); if((Sptr=strstr(UtcDataTime,"-"))==NULL) return 0; memcpy(TmpData,UtcDataTime,Sptr-UtcDataTime); show(UtcDataTime,Sptr); tm.tm_year=atoi(TmpData)-1900; Sptr++; //month memset(TmpData,0,sizeof(TmpData)); if((Eptr=strstr(Sptr,"-"))==NULL) return 0; memcpy(TmpData,Sptr,Eptr-Sptr); show(Sptr,Eptr); tm.tm_mon=atoi(TmpData)-1; Eptr++; //day memset(TmpData,0,sizeof(TmpData)); if((Sptr=strstr(Eptr,"T"))==NULL) return 0; memcpy(TmpData,Eptr,Sptr-Eptr); show(Eptr,Sptr); tm.tm_mday=atoi(TmpData); Sptr++; //HH memset(TmpData,0,sizeof(TmpData)); if((Eptr=strstr(Sptr,":"))==NULL) return 0; memcpy(TmpData,Sptr,Eptr-Sptr); show(Sptr,Eptr); tm.tm_hour=atoi(TmpData); Eptr++; //MM memset(TmpData,0,sizeof(TmpData)); if((Sptr=strstr(Eptr,":"))==NULL) return 0; memcpy(TmpData,Eptr,Sptr-Eptr); show(Eptr,Sptr); tm.tm_min=atoi(TmpData); Sptr++; //SS memset(TmpData,0,sizeof(TmpData)); if((Eptr=strstr(Sptr,"Z"))!=NULL) { memcpy(TmpData,Sptr,Eptr-Sptr); show(Sptr,Eptr); tm.tm_sec=atoi(TmpData); EpochTime=(unsigned int)mktime(&tm); } else if((Eptr=strstr(Sptr,"+"))!=NULL) { memcpy(TmpData,Sptr,Eptr-Sptr); tm.tm_sec=atoi(TmpData); EpochTime=(unsigned int)mktime(&tm); Eptr++; memset(TmpData,0,sizeof(TmpData)); if((Sptr=strstr(Eptr,":"))!=NULL) { memcpy(TmpData,Eptr,Sptr-Eptr); TimeZone=atoi(TmpData)*60*60; Sptr++; memset(TmpData,0,sizeof(TmpData)); strcpy(TmpData,Sptr); TimeZone+=(atoi(TmpData)*60); } else { strcpy(TmpData,Eptr); TimeZone=atoi(TmpData)*60*60; } EpochTime-=TimeZone; } else if((Eptr=strstr(Sptr,"-"))!=NULL) { memcpy(TmpData,Sptr,Eptr-Sptr); tm.tm_sec=atoi(TmpData); EpochTime=(unsigned int)mktime(&tm); Eptr++; memset(TmpData,0,sizeof(TmpData)); if((Sptr=strstr(Eptr,":"))!=NULL) { memcpy(TmpData,Eptr,Sptr-Eptr); TimeZone=atoi(TmpData)*60*60; Sptr++; memset(TmpData,0,sizeof(TmpData)); strcpy(TmpData,Sptr); TimeZone+=(atoi(TmpData)*60); } else { strcpy(TmpData,Eptr); TimeZone=atoi(TmpData)*60*60; } EpochTime+=TimeZone; } else if((Eptr=strstr(Sptr,"."))!=NULL) { memcpy(TmpData,Sptr,Eptr-Sptr); tm.tm_sec=atoi(TmpData); EpochTime=(unsigned int)mktime(&tm); } else EpochTime=(unsigned int)mktime(&tm); return EpochTime; } int main() { char pu8SendBuf[1024*10]; char ResponseCurrentTime[64]; unsigned int EpochTime = 0; sprintf(pu8SendBuf, "[3,\"%s\",{\"status\":\"%s\", \"currentTime\":\"%s\", \"heartbeatInterval\": 300}]" , "19223201" , "Accepted" , "2013-02-01T20:53:32.486Z" ); GetPayloadString(pu8SendBuf,"currentTime", ResponseCurrentTime); EpochTime = UtcToEpoch(ResponseCurrentTime); printf("-----------------------\nGetPayloadString: %s\nEpochTime: %d\n", ResponseCurrentTime,EpochTime); return 0; } ```