Skip to content

Commit f7ad0a6

Browse files
committed
Feat: Add CDT Support as CA (Configuration Appliance) Client Actor
This commit introduces CDT support as a CA (Configuration Appliance) client actor. It provides full support for the CDT use case, specifically Scenario 1. This includes the ability to retrieve setpoints, their constraints, and map them to their corresponding operation modes via HvacSetpointRelations. For the use case to fully function, support for the CDSF (Configuration of DHW System Function) use case is necessary. Specifically, we need to request HvacOperationModeDescriptionListDataType, which is used in conjunction with HvacSystemFunctionSetpointRelationListDataType to establish the mapping between operation modes and their setpoints, and to enable the ability to write setpoints. Note: Writing setpoints was tested and confirmed to work with Vaillant's HeatPump by requesting the HvacOperationModeDescriptionListDataType message and performing the mapping without the CDSF use case. Resources used (specifications): - EEBus UC Technical Specification Configuration of DHW Temperature - EEBus SPINE Technical Specification Resource Specification
1 parent 2a6167e commit f7ad0a6

File tree

15 files changed

+1251
-6
lines changed

15 files changed

+1251
-6
lines changed

features/client/hvac.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package client
2+
3+
import (
4+
"github.com/enbility/eebus-go/features/internal"
5+
spineapi "github.com/enbility/spine-go/api"
6+
"github.com/enbility/spine-go/model"
7+
)
8+
9+
type Hvac struct {
10+
*Feature
11+
12+
*internal.HvacCommon
13+
}
14+
15+
// Get a new HVAC features helper
16+
//
17+
// - The feature on the local entity has to be of role client
18+
// - The feature on the remote entity has to be of role server
19+
func NewHvac(
20+
localEntity spineapi.EntityLocalInterface,
21+
remoteEntity spineapi.EntityRemoteInterface,
22+
) (*Hvac, error) {
23+
feature, err := NewFeature(model.FeatureTypeTypeHvac, localEntity, remoteEntity)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
hvac := &Hvac{
29+
Feature: feature,
30+
HvacCommon: internal.NewRemoteHvac(feature.featureRemote),
31+
}
32+
33+
return hvac, nil
34+
}
35+
36+
// request FunctionTypeHvacSystemFunctionSetPointRelationListData from a remote device
37+
func (h *Hvac) RequestHvacSystemFunctionSetPointRelations(
38+
selector *model.HvacSystemFunctionSetpointRelationListDataSelectorsType,
39+
elements *model.HvacSystemFunctionSetpointRelationDataElementsType,
40+
) (*model.MsgCounterType, error) {
41+
return h.requestData(model.FunctionTypeHvacSystemFunctionSetPointRelationListData, selector, elements)
42+
}
43+
44+
// request FunctionTypeHvacOperationModeDescriptionListData from a remote device
45+
func (h *Hvac) RequestHvacOperationModeDescriptions(
46+
selector *model.HvacOperationModeDescriptionListDataSelectorsType,
47+
elements *model.HvacOperationModeDescriptionDataElementsType,
48+
) (*model.MsgCounterType, error) {
49+
return h.requestData(model.FunctionTypeHvacOperationModeDescriptionListData, selector, elements)
50+
}

