10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Balenaを使ってラズパイアプリ開発

Last updated at Posted at 2020-07-19

image.png

ラズパイで動くアプリを開発したい

↑をやろうとしたとき2つのやり方があると思います

  • ラズパイ上で開発
    sshで接続してvimなどテキストエディタで開発
    :thumbsup: コードを書いたらすぐに実行できる
    :thumbsdown: 使い慣れた開発環境を使いづらい

  • PC上で開発
    :thumbsup: 使い慣れた開発環境、エディタを使える
    :thumbsdown: コードをすぐに実行できない、ラズパイに送って必要であればbuildしてなどが必要

そんなときにbalenaを使ってみましょうー

###balenaとは

  • ヨーロッパのスタートアップ(だったはず)
  • IoTのデバイス管理とアプリ開発サービス
  • dockerベースのソリューション
  • ローカルで書いたコードをcloud上にpushするとdocker buildしてデバイスにdeployしてくれる
  • アプリ10個まで無料(だったばず)

###開発の流れ

  1. cloud上でアプリを作る
  2. OSのimageファイルがダウンロードされる
  3. ダウンロードしたimageファイルをsdに焼いてラズパイを起動
  4. cloud上にラズパイが登録される
  5. 登録されたラズパイにコードをローカルからpush

初めての人は登録したら、Create applicationをクリックします。
登録はgoogleやgithubのアカウントでできます。

image.png

デバイスのタイプでラズパイを選択して名前をタイプして、applicationを作成します。

image.png

Add deviveを選択します。

image.png

Download balenaOSをクリックすると、imgファイルのダウンロードが始まります。

image.png

wifi + Ethernetを選択すると、SSIDとパスワードを設定済みのimgファイルを作成することもできます。
今回はEthernet onlyで行います。

image.png

ダウンロードが終わるのを待ちます。
image.png

ダウンロードしたらファイルを解凍して、

image.png

imgファイルを microsdに書き込みます。

image.png

書き込みが完了したらsdカードをラズパイに挿して電源を入れます。
しばらくすると balenaの画面上でラズパイが認識されます。

image.png

クリックするとlogやブラウザ上から接続できるコンソールがあります。
リブートやアプリの再起動も可能です。
これでアプリを作成する準備ができました。

image.png

documentのGet startedで使われている Balena Seed Projects、ようはひな型プロジェクトを使います。
今回は go を選択しました。

https://www.balena.io/docs/learn/more/examples/seed-projects/
https://www.balena.io/docs/learn/getting-started/raspberrypi3/go/

※github
https://github.com/balena-io-examples/balena-go-hello-world

↑これをlocalにcloneします。

C:\Users\k-satou\go\src\balena>git clone https://github.com/balena-io-examples/balena-go-hello-world.git
Cloning into 'balena-go-hello-world'...
remote: Enumerating objects: 56, done.
remote: Total 56 (delta 0), reused 0 (delta 0), pack-reused 56
Unpacking objects: 100% (56/56), done.

C:\Users\k-satou\go\src\balena>

appフォルダにあるmain.goファイルのソースはこんな感じです。
hello worldを返すhttpサーバですね。

main.go
package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello, world (from go!)\n"))
	})
	addr := ":80"
	fmt.Println("Example app listening on port ", addr)
	log.Fatal(http.ListenAndServe(addr, nil))
}

ではこれをラズパイで動かしたいわけですが、pushするためにlocal PCにbalena-cliをインストールしておきます。
お使いのOSに合わせてインストールしてください。

https://github.com/balena-io/balena-cli/releases
image.png

インストールしたら適時PATHに通して、balena loginと打って自分のアカウントでloginします。

C:\work>balena login
 _            _
