SwiftUI

SwiftUIでRaspberryPiのデータを取得する

今まではRaspberryPiの記録した温度や湿度などといったデータはsshもしくはWebから取得してきました。

しかし、この方法では作った本人はどのように操作すればいいかわかりますが、初めてみた人にとっては使いにくいものとなっています。

そこで、今回はiOS、Mac OSのプログラミング言語の一つであるSwiftUIでRaspberyPiの情報を取得できるようにしたいと思います。

仕組み

今回は、データを通信する仕組みとしてjsonを使用したいと思います。

jsonはこのような書き方になっています。

[

    {
        "name": "raspi",
        "userid": "1222"
    },
    {
        "name": "blog"
        "userid": "324"
    }
]

今回はRaspberyPiのPythonを使用してjsonを作成し、Webサーバーで公開、SwiftUIでそのデータを取得し、表示しようと思います。

Pythonでのjson作成

今回は温度湿度の情報を使用したいと思います。

RaspberryPiで温度と湿度を測ってみるそろそろ暑くなり始める季節ですよね。気温が身近に測れない場合、いつ頃エアコンをつければいいかわからないこともあります。 な...

温度湿度計の設定は上記のURLから行なってください。

温度湿度計のコードは次のものです。

# [Pure Python library for reading DHT11 sensor on Raspberry Pi ] | [MIT license] | [https://github.com/szazo/DHT11_Python/blob/master/LICENSE.md] 
import RPi.GPIO as GPIO
import dht11
import time
import datetime

# initialize GPIO
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)

# read data using pin 14
instance = dht11.DHT11(pin=14)

try:
    while True:
        result = instance.read()
        if result.is_valid():
            print("Last valid input: " + str(datetime.datetime.now()))

            print("Temperature: %-3.1f C" % result.temperature)
            print("Humidity: %-3.1f %%" % result.humidity)

        time.sleep(6)

except KeyboardInterrupt:
    print("Cleanup")
    GPIO.cleanup()

ここに、jsonに書き込むプログラムを追加します。

jsonを使用するにはPythonでjsonというモジュールをインポートします。

import json

jsonは辞書式としてPythonで定義した変数を代入する形になるので、変数を設定するときに温度や湿度の情報を入力します。

全部のコードはこちら

# [Pure Python library for reading DHT11 sensor on Raspberry Pi ] | [MIT license] | [https://github.com/szazo/DHT11_Python/blob/master/LICENSE.md] 
import RPi.GPIO as GPIO
import dht11
import time
import datetime
import json

# initialize GPIO
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)

# read data using pin 14
instance = dht11.DHT11(pin=14)

