Skip to content

Commit

Permalink
Ocpp: serialise setup (#16262)
Browse files Browse the repository at this point in the history
  • Loading branch information
andig authored Sep 22, 2024
1 parent 92e4f46 commit df353c6
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 32 deletions.
42 changes: 17 additions & 25 deletions charger/ocpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,34 +120,26 @@ func NewOCPP(id string, connector int, idTag string,
stackLevelZero, remoteStart bool,
connectTimeout time.Duration,
) (*OCPP, error) {
unit := "ocpp"
if id != "" {
unit = id
}
unit = fmt.Sprintf("%s-%d", unit, connector)

log := util.NewLogger(unit)

cp, err := ocpp.Instance().ChargepointByID(id)
if err != nil {
cp = ocpp.NewChargePoint(log, id)
log := util.NewLogger(fmt.Sprintf("%s-%d", lo.CoalesceOrEmpty(id, "ocpp"), connector))

// should not error
if err := ocpp.Instance().Register(id, cp); err != nil {
return nil, err
}

log.DEBUG.Printf("waiting for chargepoint: %v", connectTimeout)
cp, err := ocpp.Instance().RegisterChargepoint(id,
func() *ocpp.CP {
return ocpp.NewChargePoint(log, id)
},
func(cp *ocpp.CP) error {
log.DEBUG.Printf("waiting for chargepoint: %v", connectTimeout)

select {
case <-time.After(connectTimeout):
return nil, api.ErrTimeout
case <-cp.HasConnected():
}
select {
case <-time.After(connectTimeout):
return api.ErrTimeout
case <-cp.HasConnected():
}

if err := cp.Setup(meterValues, meterInterval); err != nil {
return nil, err
}
return cp.Setup(meterValues, meterInterval)
},
)
if err != nil {
return nil, err
}

if cp.NumberOfConnectors > 0 && connector > cp.NumberOfConnectors {
Expand Down
49 changes: 42 additions & 7 deletions charger/ocpp/cs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,34 @@ type CS struct {
log *util.Logger
ocpp16.CentralSystem
cps map[string]*CP
init map[string]*sync.Mutex
txnId int
}

// Register registers a charge point with the central system.
// The charge point identified by id may already be connected in which case initial connection is triggered.
func (cs *CS) Register(id string, cp *CP) error {
func (cs *CS) register(id string, new *CP) error {
cs.mu.Lock()
defer cs.mu.Unlock()

if _, ok := cs.cps[id]; ok && id == "" {
return errors.New("cannot have >1 charge point with empty station id")
cp, ok := cs.cps[id]

// case 1: charge point neither registered nor physically connected
if !ok {
cs.cps[id] = new
return nil
}

// trigger unknown charge point connected
if unknown, ok := cs.cps[id]; ok && unknown == nil {
cp.connect(true)
// case 2: duplicate registration of id empty
if id == "" {
return errors.New("cannot have >1 charge point with empty station id")
}

cs.cps[id] = cp
// case 3: charge point not registered but physically already connected
if cp == nil {
cs.cps[id] = new
new.connect(true)
}

return nil
}
Expand All @@ -58,6 +67,32 @@ func (cs *CS) ChargepointByID(id string) (*CP, error) {
return cp, nil
}

func (cs *CS) RegisterChargepoint(id string, newfun func() *CP, init func(*CP) error) (*CP, error) {
cs.mu.Lock()
cpmu, ok := cs.init[id]
if !ok {
cpmu = new(sync.Mutex)
cs.init[id] = cpmu
}
cs.mu.Unlock()

// serialise on chargepoint id
cpmu.Lock()
defer cpmu.Unlock()

cp, err := cs.ChargepointByID(id)
if err != nil {
cp = newfun()
}

// should not error
if err := cs.register(id, cp); err != nil {
return nil, err
}

return cp, init(cp)
}

// NewChargePoint implements ocpp16.ChargePointConnectionHandler
func (cs *CS) NewChargePoint(chargePoint ocpp16.ChargePointConnection) {
cs.mu.Lock()
Expand Down
1 change: 1 addition & 0 deletions charger/ocpp/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func Instance() *CS {
instance = &CS{
log: log,
cps: make(map[string]*CP),
init: make(map[string]*sync.Mutex),
CentralSystem: cs,
txnId: int(time.Now().UTC().Unix()),
}
Expand Down

0 comments on commit df353c6

Please sign in to comment.