From c39d21b67af0290841e3e76b33149c60d7cf2fff Mon Sep 17 00:00:00 2001 From: ctlove0523 <478309639@qq.com> Date: Fri, 20 Aug 2021 22:00:53 +0800 Subject: [PATCH] #8 --- .gitignore | 1 + README.md | 16 +++ http_device.go | 126 ++++++++++++++++++++++ samples/demo_utils.go | 5 + samples/httpdevice/http_device_samples.go | 36 +++++++ 5 files changed, 184 insertions(+) create mode 100644 http_device.go create mode 100644 samples/httpdevice/http_device_samples.go diff --git a/.gitignore b/.gitignore index 839a56d..ec99613 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll *.so *.dylib +*.idea # Test binary, built with `go test -c` *.test diff --git a/README.md b/README.md index eb97ad7..15990d4 100644 --- a/README.md +++ b/README.md @@ -605,6 +605,22 @@ device.ReportDeviceInfo("1.0", "2.0") 设备可以调用`ReportLogs(logs []DeviceLogEntry) bool` 函数主动上报日志。 +### HTTP协议上报消息和属性 + +华为云IoT物联网平台支持使用HTTP协议上报消息和属性(该功能目前处于α阶段,尚未对外开放,具体开放时间参考华为云IoT物联网平台公告)。使用HTTP协议上报消息和属性非常简单方便,SDK对接口进行了封装,接口使用的对象和MQTT协议一致。使用HTTP协议的设备接口定义如下: + +~~~go +type HttpDevice interface { + SendMessage(message Message) bool + ReportProperties(properties DeviceProperties) bool +} +~~~ + +使用样例参考:http_device_samples.go + +~~~ +~~~ + ## 报告bugs diff --git a/http_device.go b/http_device.go new file mode 100644 index 0000000..a0fed15 --- /dev/null +++ b/http_device.go @@ -0,0 +1,126 @@ +package iot + +import ( + "crypto/tls" + "encoding/json" + "fmt" + "github.com/go-resty/resty/v2" + "net/http" + "sync" + "time" +) + +// 使用HTTP协议的设备,当前使用HTTP协议的设备只支持上报消息和上报属性 +type HttpDevice interface { + + // 上报消息 + SendMessage(message Message) bool + + // 上报属性 + ReportProperties(properties DeviceProperties) bool +} + +type restyHttpDevice struct { + Id string + Password string + Servers string + client *resty.Client + + lock sync.RWMutex + accessToken string +} + +func (device *restyHttpDevice) SendMessage(message Message) bool { + resp, err := device.client.R(). + SetBody(message). + Post(fmt.Sprintf("%s/v5/devices/%s/sys/messages/up", device.Servers, device.Id)) + if err != nil { + fmt.Printf("send message failed %s\n", err) + } + return err == nil && resp.StatusCode() == http.StatusOK +} + +func (device *restyHttpDevice) ReportProperties(properties DeviceProperties) bool { + response, err := device.client.R(). + SetBody(properties). + Post(fmt.Sprintf("%s/v5/devices/%s/sys/properties/report", device.Servers, device.Id)) + if err != nil { + fmt.Printf("report properties failed %s\n", err) + } + return err == nil && response.StatusCode() == http.StatusOK +} + +func (device *restyHttpDevice) init() { + accessTokenBody := accessTokenRequest{ + DeviceId: device.Id, + SignType: 0, + Timestamp: "2019120219", + Password: hmacSha256(device.Password, "2019120219"), + } + + response, err := device.client.R(). + SetBody(accessTokenBody). + Post(fmt.Sprintf("%s%s", device.Servers, "/v5/device-auth")) + if err != nil { + fmt.Printf("get device access token failed %s\n", err) + return + } + + tokenResponse := &accessTokenResponse{} + err = json.Unmarshal(response.Body(), tokenResponse) + if err != nil { + fmt.Println("json unmarshal failed") + return + } + + device.lock.Lock() + device.accessToken = tokenResponse.AccessToken + device.lock.Unlock() +} + +type accessTokenResponse struct { + AccessToken string `json:"access_token"` +} + +type accessTokenRequest struct { + DeviceId string `json:"device_id"` + SignType int `json:"sign_type"` + Timestamp string `json:"timestamp"` + Password string `json:"password"` +} + +func CreateHttpDevice(id, password, server string) HttpDevice { + c := resty.New() + c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) + c.SetTimeout(30 * time.Second) + c.SetRetryCount(3) + c.SetRetryWaitTime(10 * time.Second) + c.AddRetryCondition(func(response *resty.Response, err error) bool { + return response.StatusCode() == http.StatusForbidden + }) + + device := &restyHttpDevice{ + Id: id, + Password: password, + Servers: server, + client: c, + lock: sync.RWMutex{}, + } + + device.init() + device.client.OnBeforeRequest(func(client *resty.Client, request *resty.Request) error { + device.lock.RLock() + request.SetHeader("access_token", device.accessToken) + device.lock.RUnlock() + request.SetHeader("Content-Type", "application/json") + return nil + }) + device.client.OnAfterResponse(func(client *resty.Client, response *resty.Response) error { + if response.StatusCode() == http.StatusForbidden { + device.init() + } + return nil + }) + + return device +} diff --git a/samples/demo_utils.go b/samples/demo_utils.go index cef15e5..bc334b0 100644 --- a/samples/demo_utils.go +++ b/samples/demo_utils.go @@ -17,3 +17,8 @@ func CreateDevice() iot.Device { return device } + +func CreateHttpDevice() iot.HttpDevice{ + return iot.CreateHttpDevice(deviceId, devicePassword, "https://iot-mqtts.cn-north-4.myhuaweicloud.com:443") + +} diff --git a/samples/httpdevice/http_device_samples.go b/samples/httpdevice/http_device_samples.go new file mode 100644 index 0000000..8da2c38 --- /dev/null +++ b/samples/httpdevice/http_device_samples.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + iot "github.com/ctlove0523/huaweicloud-iot-device-sdk-go" + "github.com/ctlove0523/huaweicloud-iot-device-sdk-go/samples" +) + +func main() { + httpDevice := samples.CreateHttpDevice() + + s := SelfHttpResponse{ + HttpCode: 404, + HttpMessage: "test http device", + ReportTime: iot.GetEventTimeStamp(), + } + entry := iot.DevicePropertyEntry{ + ServiceId: "http_api", + Properties: s, + EventTime: iot.GetEventTimeStamp(), + } + + var entries []iot.DevicePropertyEntry + entries = append(entries, entry) + properties := iot.DeviceProperties{ + Services: entries, + } + + fmt.Println(httpDevice.ReportProperties(properties)) +} + +type SelfHttpResponse struct { + HttpCode int `json:"http_code"` + HttpMessage string `json:"http_message"` + ReportTime string `json:"report_time"` +}