features/client/setpoint.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package client
2+
3+
import (
4+
"github.com/enbility/eebus-go/api"
5+
"github.com/enbility/eebus-go/features/internal"
6+
spineapi "github.com/enbility/spine-go/api"
7+
"github.com/enbility/spine-go/model"
8+
)
9+
10+
type Setpoint struct {
11+
*Feature
12+
13+
*internal.SetPointCommon
14+
}
15+
16+
// Get a new SetPoint features helper
17+
//
18+
// - The feature on the local entity has to be of role client
19+
// - The feature on the remote entity has to be of role server
20+
func NewSetpoint(
21+
localEntity spineapi.EntityLocalInterface,
22+
remoteEntity spineapi.EntityRemoteInterface,
23+
) (*Setpoint, error) {
24+
feature, err := NewFeature(model.FeatureTypeTypeSetpoint, localEntity, remoteEntity)
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
sp := &Setpoint{
30+
Feature: feature,
31+
SetPointCommon: internal.NewRemoteSetPoint(feature.featureRemote),
32+
}
33+
34+
return sp, nil
35+
}
36+
37+
// request FunctionTypeSetpointDescriptionListData from a remote device
38+
func (s *Setpoint) RequestSetPointDescriptions(
39+
selector *model.SetpointDescriptionListDataSelectorsType,
40+
elements *model.SetpointDescriptionDataElementsType,
41+
) (*model.MsgCounterType, error) {
42+
return s.requestData(model.FunctionTypeSetpointDescriptionListData, selector, elements)
43+
}
44+
45+
// request FunctionTypeSetpointConstraintsListData from a remote device
46+
func (s *Setpoint) RequestSetPointConstraints(
47+
selector *model.SetpointConstraintsListDataSelectorsType,
48+
elements *model.SetpointConstraintsDataElementsType,
49+
) (*model.MsgCounterType, error) {
50+
return s.requestData(model.FunctionTypeSetpointConstraintsListData, selector, elements)
51+
}
52+
53+
// request FunctionTypeSetpointListData from a remote device
54+
func (s *Setpoint) RequestSetPoints(
55+
selector *model.SetpointListDataSelectorsType,
56+
elements *model.SetpointDataElementsType,
57+
) (*model.MsgCounterType, error) {
58+
return s.requestData(model.FunctionTypeSetpointListData, selector, elements)
59+
}
60+
61+
// WriteSetPointListData writes the given setpoint data
62+
//
63+
// Parameters:
64+
// - data: the setpoint data to write
65+
//
66+
// Returns:
67+
// - the message counter of the sent message
68+
// - an error if the data could not be written
69+
func (s *Setpoint) WriteSetPointListData(
70+
data []model.SetpointDataType,
71+
) (*model.MsgCounterType, error) {
72+
if len(data) == 0 {
73+
return nil, api.ErrMissingData
74+
}
75+
76+
cmd := model.CmdType{
77+
SetpointListData: &model.SetpointListDataType{
78+
SetpointData: data,
79+
},
80+
}
81+
82+
return s.remoteDevice.Sender().Write(s.featureLocal.Address(), s.featureRemote.Address(), cmd)
83+
}

features/internal/hvac.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package internal
2+
3+
import (
4+
"github.com/enbility/eebus-go/api"
5+
spineapi "github.com/enbility/spine-go/api"
6+
"github.com/enbility/spine-go/model"
7+
)
8+
9+
type HvacCommon struct {
10+
featureLocal spineapi.FeatureLocalInterface
11+
featureRemote spineapi.FeatureRemoteInterface
12+
}
13+
14+
// NewLocalHvac creates a new HvacCommon helper for local entities
15+
func NewLocalHvac(featureLocal spineapi.FeatureLocalInterface) *HvacCommon {
16+
return &HvacCommon{
17+
featureLocal: featureLocal,
18+
}
19+
}
20+
21+
// NewRemoteHvac creates a new HvacCommon helper for remote entities
22+
func NewRemoteHvac(featureRemote spineapi.FeatureRemoteInterface) *HvacCommon {
23+
return &HvacCommon{
24+
featureRemote: featureRemote,
25+
}
26+
}
27+
28+
// GetHvacOperationModeDescriptions returns the operation mode descriptions
29+
func (h *HvacCommon) GetHvacOperationModeDescriptions() ([]model.HvacOperationModeDescriptionDataType, error) {
30+
function := model.FunctionTypeHvacOperationModeDescriptionListData
31+
operationModeDescriptions := make([]model.HvacOperationModeDescriptionDataType, 0)
32+
33+
data, err := featureDataCopyOfType[model.HvacOperationModeDescriptionListDataType](h.featureLocal, h.featureRemote, function)
34+
if err == nil || data != nil {
35+
operationModeDescriptions = append(operationModeDescriptions, data.HvacOperationModeDescriptionData...)
36+
}
37+
38+
return operationModeDescriptions, nil
39+
}
40+
41+
// GetHvacSystemFunctionSetpointRelations returns the operation mode relations (used to map operation modes to setpoints)
42+
func (h *HvacCommon) GetHvacSystemFunctionSetpointRelationsForSystemFunctionId(
43+
id model.HvacSystemFunctionIdType,
44+
) ([]model.HvacSystemFunctionSetpointRelationDataType, error) {
45+
function := model.FunctionTypeHvacSystemFunctionSetPointRelationListData
46+
filter := model.HvacSystemFunctionSetpointRelationDataType{
47+
SystemFunctionId: &id,
48+
}
49+
50+
data, err := featureDataCopyOfType[model.HvacSystemFunctionSetpointRelationListDataType](h.featureLocal, h.featureRemote, function)
51+
if err != nil || data == nil || data.HvacSystemFunctionSetpointRelationData == nil {
52+
return nil, api.ErrDataNotAvailable
53+
}
54+
55+
result := searchFilterInList[model.HvacSystemFunctionSetpointRelationDataType](data.HvacSystemFunctionSetpointRelationData, filter)
56+
if len(result) == 0 {
57+
return nil, api.ErrDataNotAvailable
58+
}
59+
60+
return result, nil
61+
}
62+
63+
func (h *HvacCommon) GetHvacSystemFunctionDescriptionsForFilter(
64+
filter model.HvacSystemFunctionDescriptionDataType,
65+
) ([]model.HvacSystemFunctionDescriptionDataType, error) {
66+
function := model.FunctionTypeHvacSystemFunctionDescriptionListData
67+
68+
data, err := featureDataCopyOfType[model.HvacSystemFunctionDescriptionListDataType](h.featureLocal, h.featureRemote, function)
69+
if err != nil || data == nil || data.HvacSystemFunctionDescriptionData == nil {
70+
return nil, api.ErrDataNotAvailable
71+
}
72+
73+
result := searchFilterInList[model.HvacSystemFunctionDescriptionDataType](data.HvacSystemFunctionDescriptionData, filter)
74+
75+
return result, nil
76+
}

