github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/mappers/bluetooth_mapper/watcher/watcher.go (about) 1 /* 2 Copyright 2019 The KubeEdge Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package watcher 18 19 import ( 20 "errors" 21 "os" 22 "reflect" 23 "strings" 24 "time" 25 26 "github.com/paypal/gatt" 27 "k8s.io/klog" 28 29 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/action_manager" 30 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/data_converter" 31 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/helper" 32 ) 33 34 var DeviceConnected = make(chan bool) 35 var done = make(chan struct{}) 36 var deviceName string 37 var deviceID string 38 var actionManager []actionmanager.Action 39 var dataConverter dataconverter.Converter 40 41 //Watch structure contains the watcher specific configurations 42 type Watcher struct { 43 DeviceTwinAttributes []Attribute `yaml:"device-twin-attributes" json:"device-twin-attributes"` 44 } 45 46 //Attribute structure contains the name of the attribute along with the actions to be performed for this attribute 47 type Attribute struct { 48 Name string `yaml:"device-property-name" json:"device-property-name"` 49 Actions []string `yaml:"actions" json:"actions"` 50 } 51 52 //Initiate initiates the watcher module 53 func (w *Watcher) Initiate(device gatt.Device, nameOfDevice, idOfDevice string, actions []actionmanager.Action, converter dataconverter.Converter) { 54 deviceID = idOfDevice 55 deviceName = nameOfDevice 56 actionManager = actions 57 dataConverter = converter 58 // Register optional handlers. 59 device.Handle( 60 gatt.PeripheralConnected(w.onPeripheralConnected), 61 gatt.PeripheralDisconnected(onPeripheralDisconnected), 62 gatt.PeripheralDiscovered(onPeripheralDiscovered), 63 ) 64 device.Init(onStateChanged) 65 <-done 66 klog.Infof("Watcher Done") 67 } 68 69 //onStateChanged contains the operations to be performed when the state of the peripheral device changes 70 func onStateChanged(device gatt.Device, s gatt.State) { 71 switch s { 72 case gatt.StatePoweredOn: 73 klog.Infof("Scanning for BLE device Broadcasts...") 74 device.Scan([]gatt.UUID{}, true) 75 return 76 default: 77 device.StopScanning() 78 } 79 } 80 81 //onPeripheralDiscovered contains the operations to be performed as soon as the peripheral device is discovered 82 func onPeripheralDiscovered(p gatt.Peripheral, a *gatt.Advertisement, rssi int) { 83 if strings.EqualFold(a.LocalName, strings.Replace(deviceName, "-", " ", -1)) { 84 klog.Infof("Device: %s found !!!! Stop Scanning for devices", deviceName) 85 // Stop scanning once we've got the peripheral we're looking for. 86 p.Device().StopScanning() 87 klog.Infof("Connecting to %s", deviceName) 88 p.Device().Connect(p) 89 } 90 } 91 92 //onPeripheralDisconnected contains the operations to be performed as soon as the peripheral device is disconnected 93 func onPeripheralDisconnected(p gatt.Peripheral, err error) { 94 klog.Infof("Disconnecting from bluetooth device....") 95 DeviceConnected <- false 96 close(done) 97 p.Device().CancelConnection(p) 98 } 99 100 //onPeripheralConnected contains the operations to be performed as soon as the peripheral device is connected 101 func (w *Watcher) onPeripheralConnected(p gatt.Peripheral, err error) { 102 actionmanager.GattPeripheral = p 103 ss, err := p.DiscoverServices(nil) 104 if err != nil { 105 klog.Errorf("Failed to discover services, err: %s\n", err) 106 os.Exit(1) 107 } 108 for _, s := range ss { 109 // Discovery characteristics 110 cs, err := p.DiscoverCharacteristics(nil, s) 111 if err != nil { 112 klog.Errorf("Failed to discover characteristics for service %s, err: %v\n", s.Name(), err) 113 continue 114 } 115 actionmanager.CharacteristicsList = append(actionmanager.CharacteristicsList, cs...) 116 } 117 DeviceConnected <- true 118 for { 119 newWatcher := &Watcher{} 120 if !reflect.DeepEqual(w, newWatcher) { 121 err := w.EquateTwinValue(deviceID) 122 if err != nil { 123 klog.Errorf("Error in watcher functionality: %s", err) 124 } 125 } 126 } 127 } 128 129 //EquateTwinValue is responsible for equating the actual state of the device to the expected state that has been set and syncing back the result to the cloud 130 func (w *Watcher) EquateTwinValue(deviceID string) error { 131 var updateMessage helper.DeviceTwinUpdate 132 updatedActualValues := make(map[string]string) 133 helper.Wg.Add(1) 134 klog.Infof("Watching on the device twin values for device with deviceID: %s", deviceID) 135 go helper.TwinSubscribe(deviceID) 136 helper.GetTwin(updateMessage, deviceID) 137 helper.Wg.Wait() 138 twinUpdated := false 139 for _, twinAttribute := range w.DeviceTwinAttributes { 140 if helper.TwinResult.Twin[twinAttribute.Name] != nil { 141 if helper.TwinResult.Twin[twinAttribute.Name].Expected != nil && ((helper.TwinResult.Twin[twinAttribute.Name].Actual == nil) && helper.TwinResult.Twin[twinAttribute.Name].Expected != nil || (*helper.TwinResult.Twin[twinAttribute.Name].Expected.Value != *helper.TwinResult.Twin[twinAttribute.Name].Actual.Value)) { 142 klog.Infof("%s Expected Value : %s", twinAttribute.Name, *helper.TwinResult.Twin[twinAttribute.Name].Expected.Value) 143 if helper.TwinResult.Twin[twinAttribute.Name].Actual == nil { 144 klog.Infof("%s Actual Value: %v", twinAttribute.Name, helper.TwinResult.Twin[twinAttribute.Name].Actual) 145 } else { 146 klog.Infof("%s Actual Value: %s", twinAttribute.Name, *helper.TwinResult.Twin[twinAttribute.Name].Actual.Value) 147 } 148 klog.Infof("Equating the actual value to expected value for: %s", twinAttribute.Name) 149 for _, watcherAction := range twinAttribute.Actions { 150 actionExists := false 151 for _, action := range actionManager { 152 if strings.EqualFold(action.Name, watcherAction) { 153 actionExists = true 154 for _, converterAttribute := range dataConverter.DataWrite.Attributes { 155 if strings.EqualFold(converterAttribute.Name, twinAttribute.Name) { 156 for operationName, dataMap := range converterAttribute.Operations { 157 if action.Name == operationName { 158 expectedValue := helper.TwinResult.Twin[twinAttribute.Name].Expected.Value 159 if _, ok := dataMap.DataMapping[*expectedValue]; ok { 160 action.Operation.Value = dataMap.DataMapping[*expectedValue] 161 } 162 } 163 action.PerformOperation() 164 } 165 } 166 } 167 } 168 } 169 if !actionExists { 170 return errors.New("The action: " + watcherAction + " does not exist for this device") 171 } 172 } 173 updatedActualValues[twinAttribute.Name] = *helper.TwinResult.Twin[twinAttribute.Name].Expected.Value 174 twinUpdated = true 175 } 176 } else { 177 return errors.New("The attribute: " + twinAttribute.Name + " does not exist for this device") 178 } 179 } 180 if twinUpdated { 181 updateMessage = helper.CreateActualUpdateMessage(updatedActualValues) 182 helper.ChangeTwinValue(updateMessage, deviceID) 183 time.Sleep(2 * time.Second) 184 klog.Infof("Syncing to cloud.....") 185 helper.SyncToCloud(updateMessage, deviceID) 186 } else { 187 klog.Infof("Actual values are in sync with Expected value") 188 } 189 return nil 190 }