Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@tomato_sugar

AndroidThings & Raspberry Pi3 で猫用扇風機を作る(終)

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への表示部分を削除する。なお、同時に時刻の表示を「年/月/日 時:分:秒」形式にする。

CatFansEntryAdapter.java
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 の修正

以下のように変更して、タイムスパンと画像のみ表示するようにする。

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) 確認画面

スマホで確認すると次のようになる。
32.png

2. ハードの状態

ハードウェアの方も組み立て終わり、出来上がってきました。

(1) 駆動部分

34.jpg

(2) コルクボードで覆ったところ

35.jpg

(3) 扇風機部分を取り付ける

36.jpg

(4) 完成

33.jpg

3. 不具合発生

(1) 「カメラのパーミッションが無い」というエラーに遭遇

システムの方は機能限定ながらも動くようになり、発表会直前で稼働中の動画を撮ろうという段階になって、なんとシステムが動かなくなってしまいました。原因を探ると、「CatFansActivityクラス」の「onCreateメソッド」の以下の部分でreturnしていることがわかりました。

CatFansActivity.java
        // カメラにアクセスするための許可が必要
        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は資料も少く、手探り状態での作業となり、なかなか進まず大変でした。本当に拙い記事ではありますが、もし、誰かのお役に立てれば幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?