No interior de Portugal, as crianças em idade escolar têm de percorrer dezenas de quilómetros diários para se deslocarem à escola. Para muitas famílias, a longa distância da residência à escola foi um problema difícil de resolver. Felizmente, hoje, alguns municípios dispõem de serviços de transporte que permitem a essas crianças chegarem à escola atempadamente e em conforto, de modo a obterem o máximo rendimento e sempre em grande diversão.
Eu e a minha equipa tivemos o privilégio de desenvolver uma aplicação Power Apps, que regista as entradas das crianças nos diversos autocarros, armazenando toda a informação relevante: identificação da data e hora de entrada, localização da paragem, rota e sentido, validade do passe e a identificação do aluno.
Processo, investimento e dados da aplicação
O processo de criação de uma Canvas App na Plataforma Power é bastante rápido. Todo o projeto durou cerca de um mês. Desde a ideia à leitura dos primeiros passes. Partimos de uma ideia de design de uma aplicação para dispositivos Android com capacidade de leitura de etiquetas NFC. Para os alunos, apenas é necessário um cartão que aproximam do telemóvel e nada mais.
O investimento é mínimo. Como requisitos, o Cliente deverá dispor de apenas uma conta do Office 365, cujo custo mensal é inferior a €10. Os cartões NFC custarão menos de €1 cada.
A infraestrutura de dados para a leitura dos cartões também é bastante simples. Dado que a aplicação não requer a leitura de grandes volumes de dados, optámos por listas SharePoint como backend. Assim, não existirão problemas de delegação na aplicação.
Design da aplicação
O design da aplicação é intuitivo. O condutor do autocarro terá de definir algumas configurações básicas durante o arranque da aplicação, como a rota e sentido a seguir e se pretende que as paragens sejam identificadas automática ou manualmente. E é tudo.

Para a deteção automática das paragens foi necessário recolher as coordenadas geográficas de cada paragem e utilizar a funcionalidade de localização do Power Apps. De seguida, através do cálculo de distância entre o ponto em que se encontra o dispositivo móvel e todas as paragens, procura-se aquela que está mais próxima.
Esta parte do desenvolvimento é um pouco mais técnica, e por isso deixo abaixo a expressão Power Fx que o permite fazer:
Set(gblLatitudeAtual, Location.Latitude);
Set(gblLongitudeAtual, Location.Longitude);
// Calcular a distância para cada paragem e armazena-a na coluna Distancia
If(tglDetecaoParagem.Checked, // se a deteção automática de paragem estiver ativa
ClearCollect(
colRotasComDistancia,
ForAll(
colRotas,
{
Paragem: Paragem,
Latitude: Latitude,
Longitude: Longitude,
Distancia:
6371000 * 2 *
Asin(
Sqrt(
Power(Sin((Latitude - gblLatitudeAtual) * Pi() / 180 / 2), 2) +
Cos(gblLatitudeAtual * Pi() / 180) *
Cos(Latitude * Pi() / 180) *
Power(Sin((Longitude - gblLongitudeAtual) * Pi() / 180 / 2), 2)
)
)
}
)
);
// Encontrar a paragem com a distância mínima
Set(
gblParagemMaisProxima,
First(
SortByColumns(colRotasComDistancia, "Distancia", SortOrder.Ascending)
).Paragem
),
// Definir a paragem com base no dropdown
Set(
gblParagemMaisProxima,
drpParagens.Selected.Paragem
)
);
Como se pode ver no código acima, temos essencialmente três blocos:
- No primeiro, determinam-se as coordenadas geográficas nas variáveis globais gblLatitudeAtual e gblLongitudeAtual através das funções Location.
- No segundo bloco, se a opção de deteção automática das paragens estiver ativa, cria-se uma coleção (coleção é uma variável que permite armazenar uma sequência de valores em memória) com todas as paragens e a distância em metros entre o local em que nos encontramos e cada uma delas
- No terceiro, ordenando a coleção por ordem crescente de distância, encontra-se a paragem mais próxima, cujo valor fica armazenado na variável global gblParagemMaisProxima
Todo este processo é necessário, caso a deteção automática de paragens esteja ativa. Se se pretender a deteção manual, então o condutor terá de a identificar a partir de um dropdown. Neste caso, o screen anterior seria alterado para o seguinte:

A leitura dos passes NFC
Como se espera que os miúdos entrem sempre agitados nos autocarros, há que ter em conta um processo de leitura contínuo. Ou seja, espera-se que após a leitura de um passe se siga outro e outro, etc. A leitura não pode ser lenta, mas também não pode ser demasiado rápida, por isso, optámos por um intervalo de dois segundos entre cada leitura. Este tempo permite ao condutor validar que o passe foi corretamente lido sem causar filas de espera demasiado grandes.
Enquanto a aplicação aguarda pela leitura dos passes, o screen seguinte é apresentado:

Se o passe não for reconhecido ou estiver fora de validade, é apresentado o screen abaixo e um alarme sonoro simpático é disparado, o que permitirá ao condutor decidir como agir. Algo idêntico acontece se o passe for válido mas estiver fora de validade:

Dados offline
Em algumas localizações o acesso a dados móveis Internet é instável e o dispositivo pode perder a ligação durante alguns minutos. De modo a permitir que todas as leituras são recolhidas para o SharePoint, é necessário acautelar que a aplicação continua em funcionamento mesmo quando está offline.
// Se estiver online, envia os dados para o SharePoint
If(
Connection.Connected,
Patch(
LeiturasNFC,
Defaults(LeiturasNFC),
{ID_NFC: Coalesce(Text, URI), ROTA_ID: gblIdRota, DataHora: Now()}
),
// Caso contrário, guarda os dados localmente
Collect(colDadosLocais,
{IDNFC: Coalesce(Text, URI), ROTAID: gblIdRota, DATAHORA: Now()})
)
Caso não exista ligação, os dados são guardados localmente no dispositivo e enviados para o SharePoint, assim que a ligação seja reposta. Este processo ocorre de forma periódica a cada minuto.
Análise de leituras em Power BI
Finalmente, e para a análise das leituras dos passes, criámos um relatório Power BI que recolhe os dados das listas SharePoint. A análise é realizada usando os gráficos interativos do Power BI, que são extremamente flexíveis. Neste caso, como dispomos de informação geográfica, também podemos analisar os dados em mapas, onde se visualizam dados como:
- Número de alunos por paragem
- Horas de entrada por paragem
- Número de passes dentro e fora do prazo