Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDT Support #123

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions usecases/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ Actors:
Use Cases:
- `mpc`: Monitoring of Power Consumption
- `mgcp`: Monitoring of Grid Connection Point
- `mdt`: Monitoring of DHW Temperature
24 changes: 24 additions & 0 deletions usecases/api/ma_mdt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package api

import (
"github.com/enbility/eebus-go/api"
spineapi "github.com/enbility/spine-go/api"
)

// Actor: Monitoring Appliance
// UseCase: Monitoring of DHW Temperature
type MaMDTInterface interface {
api.UseCaseInterface

// Scenario 1

// return the momentary temperature of the domestic hot water circuit
//
// parameters:
// - entity: the entity of the device (e.g. DHWCircuit)
//
// possible errors:
// - ErrDataNotAvailable if no such limit is (yet) available
// - and others
Temperature(entity spineapi.EntityRemoteInterface) (float64, error)
}
80 changes: 80 additions & 0 deletions usecases/ma/mdt/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package mdt

import (
"github.com/enbility/eebus-go/features/client"
internal "github.com/enbility/eebus-go/usecases/internal"
"github.com/enbility/ship-go/logging"
spineapi "github.com/enbility/spine-go/api"
"github.com/enbility/spine-go/model"
"github.com/enbility/spine-go/util"
)

// handle SPINE events
func (e *MDT) HandleEvent(payload spineapi.EventPayload) {
// only about events from a DHWCircuit entity or device changes for this remote device

if !e.IsCompatibleEntityType(payload.Entity) {
return
}

if internal.IsEntityConnected(payload) {
e.deviceConnected(payload.Entity)
return
}

if payload.EventType != spineapi.EventTypeDataChange ||
payload.ChangeType != spineapi.ElementChangeUpdate {
return
}

switch payload.Data.(type) {
case *model.MeasurementDescriptionListDataType:
e.deviceMeasurementDescriptionDataUpdate(payload.Entity)

case *model.MeasurementListDataType:
e.deviceMeasurementDataUpdate(payload)
}
}

// process required steps when a device is connected
func (e *MDT) deviceConnected(entity spineapi.EntityRemoteInterface) {
if measurement, err := client.NewMeasurement(e.LocalEntity, entity); err == nil {
if !measurement.HasSubscription() {
if _, err := measurement.Subscribe(); err != nil {
logging.Log().Error(err)
}
}

// get measurement parameters
if _, err := measurement.RequestDescriptions(nil, nil); err != nil {
logging.Log().Error(err)
}

if _, err := measurement.RequestConstraints(nil, nil); err != nil {
logging.Log().Error(err)
}
}
}

// the measurement descriptiondata of a device was updated
func (e *MDT) deviceMeasurementDescriptionDataUpdate(entity spineapi.EntityRemoteInterface) {
if measurement, err := client.NewMeasurement(e.LocalEntity, entity); err == nil {
// measurement descriptions received, now get the data
if _, err := measurement.RequestData(nil, nil); err != nil {
logging.Log().Error("Error getting measurement list values:", err)
}
}
}

// the measurement data of a device was updated
func (e *MDT) deviceMeasurementDataUpdate(payload spineapi.EventPayload) {
if measurement, err := client.NewMeasurement(e.LocalEntity, payload.Entity); err == nil {
// Scenario 1
filter := model.MeasurementDescriptionDataType{
ScopeType: util.Ptr(model.ScopeTypeTypeDhwTemperature),
}
if measurement.CheckEventPayloadDataForFilter(payload.Data, filter) && e.EventCB != nil {
e.EventCB(payload.Ski, payload.Device, payload.Entity, DataUpdateDhwTemperature)
}
}
}
86 changes: 86 additions & 0 deletions usecases/ma/mdt/events_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package mdt

import (
spineapi "github.com/enbility/spine-go/api"
"github.com/enbility/spine-go/model"
"github.com/enbility/spine-go/util"
"github.com/stretchr/testify/assert"
)

func (s *MaMDTSuite) Test_Events() {
payload := spineapi.EventPayload{
Entity: s.mockRemoteEntity,
}
s.sut.HandleEvent(payload)

payload.Entity = s.monitoredEntity
s.sut.HandleEvent(payload)

payload.EventType = spineapi.EventTypeEntityChange
payload.ChangeType = spineapi.ElementChangeAdd
s.sut.HandleEvent(payload)

payload.ChangeType = spineapi.ElementChangeRemove
s.sut.HandleEvent(payload)

payload.EventType = spineapi.EventTypeDataChange
payload.ChangeType = spineapi.ElementChangeAdd
s.sut.HandleEvent(payload)

payload.EventType = spineapi.EventTypeDataChange
payload.ChangeType = spineapi.ElementChangeUpdate
payload.Data = util.Ptr(model.MeasurementDescriptionListDataType{})
s.sut.HandleEvent(payload)

payload.Data = util.Ptr(model.MeasurementListDataType{})
s.sut.HandleEvent(payload)

payload.Data = util.Ptr(model.NodeManagementUseCaseDataType{})
s.sut.HandleEvent(payload)
}

