AY %!s(int64=4) %!d(string=hai) anos
pai
achega
c266a0695c

+ 3 - 3
go.mod

@@ -5,6 +5,7 @@ go 1.13
 require (
 	github.com/andybalholm/brotli v1.0.0 // indirect
 	github.com/boltdb/bolt v1.3.1
+	github.com/brutella/hc v1.2.4
 	github.com/dhowden/tag v0.0.0-20200828214007-46e57f75dbfc
 	github.com/disintegration/imaging v1.6.2
 	github.com/fclairamb/ftpserverlib v0.8.0
@@ -38,9 +39,8 @@ require (
 	github.com/valyala/fasttemplate v1.1.0
 	gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 // indirect
 	gitlab.com/NebulousLabs/go-upnp v0.0.0-20181011194642-3a71999ed0d3
-	golang.org/x/net v0.0.0-20200301022130-244492dfa37a
-	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
-	golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect
+	golang.org/x/net v0.0.0-20210119194325-5f4716e94777
+	golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
 	golang.org/x/text v0.3.3 // indirect
 	gopkg.in/sourcemap.v1 v1.0.5 // indirect
 )

+ 22 - 0
go.sum

@@ -36,6 +36,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
 github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
 github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
 github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/brutella/dnssd v1.2.0 h1:bgrSycmZ2+u4BoJxRf1BzSlnViSAfeXWVdujqjLA004=
+github.com/brutella/dnssd v1.2.0/go.mod h1:FpJqlQ8+XU6w1vbnG1zJiQPTRE5fvQIRdrcBojMVuuQ=
+github.com/brutella/hc v1.2.4 h1:dQjLi4bjUbKG4436N7WXH6W7iHQgfnCceE9DxyOuSnA=
+github.com/brutella/hc v1.2.4/go.mod h1:TPPdombm3gA/2fsSON6ct2km7z7Vi8lQNqE+fzuDHQM=
 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
 github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
@@ -232,6 +236,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
 github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAzig=
 github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.1/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
 github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
 github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
@@ -365,6 +371,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/tadglines/go-pkgs v0.0.0-20140924210655-1f86682992f1 h1:ms/IQpkxq+t7hWpgKqCE5KjAUQWC24mqBrnL566SWgE=
+github.com/tadglines/go-pkgs v0.0.0-20140924210655-1f86682992f1/go.mod h1:roo6cZ/uqpwKMuvPG0YmzI5+AmUiMWfjCBZpGXqbTxE=
 github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
 github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -382,6 +390,8 @@ github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70
 github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
 github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
+github.com/xiam/to v0.0.0-20191116183551-8328998fc0ed h1:Gjnw8buhv4V8qXaHtAWPnKXNpCNx62heQpjO8lOY0/M=
+github.com/xiam/to v0.0.0-20191116183551-8328998fc0ed/go.mod h1:cqbG7phSzrbdg3aj+Kn63bpVruzwDZi58CpxlZkjwzw=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs=
 gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40/go.mod h1:rOnSnoRyxMI3fe/7KIbVcsHRGxe30OONv8dEgo+vCfA=
@@ -410,6 +420,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
 golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
@@ -442,6 +454,8 @@ golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCT
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -452,6 +466,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -468,10 +484,16 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=

+ 4 - 1
iot.go

@@ -6,6 +6,7 @@ import (
 	"imuslab.com/arozos/mod/iot"
 	"imuslab.com/arozos/mod/iot/hds"
 	"imuslab.com/arozos/mod/iot/hdsv2"
+	//"imuslab.com/arozos/mod/iot/homekit"
 	module "imuslab.com/arozos/mod/modules"
 	prout "imuslab.com/arozos/mod/prouter"
 )
@@ -87,7 +88,9 @@ func IoTHubInit() {
 		iotManager.RegisterHandler(hdsv2Handler)
 
 		//Add more here if needed
-
+		//Apple(R) Homekit
+		//homekitHandler := homekit.NewProtocolHandler(MDNS)
+		//iotManager.RegisterHandler(homekitHandler)
 	}
 
 }

+ 12 - 0
mod/disk/smart/common.go

