Skip to content
This repository was archived by the owner on Mar 22, 2025. It is now read-only.

Commit 245145e

Browse files
committed
Added functions and other goodies
1 parent 5d605be commit 245145e

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

ZigBeeValve/ZigBeeValve.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ func main() {
2121
defer cancel() // make sure all paths cancel the context to avoid context leak
2222

2323
// instantiate the System
24-
sys := components.NewSystem("ZigBee", ctx)
24+
sys := components.NewSystem("ZigBeeHandler", ctx)
2525

2626
// Instatiate the Capusle
2727
sys.Husk = &components.Husk{
28-
Description: " is a controller for smart thermostats connected with a RaspBee II",
28+
Description: " is a controller for smart devices connected with a RaspBee II",
2929
Certificate: "ABCD",
3030
Details: map[string][]string{"Developer": {"Arrowhead"}},
3131
ProtoPort: map[string]int{"https": 0, "http": 8870, "coap": 0},
@@ -37,6 +37,12 @@ func main() {
3737
assetName := assetTemplate.GetName()
3838
sys.UAssets[assetName] = &assetTemplate
3939

40+
// Find zigbee gateway and store it in a global variable for reuse
41+
err := findGateway()
42+
if err != nil {
43+
log.Fatal("Error getting gateway, shutting down: ", err)
44+
}
45+
4046
// Configure the system
4147
rawResources, servsTemp, err := usecases.Configure(&sys)
4248
if err != nil {
@@ -59,12 +65,6 @@ func main() {
5965
// Register the (system) and its services
6066
usecases.RegisterServices(&sys)
6167

62-
// Find zigbee gateway and store it in a global variable for reuse
63-
err = findGateway()
64-
if err != nil {
65-
log.Fatal("Error getting gateway, shutting down: ", err)
66-
}
67-
6868
// start the http handler and server
6969
go usecases.SetoutServers(&sys)
7070

@@ -98,7 +98,7 @@ func (rsc *UnitAsset) setpt(w http.ResponseWriter, r *http.Request) {
9898
}
9999

100100
rsc.setSetPoint(sig)
101-
if rsc.Model == "SmartThermostat" {
101+
if rsc.Model == "ZHAThermostat" {
102102
err = rsc.sendSetPoint()
103103
if err != nil {
104104
http.Error(w, "Couldn't send setpoint.", http.StatusInternalServerError)

ZigBeeValve/thing.go

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ type UnitAsset struct {
3838
ServicesMap components.Services `json:"-"`
3939
CervicesMap components.Cervices `json:"-"`
4040
//
41-
Model string `json:"model"`
42-
Period time.Duration `json:"period"`
43-
Setpt float64 `json:"setpoint"`
44-
Apikey string `json:"APIkey"`
41+
Model string `json:"model"`
42+
Uniqueid string `json:"uniqueid"`
43+
deviceIndex string
44+
Period time.Duration `json:"period"`
45+
Setpt float64 `json:"setpoint"`
46+
Apikey string `json:"APIkey"`
4547
}
4648

4749
// GetName returns the name of the Resource.
@@ -80,12 +82,14 @@ func initTemplate() components.UnitAsset {
8082

8183
// var uat components.UnitAsset // this is an interface, which we then initialize
8284
uat := &UnitAsset{
83-
Name: "Template",
84-
Details: map[string][]string{"Location": {"Kitchen"}},
85-
Model: "SmartThermostat",
86-
Period: 10,
87-
Setpt: 20,
88-
Apikey: "1234",
85+
Name: "Smart Thermostat 1",
86+
Details: map[string][]string{"Location": {"Kitchen"}},
87+
Model: "SmartThermostat",
88+
Uniqueid: "14:ef:14:10:00:6f:d0:d7-11-1201",
89+
deviceIndex: "",
90+
Period: 10,
91+
Setpt: 20,
92+
Apikey: "1234",
8993
ServicesMap: components.Services{
9094
setPointService.SubPath: &setPointService,
9195
},
@@ -115,6 +119,8 @@ func newResource(uac UnitAsset, sys *components.System, servs []components.Servi
115119
Details: uac.Details,
116120
ServicesMap: components.CloneServices(servs),
117121
Model: uac.Model,
122+
Uniqueid: uac.Uniqueid,
123+
deviceIndex: uac.deviceIndex,
118124
Period: uac.Period,
119125
Setpt: uac.Setpt,
120126
Apikey: uac.Apikey,
@@ -129,14 +135,18 @@ func newResource(uac UnitAsset, sys *components.System, servs []components.Servi
129135
}
130136
}
131137
ua.CervicesMap["temperature"].Details = components.MergeDetails(ua.Details, ref.Details)
138+
132139
return ua, func() {
133-
if ua.Model == "SmartThermostat" {
140+
141+
if ua.Model == "ZHAThermostat" {
142+
ua.getConnectedUnits("sensors")
134143
err := ua.sendSetPoint()
135144
if err != nil {
136-
log.Println("Error occured:", err)
145+
log.Println("Error occured during startup, while calling sendSetPoint():", err)
137146
// TODO: Turn off system if this startup() fails?
138147
}
139-
} else if ua.Model == "SmartPlug" {
148+
} else if ua.Model == "Smart plug" {
149+
ua.getConnectedUnits("lights")
140150
// start the unit assets feedbackloop, this fetches the temperature from ds18b20 and and toggles
141151
// between on/off depending on temperature in the room and a set temperature in the unitasset
142152
go ua.feedbackLoop(ua.Owner.Ctx)
@@ -192,6 +202,7 @@ const discoveryURL string = "https://phoscon.de/discover"
192202

193203
var errStatusCode error = fmt.Errorf("bad status code")
194204
var errMissingGateway error = fmt.Errorf("missing gateway")
205+
var errMissingUniqueID error = fmt.Errorf("uniqueid not found")
195206

196207
func findGateway() (err error) {
197208
// https://pkg.go.dev/net/http#Get
@@ -246,7 +257,9 @@ func (ua *UnitAsset) setSetPoint(f forms.SignalA_v1a) {
246257

247258
func (ua *UnitAsset) sendSetPoint() (err error) {
248259
// API call to set desired temp in smart thermostat, PUT call should be sent to URL/api/apikey/sensors/sensor_id/config
249-
apiURL := "http://" + gateway + "/api/" + ua.Apikey + "/sensors/" + ua.Name + "/config"
260+
261+
// --- Send setpoint to specific unit ---
262+
apiURL := "http://" + gateway + "/api/" + ua.Apikey + "/sensors/" + ua.deviceIndex + "/config"
250263
// Create http friendly payload
251264
s := fmt.Sprintf(`{"heatsetpoint":%f}`, ua.Setpt*100) // Create payload
252265
req, err := createRequest(s, apiURL)
@@ -258,7 +271,7 @@ func (ua *UnitAsset) sendSetPoint() (err error) {
258271

259272
func (ua *UnitAsset) toggleState(state bool) (err error) {
260273
// API call turn smart plug on/off, PUT call should be sent to URL/api/apikey/lights/sensor_id/config
261-
apiURL := "http://" + gateway + "/api/" + ua.Apikey + "/lights/" + ua.Name + "/state"
274+
apiURL := "http://" + gateway + "/api/" + ua.Apikey + "/lights/" + ua.deviceIndex + "/state"
262275
// Create http friendly payload
263276
s := fmt.Sprintf(`{"on":%t}`, state) // Create payload
264277
req, err := createRequest(s, apiURL)
@@ -268,6 +281,40 @@ func (ua *UnitAsset) toggleState(state bool) (err error) {
268281
return sendRequest(req)
269282
}
270283

284+
func (ua *UnitAsset) getConnectedUnits(unitType string) (err error) {
285+
// Get all devices
286+
apiURL := fmt.Sprintf("http://%s/api/%s/%s", gateway, ua.Apikey, unitType)
287+
// Create a new request (Get)
288+
// Put data into buffer
289+
req, err := http.NewRequest(http.MethodGet, apiURL, nil) // Put request is made
290+
req.Header.Set("Content-Type", "application/json") // Make sure it's JSON
291+
// Send the request
292+
resp, err := http.DefaultClient.Do(req) // Perform the http request
293+
if err != nil {
294+
return err
295+
}
296+
defer resp.Body.Close()
297+
resBody, err := io.ReadAll(resp.Body) // Read the response body, and check for errors/bad statuscodes
298+
if err != nil {
299+
return
300+
}
301+
if resp.StatusCode > 299 {
302+
return errStatusCode
303+
}
304+
305+
// How to access maps inside of maps below!
306+
// https://stackoverflow.com/questions/28806951/accessing-nested-map-of-type-mapstringinterface-in-golang
307+
var deviceMap map[string]interface{}
308+
json.Unmarshal([]byte(resBody), &deviceMap)
309+
for i := range deviceMap {
310+
if deviceMap[i].(map[string]interface{})["uniqueid"] == ua.Uniqueid {
311+
ua.deviceIndex = i
312+
return
313+
}
314+
}
315+
return errMissingUniqueID
316+
}
317+
271318
func createRequest(data string, apiURL string) (req *http.Request, err error) {
272319
body := bytes.NewReader([]byte(data)) // Put data into buffer
273320
req, err = http.NewRequest(http.MethodPut, apiURL, body) // Put request is made
@@ -293,3 +340,6 @@ func sendRequest(req *http.Request) (err error) {
293340
}
294341
return
295342
}
343+
344+
// Create a group, add all lights/power plugs from e.g. kitchen to said group
345+
// Create rule, on button.event toggle power plugs

0 commit comments

Comments
 (0)