-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2a6167e
commit 0349564
Showing
9 changed files
with
449 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package api | ||
|
||
import ( | ||
"github.com/enbility/eebus-go/api" | ||
spineapi "github.com/enbility/spine-go/api" | ||
"github.com/enbility/spine-go/model" | ||
) | ||
|
||
type CemOHPCFInterface interface { | ||
api.UseCaseInterface | ||
|
||
SmartEnergyManagementData(entity spineapi.EntityRemoteInterface) ( | ||
smartEnergyManagementData model.SmartEnergyManagementPsDataType, resultErr error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package ohpcf | ||
|
||
import ( | ||
"github.com/enbility/eebus-go/features/client" | ||
"github.com/enbility/eebus-go/usecases/internal" | ||
"github.com/enbility/ship-go/logging" | ||
spineapi "github.com/enbility/spine-go/api" | ||
) | ||
|
||
// handle SPINE events | ||
func (e *OHPCF) HandleEvent(payload spineapi.EventPayload) { | ||
// only about events from an EV entity or device changes for this remote device | ||
|
||
if !e.IsCompatibleEntityType(payload.Entity) { | ||
return | ||
} | ||
|
||
if internal.IsEntityConnected(payload) { | ||
// get the smart energy management data from the remote entity | ||
e.connected(payload.Entity) | ||
return | ||
} | ||
|
||
if payload.EventType != spineapi.EventTypeDataChange || | ||
payload.ChangeType != spineapi.ElementChangeUpdate { | ||
return | ||
} | ||
|
||
switch payload.Data.(type) { | ||
default: | ||
return | ||
} | ||
} | ||
|
||
func (e *OHPCF) connected(entity spineapi.EntityRemoteInterface) { | ||
smartEnergyManagement, err := client.NewSmartEnergyManagementPs(e.LocalEntity, entity) | ||
if err != nil || smartEnergyManagement == nil { | ||
return | ||
} | ||
if _, err := smartEnergyManagement.RequestData(); err != nil { | ||
logging.Log().Debug(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package ohpcf | ||
|
||
import ( | ||
"github.com/enbility/eebus-go/api" | ||
"github.com/enbility/eebus-go/features/client" | ||
spineapi "github.com/enbility/spine-go/api" | ||
"github.com/enbility/spine-go/model" | ||
"github.com/enbility/spine-go/util" | ||
) | ||
|
||
// Scenario 1 - Monitor heat pump compressor's power consumption flexibility | ||
|
||
// Read the current Smart Energy Management Data | ||
// | ||
// parameters: | ||
// - entity: the entity of the e.g. HVAC | ||
// | ||
// return values: | ||
// - limit: load limit data | ||
// | ||
// possible errors: | ||
// - ErrDataNotAvailable if no such limit is (yet) available | ||
// - and others | ||
func (e *OHPCF) SmartEnergyManagementData(entity spineapi.EntityRemoteInterface) ( | ||
smartEnergyManagementData model.SmartEnergyManagementPsDataType, resultErr error) { | ||
|
||
smartEnergyManagementData = model.SmartEnergyManagementPsDataType{ | ||
NodeScheduleInformation: &model.PowerSequenceNodeScheduleInformationDataType{ | ||
NodeRemoteControllable: util.Ptr(false), | ||
SupportsSingleSlotSchedulingOnly: util.Ptr(false), | ||
AlternativesCount: util.Ptr(uint(0)), | ||
TotalSequencesCountMax: util.Ptr(uint(0)), | ||
SupportsReselection: util.Ptr(false), | ||
}, | ||
} | ||
resultErr = api.ErrNoCompatibleEntity | ||
if !e.IsCompatibleEntityType(entity) { | ||
return | ||
} | ||
|
||
resultErr = api.ErrDataNotAvailable | ||
smartEnergyManagement, err := client.NewSmartEnergyManagementPs(e.LocalEntity, entity) | ||
if err != nil || smartEnergyManagement == nil { | ||
return | ||
} | ||
|
||
smartEnergyManagementDataPtr, err := smartEnergyManagement.GetData() | ||
if err != nil || smartEnergyManagementDataPtr == nil { | ||
return | ||
} | ||
smartEnergyManagementData = *smartEnergyManagementDataPtr | ||
resultErr = nil | ||
|
||
return smartEnergyManagementData, resultErr | ||
} | ||
|
||
// Scenario 2 - Control heat pump compressor's power consumption flexibility | ||
|
||
// Write the Smart Energy Management Data | ||
// | ||
// parameters: | ||
// - entity: the entity of the heatpump compressor | ||
// - value: the new limit in W | ||
func (e *OHPCF) WriteSmartEnergyManagementData(entity spineapi.EntityRemoteInterface, | ||
data *model.SmartEnergyManagementPsDataType) (*model.MsgCounterType, error) { | ||
|
||
if !e.IsCompatibleEntityType(entity) { | ||
return nil, api.ErrNoCompatibleEntity | ||
} | ||
|
||
smartEnergyManagement, err := client.NewSmartEnergyManagementPs(e.LocalEntity, entity) | ||
if err != nil || smartEnergyManagement == nil { | ||
return nil, api.ErrDataNotAvailable | ||
} | ||
|
||
msgCounter, err := smartEnergyManagement.WriteData(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return msgCounter, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package ohpcf | ||
|
||
import ( | ||
"github.com/enbility/spine-go/model" | ||
"github.com/enbility/spine-go/util" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func (s *CemOHPCFSuite) Test_NodeScheduleInformation() { | ||
data, err := s.sut.SmartEnergyManagementData(nil) | ||
assert.NotNil(s.T(), err) | ||
assert.Equal(s.T(), uint(0), *data.NodeScheduleInformation.AlternativesCount) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.NodeRemoteControllable) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.SupportsReselection) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.SupportsSingleSlotSchedulingOnly) | ||
assert.Equal(s.T(), uint(0), *data.NodeScheduleInformation.TotalSequencesCountMax) | ||
|
||
data, err = s.sut.SmartEnergyManagementData(s.monitoredEntity) | ||
assert.NotNil(s.T(), err) | ||
assert.Equal(s.T(), uint(0), *data.NodeScheduleInformation.AlternativesCount) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.NodeRemoteControllable) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.SupportsReselection) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.SupportsSingleSlotSchedulingOnly) | ||
assert.Equal(s.T(), uint(0), *data.NodeScheduleInformation.TotalSequencesCountMax) | ||
|
||
smartEnergyManagementData := &model.SmartEnergyManagementPsDataType{ | ||
NodeScheduleInformation: &model.PowerSequenceNodeScheduleInformationDataType{ | ||
|
||
NodeRemoteControllable: util.Ptr(true), | ||
SupportsSingleSlotSchedulingOnly: util.Ptr(true), | ||
AlternativesCount: util.Ptr(uint(1)), | ||
TotalSequencesCountMax: util.Ptr(uint(3)), | ||
SupportsReselection: util.Ptr(false), | ||
}, | ||
} | ||
|
||
rFeature := s.remoteDevice.FeatureByEntityTypeAndRole(s.monitoredEntity, model.FeatureTypeTypeSmartEnergyManagementPs, model.RoleTypeServer) | ||
_, fErr := rFeature.UpdateData(true, model.FunctionTypeSmartEnergyManagementPsData, smartEnergyManagementData, nil, nil) | ||
assert.Nil(s.T(), fErr) | ||
|
||
data, err = s.sut.SmartEnergyManagementData(s.monitoredEntity) | ||
assert.Nil(s.T(), err) | ||
assert.Equal(s.T(), uint(1), *data.NodeScheduleInformation.AlternativesCount) | ||
assert.Equal(s.T(), true, *data.NodeScheduleInformation.NodeRemoteControllable) | ||
assert.Equal(s.T(), false, *data.NodeScheduleInformation.SupportsReselection) | ||
assert.Equal(s.T(), true, *data.NodeScheduleInformation.SupportsSingleSlotSchedulingOnly) | ||
assert.Equal(s.T(), uint(3), *data.NodeScheduleInformation.TotalSequencesCountMax) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
package ohpcf | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/enbility/eebus-go/api" | ||
"github.com/enbility/eebus-go/mocks" | ||
"github.com/enbility/eebus-go/service" | ||
shipapi "github.com/enbility/ship-go/api" | ||
"github.com/enbility/ship-go/cert" | ||
shipmocks "github.com/enbility/ship-go/mocks" | ||
spineapi "github.com/enbility/spine-go/api" | ||
spinemocks "github.com/enbility/spine-go/mocks" | ||
"github.com/enbility/spine-go/model" | ||
"github.com/enbility/spine-go/spine" | ||
"github.com/enbility/spine-go/util" | ||
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
func TestCemOHPCFSuite(t *testing.T) { | ||
suite.Run(t, new(CemOHPCFSuite)) | ||
} | ||
|
||
type CemOHPCFSuite struct { | ||
suite.Suite | ||
|
||
sut *OHPCF | ||
|
||
service api.ServiceInterface | ||
|
||
remoteDevice spineapi.DeviceRemoteInterface | ||
mockRemoteEntity *spinemocks.EntityRemoteInterface | ||
monitoredEntity spineapi.EntityRemoteInterface | ||
|
||
eventCalled bool | ||
} | ||
|
||
func (s *CemOHPCFSuite) Event(ski string, device spineapi.DeviceRemoteInterface, entity spineapi.EntityRemoteInterface, event api.EventType) { | ||
s.eventCalled = true | ||
} | ||
|
||
func (s *CemOHPCFSuite) BeforeTest(suiteName, testName string) { | ||
s.eventCalled = false | ||
cert, _ := cert.CreateCertificate("test", "test", "DE", "test") | ||
configuration, _ := api.NewConfiguration( | ||
"test", "test", "test", "test", | ||
[]shipapi.DeviceCategoryType{shipapi.DeviceCategoryTypeEnergyManagementSystem}, | ||
model.DeviceTypeTypeEnergyManagementSystem, | ||
[]model.EntityTypeType{model.EntityTypeTypeCEM}, | ||
9999, cert, time.Second*4) | ||
|
||
serviceHandler := mocks.NewServiceReaderInterface(s.T()) | ||
serviceHandler.EXPECT().ServicePairingDetailUpdate(mock.Anything, mock.Anything).Return().Maybe() | ||
|
||
s.service = service.NewService(configuration, serviceHandler) | ||
_ = s.service.Setup() | ||
|
||
mockRemoteDevice := spinemocks.NewDeviceRemoteInterface(s.T()) | ||
s.mockRemoteEntity = spinemocks.NewEntityRemoteInterface(s.T()) | ||
mockRemoteFeature := spinemocks.NewFeatureRemoteInterface(s.T()) | ||
mockRemoteDevice.EXPECT().FeatureByEntityTypeAndRole(mock.Anything, mock.Anything, mock.Anything).Return(mockRemoteFeature).Maybe() | ||
mockRemoteDevice.EXPECT().Ski().Return(remoteSki).Maybe() | ||
s.mockRemoteEntity.EXPECT().Device().Return(mockRemoteDevice).Maybe() | ||
s.mockRemoteEntity.EXPECT().EntityType().Return(mock.Anything).Maybe() | ||
entityAddress := &model.EntityAddressType{} | ||
s.mockRemoteEntity.EXPECT().Address().Return(entityAddress).Maybe() | ||
mockRemoteFeature.EXPECT().DataCopy(mock.Anything).Return(mock.Anything).Maybe() | ||
mockRemoteFeature.EXPECT().Address().Return(&model.FeatureAddressType{}).Maybe() | ||
mockRemoteFeature.EXPECT().Operations().Return(nil).Maybe() | ||
|
||
localEntity := s.service.LocalDevice().EntityForType(model.EntityTypeTypeCEM) | ||
s.sut = NewOHPCF(localEntity, s.Event) | ||
s.sut.AddFeatures() | ||
s.sut.AddUseCase() | ||
|
||
s.remoteDevice, s.monitoredEntity = setupDevices(s.service, s.T()) | ||
} | ||
|
||
const remoteSki string = "testremoteski" | ||
|
||
func setupDevices( | ||
eebusService api.ServiceInterface, t *testing.T) ( | ||
spineapi.DeviceRemoteInterface, | ||
spineapi.EntityRemoteInterface) { | ||
localDevice := eebusService.LocalDevice() | ||
|
||
writeHandler := shipmocks.NewShipConnectionDataWriterInterface(t) | ||
writeHandler.EXPECT().WriteShipMessageWithPayload(mock.Anything).Return().Maybe() | ||
sender := spine.NewSender(writeHandler) | ||
remoteDevice := spine.NewDeviceRemote(localDevice, remoteSki, sender) | ||
|
||
remoteDeviceName := "remote" | ||
|
||
var remoteFeatures = []struct { | ||
featureType model.FeatureTypeType | ||
role model.RoleType | ||
supportedFcts []model.FunctionType | ||
}{ | ||
{model.FeatureTypeTypeSmartEnergyManagementPs, | ||
model.RoleTypeServer, | ||
[]model.FunctionType{ | ||
model.FunctionTypeSmartEnergyManagementPsData, | ||
}, | ||
}, | ||
} | ||
var featureInformations []model.NodeManagementDetailedDiscoveryFeatureInformationType | ||
for index, feature := range remoteFeatures { | ||
supportedFcts := []model.FunctionPropertyType{} | ||
for _, fct := range feature.supportedFcts { | ||
supportedFct := model.FunctionPropertyType{ | ||
Function: util.Ptr(fct), | ||
PossibleOperations: &model.PossibleOperationsType{ | ||
Read: &model.PossibleOperationsReadType{}, | ||
}, | ||
} | ||
supportedFcts = append(supportedFcts, supportedFct) | ||
} | ||
|
||
featureInformation := model.NodeManagementDetailedDiscoveryFeatureInformationType{ | ||
Description: &model.NetworkManagementFeatureDescriptionDataType{ | ||
FeatureAddress: &model.FeatureAddressType{ | ||
Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), | ||
Entity: []model.AddressEntityType{1}, | ||
Feature: util.Ptr(model.AddressFeatureType(index)), | ||
}, | ||
FeatureType: util.Ptr(feature.featureType), | ||
Role: util.Ptr(feature.role), | ||
SupportedFunction: supportedFcts, | ||
}, | ||
} | ||
featureInformations = append(featureInformations, featureInformation) | ||
} | ||
|
||
detailedData := &model.NodeManagementDetailedDiscoveryDataType{ | ||
DeviceInformation: &model.NodeManagementDetailedDiscoveryDeviceInformationType{ | ||
Description: &model.NetworkManagementDeviceDescriptionDataType{ | ||
DeviceAddress: &model.DeviceAddressType{ | ||
Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), | ||
}, | ||
}, | ||
}, | ||
EntityInformation: []model.NodeManagementDetailedDiscoveryEntityInformationType{ | ||
{ | ||
Description: &model.NetworkManagementEntityDescriptionDataType{ | ||
EntityAddress: &model.EntityAddressType{ | ||
Device: util.Ptr(model.AddressDeviceType(remoteDeviceName)), | ||
Entity: []model.AddressEntityType{1}, | ||
}, | ||
EntityType: util.Ptr(model.EntityTypeTypeCompressor), | ||
}, | ||
}, | ||
}, | ||
FeatureInformation: featureInformations, | ||
} | ||
|
||
entities, err := remoteDevice.AddEntityAndFeatures(true, detailedData) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
remoteDevice.UpdateDevice(detailedData.DeviceInformation.Description) | ||
|
||
for _, entity := range entities { | ||
entity.UpdateDeviceAddress(*remoteDevice.Address()) | ||
} | ||
|
||
localDevice.AddRemoteDeviceForSki(remoteSki, remoteDevice) | ||
|
||
return remoteDevice, entities[0] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ohpcf | ||
|
||
import "github.com/enbility/eebus-go/api" | ||
|
||
const ( | ||
// Update of the list of remote entities supporting the Use Case | ||
// | ||
// Use `RemoteEntities` to get the current data | ||
UseCaseSupportUpdate api.EventType = "cem-ohpcf-UseCaseSupportUpdate" | ||
) |
Oops, something went wrong.