hds.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package hds
  2. import (
  3. "errors"
  4. "log"
  5. "strconv"
  6. "strings"
  7. "sync"
  8. "time"
  9. "imuslab.com/arozos/mod/iot"
  10. )
  11. /*
  12. Home Dynamic System
  13. Author: tobychui
  14. This is a compaitbility module for those who are still using HDSv1 protocol
  15. If you are still using HDSv1, you should consider upgrading it to the latest
  16. version of HDS protocols.
  17. */
  18. type Handler struct {
  19. lastScanTime int64
  20. }
  21. //Create a new HDS Protocol Handler
  22. func NewProtocolHandler() *Handler {
  23. //Create a new MDNS Host
  24. return &Handler{}
  25. }
  26. //Start the HDSv1 scanner, which no startup process is required
  27. func (h *Handler) Start() error {
  28. log.Println("*IoT* Home Dynamic System (Legacy) Loaded")
  29. return nil
  30. }
  31. //Scan all the HDS devices in LAN using the legacy ip scanner methods
  32. func (h *Handler) Scan() ([]*iot.Device, error) {
  33. //Get the current local IP address
  34. ip := getLocalIP()
  35. if ip == "" {
  36. //Not connected to a network?
  37. return nil, errors.New("Unable to get ip address of host device")
  38. }
  39. //Only handle a small subset of ip ranges (Last 255 addfress)
  40. scanBase := ""
  41. valid := false
  42. if ip[:8] == "192.168." {
  43. tmp := strings.Split(ip, ".")
  44. tmp = tmp[:len(tmp)-1]
  45. scanBase = strings.Join(tmp, ".") + "." //Return 192.168.0.
  46. valid = true
  47. } else if ip[:4] == "172." {
  48. //Handle 172.16.x.x - 172.31.x.x
  49. tmp := strings.Split(ip, ".")
  50. val, err := strconv.Atoi(tmp[1])
  51. if err == nil {
  52. if val >= 16 && val <= 31 {
  53. //Private addr range
  54. valid = true
  55. scanBase = strings.Join(tmp, ".") + "." //Return 172.16.0.
  56. }
  57. }
  58. }
  59. //Check if the IP range is supported by HDS protocol
  60. if !valid {
  61. log.Println("*IoT* Home Dynamic Protocol requirement not satisfied. Skipping Scan")
  62. return nil, nil
  63. }
  64. results := []*iot.Device{}
  65. //Create a IP scanner
  66. var wg sync.WaitGroup
  67. for i := 1; i < 256; i++ {
  68. time.Sleep(300 * time.Microsecond)
  69. wg.Add(1)
  70. go func(wg *sync.WaitGroup) {
  71. defer wg.Done()
  72. targetIP := scanBase + strconv.Itoa(i)
  73. uuid, err := tryGetHDSUUID(targetIP)
  74. if err != nil {
  75. //Not an HDS device
  76. return
  77. }
  78. //This is an HDS device. Get its details
  79. devName, className, err := tryGetHDSInfo(targetIP)
  80. if err != nil {
  81. //Corrupted HDS device?
  82. return
  83. }
  84. //Get the device status
  85. deviceState := map[string]interface{}{}
  86. statusText, err := getHDSStatus(targetIP)
  87. if err != nil {
  88. //No status
  89. } else {
  90. deviceState["status"] = strings.TrimSpace(statusText)
  91. }
  92. //Create the hdsv1 endpoints (aka /on and /off)
  93. endpoints := []*iot.Endpoint{}
  94. endpoints = append(endpoints, &iot.Endpoint{
  95. RelPath: "on",
  96. Name: "ON",
  97. Desc: "Turn on the device",
  98. Type: "none",
  99. })
  100. endpoints = append(endpoints, &iot.Endpoint{
  101. RelPath: "off",
  102. Name: "OFF",
  103. Desc: "Turn off the device",
  104. Type: "none",
  105. })
  106. //Append the device to list
  107. results = append(results, &iot.Device{
  108. Name: devName,
  109. Port: 80, //HDS device use port 80 by default
  110. Model: className,
  111. Version: "1.0",
  112. Manufacturer: "Generic",
  113. DeviceUUID: uuid,
  114. IPAddr: targetIP,
  115. RequireAuth: false,
  116. RequireConnect: false,
  117. Status: deviceState,
  118. Handler: h,
  119. ControlEndpoints: endpoints,
  120. })
  121. log.Println("*HDS* Found device ", devName, " at ", targetIP, " with UUID ", uuid)
  122. }(&wg)
  123. }
  124. wg.Wait()
  125. return results, nil
  126. }
  127. //Home Dynamic system's devices no need to established conenction before executing anything
  128. func (h *Handler) Connect(device *iot.Device, authInfo *iot.AuthInfo) error {
  129. return nil
  130. }
  131. //Same rules also apply to disconnect
  132. func (h *Handler) Disconnect(device *iot.Device) error {
  133. return nil
  134. }
  135. //Get the icon filename of the device, it is always switch for hdsv1
  136. func (h *Handler) Icon(device *iot.Device) string {
  137. return "switch"
  138. }
  139. //Get the status of the device
  140. func (h *Handler) Execute(device *iot.Device, endpoint *iot.Endpoint, payload interface{}) (interface{}, error) {
  141. //GET request the target device endpoint
  142. resp, err := tryGet("http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/" + endpoint.RelPath)
  143. if err != nil {
  144. return map[string]interface{}{}, err
  145. }
  146. return resp, nil
  147. }
  148. //Get the status of the device
  149. func (h *Handler) Status(device *iot.Device) (map[string]interface{}, error) {
  150. resp, err := tryGet("http://" + device.IPAddr + "/status")
  151. if err != nil {
  152. return map[string]interface{}{}, err
  153. }
  154. //Convert the resp into map string itnerface
  155. result := map[string]interface{}{}
  156. result["status"] = resp
  157. return result, nil
  158. }
  159. //Return the specification of this protocol handler
  160. func (h *Handler) Stats() iot.Stats {
  161. return iot.Stats{
  162. Name: "Home Dynamic",
  163. Desc: "A basic IoT communication protocol for ESP8266 for ArOZ Online Beta",
  164. Version: "1.0",
  165. ProtocolVer: "1.0",
  166. Author: "tobychui",
  167. AuthorWebsite: "https://git.hkwtc.org/TC/HomeDynamic",
  168. AuthorEmail: "",
  169. ReleaseDate: 1576094199,
  170. }
  171. }