func (s *MaMDTSuite) Test_Failures() {
s.sut.deviceConnected(s.mockRemoteEntity)

s.sut.deviceMeasurementDescriptionDataUpdate(s.mockRemoteEntity)
}

func (s *MaMDTSuite) Test_deviceMeasurementDataUpdate() {
payload := spineapi.EventPayload{
Ski: remoteSki,
Device: s.remoteDevice,
Entity: s.monitoredEntity,
}
s.sut.deviceMeasurementDataUpdate(payload)
assert.False(s.T(), s.eventCalled)

descData := &model.MeasurementDescriptionListDataType{
MeasurementDescriptionData: []model.MeasurementDescriptionDataType{
{
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
ScopeType: util.Ptr(model.ScopeTypeTypeDhwTemperature),
},
},
}

rFeature := s.remoteDevice.FeatureByEntityTypeAndRole(s.monitoredEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeServer)
_, fErr := rFeature.UpdateData(true, model.FunctionTypeMeasurementDescriptionListData, descData, nil, nil)
assert.Nil(s.T(), fErr)

s.sut.deviceMeasurementDataUpdate(payload)
assert.False(s.T(), s.eventCalled)

data := &model.MeasurementListDataType{
MeasurementData: []model.MeasurementDataType{
{
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
Value: model.NewScaledNumberType(10),
},
},
}

payload.Data = data

s.sut.deviceMeasurementDataUpdate(payload)
assert.True(s.T(), s.eventCalled)
}
42 changes: 42 additions & 0 deletions usecases/ma/mdt/public.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mdt

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

// return the momentary temperature of the domestic hot water circuit
//
// possible errors:
// - ErrDataNotAvailable if no such limit is (yet) available
// - and others
func (e *MDT) Temperature(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
}

measurement, err := client.NewMeasurement(e.LocalEntity, entity)
if err != nil {
return 0, err
}

filter := model.MeasurementDescriptionDataType{
MeasurementType: util.Ptr(model.MeasurementTypeTypeTemperature),
CommodityType: util.Ptr(model.CommodityTypeTypeDomestichotwater),
ScopeType: util.Ptr(model.ScopeTypeTypeDhwTemperature),
}
data, err := measurement.GetDataForFilter(filter)
if err != nil || len(data) == 0 || data[0].Value == nil {
return 0, api.ErrDataNotAvailable
}

// take the first item
value := data[0].Value

return value.GetValue(), nil
}
52 changes: 52 additions & 0 deletions usecases/ma/mdt/public_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package mdt

import (
"github.com/enbility/spine-go/model"
"github.com/enbility/spine-go/util"
"github.com/stretchr/testify/assert"
)

func (s *MaMDTSuite) Test_Temperature() {
data, err := s.sut.Temperature(s.mockRemoteEntity)
assert.NotNil(s.T(), err)
assert.Equal(s.T(), 0.0, data)

data, err = s.sut.Temperature(s.monitoredEntity)
assert.NotNil(s.T(), err)
assert.Equal(s.T(), 0.0, data)

descData := &model.MeasurementDescriptionListDataType{
MeasurementDescriptionData: []model.MeasurementDescriptionDataType{
{
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
MeasurementType: util.Ptr(model.MeasurementTypeTypeTemperature),
CommodityType: util.Ptr(model.CommodityTypeTypeDomestichotwater),
ScopeType: util.Ptr(model.ScopeTypeTypeDhwTemperature),
},
},
}

rFeature := s.remoteDevice.FeatureByEntityTypeAndRole(s.monitoredEntity, model.FeatureTypeTypeMeasurement, model.RoleTypeServer)
_, fErr := rFeature.UpdateData(true, model.FunctionTypeMeasurementDescriptionListData, descData, nil, nil)
assert.Nil(s.T(), fErr)

data, err = s.sut.Temperature(s.monitoredEntity)
assert.NotNil(s.T(), err)
assert.Equal(s.T(), 0.0, data)

measData := &model.MeasurementListDataType{
MeasurementData: []model.MeasurementDataType{
{
MeasurementId: util.Ptr(model.MeasurementIdType(0)),
Value: model.NewScaledNumberType(55),
},
},
}

_, fErr = rFeature.UpdateData(true, model.FunctionTypeMeasurementListData, measData, nil, nil)
assert.Nil(s.T(), fErr)

data, err = s.sut.Temperature(s.monitoredEntity)
assert.Nil(s.T(), err)
assert.Equal(s.T(), 55.0, data)
}
Loading
Loading