| |__   __ _ | |  ____  _ __    __ _
| '_ \ / _` || | / __ \| '_ \  / _` |
| |_) | (_) || ||  ___/| | | || (_) |
|_.__/ \__,_||_| \____/|_| |_| \__,_|


Logging in to balena-cloud.com
? How would you like to login? Credentials
? Email: xxx@xxx.com
? Password: [hidden]
Successfully logged in as: g__xxx

Find out about the available commands by running:

  $ balena help

If you need help, or just want to say hi, don't hesitate in reaching out
through our discussion and support forums at https://forums.balena.io

For bug reports or feature requests, have a look at the GitHub issues or
create a new one at: https://github.com/balena-io/balena-cli/issues/

C:\work>

login成功したら balena apps と打つと自分の作成したアプリのlistが表示されます。

C:\work>balena apps
ID      APP NAME   DEVICE TYPE  ONLINE DEVICES DEVICE COUNT
1648225 raspberry  raspberrypi3 0              1
1706473 sample-app raspberrypi3 1              1

C:\work>

これで先ほどcloneしたアプリをpushできる準備が完了したので、pushしてみます。
git cloneしたフォルダに移動して、balena push <アプリ名> を実行します。

するとローカルのファイルがbalena cloud上に転送されてdocker buildが走ります。

C:\Users\k-satou\go\src\balena\balena-go-hello-world>balena push sample-app
[Info]     Starting build for sample-app, user g__610
[Info]     Dashboard link: https://dashboard.balena-cloud.com/apps/1706473/devices
[Info]     Building on arm01
[Info]     Pulling previous images for caching purposes...
[Success]  Successfully pulled cache images
[main]     Step 1/7 : FROM balenalib/raspberrypi3-golang:latest-build AS build
[main]      ---> 9a43177841ca
[main]     Step 2/7 : WORKDIR /go/src/github.com/balena-io-projects/app
[main]      ---> Running in 00561cfde90d
[main]     Removing intermediate container 00561cfde90d
[main]      ---> 5dbdd5316d49
[main]     Step 3/7 : COPY /app ./
[main]      ---> 6f05e3a48c17
[main]     Step 4/7 : RUN go build
[main]      ---> Running in 8a4652f7c303
[main]     Here are a few details about this Docker image (For more information please visit https://www.balena.io/docs/reference/base-images/base-images/):
[main]     Architecture: ARM v7
[main]     OS: Debian Buster
[main]     Variant: build variant
[main]     Default variable(s): UDEV=off
[main]     The following software stack is preinstalled:
[main]     Go v1.14.4
[main]     Extra features:
[main]     - Easy way to install packages with `install_packages <package-name>` command
[main]     - Run anywhere with cross-build feature  (for ARM only)
[main]     - Keep the container idling with `balena-idle` command
[main]     - Show base image details with `balena-info` command
[main]     Removing intermediate container 8a4652f7c303
[main]      ---> 9d859b2ad7eb
[main]     Step 5/7 : FROM balenalib/raspberrypi3-debian:stretch
[main]      ---> 28821f571ef5
[main]     Step 6/7 : COPY --from=build /go/src/github.com/balena-io-projects/app/ .
[main]      ---> dcd37d1557d0
[main]     Step 7/7 : CMD ./app
[main]      ---> Running in c468272913eb
[main]     Removing intermediate container c468272913eb
[main]      ---> fe8cabee2906
[main]     Successfully built fe8cabee2906
[Info]     Uploading images
[Success]  Successfully uploaded images
[Info]     Built on arm01
[Success]  Release successfully created!
[Info]     Release: 0c7a4625c2cf80962b4441a0ab8ff54b (id: 1464860)
[Info]     ┌─────────┬────────────┬────────────┐
[Info]     │ Service │ Image Size │ Build Time │
[Info]     ├─────────┼────────────┼────────────┤
[Info]     │ main    │ 134.59 MB  │ 49 seconds │
[Info]     └─────────┴────────────┴────────────┘
[Info]     Build finished in 1 minute, 11 seconds
                            \
                             \
                              \\
                               \\
                                >\/7
                            _.-(6'  \
                           (=___._/` \
                                )  \ |
                               /   / |
                              /    > /
                             j    < _\
                         _.-' :      ``.
                         \ r=._\        `.
                        <`\\_  \         .`-.
                         \ r-7  `-. ._  ' .  `\
                          \`,      `-.`7  7)   )
                           \/         \|  \'  / `-._
                                      ||    .'
                                       \\  (
                                        >\  >
                                    ,.-' >.'
                                   <.'_.''
                                     <'

C:\Users\k-satou\go\src\balena\balena-go-hello-world>

docker build に成功すると管理画面上でラズパイへのアプリのダウンロード、docker pullが行われます。

image.png

statusがOnlineになったら、アプリが動いているかラズパイのIPアドレスに curlコマンドを送ってみます。

image.png

ちゃんとレスポンスが返ってきました :heart_eyes:

C:\Users\k-satou\go\src\balena\balena-go-hello-world>curl 192.168.0.238
hello, world (from go!)

C:\Users\k-satou\go\src\balena\balena-go-hello-world>

あとはmain.goにコードを書いて balena push すれば簡単にローカルでアプリが開発できます。:thumbsup:

というわけでコードを変えてみます。
microbitとBLEでペアリングして温度を読み取ってみます。

micro:bitにはこのページを参考に作成したプログラムを書き込んでおきます。
https://sanuki-tech.net/micro-bit/bluetooth/temperature/

別のラズパイでスキャンして microbitのアドレスと温度の値を取得するUUIDを確認しておきます。
こちらの記事を参考にbluepyを入れたラズパイで確認しました。
https://qiita.com/FiveOne/items/ea04b74271da0f382ed6

pi@raspberrypi:ble $ sudo python3 scan.py
-----------------------------------
address  : d8:a4:8d:c5:c7:1d
addrType : random
RSSI     : -46
Adv data :
 (  1) Flags  : 06
 (  9) Complete Local Name  : BBC micro:bit [gatip]
pi@raspberrypi:ble $ sudo python3 getHandle.py d8:a4:8d:c5:c7:1d
------------------------------------------
 UUID : 00002a00-0000-1000-8000-00805f9b34fb
 Handle 0003 : READ WRITE
------------------------------------------
 UUID : 00002a01-0000-1000-8000-00805f9b34fb
 Handle 0005 : READ
------------------------------------------
 UUID : 00002a04-0000-1000-8000-00805f9b34fb
 Handle 0007 : READ
------------------------------------------
 UUID : 00002a05-0000-1000-8000-00805f9b34fb
 Handle 000A : INDICATE
------------------------------------------
 UUID : e95d93b1-251d-470a-a062-fa1922dfa9a8
 Handle 000E : READ WRITE
------------------------------------------
 UUID : e97d3b10-251d-470a-a062-fa1922dfa9a8
 Handle 0011 : WRITE NO RESPONSE NOTIFY
------------------------------------------
 UUID : 00002a24-0000-1000-8000-00805f9b34fb
 Handle 0015 : READ
------------------------------------------
 UUID : 00002a25-0000-1000-8000-00805f9b34fb
 Handle 0017 : READ
------------------------------------------
 UUID : 00002a26-0000-1000-8000-00805f9b34fb
 Handle 0019 : READ
------------------------------------------
 UUID : e95d9775-251d-470a-a062-fa1922dfa9a8
 Handle 001C : READ NOTIFY
------------------------------------------
 UUID : e95d5404-251d-470a-a062-fa1922dfa9a8
 Handle 001F : WRITE NO RESPONSE WRITE
------------------------------------------
 UUID : e95d23c4-251d-470a-a062-fa1922dfa9a8
 Handle 0021 : WRITE
------------------------------------------
 UUID : e95db84c-251d-470a-a062-fa1922dfa9a8
 Handle 0023 : READ NOTIFY
------------------------------------------
 UUID : e95dca4b-251d-470a-a062-fa1922dfa9a8
 Handle 0027 : READ NOTIFY
------------------------------------------
 UUID : e95dfb24-251d-470a-a062-fa1922dfa9a8
 Handle 002A : READ WRITE
------------------------------------------
 UUID : e95d7b77-251d-470a-a062-fa1922dfa9a8
 Handle 002D : READ WRITE
------------------------------------------
 UUID : e95d93ee-251d-470a-a062-fa1922dfa9a8
 Handle 002F : WRITE
------------------------------------------
 UUID : e95d0d2d-251d-470a-a062-fa1922dfa9a8
 Handle 0031 : READ WRITE
------------------------------------------
 UUID : e95d9250-251d-470a-a062-fa1922dfa9a8
 Handle 0034 : READ NOTIFY
------------------------------------------
 UUID : e95d1b25-251d-470a-a062-fa1922dfa9a8
 Handle 0037 : READ WRITE
pi@raspberrypi:ble $

goでBLE通信を行うためにgo-bleライブラリを利用して、sambleコードを参考に以下のようなコードにしました。
https://github.com/go-ble/ble

nameとUUIDに先ほどスキャンして調べたアドレスをセットしておきます。

main.go
package main

import (

    "context"
    "log"
    "strings"
    "time"
    "os"
    "os/signal"

    "github.com/go-ble/ble"
    "github.com/go-ble/ble/examples/lib/dev"

)

func main() {

    name := "d8:a4:8d:c5:c7:1d"
    sd := 5*time.Second
    ondo_uuid := "e95d6100251d470aa062fa1922dfa9a8"

    d, err := dev.NewDevice("raspberry")
    if err != nil {
        log.Fatalf("can't device : %s", err)
    }
    ble.SetDefaultDevice(d)

    filter := func(a ble.Advertisement) bool {
        return strings.ToUpper(a.Addr().String()) == strings.ToUpper(name)
    }

    log.Printf("Scannig for %s...\n", sd)
    ctx := ble.WithSigHandler(context.WithTimeout(context.Background(), sd))
    cln, err := ble.Connect(ctx, filter)
    if err != nil {
        log.Fatalf("can't connect : %s", err)
    }

    done := make(chan struct{})
    go func() {
        <-cln.Disconnected()
        log.Printf("%s is disconnected \n", cln.Addr())
        close(done)
    }()

    log.Printf("Discovering profile...\n")
    p, err := cln.DiscoverProfile(true)
    if err != nil {
        log.Fatalf("can't discover profile: %s", err)
    }

    var chara *ble.Characteristic

    for _, s := range p.Services {
        if ondo_uuid == s.UUID.String() {
            chara = s.Characteristics[0]
        }
    }

    read, err := cln.ReadCharacteristic(chara)
    if err != nil {
        log.Fatalf("read characterristic is err: %s", err)
    }
    for {
        log.Println("read data: ", read)
        time.Sleep(3 * time.Second)
    }

    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt)
    go func() {
        for sig := range quit {
            log.Println("Signal catch: ", sig)
            close(quit)
            os.Exit(130)
        }
    }()
    log.Printf("Disconnecting %s ...", cln.Addr())
    cln.CancelConnection()

    <-done

}