features/internal/setpoint.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package internal
2+
3+
import (
4+
"github.com/enbility/eebus-go/api"
5+
"github.com/enbility/ship-go/util"
6+
spineapi "github.com/enbility/spine-go/api"
7+
"github.com/enbility/spine-go/model"
8+
)
9+
10+
type SetPointCommon struct {
11+
featureLocal spineapi.FeatureLocalInterface
12+
featureRemote spineapi.FeatureRemoteInterface
13+
}
14+
15+
// NewLocalSetPoint creates a new SetPointCommon helper for local entities
16+
func NewLocalSetPoint(featureLocal spineapi.FeatureLocalInterface) *SetPointCommon {
17+
return &SetPointCommon{
18+
featureLocal: featureLocal,
19+
}
20+
}
21+
22+
// NewRemoteSetPoint creates a new SetPointCommon helper for remote entities
23+
func NewRemoteSetPoint(featureRemote spineapi.FeatureRemoteInterface) *SetPointCommon {
24+
return &SetPointCommon{
25+
featureRemote: featureRemote,
26+
}
27+
}
28+
29+
// GetSetpointDescriptions returns the setpoint descriptions
30+
func (s *SetPointCommon) GetSetpointDescriptions() ([]model.SetpointDescriptionDataType, error) {
31+
function := model.FunctionTypeSetpointDescriptionListData
32+
33+
data, err := featureDataCopyOfType[model.SetpointDescriptionListDataType](s.featureLocal, s.featureRemote, function)
34+
if err != nil || data == nil || data.SetpointDescriptionData == nil {
35+
return nil, api.ErrDataNotAvailable
36+
}
37+
38+
return data.SetpointDescriptionData, nil
39+
}
40+
41+
// GetSetpointForId returns the setpoint data for a given setpoint ID
42+
func (s *SetPointCommon) GetSetpointForId(
43+
id model.SetpointIdType,
44+
) (*model.SetpointDataType, error) {
45+
filter := model.SetpointDataType{
46+
SetpointId: &id,
47+
}
48+
49+
result, err := s.GetSetpointDataForFilter(filter)
50+
if err != nil || len(result) == 0 {
51+
return nil, api.ErrDataNotAvailable
52+
}
53+
54+
return util.Ptr(result[0]), nil
55+
}
56+
57+
// GetSetpoints returns the setpoints
58+
func (s *SetPointCommon) GetSetpoints() []model.SetpointDataType {
59+
function := model.FunctionTypeSetpointListData
60+
61+
data, err := featureDataCopyOfType[model.SetpointListDataType](s.featureLocal, s.featureRemote, function)
62+
if err != nil || data == nil || data.SetpointData == nil {
63+
return []model.SetpointDataType{}
64+
}
65+
66+
return data.SetpointData
67+
}
68+
69+
// GetSetpointDataForFilter returns the setpoint data for a given filter
70+
func (s *SetPointCommon) GetSetpointDataForFilter(
71+
filter model.SetpointDataType,
72+
) ([]model.SetpointDataType, error) {
73+
function := model.FunctionTypeSetpointListData
74+
75+
data, err := featureDataCopyOfType[model.SetpointListDataType](s.featureLocal, s.featureRemote, function)
76+
if err != nil || data == nil || data.SetpointData == nil {
77+
return nil, api.ErrDataNotAvailable
78+
}
79+
80+
result := searchFilterInList[model.SetpointDataType](data.SetpointData, filter)
81+
82+
return result, nil
83+
}
84+
85+
// GetSetpointConstraints returns the setpoints constraints.
86+
func (s *SetPointCommon) GetSetpointConstraints() []model.SetpointConstraintsDataType {
87+
function := model.FunctionTypeSetpointConstraintsListData
88+
89+
data, err := featureDataCopyOfType[model.SetpointConstraintsListDataType](s.featureLocal, s.featureRemote, function)
90+
if err != nil || data == nil || data.SetpointConstraintsData == nil {
91+
return []model.SetpointConstraintsDataType{}
92+
}
93+
94+
return data.SetpointConstraintsData
95+
}
96+
97+
// GetSetpointConstraintsForId returns the setpoint constraints for a given setpoint ID
98+
func (s *SetPointCommon) GetSetpointConstraintsForId(
99+
id model.SetpointIdType,
100+
) (*model.SetpointConstraintsDataType, error) {
101+
filter := model.SetpointConstraintsDataType{
102+
SetpointId: &id,
103+
}
104+
105+
result, err := s.GetSetpointConstraintsForFilter(filter)
106+
if err != nil || len(result) == 0 {
107+
return nil, api.ErrDataNotAvailable
108+
}
109+
110+
return util.Ptr(result[0]), nil
111+
}
112+
113+
// GetSetpointConstraintsForFilter returns the setpoint constraints for a given filter
114+
func (s *SetPointCommon) GetSetpointConstraintsForFilter(
115+
filter model.SetpointConstraintsDataType,
116+
) ([]model.SetpointConstraintsDataType, error) {
117+
function := model.FunctionTypeSetpointConstraintsListData
118+
119+
data, err := featureDataCopyOfType[model.SetpointConstraintsListDataType](s.featureLocal, s.featureRemote, function)
120+
if err != nil || data == nil || data.SetpointConstraintsData == nil {
121+
return nil, api.ErrDataNotAvailable
122+
}
123+
124+
result := searchFilterInList[model.SetpointConstraintsDataType](data.SetpointConstraintsData, filter)
125+
126+
return result, nil
127+
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module github.com/enbility/eebus-go
33
go 1.22.0
44

55
require (
6-
github.com/enbility/ship-go v0.0.0-20241006160314-3a4325a1a6d6
7-
github.com/enbility/spine-go v0.0.0-20241007182100-30ee8bc405a7
6+
github.com/enbility/ship-go v0.6.1-0.20241023165311-5963bf4d9424
7+
github.com/enbility/spine-go v0.7.1-0.20241023170915-0b14938a9a37
88
github.com/stretchr/testify v1.9.0
99
)
1010

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
44
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55
github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a h1:foChWb8lhzqa6lWDRs6COYMdp649YlUirFP8GqoT0JQ=
66
github.com/enbility/go-avahi v0.0.0-20240909195612-d5de6b280d7a/go.mod h1:H64mhYcAQUGUUnVqMdZQf93kPecH4M79xwH95Lddt3U=
7-
github.com/enbility/ship-go v0.0.0-20241006160314-3a4325a1a6d6 h1:bjrcJ4wxEsG5rXHlXnedRzqAV9JYglj82S14Nf1oLvs=
8-
github.com/enbility/ship-go v0.0.0-20241006160314-3a4325a1a6d6/go.mod h1:JJp8EQcJhUhTpZ2LSEU4rpdaM3E2n08tswWFWtmm/wU=
9-
github.com/enbility/spine-go v0.0.0-20241007182100-30ee8bc405a7 h1:n6tv+YUMncSR9qxUs6k7d/YsKD9ujHHp5pUspIvM6sc=
10-
github.com/enbility/spine-go v0.0.0-20241007182100-30ee8bc405a7/go.mod h1:ZoI9TaJO/So/677uknrli8sc6iryD7wC5iWhVIre+MI=
7+
github.com/enbility/ship-go v0.6.1-0.20241023165311-5963bf4d9424 h1:yzf1pWKZn+vhxtWE1ZNyspAX8GiX/r4uBXZU+SdidNY=
8+
github.com/enbility/ship-go v0.6.1-0.20241023165311-5963bf4d9424/go.mod h1:JJp8EQcJhUhTpZ2LSEU4rpdaM3E2n08tswWFWtmm/wU=
9+
github.com/enbility/spine-go v0.7.0 h1:UZeghFgnM3VFU0ghc57Htt6gnxwP9jLppfU2GUMJGgY=
10+
github.com/enbility/spine-go v0.7.0/go.mod h1:IF1sBTr7p3wXqlejeBJcJ8BYFlzzRaZcJsGw8XjgEgc=
11+
github.com/enbility/spine-go v0.7.1-0.20241023170915-0b14938a9a37 h1:oZFPU4fHYBbSMVCwP3c9GHov8dFXqqQ2McvEyalsBY8=
12+
github.com/enbility/spine-go v0.7.1-0.20241023170915-0b14938a9a37/go.mod h1:ZoI9TaJO/So/677uknrli8sc6iryD7wC5iWhVIre+MI=
1113
github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6 h1:XOYvxKtT1oxT37w/5oEiRLuPbm9FuJPt3fiYhX0h8Po=
1214
github.com/enbility/zeroconf/v2 v2.0.0-20240920094356-be1cae74fda6/go.mod h1:BszP9qFV14mPXgyIREbgIdQtWxbAj3OKqvK02HihMoM=
1315
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=

0 commit comments

Comments
 (0)