123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- package hdsv2
- import (
- "encoding/json"
- "errors"
- "io/ioutil"
- "log"
- "net/http"
- "strconv"
- "strings"
- "imuslab.com/arozos/mod/iot"
- "imuslab.com/arozos/mod/network/mdns"
- )
- /*
- Home Dynamic 2 Controller
- This is a module that handles HDSv2 protocol devices scannings
- */
- type Handler struct {
- scanner *mdns.MDNSHost
- lastScanTime int64
- }
- //Create a new HDSv2 Protocol Handler
- func NewProtocolHandler(scanner *mdns.MDNSHost) *Handler {
- //Create a new MDNS Host
- return &Handler{
- scanner,
- 0,
- }
- }
- func (h *Handler) Start() error {
- log.Println("*IoT* Home Dynamic v2 Loaded")
- return nil
- }
- //Scan the devices within the LAN
- func (h *Handler) Scan() ([]*iot.Device, error) {
- foundDevices := []*iot.Device{}
- hosts := h.scanner.Scan(3, "hds.arozos.com")
- for _, host := range hosts {
- thisDevice := iot.Device{
- Name: host.HostName,
- Port: host.Port,
- Model: host.Model,
- Version: host.BuildVersion + "-" + host.MinorVersion,
- Manufacturer: host.Vendor,
- DeviceUUID: host.UUID,
- IPAddr: host.IPv4[0].String(),
- RequireAuth: false,
- RequireConnect: false,
- Status: map[string]interface{}{},
- Handler: h,
- }
- //Try to get the device status
- status, err := getStatusForDevice(&thisDevice)
- if err != nil {
- //This might be not a valid HDSv2 device. Skip this
- log.Println("*HDSv2* Get status failed for device: ", host.HostName, err.Error())
- continue
- }
- thisDevice.Status = status
- //Get the device content endpoints
- eps, err := getEndpoints(&thisDevice)
- if err != nil {
- //This might be not a valid HDSv2 device. Skip this
- log.Println("*HDSv2* Get endpoints failed for device: ", host.HostName, err.Error())
- continue
- }
- thisDevice.ControlEndpoints = eps
- //Push this host into found device list
- foundDevices = append(foundDevices, &thisDevice)
- }
- return foundDevices, 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 status of the device
- func (h *Handler) Status(device *iot.Device) (map[string]interface{}, error) {
- return getStatusForDevice(device)
- }
- //Get the status of the device
- func (h *Handler) Execute(device *iot.Device, endpoint *iot.Endpoint, payload interface{}) (interface{}, error) {
- var result interface{}
- return result, nil
- }
- func (h *Handler) Stats() iot.Stats {
- return iot.Stats{
- Name: "Home Dynamic v2",
- Desc: "A basic IoT communication protocol for ESP8266 made by Makers",
- Version: "2.0",
- ProtocolVer: "2.0",
- Author: "tobychui",
- AuthorWebsite: "http://arozos.com",
- AuthorEmail: "[email protected]",
- ReleaseDate: 1614524498,
- }
- }
- //Get endpoint of the given device object
- func getEndpoints(device *iot.Device) ([]*iot.Endpoint, error) {
- //Parse the URL of the endpoint apis location (eps)
- requestURL := "http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/eps"
- resp, err := http.Get(requestURL)
- if err != nil {
- return nil, err
- }
- //Get the body content
- content, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
- //Convert the results to Endpoints
- endpoints := []iot.Endpoint{}
- err = json.Unmarshal(content, &endpoints)
- if err != nil {
- return nil, err
- }
- //Convert the structure to array pointers
- results := []*iot.Endpoint{}
- for _, ep := range endpoints {
- thisEp := ep
- results = append(results, &thisEp)
- }
- return results, nil
- }
- //Get status given the device object.
- func getStatusForDevice(device *iot.Device) (map[string]interface{}, error) {
- //Parse the URL for its status api endpoint
- requestURL := "http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/status"
- resp, err := http.Get(requestURL)
- if err != nil {
- return map[string]interface{}{}, err
- }
- //Get the body content
- content, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return map[string]interface{}{}, err
- }
- //Check if the resp is json
- if !isJSON(strings.TrimSpace(string(content))) {
- return map[string]interface{}{}, errors.New("Invalid HDSv2 protocol")
- }
- //Ok. Parse it
- status := map[string]interface{}{}
- err = json.Unmarshal(content, &status)
- if err != nil {
- return map[string]interface{}{}, err
- }
- return status, nil
- }
|