この記事は防災アプリ開発 Advent Calendar 2024 9日目の記事です。
←(8): 台湾の中央気象署(CWA)から地震情報を取得し震度分布図を生成する (iku55さん)
→(10): 日本の気象情報を配信してるAPIを探してみた (Wagiraさん)
前書き
今年も参加させていただきます。と言っても11月にやったものですが。
すでに生産・販売終了しているWxBeacon2ですが、地震観測画面に出したかったのでやってみました。
関係ない話
今年(1~11月)のコーディング時間が約300時間、自宅学習時間も約300時間という怠慢受験生です。大学は金沢大学を目指しています。
私は観測垢名として"GifuCam"を名乗っていますが、合格したら引っ越すので新垢作成か名前変更をします。どちらにせよ定住するかわからないので市・地域の名前を名乗るのはなぁと思っていますが案がないのでどなたかください。
概要
- C#ではUWPでやるのが一番いい感じです。たぶん。
- C#は公式ライブラリも例もあるので簡単にできる...と言いたいですが何か所がつまずいたので(今更誰得感ありますが)書いときます。
- よくわからないので雑ですが許してください。
- 地震観測画面で出しているものはこれです (ソースコードのみ)。
内容
ライブラリの準備
ウェザーニューズのGitHubにWxBeacon2-csharpというライブラリとサンプルソフトのソースがあります。これを使えばいいですが、更新日がなんと2017/11/18! 7年前です。ソースしかないので自分でビルドする必要がありますが、互換性的な問題で環境によってはうまくいかないかもしれません。
というわけで、ちょっと最適化したフォーク WxBeacon2-csharp-Extend を作成しました。良ければ使ってください。
とりあえず、READMEにある通りVS InstallerのWindows アプリケーション開発 -> ユニバーサル Windows プラットフォーム ツールが必要なので入ってなければ入れましょう。
元のウェザーニューズのものから作成する場合、git clone
かダウンロードしてSampleApp
かWxBeacon2
をビルドしてWeathernews.WxBeacon2.dll
を用意してください。
SampleApp
を実行してみてもいいです。
私のWxBeacon2-csharp-ExtendならReleasesのものを使ってもらって構いません。
作る
-
UWPのプロジェクトを作成
空白のアプリ (ユニバーサル Windows) を選択し、作成。
作成できたら、ソリューション エクスプローラー→参照→参照の追加でWeathernews.WxBeacon2.dll
を参照しusingしてください。 -
コードの編集
namespaceをWxBeacon2Viewer
としています。
私みたいにConsoleやWinFormsしかやったことないとxamlの扱いが難しいですがいろいろできるので頑張りましょう。
<Page
x:Class="WxBeacon2Viewer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WxBeacon2Viewer"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="Page_Loaded" Unloaded="Page_Unloaded"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Margin="50,50,0,0"/>
</Grid>
</Page>
追加はLoaded="Page_Loaded" Unloaded="Page_Unloaded"
と<TextBlock x:Name="textBlock" HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Margin="50,50,0,0"/>
の部分だけです。
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Weathernews.Sensor;
using Windows.UI.Core;
namespace WxBeacon2Viewer
{
public sealed partial class MainPage : Page
{
private WxBeacon2Watcher wxBeacon2Watcher = new WxBeacon2Watcher();
public MainPage()
{
InitializeComponent();
wxBeacon2Watcher.Received += WxBeacon2Watcher_Found;
}
private async void WxBeacon2Watcher_Found(object sender, WxBeacon2 beacon)
{
var latest = await beacon.GetLatestDataAsync();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
textBlock.Text = latest.ToString();
beacon.Dispose();
});//async内なのでUIをいじるときはこの中でやらないと例外になることが エラーメッセージとかなしでソフトが落ちるみたい(イベントビューアーに出る)
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
textBlock.Text = "searching...";
wxBeacon2Watcher.Start();
}
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
textBlock.Text = "exiting...";
wxBeacon2Watcher.Stop();
}
}
}
分かりやすいように進捗も表示しています。スマホアプリでは「探しています」->「接続しています」という順ですが「接続しています」の段階を表示するにはライブラリ側を調整する必要がありそうです。
3. Bluetoothの設定
ソリューション エクスプローラーでPackage.appxmanifest
を開き、機能 を押してBluetooth
をオンにしてください。こうしないといつになっても取得できません(特に例外は出ないようです)。
これで実行して数秒待つとこのように表示されます。形式はWxBeacon2Data.ToString()
を探してください。
ところで、コンソールやらフォームアプリじゃダメなの?
色々試してみましたが、うまくいきません。
System.PlatformNotSupportedException: 'Operation is not supported on this platform.'
よくわかりませんが、ウェザーニューズのライブラリの方法だとUWPじゃないとだめなようです。
こんな方法もあるようですがライブラリな関係でうまくいかない?です。表示ソフトにUwpDesktopを入れつつライブラリのコードを移植すれば行けるのかな?(未検証)
まあおとなしくUWP使いましょう。
うまく切断できない?
WxBeacon2Watcher.Dispose()
をすれば切断される...と思いましたがDisposeしてもスマホから接続できません。うまくいかないので、ライブラリをフォークし修正することにしました(それがWxBeacon2-csharp-Extendです)。
ChatGPTに聞きながら調整したところ、問題なくできました(ソフト側でもGC.Collect()
が必要かもしれません)。
/// <summary>
/// WxBeacon2Watcherのインスタンスを破棄します
/// </summary>
/// <remarks>ChatGPTを使用し適切な破棄ができるようにしました</remarks>
public void Dispose()
{
if (bluetoothLEAdvertisementWatcher != null)
{
bluetoothLEAdvertisementWatcher.Received -= BluetoothLEAdvertisementWatcher_Received;
Stop();
bluetoothLEAdvertisementWatcher = null;
}
GC.SuppressFinalize(this); //こうしないと後で参照するデータも消える(Disposeのタイミングによる)
GC.Collect();//なんかうまく切断されないことがあるため
}
なんか落ちる
定期的に取得するソフトを作りましたが、なぜか1日に1回くらい落ちる問題がありました。
UWPはエラー画面ないんですね。イベントビューアーにログが出力されます。
イベントビューアーに出るログ
障害が発生しているアプリケーション名: WxBeacon2Viewer.exe、バージョン: 1.0.0.0、タイム スタンプ: 0x62a3c35e障害が発生しているモジュール名: twinapi.appcore.dll、バージョン: 10.0.22621.4391、タイム スタンプ: 0x7d2b73d3
例外コード: 0xc000027b
障害オフセット: 0x00000000000de7f3
障害が発生しているプロセス ID: 0x0xBEF8
障害が発生しているアプリケーションの開始時刻: 0x0x1DB45D0426E4D8B
障害が発生しているアプリケーション パス: C:\Ichihai1415\source\vs\WxBeacon2Viewer\WxBeacon2Viewer\bin\x64\Debug\AppX\WxBeacon2Viewer.exe
障害が発生しているモジュール パス: C:\Windows\System32\twinapi.appcore.dll
レポート ID: aec255e4-e85f-4a09-8e84-bd316a4b1a85
障害が発生しているパッケージの完全な名前: 71b5621e-d9d0-4d4d-a67a-83f0b370ae66_1.0.0.0_x64__6253hxqnnbdsc
障害が発生しているパッケージに関連するアプリケーション ID: App
これだけではよくわからないのでWindows Error Reportingのプルダンプの設定をして、WinDbgで解析したところ、以下の内容でした。
0:019> !analyze -v
(略)
KEY_VALUES_STRING: 1
(略)
Key : Failure.Bucket
Value: STOWED_EXCEPTION_IRestrictedErrorInfo_TEXT__T_[_r_X___X_L_________s_________80131500_System.Private.CoreLib.dll!Unknown
Key : Failure.Hash
Value: {6fe3eed3-e2cc-9aa0-5711-3a6de5f443b0}
Key : SerializedError.Original
Value: サービスのスキャンに失敗しました
Key : SerializedError.Sanitized
Value: サービスのスキャンに失敗しました
(略)
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ff9a99ee7f3 (twinapi_appcore!Windows::ApplicationModel::Core::CoreApplication::ForwardLocalError+0x00000000000000e3)
ExceptionCode: c000027b
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 000001d3638ff730
Parameter[1]: 0000000000000001
(略)
どうやら普通にライブラリ側で取得失敗時に投げられる例外でソフトが落ちていたようです。適当にtry-catchします。
//wxBeacon2Watcher.Received += WxBeacon2Watcher_Found;
//↑このようにイベントハンドラを設定している場合
private async void WxBeacon2Watcher_Found(object sender, WxBeacon2 beacon)
{
try
{
//処理コード
}
catch (Exception ex)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
T_info.Text = "get failed! -> " + ex.Message;//適当に表示
});
}
}
非同期メソッド内例外(しかもライブラリ側)なので扱いが面倒ですね。
過去情報取得
ウェザーニューズのライブラリにないのでできないと思いましたが、頑張ればできそうです。
さすがにそこまで時間はないので気が向いたらやります。
その他
- 接続しっぱなしで自動で受信?されますが、接続しっぱなしだとスマホアプリで取得できなくなるので定期的に接続受信切断を繰り返すのがいいんですかね?(観測画面で出しているものはそうしてる)
まとめ
- 一応今でもUWPで受信できるソフトを作ることができます。
- UWP、つまずき所が多い。
- ライブラリを移植する必要がありますがUWP以外でもできるかもしれません。
- ウェザーニューズ公式ライブラリそのままだとうまく切断されないようなので通常通りスマホアプリでも取得したい場合少し調整する必要があります。公開しているのでぜひ(2回目)。
- 未検証ですが、過去情報の一括取得は面倒ですができそうです。