| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 | package agiimport (	"encoding/json"	"log"	"github.com/robertkrimen/otto"	"imuslab.com/arozos/mod/iot"	user "imuslab.com/arozos/mod/user")/*	AGI IoT Control Protocols	This is a library for allowing AGI script to control / send commands to IoT devices	Use with caution and prepare to handle errors. IoT devices are not always online / connectabe.	Author: tobychui*/func (g *Gateway) IoTLibRegister() {	err := g.RegisterLib("iot", g.injectIoTFunctions)	if err != nil {		log.Fatal(err)	}}func (g *Gateway) injectIoTFunctions(vm *otto.Otto, u *user.User) {	//Scan and return the latest iot device list	vm.Set("_iot_scan", func(call otto.FunctionCall) otto.Value {		scannedDevices := g.Option.IotManager.ScanDevices()		js, _ := json.Marshal(scannedDevices)		devList, err := vm.ToValue(string(js))		if err != nil {			return otto.FalseValue()		}		return devList	})	//List the current scanned device list from cache	vm.Set("_iot_list", func(call otto.FunctionCall) otto.Value {		devices := g.Option.IotManager.GetCachedDeviceList()		js, _ := json.Marshal(devices)		devList, err := vm.ToValue(string(js))		if err != nil {			return otto.FalseValue()		}		return devList	})	//Conenct an iot device. Return true if the device is connected or the device do not require connection before command exec	vm.Set("_iot_connect", func(call otto.FunctionCall) otto.Value {		//Get device ID from paratmer		devID, err := call.Argument(0).ToString()		if err != nil {			return otto.FalseValue()		}		//Get the auth info from paramters		username, err := call.Argument(1).ToString()		if err != nil {			username = ""		}		password, err := call.Argument(2).ToString()		if err != nil {			password = ""		}		token, err := call.Argument(3).ToString()		if err != nil {			token = ""		}		//Get device by id		dev := g.Option.IotManager.GetDeviceByID(devID)		if dev == nil {			//No device with that ID found			return otto.FalseValue()		}		if dev.RequireConnect == true {			//Build the auto info			autoInfo := iot.AuthInfo{				Username: username,				Password: password,				Token:    token,			}			//Connect the device			dev.Handler.Connect(dev, &autoInfo)		}		//Return true		return otto.TrueValue()	})	//Get the status of the given device	vm.Set("_iot_status", func(call otto.FunctionCall) otto.Value {		//Get device ID from paratmer		devID, err := call.Argument(0).ToString()		if err != nil {			return otto.FalseValue()		}		dev := g.Option.IotManager.GetDeviceByID(devID)		if dev == nil {			return otto.FalseValue()		}		//We have no idea what is the structure of the dev status.		//Just leave it to the front end to handle :P		devStatus, err := dev.Handler.Status(dev)		if err != nil {			log.Println("*AGI IoT* " + err.Error())			return otto.FalseValue()		}		js, _ := json.Marshal(devStatus)		results, _ := vm.ToValue(string(js))		return results	})	vm.Set("_iot_exec", func(call otto.FunctionCall) otto.Value {		//Get device ID from paratmer		devID, err := call.Argument(0).ToString()		if err != nil {			return otto.FalseValue()		}		//Get endpoint name		epname, err := call.Argument(1).ToString()		if err != nil {			return otto.FalseValue()		}		//Get payload if any		payload, err := call.Argument(2).ToString()		if err != nil {			payload = ""		}		//Get device by id		dev := g.Option.IotManager.GetDeviceByID(devID)		if dev == nil {			//Device not found			log.Println("*AGI IoT* Given device ID do not match any IoT devices")			return otto.FalseValue()		}		//Get the endpoint from name		var targetEp *iot.Endpoint		for _, ep := range dev.ControlEndpoints {			if ep.Name == epname {				//This is the target endpoint				thisEp := ep				targetEp = thisEp			}		}		if targetEp == nil {			//Endpoint not found			log.Println("*AGI IoT* Failed to get endpoint by name in this device")			return otto.FalseValue()		}		var results interface{}		//Try to convert it into a string map		if payload != "" {			payloadMap := map[string]interface{}{}			err = json.Unmarshal([]byte(payload), &payloadMap)			if err != nil {				log.Println("*AGI IoT* Failed to parse input payload: " + err.Error())				return otto.FalseValue()			}			//Execute the request			results, err = dev.Handler.Execute(dev, targetEp, payloadMap)		} else {			//Execute the request without payload			results, err = dev.Handler.Execute(dev, targetEp, nil)		}		if err != nil {			log.Println("*AGI IoT* Failed to execute request to device: " + err.Error())			return otto.FalseValue()		}		js, _ := json.Marshal(results)		reply, _ := vm.ToValue(string(js))		return reply	})	//Disconnect a given iot device using the device UUID	vm.Set("_iot_disconnect", func(call otto.FunctionCall) otto.Value {		//Get device ID from paratmer		devID, err := call.Argument(0).ToString()		if err != nil {			return otto.FalseValue()		}		dev := g.Option.IotManager.GetDeviceByID(devID)		if dev == nil {			return otto.FalseValue()		}		if dev.RequireConnect == true {			err = dev.Handler.Disconnect(dev)			if err != nil {				return otto.FalseValue()			}		}		return otto.TrueValue()	})	//Return the icon tag for this device	vm.Set("_iot_iconTag", func(call otto.FunctionCall) otto.Value {		//Get device ID from paratmer		devID, err := call.Argument(0).ToString()		if err != nil {			return otto.FalseValue()		}		dev := g.Option.IotManager.GetDeviceByID(devID)		if dev == nil {			//device not found			return otto.NullValue()		}		deviceIconTag := dev.Handler.Icon(dev)		it, _ := vm.ToValue(deviceIconTag)		return it	})	vm.Set("_iot_ready", func(call otto.FunctionCall) otto.Value {		if g.Option.IotManager == nil {			return otto.FalseValue()		} else {			return otto.TrueValue()		}	})	//Wrap all the native code function into an imagelib class	_, err := vm.Run(`		var iot = {			"scan": function(){				var devList = _iot_scan();				return JSON.parse(devList);			},			"list": function(){				var devList = _iot_list();				return JSON.parse(devList);			},			"status": function(devid){				var devStatus = _iot_status(devid);				return JSON.parse(devStatus);			},			"exec": function(devid, epname, payload){				payload = payload || "";				payload = JSON.stringify(payload);				var resp = _iot_exec(devid, epname, payload);				if (resp == false){					return false;				}else{					return JSON.parse(resp);				}			}		};		iot.ready = _iot_ready;		iot.connect = _iot_connect;		iot.disconnect = _iot_disconnect;		iot.iconTag = _iot_iconTag;			`)	if err != nil {		log.Println("*AGI* IoT Functions Injection Error", err.Error())	}}
 |