Skip to content

Commit

Permalink
Add missing MPC and MGPC cases
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi committed Nov 20, 2024
1 parent bf4dad9 commit fed478a
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 9 deletions.
65 changes: 58 additions & 7 deletions usecases/ma/mgcp/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,14 @@ import (
// return the current power limitation factor
//
// possible errors:
// - ErrDataNotAvailable if no such limit is (yet) available
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) PowerLimitationFactor(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
}

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

keyname := model.DeviceConfigurationKeyNameTypePvCurtailmentLimitFactor

deviceConfiguration, err := client.NewDeviceConfiguration(e.LocalEntity, entity)
Expand Down Expand Up @@ -58,6 +54,11 @@ func (e *MGCP) PowerLimitationFactor(entity spineapi.EntityRemoteInterface) (flo
//
// - positive values are used for consumption
// - negative values are used for production
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) Power(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -69,7 +70,11 @@ func (e *MGCP) Power(entity spineapi.EntityRemoteInterface) (float64, error) {
ScopeType: util.Ptr(model.ScopeTypeTypeACPowerTotal),
}
data, err := internal.MeasurementPhaseSpecificDataForFilter(e.LocalEntity, entity, filter, model.EnergyDirectionTypeConsume, nil)
if err != nil || len(data) != 1 {
if err != nil {
return 0, err
}

if len(data) != 1 {
return 0, api.ErrDataNotAvailable
}

Expand All @@ -81,6 +86,11 @@ func (e *MGCP) Power(entity spineapi.EntityRemoteInterface) (float64, error) {
// return the total feed in energy at the grid connection point
//
// - negative values are used for production
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) EnergyFeedIn(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -100,6 +110,13 @@ func (e *MGCP) EnergyFeedIn(entity spineapi.EntityRemoteInterface) (float64, err
if err != nil || len(result) == 0 || result[0].Value == nil {
return 0, api.ErrDataNotAvailable
}

// if the value state is set and not normal, the value is not valid and should be ignored
// therefore we return an error
if result[0].ValueState != nil && *result[0].ValueState != model.MeasurementValueStateTypeNormal {
return 0, api.ErrDataInvalid
}

return result[0].Value.GetValue(), nil
}

Expand All @@ -108,6 +125,11 @@ func (e *MGCP) EnergyFeedIn(entity spineapi.EntityRemoteInterface) (float64, err
// return the total consumption energy at the grid connection point
//
// - positive values are used for consumption
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) EnergyConsumed(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -127,6 +149,13 @@ func (e *MGCP) EnergyConsumed(entity spineapi.EntityRemoteInterface) (float64, e
if err != nil || len(result) == 0 || result[0].Value == nil {
return 0, api.ErrDataNotAvailable
}

// if the value state is set and not normal, the value is not valid and should be ignored
// therefore we return an error
if result[0].ValueState != nil && *result[0].ValueState != model.MeasurementValueStateTypeNormal {
return 0, api.ErrDataInvalid
}

return result[0].Value.GetValue(), nil
}

Expand All @@ -136,6 +165,11 @@ func (e *MGCP) EnergyConsumed(entity spineapi.EntityRemoteInterface) (float64, e
//
// - positive values are used for consumption
// - negative values are used for production
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) CurrentPerPhase(entity spineapi.EntityRemoteInterface) ([]float64, error) {
if !e.IsCompatibleEntityType(entity) {
return nil, api.ErrNoCompatibleEntity
Expand All @@ -152,6 +186,11 @@ func (e *MGCP) CurrentPerPhase(entity spineapi.EntityRemoteInterface) ([]float64
// Scenario 6

// return the voltage phase details at the grid connection point
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) VoltagePerPhase(entity spineapi.EntityRemoteInterface) ([]float64, error) {
if !e.IsCompatibleEntityType(entity) {
return nil, api.ErrNoCompatibleEntity
Expand All @@ -168,6 +207,11 @@ func (e *MGCP) VoltagePerPhase(entity spineapi.EntityRemoteInterface) ([]float64
// Scenario 7

// return frequency at the grid connection point
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MGCP) Frequency(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -187,5 +231,12 @@ func (e *MGCP) Frequency(entity spineapi.EntityRemoteInterface) (float64, error)
if err != nil || len(result) == 0 || result[0].Value == nil {
return 0, api.ErrDataNotAvailable
}

// if the value state is set and not normal, the value is not valid and should be ignored
// therefore we return an error
if result[0].ValueState != nil && *result[0].ValueState != model.MeasurementValueStateTypeNormal {
return 0, api.ErrDataInvalid
}

return result[0].Value.GetValue(), nil
}
51 changes: 51 additions & 0 deletions usecases/ma/mgcp/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,23 @@ func (s *GcpMGCPSuite) Test_EnergyFeedIn() {
data, err = s.sut.EnergyFeedIn(s.smgwEntity)
assert.Nil(s.T(), err)
assert.Equal(s.T(), 10.0, data)

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

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

data, err = s.sut.EnergyFeedIn(s.smgwEntity)
assert.NotNil(s.T(), err)
assert.Equal(s.T(), 0.0, data)
}

func (s *GcpMGCPSuite) Test_EnergyConsumed() {
Expand Down Expand Up @@ -218,6 +235,23 @@ func (s *GcpMGCPSuite) Test_EnergyConsumed() {
data, err = s.sut.EnergyConsumed(s.smgwEntity)
assert.Nil(s.T(), err)
assert.Equal(s.T(), 10.0, data)

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

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

data, err = s.sut.EnergyConsumed(s.smgwEntity)
assert.NotNil(s.T(), err)
assert.Equal(s.T(), 0.0, data)
}

func (s *GcpMGCPSuite) Test_CurrentPerPhase() {
Expand Down Expand Up @@ -461,4 +495,21 @@ func (s *GcpMGCPSuite) Test_Frequency() {
data, err = s.sut.Frequency(s.smgwEntity)
assert.Nil(s.T(), err)
assert.Equal(s.T(), 50.0, data)

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

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

data, err = s.sut.Frequency(s.smgwEntity)
assert.NotNil(s.T(), err)
assert.Equal(s.T(), 0.0, data)
}
50 changes: 48 additions & 2 deletions usecases/ma/mpc/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import (
// return the momentary active power consumption or production
//
// possible errors:
// - ErrDataNotAvailable if no such limit is (yet) available
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) Power(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
Expand All @@ -34,13 +35,15 @@ func (e *MPC) Power(entity spineapi.EntityRemoteInterface) (float64, error) {
if len(values) != 1 {
return 0, api.ErrDataNotAvailable
}

return values[0], nil
}

// return the momentary active phase specific power consumption or production per phase
//
// possible errors:
// - ErrDataNotAvailable if no such limit is (yet) available
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) PowerPerPhase(entity spineapi.EntityRemoteInterface) ([]float64, error) {
if !e.IsCompatibleEntityType(entity) {
Expand All @@ -60,6 +63,11 @@ func (e *MPC) PowerPerPhase(entity spineapi.EntityRemoteInterface) ([]float64, e
// return the total consumption energy
//
// - positive values are used for consumption
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) EnergyConsumed(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -86,12 +94,23 @@ func (e *MPC) EnergyConsumed(entity spineapi.EntityRemoteInterface) (float64, er
return 0, api.ErrDataNotAvailable
}

// if the value state is set and not normal, the value is not valid and should be ignored
// therefore we return an error
if values[0].ValueState != nil && *values[0].ValueState != model.MeasurementValueStateTypeNormal {
return 0, api.ErrDataInvalid
}

return value.GetValue(), nil
}

// return the total feed in energy
//
// - negative values are used for production
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) EnergyProduced(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -118,6 +137,12 @@ func (e *MPC) EnergyProduced(entity spineapi.EntityRemoteInterface) (float64, er
return 0, api.ErrDataNotAvailable
}

// if the value state is set and not normal, the value is not valid and should be ignored
// therefore we return an error
if values[0].ValueState != nil && *values[0].ValueState != model.MeasurementValueStateTypeNormal {
return 0, api.ErrDataInvalid
}

return value.GetValue(), nil
}

Expand All @@ -127,6 +152,11 @@ func (e *MPC) EnergyProduced(entity spineapi.EntityRemoteInterface) (float64, er
//
// - positive values are used for consumption
// - negative values are used for production
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) CurrentPerPhase(entity spineapi.EntityRemoteInterface) ([]float64, error) {
if !e.IsCompatibleEntityType(entity) {
return nil, api.ErrNoCompatibleEntity
Expand All @@ -143,6 +173,11 @@ func (e *MPC) CurrentPerPhase(entity spineapi.EntityRemoteInterface) ([]float64,
// Scenario 4

// return the phase specific voltage details
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) VoltagePerPhase(entity spineapi.EntityRemoteInterface) ([]float64, error) {
if !e.IsCompatibleEntityType(entity) {
return nil, api.ErrNoCompatibleEntity
Expand All @@ -159,6 +194,11 @@ func (e *MPC) VoltagePerPhase(entity spineapi.EntityRemoteInterface) ([]float64,
// Scenario 5

// return frequency
//
// possible errors:
// - ErrDataNotAvailable if no such value is (yet) available
// - ErrDataInvalid if the currently available data is invalid and should be ignored
// - and others
func (e *MPC) Frequency(entity spineapi.EntityRemoteInterface) (float64, error) {
if !e.IsCompatibleEntityType(entity) {
return 0, api.ErrNoCompatibleEntity
Expand All @@ -179,6 +219,12 @@ func (e *MPC) Frequency(entity spineapi.EntityRemoteInterface) (float64, error)
return 0, api.ErrDataNotAvailable
}

// if the value state is set and not normal, the value is not valid and should be ignored
// therefore we return an error
if data[0].ValueState != nil && *data[0].ValueState != model.MeasurementValueStateTypeNormal {
return 0, api.ErrDataInvalid
}

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

Expand Down
Loading

0 comments on commit fed478a

Please sign in to comment.