@@ -11,6 +11,7 @@ import (
 	"bufio"
 	"io/ioutil"
 	"time"
+	"os/exec"
 )
 
 /*
@@ -193,4 +194,15 @@ func ReflectUserIP(w http.ResponseWriter, r *http.Request) {
     }
     w.Write([]byte(IPAddress))
     return;
+}
+
+func execCommand(executable string, args ...string) string {
+	shell := exec.Command(executable, args...) // Run command
+	output, err := shell.CombinedOutput()                     // Response from cmdline
+	if err != nil {                                             // If done w/ errors then
+		log.Println(err)
+		return ""
+	}
+
+	return string(output)
 }

+ 52 - 99
mod/disk/smart/smart.go

@@ -14,7 +14,7 @@ import (
 	"encoding/json"
 	"log"
 	"net/http"
-	"os/exec"
+	//"os/exec"
 	"runtime"
 	"errors"
 	"time"
@@ -29,128 +29,81 @@ type SMART struct {
 type SMARTListener struct{
 	SystemSmartExecutable string
 	LastScanTime int64
-	SMARTInformation []*SMART
+	SMARTInformation []**SMART
 	ReadingInProgress bool
 }
 
 // DiskSmartInit Desktop script initiation
 func NewSmartListener() (*SMARTListener, error){
-	var SystemSmartExecutable string = ""
+	SystemSmartExecutable := getBinary()
 
 	log.Println("Starting SMART mointoring")
-	if !(fileExists("system/disk/smart/win/smartctl.exe") || fileExists("system/disk/smart/linux/smartctl_arm") || fileExists("system/disk/smart/linux/smartctl_arm64") || fileExists("system/disk/smart/linux/smartctl_i386")) {
-		return &SMARTListener{}, errors.New("Smartctl.exe not found")
+
+	if (SystemSmartExecutable == "") {
+		return &SMARTListener{}, errors.New("Not supported platform")
+	}
+
+	if !(fileExists(SystemSmartExecutable)) {
+		return &SMARTListener{}, errors.New("Smartctl not found")
+	}
+
+	devicesList := scanAvailableDevices(SystemSmartExecutable)
+	devicesSMART := readSMARTDevices(SystemSmartExecutable,devicesList)
+
+	return &SMARTListener{
+		SystemSmartExecutable: SystemSmartExecutable,
+		LastScanTime: time.Now().Unix(),
+		SMARTInformation: devicesSMART,
+	},nil
+}
+
+func scanAvailableDevices(SystemSmartExecutable string) *DevicesList{
+	rawInfo := execCommand(SystemSmartExecutable, "--scan", "--json=c")
+	Devices := new(DevicesList)
+	json.Unmarshal([]byte(rawInfo), &Devices)
+	return Devices
+}
+
+func readSMARTDevices(SystemSmartExecutable string, devicesList *DevicesList) []**SMART{
+	SMARTInfo := []**SMART{}
+	for _, device := range devicesList.Devices {
+		rawInfo := execCommand(SystemSmartExecutable, "-i", device.Name, "-a", "--json=c")
+		deviceSMART := new(SMART)
+		json.Unmarshal([]byte(rawInfo), &deviceSMART)
+		SMARTInfo = append(SMARTInfo, &deviceSMART)
 	}
+	return SMARTInfo
+}
+
+func getBinary() string{
 	if runtime.GOOS == "windows" {
-		SystemSmartExecutable = "./system/disk/smart/win/smartctl.exe"
+		return "./system/disk/smart/win/smartctl.exe"
 	} else if runtime.GOOS == "linux" {
 		if runtime.GOARCH == "arm" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_armv6"
+			return "./system/disk/smart/linux/smartctl_armv6"
 		}
 		if runtime.GOARCH == "arm64" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_armv6"
+			return "./system/disk/smart/linux/smartctl_armv6"
 		}
 		if runtime.GOARCH == "386" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_i386"
+			return "./system/disk/smart/linux/smartctl_i386"
 		}
 		if runtime.GOARCH == "amd64" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_i386"
-		}
-	} else {
-		return &SMARTListener{}, errors.New("Not supported platform")
-	}
-	return &SMARTListener{
-		SystemSmartExecutable: SystemSmartExecutable,
-		LastScanTime: 0,
-		SMARTInformation: []*SMART{},
-		ReadingInProgress: false,
-	},nil
-}
-
-// ReadSMART xxx
-func (s *SMARTListener)ReadSMART() []*SMART {
-	if time.Now().Unix()-s.LastScanTime > 30 {
-		if (s.ReadingInProgress == false){
-			//Set reading flag to true
-			s.ReadingInProgress = true;
-			s.SMARTInformation = []*SMART{}
-			//Scan disk
-			cmd := exec.Command(s.SystemSmartExecutable, "--scan", "--json=c")
-			out, _ := cmd.CombinedOutput()
-			Devices := new(DevicesList)
-			DevicesOutput := string(out)
-			json.Unmarshal([]byte(DevicesOutput), &Devices)
-			for _, element := range Devices.Devices {
-				//Load SMART for each drive
-				cmd := exec.Command(s.SystemSmartExecutable, "-i", element.Name, "-a", "--json=c")
-				out, err := cmd.CombinedOutput()
-				if err != nil{
-					//log.Println(string(out), err);
-				}
-				InvSMARTInformation := new(DeviceSMART)
-				SMARTOutput := string(out)
-				json.Unmarshal([]byte(SMARTOutput), &InvSMARTInformation)
-				if len(InvSMARTInformation.Smartctl.Messages) > 0 {
-					if InvSMARTInformation.Smartctl.Messages[0].Severity == "error" {
-						log.Println("[SMART Mointoring] Disk " + element.Name + " cannot be readed")
-					} else {
-						//putting everything into that struct array
-						n := SMART{Port: element.Name, DriveSmart: InvSMARTInformation}
-						s.SMARTInformation = append(s.SMARTInformation, &n)
-					}
-				} else {
-					//putting everything into that struct array
-					n := SMART{Port: element.Name, DriveSmart: InvSMARTInformation}
-					s.SMARTInformation = append(s.SMARTInformation, &n)
-				}
-
-			}
-			s.LastScanTime = time.Now().Unix()
-
-			//Set reading flag to false
-			s.ReadingInProgress = false;
+			return "./system/disk/smart/linux/smartctl_i386"
 		}
 	}
-	return s.SMARTInformation
+	return ""
 }
 
-func (s *SMARTListener)GetSMART(w http.ResponseWriter, r *http.Request) {
-	jsonText, _ := json.Marshal(s.ReadSMART())
-	sendJSONResponse(w, string(jsonText))
-}
 
 func (s *SMARTListener)CheckDiskTable(w http.ResponseWriter, r *http.Request) {
-	disks, ok := r.URL.Query()["disk"]
-	if !ok || len(disks[0]) < 1 {
-		log.Println("Parameter DISK not found.")
-		return
-	}
-
-	DiskStatus := new(DeviceSMART)
-	for _, info := range s.ReadSMART() {
-		if info.Port == disks[0] {
-			DiskStatus = info.DriveSmart
-		}
-	}
-	JSONStr, _ := json.Marshal(DiskStatus.AtaSmartAttributes.Table)
-	//send!
-	sendJSONResponse(w, string(JSONStr))
+	sendJSONResponse(w, string(""))
 }
 
 func (s *SMARTListener)CheckDiskTestStatus(w http.ResponseWriter, r *http.Request) {
-	disks, ok := r.URL.Query()["disk"]
-	if !ok || len(disks[0]) < 1 {
-		log.Println("Parameter DISK not found.")
-		return
-	}
-
-	DiskTestStatus := new(DeviceSMART)
-	for _, info := range s.ReadSMART() {
-		if info.Port == disks[0] {
-			DiskTestStatus = info.DriveSmart
-		}
-	}
-	JSONStr, _ := json.Marshal(DiskTestStatus.AtaSmartData.SelfTest.Status)
-	//send!
-	sendJSONResponse(w, string(JSONStr))
+	sendJSONResponse(w, string(""))
 }
+
+func (s *SMARTListener)GetSMART(w http.ResponseWriter, r *http.Request) {
+	sendJSONResponse(w, string(""))
+}

+ 196 - 0
mod/disk/smart_1/common.disabled

@@ -0,0 +1,196 @@
+package smart
+
+import (
+	"os"
+    "log"
+	"net/http"
+	"strconv"
+	"strings"
+	"errors"
+	"encoding/base64"
+	"bufio"
+	"io/ioutil"
+	"time"
+)
+
+/*
+	SYSTEM COMMON FUNCTIONS
+
+	This is a system function that put those we usually use function but not belongs to
+	any module / system.
+
+	E.g. fileExists / IsDir etc
+
+*/
+
+/*
+	Basic Response Functions
+
+	Send response with ease
+*/
+//Send text response with given w and message as string
+func sendTextResponse(w http.ResponseWriter, msg string) {
+	w.Write([]byte(msg))
+}
+
+//Send JSON response, with an extra json header
+func sendJSONResponse(w http.ResponseWriter, json string) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte(json))
+}
+
+func sendErrorResponse(w http.ResponseWriter, errMsg string) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte("{\"error\":\"" + errMsg + "\"}"))
+}
+
+func sendOK(w http.ResponseWriter) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte("\"OK\""))
+}
+/*
+	The paramter move function (mv)
+
+	You can find similar things in the PHP version of ArOZ Online Beta. You need to pass in
+	r (HTTP Request Object)
+	getParamter (string, aka $_GET['This string])
+
+	Will return
+	Paramter string (if any)
+	Error (if error)
+
+*/
+func mv(r *http.Request, getParamter string, postMode bool) (string, error) {
+	if postMode == false {
+		//Access the paramter via GET
+		keys, ok := r.URL.Query()[getParamter]
+
+		if !ok || len(keys[0]) < 1 {
+			//log.Println("Url Param " + getParamter +" is missing")
+			return "", errors.New("GET paramter " + getParamter + " not found or it is empty")
+		}
+
+		// Query()["key"] will return an array of items,
+		// we only want the single item.
+		key := keys[0]
+		return string(key), nil
+	} else {
+		//Access the parameter via POST
+		r.ParseForm()
+		x := r.Form.Get(getParamter)
+		if len(x) == 0 || x == "" {
+			return "", errors.New("POST paramter " + getParamter + " not found or it is empty")
+		}
+		return string(x), nil
+	}
+
+}
+
+func stringInSlice(a string, list []string) bool {
+    for _, b := range list {
+        if b == a {
+            return true
+        }
+    }
+    return false
+}
+
+
+func fileExists(filename string) bool {
+    _, err := os.Stat(filename)
+    if os.IsNotExist(err) {
+        return false
+    }
+    return true
+}
+
+
+func IsDir(path string) bool{
+	if (fileExists(path) == false){
+		return false
+	}
+	fi, err := os.Stat(path)
+    if err != nil {
+        log.Fatal(err)
+        return false
+    }
+    switch mode := fi.Mode(); {
+    case mode.IsDir():
+        return true
+    case mode.IsRegular():
+        return false
+	}
+	return false
+}
+
+func inArray(arr []string, str string) bool {
+	for _, a := range arr {
+	   if a == str {
+		  return true
+	   }
+	}
+	return false
+ }
+
+ func timeToString(targetTime time.Time) string{
+	 return targetTime.Format("2006-01-02 15:04:05")
+ }
+
+ func IntToString(number int) string{
+	return strconv.Itoa(number)
+ }
+
+ func StringToInt(number string) (int, error){
+	return strconv.Atoi(number)
+ }
+
+ func StringToInt64(number string) (int64, error){
+	i, err := strconv.ParseInt(number, 10, 64)
+	if err != nil {
+		return -1, err
+	}
+	return i, nil
+ }
+
+ func Int64ToString(number int64) string{
+	convedNumber:=strconv.FormatInt(number,10)
+	return convedNumber
+ }
+
+ func GetUnixTime() int64{
+	return time.Now().Unix()
+ }
+
+ func LoadImageAsBase64(filepath string) (string, error){
+	if !fileExists(filepath){
+		return "", errors.New("File not exists")
+	}
+	f, _ := os.Open(filepath)
+    reader := bufio.NewReader(f)
+    content, _ := ioutil.ReadAll(reader)
+	encoded := base64.StdEncoding.EncodeToString(content)
+	return string(encoded), nil
+ }
+
+ //Get the IP address of the current authentication user
+func ReflectUserIP(w http.ResponseWriter, r *http.Request) {
+    requestPort,_ :=  mv(r, "port", false)
+    showPort := false;
+    if (requestPort == "true"){
+        //Show port as well
+        showPort = true;
+    }
+    IPAddress := r.Header.Get("X-Real-Ip")
+    if IPAddress == "" {
+        IPAddress = r.Header.Get("X-Forwarded-For")
+    }
+    if IPAddress == "" {
+        IPAddress = r.RemoteAddr
+    }
+    if (!showPort){
+        IPAddress = IPAddress[:strings.LastIndex(IPAddress, ":")]
+
+    }
+    w.Write([]byte(IPAddress))
+    return;
+}

