iBeacon – niespełnione marzenia

beacon

Iot pełną gębą- tak sobie pomyślałem, gdy przyjechały do mnie 3 iBeacony w wersji Location (o ile mnie pamięc nie myli) od firmy Estimote o wdzięcznych nazwach: beetroot, candy oraz lemon.

Firma okazuje się jest prawie polska, a na pewno po części, bo jak się okazało szefem tego interesu jest Polak, mają siedzibę na Europę w Krakowie i jakieś biuro w Nowym Jorku. Nie wiem, czy to całkowicie polski wynalazek i kapitał, ale miło widzieć tak profesjonalnego gracza na globalnym rynku z naszego podwórka.

Czas zamówienia, jakość produktu, kontakt z klientem i design jest super. Po prostu piękne te beacony.

Zamawiając chciałem zbudować sobie nową funkcjonalność do aplikacji ios Pan z Pogodna. Pomysł polegał na zbudowaniu sobie przenośnego trackera, który śledziłby moje położenie, co samo w sobie nie jest trudne. Automatycznie uruchamiany tracker, który za pośrednictwem iPhona pobiera lokazlizację GPS i poprzez aplikację wysyła dane na serwer z odpowidnio zdefiniowanym interwałem czasowym. Jedynym problemem było zmuszenie aplikacji do pobierania lokacji i wysyłki na serwer, gdy urządzenie (smartfon) jest wyłączony, tzn w trybie background. Ale na szczęście istnieją odpowiednie biblioteki, które pomagają osiągnąć ten cel.

Po co mi ręcznie uruchamiany tracker pomyślałem… trzeba go podkręcić. Koncepcje były różne, ale zasada działania taka sama. Musiałem mieć coś, co wyzwoli akcję w aplikacji rozpoczynającą namierzanie (np w samochodzie lub na rowerze). Bluetooth pomyślałem…przecież mój samochod ma bluetooth i skoro mój telefon wie, że znajduje się w samochodzie, bo przełącza rozmowy na zestaw głosnomówiący to na pewno moja aplikacja rówież będzie w stanie stwierdzić, czy telefon jest sparowany z samochodem czy też nie…jeżeli tak, to rozpocznij namierzanie i wysyłanie.

Szybko zostałem sprowadzony z pomysłem na ziemię, bo wyszło na to, że z pomiomu aplikacji nie jest możliwe rozpoznanie czy urządzenie jest połączone z samochodem. Lista urządzeń w ustawieniach Bluetooth w menu jest niedostępna w aplikacji. Są to połączenia typu MOI (czy jakoś tak…), generalnie tylko dla fabrycznych parowań urządzeń.

Światełkiem w tunelu okazały się adaptery Bleutooth LE/4.0, które faktycznie można zobaczyć z apliakcji. Rozwiązaniem byłby wspomniany adapter Bluetooth na stałe wpięty do samochodu i gdy aplikacja go wykryje to rozpocznie namierzanie. Ale… jakoś nie chciało mi się przepisywać aplikacji Pan z Pogodna na swift, a tylko takie tutki do obsługi urządzeń LE udało mi się znaleźć.

Trzecim i jak juz teraz wiem, nie ostatnim wyjściem okazały sie iBeacony, o których coś kiedys słyszałem, byłem na konrefencji, gdzie opowiadano o odbiornikach NFC i iBeaconach. Więc pomyślałem, żeby przetestować, ale żeby to zrobić, to trzeba mieć… więc 100 USD i becony już mam. I zaczęło się testowanie: delegat, event, region, notyfikacje, Location manager, didEnterRegion, didExitRegion, itp…

kod…

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    _allowNotification=true;

   
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]){
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
       
    }else{
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
         (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
    }
   
    //UIApplication *application = [UIApplication sharedApplication];
    application.applicationIconBadgeNumber = 0;
   
  
   
    _locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    _locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
    _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    _locationManager.allowsBackgroundLocationUpdates = YES;


   
    self.beaconManager = [ESTBeaconManager new];
    self.beaconManager.delegate = self;
    [self.beaconManager requestAlwaysAuthorization];


    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:@"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx"] major:xxxxx minor:xxxxx identifier:@"mine"];

    self.beaconRegion.notifyOnEntry=YES;
    self.beaconRegion.notifyOnExit=YES;
    self.beaconRegion.notifyEntryStateOnDisplay=YES;
   
    [self.beaconManager startRangingBeaconsInRegion:self.beaconRegion];
    [self.beaconManager startMonitoringForRegion:self.beaconRegion];
    [self.beaconManager requestStateForRegion:self.beaconRegion];
    
    return YES;

}

