hdsv2.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package hdsv2
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io/ioutil"
  6. "log"
  7. "net/http"
  8. "strconv"
  9. "strings"
  10. "imuslab.com/arozos/mod/iot"
  11. "imuslab.com/arozos/mod/network/mdns"
  12. )
  13. /*
  14. Home Dynamic 2 Controller
  15. This is a module that handles HDSv2 protocol devices scannings
  16. */
  17. type Handler struct {
  18. scanner *mdns.MDNSHost
  19. lastScanTime int64
  20. }
  21. //Create a new HDSv2 Protocol Handler
  22. func NewProtocolHandler(scanner *mdns.MDNSHost) *Handler {
  23. //Create a new MDNS Host
  24. return &Handler{
  25. scanner,
  26. 0,
  27. }
  28. }
  29. func (h *Handler) Start() error {
  30. log.Println("*IoT* Home Dynamic v2 Loaded")
  31. return nil
  32. }
  33. //Scan the devices within the LAN
  34. func (h *Handler) Scan() ([]*iot.Device, error) {
  35. foundDevices := []*iot.Device{}
  36. hosts := h.scanner.Scan(3, "hds.arozos.com")
  37. for _, host := range hosts {
  38. thisDevice := iot.Device{
  39. Name: host.HostName,
  40. Port: host.Port,
  41. Model: host.Model,
  42. Version: host.BuildVersion + "-" + host.MinorVersion,
  43. Manufacturer: host.Vendor,
  44. DeviceUUID: host.UUID,
  45. IPAddr: host.IPv4[0].String(),
  46. RequireAuth: false,
  47. RequireConnect: false,
  48. Status: map[string]interface{}{},
  49. Handler: h,
  50. }
  51. //Try to get the device status
  52. status, err := getStatusForDevice(&thisDevice)
  53. if err != nil {
  54. //This might be not a valid HDSv2 device. Skip this
  55. log.Println("*HDSv2* Get status failed for device: ", host.HostName, err.Error())
  56. continue
  57. }
  58. thisDevice.Status = status
  59. //Get the device content endpoints
  60. eps, err := getEndpoints(&thisDevice)
  61. if err != nil {
  62. //This might be not a valid HDSv2 device. Skip this
  63. log.Println("*HDSv2* Get endpoints failed for device: ", host.HostName, err.Error())
  64. continue
  65. }
  66. thisDevice.ControlEndpoints = eps
  67. //Push this host into found device list
  68. foundDevices = append(foundDevices, &thisDevice)
  69. }
  70. return foundDevices, nil
  71. }
  72. //Home Dynamic system's devices no need to established conenction before executing anything
  73. func (h *Handler) Connect(device *iot.Device, authInfo *iot.AuthInfo) error {
  74. return nil
  75. }
  76. //Same rules also apply to disconnect
  77. func (h *Handler) Disconnect(device *iot.Device) error {
  78. return nil
  79. }
  80. //Get the status of the device
  81. func (h *Handler) Status(device *iot.Device) (map[string]interface{}, error) {
  82. return getStatusForDevice(device)
  83. }
  84. //Get the icon filename of the device
  85. func (h *Handler) Icon(device *iot.Device) string {
  86. devModel := device.Model
  87. if devModel == "Switch" {
  88. return "switch"
  89. } else if devModel == "Test Unit" {
  90. return "test"
  91. } else {
  92. return "unknown"
  93. }
  94. }
  95. //Get the status of the device
  96. func (h *Handler) Execute(device *iot.Device, endpoint *iot.Endpoint, payload interface{}) (interface{}, error) {
  97. var result interface{}
  98. targetURL := "http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/" + endpoint.RelPath
  99. //Check if there are payload for this request
  100. if payload == nil {
  101. //No payload. Just call it
  102. } else {
  103. //Payload exists. Append it to the end with value=?
  104. targetURL += "?value=" + payload.(string)
  105. }
  106. result, err := tryGet(targetURL)
  107. if err != nil {
  108. return nil, err
  109. }
  110. return result, nil
  111. }
  112. func (h *Handler) Stats() iot.Stats {
  113. return iot.Stats{
  114. Name: "Home Dynamic v2",
  115. Desc: "A basic IoT communication protocol for ESP8266 made by Makers",
  116. Version: "2.0",
  117. ProtocolVer: "2.0",
  118. Author: "tobychui",
  119. AuthorWebsite: "http://arozos.com",
  120. AuthorEmail: "[email protected]",
  121. ReleaseDate: 1614524498,
  122. }
  123. }
  124. //Get endpoint of the given device object
  125. func getEndpoints(device *iot.Device) ([]*iot.Endpoint, error) {
  126. //Parse the URL of the endpoint apis location (eps)
  127. requestURL := "http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/eps"
  128. resp, err := http.Get(requestURL)
  129. if err != nil {
  130. return nil, err
  131. }
  132. //Get the body content
  133. content, err := ioutil.ReadAll(resp.Body)
  134. if err != nil {
  135. return nil, err
  136. }
  137. //Convert the results to Endpoints
  138. endpoints := []iot.Endpoint{}
  139. err = json.Unmarshal(content, &endpoints)
  140. if err != nil {
  141. return nil, err
  142. }
  143. //Convert the structure to array pointers
  144. results := []*iot.Endpoint{}
  145. for _, ep := range endpoints {
  146. thisEp := ep
  147. results = append(results, &thisEp)
  148. }
  149. return results, nil
  150. }
  151. //Get status given the device object.
  152. func getStatusForDevice(device *iot.Device) (map[string]interface{}, error) {
  153. //Parse the URL for its status api endpoint
  154. requestURL := "http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/status"
  155. resp, err := http.Get(requestURL)
  156. if err != nil {
  157. return map[string]interface{}{}, err
  158. }
  159. //Get the body content
  160. content, err := ioutil.ReadAll(resp.Body)
  161. if err != nil {
  162. return map[string]interface{}{}, err
  163. }
  164. //Check if the resp is json
  165. if !isJSON(strings.TrimSpace(string(content))) {
  166. return map[string]interface{}{}, errors.New("Invalid HDSv2 protocol")
  167. }
  168. //Ok. Parse it
  169. status := map[string]interface{}{}
  170. err = json.Unmarshal(content, &status)
  171. if err != nil {
  172. return map[string]interface{}{}, err
  173. }
  174. return status, nil
  175. }