github.com/binkynet/BinkyNet@v1.12.1-0.20240421190447-da4e34c20be0/apis/v1/objecthelper.go (about) 1 // Copyright 2018 Ewout Prangsma 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Author Ewout Prangsma 16 // 17 18 package v1 19 20 import "strconv" 21 22 // ObjectTypeInfo holds builtin information for a type of objects. 23 type ObjectTypeInfo struct { 24 // Type of the object 25 Type ObjectType 26 // Description of the object type 27 Description string 28 // Possible (required & optional) connections of objects of this type to devices. 29 Connections []ObjectConnectionInfo 30 } 31 32 // ConnectionByName returns the information for the connection with given name. 33 // Returns name, found. 34 func (i ObjectTypeInfo) ConnectionByName(name ConnectionName) (ObjectConnectionInfo, bool) { 35 for _, x := range i.Connections { 36 if x.Name == name { 37 return x, true 38 } 39 } 40 return ObjectConnectionInfo{}, false 41 } 42 43 // ObjectConnectionInfo descripts a connection of a type of objects to a device. 44 type ObjectConnectionInfo struct { 45 // Name of the connection from object to device 46 Name ConnectionName 47 // If this connection required? 48 Required bool 49 // How many device-pins are expected for this connection 50 PinCount int 51 } 52 53 var ( 54 objectTypeInfos = []ObjectTypeInfo{ 55 ObjectTypeInfo{ 56 Type: ObjectTypeBinarySensor, 57 Description: "Single bit input sensor", 58 Connections: []ObjectConnectionInfo{ 59 ObjectConnectionInfo{Name: ConnectionNameSensor, Required: true, PinCount: 1}, 60 }, 61 }, 62 ObjectTypeInfo{ 63 Type: ObjectTypeBinaryOutput, 64 Description: "Single bit output", 65 Connections: []ObjectConnectionInfo{ 66 ObjectConnectionInfo{Name: ConnectionNameOutput, Required: true, PinCount: 1}, 67 }, 68 }, 69 ObjectTypeInfo{ 70 Type: ObjectTypeServoSwitch, 71 Description: "Left or right switch driven by a single servo with optional phase switching relays", 72 Connections: []ObjectConnectionInfo{ 73 ObjectConnectionInfo{Name: ConnectionNameServo, Required: true, PinCount: 1}, 74 ObjectConnectionInfo{Name: ConnectionNamePhaseStraightRelay, Required: false, PinCount: 1}, 75 ObjectConnectionInfo{Name: ConnectionNamePhaseOffRelay, Required: false, PinCount: 1}, 76 }, 77 }, 78 ObjectTypeInfo{ 79 Type: ObjectTypeRelaySwitch, 80 Description: "Left or right switch driven by 2 relays", 81 Connections: []ObjectConnectionInfo{ 82 ObjectConnectionInfo{Name: ConnectionNameStraightRelay, Required: true, PinCount: 1}, 83 ObjectConnectionInfo{Name: ConnectionNameOffRelay, Required: true, PinCount: 1}, 84 }, 85 }, 86 } 87 ) 88 89 // Validate the given type, returning nil on ok, 90 // or an error upon validation issues. 91 func (t ObjectType) Validate() error { 92 for _, typeInfo := range objectTypeInfos { 93 if typeInfo.Type == t { 94 return nil 95 } 96 } 97 return InvalidArgument("invalid object type '%s'", string(t)) 98 } 99 100 // TypeInfo returns the ObjectType information for this type of object. 101 func (t ObjectType) TypeInfo() ObjectTypeInfo { 102 for _, typeInfo := range objectTypeInfos { 103 if typeInfo.Type == t { 104 return typeInfo 105 } 106 } 107 return ObjectTypeInfo{} 108 } 109 110 // ConnectionByName returns the connection of the object with given name 111 func (o Object) ConnectionByName(name ConnectionName) (*Connection, bool) { 112 for _, conn := range o.GetConnections() { 113 if conn.Key == name { 114 return conn, true 115 } 116 } 117 return nil, false 118 } 119 120 // Validate the given configuration, returning nil on ok, 121 // or an error upon validation issues. 122 func (o Object) Validate() error { 123 if err := o.Type.Validate(); err != nil { 124 return InvalidArgument("Error in Type of '%s': %s", o.Id, err.Error()) 125 } 126 typeInfo := o.Type.TypeInfo() 127 // Check configured connections 128 for _, conn := range o.Connections { 129 cInfo, found := typeInfo.ConnectionByName(conn.Key) 130 if !found { 131 return InvalidArgument("Object '%s' has an unexpected connection named '%s'", o.Id, conn.Key) 132 } 133 if cInfo.PinCount != len(conn.Pins) { 134 return InvalidArgument("Object '%s' has an unexpected number of pins for connection '%s'. Got %d, expected %d", o.Id, conn.Key, len(conn.Pins), cInfo.PinCount) 135 } 136 // Validate pins 137 for idx, p := range conn.Pins { 138 if p.Index == 0 { 139 return InvalidArgument("Object '%s' has an invalid index at position %d of the connection named '%s'", o.Id, idx, conn.Key) 140 } 141 } 142 } 143 // Look for missing connections 144 for _, conn := range typeInfo.Connections { 145 if conn.Required { 146 if _, found := o.ConnectionByName(conn.Name); !found { 147 return InvalidArgument("Object '%s' lacks a required connection named '%s'", o.Id, conn.Name) 148 } 149 } 150 } 151 return nil 152 } 153 154 // GetStringConfig returns the configuration value for the given key. 155 // If not found, the default value for the key is returned. 156 func (o Object) GetStringConfig(key ObjectConfigKey) string { 157 value, found := o.Configuration[key] 158 if found { 159 return value 160 } 161 return key.DefaultValue() 162 } 163 164 // GetBoolConfig returns the bool-typed configuration value for the given key. 165 // If not found or not an int, the default value for the key is returned. 166 func (o Object) GetBoolConfig(key ObjectConfigKey) bool { 167 value, found := o.Configuration[key] 168 if !found { 169 value = key.DefaultValue() 170 } 171 if tValue, err := strconv.ParseBool(value); err == nil { 172 return tValue 173 } 174 return false 175 } 176 177 // GetIntConfig returns the int-typed configuration value for the given key. 178 // If not found or not an int, the default value for the key is returned. 179 func (o Object) GetIntConfig(key ObjectConfigKey) int { 180 value, found := o.Configuration[key] 181 if !found { 182 value = key.DefaultValue() 183 } 184 if tValue, err := strconv.Atoi(value); err == nil { 185 return tValue 186 } 187 return 0 188 }