Go2 Advent Calender 16日目です。

以下の記事を見てからMQTTで遊ぶのがブームになっています。

http://monoist.atmarkit.co.jp/mn/series/3293/

Windows10とmosquittoでローカルで試してみて最終的にAWS IoTに
Publishしてみました。

普通にPublish

まずはpahoライブラリをgo getしてローカルでPublishしてみます。

package main

import (
    "fmt"
    MQTT "github.com/eclipse/paho.mqtt.golang"
)

func main () {

    const MQTT_BROKER = "tcp://127.0.0.1:1883"
    opts := MQTT.NewClientOptions().AddBroker(MQTT_BROKER)
    opts.SetClientID("localhost")
    client := MQTT.NewClient(opts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        fmt.Println("Error %s\n", token.Error())
    }

    token := client.Publish("test", 0, false, "{\"message\":\"hello\"}")
    token.Wait()

    client.Disconnect(250)

}

2017-12-15_23h34_47.png

実行→送信できました。

TLSでPublish

AWS IoTにデータを送信するにはTLS接続が必要です。
ローカルでTLS接続ができるか試してみます。
以下を参考にオレオレ証明書を作成してmosquitto.confの末尾にセットしました。

https://mosquitto.org/man/mosquitto-tls-7.html

listener 8883
cafile certs/ca.crt
certfile certs/server.crt
keyfile certs/server.key

go getしたpahoのライブラリの中にSSLのサンプルがあります。
keyファイルをセットするところを自分で作成したものに置き換えました。

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"

    MQTT "github.com/eclipse/paho.mqtt.golang"
)

func NewTLSConfig() *tls.Config {
    certpool := x509.NewCertPool()
    pemCerts, err := ioutil.ReadFile("ca.crt")
    if err == nil {
        certpool.AppendCertsFromPEM(pemCerts)
    }

    cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
    if err != nil {
        panic(err)
    }

    cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
    if err != nil {
        panic(err)
    }

    return &tls.Config{
        RootCAs: certpool,
        ClientAuth: tls.NoClientCert,
        ClientCAs: nil,
        InsecureSkipVerify: true,
        Certificates: []tls.Certificate{cert},
    }
}

var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
    fmt.Printf("TOPIC: %s\n", msg.Topic())
    fmt.Printf("MSG: %s\n", msg.Payload())
}

func main() {
    tlsconfig := NewTLSConfig()

    opts := MQTT.NewClientOptions()
    opts.AddBroker("ssl://127.0.0.1:8883")
    opts.SetClientID("ssl-sample").SetTLSConfig(tlsconfig)
    opts.SetDefaultPublishHandler(f)

    c := MQTT.NewClient(opts)
    if token := c.Connect(); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }

    c.Publish("/go-mqtt/sample", 0, false, "Test Message")
    c.Disconnect(250)
}

2017-12-16_00h08_46.png

実行→送信できました。

AWS IoTにPublish

それではAWS IoTにPublishしてみます。

モノや証明書の作成とアタッチ、ポリシーの作成などの準備は公式docや他の方の記事を参照してください。
ローカルでTLS接続したファイルから証明書をセットするところをAWSから落としてきたファイルに差し替えて実行します。

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"

    MQTT "github.com/eclipse/paho.mqtt.golang"
)

func NewTLSConfig() *tls.Config {
    // Import trusted certificates from CAfile.pem.
    // Alternatively, manually add CA certificates to
    // default openssl CA bundle.
    certpool := x509.NewCertPool()
    pemCerts, err := ioutil.ReadFile("xxxxxxxxx.pem")
    if err == nil {
        certpool.AppendCertsFromPEM(pemCerts)
    }

    // Import client certificate/key pair
    cert, err := tls.LoadX509KeyPair("xxxxxxxxx-certificate.pem.crt", "xxxxxxxxx-private.pem.key")
    if err != nil {
        panic(err)
    }

    // Just to print out the client certificate..
    cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
    if err != nil {
        panic(err)
    }
    //fmt.Println(cert.Leaf)

    // Create tls.Config with desired tls properties
    return &tls.Config{
        // RootCAs = certs used to verify server cert.
        RootCAs: certpool,
        // ClientAuth = whether to request cert from server.
        // Since the server is set up for SSL, this happens
        // anyways.
        ClientAuth: tls.NoClientCert,
        // ClientCAs = certs used to validate client cert.
        ClientCAs: nil,
        // InsecureSkipVerify = verify that cert contents
        // match server. IP matches what is in cert etc.
        InsecureSkipVerify: true,
        // Certificates = list of certs client sends to server.
        Certificates: []tls.Certificate{cert},
    }
}

var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
    fmt.Printf("TOPIC: %s\n", msg.Topic())
    fmt.Printf("MSG: %s\n", msg.Payload())
}

func main() {
    tlsconfig := NewTLSConfig()

    opts := MQTT.NewClientOptions()
    opts.AddBroker("ssl://xxxxxxxxxxxxxxxxxxx.amazonaws.com:8883")
    opts.SetClientID("ssl-sample").SetTLSConfig(tlsconfig)
    opts.SetDefaultPublishHandler(f)

    // Start the connection
    c := MQTT.NewClient(opts)
    if token := c.Connect(); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }
    fmt.Println("AWS IoT Connect")

    if token := c.Publish("$aws/things/ESP32/shadow/update", 0, false,
        `{"state":{"reported":{"welcome":"I am gopher!!!"}}}`); token.Wait() && token.Error() != nil {
                panic(token.Error())
    }
    fmt.Println("Message Publish")
    c.Disconnect(250)
}

2017-12-16_20h13_56.png

1216.PNG

AWS IoTにPublishしてシャドウステータスを更新できました。
これでラズパイからgolangでAWS IoTにいろいろとデータを飛ばせますね。

飛ばすところまでやれってところですが。。。