- (void)beaconManager:(id)manager didEnterRegion:(CLBeaconRegion *)region {
   
    if(_allowNotification){
        NSLog(@"enter region %@", region.identifier);
        UILocalNotification *notification = [[UILocalNotification alloc]init];
        notification.alertBody = [NSString stringWithFormat: @"GPS Beacon w zasięgu - %@", region.identifier];
        notification.soundName = UILocalNotificationDefaultSoundName;
        [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
        [[UIApplication sharedApplication] cancelAllLocalNotifications];
        _TimeOfActiveNotification = [NSTimer scheduledTimerWithTimeInterval: 3.0  target:self selector:@selector(enterConfirm) userInfo:nil repeats:NO];
        }
    }
    _allowNotification=false;
}

 -(void)beaconManager:(id)manager didExitRegion:(nonnull CLBeaconRegion *)region{
   
    if(_allowNotification){
        NSLog(@"Exit region %@", region.identifier);
        UILocalNotification *notification = [UILocalNotification new];
        notification.alertBody =[NSString stringWithFormat: @"GPS Beacon poza zasięgiem - %@", region.identifier];
        notification.soundName = UILocalNotificationDefaultSoundName;
        [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
        [[UIApplication sharedApplication] cancelAllLocalNotifications];
        _TimeOfActiveNotification = [NSTimer scheduledTimerWithTimeInterval: 3.0  target:self selector:@selector(exitConfirm) userInfo:nil repeats:NO];
    }
    _allowNotification=false;
}

-(void)enterConfirm{
    [_TimeOfActiveNotification invalidate];
    _TimeOfActiveNotification = nil;
    _allowNotification=true;
    Singleton *sharedManager = [Singleton sharedManager];
    _allowSend=true;
    [_locationManager startUpdatingLocation];
    UIApplication *application = [UIApplication sharedApplication];
    application.applicationIconBadgeNumber = 1;
    bgTask = [[BackgroundTask alloc] init];
    [bgTask startBackgroundTasks:[sharedManager.autotrackInterval intValue] target:self selector:@selector  (backgroundCallback:)];
}

-(void)exitConfirm{
    [_TimeOfActiveNotification invalidate];
    _TimeOfActiveNotification = nil;
    _allowNotification=true;
    Singleton *sharedManager = [Singleton sharedManager];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"rangeVW" object:self];
    sharedManager.carBeaconInRange=false;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"inRegionVW" object:self];
    [_locationManager stopUpdatingLocation];
    UIApplication *application = [UIApplication sharedApplication];
    application.applicationIconBadgeNumber = 0;
    [bgTask stopBackgroundTask];
    bgTask=nil;
}

Po jakimś czasie cos zaczęło działać, tzn gdy Beacon był w zasięgu telefonu z aplikacją działajacą w tle przychodziła notyfikacja i generalnie w warunkach domowych to działa. Apka reaguje na obecność zdefiniowanego beacona w poblizu. Pobliżu – tzn w regione, którego wielkość definiuję za pomocą apki do konfiguracji beacona poprzez siłę wysyłanego sygnału i częstotliwość. Gdy apka jest trybie background nie jestem w stanie odczytać odległości od urządzenia, jedynie obecność w zasięgu, natomiast, gdy apka działa w trybie foreground to wiem jak daleko jestem od Beacona. Trochę to ogranicza działanie, ale na moje potrzeby wystarczy. Większym ograniczeniem było to, że notyfikacja przychodzi, tzn apka wykrywa obecność Beaocna z poślizgiem czasowym i co gorsza to obsuwa czasowa nie jest stała. Może to być 10 sekund, może być 30 sekund a może i minuta, może być i tak, że wcale nie zostanie odnotowana obecnośc lub nieobecność. Prawda jest taka, że nigdy wchodząc w zasięg nie byłem pewny czy event się wywoła, ani po jakim czasie. Również przychodziły fałszywe powiadmonia, że wyszedłem z zasięgu i potem powróciłem… a to nieprawda. Gwoździem do trumny, który spowodował, że odłożyłem zabawę z Beaconami na półkę był fakt, że w samochodzie na skutek nie wiem czego (fal radiowych, innego bluetooth, czy prędkości) te fałszywe eventy potrafią przyjść 20 razu na minutę, lub nie wykrywa obecności całkowiecie i to czasami nawet gdy samochód się nie porusza. Kompletenie nie można na tym polegać, na pewno nie w tej wersji jaka jest i z tym SDK, jake wisi na Gicie. Działa to dobrze gdy apka pracuje na froncie, ale wtedy magia tego urządzenia gdzieś pryska, bo wiesz, że nic nie może Cię zaskoczyć.

Szkoda, ale generalnie szacun za pomysł, wykonanie i całą magię tego urządzenia…może jeszcze kiedyś do tego powrócę.


Opublikowano: 1 marca, 2017 przez Pan z Pogodna

Leave a Reply