Skip to content

Commit a24f3ed

Browse files
committed
Initial commit for go_eebus
Co-authored-by: Rhib
0 parents  commit a24f3ed

25 files changed

+1700
-0
lines changed

LICENSE.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 GoEEBUS
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# go_eebus
2+
<img src="https://github.com/LMF-DHBW/go_eebus/blob/master/assets/eebus_logo.png" width="150">
3+
This repository includes a framework of the EEBUS protocol in the Go programming language.
4+
The EEBUS protocol suite provides high-quality protocols, which allow efficient communication of smart home IoT devices, independent of device brand, type and other factors.
5+
It provides an open-source, future-proof solution that can be applied in many environments and for numerous applications.
6+
7+
## About
8+
This framework is part of a student research project at DHBW Stuttgart and provides a partial implementation of the EEBUS protocols SHIP and SPINE.
9+
10+
The documentation of the student research project can be found here:
11+
12+
[GoEEBUS.pdf](https://github.com/LMF-DHBW/go_eebus/blob/main/assets/GoEEBUS.pdf)
13+
14+
The other part of the research project was the implementation of device specific code.
15+
The GitHub repository can be found here:
16+
17+
[https://github.com/LMF-DHBW/go_eebus_devices](https://github.com/LMF-DHBW/go_eebus_devices)
18+
19+
## Explanation and examples
20+
21+
The following code shows how the framework can be used in general:
22+
23+
````go
24+
// Importing the framework
25+
import eebus "github.com/LMF-DHBW/go-eebus"
26+
27+
// Configure EEBUS node
28+
eebusNode = eebus.NewEebusNode("100.90.1.102", true, "gateway", "0001", "DHBW", "Gateway")
29+
30+
// IP-Adr, is gateway, ssl cert name, device ID, brand name, device type
31+
eebusNode.Update = update // set method called on subscription updates
32+
33+
// Function that creates device structure
34+
buildDeviceModel(eebusNode)
35+
36+
// Start node
37+
eebusNode.Start()
38+
````
39+
40+
The following code shows how the device structure for an EEBUS node can be created, in this example an ActuatorSwitch device is created:
41+
42+
````go
43+
eebusNode.DeviceStructure.DeviceType = "Generic"
44+
eebusNode.DeviceStructure.DeviceAddress = "Switch1"
45+
eebusNode.DeviceStructure.Entities = []*resources.EntityModel{
46+
{
47+
EntityType: "Switch",
48+
EntityAddress: 0,
49+
Features: []*resources.FeatureModel{
50+
// Entitiy 0, Feature 0 always has to be node management
51+
eebusNode.DeviceStructure.CreateNodeManagement(false),
52+
{
53+
FeatureType: "ActuatorSwitch",
54+
FeatureAddress: 1,
55+
Role: "client",
56+
Functions: resources.ActuatorSwitch("button", "button for leds"),
57+
BindingTo: []string{"ActuatorSwitch"},
58+
},
59+
},
60+
},
61+
}
62+
63+
// Create node management again, in order to update discovery data
64+
eebusNode.DeviceStructure.Entities[0].Features[0] = eebusNode.DeviceStructure.CreateNodeManagement(false)
65+
````
66+
67+
The gateway device has a list of requests, the following code shows how requests can be accepted from the gateway:
68+
69+
````go
70+
// Requests are saved in the following list:
71+
eebusNode.SpineNode.ShipNode.Requests
72+
73+
i := 0 // Select the first entry as an example
74+
75+
// Accept request by connecting with the device
76+
req := eebusNode.SpineNode.ShipNode.Requests[i]
77+
go eebusNode.SpineNode.ShipNode.Connect(req.Path, req.Ski)
78+
79+
// Remove request from list
80+
eebusNode.SpineNode.ShipNode.Requests = append(eebusNode.SpineNode.ShipNode.Requests[:i], eebusNode.SpineNode.ShipNode.Requests[i+1:]...)
81+
````
82+
83+
How subscription messages can be read:
84+
85+
````go
86+
func update(data resources.DatagramType, conn spine.SpineConnection) {
87+
entitySource := data.Header.AddressSource.Entity
88+
featureSource := data.Header.AddressSource.Feature
89+
if conn.DiscoveryInformation.FeatureInformation[featureSource].Description.FeatureType == "Measurement" {
90+
var Function *resources.MeasurementDataType
91+
err := xml.Unmarshal([]byte(data.Payload.Cmd.Function), &Function)
92+
// Function.Value contains measured value
93+
}
94+
}
95+
````
96+
97+
How the states of features can be read:
98+
99+
````go
100+
for _, e := range eebusNode.SpineNode.Connections {
101+
for _, feature := range e.SubscriptionData {
102+
if feature.FeatureType == "ActuatorSwitch" && feature.EntityType == "LED" {
103+
var state *resources.FunctionElement
104+
err := xml.Unmarshal([]byte(feature.CurrentState), &state)
105+
// state.Function contains the state (on/off)
106+
}
107+
}
108+
}
109+
````
110+
111+
How subscription messages can be send:
112+
113+
````go
114+
for _, e := range eebusNode.SpineNode.Subscriptions {
115+
e.Send("notify", resources.MakePayload("actuatorSwitchData",
116+
resources.FunctionElement{
117+
Function: "on",
118+
}))
119+
}
120+
````
121+
122+
How binding messages can be send:
123+
124+
````go
125+
for _, e := range eebusNode.SpineNode.Bindings {
126+
e.Send("write", resources.MakePayload("actuatorSwitchData",
127+
resources.FunctionElement{
128+
Function: "toggle",
129+
}))
130+
}
131+
````
132+
133+
## UML diagrams
134+
135+
The framework is devided into the SHIP protocol, the SPINE protocol and defined EEBUS resources.
136+
137+
The following images show the UML diagrams for the framework:
138+
139+
<img src="https://github.com/LMF-DHBW/go-eebus/blob/main/assets/ship_uml.png" width="600">
140+
141+
<img src="https://github.com/LMF-DHBW/go-eebus/blob/main/assets/spine_uml.png" width="600">
142+
143+
144+
145+
146+
147+
![Resources Uml part1](https://github.com/LMF-DHBW/go-eebus/blob/main/assets/resources_uml_part1.png)
148+
149+
![Resources Uml part2](https://github.com/LMF-DHBW/go-eebus/blob/main/assets/resources_uml_part2.png)

assets/eebus_logo.png

25.8 KB
Loading

assets/resources_uml_part1.png

97.4 KB
Loading

assets/resources_uml_part2.png

158 KB
Loading

assets/ship_uml.png

76.7 KB
Loading

assets/spine_uml.png

112 KB
Loading

eebus.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package go_eebus
2+
3+
import (
4+
"github.com/LMF-DHBW/go_eebus/resources"
5+
"github.com/LMF-DHBW/go_eebus/spine"
6+
)
7+
8+
type EebusNode struct {
9+
isGateway bool
10+
SpineNode *spine.SpineNode
11+
DeviceStructure *resources.DeviceModel
12+
Update Updater
13+
}
14+
15+
type Updater func(resources.DatagramType, spine.SpineConnection)
16+
17+
func NewEebusNode(hostname string, isGateway bool, certName string, devId string, brand string, devType string) *EebusNode {
18+
deviceModel := &resources.DeviceModel{}
19+
newEebusNode := &EebusNode{isGateway, nil, deviceModel, nil}
20+
newEebusNode.SpineNode = spine.NewSpineNode(hostname, isGateway, deviceModel, newEebusNode.SubscriptionNofity, certName, devId, brand, devType)
21+
return newEebusNode
22+
}
23+
24+
func (eebusNode *EebusNode) SubscriptionNofity(datagram resources.DatagramType, conn spine.SpineConnection) {
25+
if eebusNode.Update != nil {
26+
eebusNode.Update(datagram, conn)
27+
}
28+
}
29+
30+
func (eebusNode *EebusNode) Start() {
31+
eebusNode.SpineNode.Start()
32+
}

go.mod

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module github.com/LMF-DHBW/go_eebus
2+
3+
go 1.17
4+
5+
require (
6+
github.com/grandcat/zeroconf v1.0.0
7+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
8+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
9+
)
10+
11+
require (
12+
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
13+
github.com/miekg/dns v1.1.27 // indirect
14+
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
15+
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
16+
)

go.sum

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
2+
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
3+
github.com/grandcat/zeroconf v1.0.0 h1:uHhahLBKqwWBV6WZUDAT71044vwOTL+McW0mBJvo6kE=
4+
github.com/grandcat/zeroconf v1.0.0/go.mod h1:lTKmG1zh86XyCoUeIHSA4FJMBwCJiQmGfcP2PdzytEs=
5+
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
6+
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
7+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
8+
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
9+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
10+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
11+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
12+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
13+
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
14+
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
15+
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
16+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
17+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
18+
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
19+
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
20+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
21+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
22+
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
23+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
24+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
25+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
26+
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
27+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
28+
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
29+
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
30+
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
31+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
32+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
33+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
34+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
35+
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
36+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

resources/actuatorswitch.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package resources
2+
3+
type Notifier func(string, string, FeatureAddressType)
4+
5+
type FunctionElement struct {
6+
Function string `xml:"function"`
7+
}
8+
9+
type DescriptionElement struct {
10+
Label string `xml:"label"`
11+
Description string `xml:"description"`
12+
}
13+
14+
func ActuatorSwitch(label string, description string, ChangeNotify Notifier) []*FunctionModel {
15+
return []*FunctionModel{
16+
{
17+
FunctionName: "actuatorSwitchData",
18+
Function: &FunctionElement{
19+
Function: "off",
20+
},
21+
ChangeNotify: ChangeNotify,
22+
},
23+
{
24+
FunctionName: "actuatorSwitchDescriptionData",
25+
Function: &DescriptionElement{
26+
label,
27+
description,
28+
},
29+
},
30+
}
31+
}

resources/bindsubscribe.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package resources
2+
3+
type NodeManagementBindingData struct {
4+
BindingEntries []*BindSubscribeEntry `xml:"bindingEntries"`
5+
}
6+
7+
type BindSubscribeEntry struct {
8+
ClientAddress FeatureAddressType `xml:"clientAddress"`
9+
ServerAddress FeatureAddressType `xml:"serverAddress"`
10+
}
11+
12+
type NodeManagementSubscriptionData struct {
13+
SubscriptionEntries []*BindSubscribeEntry `xml:"subscriptionEntries"`
14+
}
15+
16+
type NodeManagementBindingRequestCall struct {
17+
BindingRequest *BindingManagementRequestCallType `xml:"bindingRequest"`
18+
}
19+
20+
type BindingManagementRequestCallType struct {
21+
ClientAddress *FeatureAddressType `xml:"clientAddress"`
22+
ServerAddress *FeatureAddressType `xml:"serverAddress"`
23+
ServerFeatureType string `xml:"serverFeatureType"`
24+
}
25+
26+
type NodeManagementSubscriptionRequestCall struct {
27+
SubscriptionRequest *SubscriptionManagementRequestCallType `xml:"subscriptionRequest"`
28+
}
29+
30+
type SubscriptionManagementRequestCallType struct {
31+
ClientAddress *FeatureAddressType `xml:"clientAddress"`
32+
ServerAddress *FeatureAddressType `xml:"serverAddress"`
33+
ServerFeatureType string `xml:"serverFeatureType"`
34+
}
35+
36+
type ResultElement struct {
37+
ErrorNumber int `xml:"errorNumber"`
38+
Description string `xml:"description"`
39+
}
40+
41+
func ResultData(errorNumber int, description string) *ResultElement {
42+
return &ResultElement{
43+
ErrorNumber: errorNumber,
44+
Description: description,
45+
}
46+
}

0 commit comments

Comments
 (0)