try:
    while True:
        result = instance.read()
        if result.is_valid():
            print("Last valid input: " + str(datetime.datetime.now()))

            print("Temperature: %-3.1f C" % result.temperature)
            print("Humidity: %-3.1f %%" % result.humidity)
            data = {"temperature": result.temperature", "humidity": result.humidity}
            with open('temphum.json', 'w') as fp:
                json.dump(data, fp, indent=4)
        time.sleep(6)

except KeyboardInterrupt:
    print("Cleanup")
    GPIO.cleanup()

このコードをDHT11_Pythonのディレクトリの中で作成します。

# nano temphumAPI.py

nanoの詳細はこちら

「nano」コマンドnanoコマンドはファイルを編集するためのコマンドです。通常のテキストエディットなどと違い、コンソール上で使用します。 ...

次にWebサーバーの公開用ディレクトリにDHT11_Pythonのディレクトリごと移動させます。Webサーバーのインストールはこちら(ちなみに自動でWebサーバーを構築するスクリプトもあります)

RaspberryPiにApache2とPHPをインストールする前の記事にRaspbeeryPiにnginxとPHPをインストールするという記事を書きましたが、今回はレンタルサーバーなどで広く使われて...
ShellScriptでLinuxに自動でWebサーバーを立ち上げるプログラムを作るRaspberryPiやLinuxの環境でWebサーバーを作りたいけどめんどくさいという方のために自動でパッケージのアップデートからWe...

今回はapache2を使用しています。PHPは必要ないのでインストールしなくても大丈夫です。

この場合の公開用ディレクトリは/var/www/htmlなのでここにAPIというディレクトリを作成します。

$ cd /var/www/html
$ sudo mkdir API && cd API
$ sudo mv /home/pi/DHT11_Python DHT11_Python

これで準備は完了です。

プログラムの実行

それでは実際に実行してみましょう。このプログラムはsudoで実行しないと/var/www/html/APIへの書き込み権限がないので実行できません。

$ sudo python temphumAPI.py

すると、同じディレクトリにtemphum.jsonが生成されます。

$ cat temphum.json
{
    "temperature": 18.0,
    "humidity": 21.0
}

しっかり実行できています。

次にSwiftUIの方です。

SwiftUIでのデータ受け取り

次にSwiftUIでjsonを受け取ります。今回はiPhone用として作りたいと思います。

全体のコード

import SwiftUI




struct ContentView: View {
    @State private var thdata: THData = THData(temperature: 0.0, humidity: 0.0)
//1,ダウンロードしたデータを格納する変数の作成
    struct THData: Codable {
        var temperature: Float
        var humidity: Float
    }
//2,辞書式変数の作成
    @State var readstart:Bool = false
    @State var infinity:Bool = true
    @State var timer:Timer?
    @State var urlCache:URLCache?
//3,必要な変数の作成
    var body: some View {
        
        VStack {
            Button("Read Start") {
                infinity = true
                print(thdata)
                getData()
                
                timer = Timer.scheduledTimer(withTimeInterval: 6.5, repeats: true) { _ in
                    getData()
                }
                //4,6.5秒に1回データを取得する
                
            }
            .font(.largeTitle)
            .foregroundColor(.white)
            .frame(width: 300, height: 100, alignment: .center)
            .background(Color.orange)
            Button("Read Stop") {
                timer?.invalidate()
//5,タイマーの終了
            }
            .font(.largeTitle)
            .foregroundColor(.white)
            .frame(width: 300, height: 100, alignment: .center)
            .background(Color.gray)
            
            Text("\(thdata.temperature)")
                .font(.largeTitle)
                .foregroundColor(.white)
                .frame(width: 300, height: 100, alignment: .center)
                .background(Color.pink)
            Text("\(thdata.humidity)")
                .font(.largeTitle)
                .foregroundColor(.white)
                .frame(width: 300, height: 100, alignment: .center)
                .background(Color.brown)
            
        }
    }
    func getData() {
        
        urlCache = nil
//6,キャッシュを作らないようにする
        guard let url = URL(string: "http://raspberrypi.local/API/DHT11_Python/temphum.json") else { return }
//7,URLの設定
        URLSession.shared.dataTask(with: url) {(data, response, error) in
//8,URLからダウンロード
            do {
                if let thData = data {
                    let decoder = JSONDecoder()
                    let decodedData:THData = try decoder.decode(THData.self, from: data!)
//9,json形式からSwiftの辞書式にデコード
                    print(thData)
                    print(decodedData)
                    
                    self.thdata = decodedData
//10,thdataに代入
                    print(thdata)
                } else {
                    print("No data", data as Any)
                }
            } catch {
                print("Error", error)
            }
//11,エラー時の処理
        }.resume()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}



1,ダウンロードしたデータを変数として扱うために変数を作成します。

2,jsonがどのような形式だったかで変わってきます。今回はjsonがこのような形式でした。

{
    "temperature": 18.0,
    "humidity": 21.0
}

そのため、変数はFloatで定義します。もっと精度が必要ならDoubleで。

3,timerはscheduledTimerという一定の時間ごとに処理を実行するメゾットを使用するために使います。

urlCacheはURLSessionがキャッシュを使用しないように使います。キャッシュを使ってしまうと温度と湿度が一向に変わらない事態が起きます。

4,scheduledTimerの出番です。withTimeInterval: [待ちたい時間]

あまり早すぎるとRaspberryPiのWebサーバーが落ちる可能性があります。

Sleepだと画面が更新されないのでこれを使うことにしました。

5,Read Stopをタップしたときにタイマーが終了され、データの取得が終了します。

6,urlCacheをnilに設定するとキャッシュを生成しないようになります。

7,URLSessionを使用してraspberryPiのjsonを設定します。IPアドレスでもいいですが、IPアドレスが変わるたびに設定し直すのは面倒なので、raspberrypi.localというホスト名を使用します。

RaspberryPiでwebサーバーを作ってみる 今回は、RaspberryPiでwebサーバーを作ってみたいと思います。今回作るwebサーバーはルーターなどの設定を変えない限り、外部...

ここにホスト名の設定方法が詳しく書いてあります。

8,URLからダウンロードします。

9,このままだとjsonのままなので、JSONDecoderを使用してSwift用にデコードします。

10,thdataに代入します。

11,エラーが発生した時の処理です。コンソールに出力されます。

ビルドして実行すると変化を確認することができます。

 

 

連絡

記事について何か疑問に思ったこと、うまく動かなくなっているところ、誤字脱字、感想などはコメント欄は廃止したのでTwitterのDMもしくは@blog_raspiでツイートしてください。できる限り見ると思います。(今のところ誰からも来ないから大丈夫)(誰かツイートしてーー(´;ω;`))

COMMENT

メールアドレスが公開されることはありません。