From 507b68c1f627b60d6929522ec7be185f9cd5498d Mon Sep 17 00:00:00 2001 From: aliml92 Date: Sun, 6 Nov 2022 17:45:01 +0900 Subject: [PATCH] add one test case --- README.md | 6 +- charge_point.go | 278 +++++++++++++++----------------- charge_point_test.go | 6 - client.go | 58 +++---- examples/README.md | 11 -- examples/client/client.go | 88 ++++------ examples/server/server.go | 111 +++---------- examples/temp_readme.txt | 0 messages.go | 330 ++++++++++++++++++-------------------- messages_test.go | 47 ++++++ server.go | 65 +++----- 11 files changed, 435 insertions(+), 565 deletions(-) delete mode 100644 charge_point_test.go delete mode 100644 examples/README.md delete mode 100644 examples/temp_readme.txt create mode 100644 messages_test.go diff --git a/README.md b/README.md index 95fa3c7..af79ef6 100644 --- a/README.md +++ b/README.md @@ -65,21 +65,17 @@ func main() // start csms server with default configurations csms = ocpp.NewServer() - - csms.AddSubProtocol("ocpp1.6") csms.SetCheckOriginHandler(func(r *http.Request) bool { return true }) csms.SetPreUpgradeHandler(customPreUpgradeHandler) csms.SetCallQueueSize(32) - // register charge-point-initiated action handlers csms.On("BootNotification", BootNotificationHandler) csms.After("BootNotification", SendChangeConfigration) - csms.On("Authorize", AuthorizationHandler) + csms.On("Authorize", AuthorizationHandler) csms.Start("0.0.0.0:8999", "/ws/", nil) - } func SendChangeConfigration(cp *ocpp.ChargePoint, payload ocpp.Payload) { diff --git a/charge_point.go b/charge_point.go index c0f6efc..d5319f9 100644 --- a/charge_point.go +++ b/charge_point.go @@ -14,14 +14,12 @@ import ( "github.com/gorilla/websocket" ) - -func init(){ +func init() { log = &logger.EmptyLogger{} } const ( - - ocppV16 = "ocpp1.6" + ocppV16 = "ocpp1.6" ocppV201 = "ocpp2.0.1" // Time allowed to wait until corresponding ocpp call result received @@ -38,7 +36,6 @@ const ( // Send pings to peer with this period. Must be less than pongWait. pingPeriod = (pongWait * 9) / 10 - ) // TODO: refactor or wrap with function @@ -54,85 +51,82 @@ func SetLogger(logger logger.Logger) { log = logger } - var ErrChargePointNotConnected = errors.New("charge point not connected") var ErrCallQuequeFull = errors.New("call queque full") var ErrChargePointDisconnected = errors.New("charge point disconnected unexpectedly") - // ChargePoint Represents a connected ChargePoint (also known as a Charging Station) type ChargePoint struct { // OCPP protocol version - proto string - + proto string + // the websocket connection - conn *websocket.Conn + conn *websocket.Conn // chargePointId - Id string - + Id string + // outgoing message channel - out chan []byte - + out chan []byte + // incoming message channel - in chan []byte - + in chan []byte + // mutex ensures that only one message is sent at a time - mu sync.Mutex - // crOrce carries CallResult or CallError - ocppRespCh chan OcppMessage - // Extras is for future use to carry data between different actions - Extras map[string]interface{} + mu sync.Mutex + // crOrce carries CallResult or CallError + ocppRespCh chan OcppMessage + // Extras is for future use to carry data between different actions + Extras map[string]interface{} // tc timeout config ensures a ChargePoint has its unique timeout configuration - tc TimeoutConfig + tc TimeoutConfig // isServer defines if a ChargePoint at server or client side - isServer bool + isServer bool // TODO: - validatePayloadFunc func(s interface{}) error + validatePayloadFunc func(s interface{}) error unmarshalResponseFunc func(a string, r json.RawMessage) (Payload, error) - - // ping in channel - pingIn chan []byte - + + // ping in channel + pingIn chan []byte + // closeC used to close the websocket connection by user - closeC chan websocket.CloseError + closeC chan websocket.CloseError // TODO - forceWClose chan error - connected bool + forceWClose chan error + connected bool // Followings used for sending ping messages - ticker *time.Ticker - tickerC <-chan time.Time - + ticker *time.Ticker + tickerC <-chan time.Time + // serverPing defines if ChargePoint is in server initiated ping mode - serverPing bool + serverPing bool - stopC chan struct{} - dispatcherIn chan *callReq + stopC chan struct{} + dispatcherIn chan *callReq } // TimeoutConfig is for setting timeout configs at ChargePoint level type TimeoutConfig struct { // ocpp response timeout in seconds - ocppWait time.Duration - + ocppWait time.Duration + // time allowed to write a message to the peer - writeWait time.Duration + writeWait time.Duration // time allowed to read the next pong message from the peer - pingWait time.Duration + pingWait time.Duration // pong wait in seconds - pongWait time.Duration + pongWait time.Duration // ping period in seconds - pingPeriod time.Duration + pingPeriod time.Duration } - type TimeoutError struct { Message string } @@ -143,9 +137,9 @@ func (e *TimeoutError) Error() string { // callReq is a container for calls type callReq struct { - id string - data []byte - recvChan chan interface{} + id string + data []byte + recvChan chan interface{} } // Payload used as a container is for both Call and CallResult' Payload @@ -153,10 +147,9 @@ type Payload interface{} type Peer interface { getHandler(string) func(*ChargePoint, Payload) Payload - getAfterHandler(string) func(*ChargePoint, Payload) + getAfterHandler(string) func(*ChargePoint, Payload) } - func (cp *ChargePoint) unmarshalResponse(a string, r json.RawMessage) (Payload, error) { return cp.unmarshalResponseFunc(a, r) } @@ -165,7 +158,6 @@ func (cp *ChargePoint) validatePayload(v interface{}) error { return cp.validatePayloadFunc(v) } - func (cp *ChargePoint) SetTimeoutConfig(config TimeoutConfig) { cp.mu.Lock() defer cp.mu.Unlock() @@ -178,15 +170,13 @@ func (cp *ChargePoint) IsConnected() bool { return cp.connected } - func (cp *ChargePoint) Shutdown() { cp.mu.Lock() defer cp.mu.Unlock() cp.closeC <- websocket.CloseError{Code: websocket.CloseNormalClosure, Text: ""} } - -// ResetPingPong resets ping/pong configuration upon WebSocketPingInterval +// ResetPingPong resets ping/pong configuration upon WebSocketPingInterval func (cp *ChargePoint) ResetPingPong(t int) (err error) { if t < 0 { err = errors.New("interval cannot be less than 0") @@ -202,7 +192,7 @@ func (cp *ChargePoint) ResetPingPong(t int) (err error) { log.Debug("<- ping") return cp.conn.SetReadDeadline(cp.getReadTimeout()) }) - return + return } log.Debug("ping/pong reconfigured") cp.tc.pongWait = time.Duration(t) * time.Second @@ -219,9 +209,8 @@ func (cp *ChargePoint) ResetPingPong(t int) (err error) { return } - // EnableServerPing enables server initiated pings -func (cp *ChargePoint) EnableServerPing(t int) (err error){ +func (cp *ChargePoint) EnableServerPing(t int) (err error) { if t <= 0 { err = errors.New("interval must be greater than 0") return @@ -240,7 +229,7 @@ func (cp *ChargePoint) EnableServerPing(t int) (err error){ log.Debug("<- pong") return cp.conn.SetReadDeadline(cp.getReadTimeout()) }) - return + return } log.Debug("server ping enabled") cp.ticker.Stop() @@ -256,11 +245,10 @@ func (cp *ChargePoint) EnableServerPing(t int) (err error){ return } - -// clientReader reads incoming websocket messages +// clientReader reads incoming websocket messages // and it runs as a goroutine on client-side charge point (physical device) func (cp *ChargePoint) clientReader() { - defer func () { + defer func() { cp.connected = false }() cp.conn.SetPongHandler(func(appData string) error { @@ -268,12 +256,13 @@ func (cp *ChargePoint) clientReader() { return cp.conn.SetReadDeadline(cp.getReadTimeout()) }) for { - if cp.processIncoming(client) { break } + if cp.processIncoming(client) { + break + } } } - -// clientWriter writes websocket messages +// clientWriter writes websocket messages // and it runs as a goroutine on client-side charge point (physical device) func (cp *ChargePoint) clientWriter() { defer func() { @@ -285,12 +274,13 @@ func (cp *ChargePoint) clientWriter() { defer cp.ticker.Stop() } for { - if !cp.processOutgoing() { break } + if !cp.processOutgoing() { + break + } } } - -// serverReader reads incoming websocket messages +// serverReader reads incoming websocket messages // and it runs as a goroutine on server-side charge point (virtual device) func (cp *ChargePoint) serverReader() { cp.conn.SetPingHandler(func(appData string) error { @@ -304,37 +294,38 @@ func (cp *ChargePoint) serverReader() { server.Delete(cp.Id) }() for { - if cp.processIncoming(server) { break } + if cp.processIncoming(server) { + break + } } } - - -// serverWriter writes websocket messages +// serverWriter writes websocket messages // and it runs as a goroutine on server-side charge point (virtual device) func (cp *ChargePoint) serverWriter() { defer server.Delete(cp.Id) for { - if !cp.processOutgoing() { break } + if !cp.processOutgoing() { + break + } } } - // processIncoming processes incoming websocket messages // and is used for both types of charge points (client and server side) -// +// // incoming messages normally can be of four kind from application perspective: // - one of websocket close errors, // - ocpp Call // - ocpp CallResult -// - ocpp CallError +// - ocpp CallError func (cp *ChargePoint) processIncoming(peer Peer) (br bool) { messageType, msg, err := cp.conn.ReadMessage() log.Debugf("messageType: %d", messageType) if err != nil { log.Debug(err) if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure, websocket.CloseNormalClosure) { - // TODO: handle specific logs + // TODO: handle specific logs log.Debug(err) } // stop websocket writer goroutine @@ -344,32 +335,32 @@ func (cp *ChargePoint) processIncoming(peer Peer) (br bool) { return true } ocppMsg, err := unpack(msg, cp.proto) - + // TODO: handle this situation carefully - // at this level, it is unknown if err.(*ocppError) is caused from a corrupt Call + // at this level, it is unknown if err.(*ocppError) is caused from a corrupt Call // this is very complicated case, because it could be any of corrupted Call, CallResult or CallError // possible solution: - // + // // - if err.id is known to application (for example, id of waiting Call request in queque) // this means msg is a corrupted CallResult or CallError // and then the err can be dropped and pushed to logger // - if err.id is "-1", there is a chance it could be a corrupted Call if call request queque is empty - // only in this case, CallError can be constructed and send to the peer + // only in this case, CallError can be constructed and send to the peer if ocppMsg == nil && err != nil { log.Error(err) - return + return } if call, ok := ocppMsg.(*Call); ok { if err != nil { cp.out <- call.createCallError(err) - return + return } handler := peer.getHandler(call.Action) if handler != nil { // TODO: possible feature additions // - pushing an incoming Call into a queque // - pass Context with timeout down to handler - // - or recover from panic and print error logs + // - or recover from panic and print error logs responsePayload := handler(cp, call.Payload) err = cp.validatePayload(responsePayload) if err != nil { @@ -390,23 +381,23 @@ func (cp *ChargePoint) processIncoming(peer Peer) (br bool) { } cp.out <- call.createCallError(err) log.Errorf("No handler for action %s", call.Action) - } + } } else { select { case cp.ocppRespCh <- ocppMsg: - default: - } - } + default: + } + } return false } - // process outOutoing writes both ping/pong messages and ocpp messages // to websocket connection. // also listens on extra two channels: // - forceWClose listens for signals upon websocket close erros on reader goroutine, // - closeC is used for graceful shutdown -// TODO: remove redundant err checking +// +// TODO: remove redundant err checking func (cp *ChargePoint) processOutgoing() (br bool) { select { case message, ok := <-cp.out: @@ -450,7 +441,7 @@ func (cp *ChargePoint) processOutgoing() (br bool) { return } log.Debug("pong ->") - return true + return true case <-cp.tickerC: _ = cp.conn.SetWriteDeadline(time.Now().Add(cp.tc.writeWait)) if err := cp.conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil { @@ -468,11 +459,9 @@ func (cp *ChargePoint) processOutgoing() (br bool) { log.Error(err) } return - } + } } - - // getReadTimeout is used to tweak websocket ping/pong functionality // and it is for both client-side and server-side connections func (cp *ChargePoint) getReadTimeout() time.Time { @@ -498,53 +487,52 @@ func (cp *ChargePoint) getReadTimeout() time.Time { return time.Time{} } return time.Now().Add(cp.tc.pongWait) - -} +} // callDispatcher sends ocpp call requests -func (cp *ChargePoint) callDispatcher(){ - cleanUp := make(chan struct{},1) +func (cp *ChargePoint) callDispatcher() { + cleanUp := make(chan struct{}, 1) for { select { case callReq := <-cp.dispatcherIn: - log.Debug("dispatcher in") - cp.out <- callReq.data - deadline := time.Now().Add(cp.tc.ocppWait) - in: - for { - select { - case <- cleanUp: - log.Debug("clean up") + log.Debug("dispatcher in") + cp.out <- callReq.data + deadline := time.Now().Add(cp.tc.ocppWait) + in: + for { + select { + case <-cleanUp: + log.Debug("clean up") + break in + case <-cp.stopC: + log.Debug("charge point is closed") + for ch := range cp.dispatcherIn { + log.Debug("cancel remaning call requests in queque") + close(ch.recvChan) + } + break in + case ocppResp := <-cp.ocppRespCh: + if ocppResp.getID() == callReq.id { + callReq.recvChan <- ocppResp break in - case <- cp.stopC: - log.Debug("charge point is closed") - for ch := range cp.dispatcherIn{ - log.Debug("cancel remaning call requests in queque") - close(ch.recvChan) - } - break in - case ocppResp := <- cp.ocppRespCh: - if ocppResp.getID() == callReq.id { - callReq.recvChan <- ocppResp - break in - } - case <-time.After(time.Until(deadline)): - log.Debug("ocpp timeout occured") - callReq.recvChan <- &TimeoutError{ - Message: fmt.Sprintf("timeout of %s sec for response to Call with id: %s passed", cp.tc.ocppWait, callReq.id), - } - break in - } + } + case <-time.After(time.Until(deadline)): + log.Debug("ocpp timeout occured") + callReq.recvChan <- &TimeoutError{ + Message: fmt.Sprintf("timeout of %s sec for response to Call with id: %s passed", cp.tc.ocppWait, callReq.id), + } + break in } - log.Debug("broke from loop") - case <- cp.stopC: + } + log.Debug("broke from loop") + case <-cp.stopC: log.Debug("charge point is closed") select { case cleanUp <- struct{}{}: - default: + default: } - for ch := range cp.dispatcherIn{ + for ch := range cp.dispatcherIn { log.Debug("cancel remaning call requests in queque") close(ch.recvChan) } @@ -552,15 +540,10 @@ func (cp *ChargePoint) callDispatcher(){ } } - - - - - // Call sends a message to peer func (cp *ChargePoint) Call(action string, p Payload) (Payload, error) { // check if charge point is connected - if !cp.IsConnected(){ + if !cp.IsConnected() { return nil, ErrChargePointNotConnected } // add validator function @@ -578,16 +561,16 @@ func (cp *ChargePoint) Call(action string, p Payload) (Payload, error) { raw, _ := json.Marshal(call) recvChan := make(chan interface{}, 1) cr := &callReq{ - id: id, - data: raw, + id: id, + data: raw, recvChan: recvChan, } select { - case cp.dispatcherIn <- cr: + case cp.dispatcherIn <- cr: log.Debug("call request added to dispatcher") - default: + default: return nil, ErrCallQuequeFull - } + } r, ok := <-recvChan if !ok { return nil, ErrChargePointDisconnected @@ -605,9 +588,6 @@ func (cp *ChargePoint) Call(action string, p Payload) (Payload, error) { return nil, r.(*TimeoutError) } - - - // NewChargepoint creates a new ChargePoint func NewChargePoint(conn *websocket.Conn, id, proto string, isServer bool) *ChargePoint { cp := &ChargePoint{ @@ -620,7 +600,7 @@ func NewChargePoint(conn *websocket.Conn, id, proto string, isServer bool) *Char Extras: make(map[string]interface{}), closeC: make(chan websocket.CloseError, 1), forceWClose: make(chan error, 1), - stopC: make(chan struct{}), + stopC: make(chan struct{}), connected: true, } if isServer { @@ -630,7 +610,7 @@ func NewChargePoint(conn *websocket.Conn, id, proto string, isServer bool) *Char cp.tickerC = nil cp.inheritServerTimeoutConfig() go cp.serverReader() - go cp.serverWriter() + go cp.serverWriter() } else { cp.dispatcherIn = make(chan *callReq, client.callQuequeSize) cp.inheritClientTimeoutConfig() @@ -644,37 +624,33 @@ func NewChargePoint(conn *websocket.Conn, id, proto string, isServer bool) *Char return cp } - func (cp *ChargePoint) setResponseUnmarshaller() { switch cp.proto { case ocppV16: cp.unmarshalResponseFunc = unmarshalResponsePv16 case ocppV201: - cp.unmarshalResponseFunc = unmarshalResponsePv201 + cp.unmarshalResponseFunc = unmarshalResponsePv201 } } - func (cp *ChargePoint) setPayloadValidator() { switch cp.proto { case ocppV16: cp.validatePayloadFunc = validateV16.Struct case ocppV201: - cp.validatePayloadFunc = validateV201.Struct - } + cp.validatePayloadFunc = validateV201.Struct + } } - func (cp *ChargePoint) inheritServerTimeoutConfig() { cp.tc.ocppWait = server.ocppWait cp.tc.writeWait = server.writeWait cp.tc.pingWait = server.pingWait } - func (cp *ChargePoint) inheritClientTimeoutConfig() { cp.tc.ocppWait = client.ocppWait cp.tc.writeWait = client.writeWait cp.tc.pongWait = client.pongWait cp.tc.pingPeriod = client.pingPeriod -} \ No newline at end of file +} diff --git a/charge_point_test.go b/charge_point_test.go deleted file mode 100644 index ed9afb9..0000000 --- a/charge_point_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package ocpp - -import ( - -) - diff --git a/client.go b/client.go index 0db4e84..7385572 100644 --- a/client.go +++ b/client.go @@ -9,68 +9,61 @@ import ( "github.com/gorilla/websocket" ) - var client *Client type ClientTimeoutConfig struct { - // ocpp response timeout in seconds - OcppWait time.Duration + // ocpp response timeout in seconds + OcppWait time.Duration // time allowed to write a message to the peer - WriteWait time.Duration + WriteWait time.Duration // pong wait in seconds - PongWait time.Duration + PongWait time.Duration // ping period in seconds - PingPeriod time.Duration + PingPeriod time.Duration } - - type Client struct { Id string // register implemented action handler functions - actionHandlers map[string]func(*ChargePoint, Payload) Payload + actionHandlers map[string]func(*ChargePoint, Payload) Payload // register after-action habdler functions - afterHandlers map[string]func(*ChargePoint, Payload) + afterHandlers map[string]func(*ChargePoint, Payload) // timeout configuration - ocppWait time.Duration - + ocppWait time.Duration + writeWait time.Duration - pongWait time.Duration + pongWait time.Duration - pingPeriod time.Duration + pingPeriod time.Duration + + header http.Header - header http.Header - returnError func(error) callQuequeSize int } - // create new Client instance func NewClient() *Client { client = &Client{ actionHandlers: make(map[string]func(*ChargePoint, Payload) Payload), afterHandlers: make(map[string]func(*ChargePoint, Payload)), - ocppWait: ocppWait, - writeWait: writeWait, - pongWait: pongWait, - pingPeriod: pingPeriod, - header: http.Header{}, + ocppWait: ocppWait, + writeWait: writeWait, + pongWait: pongWait, + pingPeriod: pingPeriod, + header: http.Header{}, } return client } - func (c *Client) SetCallQueueSize(size int) { c.callQuequeSize = size -} - - +} func (c *Client) SetTimeoutConfig(config ClientTimeoutConfig) { c.ocppWait = config.OcppWait @@ -79,9 +72,6 @@ func (c *Client) SetTimeoutConfig(config ClientTimeoutConfig) { c.pingPeriod = config.PingPeriod } - - - // register action handler function func (c *Client) On(action string, f func(*ChargePoint, Payload) Payload) *Client { c.actionHandlers[action] = f @@ -109,23 +99,23 @@ func (c *Client) AddSubProtocol(protocol string) { func (c *Client) SetBasicAuth(username string, password string) { auth := username + ":" + password enc := base64.StdEncoding.EncodeToString([]byte(auth)) - c.header.Set("Authorization", "Basic "+ enc) + c.header.Set("Authorization", "Basic "+enc) } func (c *Client) Start(addr string, path string) (cp *ChargePoint, err error) { urlStr, err := url.JoinPath(addr, path, c.Id) if err != nil { c.returnError(err) - return + return } conn, _, err := websocket.DefaultDialer.Dial(urlStr, c.header) if err != nil { - return + return } cp = NewChargePoint(conn, c.Id, conn.Subprotocol(), false) - return + return } func (c *Client) SetID(id string) { c.Id = id -} \ No newline at end of file +} diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 09b7a1f..0000000 --- a/examples/README.md +++ /dev/null @@ -1,11 +0,0 @@ -Simple example of sending a Call to multiple Charge Points. -First run server.go -``` -go run server.go -``` -Then run both clients in different terminals -``` -go run client1/client.go -go run client2/client.go -``` - diff --git a/examples/client/client.go b/examples/client/client.go index 7c1e6d7..92217b2 100644 --- a/examples/client/client.go +++ b/examples/client/client.go @@ -2,21 +2,17 @@ package main import ( "fmt" - "time" - // "time" - // "net/http" - // "strconv" - // "time" - // _ "net/http/pprof" + "net/http" + _ "net/http/pprof" "github.com/aliml92/ocpp" v16 "github.com/aliml92/ocpp/v16" "go.uber.org/zap" ) -var confData map[string]string + var client *ocpp.Client @@ -31,16 +27,16 @@ func initLogger() { } func main() { - // go func() { - // log.Debugln(http.ListenAndServe("localhost:5050", nil)) - // }() + go func() { + log.Debugln(http.ListenAndServe("localhost:5050", nil)) + }() // initialize logger initLogger() defer log.Sync() // set ocpp library's logger to zap logger ocpp.SetLogger(log) - confData = make(map[string]string) + // create client client = ocpp.NewClient() id := "client00" @@ -48,10 +44,10 @@ func main() { client.AddSubProtocol("ocpp1.6") client.SetBasicAuth(id, "dummypass") client.SetCallQueueSize(32) - // client.On("ChangeAvailability", ChangeAvailabilityHandler) - // client.On("GetLocalListVersion", GetLocalListVersionHandler) + client.On("ChangeAvailability", ChangeAvailabilityHandler) + client.On("GetLocalListVersion", GetLocalListVersionHandler) client.On("ChangeConfiguration", ChangeConfigurationHandler) - + cp, err := client.Start("ws://localhost:8999", "/ws") if err != nil { fmt.Printf("error dialing: %v\n", err) @@ -60,52 +56,37 @@ func main() { sendBootNotification(cp) defer cp.Shutdown() log.Debugf("charge point status %v", cp.IsConnected()) - // time.Sleep(10 * time.Second) - // sendAuthorize(cp) - // log.Debugf("charge point status %v", cp.IsConnected()) - // time.Sleep(3 * time.Second) - // sendAuthorize(cp) - // log.Debugf("charge point status %v", cp.IsConnected()) - // time.Sleep(3 * time.Second) - // sendAuthorize(cp) - // log.Debugf("charge point status %v", cp.IsConnected()) select {} } func ChangeConfigurationHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { req := p.(*v16.ChangeConfigurationReq) log.Debugf("ChangeConfigurationReq: %v\n", req) - confData[req.Key] = req.Value - // if req.Key == "WebSocketPingInterval" { - // t, _ := strconv.Atoi(req.Value) - // cp.ResetPingPong(t) - // cp.EnableServerPing(t) - // } - time.Sleep(2 * time.Second) + var res ocpp.Payload = &v16.ChangeConfigurationConf{ Status: "Accepted", } return res } -// Later use -// func ChangeAvailabilityHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { -// req := p.(*v16.ChangeAvailabilityReq) -// log.Debugf("ChangeAvailability: %v\n", req) -// var res ocpp.Payload = &v16.ChangeAvailabilityConf{ -// Status: "Accepted", -// } -// return res -// } - -// func GetLocalListVersionHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { -// req := p.(*v16.GetLocalListVersionReq) -// log.Debugf("GetLocalListVersionReq: %v\n", req) -// var res ocpp.Payload = &v16.GetLocalListVersionConf{ -// ListVersion: 1, -// } -// return res -// } + +func ChangeAvailabilityHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { + req := p.(*v16.ChangeAvailabilityReq) + log.Debugf("ChangeAvailability: %v\n", req) + var res ocpp.Payload = &v16.ChangeAvailabilityConf{ + Status: "Accepted", + } + return res +} + +func GetLocalListVersionHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { + req := p.(*v16.GetLocalListVersionReq) + log.Debugf("GetLocalListVersionReq: %v\n", req) + var res ocpp.Payload = &v16.GetLocalListVersionConf{ + ListVersion: 1, + } + return res +} func sendBootNotification(c *ocpp.ChargePoint) { req := &v16.BootNotificationReq{ @@ -121,14 +102,3 @@ func sendBootNotification(c *ocpp.ChargePoint) { } -// func sendAuthorize(c *ocpp.ChargePoint) { -// req := &v16.AuthorizeReq{ -// IdTag: "safdasdfdsa", -// } -// res, err := c.Call("Authorize", req, 10) -// if err != nil { -// fmt.Printf("error dialing: %v\n", err) -// return -// } -// fmt.Printf("AuthorizeConf: %v\n", res) -// } \ No newline at end of file diff --git a/examples/server/server.go b/examples/server/server.go index a4e88d4..e0fd7c0 100644 --- a/examples/server/server.go +++ b/examples/server/server.go @@ -7,7 +7,7 @@ import ( "go.uber.org/zap" - // _ "net/http/pprof" + _ "net/http/pprof" "github.com/aliml92/ocpp" v16 "github.com/aliml92/ocpp/v16" @@ -23,9 +23,9 @@ var log *zap.SugaredLogger func main() { - // go func() { - // log.Debug(http.ListenAndServe(":6060", nil)) - // }() + go func() { + log.Debug(http.ListenAndServe(":6060", nil)) + }() logger, _ := zap.NewDevelopment() log = logger.Sugar() @@ -49,97 +49,36 @@ func main() { csms.On("BootNotification", BootNotificationHandler) // csms.On("Authorize", AuthorizationHandler) csms.After("BootNotification", SendChangeConfigration) - // go func() { - // log.Debugln("sleeping 20s") - // time.Sleep(20 * time.Second) - // cp, ok := csms.Load("client00") - // if !ok { - // log.Debugln("charge point found") - // return - // } - // var arr [6]ocpp.Payload - // var req0 ocpp.Payload = v16.ChangeConfigurationReq{ - // Key: "WebSocketPingInterval", - // Value: "30", - // } - // arr[0] = req0 - // var req1 ocpp.Payload = v16.ChangeConfigurationReq{ - // Key: "BlinkRepeat", - // Value: "5", - // } - // arr[1] = req1 - // var req2 ocpp.Payload = v16.ChangeConfigurationReq{ - // Key: "ConnectionTimeOut", - // Value: "300", - // } - // arr[2] = req2 - // arr[3] = req0 - // arr[4] = req1 - // arr[5] = req2 - // time.Sleep(2 * time.Second) - // for i:=0; i < 5; i++ { - // go func(idx int){ - // res, err := cp.Call("ChangeConfiguration", arr[idx], 10) - // if err != nil { - // log.Debug(err) - // } - // log.Debug(res) - // }(i) - // } - // res, err := cp.Call("ChangeConfiguration", arr[5], 10) - // if err != nil { - // log.Debug(err) - // } - // // cp.ResetPingPong(30) - // // cp.ResetPingPong(0) - // // cp.EnableServerPing(10) - // log.Debug(res) - // }() csms.Start("0.0.0.0:8999", "/ws/", nil) } func SendChangeConfigration(cp *ocpp.ChargePoint, payload ocpp.Payload) { - var arr [32]ocpp.Payload var req ocpp.Payload = v16.ChangeConfigurationReq{ Key: "WebSocketPingInterval", Value: "30", } - for i:=0; i < 30; i++ { - arr[i] = req - go func(idx int){ - res, err := cp.Call("ChangeConfiguration", arr[idx]) - if err != nil { - log.Debug(err) - } - log.Debug(res) - }(i) - } - arr[31] = req - res, err := cp.Call("ChangeConfiguration", arr[31]) + res, err := cp.Call("ChangeConfiguration", req) if err != nil { log.Debug(err) } - // cp.ResetPingPong(30) - // cp.ResetPingPong(0) - // cp.EnableServerPing(10) log.Debug(res) } -// func SendGetLocalListVersion(cp *ocpp.ChargePoint, payload ocpp.Payload) { -// var req ocpp.Payload = v16.GetLocalListVersionReq{} -// res, err := cp.Call("GetLocalListVersion", req, 10) -// if err != nil { -// log.Debug(err) -// } -// log.Debug(res) -// } +func SendGetLocalListVersion(cp *ocpp.ChargePoint, payload ocpp.Payload) { + var req ocpp.Payload = v16.GetLocalListVersionReq{} + res, err := cp.Call("GetLocalListVersion", req) + if err != nil { + log.Debug(err) + } + log.Debug(res) +} + -// func customPreUpgradeHandler(w http.ResponseWriter, r *http.Request) bool { u, p, ok := r.BasicAuth() if !ok { @@ -171,14 +110,14 @@ func BootNotificationHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload return res } -// func AuthorizationHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { -// time.Sleep(time.Second * 2) -// req := p.(*v16.AuthorizeReq) -// log.Debugf("\nid: %s\nAuthorizeReq: %v", cp.Id, req) -// var res ocpp.Payload = &v16.AuthorizeConf{ -// IdTagInfo: v16.IdTagInfo{ -// Status: "Accepted", -// }, -// } -// return res -// } \ No newline at end of file +func AuthorizationHandler(cp *ocpp.ChargePoint, p ocpp.Payload) ocpp.Payload { + time.Sleep(time.Second * 2) + req := p.(*v16.AuthorizeReq) + log.Debugf("\nid: %s\nAuthorizeReq: %v", cp.Id, req) + var res ocpp.Payload = &v16.AuthorizeConf{ + IdTagInfo: v16.IdTagInfo{ + Status: "Accepted", + }, + } + return res +} \ No newline at end of file diff --git a/examples/temp_readme.txt b/examples/temp_readme.txt deleted file mode 100644 index e69de29..0000000 diff --git a/messages.go b/messages.go index cc8ad6d..a92594b 100644 --- a/messages.go +++ b/messages.go @@ -10,15 +10,14 @@ import ( ) const ( - MessageTypeIdCall = 2 - MessageTypeIdCallResult = 3 - MessageTypeIdCallError = 4 - + MessageTypeIdCall = 2 + MessageTypeIdCallResult = 3 + MessageTypeIdCallError = 4 ) -var errInvalidAction = errors.New("invalid action") +var errInvalidAction = errors.New("invalid action") -var reqmapv16, resmapv16, reqmapv201, resmapv201 map[string]func(json.RawMessage) (Payload, error) +var reqmapv16, resmapv16, reqmapv201, resmapv201 map[string]func(json.RawMessage) (Payload, error) type ocppError struct { id string @@ -38,11 +37,9 @@ type Call struct { Payload Payload } - func (c *Call) getID() string { return c.UniqueId -} - +} // Create CallResult from a received Call func (call *Call) createCallResult(r Payload) []byte { @@ -69,9 +66,9 @@ func (call *Call) createCallError(err error) []byte { id = "-1" } callError := &CallError{ - UniqueId: id, - ErrorCode: code, - ErrorDetails: cause, + UniqueId: id, + ErrorCode: code, + ErrorDetails: cause, } switch code { case "ProtocolError": @@ -98,7 +95,7 @@ type CallResult struct { UniqueId string Payload json.RawMessage } - + func (cr *CallResult) getID() string { return cr.UniqueId } @@ -138,14 +135,13 @@ type OcppMessage interface { getID() string } - - -// umpack converts json byte to one of the ocpp messages, if not successful +// umpack converts json byte to one of the ocpp messages, if not successful // returns an error // unpack expects ocpp messages in the below forms: -// - [, "", "", {}] -> Call -// - [, "", {}] -> CallResult -// - [, "", "", "" , {}] -> CallError +// - [, "", "", {}] -> Call +// - [, "", {}] -> CallResult +// - [, "", "", "" , {}] -> CallError +// // if json byte does not conform with these three formats, OcppError is created // and is returned as error // @@ -170,19 +166,18 @@ func unpack(b []byte, proto string) (OcppMessage, error) { return nil, e } - // unmarshal [0]json.RawMessage to MessageTypeId err1 := json.Unmarshal(rm[0], &mti) // unmarshal [1]json.RawMessage to UniqueId err2 := json.Unmarshal(rm[1], &ui) - if err1 != nil { + if err1 != nil { if err2 != nil { e.id = "-1" e.cause = e.cause + "," + fmt.Sprintf("UniqueId: %v is not valid", rm[1]) } else { e.id = ui } - return nil, e + return nil, e } if len(ui) > 36 { e = &ocppError{ @@ -194,7 +189,7 @@ func unpack(b []byte, proto string) (OcppMessage, error) { case MessageTypeIdCall: call := &Call{ MessageTypeId: mti, - UniqueId: ui, + UniqueId: ui, } if e != nil { return call, e @@ -242,21 +237,21 @@ func unpack(b []byte, proto string) (OcppMessage, error) { code: "MessageTypeNotSupported", cause: fmt.Sprintf("A message with: %v is not supported by this implementation", mti), } - return nil, e + return nil, e } return ocppMsg, nil } -// unmarshalRequestPayload unmarshals raw bytes of request type payload +// unmarshalRequestPayload unmarshals raw bytes of request type payload // to a corresponding struct depending on Action and ocpp protocol func unmarshalRequestPayload(actionName string, rawPayload json.RawMessage, proto string) (Payload, error) { - var uf func(json.RawMessage) (Payload, error) // uf unmarshal function for a specific action request + var uf func(json.RawMessage) (Payload, error) // uf unmarshal function for a specific action request var ok bool switch proto { case ocppV16: uf, ok = reqmapv16[actionName] case ocppV201: - uf, ok = reqmapv201[actionName] + uf, ok = reqmapv201[actionName] } if !ok { e := &ocppError{ @@ -268,9 +263,7 @@ func unmarshalRequestPayload(actionName string, rawPayload json.RawMessage, prot return uf(rawPayload) } - - -// unmarshalRequestPayloadv16 unmarshals raw request type payload to a ***Req type struct of ocppv16 +// unmarshalRequestPayloadv16 unmarshals raw request type payload to a ***Req type struct of ocppv16 func unmarshalRequestPayloadv16[T any](rawPayload json.RawMessage) (Payload, error) { var p T var payload Payload @@ -295,8 +288,7 @@ func unmarshalRequestPayloadv16[T any](rawPayload json.RawMessage) (Payload, err return payload, nil } - -// unmarshalRequestPayloadv201 unmarshals raw request type payload to a ***Req type struct of ocppv201 +// unmarshalRequestPayloadv201 unmarshals raw request type payload to a ***Req type struct of ocppv201 func unmarshalRequestPayloadv201[T any](rawPayload json.RawMessage) (Payload, error) { var p T var payload Payload @@ -323,28 +315,27 @@ func unmarshalRequestPayloadv201[T any](rawPayload json.RawMessage) (Payload, er return payload, nil } - -// unmarshalResponsePv16 unmarshals raw bytes of request type payload -// to a corresponding struct depending on actionName +// unmarshalResponsePv16 unmarshals raw bytes of request type payload +// to a corresponding struct depending on actionName func unmarshalResponsePv16(actionName string, rawPayload json.RawMessage) (Payload, error) { - uf, ok := resmapv16[actionName] // uf unmarshal function for a specific action request + uf, ok := resmapv16[actionName] // uf unmarshal function for a specific action request if !ok { return nil, errInvalidAction } return uf(rawPayload) } -// unmarshalResponsePv201 unmarshals raw bytes of request type payload +// unmarshalResponsePv201 unmarshals raw bytes of request type payload // to a corresponding struct depending on actionName func unmarshalResponsePv201(mAction string, rawPayload json.RawMessage) (Payload, error) { - uf, ok := resmapv201[mAction] // uf unmarshal function for a specific action request + uf, ok := resmapv201[mAction] // uf unmarshal function for a specific action request if !ok { return nil, errInvalidAction } return uf(rawPayload) } -// unmarshalResponsePayloadv16 unmarshals raw response type payload to a ***Conf type struct of ocppv16 +// unmarshalResponsePayloadv16 unmarshals raw response type payload to a ***Conf type struct of ocppv16 func unmarshalResponsePayloadv16[T any](rawPayload json.RawMessage) (Payload, error) { var p T var payload Payload @@ -360,8 +351,7 @@ func unmarshalResponsePayloadv16[T any](rawPayload json.RawMessage) (Payload, er return payload, nil } - -// unmarshalResponsePayloadv201 unmarshals raw response type payload to a ***Res type struct of ocppv201 +// unmarshalResponsePayloadv201 unmarshals raw response type payload to a ***Res type struct of ocppv201 func unmarshalResponsePayloadv201[T any](rawPayload json.RawMessage) (Payload, error) { var p T var payload Payload @@ -377,9 +367,7 @@ func unmarshalResponsePayloadv201[T any](rawPayload json.RawMessage) (Payload, e return payload, nil } - - -func init(){ +func init() { reqmapv16 = map[string]func(json.RawMessage) (Payload, error){ "BootNotification": unmarshalRequestPayloadv16[v16.BootNotificationReq], "Authorize": unmarshalRequestPayloadv16[v16.AuthorizeReq], @@ -443,136 +431,136 @@ func init(){ } reqmapv201 = map[string]func(json.RawMessage) (Payload, error){ - "Authorize": unmarshalRequestPayloadv201[v201.AuthorizeReq], - "BootNotification": unmarshalRequestPayloadv201[v201.BootNotificationReq], - "CancelReservation": unmarshalRequestPayloadv201[v201.CancelReservationReq], - "CertificateSigned": unmarshalRequestPayloadv201[v201.CertificateSignedReq], - "ChangeAvailability": unmarshalRequestPayloadv201[v201.ChangeAvailabilityReq], - "ClearCache": unmarshalRequestPayloadv201[v201.ClearCacheReq], - "ClearChargingProfile": unmarshalRequestPayloadv201[v201.ClearChargingProfileReq], - "ClearDisplayMessage": unmarshalRequestPayloadv201[v201.ClearDisplayMessageReq], - "ClearedChargingLimit": unmarshalRequestPayloadv201[v201.ClearedChargingLimitReq], - "ClearVariableMonitoring": unmarshalRequestPayloadv201[v201.ClearVariableMonitoringReq], - "CostUpdated": unmarshalRequestPayloadv201[v201.CostUpdatedReq], - "CustomerInformation": unmarshalRequestPayloadv201[v201.CustomerInformationReq], - "DataTransfer": unmarshalRequestPayloadv201[v201.DataTransferReq], - "DeleteCertificate": unmarshalRequestPayloadv201[v201.DeleteCertificateReq], - "FirmwareStatusNotification": unmarshalRequestPayloadv201[v201.FirmwareStatusNotificationReq], - "Get15118EVCertificate": unmarshalRequestPayloadv201[v201.Get15118EVCertificateReq], - "GetBaseReport": unmarshalRequestPayloadv201[v201.GetBaseReportReq], - "GetCertificateStatus": unmarshalRequestPayloadv201[v201.GetCertificateStatusReq], - "GetChargingProfiles": unmarshalRequestPayloadv201[v201.GetChargingProfilesReq], - "GetCompositeSchedule": unmarshalRequestPayloadv201[v201.GetCompositeScheduleReq], - "GetDisplayMessages": unmarshalRequestPayloadv201[v201.GetDisplayMessagesReq], - "GetInstalledCertificateIds": unmarshalRequestPayloadv201[v201.GetInstalledCertificateIdsReq], - "GetLocalListVersion": unmarshalRequestPayloadv201[v201.GetLocalListVersionReq], - "GetLog": unmarshalRequestPayloadv201[v201.GetLogReq], - "GetMonitoringReport": unmarshalRequestPayloadv201[v201.GetMonitoringReportReq], - "GetReport": unmarshalRequestPayloadv201[v201.GetReportReq], - "GetTransactionStatus": unmarshalRequestPayloadv201[v201.GetTransactionStatusReq], - "GetVariables": unmarshalRequestPayloadv201[v201.GetVariablesReq], - "Heartbeat": unmarshalRequestPayloadv201[v201.HeartbeatReq], - "InstallCertificate": unmarshalRequestPayloadv201[v201.InstallCertificateReq], - "LogStatusNotification": unmarshalRequestPayloadv201[v201.LogStatusNotificationReq], - "MeterValues": unmarshalRequestPayloadv201[v201.MeterValuesReq], - "NotifyChargingLimit": unmarshalRequestPayloadv201[v201.NotifyChargingLimitReq], - "NotifyCustomerInformation": unmarshalRequestPayloadv201[v201.NotifyCustomerInformationReq], - "NotifyDisplayMessages": unmarshalRequestPayloadv201[v201.NotifyDisplayMessagesReq], - "NotifyEVChargingNeeds": unmarshalRequestPayloadv201[v201.NotifyEVChargingNeedsReq], - "NotifyEVChargingSchedule": unmarshalRequestPayloadv201[v201.NotifyEVChargingScheduleReq], - "NotifyEvent": unmarshalRequestPayloadv201[v201.NotifyEventReq], - "NotifyMonitoringReport": unmarshalRequestPayloadv201[v201.NotifyMonitoringReportReq], - "NotifyReport": unmarshalRequestPayloadv201[v201.NotifyReportReq], - "PublishFirmware": unmarshalRequestPayloadv201[v201.PublishFirmwareReq], + "Authorize": unmarshalRequestPayloadv201[v201.AuthorizeReq], + "BootNotification": unmarshalRequestPayloadv201[v201.BootNotificationReq], + "CancelReservation": unmarshalRequestPayloadv201[v201.CancelReservationReq], + "CertificateSigned": unmarshalRequestPayloadv201[v201.CertificateSignedReq], + "ChangeAvailability": unmarshalRequestPayloadv201[v201.ChangeAvailabilityReq], + "ClearCache": unmarshalRequestPayloadv201[v201.ClearCacheReq], + "ClearChargingProfile": unmarshalRequestPayloadv201[v201.ClearChargingProfileReq], + "ClearDisplayMessage": unmarshalRequestPayloadv201[v201.ClearDisplayMessageReq], + "ClearedChargingLimit": unmarshalRequestPayloadv201[v201.ClearedChargingLimitReq], + "ClearVariableMonitoring": unmarshalRequestPayloadv201[v201.ClearVariableMonitoringReq], + "CostUpdated": unmarshalRequestPayloadv201[v201.CostUpdatedReq], + "CustomerInformation": unmarshalRequestPayloadv201[v201.CustomerInformationReq], + "DataTransfer": unmarshalRequestPayloadv201[v201.DataTransferReq], + "DeleteCertificate": unmarshalRequestPayloadv201[v201.DeleteCertificateReq], + "FirmwareStatusNotification": unmarshalRequestPayloadv201[v201.FirmwareStatusNotificationReq], + "Get15118EVCertificate": unmarshalRequestPayloadv201[v201.Get15118EVCertificateReq], + "GetBaseReport": unmarshalRequestPayloadv201[v201.GetBaseReportReq], + "GetCertificateStatus": unmarshalRequestPayloadv201[v201.GetCertificateStatusReq], + "GetChargingProfiles": unmarshalRequestPayloadv201[v201.GetChargingProfilesReq], + "GetCompositeSchedule": unmarshalRequestPayloadv201[v201.GetCompositeScheduleReq], + "GetDisplayMessages": unmarshalRequestPayloadv201[v201.GetDisplayMessagesReq], + "GetInstalledCertificateIds": unmarshalRequestPayloadv201[v201.GetInstalledCertificateIdsReq], + "GetLocalListVersion": unmarshalRequestPayloadv201[v201.GetLocalListVersionReq], + "GetLog": unmarshalRequestPayloadv201[v201.GetLogReq], + "GetMonitoringReport": unmarshalRequestPayloadv201[v201.GetMonitoringReportReq], + "GetReport": unmarshalRequestPayloadv201[v201.GetReportReq], + "GetTransactionStatus": unmarshalRequestPayloadv201[v201.GetTransactionStatusReq], + "GetVariables": unmarshalRequestPayloadv201[v201.GetVariablesReq], + "Heartbeat": unmarshalRequestPayloadv201[v201.HeartbeatReq], + "InstallCertificate": unmarshalRequestPayloadv201[v201.InstallCertificateReq], + "LogStatusNotification": unmarshalRequestPayloadv201[v201.LogStatusNotificationReq], + "MeterValues": unmarshalRequestPayloadv201[v201.MeterValuesReq], + "NotifyChargingLimit": unmarshalRequestPayloadv201[v201.NotifyChargingLimitReq], + "NotifyCustomerInformation": unmarshalRequestPayloadv201[v201.NotifyCustomerInformationReq], + "NotifyDisplayMessages": unmarshalRequestPayloadv201[v201.NotifyDisplayMessagesReq], + "NotifyEVChargingNeeds": unmarshalRequestPayloadv201[v201.NotifyEVChargingNeedsReq], + "NotifyEVChargingSchedule": unmarshalRequestPayloadv201[v201.NotifyEVChargingScheduleReq], + "NotifyEvent": unmarshalRequestPayloadv201[v201.NotifyEventReq], + "NotifyMonitoringReport": unmarshalRequestPayloadv201[v201.NotifyMonitoringReportReq], + "NotifyReport": unmarshalRequestPayloadv201[v201.NotifyReportReq], + "PublishFirmware": unmarshalRequestPayloadv201[v201.PublishFirmwareReq], "PublishFirmawareStatusNotification": unmarshalRequestPayloadv201[v201.PublishFirmwareStatusNotificationReq], - "ReportChargingProfiles": unmarshalRequestPayloadv201[v201.ReportChargingProfilesReq], - "RequestStartTransaction": unmarshalRequestPayloadv201[v201.RequestStartTransactionReq], - "RequestStopTransaction": unmarshalRequestPayloadv201[v201.RequestStopTransactionReq], - "ReservationStatusUpdate": unmarshalRequestPayloadv201[v201.ReservationStatusUpdateReq], - "ReserveNow": unmarshalRequestPayloadv201[v201.ReserveNowReq], - "Reset": unmarshalRequestPayloadv201[v201.ResetReq], - "SecurityEventNotification": unmarshalRequestPayloadv201[v201.SecurityEventNotificationReq], - "SendLocalList": unmarshalRequestPayloadv201[v201.SendLocalListReq], - "SetChargingProfile": unmarshalRequestPayloadv201[v201.SetChargingProfileReq], - "SetDisplayMessage": unmarshalRequestPayloadv201[v201.SetDisplayMessageReq], - "SetMonitoringBase": unmarshalRequestPayloadv201[v201.SetMonitoringBaseReq], - "SetMonitoringLevel": unmarshalRequestPayloadv201[v201.SetMonitoringLevelReq], - "SetNetworkProfile": unmarshalRequestPayloadv201[v201.SetNetworkProfileReq], - "SetVariableMonitoring": unmarshalRequestPayloadv201[v201.SetVariableMonitoringReq], - "SetVariables": unmarshalRequestPayloadv201[v201.SetVariablesReq], - "SignCertificate": unmarshalRequestPayloadv201[v201.SignCertificateReq], - "StatusNotification": unmarshalRequestPayloadv201[v201.StatusNotificationReq], - "TransactionEvent": unmarshalRequestPayloadv201[v201.TransactionEventReq], - "TriggerMessage": unmarshalRequestPayloadv201[v201.TriggerMessageReq], - "UnlockConnector": unmarshalRequestPayloadv201[v201.UnlockConnectorReq], - "UnpublishFirmware": unmarshalRequestPayloadv201[v201.UnpublishFirmwareReq], - "UpdateFirmware": unmarshalRequestPayloadv201[v201.UpdateFirmwareReq], + "ReportChargingProfiles": unmarshalRequestPayloadv201[v201.ReportChargingProfilesReq], + "RequestStartTransaction": unmarshalRequestPayloadv201[v201.RequestStartTransactionReq], + "RequestStopTransaction": unmarshalRequestPayloadv201[v201.RequestStopTransactionReq], + "ReservationStatusUpdate": unmarshalRequestPayloadv201[v201.ReservationStatusUpdateReq], + "ReserveNow": unmarshalRequestPayloadv201[v201.ReserveNowReq], + "Reset": unmarshalRequestPayloadv201[v201.ResetReq], + "SecurityEventNotification": unmarshalRequestPayloadv201[v201.SecurityEventNotificationReq], + "SendLocalList": unmarshalRequestPayloadv201[v201.SendLocalListReq], + "SetChargingProfile": unmarshalRequestPayloadv201[v201.SetChargingProfileReq], + "SetDisplayMessage": unmarshalRequestPayloadv201[v201.SetDisplayMessageReq], + "SetMonitoringBase": unmarshalRequestPayloadv201[v201.SetMonitoringBaseReq], + "SetMonitoringLevel": unmarshalRequestPayloadv201[v201.SetMonitoringLevelReq], + "SetNetworkProfile": unmarshalRequestPayloadv201[v201.SetNetworkProfileReq], + "SetVariableMonitoring": unmarshalRequestPayloadv201[v201.SetVariableMonitoringReq], + "SetVariables": unmarshalRequestPayloadv201[v201.SetVariablesReq], + "SignCertificate": unmarshalRequestPayloadv201[v201.SignCertificateReq], + "StatusNotification": unmarshalRequestPayloadv201[v201.StatusNotificationReq], + "TransactionEvent": unmarshalRequestPayloadv201[v201.TransactionEventReq], + "TriggerMessage": unmarshalRequestPayloadv201[v201.TriggerMessageReq], + "UnlockConnector": unmarshalRequestPayloadv201[v201.UnlockConnectorReq], + "UnpublishFirmware": unmarshalRequestPayloadv201[v201.UnpublishFirmwareReq], + "UpdateFirmware": unmarshalRequestPayloadv201[v201.UpdateFirmwareReq], } resmapv201 = map[string]func(json.RawMessage) (Payload, error){ - "Authorize": unmarshalResponsePayloadv201[v201.AuthorizeRes], - "BootNotification": unmarshalResponsePayloadv201[v201.BootNotificationRes], - "CancelReservation": unmarshalResponsePayloadv201[v201.CancelReservationRes], - "CertificateSigned": unmarshalResponsePayloadv201[v201.CertificateSignedRes], - "ChangeAvailability": unmarshalResponsePayloadv201[v201.ChangeAvailabilityRes], - "ClearCache": unmarshalResponsePayloadv201[v201.ClearCacheRes], - "ClearChargingProfile": unmarshalResponsePayloadv201[v201.ClearChargingProfileRes], - "ClearDisplayMessage": unmarshalResponsePayloadv201[v201.ClearDisplayMessageRes], - "ClearedChargingLimit": unmarshalResponsePayloadv201[v201.ClearedChargingLimitRes], - "ClearVariableMonitoring": unmarshalResponsePayloadv201[v201.ClearVariableMonitoringRes], - "CostUpdated": unmarshalResponsePayloadv201[v201.CostUpdatedRes], - "CustomerInformation": unmarshalResponsePayloadv201[v201.CustomerInformationRes], - "DataTransfer": unmarshalResponsePayloadv201[v201.DataTransferRes], - "DeleteCertificate": unmarshalResponsePayloadv201[v201.DeleteCertificateRes], - "FirmwareStatusNotification": unmarshalResponsePayloadv201[v201.FirmwareStatusNotificationRes], - "Get15118EVCertificate": unmarshalResponsePayloadv201[v201.Get15118EVCertificateRes], - "GetBaseReport": unmarshalResponsePayloadv201[v201.GetBaseReportRes], - "GetCertificateStatus": unmarshalResponsePayloadv201[v201.GetCertificateStatusRes], - "GetChargingProfiles": unmarshalResponsePayloadv201[v201.GetChargingProfilesRes], - "GetCompositeSchedule": unmarshalResponsePayloadv201[v201.GetCompositeScheduleRes], - "GetDisplayMessages": unmarshalResponsePayloadv201[v201.GetDisplayMessagesRes], - "GetInstalledCertificateIds": unmarshalResponsePayloadv201[v201.GetInstalledCertificateIdsRes], - "GetLocalListVersion": unmarshalResponsePayloadv201[v201.GetLocalListVersionRes], - "GetLog": unmarshalResponsePayloadv201[v201.GetLogRes], - "GetMonitoringReport": unmarshalResponsePayloadv201[v201.GetMonitoringReportRes], - "GetReport": unmarshalResponsePayloadv201[v201.GetReportRes], - "GetTransactionStatus": unmarshalResponsePayloadv201[v201.GetTransactionStatusRes], - "GetVariables": unmarshalResponsePayloadv201[v201.GetVariablesRes], - "Heartbeat": unmarshalResponsePayloadv201[v201.HeartbeatRes], - "InstallCertificate": unmarshalResponsePayloadv201[v201.InstallCertificateRes], - "LogStatusNotification": unmarshalResponsePayloadv201[v201.LogStatusNotificationRes], - "MeterValues": unmarshalResponsePayloadv201[v201.MeterValuesRes], - "NotifyChargingLimit": unmarshalResponsePayloadv201[v201.NotifyChargingLimitRes], - "NotifyCustomerInformation": unmarshalResponsePayloadv201[v201.NotifyCustomerInformationRes], - "NotifyDisplayMessages": unmarshalResponsePayloadv201[v201.NotifyDisplayMessagesRes], - "NotifyEVChargingNeeds": unmarshalResponsePayloadv201[v201.NotifyEVChargingNeedsRes], - "NotifyEVChargingSchedule": unmarshalResponsePayloadv201[v201.NotifyEVChargingScheduleRes], - "NotifyEvent": unmarshalResponsePayloadv201[v201.NotifyEventRes], - "NotifyMonitoringReport": unmarshalResponsePayloadv201[v201.NotifyMonitoringReportRes], - "NotifyReport": unmarshalResponsePayloadv201[v201.NotifyReportRes], - "PublishFirmware": unmarshalResponsePayloadv201[v201.PublishFirmwareRes], + "Authorize": unmarshalResponsePayloadv201[v201.AuthorizeRes], + "BootNotification": unmarshalResponsePayloadv201[v201.BootNotificationRes], + "CancelReservation": unmarshalResponsePayloadv201[v201.CancelReservationRes], + "CertificateSigned": unmarshalResponsePayloadv201[v201.CertificateSignedRes], + "ChangeAvailability": unmarshalResponsePayloadv201[v201.ChangeAvailabilityRes], + "ClearCache": unmarshalResponsePayloadv201[v201.ClearCacheRes], + "ClearChargingProfile": unmarshalResponsePayloadv201[v201.ClearChargingProfileRes], + "ClearDisplayMessage": unmarshalResponsePayloadv201[v201.ClearDisplayMessageRes], + "ClearedChargingLimit": unmarshalResponsePayloadv201[v201.ClearedChargingLimitRes], + "ClearVariableMonitoring": unmarshalResponsePayloadv201[v201.ClearVariableMonitoringRes], + "CostUpdated": unmarshalResponsePayloadv201[v201.CostUpdatedRes], + "CustomerInformation": unmarshalResponsePayloadv201[v201.CustomerInformationRes], + "DataTransfer": unmarshalResponsePayloadv201[v201.DataTransferRes], + "DeleteCertificate": unmarshalResponsePayloadv201[v201.DeleteCertificateRes], + "FirmwareStatusNotification": unmarshalResponsePayloadv201[v201.FirmwareStatusNotificationRes], + "Get15118EVCertificate": unmarshalResponsePayloadv201[v201.Get15118EVCertificateRes], + "GetBaseReport": unmarshalResponsePayloadv201[v201.GetBaseReportRes], + "GetCertificateStatus": unmarshalResponsePayloadv201[v201.GetCertificateStatusRes], + "GetChargingProfiles": unmarshalResponsePayloadv201[v201.GetChargingProfilesRes], + "GetCompositeSchedule": unmarshalResponsePayloadv201[v201.GetCompositeScheduleRes], + "GetDisplayMessages": unmarshalResponsePayloadv201[v201.GetDisplayMessagesRes], + "GetInstalledCertificateIds": unmarshalResponsePayloadv201[v201.GetInstalledCertificateIdsRes], + "GetLocalListVersion": unmarshalResponsePayloadv201[v201.GetLocalListVersionRes], + "GetLog": unmarshalResponsePayloadv201[v201.GetLogRes], + "GetMonitoringReport": unmarshalResponsePayloadv201[v201.GetMonitoringReportRes], + "GetReport": unmarshalResponsePayloadv201[v201.GetReportRes], + "GetTransactionStatus": unmarshalResponsePayloadv201[v201.GetTransactionStatusRes], + "GetVariables": unmarshalResponsePayloadv201[v201.GetVariablesRes], + "Heartbeat": unmarshalResponsePayloadv201[v201.HeartbeatRes], + "InstallCertificate": unmarshalResponsePayloadv201[v201.InstallCertificateRes], + "LogStatusNotification": unmarshalResponsePayloadv201[v201.LogStatusNotificationRes], + "MeterValues": unmarshalResponsePayloadv201[v201.MeterValuesRes], + "NotifyChargingLimit": unmarshalResponsePayloadv201[v201.NotifyChargingLimitRes], + "NotifyCustomerInformation": unmarshalResponsePayloadv201[v201.NotifyCustomerInformationRes], + "NotifyDisplayMessages": unmarshalResponsePayloadv201[v201.NotifyDisplayMessagesRes], + "NotifyEVChargingNeeds": unmarshalResponsePayloadv201[v201.NotifyEVChargingNeedsRes], + "NotifyEVChargingSchedule": unmarshalResponsePayloadv201[v201.NotifyEVChargingScheduleRes], + "NotifyEvent": unmarshalResponsePayloadv201[v201.NotifyEventRes], + "NotifyMonitoringReport": unmarshalResponsePayloadv201[v201.NotifyMonitoringReportRes], + "NotifyReport": unmarshalResponsePayloadv201[v201.NotifyReportRes], + "PublishFirmware": unmarshalResponsePayloadv201[v201.PublishFirmwareRes], "PublishFirmawareStatusNotification": unmarshalResponsePayloadv201[v201.PublishFirmwareStatusNotificationRes], - "ReportChargingProfiles": unmarshalResponsePayloadv201[v201.ReportChargingProfilesRes], - "RequestStartTransaction": unmarshalResponsePayloadv201[v201.RequestStartTransactionRes], - "RequestStopTransaction": unmarshalResponsePayloadv201[v201.RequestStopTransactionRes], - "ReservationStatusUpdate": unmarshalResponsePayloadv201[v201.ReservationStatusUpdateRes], - "ReserveNow": unmarshalResponsePayloadv201[v201.ReserveNowRes], - "Reset": unmarshalResponsePayloadv201[v201.ResetRes], - "SecurityEventNotification": unmarshalResponsePayloadv201[v201.SecurityEventNotificationRes], - "SendLocalList": unmarshalResponsePayloadv201[v201.SendLocalListRes], - "SetChargingProfile": unmarshalResponsePayloadv201[v201.SetChargingProfileRes], - "SetDisplayMessage": unmarshalResponsePayloadv201[v201.SetDisplayMessageRes], - "SetMonitoringBase": unmarshalResponsePayloadv201[v201.SetMonitoringBaseRes], - "SetMonitoringLevel": unmarshalResponsePayloadv201[v201.SetMonitoringLevelRes], - "SetNetworkProfile": unmarshalResponsePayloadv201[v201.SetNetworkProfileRes], - "SetVariableMonitoring": unmarshalResponsePayloadv201[v201.SetVariableMonitoringRes], - "SetVariables": unmarshalResponsePayloadv201[v201.SetVariablesRes], - "SignCertificate": unmarshalResponsePayloadv201[v201.SignCertificateRes], - "StatusNotification": unmarshalResponsePayloadv201[v201.StatusNotificationRes], - "TransactionEvent": unmarshalResponsePayloadv201[v201.TransactionEventRes], - "TriggerMessage": unmarshalResponsePayloadv201[v201.TriggerMessageRes], - "UnlockConnector": unmarshalResponsePayloadv201[v201.UnlockConnectorRes], - "UnpublishFirmware": unmarshalResponsePayloadv201[v201.UnpublishFirmwareRes], - "UpdateFirmware": unmarshalResponsePayloadv201[v201.UpdateFirmwareRes], + "ReportChargingProfiles": unmarshalResponsePayloadv201[v201.ReportChargingProfilesRes], + "RequestStartTransaction": unmarshalResponsePayloadv201[v201.RequestStartTransactionRes], + "RequestStopTransaction": unmarshalResponsePayloadv201[v201.RequestStopTransactionRes], + "ReservationStatusUpdate": unmarshalResponsePayloadv201[v201.ReservationStatusUpdateRes], + "ReserveNow": unmarshalResponsePayloadv201[v201.ReserveNowRes], + "Reset": unmarshalResponsePayloadv201[v201.ResetRes], + "SecurityEventNotification": unmarshalResponsePayloadv201[v201.SecurityEventNotificationRes], + "SendLocalList": unmarshalResponsePayloadv201[v201.SendLocalListRes], + "SetChargingProfile": unmarshalResponsePayloadv201[v201.SetChargingProfileRes], + "SetDisplayMessage": unmarshalResponsePayloadv201[v201.SetDisplayMessageRes], + "SetMonitoringBase": unmarshalResponsePayloadv201[v201.SetMonitoringBaseRes], + "SetMonitoringLevel": unmarshalResponsePayloadv201[v201.SetMonitoringLevelRes], + "SetNetworkProfile": unmarshalResponsePayloadv201[v201.SetNetworkProfileRes], + "SetVariableMonitoring": unmarshalResponsePayloadv201[v201.SetVariableMonitoringRes], + "SetVariables": unmarshalResponsePayloadv201[v201.SetVariablesRes], + "SignCertificate": unmarshalResponsePayloadv201[v201.SignCertificateRes], + "StatusNotification": unmarshalResponsePayloadv201[v201.StatusNotificationRes], + "TransactionEvent": unmarshalResponsePayloadv201[v201.TransactionEventRes], + "TriggerMessage": unmarshalResponsePayloadv201[v201.TriggerMessageRes], + "UnlockConnector": unmarshalResponsePayloadv201[v201.UnlockConnectorRes], + "UnpublishFirmware": unmarshalResponsePayloadv201[v201.UnpublishFirmwareRes], + "UpdateFirmware": unmarshalResponsePayloadv201[v201.UpdateFirmwareRes], } -} \ No newline at end of file +} diff --git a/messages_test.go b/messages_test.go new file mode 100644 index 0000000..5f88b3a --- /dev/null +++ b/messages_test.go @@ -0,0 +1,47 @@ +package ocpp + +import ( + "reflect" + "testing" +) + +type RawMessage struct { + data []byte + proto string +} + + +// Add more test cases +func TestUnpack(t *testing.T) { + cases := []struct{ + name string + rawMsg RawMessage + want1 OcppMessage + want2 error + }{ + { "non array json", + RawMessage{ []byte(`{"some": "data"}`),"ocppv16",}, + nil, + &ocppError{ + id: "-1", + code: "ProtocolError", + cause: "Invalid JSON format", + }, + }, + + } + + for _, v := range cases { + t.Run(v.name, func(t *testing.T) { + got1, got2 := unpack(v.rawMsg.data, v.rawMsg.proto) + + if got1 != v.want1{ + t.Errorf("got %v want %v", got1, v.want1) + } + + if !reflect.DeepEqual(got2, v.want2) { + t.Errorf("got %v want %v", got2, v.want2) + } + }) + } +} \ No newline at end of file diff --git a/server.go b/server.go index ec17027..74c4aa0 100644 --- a/server.go +++ b/server.go @@ -11,46 +11,40 @@ import ( "github.com/gorilla/websocket" ) - - var server *Server type ServerTimeoutConfig struct { // ocpp response timeout in seconds - OcppWait time.Duration + OcppWait time.Duration // time allowed to write a message to the peer - WriteWait time.Duration + WriteWait time.Duration // time allowed to read the next pong message from the peer - PingWait time.Duration + PingWait time.Duration } - - // Server type representes csms server type Server struct { // keeps track of all connected ChargePoints - chargepoints map[string]*ChargePoint - + chargepoints map[string]*ChargePoint + // register implemented action handler functions actionHandlers map[string]func(*ChargePoint, Payload) Payload - + // register after-action habdler functions - afterHandlers map[string]func(*ChargePoint, Payload) - + afterHandlers map[string]func(*ChargePoint, Payload) + // timeout configuration - ocppWait time.Duration - - - writeWait time.Duration + ocppWait time.Duration + writeWait time.Duration - pingWait time.Duration + pingWait time.Duration - mu sync.Mutex - - upgrader websocket.Upgrader + mu sync.Mutex + + upgrader websocket.Upgrader preUpgradeHandler func(w http.ResponseWriter, r *http.Request) bool @@ -65,9 +59,9 @@ func NewServer() *Server { chargepoints: make(map[string]*ChargePoint), actionHandlers: make(map[string]func(*ChargePoint, Payload) Payload), afterHandlers: make(map[string]func(*ChargePoint, Payload)), - ocppWait: ocppWait, - writeWait: writeWait, - pingWait: pingWait, + ocppWait: ocppWait, + writeWait: writeWait, + pingWait: pingWait, upgrader: websocket.Upgrader{ Subprotocols: []string{}, }, @@ -75,14 +69,12 @@ func NewServer() *Server { return server } - func (s *Server) SetTimeoutConfig(config ServerTimeoutConfig) { s.ocppWait = config.OcppWait s.writeWait = config.WriteWait s.pingWait = config.PingWait } - // register action handler function func (s *Server) On(action string, f func(*ChargePoint, Payload) Payload) *Server { s.actionHandlers[action] = f @@ -95,13 +87,12 @@ func (s *Server) After(action string, f func(*ChargePoint, Payload)) *Server { return s } - func (s *Server) IsConnected(id string) bool { if cp, ok := s.chargepoints[id]; ok { return cp.connected } - return false -} + return false +} func (s *Server) getHandler(action string) func(*ChargePoint, Payload) Payload { return s.actionHandlers[action] @@ -111,9 +102,8 @@ func (s *Server) getAfterHandler(action string) func(*ChargePoint, Payload) { return s.afterHandlers[action] } - func (s *Server) Delete(id string) { - s.mu.Lock() + s.mu.Lock() if cp, ok := s.chargepoints[id]; ok { cp.connected = false } @@ -121,15 +111,12 @@ func (s *Server) Delete(id string) { s.mu.Unlock() } - - func (s *Server) Store(cp *ChargePoint) { s.mu.Lock() server.chargepoints[cp.Id] = cp s.mu.Unlock() } - func (s *Server) Load(id string) (*ChargePoint, bool) { s.mu.Lock() defer s.mu.Unlock() @@ -140,8 +127,6 @@ func (s *Server) Load(id string) (*ChargePoint, bool) { return nil, false } - - func (s *Server) AddSubProtocol(protocol string) { for _, p := range server.upgrader.Subprotocols { if p == protocol { @@ -151,17 +136,14 @@ func (s *Server) AddSubProtocol(protocol string) { s.upgrader.Subprotocols = append(s.upgrader.Subprotocols, protocol) } - func (s *Server) SetCheckOriginHandler(f func(r *http.Request) bool) { s.upgrader.CheckOrigin = f } - func (s *Server) SetPreUpgradeHandler(f func(w http.ResponseWriter, r *http.Request) bool) { s.preUpgradeHandler = f } - // TODO: add more functionality func (s *Server) Start(addr string, path string, handler func(http.ResponseWriter, *http.Request)) { if handler != nil { @@ -183,8 +165,7 @@ func defaultWebsocketHandler(w http.ResponseWriter, r *http.Request) { } else { upgrade(w, r) } -} - +} func upgrade(w http.ResponseWriter, r *http.Request) { c, err := server.upgrader.Upgrade(w, r, nil) @@ -200,11 +181,11 @@ func upgrade(w http.ResponseWriter, r *http.Request) { func (s *Server) SetCallQueueSize(size int) { s.callQuequeSize = size -} +} func (s *Server) getCallQueueSize() int { s.mu.Lock() size := s.callQuequeSize s.mu.Unlock() return size -} \ No newline at end of file +}