Skip to content

Commit

Permalink
Merge branch 'release/v0.7.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi committed Sep 21, 2024
2 parents 6bddfe6 + fc43eb8 commit 99f07ff
Show file tree
Hide file tree
Showing 104 changed files with 1,527 additions and 546 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
file: coverage.out

- name: Run Gosec Security Scanner
uses: securego/gosec@master
uses: securego/gosec@v2.20.0
with:
# we let the report trigger content trigger a failure using the GitHub Security features.
args: '-no-fail -fmt sarif -out results.sarif ./...'
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# eebus-go

[![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)
[![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)
[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4)](https://godoc.org/github.com/enbility/eebus-go)
[![Coverage Status](https://coveralls.io/repos/github/enbility/eebus-go/badge.svg?branch=master)](https://coveralls.io/github/enbility/eebus-go?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/enbility/eebus-go/badge.svg?branch=main)](https://coveralls.io/github/enbility/eebus-go?branch=main)
[![Go report](https://goreportcard.com/badge/github.com/enbility/eebus-go)](https://goreportcard.com/report/github.com/enbility/eebus-go)
[![CodeFactor](https://www.codefactor.io/repository/github/enbility/eebus-go/badge)](https://www.codefactor.io/repository/github/enbility/eebus-go)

Expand Down
5 changes: 3 additions & 2 deletions api/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ type Configuration struct {
// The certificate used for the service and its connections, required
certificate tls.Certificate

// The timeout to be used for sending heartbeats
// The timeout to be used for sending heartbeats and applied to all
// local entities created on setup the service
heartbeatTimeout time.Duration

// Optional set which mDNS providers should be used
Expand All @@ -87,7 +88,7 @@ func NewConfiguration(
certificate: certificate,
port: port,
heartbeatTimeout: heartbeatTimeout,
mdnsProviderSelection: mdns.MdnsProviderSelectionGoZeroConfOnly,
mdnsProviderSelection: mdns.MdnsProviderSelectionAll,
}

if port == 0 {
Expand Down
2 changes: 1 addition & 1 deletion api/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (s *ConfigurationSuite) Test_Configuration() {
assert.NotNil(s.T(), config)
assert.Nil(s.T(), err)

assert.Equal(s.T(), mdns.MdnsProviderSelectionGoZeroConfOnly, config.MdnsProviderSelection())
assert.Equal(s.T(), mdns.MdnsProviderSelectionAll, config.MdnsProviderSelection())

config.SetMdnsProviderSelection(mdns.MdnsProviderSelectionAvahiOnly)
assert.Equal(s.T(), mdns.MdnsProviderSelectionAvahiOnly, config.MdnsProviderSelection())
Expand Down
11 changes: 11 additions & 0 deletions cmd/evse/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/enbility/eebus-go/api"
"github.com/enbility/eebus-go/service"
ucapi "github.com/enbility/eebus-go/usecases/api"
"github.com/enbility/eebus-go/usecases/cs/lpc"
shipapi "github.com/enbility/ship-go/api"
"github.com/enbility/ship-go/cert"
Expand Down Expand Up @@ -92,6 +93,16 @@ func (h *evse) run() {
h.uclpc = lpc.NewLPC(localEntity, h.OnLPCEvent)
h.myService.AddUseCase(h.uclpc)

// Initialize local server data
_ = h.uclpc.SetConsumptionNominalMax(32000)
_ = h.uclpc.SetConsumptionLimit(ucapi.LoadLimit{
Value: 4200,
IsChangeable: true,
IsActive: false,
})
_ = h.uclpc.SetFailsafeConsumptionActivePowerLimit(4200, true)
_ = h.uclpc.SetFailsafeDurationMinimum(2*time.Hour, true)

if len(remoteSki) == 0 {
os.Exit(0)
}
Expand Down
36 changes: 27 additions & 9 deletions cmd/hems/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/enbility/eebus-go/api"
"github.com/enbility/eebus-go/service"
ucapi "github.com/enbility/eebus-go/usecases/api"
"github.com/enbility/eebus-go/usecases/cs/lpc"
cslpc "github.com/enbility/eebus-go/usecases/cs/lpc"
cslpp "github.com/enbility/eebus-go/usecases/cs/lpp"
eglpc "github.com/enbility/eebus-go/usecases/eg/lpc"
Expand Down Expand Up @@ -104,6 +103,25 @@ func (h *hems) run() {
h.uceglpp = eglpp.NewLPP(localEntity, nil)
h.myService.AddUseCase(h.uceglpp)

// Initialize local server data
_ = h.uccslpc.SetConsumptionNominalMax(32000)
_ = h.uccslpc.SetConsumptionLimit(ucapi.LoadLimit{
Value: 4200,
IsChangeable: true,
IsActive: false,
})
_ = h.uccslpc.SetFailsafeConsumptionActivePowerLimit(4200, true)
_ = h.uccslpc.SetFailsafeDurationMinimum(2*time.Hour, true)

_ = h.uccslpp.SetProductionNominalMax(10000)
_ = h.uccslpp.SetProductionLimit(ucapi.LoadLimit{
Value: 10000,
IsChangeable: true,
IsActive: false,
})
_ = h.uccslpp.SetFailsafeProductionActivePowerLimit(4200, true)
_ = h.uccslpp.SetFailsafeDurationMinimum(2*time.Hour, true)

if len(remoteSki) == 0 {
os.Exit(0)
}
Expand All @@ -122,7 +140,7 @@ func (h *hems) OnLPCEvent(ski string, device spineapi.DeviceRemoteInterface, ent
}

switch event {
case lpc.WriteApprovalRequired:
case cslpc.WriteApprovalRequired:
// get pending writes
pendingWrites := h.uccslpc.PendingConsumptionLimits()

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

switch event {
case lpc.WriteApprovalRequired:
case cslpp.WriteApprovalRequired:
// get pending writes
pendingWrites := h.uccslpp.PendingProductionLimits()

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

func (h *hems) Trace(args ...interface{}) {
// h.print("TRACE", args...)
h.print("TRACE", args...)
}

func (h *hems) Tracef(format string, args ...interface{}) {
// h.printFormat("TRACE", format, args...)
h.printFormat("TRACE", format, args...)
}

func (h *hems) Debug(args ...interface{}) {
// h.print("DEBUG", args...)
h.print("DEBUG", args...)
}

func (h *hems) Debugf(format string, args ...interface{}) {
// h.printFormat("DEBUG", format, args...)
h.printFormat("DEBUG", format, args...)
}

func (h *hems) Info(args ...interface{}) {
Expand Down
23 changes: 21 additions & 2 deletions features/client/deviceconfiguration.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,32 @@ func (d *DeviceConfiguration) WriteKeyValues(data []model.DeviceConfigurationKey
return nil, api.ErrMissingData
}

filters := []model.FilterType{*model.NewFilterTypePartial()}

// does the remote server feature not support partials?
operation := d.featureRemote.Operations()[model.FunctionTypeDeviceConfigurationKeyValueListData]
if operation == nil || !operation.WritePartial() {
filters = nil
// we need to send all data
updateData := &model.DeviceConfigurationKeyValueListDataType{
DeviceConfigurationKeyValueData: data,
}

if mergedData, err := d.featureRemote.UpdateData(false, model.FunctionTypeDeviceConfigurationKeyValueListData, updateData, nil, nil); err == nil {
data = mergedData.([]model.DeviceConfigurationKeyValueDataType)
}
}

cmd := model.CmdType{
Function: util.Ptr(model.FunctionTypeDeviceConfigurationKeyValueListData),
Filter: []model.FilterType{*model.NewFilterTypePartial()},
DeviceConfigurationKeyValueListData: &model.DeviceConfigurationKeyValueListDataType{
DeviceConfigurationKeyValueData: data,
},
}

if filters != nil {
cmd.Filter = filters
cmd.Function = util.Ptr(model.FunctionTypeDeviceConfigurationKeyValueListData)
}

return d.remoteDevice.Sender().Write(d.featureLocal.Address(), d.featureRemote.Address(), cmd)
}
110 changes: 107 additions & 3 deletions features/client/deviceconfiguration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ func TestDeviceConfigurationSuite(t *testing.T) {
type DeviceConfigurationSuite struct {
suite.Suite

localEntity spineapi.EntityLocalInterface
remoteEntity spineapi.EntityRemoteInterface
localEntity spineapi.EntityLocalInterface
localEntityPartial spineapi.EntityLocalInterface

remoteEntity spineapi.EntityRemoteInterface
remoteEntityPartial spineapi.EntityRemoteInterface

mockRemoteEntity *mocks.EntityRemoteInterface

deviceConfiguration *DeviceConfiguration
deviceConfiguration *DeviceConfiguration
deviceConfigurationPartial *DeviceConfiguration
}

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

s.localEntityPartial, s.remoteEntityPartial = setupFeatures(
s.T(),
mockWriter,
[]featureFunctions{
{
featureType: model.FeatureTypeTypeDeviceConfiguration,
functions: []model.FunctionType{
model.FunctionTypeDeviceConfigurationKeyValueDescriptionListData,
model.FunctionTypeDeviceConfigurationKeyValueListData,
},
partial: true,
},
},
)

mockRemoteDevice := mocks.NewDeviceRemoteInterface(s.T())
s.mockRemoteEntity = mocks.NewEntityRemoteInterface(s.T())
mockRemoteFeature := mocks.NewFeatureRemoteInterface(s.T())
Expand All @@ -66,6 +86,10 @@ func (s *DeviceConfigurationSuite) BeforeTest(suiteName, testName string) {
s.deviceConfiguration, err = NewDeviceConfiguration(s.localEntity, s.remoteEntity)
assert.Nil(s.T(), err)
assert.NotNil(s.T(), s.deviceConfiguration)

s.deviceConfigurationPartial, err = NewDeviceConfiguration(s.localEntityPartial, s.remoteEntityPartial)
assert.Nil(s.T(), err)
assert.NotNil(s.T(), s.deviceConfiguration)
}

func (s *DeviceConfigurationSuite) Test_RequestKeyValueDescriptions() {
Expand Down Expand Up @@ -104,6 +128,34 @@ func (s *DeviceConfigurationSuite) Test_WriteValues() {
assert.NotNil(s.T(), err)
assert.Nil(s.T(), counter)

rF := s.remoteEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeDeviceConfiguration, model.RoleTypeServer)
data1 := rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
assert.Nil(s.T(), data1)

defaultData := &model.DeviceConfigurationKeyValueListDataType{
DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
IsValueChangeable: util.Ptr(true),
Value: &model.DeviceConfigurationKeyValueValueType{
ScaledNumber: model.NewScaledNumberType(16),
},
},
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
IsValueChangeable: util.Ptr(true),
Value: &model.DeviceConfigurationKeyValueValueType{
ScaledNumber: model.NewScaledNumberType(32),
},
},
},
}
_, err1 := rF.UpdateData(true, model.FunctionTypeDeviceConfigurationKeyValueListData, defaultData, nil, nil)
assert.Nil(s.T(), err1)
data1 = rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
assert.NotNil(s.T(), data1)
assert.Equal(s.T(), 2, len(data1.DeviceConfigurationKeyValueData))

data = []model.DeviceConfigurationKeyValueDataType{
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
Expand All @@ -116,3 +168,55 @@ func (s *DeviceConfigurationSuite) Test_WriteValues() {
assert.Nil(s.T(), err)
assert.NotNil(s.T(), counter)
}

// test with partial support
func (s *DeviceConfigurationSuite) Test_WriteValues_Partial() {
counter, err := s.deviceConfigurationPartial.WriteKeyValues(nil)
assert.NotNil(s.T(), err)
assert.Nil(s.T(), counter)

data := []model.DeviceConfigurationKeyValueDataType{}
counter, err = s.deviceConfigurationPartial.WriteKeyValues(data)
assert.NotNil(s.T(), err)
assert.Nil(s.T(), counter)

rF := s.remoteEntity.FeatureOfTypeAndRole(model.FeatureTypeTypeDeviceConfiguration, model.RoleTypeServer)
data1 := rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
assert.Nil(s.T(), data1)

defaultData := &model.DeviceConfigurationKeyValueListDataType{
DeviceConfigurationKeyValueData: []model.DeviceConfigurationKeyValueDataType{
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
IsValueChangeable: util.Ptr(true),
Value: &model.DeviceConfigurationKeyValueValueType{
ScaledNumber: model.NewScaledNumberType(16),
},
},
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(1)),
IsValueChangeable: util.Ptr(true),
Value: &model.DeviceConfigurationKeyValueValueType{
ScaledNumber: model.NewScaledNumberType(32),
},
},
},
}
_, err1 := rF.UpdateData(true, model.FunctionTypeDeviceConfigurationKeyValueListData, defaultData, nil, nil)
assert.Nil(s.T(), err1)
data1 = rF.DataCopy(model.FunctionTypeDeviceConfigurationKeyValueListData).(*model.DeviceConfigurationKeyValueListDataType)
assert.NotNil(s.T(), data1)
assert.Equal(s.T(), 2, len(data1.DeviceConfigurationKeyValueData))

data = []model.DeviceConfigurationKeyValueDataType{
{
KeyId: util.Ptr(model.DeviceConfigurationKeyIdType(0)),
Value: &model.DeviceConfigurationKeyValueValueType{
ScaledNumber: model.NewScaledNumberType(10),
},
},
}
counter, err = s.deviceConfigurationPartial.WriteKeyValues(data)
assert.Nil(s.T(), err)
assert.NotNil(s.T(), counter)
}
3 changes: 2 additions & 1 deletion features/client/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ func (f *Feature) requestData(function model.FunctionType, selectors any, elemen
}

// remove the selectors if the remote does not allow partial reads
if selectors != nil && !op.ReadPartial() {
// or partial writes, because in that case we need to have all data
if selectors != nil && (!op.ReadPartial() || !op.WritePartial()) {
selectors = nil
elements = nil
}
Expand Down
4 changes: 2 additions & 2 deletions features/client/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ func setupFeatures(
dataCon shipapi.ShipConnectionDataWriterInterface,
featureFunctions []featureFunctions) (spineapi.EntityLocalInterface, spineapi.EntityRemoteInterface) {
localDevice := spine.NewDeviceLocal("TestBrandName", "TestDeviceModel", "TestSerialNumber", "TestDeviceCode",
"TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart, time.Second*4)
localEntity := spine.NewEntityLocal(localDevice, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1}))
"TestDeviceAddress", model.DeviceTypeTypeEnergyManagementSystem, model.NetworkManagementFeatureSetTypeSmart)
localEntity := spine.NewEntityLocal(localDevice, model.EntityTypeTypeCEM, spine.NewAddressEntityType([]uint{1}), time.Second*4)

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

0 comments on commit 99f07ff

Please sign in to comment.