github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/mappers/bluetooth_mapper/controller/controller.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 controller 18 19 import ( 20 "encoding/json" 21 "strings" 22 23 MQTT "github.com/eclipse/paho.mqtt.golang" 24 "github.com/paypal/gatt" 25 "github.com/paypal/gatt/examples/option" 26 "k8s.io/klog" 27 28 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/action_manager" 29 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/configuration" 30 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/data_converter" 31 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/helper" 32 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/scheduler" 33 "github.com/kubeedge/kubeedge/mappers/bluetooth_mapper/watcher" 34 ) 35 36 // constants which can be used to convey topic information 37 const ( 38 MapperTopicPrefix = "$ke/device/bluetooth-mapper/" 39 WatcherTopicSuffix = "/watcher/create" 40 SchedulerCreateTopicSuffix = "/scheduler/create" 41 SchedulerDeleteTopicSuffix = "/scheduler/delete" 42 ActionManagerCreateTopicSuffix = "/action-manager/create" 43 ActionManagerDeleteTopicSuffix = "/action-manager/delete" 44 ) 45 46 var topicMap = make(map[string]MQTT.MessageHandler) 47 48 //Config contains the configuration used by the controller 49 type Config struct { 50 Mqtt configuration.Mqtt `yaml:"mqtt"` 51 Device configuration.Device `yaml:"device"` 52 Watcher watcher.Watcher `yaml:"watcher"` 53 Scheduler scheduler.Scheduler `yaml:"scheduler"` 54 ActionManager actionmanager.ActionManager `yaml:"action-manager"` 55 Converter dataconverter.Converter `yaml:"data-converter"` 56 } 57 58 // initTopicMap initializes topics to their respective handler functions 59 func (c *Config) initTopicMap() { 60 topicMap[MapperTopicPrefix+c.Device.ID+WatcherTopicSuffix] = c.handleWatchMessage 61 topicMap[MapperTopicPrefix+c.Device.ID+SchedulerCreateTopicSuffix] = c.handleScheduleCreateMessage 62 topicMap[MapperTopicPrefix+c.Device.ID+SchedulerDeleteTopicSuffix] = c.handleScheduleDeleteMessage 63 topicMap[MapperTopicPrefix+c.Device.ID+ActionManagerCreateTopicSuffix] = c.handleActionCreateMessage 64 topicMap[MapperTopicPrefix+c.Device.ID+ActionManagerDeleteTopicSuffix] = c.handleActionDeleteMessage 65 } 66 67 //Start starts the controller of the mapper 68 func (c *Config) Start() { 69 c.initTopicMap() 70 helper.MqttConnect(c.Mqtt.Mode, c.Mqtt.InternalServer, c.Mqtt.Server) 71 subscribeAllTopics() 72 helper.ControllerWg.Add(1) 73 device, err := gatt.NewDevice(option.DefaultClientOptions...) 74 if err != nil { 75 klog.Fatalf("Failed to open device, err: %s\n", err) 76 return 77 } 78 go c.Watcher.Initiate(device, c.Device.Name, c.Device.ID, c.ActionManager.Actions, c.Converter) 79 80 <-watcher.DeviceConnected 81 for _, action := range c.ActionManager.Actions { 82 if action.PerformImmediately { 83 action.PerformOperation(c.Converter.DataRead) 84 } 85 } 86 87 for _, schedule := range c.Scheduler.Schedules { 88 helper.ControllerWg.Add(1) 89 go schedule.ExecuteSchedule(c.ActionManager.Actions, c.Converter.DataRead, c.Device.ID) 90 } 91 helper.ControllerWg.Wait() 92 } 93 94 //subscribeAllTopics subscribes to mqtt topics associated with mapper 95 func subscribeAllTopics() { 96 for key, value := range topicMap { 97 helper.TokenClient = helper.Client.Subscribe(key, 0, value) 98 if helper.TokenClient.Wait() && helper.TokenClient.Error() != nil { 99 klog.Errorf("subscribe() Error in topic: %s is: %s", key, helper.TokenClient.Error()) 100 } 101 } 102 } 103 104 //handleWatchMessage is the MQTT handler function for changing watcher configuration at runtime 105 func (c *Config) handleWatchMessage(client MQTT.Client, message MQTT.Message) { 106 newWatch := watcher.Watcher{} 107 err := json.Unmarshal(message.Payload(), &newWatch) 108 if err != nil { 109 klog.Errorf("Error in unmarshalling: %s", err) 110 } 111 c.Watcher = newWatch 112 configuration.Config.Watcher = c.Watcher 113 klog.Infof("New watcher has been started") 114 klog.Infof("New Watcher: %v", c.Watcher) 115 } 116 117 //handleScheduleCreateMessage is the MQTT handler function for adding schedules at runtime 118 func (c *Config) handleScheduleCreateMessage(client MQTT.Client, message MQTT.Message) { 119 newSchedules := []scheduler.Schedule{} 120 err := json.Unmarshal(message.Payload(), &newSchedules) 121 if err != nil { 122 klog.Errorf("Error in unmarshalling: %s", err) 123 } 124 for _, newSchedule := range newSchedules { 125 scheduleExists := false 126 for scheduleIndex, schedule := range c.Scheduler.Schedules { 127 if schedule.Name == newSchedule.Name { 128 c.Scheduler.Schedules[scheduleIndex] = newSchedule 129 scheduleExists = true 130 break 131 } 132 } 133 if scheduleExists { 134 c.Scheduler.Schedules = append(c.Scheduler.Schedules, newSchedule) 135 klog.Infof("Schedule: %s has been updated", newSchedule.Name) 136 klog.Infof("Updated Schedule: %v", newSchedule) 137 } else { 138 klog.Infof("Schedule: %s has been added", newSchedule.Name) 139 klog.Infof("New Schedule: %v", newSchedule) 140 } 141 configuration.Config.Scheduler = c.Scheduler 142 helper.ControllerWg.Add(1) 143 newSchedule.ExecuteSchedule(c.ActionManager.Actions, c.Converter.DataRead, c.Device.ID) 144 } 145 } 146 147 //handleScheduleDeleteMessage is the MQTT handler function for deleting schedules at runtime 148 func (c *Config) handleScheduleDeleteMessage(client MQTT.Client, message MQTT.Message) { 149 schedulesToBeDeleted := []scheduler.Schedule{} 150 err := json.Unmarshal(message.Payload(), &schedulesToBeDeleted) 151 if err != nil { 152 klog.Errorf("Error in unmarshalling: %s", err) 153 } 154 for _, scheduleToBeDeleted := range schedulesToBeDeleted { 155 scheduleExists := false 156 for index, schedule := range c.Scheduler.Schedules { 157 if strings.EqualFold(schedule.Name, scheduleToBeDeleted.Name) { 158 scheduleExists = true 159 copy(c.Scheduler.Schedules[index:], c.Scheduler.Schedules[index+1:]) 160 c.Scheduler.Schedules = c.Scheduler.Schedules[:len(c.Scheduler.Schedules)-1] 161 break 162 } 163 } 164 configuration.Config.Scheduler = c.Scheduler 165 if !scheduleExists { 166 klog.Errorf("Schedule: %s does not exist", scheduleToBeDeleted.Name) 167 } else { 168 klog.Infof("Schedule: %s has been deleted ", scheduleToBeDeleted.Name) 169 } 170 } 171 } 172 173 //handleActionCreateMessage MQTT handler function for adding actions at runtime 174 func (c *Config) handleActionCreateMessage(client MQTT.Client, message MQTT.Message) { 175 newActions := []actionmanager.Action{} 176 err := json.Unmarshal(message.Payload(), &newActions) 177 if err != nil { 178 klog.Errorf("Error in unmarshalling: %s", err) 179 } 180 for _, newAction := range newActions { 181 actionExists := false 182 for actionIndex, action := range c.ActionManager.Actions { 183 if action.Name == newAction.Name { 184 c.ActionManager.Actions[actionIndex] = newAction 185 actionExists = true 186 break 187 } 188 } 189 if actionExists { 190 c.ActionManager.Actions = append(c.ActionManager.Actions, newAction) 191 klog.Infof("Action: %s has been updated", newAction.Name) 192 klog.Infof("Updated Action: %v", newAction) 193 } else { 194 klog.Infof("Action: %s has been added ", newAction.Name) 195 klog.Infof("New Action: %v", newAction) 196 } 197 configuration.Config.ActionManager = c.ActionManager 198 if newAction.PerformImmediately { 199 newAction.PerformOperation(c.Converter.DataRead) 200 } 201 } 202 } 203 204 //handleActionDeleteMessage MQTT handler function for deleting actions at runtime 205 func (c *Config) handleActionDeleteMessage(client MQTT.Client, message MQTT.Message) { 206 actionsToBeDeleted := []actionmanager.Action{} 207 err := json.Unmarshal(message.Payload(), &actionsToBeDeleted) 208 if err != nil { 209 klog.Errorf("Error in unmarshalling: %s", err) 210 } 211 for _, actionToBeDeleted := range actionsToBeDeleted { 212 actionExists := false 213 for index, action := range c.ActionManager.Actions { 214 if strings.EqualFold(action.Name, actionToBeDeleted.Name) { 215 actionExists = true 216 copy(c.ActionManager.Actions[index:], c.ActionManager.Actions[index+1:]) 217 c.ActionManager.Actions = c.ActionManager.Actions[:len(c.ActionManager.Actions)-1] 218 break 219 } 220 } 221 configuration.Config.ActionManager = c.ActionManager 222 if !actionExists { 223 klog.Errorf("Action: %s did not exist", actionToBeDeleted.Name) 224 } else { 225 klog.Infof("Action: %s has been deleted ", actionToBeDeleted.Name) 226 } 227 } 228 }