123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package hds
- import (
- "errors"
- "log"
- "strconv"
- "strings"
- "sync"
- "time"
- "imuslab.com/arozos/mod/iot"
- )
- /*
- Home Dynamic System
- Author: tobychui
- This is a compaitbility module for those who are still using HDSv1 protocol
- If you are still using HDSv1, you should consider upgrading it to the latest
- version of HDS protocols.
- */
- type Handler struct {
- lastScanTime int64
- }
- //Create a new HDS Protocol Handler
- func NewProtocolHandler() *Handler {
- //Create a new MDNS Host
- return &Handler{}
- }
- //Start the HDSv1 scanner, which no startup process is required
- func (h *Handler) Start() error {
- log.Println("[IoT] Home Dynamic System (Legacy) Loaded")
- return nil
- }
- //Scan all the HDS devices in LAN using the legacy ip scanner methods
- func (h *Handler) Scan() ([]*iot.Device, error) {
- //Get the current local IP address
- ip := getLocalIP()
- if ip == "" {
- //Not connected to a network?
- return nil, errors.New("Unable to get ip address of host device")
- }
- //Only handle a small subset of ip ranges (Last 255 addfress)
- scanBase := ""
- valid := false
- if ip[:8] == "192.168." {
- tmp := strings.Split(ip, ".")
- tmp = tmp[:len(tmp)-1]
- scanBase = strings.Join(tmp, ".") + "." //Return 192.168.0.
- valid = true
- } else if ip[:4] == "172." {
- //Handle 172.16.x.x - 172.31.x.x
- tmp := strings.Split(ip, ".")
- val, err := strconv.Atoi(tmp[1])
- if err == nil {
- if val >= 16 && val <= 31 {
- //Private addr range
- valid = true
- scanBase = strings.Join(tmp, ".") + "." //Return 172.16.0.
- }
- }
- }
- //Check if the IP range is supported by HDS protocol
- if !valid {
- log.Println("[IoT] Home Dynamic Protocol requirement not satisfied. Skipping Scan")
- return nil, nil
- }
- results := []*iot.Device{}
- //Create a IP scanner
- var wg sync.WaitGroup
- for i := 1; i < 256; i++ {
- time.Sleep(300 * time.Microsecond)
- wg.Add(1)
- go func(wg *sync.WaitGroup) {
- defer wg.Done()
- targetIP := scanBase + strconv.Itoa(i)
- uuid, err := tryGetHDSUUID(targetIP)
- if err != nil {
- //Not an HDS device
- return
- }
- //This is an HDS device. Get its details
- devName, className, err := tryGetHDSInfo(targetIP)
- if err != nil {
- //Corrupted HDS device?
- return
- }
- //Get the device status
- deviceState := map[string]interface{}{}
- statusText, err := getHDSStatus(targetIP)
- if err != nil {
- //No status
- } else {
- deviceState["status"] = strings.TrimSpace(statusText)
- }
- //Create the hdsv1 endpoints (aka /on and /off)
- endpoints := []*iot.Endpoint{}
- endpoints = append(endpoints, &iot.Endpoint{
- RelPath: "on",
- Name: "ON",
- Desc: "Turn on the device",
- Type: "none",
- })
- endpoints = append(endpoints, &iot.Endpoint{
- RelPath: "off",
- Name: "OFF",
- Desc: "Turn off the device",
- Type: "none",
- })
- //Append the device to list
- results = append(results, &iot.Device{
- Name: devName,
- Port: 80, //HDS device use port 80 by default
- Model: className,
- Version: "1.0",
- Manufacturer: "Generic",
- DeviceUUID: uuid,
- IPAddr: targetIP,
- RequireAuth: false,
- RequireConnect: false,
- Status: deviceState,
- Handler: h,
- ControlEndpoints: endpoints,
- })
- log.Println("*HDS* Found device ", devName, " at ", targetIP, " with UUID ", uuid)
- }(&wg)
- }
- wg.Wait()
- return results, nil
- }
- //Home Dynamic system's devices no need to established conenction before executing anything
- func (h *Handler) Connect(device *iot.Device, authInfo *iot.AuthInfo) error {
- return nil
- }
- //Same rules also apply to disconnect
- func (h *Handler) Disconnect(device *iot.Device) error {
- return nil
- }
- //Get the icon filename of the device, it is always switch for hdsv1
- func (h *Handler) Icon(device *iot.Device) string {
- return "switch"
- }
- //Get the status of the device
- func (h *Handler) Execute(device *iot.Device, endpoint *iot.Endpoint, payload interface{}) (interface{}, error) {
- //GET request the target device endpoint
- resp, err := tryGet("http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/" + endpoint.RelPath)
- if err != nil {
- return map[string]interface{}{}, err
- }
- return resp, nil
- }
- //Get the status of the device
- func (h *Handler) Status(device *iot.Device) (map[string]interface{}, error) {
- resp, err := tryGet("http://" + device.IPAddr + "/status")
- if err != nil {
- return map[string]interface{}{}, err
- }
- //Convert the resp into map string itnerface
- result := map[string]interface{}{}
- result["status"] = resp
- return result, nil
- }
- //Return the specification of this protocol handler
- func (h *Handler) Stats() iot.Stats {
- return iot.Stats{
- Name: "Home Dynamic",
- Desc: "A basic IoT communication protocol for ESP8266 for ArOZ Online Beta",
- Version: "1.0",
- ProtocolVer: "1.0",
- Author: "tobychui",
- AuthorWebsite: "https://git.hkwtc.org/TC/HomeDynamic",
- AuthorEmail: "",
- ReleaseDate: 1576094199,
- }
- }
|