-
Notifications
You must be signed in to change notification settings - Fork 1
/
devicereinterrogation.go
100 lines (84 loc) · 3.07 KB
/
devicereinterrogation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package ezstack
// Registration is somewhat the most complex operation of this package, so it deserves its own file
import (
"fmt"
"github.com/function61/hautomo/pkg/ezstack/zcl/cluster"
"github.com/function61/hautomo/pkg/ezstack/zigbee"
"github.com/function61/hautomo/pkg/ezstack/znp"
)
// queries "device metadata" such as description, endpoints, supported clusters
func (s *Stack) interrogateDevice(announcedDevice *znp.ZdoEndDeviceAnnceInd) (*Device, error) {
ieeeAddress := zigbee.IEEEAddress(announcedDevice.IEEEAddr)
nwkAddress := announcedDevice.NwkAddr
deviceDetails, err := s.ReadAttributes(nwkAddress, cluster.IdGenBasic, []cluster.AttributeId{
cluster.AttrBasicManufacturerName,
cluster.AttrBasicModelId,
cluster.AttrBasicPowerSource,
})
if err != nil {
return nil, fmt.Errorf("querying basic metadata: %w", err)
}
findAttr := func(id cluster.AttributeId) *cluster.Attribute { // ugh
for _, attr := range deviceDetails.ReadAttributeStatuses {
if attr.AttributeID == uint16(id) {
return attr.Attribute
}
}
return nil
}
manufacturer := func() string {
if val, ok := findAttr(cluster.AttrBasicManufacturerName).Value.(string); ok {
return val
}
return ""
}()
deviceModel := func() string {
if val, ok := findAttr(cluster.AttrBasicModelId).Value.(string); ok {
return val
}
return ""
}()
powerSource := func() PowerSource {
if val, ok := findAttr(cluster.AttrBasicPowerSource).Value.(uint64); ok {
return PowerSource(val)
}
return PowerSource(0) // this is what unset branch did in previous implementation anyway
}()
logl.Debug.Printf("Querying node description: [%s]", ieeeAddress)
nodeDescription, err := s.coordinator.NodeDescription(nwkAddress)
if err != nil {
return nil, fmt.Errorf("querying node description: %w", err)
}
logl.Debug.Printf("Querying active endpoints: [%s]", ieeeAddress)
activeEndpoints, err := s.coordinator.ActiveEndpoints(nwkAddress)
if err != nil {
return nil, fmt.Errorf("querying active endpoints: %w", err)
}
endpoints := []*Endpoint{}
for _, endpointNo := range activeEndpoints.ActiveEPList {
logl.Debug.Printf("Request endpoint description: [%s], ep: [%d]", ieeeAddress, endpointNo)
endpointDescr, err := s.coordinator.SimpleDescription(nwkAddress, endpointNo)
if err != nil {
return nil, fmt.Errorf("query endpoint %d description: %w", endpointNo, err)
}
endpoints = append(endpoints, &Endpoint{
Id: endpointDescr.Endpoint,
ProfileId: endpointDescr.ProfileID,
DeviceId: endpointDescr.DeviceID,
DeviceVersion: endpointDescr.DeviceVersion,
InClusterList: castClusterIds(endpointDescr.InClusterList),
OutClusterList: castClusterIds(endpointDescr.OutClusterList),
})
}
return &Device{
IEEEAddress: ieeeAddress,
NetworkAddress: nwkAddress,
MainPowered: announcedDevice.Capabilities.MainPowered > 0,
Manufacturer: manufacturer,
Model: Model(deviceModel),
PowerSource: powerSource,
LogicalType: nodeDescription.LogicalType,
ManufacturerId: nodeDescription.ManufacturerCode,
Endpoints: endpoints,
}, nil
}