Skip to content

Commit 36970dd

Browse files
committed
Merge branch 'release/v0.6.2'
2 parents 68c6bcc + 6c8360d commit 36970dd

10 files changed

Lines changed: 146 additions & 14 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# spine-go
22

3-
[![Build Status](https://github.com/enbility/spine-go/actions/workflows/default.yml/badge.svg?branch=main)](https://github.com/enbility/spine-go/actions/workflows/default.yml/badge.svg?branch=main)
3+
[![Build Status](https://github.com/enbility/spine-go/actions/workflows/default.yml/badge.svg?branch=master)](https://github.com/enbility/spine-go/actions/workflows/default.yml/badge.svg?branch=master)
44
[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4)](https://godoc.org/github.com/enbility/spine-go)
5-
[![Coverage Status](https://coveralls.io/repos/github/enbility/spine-go/badge.svg?branch=main)](https://coveralls.io/github/enbility/spine-go?branch=main)
5+
[![Coverage Status](https://coveralls.io/repos/github/enbility/spine-go/badge.svg?branch=master)](https://coveralls.io/github/enbility/spine-go?branch=master)
66
[![Go report](https://goreportcard.com/badge/github.com/enbility/spine-go)](https://goreportcard.com/report/github.com/enbility/spine-go)
77
[![CodeFactor](https://www.codefactor.io/repository/github/enbility/spine-go/badge)](https://www.codefactor.io/repository/github/enbility/spine-go)
88

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.21.1
44

55
require (
66
github.com/ahmetb/go-linq/v3 v3.2.0
7-
github.com/enbility/ship-go v0.5.2
7+
github.com/enbility/ship-go v0.5.3
88
github.com/golanguzb70/lrucache v1.2.0
99
github.com/google/go-cmp v0.6.0
1010
github.com/rickb777/date v1.20.6

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ github.com/ahmetb/go-linq/v3 v3.2.0 h1:BEuMfp+b59io8g5wYzNoFe9pWPalRklhlhbiU3hYZ
22
github.com/ahmetb/go-linq/v3 v3.2.0/go.mod h1:haQ3JfOeWK8HpVxMtHHEMPVgBKiYyQ+f1/kLZh/cj9U=
33
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
44
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5-
github.com/enbility/ship-go v0.5.2 h1:T9+YuP5ZpofKd463PLKq78fAaPAcGMnRAcv8c8aD5yU=
6-
github.com/enbility/ship-go v0.5.2/go.mod h1:jewJWYQ10jNhsnhS1C4jESx3CNmDa5HNWZjBhkTug5Y=
5+
github.com/enbility/ship-go v0.5.3 h1:P8eA/WDz3hq18zEKzqCB697OA1sVFiZkTF51Cx4tyGU=
6+
github.com/enbility/ship-go v0.5.3/go.mod h1:jewJWYQ10jNhsnhS1C4jESx3CNmDa5HNWZjBhkTug5Y=
77
github.com/golanguzb70/lrucache v1.2.0 h1:VjpjmB4VTf9VXBtZTJGcgcN0CNFM5egDrrSjkGyQOlg=
88
github.com/golanguzb70/lrucache v1.2.0/go.mod h1:zc2GD26KwGEDdTHsCCTcJorv/11HyKwQVS9gqg2bizc=
99
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=

spine/function_data_cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func filtersForSelectorsElements(functionType model.FunctionType, filters []mode
7878
if !util.IsNil(partialSelector) {
7979
filter = addSelectorToFilter(filter, functionType, partialSelector)
8080
}
81-
if !util.IsNil(readElements != nil) {
81+
if !util.IsNil(readElements) {
8282
filter = addElementToFilter(filter, functionType, readElements)
8383
}
8484
filters = append(filters, filter)

spine/heartbeat_manager.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ func (c *HeartbeatManager) heartbeatData(t time.Time, counter *uint64) *model.De
120120
}
121121

122122
func (c *HeartbeatManager) updateHeartbeatData(stopC chan struct{}, d time.Duration) {
123+
// Substract two seconds, because some devices (like Elli Connect/Pro) with OPEV/OSCEV interpret
124+
// the heartbeat timeout (<= 4s) as the time within which a heartbeat should be received and otherwise
125+
// will go into fallback mode.
126+
// But other EVSE devices and in LPC (<= 60s), the heartbeat should be considered missing, if it is not
127+
// received within twice the heartbeat timeout timeframe.
128+
if d > 2*time.Second {
129+
d -= 2 * time.Second
130+
}
123131
ticker := time.NewTicker(d)
124132
for {
125133
select {

spine/helper_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import (
1818
)
1919

2020
const (
21-
wallbox_detaileddiscoverydata_recv_reply_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_reply.json"
22-
wallbox_detaileddiscoverydata_recv_notify_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_notify.json"
21+
wallbox_detaileddiscoverydata_recv_reply_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_reply.json"
22+
wallbox_detaileddiscoverydata_recv_notify_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_notify.json"
23+
wallbox_detaileddiscoverydata_recv_notify_remove_file_path = "./testdata/wallbox_detaileddiscoverydata_recv_notify_remove.json"
2324
)
2425

2526
type WriteMessageHandler struct {

spine/nodemanagement_detaileddiscovery_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,27 @@ func (s *NodeManagementSuite) TestDetailedDiscovery_RecvNotifyAdded() {
153153
assert.Equal(s.T(), 10, len(ev.Features()))
154154
}
155155
}
156+
157+
// Act
158+
msgCounter, _ = s.remoteDevice.HandleSpineMesssage(loadFileData(s.T(), wallbox_detaileddiscoverydata_recv_notify_remove_file_path))
159+
waitForAck(s.T(), msgCounter, s.writeHandler)
160+
161+
// Assert
162+
rEntities = remoteDevice.Entities()
163+
if assert.Equal(s.T(), 2, len(rEntities)) {
164+
{
165+
di := rEntities[DeviceInformationEntityId]
166+
assert.NotNil(s.T(), di)
167+
assert.Equal(s.T(), model.EntityTypeTypeDeviceInformation, di.EntityType())
168+
assert.Equal(s.T(), 2, len(di.Features()))
169+
}
170+
{
171+
evse := rEntities[1]
172+
assert.NotNil(s.T(), evse)
173+
assert.Equal(s.T(), model.EntityTypeTypeEVSE, evse.EntityType())
174+
assert.Equal(s.T(), 3, len(evse.Features()))
175+
}
176+
}
156177
}
157178

158179
func (s *NodeManagementSuite) TestDetailedDiscovery_SendReplyWithAcknowledge() {

spine/subscription_manager.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ func (c *SubscriptionManager) RemoveSubscription(data model.SubscriptionManageme
114114
for _, item := range c.subscriptionEntries {
115115
itemAddress := item.ClientFeature.Address()
116116

117-
if !reflect.DeepEqual(*itemAddress, clientAddress) &&
117+
if !reflect.DeepEqual(itemAddress.Device, clientAddress.Device) ||
118+
!reflect.DeepEqual(itemAddress.Entity, clientAddress.Entity) ||
119+
!reflect.DeepEqual(itemAddress.Feature, clientAddress.Feature) ||
118120
!reflect.DeepEqual(item.ServerFeature, serverFeature) {
119121
newSubscriptionEntries = append(newSubscriptionEntries, item)
120122
}
@@ -163,7 +165,8 @@ func (c *SubscriptionManager) RemoveSubscriptionsForEntity(remoteEntity api.Enti
163165

164166
var newSubscriptionEntries []*api.SubscriptionEntry
165167
for _, item := range c.subscriptionEntries {
166-
if !reflect.DeepEqual(item.ClientFeature.Address().Entity, remoteEntity.Address().Entity) {
168+
if !reflect.DeepEqual(item.ClientFeature.Address().Device, remoteEntity.Address().Device) ||
169+
!reflect.DeepEqual(item.ClientFeature.Address().Entity, remoteEntity.Address().Entity) {
167170
newSubscriptionEntries = append(newSubscriptionEntries, item)
168171
continue
169172
}

spine/subscription_manager_test.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ func TestSubscriptionManagerSuite(t *testing.T) {
1818
type SubscriptionManagerSuite struct {
1919
suite.Suite
2020

21-
localDevice api.DeviceLocalInterface
22-
remoteDevice api.DeviceRemoteInterface
23-
sut api.SubscriptionManagerInterface
21+
localDevice api.DeviceLocalInterface
22+
remoteDevice,
23+
remoteDevice2 api.DeviceRemoteInterface
24+
sut api.SubscriptionManagerInterface
2425
}
2526

2627
func (suite *SubscriptionManagerSuite) WriteShipMessageWithPayload([]byte) {}
@@ -31,9 +32,12 @@ func (suite *SubscriptionManagerSuite) SetupSuite() {
3132
ski := "test"
3233
sender := NewSender(suite)
3334
suite.remoteDevice = NewDeviceRemote(suite.localDevice, ski, sender)
34-
3535
_ = suite.localDevice.SetupRemoteDevice(ski, suite)
3636

37+
ski2 := "test2"
38+
suite.remoteDevice2 = NewDeviceRemote(suite.localDevice, ski2, sender)
39+
_ = suite.localDevice.SetupRemoteDevice(ski2, suite)
40+
3741
suite.sut = NewSubscriptionManager(suite.localDevice)
3842
}
3943

@@ -49,13 +53,28 @@ func (suite *SubscriptionManagerSuite) Test_Subscriptions() {
4953
remoteFeature := NewFeatureRemote(remoteEntity.NextFeatureId(), remoteEntity, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeClient)
5054
remoteFeature.Address().Device = util.Ptr(model.AddressDeviceType("remoteDevice"))
5155
remoteEntity.AddFeature(remoteFeature)
56+
remoteEntity.Address().Device = util.Ptr(model.AddressDeviceType("remoteDevice"))
5257

5358
subscrRequest := model.SubscriptionManagementRequestCallType{
5459
ClientAddress: remoteFeature.Address(),
5560
ServerAddress: localFeature.Address(),
5661
ServerFeatureType: util.Ptr(model.FeatureTypeTypeDeviceDiagnosis),
5762
}
5863

64+
remoteEntity2 := NewEntityRemote(suite.remoteDevice2, model.EntityTypeTypeEVSE, []model.AddressEntityType{1})
65+
suite.remoteDevice2.AddEntity(remoteEntity2)
66+
67+
remoteFeature2 := NewFeatureRemote(remoteEntity2.NextFeatureId(), remoteEntity2, model.FeatureTypeTypeDeviceDiagnosis, model.RoleTypeClient)
68+
remoteFeature2.Address().Device = util.Ptr(model.AddressDeviceType("remoteDevice2"))
69+
remoteEntity2.AddFeature(remoteFeature2)
70+
remoteEntity2.Address().Device = util.Ptr(model.AddressDeviceType("remoteDevice2"))
71+
72+
subscrRequest2 := model.SubscriptionManagementRequestCallType{
73+
ClientAddress: remoteFeature2.Address(),
74+
ServerAddress: localFeature.Address(),
75+
ServerFeatureType: util.Ptr(model.FeatureTypeTypeDeviceDiagnosis),
76+
}
77+
5978
subMgr := suite.localDevice.SubscriptionManager()
6079
err := subMgr.AddSubscription(suite.remoteDevice, subscrRequest)
6180
assert.Nil(suite.T(), err)
@@ -69,6 +88,12 @@ func (suite *SubscriptionManagerSuite) Test_Subscriptions() {
6988
subs = subMgr.Subscriptions(suite.remoteDevice)
7089
assert.Equal(suite.T(), 1, len(subs))
7190

91+
err = subMgr.AddSubscription(suite.remoteDevice2, subscrRequest2)
92+
assert.Nil(suite.T(), err)
93+
94+
subs = subMgr.Subscriptions(suite.remoteDevice2)
95+
assert.Equal(suite.T(), 1, len(subs))
96+
7297
subscrDelete := model.SubscriptionManagementDeleteCallType{
7398
ClientAddress: remoteFeature.Address(),
7499
ServerAddress: localFeature.Address(),
@@ -90,8 +115,21 @@ func (suite *SubscriptionManagerSuite) Test_Subscriptions() {
90115
subs = subMgr.Subscriptions(suite.remoteDevice)
91116
assert.Equal(suite.T(), 1, len(subs))
92117

118+
subMgr.RemoveSubscriptionsForEntity(nil)
119+
120+
subs = subMgr.Subscriptions(suite.remoteDevice)
121+
assert.Equal(suite.T(), 1, len(subs))
122+
123+
subMgr.RemoveSubscriptionsForDevice(nil)
124+
125+
subs = subMgr.Subscriptions(suite.remoteDevice)
126+
assert.Equal(suite.T(), 1, len(subs))
127+
93128
subMgr.RemoveSubscriptionsForDevice(suite.remoteDevice)
94129

95130
subs = subMgr.Subscriptions(suite.remoteDevice)
96131
assert.Equal(suite.T(), 0, len(subs))
132+
133+
subs = subMgr.Subscriptions(suite.remoteDevice2)
134+
assert.Equal(suite.T(), 1, len(subs))
97135
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"datagram": {
3+
"header": {
4+
"specificationVersion": "1.3.0",
5+
"addressSource": {
6+
"device": "Wallbox",
7+
"entity": [
8+
0
9+
],
10+
"feature": 0
11+
},
12+
"addressDestination": {
13+
"device": "HEMS",
14+
"entity": [
15+
0
16+
],
17+
"feature": 0
18+
},
19+
"msgCounter": 4,
20+
"cmdClassifier": "notify",
21+
"ackRequest":true
22+
},
23+
"payload": {
24+
"cmd": [
25+
{
26+
"function": "nodeManagementDetailedDiscoveryData",
27+
"filter": [
28+
{
29+
"cmdControl": {
30+
"partial": {}
31+
}
32+
}
33+
],
34+
"nodeManagementDetailedDiscoveryData": {
35+
"deviceInformation": {
36+
"description": {
37+
"deviceAddress": {
38+
"device": "Wallbox"
39+
}
40+
}
41+
},
42+
"entityInformation": [
43+
{
44+
"description": {
45+
"entityAddress": {
46+
"entity": [
47+
1,
48+
1
49+
]
50+
},
51+
"entityType": "EV",
52+
"lastStateChange": "removed"
53+
}
54+
}
55+
]
56+
}
57+
}
58+
]
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)