diff --git a/README.md b/README.md index 0f5b9ed..07bbd4a 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ huaweicloud-iot-device-sdk-go提供设备接入华为云IoT物联网平台的Go * [设备日志收集](#设备日志收集) * [HTTP协议上报消息和属性](#HTTP协议上报消息和属性) - +* [支持设备发放服务](#使用设备发放服务) ## 版本说明 -当前稳定版本:v2.0.0 +当前稳定版本:v1.0.1 @@ -658,6 +658,49 @@ type HttpDevice interface { +### 使用设备发放服务 + +有两种方法可以使用设备发放服务动态获取设备连接平台的地址 + +方法1:通过设备发放服务获取设备连接平台的地址,然后创建设备 + +~~~golang +id := "device_id" +pwd := "your device password" + +bootstrapClient, err := iot.NewBootstrapClient(id, pwd) +if err != nil { + fmt.Printf("create bs client failed") + return +} + +server := bootstrapClient.Boot() +if len(server) == 0 { + fmt.Println("get server address failed") + return +} + +device := iot.CreateIotDevice(id, pwd, server) +device.Init() +~~~ + +方法2:在创建设备时启动设备发放服务 + +~~~go +id := "device_id" +pwd := "your device password" +config := iot.DeviceConfig{ + Id: id, + Password: pwd, + UseBootstrap: true, +} +device := iot.CreateIotDeviceWitConfig(config) +initRes := device.Init() +fmt.Println(initRes) + +time.Sleep(1 * time.Minute) +~~~ + diff --git a/base_device.go b/base_device.go index 6c17abb..732fd08 100644 --- a/base_device.go +++ b/base_device.go @@ -76,6 +76,7 @@ type DeviceConfig struct { ServerCaPath string CertFilePath string CertKeyFilePath string + UseBootstrap bool // 使用设备引导功能开关,true-使用,false-不使用 } type BaseDevice interface { @@ -152,6 +153,7 @@ type baseIotDevice struct { devicePropertyLogCollector DevicePropertyLogCollector deviceMessageLogCollector DeviceMessageLogCollector deviceCommandLogCollector DeviceCommandLogCollector + useBootstrap bool } func (device *baseIotDevice) DisConnect() { @@ -168,9 +170,24 @@ func (device *baseIotDevice) IsConnected() bool { } func (device *baseIotDevice) Init() bool { - options := mqtt.NewClientOptions() - options.AddBroker(device.Servers) + if device.useBootstrap { + bootstracpClient, err := NewBootstrapClient(device.Id, device.Password) + if err != nil { + fmt.Printf("create bootstrap client failed,err %s\n", err) + return false + } + + serverAddress := bootstracpClient.Boot() + if len(serverAddress) == 0 { + fmt.Println("get server address from bootstrap server failed") + return false + } + options.AddBroker(serverAddress) + } else { + options.AddBroker(device.Servers) + } + options.SetClientID(assembleClientId(device)) options.SetUsername(device.Id) options.SetPassword(hmacSha256(device.Password, timeStamp())) diff --git a/bootstrap.go b/bootstrap.go index dcf20ec..61be1d0 100644 --- a/bootstrap.go +++ b/bootstrap.go @@ -7,51 +7,48 @@ import ( "fmt" mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/golang/glog" - "io/ioutil" - "strings" "sync" "time" ) -type BootstrapClientConfig struct { - id string // 设备Id,平台又称为deviceId - password string // 设备密码 - server string // 设备发放平台地址:tls://iot-bs.cn-north-4.myhuaweicloud.com:8883 - caPath string // 设备发放平台CA证书 -} - -func NewBootstrapClientConfig() *BootstrapClientConfig { - return &BootstrapClientConfig{} -} - -func (conf *BootstrapClientConfig) WithId(id string) *BootstrapClientConfig { - conf.id = id - return conf -} - -func (conf *BootstrapClientConfig) WithPassword(password string) *BootstrapClientConfig { - conf.password = password - return conf -} - -func (conf *BootstrapClientConfig) WithServer(server string) *BootstrapClientConfig { - conf.server = server - return conf -} - -func (conf *BootstrapClientConfig) WithCaPath(caPath string) *BootstrapClientConfig { - conf.caPath = caPath - return conf -} +const ( + bsServer = "tls://iot-bs.cn-north-4.myhuaweicloud.com:8883" + bsServerCa = "-----BEGIN CERTIFICATE-----\n" + + "MIIETjCCAzagAwIBAgINAe5fIh38YjvUMzqFVzANBgkqhkiG9w0BAQsFADBMMSAw\n" + + "HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs\n" + + "U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODExMjEwMDAwMDBaFw0yODEx\n" + + "MjEwMDAwMDBaMFAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52\n" + + "LXNhMSYwJAYDVQQDEx1HbG9iYWxTaWduIFJTQSBPViBTU0wgQ0EgMjAxODCCASIw\n" + + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdaydUMGCEAI9WXD+uu3Vxoa2uP\n" + + "UGATeoHLl+6OimGUSyZ59gSnKvuk2la77qCk8HuKf1UfR5NhDW5xUTolJAgvjOH3\n" + + "idaSz6+zpz8w7bXfIa7+9UQX/dhj2S/TgVprX9NHsKzyqzskeU8fxy7quRU6fBhM\n" + + "abO1IFkJXinDY+YuRluqlJBJDrnw9UqhCS98NE3QvADFBlV5Bs6i0BDxSEPouVq1\n" + + "lVW9MdIbPYa+oewNEtssmSStR8JvA+Z6cLVwzM0nLKWMjsIYPJLJLnNvBhBWk0Cq\n" + + "o8VS++XFBdZpaFwGue5RieGKDkFNm5KQConpFmvv73W+eka440eKHRwup08CAwEA\n" + + "AaOCASkwggElMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G\n" + + "A1UdDgQWBBT473/yzXhnqN5vjySNiPGHAwKz6zAfBgNVHSMEGDAWgBSP8Et/qC5F\n" + + "JK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6\n" + + "Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAroCmgJ4Yl\n" + + "aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBHBgNVHSAEQDA+\n" + + "MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j\n" + + "b20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAJmQyC1fQorUC2bbmANz\n" + + "EdSIhlIoU4r7rd/9c446ZwTbw1MUcBQJfMPg+NccmBqixD7b6QDjynCy8SIwIVbb\n" + + "0615XoFYC20UgDX1b10d65pHBf9ZjQCxQNqQmJYaumxtf4z1s4DfjGRzNpZ5eWl0\n" + + "6r/4ngGPoJVpjemEuunl1Ig423g7mNA2eymw0lIYkN5SQwCuaifIFJ6GlazhgDEw\n" + + "fpolu4usBCOmmQDo8dIm7A9+O4orkjgTHY+GzYZSR+Y0fFukAj6KYXwidlNalFMz\n" + + "hriSqHKvoflShx8xpfywgVcvzfTO3PYkz6fiNJBonf6q8amaEsybwMbDqKWwIX7eSPY=\n" + + "-----END CERTIFICATE-----" +) type BootstrapClient interface { Boot() string Close() } -func NewBootstrapClient(conf *BootstrapClientConfig) (BootstrapClient, error) { +func NewBootstrapClient(id, password string) (BootstrapClient, error) { client := &bsClient{ - conf: conf, + id: id, + password: password, iotdaServer: newResult(), } @@ -64,27 +61,24 @@ func NewBootstrapClient(conf *BootstrapClientConfig) (BootstrapClient, error) { } type bsClient struct { - conf *BootstrapClientConfig + id string + password string client mqtt.Client // 使用的MQTT客户端 iotdaServer *Result // 设备接入平台地址 } func (bs *bsClient) init() (bool, error) { options := mqtt.NewClientOptions() - options.AddBroker(bs.conf.server) - options.SetClientID(createClientId(bs.conf.id)) - options.SetUsername(bs.conf.id) - options.SetPassword(hmacSha256(bs.conf.password, timeStamp())) + options.AddBroker(bsServer) + options.SetClientID(CreateMqttClientId(bs.id)) + options.SetUsername(bs.id) + options.SetPassword(hmacSha256(bs.password, timeStamp())) options.SetKeepAlive(250 * time.Second) options.SetAutoReconnect(true) options.SetConnectRetry(true) options.SetConnectTimeout(2 * time.Second) - ca, err := ioutil.ReadFile(bs.conf.caPath) - if err != nil { - glog.Error("load server ca failed\n") - return false, err - } + ca := []byte(bsServerCa) serverCaPool := x509.NewCertPool() serverCaPool.AppendCertsFromPEM(ca) @@ -98,11 +92,11 @@ func (bs *bsClient) init() (bool, error) { bs.client = mqtt.NewClient(options) if token := bs.client.Connect(); token.Wait() && token.Error() != nil { - glog.Warningf("device %s create bootstrap client failed,error = %v", bs.conf.id, token.Error()) + glog.Warningf("device %s create bootstrap client failed,error = %v", bs.id, token.Error()) return false, token.Error() } - downTopic := fmt.Sprintf("$oc/devices/%s/sys/bootstrap/down", bs.conf.id) + downTopic := fmt.Sprintf("$oc/devices/%s/sys/bootstrap/down", bs.id) subRes := bs.client.Subscribe(downTopic, 0, func(client mqtt.Client, message mqtt.Message) { go func() { fmt.Println("get message from bs server") @@ -127,7 +121,7 @@ func (bs *bsClient) init() (bool, error) { } func (bs *bsClient) Boot() string { - upTopic := fmt.Sprintf("$oc/devices/%s/sys/bootstrap/up", bs.conf.id) + upTopic := fmt.Sprintf("$oc/devices/%s/sys/bootstrap/up", bs.id) pubRes := bs.client.Publish(upTopic, 0, false, "") if pubRes.Wait() && pubRes.Error() != nil { fmt.Println(pubRes.Error()) @@ -146,22 +140,10 @@ type serverResponse struct { Address string `json:"address"` } -func createClientId(deviceId string) string { - segments := make([]string, 4) - segments[0] = deviceId - segments[1] = "0" - segments[2] = "0" - segments[3] = timeStamp() - - return strings.Join(segments, "_") -} - type Result struct { Flag chan int - err error mErr sync.RWMutex - res string mRes sync.RWMutex } @@ -172,13 +154,11 @@ func (b *Result) Value() string { return b.res } -// Wait implements the Token Wait method. func (b *Result) Wait() bool { <-b.Flag return true } -// WaitTimeout implements the Token WaitTimeout method. func (b *Result) WaitTimeout(d time.Duration) bool { timer := time.NewTimer(d) select { diff --git a/device.go b/device.go index c34ecbc..adf422f 100644 --- a/device.go +++ b/device.go @@ -518,6 +518,7 @@ func CreateIotDeviceWitConfig(config DeviceConfig) Device { device.CertFilePath = config.CertFilePath device.CertKeyFilePath = config.CertKeyFilePath + device.useBootstrap = config.UseBootstrap result := &iotDevice{ base: device, diff --git a/samples/bs/bootstrap_demo.go b/samples/bs/bootstrap_demo.go new file mode 100644 index 0000000..404d236 --- /dev/null +++ b/samples/bs/bootstrap_demo.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + iot "github.com/ctlove0523/huaweicloud-iot-device-sdk-go" + "time" +) + +func main() { + id := "611d13360ad1ed028658e089_zhou_sdk" + pwd := "12345678901234567890" + config := iot.DeviceConfig{ + Id: id, + Password: pwd, + UseBootstrap: true, + } + device := iot.CreateIotDeviceWitConfig(config) + initRes := device.Init() + fmt.Println(initRes) + + time.Sleep(1 * time.Minute) +} diff --git a/util.go b/util.go index 6c24725..3a7d717 100644 --- a/util.go +++ b/util.go @@ -61,3 +61,13 @@ func smartFileName(filename string) string { return filename } + +func CreateMqttClientId(deviceId string) string { + segments := make([]string, 4) + segments[0] = deviceId + segments[1] = "0" + segments[2] = "0" + segments[3] = timeStamp() + + return strings.Join(segments, "_") +}