Dockerfileにライブラリをgo getするように追加します。

FROM balenalib/%%BALENA_MACHINE_NAME%%-golang:latest-build AS build

WORKDIR /go/src/github.com/balena-io-projects/app

RUN go get github.com/go-ble/ble && go get github.com/mgutz/logxi/v1 && go get golang.org/x/sys/unix

COPY /app ./

RUN CGO_ENABLED=0 go build

FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:stretch

COPY --from=build /go/src/github.com/balena-io-projects/app/ .

CMD ./app

ではこれをbalena pushしてみます。

C:\Users\k-satou\go\src\balena\balena-go-hello-world>balena push sample-app
[Info]     Starting build for sample-app, user g__610
[Info]     Dashboard link: https://dashboard.balena-cloud.com/apps/1706473/devices
[Info]     Building on arm01
[Info]     Pulling previous images for caching purposes...
[Success]  Successfully pulled cache images
[main]     Step 1/7 : FROM balenalib/raspberrypi3-golang:latest-build AS build
[main]      ---> 9a43177841ca
[main]     Step 2/7 : WORKDIR /go/src/github.com/balena-io-projects/app
[main]      ---> Running in 00561cfde90d
[main]     Removing intermediate container 00561cfde90d
[main]      ---> 5dbdd5316d49
[main]     Step 3/7 : COPY /app ./
[main]      ---> 6f05e3a48c17
[main]     Step 4/7 : RUN go build
[main]      ---> Running in 8a4652f7c303
[main]     Here are a few details about this Docker image (For more information please visit https://www.balena.io/docs/reference/base-images/base-images/):
[main]     Architecture: ARM v7
[main]     OS: Debian Buster
[main]     Variant: build variant
[main]     Default variable(s): UDEV=off
[main]     The following software stack is preinstalled:
[main]     Go v1.14.4
[main]     Extra features:
[main]     - Easy way to install packages with `install_packages <package-name>` command
[main]     - Run anywhere with cross-build feature  (for ARM only)
[main]     - Keep the container idling with `balena-idle` command
[main]     - Show base image details with `balena-info` command
[main]     Removing intermediate container 8a4652f7c303
[main]      ---> 9d859b2ad7eb
[main]     Step 5/7 : FROM balenalib/raspberrypi3-debian:stretch
[main]      ---> 28821f571ef5
[main]     Step 6/7 : COPY --from=build /go/src/github.com/balena-io-projects/app/ .
[main]      ---> dcd37d1557d0
[main]     Step 7/7 : CMD ./app
[main]      ---> Running in c468272913eb
[main]     Removing intermediate container c468272913eb
[main]      ---> fe8cabee2906
[main]     Successfully built fe8cabee2906
[Info]     Uploading images
[Success]  Successfully uploaded images
[Info]     Built on arm01
[Success]  Release successfully created!
[Info]     Release: 0c7a4625c2cf80962b4441a0ab8ff54b (id: 1464860)
[Info]     ┌─────────┬────────────┬────────────┐
[Info]     │ Service │ Image Size │ Build Time │
[Info]     ├─────────┼────────────┼────────────┤
[Info]     │ main    │ 134.59 MB  │ 49 seconds │
[Info]     └─────────┴────────────┴────────────┘
[Info]     Build finished in 1 minute, 11 seconds
                            \
                             \
                              \\
                               \\
                                >\/7
                            _.-(6'  \
                           (=___._/` \
                                )  \ |
                               /   / |
                              /    > /
                             j    < _\
                         _.-' :      ``.
                         \ r=._\        `.
                        <`\\_  \         .`-.
                         \ r-7  `-. ._  ' .  `\
                          \`,      `-.`7  7)   )
                           \/         \|  \'  / `-._
                                      ||    .'
                                       \\  (
                                        >\  >
                                    ,.-' >.'
                                   <.'_.''
                                     <'

/ Packaging the project source...[Warn]    CRLF (Windows) line endings detected in file: C:\Users\k-satou\go\src\balena\balena-ble\Dockerfile.template
[Warn]    CRLF (Windows) line endings detected in file: C:\Users\k-satou\go\src\balena\balena-ble\.gitignore
[Warn]    CRLF (Windows) line endings detected in file: C:\Users\k-satou\go\src\balena\balena-ble\README.md
[Warn]    CRLF (Windows) line endings detected in file: C:\Users\k-satou\go\src\balena\balena-ble\LICENSE
[Info]     Starting build for sample-app, user g__610
[Info]     Dashboard link: https://dashboard.balena-cloud.com/apps/1706473/devices
[Info]     Building on arm03
[Info]     Pulling previous images for caching purposes...
[Success]  Successfully pulled cache images
[main]     Step 1/8 : FROM balenalib/raspberrypi3-golang:latest-build AS build
[main]      ---> 9a43177841ca
[main]     Step 2/8 : WORKDIR /go/src/github.com/balena-io-projects/app
[main]     Using cache
[main]      ---> 75fe37fd7909
[main]     Step 3/8 : RUN go get github.com/go-ble/ble && go get github.com/mgutz/logxi/v1 && go get golang.org/x/sys/unix
[main]      ---> Running in 8327007ce2e9
[main]     Here are a few details about this Docker image (For more information please visit https://www.balena.io/docs/reference/base-images/base-images/):
[main]     Architecture: ARM v7
[main]     OS: Debian Buster
[main]     Variant: build variant
[main]     Default variable(s): UDEV=off
[main]     The following software stack is preinstalled:
[main]     Go v1.14.4
[main]     Extra features:
[main]     - Easy way to install packages with `install_packages <package-name>` command
[main]     - Run anywhere with cross-build feature  (for ARM only)
[main]     - Keep the container idling with `balena-idle` command
[main]     - Show base image details with `balena-info` command
[main]     Removing intermediate container 8327007ce2e9
[main]      ---> 9cb3a5decba6
[main]     Step 4/8 : COPY /app ./
[main]      ---> 4be0eea56236
[main]     Step 5/8 : RUN CGO_ENABLED=0 go build
[main]      ---> Running in db32f2e9a080
[main]     Removing intermediate container db32f2e9a080
[main]      ---> 215778d493a4
[main]     Step 6/8 : FROM balenalib/raspberrypi3-debian:stretch
[main]      ---> 28821f571ef5
[main]     Step 7/8 : COPY --from=build /go/src/github.com/balena-io-projects/app/ .
[main]      ---> 0d20d73a9424
[main]     Step 8/8 : CMD ./app
[main]      ---> Running in ecde7b0d4c05
[main]     Removing intermediate container ecde7b0d4c05
[main]      ---> 53a772a2b1ed
[main]     Successfully built 53a772a2b1ed
[Info]     Generating image deltas from release 0c7a4625c2cf80962b4441a0ab8ff54b (id: 1464860)
[Success]  Successfully generated image deltas
[Info]     Uploading images
[Success]  Successfully uploaded images
[Info]     Built on arm03
[Success]  Release successfully created!
[Info]     Release: 5a7247943dfa1359b49fa6676e16129b (id: 1464893)
[Info]     ┌─────────┬────────────┬────────────┬────────────┐
[Info]     │ Service │ Image Size │ Delta Size │ Build Time │
[Info]     ├─────────┼────────────┼────────────┼────────────┤
[Info]     │ main    │ 131.63 MB  │ 3.08 MB    │ 46 seconds │
[Info]     └─────────┴────────────┴────────────┴────────────┘
[Info]     Build finished in 2 minutes,
                            \
                             \
                              \\
                               \\
                                >\/7
                            _.-(6'  \
                           (=___._/` \
                                )  \ |
                               /   / |
                              /    > /
                             j    < _\
                         _.-' :      ``.
                         \ r=._\        `.
                        <`\\_  \         .`-.
                         \ r-7  `-. ._  ' .  `\
                          \`,      `-.`7  7)   )
                           \/         \|  \'  / `-._
                                      ||    .'
                                       \\  (
                                        >\  >
                                    ,.-' >.'
                                   <.'_.''
                                     <'
[Warn]    Windows-format line endings were detected in some files. Consider using the `--convert-eol` option.

C:\Users\k-satou\go\src\balena\balena-ble>

先ほどまでアプリに代わり新しいアプリがインストールされました。
microbitとペアリングして正常に温度を読み取れているようです。
image.png

というわけでこのようにbalena cloudを利用することでIoTアプリの開発がスムーズに行えるかと思います。
ぜひ試してみてはいかがでしょうか。

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?