Conteúdo


Traga a IoT para casa: conecte seu carro à sua casa

Use o IBM Watson IoT Platform e um Raspberry Pi, um dispositivo Bluetooth, e uma tomada múltipla rogramável para acender suas luzes e seus dispositivos à medida que seu carro se aproxima de casa

Comments

Carros conectados e casas inteligentes são temas que atualmente estão em destaque no domínio da IoT. Se você olhar mais de perto, verá que carros conectados e casas inteligentes parecem existir em silos. Sim, um residente de uma casa inteligente consegue acender as luzes e os dispositivos com seu telefone celular. Mas, por que o carro, à medida que se aproxima da casa inteligente, não consegue fazer exatamente a mesma coisa?

Neste tutorial, você aprenderá como usar o IBM Cloud e Node-RED para conectar um carro a uma casa inteligente, permitindo que o carro ative automaticamente os recursos domésticos, tais como acender as luzes e ajustar o ar condicionado.

Usaremos um Raspberry Pi para sentir a força do sinal de um dispositivo Bluetooth na casa inteligente e enviar essa informação ao Watson IoT Platform. Em seguida, com base na força do sinal, ativaremos um dispositivo elétrico com esse dispositivo Bluetooth. Além disso, usaremos o rastreamento do carro baseado em GPS, criando uma geo-fence ao redor da casa inteligente, para, essencialmente, podermos conectar seu carro à sua casa.

O que será necessário para construir esse aplicativo IoT

Este tutorial prático é baseado em uma Prova de Conceito (PoC) que eu fiz de última hora com um equipamento que encontrei em casa no momento em que fiz a PoC. É possível usar os mesmos dispositivos ou você pode substituí-los pelo que precisa para seu propósito específico.

São necessários os seguintes dispositivos, contas ou habilidades para construir este aplicativo IoT como eu construí:

  • Um sistema Linux com um dispositivo Bluetooth, tal como um Raspberry Pi com um dongle USB Bluetooth. Embora qualquer dispositivo Linux com um C-Compiler configurado funcione, ninguém de fato deseja executar um computador em um planejamento de 24 horas, 7 dias da semana como um gateway de dispositivo.
  • Uma tomada de energia que possa ser ativada a partir de um PC. Eu usei uma Gembird Silver Shield (uma tomada múltipla programável), mas existem outras marcas que podem funcionar melhor para você.
  • Familiaridade com a linguagem de programação C e o desenvolvimento C em um sistema Linux (tal como Fedora, que é um sistema operacional de software livre baseado em Linux).
  • Uma conta do IBM Cloud® . (É possível solicitar uma avaliação grátis aqui.)
  • Familiaridade com o IBM Cloud. É necessário saber como navegar pelo catálogo e instanciar um dos serviços do IBM Cloud.
  • Familiaridade com MQTT, especialmente a biblioteca Eclipse Mosquitto, que é um message broker de software livre que implementa o protocolo MQTT e que pode ser localizado em todas as principais distribuições do Linux. Use sua ferramenta de gerenciamento de pacote da plataforma Linux para procurar o Mosquitto e instalar o pacote em seu dispositivo.
  • Familiaridade com o Node-RED. É necessário entender como usar nós no Node-RED e como processar uma mensagem no Node-RED. O Node-RED é um front-end para JavaScript, portanto, também é necessária alguma experiência com o JavaScript. É possível usar a documentação de introdução no website do Node-RED para ajudá-lo a ganhar esta familiaridade.

Obtenha o códigoExecute o aplicativo

 

A arquitetura de nosso aplicativo IoT de amostra

Figura 1 representa a primeira fase da arquitetura do aplicativo IoT que recebe a força de um sinal de Bluetooth.

Figura 1. Diagrama da arquitetura do aplicativo IoT de amostra e os dispositivos

EmFigura 1, os números nos círculos o guiam pelas etapas para construir o aplicativo IoT:

  1. No IBM Cloud, você cria um aplicativo usando o Internet of Things Platform Starter. O aplicativo lerá dados do sensor que são recebidos de um dispositivo e enviará dados a um dispositivo. Para proteger o aplicativo contra o envio de dados por dispositivos arbitrários a ele, cada dispositivo precisa se autenticar usando um token da API. Do mesmo modo, o aplicativo precisa se autenticar usando um token da API para que possa ler e processar os dados do dispositivo que ele recebe.
  2. Em um dispositivo Raspberry Pi, você cria um cliente MQTT para ler a força de sinal do Bluetooth e enviar continuamente os valores ao IBM Watson IoT Plataform.
  3. Você cria um aplicativo Node-RED para processar os dados e gerar comandos para enviar à tomada múltipla programável para acender as luzes e o ar condicionado na casa.

Após implementar esta versão inicial do aplicativo IoT com êxito, você aprenderá como estendê-lo para utilizar as coordenadas do GPS do carro. Você também desenvolverá um painel para definir a geo-fence para a função de controle do GPS e para configurar a sensibilidade do sensor de aproximação do Bluetooth.

Vamos começar!

1

Crie seu aplicativo IoT e conecte seu Raspberry Pi ao Watson IoT Platform

Primeiro, vamos conectar nosso Raspberry Pi ao Watson IoT Platform.

1a

Crie seu aplicativo IoT no IBM Cloud

  1. Efetue login em sua conta do IBM Cloud.
  2. Use o texto padrão do Internet of Things Platform Starter para criar seu aplicativo. É possível escolher seu próprio nome para o aplicativo; neste tutorial, eu uso dw-example-iot. O aplicativo será iniciado, o que pode demorar um pouco.
  3. Clique no link de visão geral na área de janela de navegação à esquerda e aguarde o serviço ser implementado.
  4. Clique em INCLUIR UM SERVIÇO OU UMA API.
  5. Localize o serviço de Internet of Things Platform e clique em CRIAR.
1b

Registre seu Raspberry Pi no serviço do Internet of Things Platform e identifique os tokens de autenticação e autorização

Para enviar dados ao Watson IoT Platform, é necessário registrar seus dispositivos no serviço do Internet of Things Platform. Neste tutorial, eu uso o Raspberry Pi como um dispositivo de gateway. O token de autenticação que é gerado quando você registra seu dispositivo permite que o dispositivo envie os dados ao Watson IoT Platform.

