支持文件上传功能
This commit is contained in:
parent
71e032de65
commit
11cfffae71
32
README.md
32
README.md
|
@ -2,15 +2,16 @@
|
|||
|
||||
huaweicloud-iot-device-sdk-go提供设备接入华为云IoT物联网平台的Go版本的SDK,提供设备和平台之间通讯能力,以及设备服务、网关服务、OTA等高级服务。IoT设备开发者使用SDK可以大大简化开发复杂度,快速的接入平台。
|
||||
|
||||
|
||||
|
||||
## 安装和构建
|
||||
|
||||
安装和构建的过程取决于你是使用go的 [modules](https://golang.org/ref/mod)(推荐) 还是还是`GOPATH`
|
||||
安装和构建的过程取决于你是使用go的 [modules](https://golang.org/ref/mod)(推荐) 还是还是`GOPATH`
|
||||
|
||||
### Modules
|
||||
|
||||
如果你使用 [modules](https://golang.org/ref/mod) 只需要导入包"github.com/ctlove0523/huaweicloud-iot-device-sdk-go"即可使用。当你使用go build命令构建项目时,依赖的包会自动被下载。注意使用go build命令构建时会自动下载最新版本,最新版本还没有达到release的标准可能存在一些尚未修复的bug。如果想使用稳定的发布版本可以从[release](https://github.com/ctlove0523/huaweicloud-iot-device-sdk-go/releases) 获取最新稳定的版本号,并在go.mod文件中指定版本号。
|
||||
如果你使用 [modules](https://golang.org/ref/mod) 只需要导入包"github.com/ctlove0523/huaweicloud-iot-device-sdk-go"即可使用。当你使用go
|
||||
build命令构建项目时,依赖的包会自动被下载。注意使用go
|
||||
build命令构建时会自动下载最新版本,最新版本还没有达到release的标准可能存在一些尚未修复的bug。如果想使用稳定的发布版本可以从[release](https://github.com/ctlove0523/huaweicloud-iot-device-sdk-go/releases)
|
||||
获取最新稳定的版本号,并在go.mod文件中指定版本号。
|
||||
|
||||
~~~go
|
||||
module example
|
||||
|
@ -28,8 +29,6 @@ require github.com/ctlove0523/huaweicloud-iot-device-sdk-go v0.0.1-alpha
|
|||
go get github.com/ctlove0523/huaweicloud-iot-device-sdk-go
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
## 使用API
|
||||
|
||||
### 创建设备并初始化
|
||||
|
@ -63,8 +62,6 @@ func main() {
|
|||
|
||||
> iot-mqtts.cn-north-4.myhuaweicloud.com为华为IoT平台(基础班)在华为云北京四的访问端点,如果你购买了标准版或企业版,请将iot-mqtts.cn-north-4.myhuaweicloud.com更换为对应的MQTT协议接入端点。
|
||||
|
||||
|
||||
|
||||
### 设备处理平台下发的命令
|
||||
|
||||
1、首先,在华为云IoT平台创建一个设备,设备的信息如下:
|
||||
|
@ -143,8 +140,6 @@ func main() {
|
|||
}
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
> 设备支持的命令定义在产品中
|
||||
|
||||
### 设备消息
|
||||
|
@ -232,8 +227,6 @@ func main() {
|
|||
}
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
### 设备属性
|
||||
|
||||
1、首先,在华为云IoT平台创建一个设备,并在该设备下创建3个子设备,设备及子设备的信息如下:
|
||||
|
@ -257,8 +250,6 @@ device.Init()
|
|||
fmt.Printf("device connected: %v\n", device.IsConnected())
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
#### 设备属性上报
|
||||
|
||||
使用`ReportProperties(properties ServiceProperty) bool` 上报设备属性
|
||||
|
@ -282,8 +273,6 @@ services := iot.ServiceProperty{
|
|||
device.ReportProperties(services)
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
#### 网关批量设备属性上报
|
||||
|
||||
使用`BatchReportSubDevicesProperties(service DevicesService)` 实现网关批量设备属性上报
|
||||
|
@ -312,8 +301,6 @@ device.BatchReportSubDevicesProperties(iot.DevicesService{
|
|||
})
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
#### 平台设置设备属性
|
||||
|
||||
使用`AddPropertiesSetHandler(handler DevicePropertiesSetHandler)` 注册平台设置设备属性handler,当接收到平台的命令时SDK回调。
|
||||
|
@ -327,8 +314,6 @@ device.AddPropertiesSetHandler(func(propertiesSetRequest iot.DevicePropertyDownR
|
|||
})
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
#### 平台查询设备属性
|
||||
|
||||
使用`SetPropertyQueryHandler(handler DevicePropertyQueryHandler)`注册平台查询设备属性handler,当接收到平台的查询请求时SDK回调。
|
||||
|
@ -347,11 +332,10 @@ device.SetPropertyQueryHandler(func(query iot.DevicePropertyQueryRequest) iot.Se
|
|||
})
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
#### 设备侧获取平台的设备影子数据
|
||||
|
||||
使用`QueryDeviceShadow(query DevicePropertyQueryRequest, handler DevicePropertyQueryResponseHandler)` 可以查询平台的设备影子数据,当接收到平台的响应后SDK自动回调`DevicePropertyQueryResponseHandler`。
|
||||
使用`QueryDeviceShadow(query DevicePropertyQueryRequest, handler DevicePropertyQueryResponseHandler)`
|
||||
可以查询平台的设备影子数据,当接收到平台的响应后SDK自动回调`DevicePropertyQueryResponseHandler`。
|
||||
|
||||
~~~go
|
||||
// 设备查询设备影子数据
|
||||
|
@ -450,8 +434,6 @@ type DemoProperties struct {
|
|||
}
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
## 报告bugs
|
||||
|
||||
如果你在使用过程中遇到任何问题或bugs,请通过issue的方式上报问题或bug,我们将会在第一时间内答复。上报问题或bugs时请尽量提供以下内容:
|
||||
|
|
21
constants.go
21
constants.go
|
@ -23,19 +23,26 @@ const (
|
|||
PropertiesSetResponseTopic string = "$oc/devices/{device_id}/sys/properties/set/response/request_id="
|
||||
|
||||
// 平台查询设备属性
|
||||
PropertiesQueryRequestTopicName string = "propertiesQueryRequestTopicName"
|
||||
PropertiesQueryRequestTopic string = "$oc/devices/{device_id}/sys/properties/get/#"
|
||||
PropertiesQueryRequestTopicName string = "propertiesQueryRequestTopicName"
|
||||
PropertiesQueryRequestTopic string = "$oc/devices/{device_id}/sys/properties/get/#"
|
||||
PropertiesQueryResponseTopicName string = "propertiesQueryResponseTopicName"
|
||||
PropertiesQueryResponseTopic string = "$oc/devices/{device_id}/sys/properties/get/response/request_id="
|
||||
|
||||
// 设备侧获取平台的设备影子数据
|
||||
DeviceShadowQueryRequestTopicName string = "deviceShadowQueryRequestTopicName"
|
||||
DeviceShadowQueryRequestTopic string = "$oc/devices/{device_id}/sys/shadow/get/request_id="
|
||||
DeviceShadowQueryRequestTopicName string = "deviceShadowQueryRequestTopicName"
|
||||
DeviceShadowQueryRequestTopic string = "$oc/devices/{device_id}/sys/shadow/get/request_id="
|
||||
DeviceShadowQueryResponseTopicName string = "deviceShadowQueryResponseTopicName"
|
||||
DeviceShadowQueryResponseTopic string = "$oc/devices/{device_id}/sys/shadow/get/response/#"
|
||||
DeviceShadowQueryResponseTopic string = "$oc/devices/{device_id}/sys/shadow/get/response/#"
|
||||
|
||||
// 网关批量上报子设备属性
|
||||
GatewayBatchReportSubDeviceTopicName string = "gatewayBatchReportSubDeviceTopicName"
|
||||
GatewayBatchReportSubDeviceTopic string = "$oc/devices/{device_id}/sys/gateway/sub_devices/properties/report"
|
||||
)
|
||||
GatewayBatchReportSubDeviceTopic string = "$oc/devices/{device_id}/sys/gateway/sub_devices/properties/report"
|
||||
|
||||
// 文件上传
|
||||
FileUploadUrlRequestTopicName string = "fileUploadUrlRequestTopicName"
|
||||
FileUploadUrlRequestTopic string = "$oc/devices/{device_id}/sys/events/up"
|
||||
FileUploadUrlResponseTopicName string = "fileUploadUrlResponseTopicName"
|
||||
FileUploadUrlResponseTopic string = "$oc/devices/{device_id}/sys/events/down"
|
||||
FileUploadResultTopicName string = "FileUploadResultTopic"
|
||||
FileUploadResultTopic string = "$oc/devices/{device_id}/sys/events/up"
|
||||
)
|
||||
|
|
87
handlers.go
87
handlers.go
|
@ -119,3 +119,90 @@ type DeviceService struct {
|
|||
DeviceId string `json:"device_id"`
|
||||
Services []ServicePropertyEntry `json:"services"`
|
||||
}
|
||||
|
||||
// 文件上传下载管理
|
||||
|
||||
func CreateFileUploadResultResponse(filename string, result bool) FileUploadResultResponse {
|
||||
code := 0
|
||||
if result {
|
||||
code = 0
|
||||
} else {
|
||||
code = 1
|
||||
}
|
||||
paras := UploadFileResultResponseServiceEventParas{
|
||||
ObjectName: filename,
|
||||
ResultCode: code,
|
||||
}
|
||||
|
||||
serviceEvent := UploadResultResponseServiceEvent{
|
||||
Paras: paras,
|
||||
}
|
||||
serviceEvent.ServiceId = "$file_manager"
|
||||
serviceEvent.EventType = "upload_result_report"
|
||||
serviceEvent.EventTime = GetEventTimeStamp()
|
||||
|
||||
var services []UploadResultResponseServiceEvent
|
||||
services = append(services, serviceEvent)
|
||||
|
||||
response := FileUploadResultResponse{
|
||||
Services: services,
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
type FileUploadUrlRequest struct {
|
||||
ObjectDeviceId string `json:"object_device_id"`
|
||||
Services []UploadRequestServiceEvent `json:"services"`
|
||||
}
|
||||
|
||||
type FileUploadUrlResponse struct {
|
||||
ObjectDeviceId string `json:"object_device_id"`
|
||||
Services []UploadResponseServiceEvent `json:"services"`
|
||||
}
|
||||
|
||||
type FileUploadResultResponse struct {
|
||||
ObjectDeviceId string `json:"object_device_id"`
|
||||
Services []UploadResultResponseServiceEvent `json:"services"`
|
||||
}
|
||||
|
||||
type BaseServiceEvent struct {
|
||||
ServiceId string `json:"service_id"`
|
||||
EventType string `json:"event_type"`
|
||||
EventTime string `json:"event_time"`
|
||||
}
|
||||
|
||||
type UploadRequestServiceEvent struct {
|
||||
BaseServiceEvent
|
||||
Paras UploadRequestServiceEventParas `json:"paras"`
|
||||
}
|
||||
|
||||
type UploadResponseServiceEvent struct {
|
||||
BaseServiceEvent
|
||||
Paras UploadResponseServiceEventParas `json:"paras"`
|
||||
}
|
||||
|
||||
type UploadResultResponseServiceEvent struct {
|
||||
BaseServiceEvent
|
||||
Paras UploadFileResultResponseServiceEventParas `json:"paras"`
|
||||
}
|
||||
|
||||
type UploadRequestServiceEventParas struct {
|
||||
FileName string `json:"file_name"`
|
||||
FileAttributes interface{} `json:"file_attributes"`
|
||||
}
|
||||
|
||||
type UploadResponseServiceEventParas struct {
|
||||
Url string `json:"url"`
|
||||
BucketName string `json:"bucket_name"`
|
||||
ObjectName string `json:"object_name"`
|
||||
Expire int `json:"expire"`
|
||||
FileAttributes interface{} `json:"file_attributes"`
|
||||
}
|
||||
|
||||
type UploadFileResultResponseServiceEventParas struct {
|
||||
ObjectName string `json:"object_name"`
|
||||
ResultCode int `json:"result_code"`
|
||||
StatusCode int `json:"status_code"`
|
||||
StatusDescription string `json:"status_description"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package iot
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"github.com/golang/glog"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func OsName() string {
|
||||
return runtime.GOOS
|
||||
}
|
||||
|
||||
func SdkInfo() map[string]string {
|
||||
f, err := os.Open("sdk_info")
|
||||
if err != nil {
|
||||
glog.Warning("read sdk info failed")
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
// 文件很小
|
||||
info := make(map[string]string)
|
||||
buf := bufio.NewReader(f)
|
||||
for {
|
||||
b, _, err := buf.ReadLine()
|
||||
if err != nil && err == io.EOF {
|
||||
glog.Warningf("read sdk info failed or end")
|
||||
break
|
||||
}
|
||||
line := string(b)
|
||||
if len(line) != 0 {
|
||||
parts := strings.Split(line, "=")
|
||||
info[strings.Trim(parts[0], " ")] = strings.Trim(parts[1], " ")
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package iot
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 该测试用力仅能在Windows系统运行
|
||||
func TestOsName(t *testing.T) {
|
||||
if !strings.Contains(OsName(), "windows") {
|
||||
t.Errorf(`OsName must be windwos`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
if SdkInfo()["sdk-version"] != "v0.0.1" {
|
||||
t.Errorf("sdk version must be v0.0.1")
|
||||
}
|
||||
|
||||
if SdkInfo()["author"] != "chen tong" {
|
||||
t.Errorf("sdk author must be chen tong")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFileUploadResultResponse(t *testing.T) {
|
||||
f, err := os.Open("sdk_info")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
//建立缓冲区,把文件内容放到缓冲区中
|
||||
buf := bufio.NewReader(f)
|
||||
for {
|
||||
//遇到\n结束读取
|
||||
b, errR := buf.ReadBytes('\n')
|
||||
if errR != nil {
|
||||
if errR == io.EOF {
|
||||
break
|
||||
}
|
||||
fmt.Println(errR.Error())
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package iot
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/golang/glog"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 仅用于设备上传文件
|
||||
type HttpClient interface {
|
||||
UploadFile(filename, uri string) bool
|
||||
}
|
||||
|
||||
type httpClient struct {
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func (client *httpClient) UploadFile(filename, uri string) bool {
|
||||
|
||||
bodyBuffer := &bytes.Buffer{}
|
||||
bodyWriter := multipart.NewWriter(bodyBuffer)
|
||||
|
||||
fileWriter, err := bodyWriter.CreateFormFile("files", filename)
|
||||
if err != nil {
|
||||
glog.Errorf("create form file failed %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
glog.Errorf("open file failed %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(fileWriter, file)
|
||||
if err != nil {
|
||||
glog.Errorf("copy file to writer failed %v", err)
|
||||
}
|
||||
|
||||
//contentType := bodyWriter.FormDataContentType()
|
||||
defer bodyWriter.Close()
|
||||
|
||||
req, err := http.NewRequest("PUT", uri, bodyBuffer)
|
||||
if err != nil {
|
||||
glog.Errorf("create request filed %v", err)
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "text/plain")
|
||||
|
||||
originalUri, err := url.ParseRequestURI(uri)
|
||||
if err != nil {
|
||||
glog.Errorf("parse request uri failed %v", err)
|
||||
}
|
||||
req.Header.Add("Host", originalUri.Host)
|
||||
resp, _ := client.client.Do(req)
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
_, err = ioutil.ReadAll(resp.Body)
|
||||
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func CreateHttpClient() HttpClient {
|
||||
tr := &http.Transport{
|
||||
MaxIdleConns: 10,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
DisableCompression: true,
|
||||
}
|
||||
innerClient := &http.Client{Transport: tr}
|
||||
|
||||
httpClient := &httpClient{
|
||||
client: innerClient,
|
||||
}
|
||||
|
||||
return httpClient
|
||||
|
||||
}
|
78
iotdevice.go
78
iotdevice.go
|
@ -2,6 +2,7 @@ package iot
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/golang/glog"
|
||||
"github.com/satori/go.uuid"
|
||||
|
@ -20,6 +21,7 @@ type Device interface {
|
|||
AddCommandHandler(handler CommandHandler)
|
||||
AddPropertiesSetHandler(handler DevicePropertiesSetHandler)
|
||||
SetPropertyQueryHandler(handler DevicePropertyQueryHandler)
|
||||
UploadFile(filename string) bool
|
||||
}
|
||||
|
||||
type iotDevice struct {
|
||||
|
@ -35,6 +37,75 @@ type iotDevice struct {
|
|||
topics map[string]string
|
||||
}
|
||||
|
||||
type FileAtt struct {
|
||||
HashCode string `json:"hash_code"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
func (device *iotDevice) UploadFile(filename string) bool {
|
||||
// first subscribe
|
||||
uploadUrlChan := make(chan string)
|
||||
|
||||
device.client.Subscribe(device.topics[FileUploadUrlResponseTopicName], 1, func(client mqtt.Client, message mqtt.Message) {
|
||||
response := &FileUploadUrlResponse{}
|
||||
if json.Unmarshal(message.Payload(), response) != nil {
|
||||
glog.Errorf("unmarshal file upload response failed")
|
||||
uploadUrlChan <- ""
|
||||
} else {
|
||||
uploadUrlChan <- response.Services[0].Paras.Url
|
||||
}
|
||||
})
|
||||
|
||||
// 构造获取文件上传URL的请求
|
||||
requestParas := UploadRequestServiceEventParas{
|
||||
FileName: filename,
|
||||
}
|
||||
|
||||
serviceEvent := UploadRequestServiceEvent{
|
||||
Paras: requestParas,
|
||||
}
|
||||
serviceEvent.ServiceId = "$file_manager"
|
||||
serviceEvent.EventTime = GetEventTimeStamp()
|
||||
serviceEvent.EventType = "get_upload_url"
|
||||
|
||||
var services []UploadRequestServiceEvent
|
||||
services = append(services, serviceEvent)
|
||||
request := FileUploadUrlRequest{
|
||||
Services: services,
|
||||
}
|
||||
|
||||
if token := device.client.Publish(device.topics[FileUploadUrlRequestTopicName], 1, false, Interface2JsonString(request));
|
||||
token.Wait() && token.Error() != nil {
|
||||
glog.Warningf("publish file upload request url failed")
|
||||
return false
|
||||
}
|
||||
|
||||
upLoadUrl := <-uploadUrlChan
|
||||
|
||||
if len(upLoadUrl) == 0 {
|
||||
glog.Errorf("get file upload url failed")
|
||||
return false
|
||||
}
|
||||
glog.Infof("file upload url is %s", upLoadUrl)
|
||||
|
||||
filename = SmartFileName(filename)
|
||||
uploadFlag := CreateHttpClient().UploadFile(filename, upLoadUrl)
|
||||
if !uploadFlag {
|
||||
glog.Errorf("upload file failed")
|
||||
return false
|
||||
}
|
||||
|
||||
response := CreateFileUploadResultResponse(filename, uploadFlag)
|
||||
|
||||
token := device.client.Publish(device.topics[FileUploadResultTopicName], 1, false, Interface2JsonString(response))
|
||||
if token.Wait() && token.Error() != nil {
|
||||
glog.Error("report file upload file result failed")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (device *iotDevice) createMessageMqttHandler() func(client mqtt.Client, message mqtt.Message) {
|
||||
messageHandler := func(client mqtt.Client, message mqtt.Message) {
|
||||
msg := &Message{}
|
||||
|
@ -141,6 +212,8 @@ func (device *iotDevice) Init() bool {
|
|||
options.SetClientID(assembleClientId(device))
|
||||
options.SetUsername(device.Id)
|
||||
options.SetPassword(HmacSha256(device.Password, TimeStamp()))
|
||||
fmt.Println(assembleClientId(device))
|
||||
fmt.Println(HmacSha256(device.Password, TimeStamp()))
|
||||
|
||||
device.client = mqtt.NewClient(options)
|
||||
|
||||
|
@ -249,6 +322,9 @@ func CreateIotDevice(id, password, servers string) Device {
|
|||
device.topics[DeviceShadowQueryRequestTopicName] = FormatTopic(DeviceShadowQueryRequestTopic, id)
|
||||
device.topics[DeviceShadowQueryResponseTopicName] = FormatTopic(DeviceShadowQueryResponseTopic, id)
|
||||
device.topics[GatewayBatchReportSubDeviceTopicName] = FormatTopic(GatewayBatchReportSubDeviceTopic, id)
|
||||
device.topics[FileUploadUrlRequestTopicName] = FormatTopic(FileUploadUrlRequestTopic, id)
|
||||
device.topics[FileUploadUrlResponseTopicName] = FormatTopic(FileUploadUrlResponseTopic, id)
|
||||
device.topics[FileUploadResultTopicName] = FormatTopic(FileUploadResultTopic, id)
|
||||
return device
|
||||
}
|
||||
|
||||
|
@ -264,7 +340,7 @@ func assembleClientId(device *iotDevice) string {
|
|||
|
||||
func logFlush() {
|
||||
ticker := time.Tick(5 * time.Second)
|
||||
for{
|
||||
for {
|
||||
select {
|
||||
case <-ticker:
|
||||
glog.Flush()
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
iot "github.com/ctlove0523/huaweicloud-iot-device-sdk-go"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//创建一个设备并初始化
|
||||
device := iot.CreateIotDevice("5fdb75cccbfe2f02ce81d4bf_go-mqtt", "123456789", "tcp://iot-mqtts.cn-north-4.myhuaweicloud.com:1883")
|
||||
device.Init()
|
||||
|
||||
device.UploadFile("D/software/mqttfx/chentong.txt")
|
||||
|
||||
time.Sleep(time.Hour)
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ticker := time.Tick(5 * time.Second)
|
||||
for ; ; {
|
||||
select {
|
||||
case <-ticker:
|
||||
fmt.Println(time.Now().Second())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ func main() {
|
|||
// 设备上报属性
|
||||
props := iot.ServicePropertyEntry{
|
||||
ServiceId: "value",
|
||||
EventTime: iot.DataCollectionTime(),
|
||||
EventTime: iot.GetEventTimeStamp(),
|
||||
Properties: DemoProperties{
|
||||
Value: "chen tong",
|
||||
MsgType: "23",
|
||||
|
|
17
util.go
17
util.go
|
@ -20,7 +20,7 @@ func TimeStamp() string {
|
|||
|
||||
// 设备采集数据UTC时间(格式:yyyyMMdd'T'HHmmss'Z'),如:20161219T114920Z。
|
||||
//设备上报数据不带该参数或参数格式错误时,则数据上报时间以平台时间为准。
|
||||
func DataCollectionTime() string {
|
||||
func GetEventTimeStamp() string {
|
||||
now := time.Now().UTC()
|
||||
return now.Format("20060102T150405Z")
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ func HmacSha256(data string, secret string) string {
|
|||
}
|
||||
|
||||
func Interface2JsonString(v interface{}) string {
|
||||
if v == nil {
|
||||
return ""
|
||||
}
|
||||
byteData, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return ""
|
||||
|
@ -46,3 +49,15 @@ func GetTopicRequestId(topic string) string {
|
|||
func FormatTopic(topic, deviceId string) string {
|
||||
return strings.ReplaceAll(topic, "{device_id}", deviceId)
|
||||
}
|
||||
|
||||
// 根据当前运行的操作系统重新修改文件路径以适配操作系统
|
||||
func SmartFileName(filename string) string {
|
||||
// Windows操作系统适配
|
||||
if strings.Contains(OsName(), "windows") {
|
||||
pathParts := strings.Split(filename, "/")
|
||||
pathParts[0] = pathParts[0] + ":"
|
||||
return strings.Join(pathParts, "\\\\")
|
||||
}
|
||||
|
||||
return filename
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package iot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTimeStamp(t *testing.T) {
|
||||
timeStamp := TimeStamp()
|
||||
if len(timeStamp) != 10 {
|
||||
t.Error(`Time Stamp length must be 10`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataCollectionTime(t *testing.T) {
|
||||
if len(GetEventTimeStamp()) != 16 {
|
||||
t.Errorf(`Data Collection Time length must be 16,but is %d`, len(GetEventTimeStamp()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHmacSha256(t *testing.T) {
|
||||
encodedPassword := "c0fefa1341fb0647290e93f641a9bcea74cd32111668cdc5f7418553640a55cc"
|
||||
if HmacSha256("123456789", "202012222200") != encodedPassword {
|
||||
t.Errorf("encoded password must be %s but is %s", encodedPassword, HmacSha256("123456789", "202012222200"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterface2JsonString(t *testing.T) {
|
||||
if Interface2JsonString(nil) != "" {
|
||||
t.Errorf("nill interface to json string must empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTopicRequestId(t *testing.T) {
|
||||
topic := "$os/device/down/request=123456789"
|
||||
if GetTopicRequestId(topic) != "123456789" {
|
||||
t.Errorf("topic request id must be %s", "123456789")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatTopic(t *testing.T) {
|
||||
topic := "$os/device/{device_id}/up"
|
||||
deviceId := "123"
|
||||
formatTopic := "$os/device/123/up"
|
||||
if formatTopic != FormatTopic(topic, deviceId) {
|
||||
t.Errorf("formated topic must be %s", formatTopic)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 仅适用于windows系统
|
||||
func TestSmartFileName(t *testing.T) {
|
||||
fileName := "D/go/sdk/test.log"
|
||||
smartFileName := "D:\\\\go\\\\sdk\\\\test.log"
|
||||
|
||||
if smartFileName != SmartFileName(fileName) {
|
||||
t.Errorf("in windows file system,smart file name must be %s", smartFileName)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue