agi.iot.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package agi
  2. import (
  3. "encoding/json"
  4. "log"
  5. "github.com/robertkrimen/otto"
  6. "imuslab.com/arozos/mod/agi/static"
  7. "imuslab.com/arozos/mod/iot"
  8. )
  9. /*
  10. AGI IoT Control Protocols
  11. This is a library for allowing AGI script to control / send commands to IoT devices
  12. Use with caution and prepare to handle errors. IoT devices are not always online / connectabe.
  13. Author: tobychui
  14. */
  15. func (g *Gateway) IoTLibRegister() {
  16. err := g.RegisterLib("iot", g.injectIoTFunctions)
  17. if err != nil {
  18. log.Fatal(err)
  19. }
  20. }
  21. func (g *Gateway) injectIoTFunctions(payload *static.AgiLibInjectionPayload) {
  22. vm := payload.VM
  23. //u := payload.User
  24. //scriptFsh := payload.ScriptFsh
  25. //scriptPath := payload.ScriptPath
  26. //w := payload.Writer
  27. //r := payload.Request
  28. //Scan and return the latest iot device list
  29. vm.Set("_iot_scan", func(call otto.FunctionCall) otto.Value {
  30. scannedDevices := g.Option.IotManager.ScanDevices()
  31. js, _ := json.Marshal(scannedDevices)
  32. devList, err := vm.ToValue(string(js))
  33. if err != nil {
  34. return otto.FalseValue()
  35. }
  36. return devList
  37. })
  38. //List the current scanned device list from cache
  39. vm.Set("_iot_list", func(call otto.FunctionCall) otto.Value {
  40. devices := g.Option.IotManager.GetCachedDeviceList()
  41. js, _ := json.Marshal(devices)
  42. devList, err := vm.ToValue(string(js))
  43. if err != nil {
  44. return otto.FalseValue()
  45. }
  46. return devList
  47. })
  48. //Conenct an iot device. Return true if the device is connected or the device do not require connection before command exec
  49. vm.Set("_iot_connect", func(call otto.FunctionCall) otto.Value {
  50. //Get device ID from paratmer
  51. devID, err := call.Argument(0).ToString()
  52. if err != nil {
  53. return otto.FalseValue()
  54. }
  55. //Get the auth info from paramters
  56. username, err := call.Argument(1).ToString()
  57. if err != nil {
  58. username = ""
  59. }
  60. password, err := call.Argument(2).ToString()
  61. if err != nil {
  62. password = ""
  63. }
  64. token, err := call.Argument(3).ToString()
  65. if err != nil {
  66. token = ""
  67. }
  68. //Get device by id
  69. dev := g.Option.IotManager.GetDeviceByID(devID)
  70. if dev == nil {
  71. //No device with that ID found
  72. return otto.FalseValue()
  73. }
  74. if dev.RequireConnect == true {
  75. //Build the auto info
  76. autoInfo := iot.AuthInfo{
  77. Username: username,
  78. Password: password,
  79. Token: token,
  80. }
  81. //Connect the device
  82. dev.Handler.Connect(dev, &autoInfo)
  83. }
  84. //Return true
  85. return otto.TrueValue()
  86. })
  87. //Get the status of the given device
  88. vm.Set("_iot_status", func(call otto.FunctionCall) otto.Value {
  89. //Get device ID from paratmer
  90. devID, err := call.Argument(0).ToString()
  91. if err != nil {
  92. return otto.FalseValue()
  93. }
  94. dev := g.Option.IotManager.GetDeviceByID(devID)
  95. if dev == nil {
  96. return otto.FalseValue()
  97. }
  98. //We have no idea what is the structure of the dev status.
  99. //Just leave it to the front end to handle :P
  100. devStatus, err := dev.Handler.Status(dev)
  101. if err != nil {
  102. log.Println("*AGI IoT* " + err.Error())
  103. return otto.FalseValue()
  104. }
  105. js, _ := json.Marshal(devStatus)
  106. results, _ := vm.ToValue(string(js))
  107. return results
  108. })
  109. vm.Set("_iot_exec", func(call otto.FunctionCall) otto.Value {
  110. //Get device ID from paratmer
  111. devID, err := call.Argument(0).ToString()
  112. if err != nil {
  113. return otto.FalseValue()
  114. }
  115. //Get endpoint name
  116. epname, err := call.Argument(1).ToString()
  117. if err != nil {
  118. return otto.FalseValue()
  119. }
  120. //Get payload if any
  121. payload, err := call.Argument(2).ToString()
  122. if err != nil {
  123. payload = ""
  124. }
  125. //Get device by id
  126. dev := g.Option.IotManager.GetDeviceByID(devID)
  127. if dev == nil {
  128. //Device not found
  129. log.Println("*AGI IoT* Given device ID do not match any IoT devices")
  130. return otto.FalseValue()
  131. }
  132. //Get the endpoint from name
  133. var targetEp *iot.Endpoint
  134. for _, ep := range dev.ControlEndpoints {
  135. if ep.Name == epname {
  136. //This is the target endpoint
  137. thisEp := ep
  138. targetEp = thisEp
  139. }
  140. }
  141. if targetEp == nil {
  142. //Endpoint not found
  143. log.Println("*AGI IoT* Failed to get endpoint by name in this device")
  144. return otto.FalseValue()
  145. }
  146. var results interface{}
  147. //Try to convert it into a string map
  148. if payload != "" {
  149. payloadMap := map[string]interface{}{}
  150. err = json.Unmarshal([]byte(payload), &payloadMap)
  151. if err != nil {
  152. log.Println("*AGI IoT* Failed to parse input payload: " + err.Error())
  153. return otto.FalseValue()
  154. }
  155. //Execute the request
  156. results, err = dev.Handler.Execute(dev, targetEp, payloadMap)
  157. } else {
  158. //Execute the request without payload
  159. results, err = dev.Handler.Execute(dev, targetEp, nil)
  160. }
  161. if err != nil {
  162. log.Println("*AGI IoT* Failed to execute request to device: " + err.Error())
  163. return otto.FalseValue()
  164. }
  165. js, _ := json.Marshal(results)
  166. reply, _ := vm.ToValue(string(js))
  167. return reply
  168. })
  169. //Disconnect a given iot device using the device UUID
  170. vm.Set("_iot_disconnect", func(call otto.FunctionCall) otto.Value {
  171. //Get device ID from paratmer
  172. devID, err := call.Argument(0).ToString()
  173. if err != nil {
  174. return otto.FalseValue()
  175. }
  176. dev := g.Option.IotManager.GetDeviceByID(devID)
  177. if dev == nil {
  178. return otto.FalseValue()
  179. }
  180. if dev.RequireConnect == true {
  181. err = dev.Handler.Disconnect(dev)
  182. if err != nil {
  183. return otto.FalseValue()
  184. }
  185. }
  186. return otto.TrueValue()
  187. })
  188. //Return the icon tag for this device
  189. vm.Set("_iot_iconTag", func(call otto.FunctionCall) otto.Value {
  190. //Get device ID from paratmer
  191. devID, err := call.Argument(0).ToString()
  192. if err != nil {
  193. return otto.FalseValue()
  194. }
  195. dev := g.Option.IotManager.GetDeviceByID(devID)
  196. if dev == nil {
  197. //device not found
  198. return otto.NullValue()
  199. }
  200. deviceIconTag := dev.Handler.Icon(dev)
  201. it, _ := vm.ToValue(deviceIconTag)
  202. return it
  203. })
  204. vm.Set("_iot_ready", func(call otto.FunctionCall) otto.Value {
  205. if g.Option.IotManager == nil {
  206. return otto.FalseValue()
  207. } else {
  208. return otto.TrueValue()
  209. }
  210. })
  211. //Wrap all the native code function into an imagelib class
  212. _, err := vm.Run(`
  213. var iot = {
  214. "scan": function(){
  215. var devList = _iot_scan();
  216. return JSON.parse(devList);
  217. },
  218. "list": function(){
  219. var devList = _iot_list();
  220. return JSON.parse(devList);
  221. },
  222. "status": function(devid){
  223. var devStatus = _iot_status(devid);
  224. return JSON.parse(devStatus);
  225. },
  226. "exec": function(devid, epname, payload){
  227. payload = payload || "";
  228. payload = JSON.stringify(payload);
  229. var resp = _iot_exec(devid, epname, payload);
  230. if (resp == false){
  231. return false;
  232. }else{
  233. return JSON.parse(resp);
  234. }
  235. }
  236. };
  237. iot.ready = _iot_ready;
  238. iot.connect = _iot_connect;
  239. iot.disconnect = _iot_disconnect;
  240. iot.iconTag = _iot_iconTag;
  241. `)
  242. if err != nil {
  243. log.Println("*AGI* IoT Functions Injection Error", err.Error())
  244. }
  245. }