« 各種mbedのベンチマークテスト | トップページ | ESP-WROOM-02を直接プログラムしてIFTTTにイベントをポストする »

自宅iBeaconの改良

今回は小ネタですが、以前「REBL600FRで自宅iBeacon」で書いた、自宅iBeaconの改良記事です。当初の自宅iBeaconは外出(exit region)・帰宅(enter region)で「いってらっしゃい」「おかえりなさい」のメッセージを投げるだけでした。今回、帰宅時にWiFiがOFFの場合は、ONにするよう通知する機能を追加しました。

2014/10/3追記:iOS 8への対応を追記しました。


機能追加の目的

私はau iPhone5を使っているのですが、通勤路線の駅毎にau WiFiを掴んでくれます。一時期掴まなくなっていたのですが、最近なぜか復活しました。多くの方が感じていると思いますが、これ、ハッキリ言って『迷惑』です。たいがい品質の悪いWiFiを掴み停車中はLTEに比べてアクセス速度がスローダウン、電車が動き出してもしばらくWiFiを離してくれない(モバイル/LTEに切り替えてくれない)ためアクセスが止まってしまいます。そのため、電車に乗っている間は通常WiFiをOFFにしています。

家に帰ったときWiFiをONにし忘れていると、そういうときに限って、子供がモバイル/LTEの状態でYou Tubeを使い倒してパケットカウントを上げてくれることがあります・・・まあ、7Gの上限に到達することはないのですが、家にいるときはWiFiを使った方が速度も速いし、キャリアにも優しいので、家ではWiFiをONにするのを忘れないようにしたいものです。

そこで、iBeaconと連動して、家に帰ったときにWiFiがOFFの場合は、ONにするよう通知を出すようにしました。通知のイメージはこんな感じです。

IMG_0518

下から2行目の「おかえりなさい」時はWiFiがONなのでそのまま、上から2行目の「おかえりなさい」時はWiFiがOFFのため、「WiFiをOnにしましょう」と追加メッセージを投げています。


実現方式

最初は、iOSでWiFiのOn/Off状態を取得するAPIがないか調べてみたのですがなさそうです。On/Offの設定をするのは当然、脱獄(Jail Break)しないと無理とstackOverflowにも書いてあります。iOSの場合、インタフェースの状態を調べるAPIはなさそうなので、他の方法として、Reachabilityクラスを使うことにしました(使い方は、このサイトを参考にしました)。

Reachabilityクラスは、iOSでネット接続の状態を調べることができるクラスで、WiFi接続状態、モバイル(3G/4G)接続状態、未接続状態などを取得できます。間接的な方法ですが、家に帰ったとき(iBeacon regionに入ったとき)Reachability状態がモバイル接続の場合、WiFiがOFFであると判定します。

 

コード

コードを以下に示します。

//
//  ViewController.m
//  Bea子v2
//
//  Created by Todotani on 2014/05/11.
//

#import "ViewController.h"
#import "Reachability.h"

@interface ViewController ()

@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSUUID *proximityUUID;
@property (strong, nonatomic) CLBeaconRegion *beaconRegion;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        
        self.proximityUUID = [[NSUUID alloc] initWithUUIDString:@"03BA6107-9F0A-4461-B1D8-504DA65632DD"];
        self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID: self.proximityUUID
                                                               identifier:@"com.todotani.ibeacon"];
        [self.locationManager startMonitoringForRegion: self.beaconRegion];
    } else {
        //iBeaconが利用できないOS, Deviceの場合
        NSLog(@"お使いの端末ではiBeaconを利用できません。");
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"確認"
                                                        message:@"お使いの端末ではiBeaconを利用できません。"
                                                       delegate:self
                                              cancelButtonTitle:nil
                                              otherButtonTitles:@"OK", nil];
        [alert show];
    }
}


// 指定した領域に入った場合
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    [self sendLocalNotificationForMessage:@"おかえりなさい、ご主人様"];
    [NSThread sleepForTimeInterval:5.0];
    Reachability *reachablity = [Reachability reachabilityForInternetConnection];
    NetworkStatus status = [reachablity currentReachabilityStatus];
    if (status == ReachableViaWWAN) {
        [self sendLocalNotificationForMessage:@"WiFiをOnにしましょう"];
    }
}

// 指定した領域から出た場合
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    [self sendLocalNotificationForMessage:@"いってらっしゃい、ご主人様"];
}

#pragma mark - Private methods

- (void)sendLocalNotificationForMessage:(NSString *)message
{
    UILocalNotification *localNotification = [UILocalNotification new];
    localNotification.alertBody = message;
    localNotification.fireDate = [NSDate date];
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}

@end
51行目(Reachabilityインスタンスの生成)~55行目までがWiFi Off判定のために追加した部分です。

50行目に5秒のsleepが入れてあるのは、家に帰った際に自宅WiFiに接続される前に53行目の条件判定が動いて、WiFi ONの場合でもOFFと誤判定するのを回避するためです。5秒のsleepを入れることで、WiFiがONの場合は確実に接続されてから条件判定を行います。sleepを入れるのは、汚いコードで気に入らないのですが、仕方なく妥協。


iOS 8への対応

2014/10/3追記:iPhoen 6の発売早々に機種変してしまいました(キャリアも訳あってドコモにチェンジ)。iPhone 6設定後「Be子 App」を再度入れても動いてくれません。iOS 8から位置情報取得設定(iBeaconを使う場合は位置情報取得をOnにする必要があります)の方法が変わっていますが、設定 → プライバシー → 位置情報サービスから「Be子 App」の位置情報取得を「常に許可」にしても勝手に「許可しない」に戻されてしまい、iBeaconが検知できません。Twitterで症状を流したら、@tw_hoehoeさんから、リンクのblogに記載がある問題であることを教えてもらいました。このblogによると、常時位置情報取得を許可するためにはinfo.plistを編集して、”NSLocationAlwaysUsageDescription”エントリを作り、”This app use iBeacon Loacation”などの適当なString Valueを設定する必要があります。

iOS 8になって、設定条件が変わった箇所に当たってしまったということでした。


我が家のiBeaconたち

当初は、ランニングエレクトロニクスさんのREBL600FR 1個で運用していましたが、部屋を移動するとiBeaconが切れ、「いってらっしゃいませ」「おかえりなさい」を繰り返すフラップ状態になることがあったため、現在はスイッチサイエンスさんのmbed HRM1017との2台体制にしています。BL600FRは電池駆動を生かして、電源が取れない居間の壁に貼り付けてあり、HRM1017はパソコン部屋においてACアダプタから電源を取っています。

Friskケースに入れて壁に貼り付けたREBL600FR

IMG_0521

 

机の上に置いた、mbed HRM1017

IMG_0523

« 各種mbedのベンチマークテスト | トップページ | ESP-WROOM-02を直接プログラムしてIFTTTにイベントをポストする »

Bluetooth」カテゴリの記事

コメント

この記事へのコメントは終了しました。

2018年10月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
無料ブログはココログ