2017年11月18日、19日に実施された「東北Tech道場 郡山道場 第8回」の作業内容の続きをまとめます。
とりあえず、発表会用のRaspbery pi3側のプログラムは完成しましたが、スマホ側がほとんど手付かずです。最初はXamarinでAndroidとiPhoneの両端末に対応させる予定でしたが、もうそんなことは言っていられません。DorebellにAndroid端末用のソースも入っているので、それを一部修正してスマホでFirebeceの内容を確認するだけにしました。
#1.スマホ側の処理を作成
Doorbellの「companionApp」をそのまま流用しますが、以下の点を変更しました。
##(1) パッケージ名とクラス名の変更
- パッケージ名を変更
- DoorbellEntry → CatFansEntry に変更
- DoorbellEntryAdapter → CatFansEntryAdapter に変更
##(2) 注釈の表示を削除
Doorbellで行っている注釈のTextViewへの表示部分を削除する。
###(i) CatFansEntryAdapterの修正
TextViewへの表示部分を削除する。なお、同時に時刻の表示を「年/月/日 時:分:秒」形式にする。
package xxxxxx.catfans;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Base64;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.google.firebase.database.DatabaseReference;
import java.text.SimpleDateFormat;
/**
* RecyclerView adapter to populate CatFans entries from Firebase.
*/
public class CatFansEntryAdapter extends FirebaseRecyclerAdapter<CatFansEntry, CatFansEntryAdapter.CatFansEntryViewHolder> {
/**
* ViewHolder for each CatFans entry
*/
public static class CatFansEntryViewHolder extends RecyclerView.ViewHolder {
public final ImageView image;
public final TextView time;
public CatFansEntryViewHolder(View itemView) {
super(itemView);
this.image = (ImageView) itemView.findViewById(R.id.imageView1);
this.time = (TextView) itemView.findViewById(R.id.textView1);
}
}
private Context mApplicationContext;
public CatFansEntryAdapter(Context context, DatabaseReference ref) {
super(CatFansEntry.class, R.layout.catfans_entry, CatFansEntryViewHolder.class, ref);
mApplicationContext = context.getApplicationContext();
}
@Override
protected void populateViewHolder(CatFansEntryViewHolder viewHolder, CatFansEntry model, int position) {
// Display the timestamp
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String tm = sdf.format(model.getTimestamp());
viewHolder.time.setText(tm);
// Display the image
if (model.getImage() != null) {
// Decode image data encoded by the Cloud Vision library
byte[] imageBytes = Base64.decode(model.getImage(), Base64.NO_WRAP | Base64.URL_SAFE);
Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
if (bitmap != null) {
viewHolder.image.setImageBitmap(bitmap);
} else {
Drawable placeholder =
ContextCompat.getDrawable(mApplicationContext, R.drawable.ic_image);
viewHolder.image.setImageDrawable(placeholder);
}
}
}
}
###(ii) catfans_entry.xml の修正
以下のように変更して、タイムスパンと画像のみ表示するようにする。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:gravity="center_horizontal">
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:textStyle="bold" />
<ImageView
android:layout_width="320dp"
android:layout_height="240dp"
android:id="@+id/imageView1" />
</LinearLayout>
###(iii) 確認画面
スマホで確認すると次のようになる。
#2. ハードの状態
ハードウェアの方も組み立て終わり、出来上がってきました。
##(1) 駆動部分
#3. 不具合発生
##(1) 「カメラのパーミッションが無い」というエラーに遭遇
システムの方は機能限定ながらも動くようになり、発表会直前で稼働中の動画を撮ろうという段階になって、なんとシステムが動かなくなってしまいました。原因を探ると、「CatFansActivityクラス」の「onCreateメソッド」の以下の部分でreturnしていることがわかりました。
// カメラにアクセスするための許可が必要
if (checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// 権限を自動付与する際に問題が発生した
Log.d(TAG, "No permission");
return;
}
今まで動いていたわけですから、当然、AndroidManifest.xmlには、
<uses-permission android:name="android.permission.CAMERA" />
の記述があります。なんでパーミッションが無いと判定されるのか全く分かりません。10回実行して1回くらいは成功するという状態になってしまいました。何度も繰り返し実行して、なんとかプレゼン用の動画を撮って発表会を迎えます。
##(2) 原因究明
このエラーの原因を探るために以下のことを試しました。
- Android Things を再起動する。
- Doorbell を試す。
- Raspbery pi3 を取り換える。
- カメラを取り換える。
- 電源コードを取り換える。
- Android Thingsを最新バージョン(Android Things DP 0.6.0)にバージョンUPする。
しかし、いずれも失敗に終わりました。オリジナルのDorebellでさえパーミッションが無いとエラー落ちするのです。さっぱり原因がわかりません。
##(3) 対処法
でも、このままでは開発を続けられないので、以下のようにコマンドラインで直接Android Thingsにカメラのパーミッションを与えることにしました。
- 一旦、android studioでプロジェクトを実行する。
- 1回目はパーミッションが不許可なので、そのままエラー終了する。
- コマンドプロンプトで以下のコマンドを実行する。
adb shell pm grant <プロジェクト名> android.permission.CAMERA
- 再度、android studioでプロジェクトを実行する。すると、パーミッションが許可され、カメラが使えるようになる。(なお、プロジェクトをuninstallすると、再度コマンドの入力が必要。)
#4. 今後の作業
東北Tech道場の発表会は終わりましたが、今後、未実装だった温湿による制御と、半端に終わってしまったスマホ側の処理を実装する予定です。
#5. おわりに
初めてのIoTの開発でしたが、Android Thingsは資料も少く、手探り状態での作業となり、なかなか進まず大変でした。本当に拙い記事ではありますが、もし、誰かのお役に立てれば幸いです。