Para identificar um dispositivo exclusivamente, é necessário um ID do cliente. Um ID do cliente é criado com este formato predefinido, no qual typeid é uma sequência que identifica o propósito dos dispositivos e no qual "device-id" é um identificador exclusivo de seu dispositivo:
d:<organization>:<typeid>:<device-id>

Emita o comando a seguir em seu dispositivo Raspberry Pi para identificar o endereço MAC exclusivo para o dispositivo, o qual é possível usar como o device ID exclusivo:
ip add show|grep -A1 '^[0-9]:'

Na saída de comando, procure uma interface denominada 'eth0', 'em1' ou semelhante a 'enp1s0'. Os nomes variam entre distribuições do Linux, mas a linha após a interface mostra seu endereço MAC como 'link/ether':

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
--
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 12597 qdisc pfifo_fast state UP….
link/ether b8:72:be:f2:7a:a8 brd ff:ff:ff:ff:ff:ff

Para registrar seu dispositivo, conclua estas etapas:

  1. No painel de seu aplicativo IBM Cloud, clique no serviço do Internet of Things Platform.
  2. Na coluna esquerda, na parte inferior, clique em Ativar painel. Uma nova janela ou guia se abre em seu navegador. Seu ID da organização é exibido na parte superior do painel.
  3. Na seção Dispositivos abaixo do ID da Organização, clique em Incluir Dispositivo.
  4. Especifique proximity como o tipo de dispositivo (typeid) e especifique o endereço MAC de seu dispositivo Ethernet, sem os dois pontos, como seu ID do dispositivo (device-id).
  5. Clique em Continuar.
  6. Revise a próxima página cuidadosamente e anote as credenciais do dispositivo, especificamente o Token de Autenticação para seu dispositivo.
1c

Teste sua conectividade

Agora que nosso dispositivo foi registrado no Watson IoT Platform, é possível usar o token de autenticação para enviar uma mensagem de teste a partir do Raspberry Pi. Vamos usar a biblioteca Mosquitto MQTT. Por exemplo, efetue login em seu Raspberry Pi e emita o comando do Mosquitto a seguir, fornecendo seus próprios valores para a organização e para device-id:

mosquitto_pub -h e62whi.messaging.internetofthings.ibmcloud.com \
-i d:e62whi:proximity:b872bef27aa8 \
-u use-token-auth -P '<your device credentials here>' \
-t /iot/x -m '{"d":"hello iot"}'

No painel para o Watson IoT Platform, você verá a mensagem "hello iot" nas informações do sensor para seu dispositivo:

Enquanto você está no painel do Watson IoT Platform, vamos assegurar que nosso aplicativo Node-RED esteja autorizado a consumir os dados do dispositivo enviados ao nosso aplicativo IoT. Em vez de um token de autenticação, precisamos de um token de autorização de API. Para autorizar um aplicativo a consumir dados deste aplicativo, conclua essas etapas:

  1. No painel do Watson IoT Platform, clique em Acessar e, em seguida, Chaves da API.
  2. Clique em Gerar Chave da API.
  3. Revise a próxima página cuidadosamente e anote as credenciais da API, especificamente o Token de Autenticação.
2

Grave um cliente MQTT em seu Raspberry Pi para ler a força do sinal do Bluetooth

O cliente MQTT é um programa C que lê a força do sinal do Bluetooth e envia o valor ao aplicativo IoT no IBM Cloud. Da mesma forma, o cliente recebe comandos do aplicativo IoT e chama um script para executar o comando.

2a

Determine o endereço MAC de seu dispositivo Bluetooth

O cliente do dispositivo precisa se conectar a um dispositivo Bluetooth usando o endereço MAC do dispositivo. É possível determinar o endereço MAC de seu dispositivo Bluetooth emitindo os comandos a seguir em seu dispositivo (no meu caso, um Raspberry Pi), que deve fornecer resultados ou saída semelhantes:

# bluetoothctl
[NEW] Controller 00:15:83:07:CC:97 traumcloud.enet [default]

[Bluetooth]# power on
Changing power on succeeded
[CHG] Controller 00:15:83:07:CC:97 Powered: yes

[Bluetooth]# scan on
Discovery started
[CHG] Controller 00:15:83:07:CC:97 Discovering: yes
[NEW] Device 3C:77:E6:EF:57:F5 3C-77-E6-EF-57-F5
[NEW] Device 00:0A:3A:2B:C6:ED MSI FT200
[CHG] Device 00:0A:3A:2B:C6:ED RSSI: -79
[CHG] Device 00:0A:3A:2B:C6:ED RSSI: -88

[Bluetooth]# agent on
Agent registered

[Bluetooth]# pair 00:0A:3A:2B:C6:ED
Attempting to pair with 00:0A:3A:2B:C6:ED
Request PIN code
[agent] Enter PIN code: 1234
[DEL] Device 3C:77:E6:EF:57:F5 3C-77-E6-EF-57-F5
[CHG] Device 00:0A:3A:2B:C6:ED Connected: yes
[CHG] Device 00:0A:3A:2B:C6:ED UUIDs:
        00001108-0000-1000-8000-00805f9b34fb
        0000111e-0000-1000-8000-00805f9b34fb
[CHG] Device 00:0A:3A:2B:C6:ED Paired: yes
Pairing successful

[Bluetooth]#exit

Em meu exemplo, eu sei que estou procurando um MSI FT200 headsete vejo que este endereço MAC é 00:0A:3A:2B:C6:ED. Anote o endereço MAC para seu dispositivo.

2b

Codifique o núcleo MQTT

Após a biblioteca Mosquitto ser inicializada, o programa configura os retornos de chamada para os eventos nos quais ele está interessado e se conecta ao serviço do Internet of Things Platform no IBM Cloud. O código de inicialização segue, essencialmente, o código de exemplo do website do Mosquitto:

        mqtt = mosquitto_new(cfg.deviceid, 1, NULL);
        if(!mqtt){
                tprintf("Cannot Initialize MQTT library\n");
                mosquitto_lib_cleanup();
                return 1;
        }
        mosquitto_connect_callback_set(mqtt, bt_connect_callback);
        mosquitto_disconnect_callback_set(mqtt, bt_disconnect_callback);