+ 156 - 0
mod/disk/smart_1/smart.go_disabled

@@ -0,0 +1,156 @@
+package smart
+
+/*
+	DISK SMART Service Listener
+	Original author: alanyeung
+	Rewritten by tobychui in Oct 2020 for system arch upgrade
+
+	This module is not the core part of aroz online system.
+	If you want to remove disk smart handler (e.g. running in VM?)
+	remove the corrisponding code in disk.go
+*/
+
+import (
+	"encoding/json"
+	"log"
+	"net/http"
+	"os/exec"
+	"runtime"
+	"errors"
+	"time"
+)
+
+// SMART was used for storing all Devices data
+type SMART struct {
+	Port       string       `json:"Port"`
+	DriveSmart *DeviceSMART `json:"SMART"`
+}
+
+type SMARTListener struct{
+	SystemSmartExecutable string
+	LastScanTime int64
+	SMARTInformation []*SMART
+	ReadingInProgress bool
+}
+
+// DiskSmartInit Desktop script initiation
+func NewSmartListener() (*SMARTListener, error){
+	var SystemSmartExecutable string = ""
+
+	log.Println("Starting SMART mointoring")
+	if !(fileExists("system/disk/smart/win/smartctl.exe") || fileExists("system/disk/smart/linux/smartctl_arm") || fileExists("system/disk/smart/linux/smartctl_arm64") || fileExists("system/disk/smart/linux/smartctl_i386")) {
+		return &SMARTListener{}, errors.New("Smartctl.exe not found")
+	}
+	if runtime.GOOS == "windows" {
+		SystemSmartExecutable = "./system/disk/smart/win/smartctl.exe"
+	} else if runtime.GOOS == "linux" {
+		if runtime.GOARCH == "arm" {
+			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_armv6"
+		}
+		if runtime.GOARCH == "arm64" {
+			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_armv6"
+		}
+		if runtime.GOARCH == "386" {
+			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_i386"
+		}
+		if runtime.GOARCH == "amd64" {
+			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_i386"
+		}
+	} else {
+		return &SMARTListener{}, errors.New("Not supported platform")
+	}
+	return &SMARTListener{
+		SystemSmartExecutable: SystemSmartExecutable,
+		LastScanTime: 0,
+		SMARTInformation: []*SMART{},
+		ReadingInProgress: false,
+	},nil
+}
+
+// ReadSMART xxx
+func (s *SMARTListener)ReadSMART() []*SMART {
+	if time.Now().Unix()-s.LastScanTime > 30 {
+		if (s.ReadingInProgress == false){
+			//Set reading flag to true
+			s.ReadingInProgress = true;
+			s.SMARTInformation = []*SMART{}
+			//Scan disk
+			cmd := exec.Command(s.SystemSmartExecutable, "--scan", "--json=c")
+			out, _ := cmd.CombinedOutput()
+			Devices := new(DevicesList)
+			DevicesOutput := string(out)
+			json.Unmarshal([]byte(DevicesOutput), &Devices)
+			for _, element := range Devices.Devices {
+				//Load SMART for each drive
+				cmd := exec.Command(s.SystemSmartExecutable, "-i", element.Name, "-a", "--json=c")
+				out, err := cmd.CombinedOutput()
+				if err != nil{
+					//log.Println(string(out), err);
+				}
+				InvSMARTInformation := new(DeviceSMART)
+				SMARTOutput := string(out)
+				json.Unmarshal([]byte(SMARTOutput), &InvSMARTInformation)
+				if len(InvSMARTInformation.Smartctl.Messages) > 0 {
+					if InvSMARTInformation.Smartctl.Messages[0].Severity == "error" {
+						log.Println("[SMART Mointoring] Disk " + element.Name + " cannot be readed")
+					} else {
+						//putting everything into that struct array
+						n := SMART{Port: element.Name, DriveSmart: InvSMARTInformation}
+						s.SMARTInformation = append(s.SMARTInformation, &n)
+					}
+				} else {
+					//putting everything into that struct array
+					n := SMART{Port: element.Name, DriveSmart: InvSMARTInformation}
+					s.SMARTInformation = append(s.SMARTInformation, &n)
+				}
+
+			}
+			s.LastScanTime = time.Now().Unix()
+
+			//Set reading flag to false
+			s.ReadingInProgress = false;
+		}
+	}
+	return s.SMARTInformation
+}
+
+func (s *SMARTListener)GetSMART(w http.ResponseWriter, r *http.Request) {
+	jsonText, _ := json.Marshal(s.ReadSMART())
+	sendJSONResponse(w, string(jsonText))
+}
+
+func (s *SMARTListener)CheckDiskTable(w http.ResponseWriter, r *http.Request) {
+	disks, ok := r.URL.Query()["disk"]
+	if !ok || len(disks[0]) < 1 {
+		log.Println("Parameter DISK not found.")
+		return
+	}
+
+	DiskStatus := new(DeviceSMART)
+	for _, info := range s.ReadSMART() {
+		if info.Port == disks[0] {
+			DiskStatus = info.DriveSmart
+		}
+	}
+	JSONStr, _ := json.Marshal(DiskStatus.AtaSmartAttributes.Table)
+	//send!
+	sendJSONResponse(w, string(JSONStr))
+}
+
+func (s *SMARTListener)CheckDiskTestStatus(w http.ResponseWriter, r *http.Request) {
+	disks, ok := r.URL.Query()["disk"]
+	if !ok || len(disks[0]) < 1 {
+		log.Println("Parameter DISK not found.")
+		return
+	}
+
+	DiskTestStatus := new(DeviceSMART)
+	for _, info := range s.ReadSMART() {
+		if info.Port == disks[0] {
+			DiskTestStatus = info.DriveSmart
+		}
+	}
+	JSONStr, _ := json.Marshal(DiskTestStatus.AtaSmartData.SelfTest.Status)
+	//send!
+	sendJSONResponse(w, string(JSONStr))
+}

