Skip to content

Commit 99f07ff

Browse files
committed
Merge branch 'release/v0.7.0'
2 parents 6bddfe6 + fc43eb8 commit 99f07ff

File tree

104 files changed

+1527
-546
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+1527
-546
lines changed

.github/workflows/default.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
file: coverage.out
4949

5050
- name: Run Gosec Security Scanner
51-
uses: securego/gosec@master
51+
uses: securego/gosec@v2.20.0
5252
with:
5353
# we let the report trigger content trigger a failure using the GitHub Security features.
5454
args: '-no-fail -fmt sarif -out results.sarif ./...'

README.md

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

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

api/configuration.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ type Configuration struct {
6464
// The certificate used for the service and its connections, required
6565
certificate tls.Certificate
6666

67-
// The timeout to be used for sending heartbeats
67+
// The timeout to be used for sending heartbeats and applied to all
68+
// local entities created on setup the service
6869
heartbeatTimeout time.Duration
6970

7071
// Optional set which mDNS providers should be used
@@ -87,7 +88,7 @@ func NewConfiguration(
8788
certificate: certificate,
8889
port: port,
8990
heartbeatTimeout: heartbeatTimeout,
90-
mdnsProviderSelection: mdns.MdnsProviderSelectionGoZeroConfOnly,
91+
mdnsProviderSelection: mdns.MdnsProviderSelectionAll,
9192
}
9293

9394
if port == 0 {

api/configuration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (s *ConfigurationSuite) Test_Configuration() {
7878
assert.NotNil(s.T(), config)
7979
assert.Nil(s.T(), err)
8080

81-
assert.Equal(s.T(), mdns.MdnsProviderSelectionGoZeroConfOnly, config.MdnsProviderSelection())
81+
assert.Equal(s.T(), mdns.MdnsProviderSelectionAll, config.MdnsProviderSelection())
8282

8383
config.SetMdnsProviderSelection(mdns.MdnsProviderSelectionAvahiOnly)
8484
assert.Equal(s.T(), mdns.MdnsProviderSelectionAvahiOnly, config.MdnsProviderSelection())

cmd/evse/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"github.com/enbility/eebus-go/api"
1717
"github.com/enbility/eebus-go/service"
18+
ucapi "github.com/enbility/eebus-go/usecases/api"
1819
"github.com/enbility/eebus-go/usecases/cs/lpc"
1920
shipapi "github.com/enbility/ship-go/api"
2021
"github.com/enbility/ship-go/cert"
@@ -92,6 +93,16 @@ func (h *evse) run() {
9293
h.uclpc = lpc.NewLPC(localEntity, h.OnLPCEvent)
9394
h.myService.AddUseCase(h.uclpc)
9495

96+
// Initialize local server data
97+
_ = h.uclpc.SetConsumptionNominalMax(32000)
98+
_ = h.uclpc.SetConsumptionLimit(ucapi.LoadLimit{
99+
Value: 4200,
100+
IsChangeable: true,
101+
IsActive: false,
102+
})
103+
_ = h.uclpc.SetFailsafeConsumptionActivePowerLimit(4200, true)
104+
_ = h.uclpc.SetFailsafeDurationMinimum(2*time.Hour, true)
105+
95106
if len(remoteSki) == 0 {
96107
os.Exit(0)
97108
}

cmd/hems/main.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/enbility/eebus-go/api"
1717
"github.com/enbility/eebus-go/service"
1818
ucapi "github.com/enbility/eebus-go/usecases/api"
19-
"github.com/enbility/eebus-go/usecases/cs/lpc"
2019
cslpc "github.com/enbility/eebus-go/usecases/cs/lpc"
2120
cslpp "github.com/enbility/eebus-go/usecases/cs/lpp"
2221
eglpc "github.com/enbility/eebus-go/usecases/eg/lpc"
@@ -104,6 +103,25 @@ func (h *hems) run() {
104103
h.uceglpp = eglpp.NewLPP(localEntity, nil)
105104
h.myService.AddUseCase(h.uceglpp)
106105

106+
// Initialize local server data
107+
_ = h.uccslpc.SetConsumptionNominalMax(32000)
108+
_ = h.uccslpc.SetConsumptionLimit(ucapi.LoadLimit{
109+
Value: 4200,
110+
IsChangeable: true,
111+
IsActive: false,
112+
})
113+
_ = h.uccslpc.SetFailsafeConsumptionActivePowerLimit(4200, true)
114+
_ = h.uccslpc.SetFailsafeDurationMinimum(2*time.Hour, true)
115+
116+
_ = h.uccslpp.SetProductionNominalMax(10000)
117+
_ = h.uccslpp.SetProductionLimit(ucapi.LoadLimit{
118+
Value: 10000,
119+
IsChangeable: true,
120+
IsActive: false,
121+
})
122+
_ = h.uccslpp.SetFailsafeProductionActivePowerLimit(4200, true)
123+
_ = h.uccslpp.SetFailsafeDurationMinimum(2*time.Hour, true)
124+
107125
if len(remoteSki) == 0 {
108126
os.Exit(0)
109127
}
@@ -122,7 +140,7 @@ func (h *hems) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterface, ent
122140
}
123141

124142
switch event {
125-
case lpc.WriteApprovalRequired:
143+
case cslpc.WriteApprovalRequired:
126144
// get pending writes
127145
pendingWrites := h.uccslpc.PendingConsumptionLimits()
128146

@@ -131,7 +149,7 @@ func (h *hems) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterface, ent
131149
fmt.Println("Approving LPC write with msgCounter", msgCounter, "and limit", write.Value, "W")
132150
h.uccslpc.ApproveOrDenyConsumptionLimit(msgCounter, true, "")
133151
}
134-
case lpc.DataUpdateLimit:
152+
case cslpc.DataUpdateLimit:
135153
if currentLimit, err := h.uccslpc.ConsumptionLimit(); err != nil {
136154
fmt.Println("New LPC Limit set to", currentLimit.Value, "W")
137155
}
@@ -146,7 +164,7 @@ func (h *hems) OnLPPEvent(ski string, device spineapi.DeviceRemoteInterface, ent
146164
}
147165

148166
switch event {
149-
case lpc.WriteApprovalRequired:
167+
case cslpp.WriteApprovalRequired:
150168
// get pending writes
151169
pendingWrites := h.uccslpp.PendingProductionLimits()
152170

@@ -155,7 +173,7 @@ func (h *hems) OnLPPEvent(ski string, device spineapi.DeviceRemoteInterface, ent
155173
fmt.Println("Approving LPP write with msgCounter", msgCounter, "and limit", write.Value, "W")
156174
h.uccslpp.ApproveOrDenyProductionLimit(msgCounter, true, "")
157175
}
158-
case lpc.DataUpdateLimit:
176+
case cslpp.DataUpdateLimit:
159177
if currentLimit, err := h.uccslpp.ProductionLimit(); err != nil {
160178
fmt.Println("New LPP Limit set to", currentLimit.Value, "W")
161179
}
@@ -222,19 +240,19 @@ func main() {
222240
// Logging interface
223241

224242
func (h *hems) Trace(args ...interface{}) {
225-
// h.print("TRACE", args...)
243+
h.print("TRACE", args...)
226244
}
227245

228246
func (h *hems) Tracef(format string, args ...interface{}) {
229-
// h.printFormat("TRACE", format, args...)
247+
h.printFormat("TRACE", format, args...)
230248
}
231249

232250
func (h *hems) Debug(args ...interface{}) {
233-
// h.print("DEBUG", args...)
251+
h.print("DEBUG", args...)
234252
}
235253

236254
func (h *hems) Debugf(format string, args ...interface{}) {
237-
// h.printFormat("DEBUG", format, args...)
255+
h.printFormat("DEBUG", format, args...)
238256
}
239257

240258
func (h *hems) Info(args ...interface{}) {

features/client/deviceconfiguration.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,32 @@ func (d *DeviceConfiguration) WriteKeyValues(data []model.DeviceConfigurationKey
5959
return nil, api.ErrMissingData
6060
}
6161

62+
filters := []model.FilterType{*model.NewFilterTypePartial()}
63+
64+
// does the remote server feature not support partials?
65+
operation := d.featureRemote.Operations()[model.FunctionTypeDeviceConfigurationKeyValueListData]
66+
if operation == nil || !operation.WritePartial() {
67+
filters = nil
68+
// we need to send all data
69+
updateData := &model.DeviceConfigurationKeyValueListDataType{
70+
DeviceConfigurationKeyValueData: data,
71+
}
72+
73+
if mergedData, err := d.featureRemote.UpdateData(false, model.FunctionTypeDeviceConfigurationKeyValueListData, updateData, nil, nil); err == nil {
74+
data = mergedData.([]model.DeviceConfigurationKeyValueDataType)
75+
}
76+
}
77+
6278
cmd := model.CmdType{
63-
Function: util.Ptr(model.FunctionTypeDeviceConfigurationKeyValueListData),
64-
Filter: []model.FilterType{*model.NewFilterTypePartial()},
6579
DeviceConfigurationKeyValueListData: &model.DeviceConfigurationKeyValueListDataType{
6680
DeviceConfigurationKeyValueData: data,
6781
},
6882
}
6983

84+
if filters != nil {
85+
cmd.Filter = filters
86+
cmd.Function = util.Ptr(model.FunctionTypeDeviceConfigurationKeyValueListData)
87+
}
88+
7089
return d.remoteDevice.Sender().Write(d.featureLocal.Address(), d.featureRemote.Address(), cmd)
7190
}

features/client/deviceconfiguration_test.go

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@ func TestDeviceConfigurationSuite(t *testing.T) {
2020
type DeviceConfigurationSuite struct {
2121
suite.Suite
2222

23-
localEntity spineapi.EntityLocalInterface
24-
remoteEntity spineapi.EntityRemoteInterface
23+
localEntity spineapi.EntityLocalInterface
24+
localEntityPartial spineapi.EntityLocalInterface
25+
26+
remoteEntity spineapi.EntityRemoteInterface
27+
remoteEntityPartial spineapi.EntityRemoteInterface
28+
2529
mockRemoteEntity *mocks.EntityRemoteInterface
2630

27-
deviceConfiguration *DeviceConfiguration
31+
deviceConfiguration *DeviceConfiguration
32+
deviceConfigurationPartial *DeviceConfiguration
2833
}
2934

3035
const remoteSki string = "testremoteski"
@@ -47,6 +52,21 @@ func (s *DeviceConfigurationSuite) BeforeTest(suiteName, testName string) {
4752
},
4853
)
4954

55+
s.localEntityPartial, s.remoteEntityPartial = setupFeatures(
56+
s.T(),
57+
mockWriter,
58+
[]featureFunctions{
59+
{
60+
featureType: model.FeatureTypeTypeDeviceConfiguration,
61+
functions: []model.FunctionType{
62+
model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData,
63+
model.FunctionTypeDeviceConfigurationKeyValueListData,
64+
},
65+
partial: true,
66+
},
67+
},
68+
)
69+
5070
mockRemoteDevice := mocks.NewDeviceRemoteInterface(s.T())
5171
s.mockRemoteEntity = mocks.NewEntityRemoteInterface(s.T())
5272
mockRemoteFeature := mocks.NewFeatureRemoteInterface(s.T())
@@ -66,6 +86,10 @@ func (s *DeviceConfigurationSuite) BeforeTest(suiteName, testName string) {
6686
s.deviceConfiguration, err = NewDeviceConfiguration(s.localEntity, s.remoteEntity)
6787
assert.Nil(s.T(), err)
6888
assert.NotNil(s.T(), s.deviceConfiguration)
89+
90+
s.deviceConfigurationPartial, err = NewDeviceConfiguration(s.localEntityPartial, s.remoteEntityPartial)
91+
assert.Nil(s.T(), err)
92+
assert.NotNil(s.T(), s.deviceConfiguration)
6993
}
7094

7195
func (s *DeviceConfigurationSuite) Test_RequestKeyValueDescriptions() {
@@ -104,6 +128,34 @@ func (s *DeviceConfigurationSuite) Test_WriteValues() {
104128
assert.NotNil(s.T(), err)
105129
assert.Nil(s.T(), counter)
106130

131+
rF := s.remoteEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeDeviceConfiguration, model.RoleTypeServer)
132+
data1 := rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
133+
assert.Nil(s.T(), data1)
134+
135+
defaultData := &model.DeviceConfigurationKeyValueListDataType{
136+
DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{
137+
{
138+
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
139+
IsValueChangeable: util.Ptr(true),
140+
Value: &model.DeviceConfigurationKeyValueValueType{
141+
ScaledNumber: model.NewScaledNumberType(16),
142+
},
143+
},
144+
{
145+
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
146+
IsValueChangeable: util.Ptr(true),
147+
Value: &model.DeviceConfigurationKeyValueValueType{
148+
ScaledNumber: model.NewScaledNumberType(32),
149+
},
150+
},
151+
},
152+
}
153+
_, err1 := rF.UpdateData(true, model.FunctionTypeDeviceConfigurationKeyValueListData, defaultData, nil, nil)
154+
assert.Nil(s.T(), err1)
155+
data1 = rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
156+
assert.NotNil(s.T(), data1)
157+
assert.Equal(s.T(), 2, len(data1.DeviceConfigurationKeyValueData))
158+
107159
data = []model.DeviceConfigurationKeyValueDataType{
108160
{
109161
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
@@ -116,3 +168,55 @@ func (s *DeviceConfigurationSuite) Test_WriteValues() {
116168
assert.Nil(s.T(), err)
117169
assert.NotNil(s.T(), counter)
118170
}
171+
172+
// test with partial support
173+
func (s *DeviceConfigurationSuite) Test_WriteValues_Partial() {
174+
counter, err := s.deviceConfigurationPartial.WriteKeyValues(nil)
175+
assert.NotNil(s.T(), err)
176+
assert.Nil(s.T(), counter)
177+
178+
data := []model.DeviceConfigurationKeyValueDataType{}
179+
counter, err = s.deviceConfigurationPartial.WriteKeyValues(data)
180+
assert.NotNil(s.T(), err)
181+
assert.Nil(s.T(), counter)
182+
183+
rF := s.remoteEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeDeviceConfiguration, model.RoleTypeServer)
184+
data1 := rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
185+
assert.Nil(s.T(), data1)
186+
187+
defaultData := &model.DeviceConfigurationKeyValueListDataType{
188+
DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{
189+
{
190+
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
191+
IsValueChangeable: util.Ptr(true),
192+
Value: &model.DeviceConfigurationKeyValueValueType{
193+
ScaledNumber: model.NewScaledNumberType(16),
194+
},
195+
},
196+
{
197+
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
198+
IsValueChangeable: util.Ptr(true),
199+
Value: &model.DeviceConfigurationKeyValueValueType{
200+
ScaledNumber: model.NewScaledNumberType(32),
201+
},
202+
},
203+
},
204+
}
205+
_, err1 := rF.UpdateData(true, model.FunctionTypeDeviceConfigurationKeyValueListData, defaultData, nil, nil)
206+
assert.Nil(s.T(), err1)
207+
data1 = rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
208+
assert.NotNil(s.T(), data1)
209+
assert.Equal(s.T(), 2, len(data1.DeviceConfigurationKeyValueData))
210+
211+
data = []model.DeviceConfigurationKeyValueDataType{
212+
{
213+
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
214+
Value: &model.DeviceConfigurationKeyValueValueType{
215+
ScaledNumber: model.NewScaledNumberType(10),
216+
},
217+
},
218+
}
219+
counter, err = s.deviceConfigurationPartial.WriteKeyValues(data)
220+
assert.Nil(s.T(), err)
221+
assert.NotNil(s.T(), counter)
222+
}

features/client/feature.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ func (f *Feature) requestData(function model.FunctionType, selectors any, elemen
141141
}
142142

143143
// remove the selectors if the remote does not allow partial reads
144-
if selectors != nil && !op.ReadPartial() {
144+
// or partial writes, because in that case we need to have all data
145+
if selectors != nil && (!op.ReadPartial() || !op.WritePartial()) {
145146
selectors = nil
146147
elements = nil
147148
}

features/client/helper_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ func setupFeatures(
102102
dataCon shipapi.ShipConnectionDataWriterInterface,
103103
featureFunctions []featureFunctions) (spineapi.EntityLocalInterface, spineapi.EntityRemoteInterface) {
104104
localDevice := spine.NewDeviceLocal("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode",
105-
"TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4)
106-
localEntity := spine.NewEntityLocal(localDevice, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1}))
105+
"TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart)
106+
localEntity := spine.NewEntityLocal(localDevice, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1}), time.Second*4)
107107

108108
for i, item := range featureFunctions {
109109
f := spine.NewFeatureLocal(uint(i+1), localEntity, item.featureType, model.RoleTypeClient)

0 commit comments

Comments
 (0)