Em seguida, você inclui retornos de chamada do Mosquitto em eventos de MQTT:

        mosquitto_log_callback_set(mqtt, bt_log_callback);
        mosquitto_message_callback_set(mqtt, bt_message_callback);
        mosquitto_subscribe_callback_set(mqtt, bt_subscribe_callback);
         dprintf("now setting username and password to %s/*************\n", cfg.username);
        sts=mosquitto_username_pw_set(mqtt, cfg.username, cfg.password);
        if(sts) {
                tprintf("Error setting username/password\n");
                return sts;
        }
        dprintf("now connection using host=%s port=%d\n", cfg.host, cfg.port);
        sts = mosquitto_connect_bind(mqtt, cfg.host, cfg.port, 60, NULL);
        if(sts) {
                tprintf("Error connecting to %s:%d as %s\n", HOST, PORT, IDFMT);
                return sts;

Em seguida, o programa registra quando o retorno de chamada de conexão indica uma conexão adequada:

void bt_connect_callback(struct mosquitto *mqtt, void *obj, int result) {
         char buf[1024];
        dprintf("conn cb %d '%s'\n", result, mosquitto_connack_string(result));
        is_connected=(result==0?CONN_OK:CONN_ERR);
        if (is_connected==CONN_OK) {
                mosquitto_subscribe(mqtt, NULL, cfg.subscription, 0);
        }
        sprintf(buf, PAYLOAD, -100, -100); // simulate a very far away beacon
        mosquitto_publish(mqtt, NULL, TOPIC, strlen(buf), buf, 0, false);
}

O programa principal é executado em um loop, que envia periodicamente a força de sinal do Bluetooth.

while (is_connected != CONN_ERR) {
                if (is_connected == CONN_OK) publish_bt(mqtt);
                else dprintf("waiting for connection to come up\n", "");
                sleep(cfg.sleep);
        }
2c

Chame um script externo

A biblioteca Mosquitto cuida do recebimento de comandos e chama a função de retorno de chamada apropriada. Em nosso caso, chamamos um script externo para executar o trabalho real. Este script permite que sejamos flexíveis com diferentes tipos de atuadores para controlar os dispositivos.

void bt_message_callback(struct mosquitto *mqtt, void *udata, const struct mosquitto_message *message) {
        dprintf("msg cb topic='%s' payload='%s'\n", message->topic, message->payload);
/*
 * A execute script btclient.d/command.sh
 */
         int pid,sts;
        pid = fork();
        switch (pid) {
        case 0:         // child, execute shell script
                setenv("TOPIC", message->topic, 1);
                setenv("PAYLOAD", message->payload, 1);
                sts=execl("btclient.d/mqtt-command.sh", "mqtt-command", (const char*)NULL);
                tprintf("something went wrong with execl(), error='%s'\n", strerror(errno));
         break;
        case -1:        // error
                tprintf("something went wrong with fork(), error='%s'\n", strerror(errno));
        break;
        default:        // parent
                wait(&sts);
        break;
        }
}

Usando um script, o cliente MQTT pode ser adaptado facilmente ao hardware ou aos dispositivos inteligentes que você usa. Eu usei uma tomada múltipla programável Gembird Silver Shield, que me permite controlar a comutação individual de quatro tomadas de energia usando um USB com um utilitário Linux chamado sispmctl (que está disponível como um pacote no Fedora Linux).

#!/bin/bash
if [ "$TOPIC" == "iot-2/cmd/switch/fmt/text" ];then
        [ "$PAYLOAD" == "on" ] && arg="-o4"
        [ "$PAYLOAD" == "off" ] && arg="-f4"
        [ "$arg" != "" ] && sispmctl $arg
fi

Como alternativa, usei um transceptor de 433 MHz para ativar tomadas elétricas wireless usando a estrutura de pilight. A estrutura de pilight é uma estrutura para automação residencial no Raspberry Pi. É possível investigar qual tomada e projeto elétrico se ajustam às suas necessidades.

2d

Modifique o arquivo de configuração do cliente MQTT

O cliente MQTT lê um arquivo de configuração na inicialização, que possui o mesmo nome que o arquivo executável, mas anexado com .cfg. Este arquivo de configuração separado permite executar diferentes instâncias usando apenas um nome diferente para o executável; por exemplo, após otherclient ser iniciado, o cliente MQTT lerá otherclient.cfg como seu arquivo de configuração.

O arquivo de configuração define:

  • btmac: Use o endereço MAC do dispositivo Bluetooth para o qual você mede a força de sinal (não o dispositivo integrado de seu sistema Linux).
  • subscription: Use o tópico que o cliente precisa para fazer a assinatura. Em meu exemplo, iot-2/cmd/switch/fmt/+.
  • host: O nome do host de sua instância de serviço do Internet of Things Platform. Use o nome que você usou quando enviou a mensagem "hello iot".
  • password: A senha é o token de autenticação do dispositivo. Use aquela que você anotou quando registrou o dispositivo.
  • username: O nome do usuário é a cadeia de caractere literal use-token-auth
  • typeid: O typeid é o tipo de dispositivo que você usou quando registrou o dispositivo. Em meu exemplo, eu usei proximity.
  • organization: Use seu ID da organização.
3

Grave um aplicativo Node-RED para sentir o sinal do Bluetooth e ativar um dispositivo elétrico

O cliente MQTT envia a força de sinal do Bluetooth em um intervalo regular para o serviço do Internet of Things Platform no IBM Cloud. Agora, é necessário gravar um aplicativo no IBM Cloud para processar esses valores. Usamos Node-RED como o ambiente para criar esse aplicativo.

3a

Crie o aplicativo Node-RED e conecte seu dispositivo

Primeiro, conectaremos nosso dispositivo e nos certificaremos de que ele esteja recebendo mensagens.

  1. Em seu aplicativo IBM Cloud IoT, clique no link de codificação inicial na área de janela de navegação à esquerda.
  2. Na parte superior da tela, localize a URL para seu aplicativo em execução. Clique nessa URL.
  3. Clique no botão vermelho grande para abrir seu editor de fluxo Node-RED.
  4. Um aplicativo de amostra é exibido no editor de fluxo. Selecione todos os elementos no fluxo e exclua-os.
  5. Arraste um nó de entrada ibmiot para a área de trabalho e configure-o dando um clique duplo nele. Use o Token de Autenticação da API que você criou anteriormente para ganhar acesso aos seus dados do dispositivo conforme mostrado na ilustração abaixo.
  6. Selecione Todos para tipo de dispositivo, ID de dispositivo, evento e formato.
  7. Para testar seu dispositivo, inicie o cliente do dispositivo em seu sistema Linux. Certifique-se de que algumas mensagens sejam enviadas ao Watson IoT Platform.
    [root@traumcloud btclient]# ./dwclient
    [2015-08-18 17:16:39] trying to use ./dwclient.cfg for configuration
    [2015-08-18 17:16:39] got option 'btmac' with arg 00:0A:3A:2B:C6:ED
    [2015-08-18 17:16:39] got option 'subscription' with arg iot-2/cmd/switch/fmt/+
    [2015-08-18 17:16:39] got option 'host' with arg e62whi.messaging.internetofthings.ibmcloud.com
    [2015-08-18 17:16:39] got option 'password' with arg R3!1sFY(846HRCC0P6
    [2015-08-18 17:16:39] got option 'username' with arg use-token-auth
    [2015-08-18 17:16:39] got option 'typeid' with arg proximity
    [2015-08-18 17:16:39] got option 'organisation' with arg e62whi
    [2015-08-18 17:16:39] got MAC address of this machine as 'b827eb2fa78a'@  eth0
    [2015-08-18 17:16:39] now setting username and password to use-token-auth/*************
    [2015-08-18 17:16:39] now connection using host=e62whi.messaging.internetofthings.ibmcloud.com port=1883
    [2015-08-18 17:16:39] log cb: 'Client d:e62whi:proximity:b827eb2fa78a sending CONNECT'
    [2015-08-18 17:16:40] log cb: 'Client d:e62whi:proximity:b827eb2fa78a received CONNACK'
    [2015-08-18 17:16:40] conn cb 0 'Connection Accepted.'
    [2015-08-18 17:16:40] log cb: 'Client d:e62whi:proximity:b827eb2fa78a sending SUBSCRIBE (Mid: 1, Topic: iot-2/cmd/switch/fmt/+, QoS: 0)'
    [2015-08-18 17:16:40] log cb: 'Client d:e62whi:proximity:b827eb2fa78a sending PUBLISH (d0, q0, r0, m2, 'iot-2/evt/status/fmt/json', ... (31 bytes))'
    [2015-08-18 17:16:40] log cb: 'Client d:e62whi:proximity:b827eb2fa78a received SUBACK'
    [2015-08-18 17:16:40] sub cb 1 subscriptions
    [2015-08-18 17:16:41] BT MQTT msg '{ "d": {"lq":235,"rssi":-13}}'
    [2015-08-18 17:16:41] log cb: 'Client d:e62whi:proximity:b827eb2fa78a sending PUBLISH (d0, q0, r0, m3, 'iot-2/evt/status/fmt/json', ... (29 bytes))'
    [2015-08-18 17:16:46] BT MQTT msg '{ "d": {"lq":250,"rssi":-13}}'
    [2015-08-18 17:16:46] log cb: 'Client d:e62whi:proximity:b827eb2fa78a sending PUBLISH (d0, q0, r0, m4, 'iot-2/evt/status/fmt/json', ... (29 bytes))'
  8. Arraste um nó de saída debug para sua planilha e conecte-o ao seu nó ibmiot .
  9. Clique em Implementar.
  10. Clique na guia de Depuração à direita para ver mensagens de depuração recebidas.
  11. Mova seu dispositivo Bluetooth para frente e para trás e verifique se os valores mín/máx de RSSI mudam.
3b

Grave o aplicativo Node-RED para processar os dados do dispositivo Bluetooth

Após verificar que seu dispositivo está conectado, é possível gravar o aplicativo Node-RED.

  1. Iniciamos com uma função de inicialização. Arraste um nó Inject, um nó function e um nó de saída debug para sua área de trabalho e conecte-os nesta sequência.
  2. Configure o nó Inject com carga útil em branco, marque injetar uma vez no início e forneça um nome significativo ao nó (por exemplo, AppSetup ).
  3. Configure o nó function com o código a seguir e forneça-lhe um nome significativo. É necessário fornecer um valor a rssimin que seja entre os valores mín e máx observados que você descobriu anteriormente para seu dispositivo Bluetooth.
    	// bluetooth related
    context.global.bttime=0;
    context.global.rssimin=-32;
    context.global.rssi=0;
    context.global.inBeacon=false;
    	
    // Timer related
    context.global.lastCmd="";
    context.global.nextSwitch=0;
    context.global.delay=30*1000; // 30 secs
    
    	// will be used later with gps
    	context.global.gpstime=0;
    	context.global.gps={lat: 0.0, lng:0.0};
    	context.global.inFence=true;
    	msg.payload="App initialized";
    	return msg;
  4. Configure o nó de Depurarção com a saída msg.payload e forneça-lhe um nome significativo.
  5. Implemente o código. Você deverá ver uma mensagem "Aplicativo inicializado" na guia de Depuraração .
  6. Arraste um nó inject , um nó de entrada ibmiot , dois nós function , um nó de saída ibmiot e um nó debug para sua área de trabalho.
  7. Configure o primeiro nó function com este código:
     	context.global.rssi=msg.payload.d.rssi
    	context.global.inBeacon=context.global.rssi>context.global.rssimin;
    	return msg;
  8. Configure o segundo nó function com o código abaixo:
    	//
    // determine when to send a switch command
    // A command is sent when a grace period has
    // expired since last switch (to protect the
    // appliance) and if the state of the appliance
    // is to be changed
    now = Date.now();
    dbg={ payload:""};
    var cmd=(context.global.inBeacon &&
     context.globalinFence)?"on":"off";
    if (now > context.global.nextSwitch &&
     context.global.lastCmd != cmd) {
     // we need to switch now
     context.global.nextSwitch+=now+context.global.delay;
     context.global.lastCmd=cmd;
     msg.payload=cmd;
     dbg.payload="switch appliance '"+cmd+"'";
    } else {
     msg=null
     dbg.payload="not switching appliance";
    }
    return [ msg, dbg ];
  9. Configure o nó ibmiot como na imagem abaixo.
  10. Finalmente, conecte os nós:
3c

Teste o aplicativo Node-RED

  1. Implemente seu aplicativo. Você deverá ver a mensagem "Aplicativo inicializado".
  2. Para testar o fluxo, clique no nó timestamp para inserir uma mensagem, se seu dispositivo ainda não estiver conectado. Se seu dispositivo estiver conectado, você deverá ver mensagens periódicas de "não alterar dispositivo".
  3. Mova lentamente o dispositivo Bluetooth mais próximo e mais distante de seu sistema Linux e você verá as mensagens de depuração que estão tentando ativar e desativar o dispositivo. Ao mesmo tempo, você deverá ver os comandos de ativação ou desativação que estão chegando no programa cliente que está em execução em seu Raspberry Pi e o script que está configurado para ativar seu ventilador ou luz ou ar condicionado (A/C) é chamado. Esteja ciente de que há um limite de taxa de uma comutação por 30 segundos; você pode desejar reduzir o parâmetro context.global.delay para propósitos de teste.
4

Inclua o fluxo no aplicativo Node-RED para aceitar e processar dados de GPS

Até o momento, criamos um aplicativo que ativa um dispositivo com base na proximidade de um dispositivo Bluetooth. Em seguida, aprimoraremos o aplicativo para usar uma localização geográfica específica que seja fornecida por um dispositivo GPS para determinar quando ativar um dispositivo.

Embora dispositivos GPS atualmente se comuniquem usando uma variedade de protocolos, para este tutorial e aplicativo de amostra, eu acredito que o GPS envia solicitações de HTTP com o par de latitude e longitude como uma carga útil da mensagem.

4a

Crie um terminal HTTP para o dispositivo GPS

Em seu editor de fluxo Node-RED, arraste um nó HTTP-input para sua área de trabalho. Dê um clique duplo nele para configurá-lo com esses valores:

  • Método:POST
  • URL:/gps
  • Nome:GPS Input [POST] /gps

Este nó HTTP aceita solicitações POST nesta URL: http://dwexample-iot.mybluemix.net/gps. Dados postados estão disponíveis como um objeto de mensagem no fluxo Node-RED. Os valores de latitude e longitude do dispositivo GPS são processados adicionalmente com relação a uma geo-fence.

O controle dos dispositivos por localização geográfica não está vinculado a um local específico. Geralmente, o controle ocorre entrando ou saindo de uma geo-fence definida. Uma fence em nosso aplicativo é representada como uma array de pares de latitude e longitude como objeto JSON, como este:

[
    {"lat":43.7074340290373,"lng":7.28219747543335},
	…
	…	
    {"lat":43.705196002070636,"lng":7.284321784973145},
    {"lat":43.706995349373884,"lng":7.284793853759766}
]
4b

Recupere a geo-fence a partir do banco de dados Cloudant

A array de pares de latitude e longitude é armazenada em um banco de dados Cloudant que faz parte do Internet of Things Platform Starter que foi usado para criar nosso aplicativo. Se um serviço de banco de dados Cloudant não existir em seu aplicativo, acesse o catálogo do IBM Cloud, localize o serviço Cloudant NoSQL DB e crie um serviço.

No recebimento de uma mensagem com coordenadas de GPS, nosso aplicativo precisa recuperar a definição de fence do banco de dados e, em seguida, determinar se o local que acabou de ser enviado está dentro ou fora da fence. O nó de banco de dados substitui o elemento de carga útil da mensagem, portanto, precisamos salvar temporariamente o corpo da solicitação de HTTP. Usamos os atributos globais de Node-RED como um armazenamento provisório para esta solicitação de HTTP.

Em seu editor de fluxo de Node-RED, inclua um nó function e inclua o seguinte código JavaScript no nó:

context.global.gps=msg.payload;
context.global.gpstime=Date.now();
msg.save=msg.payload;
msg.payload="fence";
return msg;

A consulta de banco de dados real é feita por um nó Cloudant a partir da seção de armazenamento da paleta. Arraste o nó com uma pequena nuvem para a esquerda, que é o nó query do Cloudant.

Configure o nó com esses valores:

  • Serviço: <your-app-name>
  • Banco de Dados: tsldemo
  • Procure por: _id
  • Nome:Recuperar Fence
4c

Determine se as coordenadas do GPS estão na geo-fence

A saída do nó Cloudant é alimentada com outro nó function , no qual um fragmento de JavaScript determina se as coordenadas do GPS estão dentro ou fora da fence. O algoritmo é obtido a partir do repo point-in-polygon da subpilha no GitHub. O nó function registra o estado da interface em um membro de estrutura global.

A saída do nó function é alimentada com esses nós:

  • Um nó HTTP response que retorna o status adequado para os dispositivos GPS
  • Um nó que reúne a medida do Bluetooth com o rastreamento do GPS

Este nó implementa a função ativar o A/C se o GPS estiver dentro da fence ou se o carro estiver perto o suficiente do sensor do Bluetooth, mas não se a última comutação for inferior a <m>inutos atrás. Incluindo a última condição, o aplicativo evita ativar ou desativar o A/C em intervalos curtos enquanto o carro está sendo conduzido no limite da fence. O código que implementa a função é semelhante ao código a seguir:

//
// determine when to send a switch command
// A command is sent when a grace period has
// expired since last switch (to protect the
// appliance) and if the state of the appliance
// is to be changed
now = Date.now();
var cmd=(context.global.inBeacon ||
 context.global.inFence)?"on":"off";
if (now > context.global.nextSwitch &&
 context.global.lastCmd != cmd) {
 // we need to switch now
 context.global.nextSwitch=now+context.global.delay;
 context.global.lastCmd=cmd;
 msg.payload=cmd;
 msg.format="text";
} else {
 msg=null
}
return msg;

O aplicativo Node-RED final é semelhante ao fluxo no Figura 2. Os nós cinza claro e cinza escuro são os nós que você criou nas Etapas de 1 a— 4.

Figura 2. Aplicativo Node-RED final
4d

Verifique as funções da geo-fence

Vamos fazer um teste simples das novas funções de geo-fence com coordenadas de GPS simuladas que enviamos por um comando curl.

  1. No painel do IBM Cloud, dê um clique duplo em seu serviço do Cloudant DB.
  2. Clique em Ativar para abrir o painel para seu banco de dados Cloudant:
  3. Em seu painel do banco de dados, insira um novo documento:
    	"_id": "fence",
      "fence": "[{\"lat\":50.945,\"lng\":6.955},{\"lat\":50.946,\"lng\":6.957},{\"lat\":50.943,\"lng\":6.962},{\"lat\":50.940,\"lng\":6.962}]"
  4. Clique em Salvar para armazenar o documento.
  5. Teste o fluxo de Node-RED com duas coordenadas de GPS simuladas (um par de lat/lng que esteja dentro da fence e um par de lat/lng que esteja claramente fora da fence) emitindo este comando curl (e especificando o nome de seu aplicativo de amostra):
    	curl -XPOST -d 'lat=1&lng=26' dwexample-iot.mybluemix.net/gps
    	{
    	  "bttime": 0,
    	  "rssimin": -32,
    	  "rssi": 0,
    	  "inBeacon": false,
    	  "lastCmd": "on",
    	  "nextSwitch": 1447771815039,
    	  "delay": 5000,
    	  "gpstime": 1447771815841,
    	  "gps": {
    	    "lat": "1",
    	    "lng": "2"
    	  },
    	  "inFence": false,
    	}

    Revise as mensagens na guia debug em seu editor de fluxo Node-RED.

    [root@traumcloud btclient]# ./dwclient
    trying to use ./dwclient.cfg for configuration
    got option 'btmac' with arg 00:0A:3A:2B:C6:ED
    got option 'subscription' with arg iot-2/cmd/switch/fmt/+
    [2015-11-17 18:42:25] got option 'host' with arg e62whi.messaging.internetofthings.ibmcloud.com
    got option 'password' with arg R3!1sFY(846HRCC0P6
    got option 'username' with arg use-token-auth
    got option 'typeid' with arg proximity
    got option 'organisation' with arg e62whi
    got MAC address of this machine as 'b827eb2fa78a'@  eth0
    now setting username and password
    log cb:received PUBLISH (d0, q0, r0, m0, '...'
    msg cb topic='iot-2/cmd/switch/fmt/text' payload='on'
    set state of switch2 to on
    log cb: 'Client received PUBLISH (d0, q0, r0, m0, '...'))'
    msg cb topic='iot-2/cmd/switch/fmt/text' payload='off'
    set state of switch2 to off
5

Inclua um painel para editar a fence do GPS e configure um limite para o indicador

Até o momento, controlamos o A/C com duas maneiras diferentes de obter a localização do carro:

  • Sentindo um indicador de Bluetooth em um estacionamento ou garagem
  • Rastreando o carro pelas coordenadas do GPS

Agora, em nosso aplicativo de amostra, ainda precisamos gerenciar esses dois dispositivos de aproximação. Precisamos configurar o limite para o indicador e, também, definir a fence de maneira mais realista. Para gerenciar esses dispositivos, incluiremos uma página da web que é uma UI de administração e incluiremos dois novos fluxos em nosso aplicativo de backend que retorne valores de operação atuais ou configuraremos novos valores de operação. Consulte Figura 3.

Figura 3. Um painel para a sensibilidade do Bluetooth e a visualização do GPS

O diagrama de sequência em Figura 4 descreve os componentes e suas interações que são necessários para criar o painel. O painel suporta esses casos de uso:

  • Monitoramento contínuo das coordenadas do GPS e da sensibilidade do Bluetooth
  • Editando e mudando a sensibilidade do Bluetooth
  • Ativando e mudando a geo-fence

O painel é implementado como uma página HTML e usa uma solicitação Ajax para obter dados do aplicativo backend. As linhas de vida à esquerda no Figura 4 são implementadas como fluxos no Node-RED.

Figura 4. Um painel para a sensibilidade do Bluetooth e a visualização do GPS
5a

Crie a página da web do painel

É possível fazer download dos arquivos necessários para construir o painel a partir de meu repo car-meets-home no GitHub. Você importará esses arquivos em seu aplicativo IBM Cloud IoT.

  1. Em seu painel do IBM Cloud, selecione seu aplicativo IoT e clique em Código de Edição.

    Os serviços do IBM Cloud DevOps são abertos. Pode demorar um pouco na primeira vez que você clica nele, pois ele gera um novo projeto para você.

  2. Na barra de navegação à esquerda, identifique a pasta pública. Clique com o botão direito na pasta pública e selecione Importar.
  3. No diálogo aberto, navegue até o arquivo dash.html e clique em Abrir. O arquivo dash.html aparece sob o diretório público.
  4. Clique com o botão direito novamente na pasta pública e selecione Nova > Pasta. Nomeie a nova pasta js.
  5. Clique com o botão direito na pasta js e importe o arquivo dash.js .
  6. Clique com o botão direito na pasta css e importe o arquivo dash.css .
  7. Clique com o botão direito na pasta imagens e importe os arquivos .png.

    Esses arquivos formam o aplicativo de painel. É possível abrir seu painel anexando /dash.html à rota de seu aplicativo (por exemplo, <your name>.mybluemix.net/dash.html).

5b

Inclua APIs no fluxo para atender às solicitações Ajax

Para que o painel funcione, precisamos incluir algumas APIs em nosso fluxo de Node-RED. O painel obtém o status do aplicativo backend com uma solicitação HTTP-GET para /status. Da mesma forma, o novo valor rssimin (a sensibilidade) é enviado com uma solicitação HTTP-POST para /status. A geo-fence é recuperada por um GET para /fence, enquanto a fence é armazenada com um POST para /fence.

Crie os fluxos e inclua o código nas funções:

  1. Inclua fluxos para recuperação de status e atualize como na figura abaixo:
  2. Inclua o seguinte código no nó denominado Add global as payload:
    msg.payload=context.global;
    msg.payload.jt=Date.now();
    return msg;
  3. O código JavaScript a seguir na página da web utiliza os valores de Bluetooth e de GPS e os exibe na forma de texto, graficamente como um indicador de medida para valores do Bluetooth e como uma posição em um mapa para valores do GPS. As principais linhas de código para exibir os dados são:
    	    //
    	    // get status and display methods
    	    //
    	    this.getData=function () {
    		 	$.ajax({url: "/status",
    		 	 	success: thiz.getDataOK,
    		 	 	error: thiz.getDataErr,
    		 	 	dataType: "json"
    		 	});
    		 	window.setTimeout(thiz.getData, 5000);
    	    };
    	    this.getDataOK=function (data) {
    		 	//console.dir(data);
    		 	if (olddata == null) olddata=data;
    	
    		 	car.setLatLng(L.latLng(data.gps.lat, data.gps.lng));
    		 	map.panTo(L.latLng(data.gps.lat, data.gps.lng));
    	
    		 	$('#bt-rssi').text(data.rssi+"/"+data.lq);
    		 	$('#bt-rssimin').text(data.rssimin);
    		
    		 	$('#time').text(new Date().toLocaleString());
    		 	thiz.drawRssiMeter(data);
    		 	olddata=data;
    	
    	    };
    	    this.drawRssiMeter=function (data) {
    		 	var rssi=Math.floor(data.rssi||-50);
    		 	var rssimin=Math.floor(data.rssimin||-50);
    		 	var min = Math.min(rssimin, rssi);
    		 	var max = Math.max(rssimin, rssi);
    	
    		 	var rssiMeterData = new google.visualization.DataTable();
    	
    		 	rssiMeterData.addColumn('number', 'Rssi');
    		 	rssiMeterData.addColumn('number', 'lq');
    		 	rssiMeterData.addRows(2);
    		 	rssiMeterData.setCell(0, 0, rssi);
    	
    		 	rssiMeterOptions.min=min-15;
    	 	 	rssiMeterOptions.max=max+5;
    		 	 	 	
    		 	rssiMeterOptions.greenFrom=rssimin;
    		 	rssiMeterOptions.yellowTo=rssimin;
    	  	 	// draw space from min to yellow to half yellow, half red
    		 	var step=Math.floor(Math.abs(rssimin-rssiMeterOptions.min)/2);
    		 	rssiMeterOptions.yellowFrom=rssimin-step;
    		 	rssiMeterOptions.redTo=rssimin-step;
    	
    		 	rssiMeterOptions.redFrom=Math.min(min,rssimin)-2*step;
    		 	
    		 	rssiMeter.draw(rssiMeterData, rssiMeterOptions);
    	    };
  4. O painel contém um pouco mais de linhas de código, o que faz com que os valores alterados sejam exibidos em vermelho entre conjuntos de dados.

    O botão denominado "Inserir novo valor para RSSI Min" utiliza os valores inseridos para RSSI e envia os dados à API Node-RED.

        this.getDataErr=function (xhr, sts, txt) {
    	    thiz.error("Ajax Error: sts='"+sts+"', txt='"+txt+"'");
        };
        //
        // update bluetooth sensitivity
        //
        this.setRssiVal=function() {
    	 	var url="/status";
    	 	$.ajax({url: url,
    	 	 	success: thiz.getDataOK,
    	 	 	error: thiz.getDataErr,
    	 	 	method: "POST",
    	 	 	data: {rssimin: $('#rssid-val-text').val().trim()},
    	 	 	dataType: "json"
    	 	 	});
        };
  5. A API Node-RED configura o valor de RSSI (sensibilidade do Bluetooth) na estrutura de variável global.
    if (msg.payload.rssimin) context.global.rssimin=msg.payload.rssimin;
    msg.payload=context.global;
    return msg;
  6. Da mesma maneira, é possível incluir elementos da UI para o tempo de atraso entre operações de comutação e configurá-los para os fluxos semelhantes a rssimin.

    Inclua fluxos para recuperar os dados da geo-fence conforme mostrado na figura a seguir:

        var storeFence=function() {
        	var ll=fence.getLatLngs();
    	 	var data={ fence: JSON.stringify(ll) };
    	 	if (fencers._id !== undefined) data._id=fencers._id;
     	 	if (fencers._rev !== undefined) data._rev=fencers._rev;
    	 	// upload to bluemix
    	 	$.ajax({
    	 	 	url: "/fence2",
    	 	 	data: data,
      	 	 	contenttype: "application/json",
    	 	 	method: "POST",
    	 	 	/**
    	 	 	 * @callback
    	 	 	 */
    	 	 	success: function( data ) {
    	 	 	 	$('#upload').show();
    	 	 	 	window.setTimeout(function() {
    	 	 	 	 	$('#upload').fadeOut(2000);
    	 	 	 	}, 2000);
    	 	 	 	loadFence(); // to update _rev
    	 	 	}
    	 	});
    	};
  7. O carregamento da geo-fence é implementado como dois métodos, o primeiro para chamar a API Node-RED API de modo assíncrono e o segundo como uma função de retorno de chamada. A geo-fence é carregada quando o aplicativo inicia ou quando o usuário pressiona o botão carregar .
    var loadFence=function() {
    	// load the fence definition from bluemix
    	//
    	$('#download').show();
    	$.ajax({
    	 	url: "/fence",
    	 	contenttype: "application/json",
    	 	method: "GET",
    	 	success: function( data ) {
    	 	 	$('#download').fadeOut(1000);
    	 	 	$('#received').fadeIn(1000);
    	 	 	window.setTimeout(function() {
    	 	 	 	$('#received').fadeOut(1000);
    	 	 	}, 2000);
    	 	 	loadFenceOK(data);
    	 	},
    	 	error: function(a, b) {
    	 	 	thiz.error("Cannot load fence data, reason given: '"+a+"':'"+b+"'");
    	 	}
    	});
    };
    var loadFenceOK=function(data) {
        var ll=[];
        var i;
        fencers=data;
        if (data.fence) {
            ll=JSON.parse(data.fence);
    	    for (i=0; i<ll.length; i++) {
    	 	L.marker([ll[i].lat, ll[i].lng], {icon: reddot}).addTo(map).on('click', removeDot);
    	    }
    	}
    	fence=L.polygon(ll, {color: 'red'}).addTo(map);
    	//
    	// position map to fit car & fence in browser window
    	//
    	ll=fence.getLatLngs();
    	var b=L.latLngBounds(ll);
    	b.extend(car.getLatLng());
    	map.fitBounds(b, {animate: true, duration: 2.0});
    	$('#save').prop( "disabled", ll.length <= 2 );
    	$('#load').prop( "disabled", false);
    };
  8. Além disso, o painel contém um editor de geo-fence básico. Se você clicar em um ponto no mapa, o ponto será incluído no polígono e definirá a área da geo-fence. Se você clicar em um dos pontos vermelhos, o ponto será removido do polígono da geo-fence.
    1. Para remover o ponto do polígono, um loop compara as coordenadas das coordenadas no polígono com relação às coordenadas do ícone criado com Leaflet. Se elas corresponderem, o ponto será removido do polígono.
          //
            // fence editor (very basic)
          //
          var removeDot=function(me) {
      	 	var ll=fence.getLatLngs();
      	 	var i, l=ll.length;
      	 	for (i=0; i<l; i++) {
      	 	 	var p=ll[i];
      	 	 	var dx=p.lat-me.latlng.lat; // distance of a dot in fence to position clicked on map
      	 	 	var dy=p.lng-me.latlng.lng;
      	 	 	if (dy === 0 || dx === 0) {
      	    		fence.spliceLatLngs(i, 1);
      	    		l--;
      	    		break;
      	 	 	}
      	 	}
      	 	 
      	 	map.removeLayer(me.target);	// delete dot clicked on;
      	 	$('#save').prop( "disabled", l <= 2 );
      
          };
    2. A inclusão de um ponto no polígono precisa de um pouco mais de esforço, pois o código precisa localizar os dois pontos do polígono que sejam os melhores para incluir o novo ponto entre eles. O aplicativo do painel executa as seguintes etapas:
      • Localizar o ponto mais próximo das coordenadas do ponto que foi clicado no mapa.
      • A partir de dois vizinhos, determinar o mais próximo do ponto no mapa.
      • Insira o novo ponto entre os dois pontos localizados.

      O código JavaScript, que cuida de polígonos (quase) vazios e do estado do botão Salvar, é semelhante ao código a seguir:

      var addDot=function(me) {
          	// see which existing dot is close to the mouse event me as p1
          	// find the adjacent nodes of p1 closest to me
          	// insert me between them
          	var ll=fence.getLatLngs();
          	var i, l=ll.length;
          	var p0=me.latlng, p1=null, p2=null;
          	if (l < 2) {
          	 	// there is no or only one dot in the fence - just add anew one
          	 	fence.addLatLng([ok, good, me.latlng.lng]);
          	} else {
          	 	var dist=0x07ffffff;	// max 32bit signed int
      	    	var p, dlat, dlng;
      	    	var d=Math.sqrt(dlat*dlat+dlng*dlng);
      	    	for (i=0; i<l; i++) {
      	    		p=ll[i];
      	    		dlat=p0.lat-p.lat;
      	    		dlng=p0.lng-p.lng;
      	    		d=Math.sqrt(dlat*dlat+dlng*dlng);
      	    		if (d < dist) {
      	    			p1=i;
      	    			dist=d;
      	    		}
      	    	}
      	    	// find closest adjacent
          	 	p2=(p1+l-1)%l;
          	 	p=ll[p2];
          	 	dlat=p0.lat-p.lat;
          	 	dlng=p0.lng-p.lng;
      	    	dist=Math.sqrt(dlat*dlat+dlng*dlng);
      	    	
          	 	p=ll[(p1+l+1)%l];
          	 	dlat=p0.lat-p.lat;
           	 	dlng=p0.lng-p.lng;
      	    	d=Math.sqrt(dlat*dlat+dlng*dlng);
      	    	if (d < dist) p2=(p1+l+1)%l;
      	    	console.log("add dot @"+p1+"/"+p2);
      	    	if (p1 > p2) { var t=p1; p1=p2; p2=t;}
      	    	// special case: p1 and p2 are beginning and end of array
        	    	if (p1 === 0 && p2 === l-1) {
      	    		fence.addLatLng(p0);
      	    	} else {
      	    		fence.spliceLatLngs(p2, 0, p0);
      	    	}
          	}
      	L.marker(me.latlng, {icon: reddot}).addTo(map).on('click', removeDot);
      	$('#save').prop( "disabled", l+1 <= 2 );
          };

      Observe que um ponto no polígono é implementado como um Ícone Leaflet com um retorno de chamada que é acionado quando o usuário clica no ícone. Como consequência, o ponto é removido do polígono e o ícone associado é removido do mapa. Este código permite que você determine facilmente se um clique do usuário é para incluir ou para remover um ponto no polígono da geo-fence.

