From 640242bf946030ec9b0342d8d7abd76a7b7550ca Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 1 Aug 2022 11:34:15 +0200 Subject: [PATCH] Ocpp: handle nil timestamp (#3930) --- charger/ocpp/cp.go | 10 +++++----- charger/ocpp/cp_core.go | 35 ++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/charger/ocpp/cp.go b/charger/ocpp/cp.go index 7aa3725be..c4ec66e68 100644 --- a/charger/ocpp/cp.go +++ b/charger/ocpp/cp.go @@ -60,11 +60,11 @@ type CP struct { boot *core.BootNotificationRequest status *core.StatusNotificationRequest - meterSupported bool - meterUpdated time.Time - measureDoneCh chan struct{} - measurements map[string]types.SampledValue - meterTrickerRunning bool + meterSupported bool + measureDoneCh chan struct{} + meterUpdated time.Time + measurements map[string]types.SampledValue + meterTickerRunning bool supportedNumberOfConnectors int smartChargingCapabilities smartChargingProfile diff --git a/charger/ocpp/cp_core.go b/charger/ocpp/cp_core.go index df470512e..5b2dff874 100644 --- a/charger/ocpp/cp_core.go +++ b/charger/ocpp/cp_core.go @@ -9,6 +9,11 @@ import ( "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" ) +const ( + messageExpiry = 30 * time.Second + transactionExpiry = time.Hour +) + func (cp *CP) Authorize(request *core.AuthorizeRequest) (*core.AuthorizeConfirmation, error) { cp.log.TRACE.Printf("%T: %+v", request, request) @@ -42,6 +47,22 @@ func (cp *CP) BootNotification(request *core.BootNotificationRequest) (*core.Boo return res, nil } +// timestampValid returns false if status timestamps are outdated +func (cp *CP) timestampValid(t time.Time) bool { + // reject if expired + if time.Since(t) > messageExpiry { + return false + } + + // assume having a timestamp is better than not + if cp.status.Timestamp == nil { + return true + } + + // reject older values than we already have + return !t.Before(cp.status.Timestamp.Time) +} + func (cp *CP) StatusNotification(request *core.StatusNotificationRequest) (*core.StatusNotificationConfirmation, error) { cp.log.TRACE.Printf("%T: %+v", request, request) @@ -52,7 +73,7 @@ func (cp *CP) StatusNotification(request *core.StatusNotificationRequest) (*core if cp.status == nil { cp.status = request cp.initialized.Broadcast() - } else if (request.Timestamp.Equal(cp.status.Timestamp.Time) || request.Timestamp.After(cp.status.Timestamp.Time)) && request.Timestamp.After(time.Now().Add(-30*time.Second)) { + } else if request.Timestamp == nil || cp.timestampValid(request.Timestamp.Time) { cp.status = request } else { cp.log.TRACE.Printf("ignoring status: %s < %s", request.Timestamp.Time, cp.status.Timestamp) @@ -86,7 +107,7 @@ func (cp *CP) Heartbeat(request *core.HeartbeatRequest) (*core.HeartbeatConfirma CurrentTime: types.NewDateTime(time.Now()), } - if !cp.meterTrickerRunning && cp.meterSupported { + if !cp.meterTickerRunning && cp.meterSupported { Instance().TriggerMeterValueRequest(cp) } @@ -144,7 +165,7 @@ func (cp *CP) StartTransaction(request *core.StartTransactionRequest) (*core.Sta // create new transaction if request != nil { - if request.Timestamp.After(time.Now().Add(-1 * time.Hour)) { // only respect transactions in the last hour + if time.Since(request.Timestamp.Time) < transactionExpiry { // only respect transactions in the last hour cp.mu.Lock() cp.currentTransaction = NewTransaction(cp.currentTransaction.ID+1, request.IdTag, request.Timestamp.Time, request.MeterStart) @@ -152,10 +173,10 @@ func (cp *CP) StartTransaction(request *core.StartTransactionRequest) (*core.Sta res.TransactionId = cp.currentTransaction.ID - if request.Timestamp.After(time.Now().Add(-30*time.Second)) && cp.meterSupported && !cp.meterTrickerRunning { + if cp.meterSupported && !cp.meterTickerRunning && time.Since(request.Timestamp.Time) < messageExpiry { go func() { cp.log.TRACE.Printf("starting meter value ticker") - cp.meterTrickerRunning = true + cp.meterTickerRunning = true cp.measureDoneCh = make(chan struct{}) ticker := time.NewTicker(15 * time.Second) @@ -166,7 +187,7 @@ func (cp *CP) StartTransaction(request *core.StartTransactionRequest) (*core.Sta Instance().TriggerMeterValueRequest(cp) case <-cp.measureDoneCh: cp.log.TRACE.Printf("returning from meter value requests") - cp.meterTrickerRunning = false + cp.meterTickerRunning = false return } } @@ -202,7 +223,7 @@ func (cp *CP) StopTransaction(request *core.StopTransactionRequest) (*core.StopT } if cp.meterSupported { - if cp.meterTrickerRunning { + if cp.meterTickerRunning { cp.measureDoneCh <- struct{}{} }