---
# System prepended metadata

title: OCPP

---

# 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;
}
```