É possível ver o painel da demo em execução no IBM Cloud:
http://car-meets-home.mybluemix.net/.

Conclusão

Neste tutorial, você aprendeu como criar um aplicativo IBM Cloud, registrar um Raspberry Pi no Watson IoT Platform, obter acesso aos dados do dispositivo e gravar um aplicativo Node-RED para processar dados que são recebidos usando o protocolo MQTT.

No Raspberry Pi, você criou um cliente MQTT que pode relatar a força do sinal do Bluetooth e receber comandos de seu aplicativo IBM Cloud.

Estendemos de modo rápido e fácil o aplicativo básico para incluir novas funções, como receber coordenadas do GPS a partir de um dispositivo externo, decidir quando ativar os dispositivos com base em uma combinação da força de sinal do Bluetooth e uma localização geográfica dentro ou fora de uma geo-fence definida. Por último, criamos um painel para definir a geo-fence para a função de controle do GPS e configuramos a sensibilidade do sensor do Bluetooth. As funções foram incluídas como APIs apenas com alguns nós extras no aplicativo Node-RED.

Agora, vá exibir sua inteligência e conectar seu carro à sua casa.


Recursos para download


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Internet of Things
ArticleID=1036217
ArticleTitle=Traga a IoT para casa: conecte seu carro à sua casa
publish-date=12262016