今までは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作成
今回は温度湿度の情報を使用したいと思います。
温度湿度計の設定は上記の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の詳細はこちら
次にWebサーバーの公開用ディレクトリにDHT11_Pythonのディレクトリごと移動させます。Webサーバーのインストールはこちら(ちなみに自動でWebサーバーを構築するスクリプトもあります)
今回は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というホスト名を使用します。
ここにホスト名の設定方法が詳しく書いてあります。
8,URLからダウンロードします。
9,このままだとjsonのままなので、JSONDecoderを使用してSwift用にデコードします。
10,thdataに代入します。
11,エラーが発生した時の処理です。コンソールに出力されます。
ビルドして実行すると変化を確認することができます。