「温度管理システム的なものを作ってみる」の3回目です。前回はArduinoで温度データを取得する内容についてでした。今回はそのArduinoから温度データを取得するスマホ(Android)のアプリについてです。ここでのスクリーンショットはそのアプリの画面です。AndroidでArduinoとのシリアル通信を行うためのドライバは以下からのエントリで書きました。ここでもこのドライバ、ライブラリを使います。
AndroidでUSBシリアル通信(その1)ハードウェア・ソフトウェア構成等
ここでは上記のシリーズからの応用的な展開としてAndroidアプリでのArduinoから温度データを取得する通信処理について書きたいと思います。
通信といいましても、Android側からTという文字を送信してArduinoから送信される温度データを受信するだけのシンプルな送受信です。これをボタンをタッチしたら実行するという処理を実装します。
実際のプログラムの説明に入る前にですが、今回の「温度管理システム」という中ではAndroidアプリは取得した温度データをCloudへ送信するという機能もあります。(スクリーンショットの登録実行ボタンでの処理です。)この部分はCloudのプログラムについて書いた後に書きます。
それではプログラムについてですが、以下のエントリで書いた内容が基本になります。
AndroidでUSBシリアル通信(その4)ライブラリサンプルの内容
最初に認識したドライバ(ここではArduinoとのUSBケーブルのドライバ)を使って通信をします。ドライバは種類を意識しないで UsbSerialDriver クラスを使います。このクラスのopen()、close()、write()あたりを使います。実際は、SerialInputOutputManagerクラスを使ってスレッドで送受信を行います。listenerを定義して、データを受信した際の処理を実装します。やはり説明より実際に見て頂いた方がいいでしょうか。以下がこのあたりの処理です。ここでは1回の処理ごとにオープン、クローズで完結しています。
ソース全体は以下からダウンロード出来ます。位置情報の取得やCloudへの登録処理も含まれています。
(※念のためですが一切動作保証はしておりません。サンプルプログラムのレベルです。)
ソースファイル一式(USB Serialライブラリは含まれていません。)
インスタンス変数
//通信関連 private UsbSerialDriver usb = null; private SerialInputOutputManager serialIoManager; private final ExecutorService executor = Executors.newSingleThreadExecutor(); //受信データ関連 private int responseCounter; //レスポンスの現在位置の読み込み用 private byte[] response; private final int buflen = 100; //とりあえず
listenerの定義
/** * シリアル入出力 Listener */ private final SerialInputOutputManager.Listener mListener = new SerialInputOutputManager.Listener() { @Override public void onRunError(Exception e) { tvMsg.setText("通信エラーが発生しました。" + e.getMessage()); try { usb.close(); } catch (IOException e1) { } serialIoManager.stop(); } public void onNewData(final byte[] data) { runOnUiThread(new Runnable() { @Override public void run() { updateReceivedData(data); } }); } };
ドライバ取得
/** * ドライバの取得 */ private void getUsbDriver(){ UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); List<UsbSerialDriver> drvs = new ArrayList<UsbSerialDriver>(); if(manager.getDeviceList().size() == 0){ return; } //ドライバを取得する //最初のドライバを利用する for (UsbDevice device : manager.getDeviceList().values()) { List<UsbSerialDriver> drivers = UsbSerialProber.probeSingleDevice(manager, device); if (!drivers.isEmpty()) { for (UsbSerialDriver driver : drivers) { drvs.add(driver); } } } usb = drvs.get(0); }
通信開始処理
/** * 温度データの取得 */ private void getTempData(){ try{ if(usb == null){ getUsbDriver(); } } catch(Exception e){ tvMsg.setText("ケーブルを再度接続して下さい。"); btnGetTemp.setEnabled(false); return; } if (usb == null) { tvMsg.setText("ケーブルが認識出来ません。"); return; } //接続の開始 try{ response = null; response = new byte[buflen]; usb.open(); usb.setParameters(9600, 8, UsbSerialDriver.STOPBITS_1, UsbSerialDriver.PARITY_NONE); serialIoManager = new SerialInputOutputManager(usb, mListener); executor.submit(serialIoManager); try { String cmd = "t"; usb.write(cmd.getBytes(), 10000); } catch (Exception e) { tvMsg.setText("送信処理でエラーが発生しました。" + e.getMessage()); serialIoManager.stop(); serialIoManager = null; try { usb.close(); usb = null; } catch (IOException ex) { } } } catch(IOException e){ tvMsg.setText("送信処理で入出力エラーが発生しました。" + e.getMessage()); } }
データ受信時の処理
/** * シリアル通信の受信時の処理 * @param data */ private void updateReceivedData(byte[] data) { //tvMsg.setText("受信した。"); //受信データ取得 boolean bCR = false; for(int i=0; i<data.length; i++){ response[responseCounter] = data[i]; responseCounter++; if(data[i] == '\n'){ bCR = true; } } if(bCR) { try { String value = new String(response, "US-ASCII"); //tvMsg.setText(value); tvTemp.setText(getString(R.string.label_temp) + value); temperature = Double.parseDouble(value); serialIoManager.stop(); serialIoManager = null; try { usb.close(); usb = null; tvMsg.setText("温度データを取得しました。"); bTemp = true; } catch (IOException e1) { } } catch (UnsupportedEncodingException e) { //e.printStackTrace(); } } }
実際にArduinoを接続した状態で動作させた画面が以下です。(※ページ先頭のスクリーンショットと同じです。)この温度を取得するのボタンで温度の取得を実行します。
今回はここまでです。次回は、Cloud(Microsoft Azure)での処理についてです。Cloudでは温度データ、位置データを保存して表示します。