+ 202 - 0
mod/disk/smart_1/structure.go_disabled

@@ -0,0 +1,202 @@
+package smart
+
+// DevicesList was used for storing the disk scanning result
+type DevicesList struct {
+	JSONFormatVersion []int `json:"json_format_version"`
+	Smartctl          struct {
+		Version      []int    `json:"version"`
+		SvnRevision  string   `json:"svn_revision"`
+		PlatformInfo string   `json:"platform_info"`
+		BuildInfo    string   `json:"build_info"`
+		Argv         []string `json:"argv"`
+		Messages     []struct {
+			String   string `json:"string"`
+			Severity string `json:"severity"`
+		} `json:"messages"`
+		ExitStatus int `json:"exit_status"`
+	} `json:"smartctl"`
+	Devices []struct {
+		Name     string `json:"name"`
+		InfoName string `json:"info_name"`
+		Type     string `json:"type"`
+		Protocol string `json:"protocol"`
+	} `json:"devices"`
+}
+
+// DeviceSMART was used for storing each disk smart information
+type DeviceSMART struct {
+	JSONFormatVersion []int `json:"json_format_version"`
+	Smartctl          struct {
+		Version      []int    `json:"version"`
+		SvnRevision  string   `json:"svn_revision"`
+		PlatformInfo string   `json:"platform_info"`
+		BuildInfo    string   `json:"build_info"`
+		Argv         []string `json:"argv"`
+		Messages     []struct {
+			String   string `json:"string"`
+			Severity string `json:"severity"`
+		} `json:"messages"`
+		ExitStatus int `json:"exit_status"`
+	} `json:"smartctl"`
+	Device struct {
+		Name     string `json:"name"`
+		InfoName string `json:"info_name"`
+		Type     string `json:"type"`
+		Protocol string `json:"protocol"`
+	} `json:"device"`
+	ModelFamily  string `json:"model_family"`
+	ModelName    string `json:"model_name"`
+	SerialNumber string `json:"serial_number"`
+	Wwn          struct {
+		Naa int   `json:"naa"`
+		Oui int   `json:"oui"`
+		ID  int64 `json:"id"`
+	} `json:"wwn"`
+	FirmwareVersion string `json:"firmware_version"`
+	UserCapacity    struct {
+		Blocks int   `json:"blocks"`
+		Bytes  int64 `json:"bytes"`
+	} `json:"user_capacity"`
+	LogicalBlockSize   int  `json:"logical_block_size"`
+	PhysicalBlockSize  int  `json:"physical_block_size"`
+	RotationRate       int  `json:"rotation_rate"`
+	InSmartctlDatabase bool `json:"in_smartctl_database"`
+	AtaVersion         struct {
+		String     string `json:"string"`
+		MajorValue int    `json:"major_value"`
+		MinorValue int    `json:"minor_value"`
+	} `json:"ata_version"`
+	SataVersion struct {
+		String string `json:"string"`
+		Value  int    `json:"value"`
+	} `json:"sata_version"`
+	InterfaceSpeed struct {
+		Max struct {
+			SataValue      int    `json:"sata_value"`
+			String         string `json:"string"`
+			UnitsPerSecond int    `json:"units_per_second"`
+			BitsPerUnit    int    `json:"bits_per_unit"`
+		} `json:"max"`
+		Current struct {
+			SataValue      int    `json:"sata_value"`
+			String         string `json:"string"`
+			UnitsPerSecond int    `json:"units_per_second"`
+			BitsPerUnit    int    `json:"bits_per_unit"`
+		} `json:"current"`
+	} `json:"interface_speed"`
+	LocalTime struct {
+		TimeT   int    `json:"time_t"`
+		Asctime string `json:"asctime"`
+	} `json:"local_time"`
+	SmartStatus struct {
+		Passed bool `json:"passed"`
+	} `json:"smart_status"`
+	AtaSmartData struct {
+		OfflineDataCollection struct {
+			Status struct {
+				Value  int    `json:"value"`
+				String string `json:"string"`
+			} `json:"status"`
+			CompletionSeconds int `json:"completion_seconds"`
+		} `json:"offline_data_collection"`
+		SelfTest struct {
+			Status struct {
+				Value  int    `json:"value"`
+				String string `json:"string"`
+				Passed bool   `json:"passed"`
+			} `json:"status"`
+			PollingMinutes struct {
+				Short      int `json:"short"`
+				Extended   int `json:"extended"`
+				Conveyance int `json:"conveyance"`
+			} `json:"polling_minutes"`
+		} `json:"self_test"`
+		Capabilities struct {
+			Values                        []int `json:"values"`
+			ExecOfflineImmediateSupported bool  `json:"exec_offline_immediate_supported"`
+			OfflineIsAbortedUponNewCmd    bool  `json:"offline_is_aborted_upon_new_cmd"`
+			OfflineSurfaceScanSupported   bool  `json:"offline_surface_scan_supported"`
+			SelfTestsSupported            bool  `json:"self_tests_supported"`
+			ConveyanceSelfTestSupported   bool  `json:"conveyance_self_test_supported"`
+			SelectiveSelfTestSupported    bool  `json:"selective_self_test_supported"`
+			AttributeAutosaveEnabled      bool  `json:"attribute_autosave_enabled"`
+			ErrorLoggingSupported         bool  `json:"error_logging_supported"`
+			GpLoggingSupported            bool  `json:"gp_logging_supported"`
+		} `json:"capabilities"`
+	} `json:"ata_smart_data"`
+	AtaSctCapabilities struct {
+		Value                         int  `json:"value"`
+		ErrorRecoveryControlSupported bool `json:"error_recovery_control_supported"`
+		FeatureControlSupported       bool `json:"feature_control_supported"`
+		DataTableSupported            bool `json:"data_table_supported"`
+	} `json:"ata_sct_capabilities"`
+	AtaSmartAttributes struct {
+		Revision int `json:"revision"`
+		Table    []struct {
+			ID         int    `json:"id"`
+			Name       string `json:"name"`
+			Value      int    `json:"value"`
+			Worst      int    `json:"worst"`
+			Thresh     int    `json:"thresh"`
+			WhenFailed string `json:"when_failed"`
+			Flags      struct {
+				Value         int    `json:"value"`
+				String        string `json:"string"`
+				Prefailure    bool   `json:"prefailure"`
+				UpdatedOnline bool   `json:"updated_online"`
+				Performance   bool   `json:"performance"`
+				ErrorRate     bool   `json:"error_rate"`
+				EventCount    bool   `json:"event_count"`
+				AutoKeep      bool   `json:"auto_keep"`
+			} `json:"flags"`
+			Raw struct {
+				Value  int    `json:"value"`
+				String string `json:"string"`
+			} `json:"raw"`
+		} `json:"table"`
+	} `json:"ata_smart_attributes"`
+	PowerOnTime struct {
+		Hours   int `json:"hours"`
+		Minutes int `json:"minutes"`
+	} `json:"power_on_time"`
+	PowerCycleCount int `json:"power_cycle_count"`
+	Temperature     struct {
+		Current int `json:"current"`
+	} `json:"temperature"`
+	AtaSmartSelfTestLog struct {
+		Standard struct {
+			Revision int `json:"revision"`
+			Table    []struct {
+				Type struct {
+					Value  int    `json:"value"`
+					String string `json:"string"`
+				} `json:"type"`
+				Status struct {
+					Value  int    `json:"value"`
+					String string `json:"string"`
+					Passed bool   `json:"passed"`
+				} `json:"status,omitempty"`
+				LifetimeHours int `json:"lifetime_hours"`
+			} `json:"table"`
+			Count              int `json:"count"`
+			ErrorCountTotal    int `json:"error_count_total"`
+			ErrorCountOutdated int `json:"error_count_outdated"`
+		} `json:"standard"`
+	} `json:"ata_smart_self_test_log"`
+	AtaSmartSelectiveSelfTestLog struct {
+		Revision int `json:"revision"`
+		Table    []struct {
+			LbaMin int `json:"lba_min"`
+			LbaMax int `json:"lba_max"`
+			Status struct {
+				Value  int    `json:"value"`
+				String string `json:"string"`
+			} `json:"status"`
+		} `json:"table"`
+		Flags struct {
+			Value                int  `json:"value"`
+			RemainderScanEnabled bool `json:"remainder_scan_enabled"`
+		} `json:"flags"`
+		PowerUpScanResumeMinutes int `json:"power_up_scan_resume_minutes"`
+	} `json:"ata_smart_selective_self_test_log"`
+}

