@@ -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
193203var errStatusCode error = fmt .Errorf ("bad status code" )
194204var errMissingGateway error = fmt .Errorf ("missing gateway" )
205+ var errMissingUniqueID error = fmt .Errorf ("uniqueid not found" )
195206
196207func findGateway () (err error ) {
197208 // https://pkg.go.dev/net/http#Get
@@ -246,7 +257,9 @@ func (ua *UnitAsset) setSetPoint(f forms.SignalA_v1a) {
246257
247258func (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
259272func (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+
271318func 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