#はじめに
【IoT】ESP8266で温湿度取得してスマホでモニタリング 第1回に引き続き、第2回はAndroidアプリ側を制作したので投稿します。
グラフはネットで調べたところ、MPAndroidChartが広く使われている(?)ようだったので使ってみました。
#Xamarin.Android
開発環境は、前回に引き続きVisual Studio Community 2017を使っています。
Xamarin.Androidインストール手順
公式サンプルソース
#MPAndroidChartライブラリ
Xamarinで使えるMPAndroidChartはこちらからソースをダウンロードできます。
ダウンロードはここからgithub
ダウンロード後、ソースをビルドすると各種DLLが生成させるようです。
(私の環境では普通にビルド通りましたけどどうなんでしょうか)
今回は、\packages\MPAndroidChart.3.0.0\lib\MPAndroidChart.dllを使いました。
Xamarin版のサンプルソースがJava版と比較して圧倒的に少ないのが難点ですね。
#MQTTライブラリ
MQTTはC#で使えるライブラリを適当にチョイスしました。
ダウンロードはここからgithub
ダウンロード後、M2Mqtt.dllを使いました。
すぐ使えるアプリケーションもセットになっているので、使い易いかと思います。
#開発で行き詰った事
##NumberPickerはマイナスが表示できない問題
温度・湿度のスケールを設定するダイアログで、当初はNumberPickerで作っていたましたが、いざ作ってみるとマイナスが表示されないことに気づきました。仕方ないので、普通にListViewで選択する方向で作ってみましたが、なんかダサいですね。
後々調べてみると、NumberPickerをカスタムして使う投稿もあったみたいですね。
NumberPickerをカスタムして使う
##ポップアップをクローズしたときに親画面に値を返せない問題
AlertDialogクラスにはクローズ時のイベントOnDismissが用意されていますが、さすがに親に値を返すイベントまではないようです。
仕方ないので、クローズしたときに呼び出されるコールバック関数を用意しました。
public class DialogEventArgs : EventArgs
{
public string ReturnValue { get; set; }
}
/// <summary>
/// リストダイアログ表示クラス
/// </summary>
public class ListDialogFragment : DialogFragment
{
public event EventHandler<DialogEventArgs> DialogClosed;
public delegate void DialogEventHandloer(object sender, DialogEventArgs e);
//処理内容省略...
/// <summary>
/// ダイアログクローズ時のイベント
/// </summary>
/// <param name="dialog"></param>
public override void OnDismiss(IDialogInterface dialog)
{
base.OnDismiss(dialog);
// 呼び出した親に値を返す
if (DialogClosed != null)
{
DialogClosed(this, new DialogEventArgs { ReturnValue = _selectedValue });
}
}
}
ダイアログを呼び出す親画面でDialogClosedにコールバック関数を設定してあげると、ダイアログをクローズしたときにコールバック関数が呼び出されます。尚、値はDialogEventArgs eのReturnValueプロパティにセットされています。
protected override void OnCreate(Bundle savedInstanceState)
{
//処理内容省略...
// 室温最小値ボタンのクリックイベント
btnTempMin.Click += (_, __) =>
{
dialogKey = TempMinKey;
// ダイアログ表示
ListDialogFragment dlg = new ListDialogFragment(
this,
"室温(最小)を選択してください",
Resource.Array.TempAxisItems,
Resource.Array.TempAxisValues);
dlg.DialogClosed += OnDialogClosed; // 選択時のコールバック関数
dlg.Show(this.FragmentManager, typeof(ListDialogFragment).Name);
};
//処理内容省略...
}
/// <summary>
/// ダイヤログ選択時のコールバック関数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void OnDialogClosed(object sender, DialogEventArgs e)
{
//処理内容省略...
}
##MPAndroidChartのX軸のラベルをカスタムする方法
MPAndroidChartのX軸のラベルはデフォルトでは、0,1,2…のようにインデックスで表示されます。
カスタムラベルする方法は、Javaでは結構サンプルソースがあるのですが、Xamarin.Androidでは中々見つからないので苦労しました。
結局のところ、IAxisValueFormatterを継承したクラスを作らないといけないようです。
以下のソースでは、IAxisValueFormatterを継承したXLabelFormatterクラスを用意し、GetFormattedValueでラベルを作成します。
”if (int.TryParse(value.ToString("0.#"), out val) == true)”をしているのは、整数チェックをしています。というのは、引数のfloat valueには少数で値が入ってくることがあるようです。(なぜかは不明)
また、”if (labelList.Count > val && val >= 0)”は、グラフに表示するデータ件数が0件でもグラフの枠だけ表示し、ラベルは何も表示したくないので、このような処理を入れています。
XLabelFormatterでは、addLabelでX軸に表示したいラベルをlabelListにaddし、GetFormattedValueでX軸のインデックスに対応したラベルをlabelListから取得しています。
public class MainActivity : Activity
{
//処理内容省略...
XLabelFormatter xformatter = new XLabelFormatter();
private void setData(string xlabel, string temp, string humi)
{
// X軸の設定
XAxis xAxis = mChart.XAxis;
xAxis.SetLabelCount(tempDataset.EntryCount, true);
xformatter.addLabel(xlabel);
xAxis.ValueFormatter = xformatter;
//処理内容省略...
}
//処理内容省略...
}
public class XLabelFormatter : Java.Lang.Object, IAxisValueFormatter
{
private static List<string> labelList = new List<string>();
public int DecimalDigits => 0;
public void addLabel(string item)
{
labelList.Add(item);
}
public string GetFormattedValue(float value, AxisBase axis)
{
int val = 0;
string ret = "";
if (int.TryParse(value.ToString("0.#"), out val) == true)
if (labelList.Count > val && val >= 0)
ret = labelList[val];
return ret;
}
}
#おわりに
今回はArduinoもXamarinもAndroidも初めてづくしで調べなたら開発したので、かなり時間かかってしまった印象です。
Arduinoではセンサー系を試してみたので、次はモータ系を試してみたいですね。
構想としては、Arduino+ROS+ドローン+PS4コントローラとかやってみたいなぁ・・・
と考えているので、進捗が出ましたらまた投稿したいと思います。
#関連記事
【IoT】ESP8266で温湿度取得してスマホでモニタリング 第1回
#ソース
準備中...少々お待ちください。