+ 222 - 0
mod/iot/homekit/homekit.go_dis

@@ -0,0 +1,222 @@
+package homekit
+
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"imuslab.com/arozos/mod/iot"
+	"imuslab.com/arozos/mod/network/mdns"
+	"github.com/brutella/hc"
+    "github.com/brutella/hc/accessory"
+)
+
+/*
+	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 {
+			//Homekit
+    info := accessory.Info{Name: "ArOZ Bridge", ID: 1}
+    ac := accessory.NewBridge(info)
+    
+	outlet := accessory.NewOutlet(accessory.Info{Name: "ArOZ Speaker", ID: 2})
+
+    // configure the ip transport
+    config := hc.Config{Pin: "00102003"}
+    t, err := hc.NewIPTransport(config, ac.Accessory, outlet.Accessory)
+    if err != nil {
+        log.Panic(err)
+    }
+    
+    hc.OnTermination(func(){
+        <-t.Stop()
+    })
+    
+    t.Start()
+	//Create a new MDNS Host
+	return &Handler{
+		scanner,
+		0,
+	}
+}
+
+func (h *Handler) Start() error {
+	log.Println("*IoT* Homekit 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{}
+
+	targetURL := "http://" + device.IPAddr + ":" + strconv.Itoa(device.Port) + "/" + endpoint.RelPath
+
+	//Check if there are payload for this request
+	if payload == nil {
+		//No payload. Just call it
+
+	} else {
+		//Payload exists. Append it to the end with value=?
+		targetURL += "?value=" + payload.(string)
+	}
+
+	result, err := tryGet(targetURL)
+	if err != nil {
+		return nil, err
+	}
+
+	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
+
+}

+ 37 - 0
mod/iot/homekit/utils.go_dis

@@ -0,0 +1,37 @@
+package homekit
+
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"net/http"
+	"strconv"
+	"time"
+)
+
+func isJSON(s string) bool {
+	var js map[string]interface{}
+	return json.Unmarshal([]byte(s), &js) == nil
+}
+
+func tryGet(url string) (string, error) {
+	client := http.Client{
+		Timeout: 10 * time.Second,
+	}
+
+	resp, err := client.Get(url)
+	if err != nil {
+		return "", err
+	}
+
+	if resp.StatusCode != 200 {
+		return "", errors.New("Server side return status code " + strconv.Itoa(resp.StatusCode))
+	}
+
+	content, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return "", err
+	}
+
+	return string(content), nil
+}