Brincando com Ionic, Lumen, Firebase, Google Maps, Raspberry Pi e geolocalização de background

Photo of Brincando com Ionic, Lumen, Firebase, Google Maps, Raspberry Pi e geolocalização de background
Facebook
VKontakte
share_fav

Eu quero fazer um projeto simples de estimação. A ideia é criar um aplicativo móvel. Esse aplicativo acompanhará minha localização do GPS e enviará essas informações para um banco de dados Firebase. Eu nunca brinquei com Firebase e quero aprender um pouco.

Com essa informação, vou criar um aplicativo web simples, hospedado no meu Raspberry Pi. Esse aplicativo web mostrará um mapa do Google com a minha última localização. Eu colocarei esse aplicativo web na minha TV, e qualquer pessoa na minha casa poderá sempre ver onde eu estou.

Essa é a ideia. Eu quero um MVP. Primeiro, o aplicativo móvel. Eu usarei o framework Ionic, do qual sou grande fã.

O aplicativo móvel é muito simples. Só tem uma alternância para ativar-desativar a geolocalização de background (às vezes eu não quero ser rastreado).

    
        
            Ionic Blank
        
         
        {{title}}
        
            
            
        
     

E o controller:

import {Component} from '@angular/core';
import {Platform} from 'ionic-angular';
import {LocationTracker} from "../../providers/location-tracker/location-tracker";
 
@Component({
    selector: 'page-home',
    templateUrl: 'home.html'
})
export class HomePage {
    public status: string = localStorage.getItem('status') || "-";
    public title: string = "";
    public isBgEnabled: boolean = false;
    public toolbarColor: string;
 
    constructor(platform: Platform,
                public locationTracker: LocationTracker) {
 
        platform.ready().then(() => {
 
                if (localStorage.getItem('isBgEnabled') === 'on') {
                    this.isBgEnabled = true;
                    this.title = "Working ...";
                    this.toolbarColor = 'secondary';
                } else {
                    this.isBgEnabled = false;
                    this.title = "Idle";
                    this.toolbarColor = 'light';
                }
        });
    }
 
    public changeWorkingStatus(event) {
        if (event.checked) {
            localStorage.setItem('isBgEnabled', "on");
            this.title = "Working ...";
            this.toolbarColor = 'secondary';
            this.locationTracker.startTracking();
        } else {
            localStorage.setItem('isBgEnabled', "off");
            this.title = "Idle";
            this.toolbarColor = 'light';
            this.locationTracker.stopTracking();
        }
    }
}

Como você pode ver, o botão de alternância irá ativar-desativar a geolocalização de background e também alterar a cor de fundo da barra de ferramentas.

Para a geolocalização de background, usarei um plugin cordova disponível como plugin ionic nativo.

Aqui você pode ver um artigo muito legal, explicando como usar o plugin com Ionic. Como o artigo explica, eu criei um provedor.

import {Injectable, NgZone} from '@angular/core';
import {BackgroundGeolocation} from '@ionic-native/background-geolocation';
import {CONF} from "../conf/conf";
 
@Injectable()
export class LocationTracker {
    constructor(public zone: NgZone,
                private backgroundGeolocation: BackgroundGeolocation) {
    }
 
    showAppSettings() {
        return this.backgroundGeolocation.showAppSettings();
    }
 
    startTracking() {
        this.startBackgroundGeolocation();
    }
 
    stopTracking() {
        this.backgroundGeolocation.stop();
    }
 
    private startBackgroundGeolocation() {
        this.backgroundGeolocation.configure(CONF.BG_GPS);
        this.backgroundGeolocation.start();
    }
}

A ideia do plugin é enviar uma solicitação POST para uma URL com os dados do GPS no corpo da solicitação. Então, vou criar um servidor api web para lidar com essa solicitação. Usarei meu Raspberry Pi3 para atender ao aplicativo. Vou criar um aplicativo PHP/Lumen simples. Esse aplicativo irá lidar com a solicitação POST do aplicativo móvel e também servirá uma página HTML com o mapa (usando o Google Maps).

As solicitações móveis serão autenticadas com um token no cabeçalho, e o aplicativo web usará uma autenticação HTTP básica. Por isso, vou criar dois middlewares para lidar com as diferentes maneiras de autenticar.

load();
 
$app = new Application(__DIR__ . '/..');
$app->singleton(ExceptionHandler::class, App\Exceptions\Handler::class);
$app->routeMiddleware([
    'auth'  => Middleware\AuthMiddleware::class,
    'basic' => Middleware\BasicAuthMiddleware::class,
]);
 
$app->router->group(['middleware' => 'auth', 'prefix' => '/locator'], function (Router $route) {
    $route->post('/gps', function (Gps $gps, Request $request) {
        $requestData = $request->all();
        foreach ($requestData as $poi) {
            $gps->persistsData([
                'date'             => date('YmdHis'),
                'serverTime'       => time(),
                'time'             => $poi['time'],
                'latitude'         => $poi['latitude'],
                'longitude'        => $poi['longitude'],
                'accuracy'         => $poi['accuracy'],
                'speed'            => $poi['speed'],
                'altitude'         => $poi['altitude'],
                'locationProvider' => $poi['locationProvider'],
            ]);
        }
 
        return 'OK';
    });
});
 
return $app;

Como podemos ver, rout/locator/gps irá lidar com a solicitação POST. Eu criei um modelo para persistir os dados do GPS no banco de dados do Firebase:

withServiceAccount($serviceAccount)
            ->create();
 
        $this->database = $firebase->getDatabase();
    }
 
    public function getLast()
    {
        $value = $this->database->getReference('gps/poi')
            ->orderByKey()
            ->limitToLast(1)
            ->getValue();
 
        $out                 = array_values($value)[0];
        $out['formatedDate'] = \DateTimeImmutable::createFromFormat('YmdHis', $out['date'])->format('d/m/Y H:i:s');
 
        return $out;
    }
 
    public function persistsData(array $data)
    {
        return $this->database
            ->getReference('gps/poi')
            ->push($data);
    }
}

O projeto está quase concluído. Agora só precisamos criar o mapa do Google.

Aqui está a API:

router->group(['middleware' => 'basic', 'prefix' => '/map'], function (Router $route) {
    $route->get('/', function (Gps $gps) {
        return view("index", $gps->getLast());
    });
 
    $route->get('/last', function (Gps $gps) {
        return $gps->getLast();
    });
});

E o HTML:

    
    
    Locator
    

E isso é o suficiente! O código-fonte está disponível na minha conta do Github.

***

Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2018/02/19/playing-with-ionic-lumen-firebase-google-maps-raspberry-pi-and-background-geolocation/

ver iMasters
#google maps
#raspberry pi
#gps
#firebase
#ionic
#desenvolvimento
#lumen