-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathentities.go
116 lines (95 loc) · 2.65 KB
/
entities.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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package hal
import (
"reflect"
"github.com/dansimau/hal/homeassistant"
)
// EntityInterface is the interface that we accept which allows us to create
// custom components that embed an Entity.
type EntityInterface interface {
ConnectionBinder
GetID() string
GetState() homeassistant.State
SetState(event homeassistant.State)
}
type Entities []EntityInterface
// Entity is a base type for all entities that can be embedded into other types.
type Entity struct {
connection *Connection
state homeassistant.State
}
func NewEntity(id string) *Entity {
return &Entity{state: homeassistant.State{EntityID: id}}
}
// BindConnection binds the entity to the connection. This allows entities to
// publish messages.
func (e *Entity) BindConnection(connection *Connection) {
e.connection = connection
}
func (e *Entity) GetID() string {
return e.state.EntityID
}
func (e *Entity) SetState(state homeassistant.State) {
e.state = state
}
func (e *Entity) GetState() homeassistant.State {
return e.state
}
// findEntities recursively finds all entities in a struct, map, or slice.
func findEntities(v any) []EntityInterface {
var entities []EntityInterface
value := reflect.ValueOf(v)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
if value.Kind() != reflect.Struct {
return entities
}
valueType := value.Type()
for i := range value.NumField() {
field := value.Field(i)
fieldType := field.Type()
// Skip unexported fields
if !valueType.Field(i).IsExported() {
continue
}
// Check if field implements EntityLike interface
if field.Kind() == reflect.Ptr && !field.IsNil() {
if entity, ok := field.Interface().(EntityInterface); ok {
entities = append(entities, entity)
continue
}
}
// Recursively check for nested structs, maps, and slices
switch fieldType.Kind() {
case reflect.Struct:
if field.CanInterface() {
entities = append(entities, findEntities(field.Interface())...)
}
case reflect.Ptr:
if !field.IsNil() && field.CanInterface() {
entities = append(entities, findEntities(field.Interface())...)
}
case reflect.Map:
if !field.IsNil() && field.CanInterface() {
for _, key := range field.MapKeys() {
mapValue := field.MapIndex(key)
if mapValue.CanInterface() {
entities = append(entities, findEntities(mapValue.Interface())...)
}
}
}
case reflect.Slice:
if !field.IsNil() && field.CanInterface() {
for i := range field.Len() {
sliceValue := field.Index(i)
if sliceValue.CanInterface() {
entities = append(entities, findEntities(sliceValue.Interface())...)
}
}
}
default:
// Ignore other types
}
}
return entities
}