Introduction: Saude Certa - Monitorando Pacientes

About: IoT Researcher and Entusiast.
Intro: This is a project of the Qualcomm partnerships program, in which a prototype for patient monitoring and identification was developed. Our goal with this project is to help identify patients, medications and vital signs monitoring of home-care patients. We are using the Qualcomm DragonBoard 410c connected to the Microsoft Azure IoT Hub to capture the data and send them to applications that can monitor them.

Nos oferecemos tecnologia para aumento de eficiência, monitoramento em tempo real e segurança ao paciente de home care.

Neste Instructables, iremos mostrar o conceito do desenvolvimento de um protótipo para monitoramento de pacientes em tempo real, no qual serão capturados os sinal vitais do paciente, dados do ambiente (quarto) e permitirá ao paciente emitir comandos de voz.

Os dados capturados são então enviados para o Microsoft Azure, onde foi criado um IoT Hub para recepção de dados e um Stream Analytics para que os dados sejam apresentados em uma página Web. Um banco de dados SQL foi também criado para manter um registro dos dados.d araP foram utilizados:

Para desenvolver este projeto, foram utilizados:

Hardware

  1. Placa DragonBoard 410c (Datasheet)
  2. Placa Linker Mezzanine (Especificações)
  3. Sensor de Batimentos Cardíacos (da Pulse Sensor)
  4. Sensor de toque (Especificações)
  5. Sensor de temperatura DS18b20 (Datasheet)
  6. Sensor de temperatura e umidade DHT11 (Datasheet)
  7. Arduino Pró Mini (Datasheet)
  8. Módulo RFID RC-522 (Datasheet)
  9. Tela 14 polegadas LED (aproveitada de um notebook, conector 30 pinos LVDS)
  10. Placa LVDS - HDMI v56/v29
  11. Microfone (USB ou com adaptador USB)
  12. Módulo de Relés duplo
  13. Módulo de Led 12 volts
  14. Ventilador 12 volts
  15. Fonte de Alimentação
  16. Placa Controladora de Energia
  17. Placa para montagem do Arduino Pro Mini e Sensores
  18. Base para montagem dos componentes

Software:

  1. Windows IoT Core
  2. Microsoft Visual Studio 2017
  3. Azure IoT Hub
  4. Azure Stream Analytics
  5. Azure SQL Server
  6. Azure Web Application
  7. Arduino IDE
  8. DragonBoard Update Tool

Step 1: Preparando O Ambiente De Software

O primeiro passo de desenvolvimento foi a instalação do Windows 10 IoT Core na DragonBoard 410c, descrito neste Instructables.

Após a instalação do Windows IoT Core, foi realizada a configuração do Windows IoT Core na DragonBoard através da ferramenta Windows IoT Core DashBoard.

Através do IoT DashBoard, é possível acessar a ferramenta de configuração do Windows 10 IoT Core, o Device Portal. O Device Portal é acessado através do endereç IP da placa na porta 8080, no nosso caso http://192.168.1.6:8080. O login padrão é administrator e a senha p@ssw0rd.

Para programar um dispositivo com Windows IoT Core, vamos utilizar o Visual Studio 2017 Community, disponível aqui e é necessário instalar o IoT Core Templates do Visual Studio Galleries, disponível aqui. Outro componente utilizado foi o Azure IoT Hub Connected Services, disponível no gerenciador de bibliotecas Nuget do Visual Studio. Maiores informações sobre o Azure IoT Hub Connected Services pode ser obtido aqui.

Uma vez instalados, podemos programar o dispositivo utilizando a linguagem C#.

O desenvolvimento da tela da aplicação foi feito no editor XAML do Visual Studio. É importante notar que quando a aplicação está compilada, executando e sendo debugada pelo Visual Studio, qualquer modificação que realizemos na interface gráfica usando XAML é refletida automaticamente na tela da aplicação em execução. Isto facilitou enormemente o desenvolviemento da interface gráfica.

Step 2: Diagrama Em Blocos Da Aplicação

Nosso projeto utiliza a DragonBoard 410c, conectada a uma placa Linker Base Mezzanine.

A Linker Base Mezzanine possui uma porta UART para comunicação serial, quatro conectores para portas digitais, totalizando 8 portas digitais, dois conectores conectados a um conversor Analógico-Digital (ADC), totalizando 4 portas ADC, sendo duas portas em cada conector.

Conectamos o sensor de batimentos cardíacos à porta ADC1, canal A0 e os relés foram conectados na porta D3, canais 1 e 2, permitindo o controle de dois relés. O sensor de toque foi conectado à porta digital D2, no canal 1 desta porta.

A placa Arduino foi utilizada por possuirmos parte da nossa solução de captura de dados já desenvolvida utilizando os sensores DHT11 para temperatura e umidade ambiente e o sensor ds18b20 para captura da temperatura corporal, além do leitor RC522 para captura dos cartões RFID, utilizados para identificar os pacientes e aproveitando as bibliotecas desses sensores.

Conectamos o Arduino à porta UART da Linker Mezzanine, o que nos permitiu um enorme ganho de tempo no desenvolvimento, ao conseguirmos conectar à DragonBoard uma solução legada e integrá-la ao Azure.

Isso também nos permitiu mostrar a modularidade de nossa solução, uma vez que podemos adicionar novos sensores através de comunicação serial, bluetooth ou mesmo wifi.

No diagrama em blocos podemos observar que foi desenvolvida uma placa para que pudéssemos realizar a distribuição da energia para a DragonBoard, para a placa conversora de vídeo e para os relés, que controlam a lâmpada e o ventilador.

Step 3: Portas Digitais Na Linker Mezzanine E Windows IoT

Mapeamos os endereços das portas na Linker Mezzanine na DragonBoard e criamos duas classes para mapear essas portas para facilitar o desenvolvimento.

public class CanalADC {
        public static byte ADC1_A0 = 0x80;
        public static byte ADC1_A1 = 0x90;
        public static byte ADC2_A2 = 0xA0;
        public static byte ADC2_A3 = 0xB0;    }

public class PortaDigital {
        public static int D1_1 = 36;
        public static int D1_2 = 12;
        public static int D2_1 = 13;
        public static int D2_2 = 69;
        public static int D3_1 = 115;
        public static int D3_2 = 34;
        public static int D4_1 = 24;
        public static int D4_2 = 25;    }

Com isso, mapeamos os pinos à às portas, facilitando o entendimento do código, onde temos o PINO_HEARTBEAT para conectar o sensor de batimentos cardíacos, o PINO_GOTAS, para mapear o sensor de gotejamento (ainda em desenvolvimento), o PINO_LUZ para controlar o relé da iluminação, o PINO_VENT para controlar o relé da ventilação e o PINO_BOTAO para controlar ciclicamente o acionamento da iluminação e da ventilação por um toque:

private byte PINO_HEARTBEAT = CanalADC.ADC1_A0;
private byte PINO_GOTAS = CanalADC.ADC2_A2;             
private int PINO_LUZ = PortaDigital.D3_2;         
private int PINO_VENT = PortaDigital.D3_1;         
private int PINO_BOTAO = PortaDigital.D2_1;

Como o Windows IoT é um sistema operacional multithread, vamos criar algumas threads para ler os dados dos sensores. Declaramos as portas GPIO com os valores das portas da DragonBoard declaradas anteriormente.

gpio = GpioController.GetDefault();    
pinoBotao = gpio.OpenPin(PINO_BOTAO);
pinoLuz = gpio.OpenPin(PINO_LUZ);
pinoVent = gpio.OpenPin(PINO_VENT);

Para o controle do Relé, declaramos a porta como saída (Output) em SetDriveMode e escrevemos na porta como Low para deixar as portas desligadas inicialmente, no método Write(GpioPinValue.Low).

pinoLuz.Write(GpioPinValue.Low);             
pinoLuz.SetDriveMode(GpioPinDriveMode.Output);
pinoVent.Write(GpioPinValue.Low);
pinoVent.SetDriveMode(GpioPinDriveMode.Output);pinoBotao.SetDriveMode(GpioPinDriveMode.Input);
pinoBotao.DebounceTimeout = TimeSpan.FromMilliseconds(50); pinoBotao.ValueChanged += pinoBotao_ValueChanged;

Criamos um método para verificar o estado do botão de toque, alternando entre os estados de ligado e desligado do ventilador e da luz. O método pinoBotao_ValueChanged é acionad sempre que for detectada uma variação na porta do pino. Cada vez que o botão por tocado, a variável switchModoBotao irá mudar de valor, alterando qual relé estará ligado, como pode ser visto no código abaixo.

private void pinoBotao_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{ if (args.Edge == GpioPinEdge.FallingEdge) { switch (switchModoBotao) {
case 0:
//Liga luz
pinoVent.Write(GpioPinValue.Low);
pinoLuz.Write(GpioPinValue.High);
switchModoBotao++;
break;
case 1:
// Liga ventilador
pinoVent.Write(GpioPinValue.High);
pinoLuz.Write(GpioPinValue.High);
switchModoBotao++;
break;
case 2:
// Desliga luz
pinoVent.Write(GpioPinValue.High);
pinoLuz.Write(GpioPinValue.Low);
switchModoBotao++;
break;
case 3:
// Desliga tudo;
pinoVent.Write(GpioPinValue.Low);
pinoLuz.Write(GpioPinValue.Low);
switchModoBotao = 0;
break; } }

Step 4: Portas Analógicas Na Linker Mezzanine E Windows IoT

O conversor analógico-digital da Linker Base Mezzanine é baseado no chip Conversor Analógico Digital MCP3004. O MCP3004 possui 4 canais de conversão de 10 bits cada e ele é conectado à DragonBoard através do barramento SPI, que no caso da DragonBoard é a SPI 0.

O primeiro passo é inicializar o SPI:

private async Task InitSPI()
{ try { var settings = new SpiConnectionSettings(0); // Seleciona a porta SPI0 da DragonBoard settings.ClockFrequency = 500000; // Configura o clock do barramento SPI em 0.5MHz settings.Mode = SpiMode.Mode0; // COnfigura polaridade e fase do clock do SPI var controller = await SpiController.GetDefaultAsync(); SpiADC = controller.GetDevice(settings); }
catch (Exception ex) {
throw new Exception("Falha na inicialização do SPI", ex); } }

Após inicializar o SPI, devemos chamar um método para ler as portas periodicamente. No caso, iremos criar uma thread para a leitura do ADC a cada 50ms.

_frequenciaHeartBeat = ThreadPoolTimer.CreatePeriodicTimer(atualizaHeartBeat, TimeSpan.FromMilliseconds(50));

No método frequenciaHeartBeat, passamos qual a porta à ler para pegar os dados (no caso, do sensor de batimentos cardíacos).

private void atualizaHeartBeat(ThreadPoolTimer timer)        {
         byte[] readBuffer = new byte[3];                        // Buffer para receber os dados
byte[] writeBuffer = new byte[3] { 0x00, 0x00, 0x00 };
writeBuffer[0] = 0x01;
writeBuffer[1] = canalADC.ADC2_A2; // Seleciona qual canal do ADC irá ser lido SpiADC.TransferFullDuplex(writeBuffer, readBuffer); // Lê os dados do ADC
adcValue = ConvertToInt(readBuffer); // Converte os valores em Inteiro return adcValue; }

O valor lido em adcValue é o utilizado para calcularmos a frequência cardíaca. A mesma metodologia é utilizada para lermos o valor do sensor de gotejamento, ainda em desenvolvimento.

Step 5: Comunicando a DragonBoard Com O Arduino

Para lermos os sensores DHT11 e DS18B20, bem como o leitor de cartões RFID RC522, utilizamos um Arduino Pro Mini e criamos a comunicação do mesmo com a DragonBoard através da porta UART da Linker Mezzanine e das portas RX e TX do Arduino.

Com isso, quisemos aproveitar as bibliotecas dos sensores e do leitor do Arduino em uma solução que utilizávamos anteriormente, permitindo um ganho no tempo de desenvolvimento. Do lado do Arduino, configuramos para que o Arduino escrevesse na saída serial, através da instrução Serial.print(dadosSensor).

No lado da DragonBoard, criamos um método para abrir a porta serial e configurá-la

public async void ConectaSerial()
{ var selection = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector("UART1")); if (selection.Count <= 0) return;
DeviceInformation entry = (DeviceInformation)selection[0];
try {
serialPort = await SerialDevice.FromIdAsync(entry.Id);
txtSerial.Text = entry.Id.ToString();
if (serialPort == null) return;
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(100);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(100);
serialPort.BaudRate = 115200;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
ReadCancellationTokenSource = new CancellationTokenSource();
Listen(); } catch (Exception ex) { txtSerial.Text = ex.Message; } }

public async void Listen()
{ try { if (serialPort != null) { dataReaderObject = new DataReader(serialPort.InputStream);

while (true) { await ReadAsync(ReadCancellationTokenSource.Token); } } } catch (TaskCanceledException tce) { Debug.WriteLine("TaskCanceledException Erro: " + tce.ToString()); CloseDevice(); } catch (Exception ex) { Debug.WriteLine("Erro: " + ex.ToString()); } finally { if (dataReaderObject != null) { dataReaderObject.DetachStream(); dataReaderObject = null; } } } // Método para ler os dados de forma assíncrona
        public async Task ReadAsync(CancellationToken cancellationToken)
        {
            Task loadAsyncTask;
uint ReadBufferLength = 1024;
// Obedecer se a tarefa assincrona for cancelada cancellationToken.ThrowIfCancellationRequested();
// Configura InputStreamOptions para completar a operação assíncrona de leitura quando dados forem recebidos.
dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
using (var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) {
// Cria um objeto para receber os dados de serialPort.InputStream
loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(childCancellationTokenSource.Token);
// Inicializa a tarefa e aguarda os dados
bytesRead = await loadAsyncTask;
if (bytesRead > 0)
{
dadosRecebidos = dataReaderObject.ReadString(bytesRead);// .Replace("\r\n", "");
string[] sensores = dadosRecebidos.Split(';');
foreach (string sensor in sensores) {
string[] dadoSensor = sensor.Split(':');
if (dadoSensor.Length > 1)
{
await AnalisaSensor(dadoSensor[0], dadoSensor[1]);
} } } }

Step 6: Trabalhando Com a Detecção De Voz

A detecção de voz foi realizada para que o paciente ou acompanhante pudesse controlar o ambiente e chamar a enfermagem com o máximo de praticidade. Utilizamos os comandos "ligar", "desligar" e "chamar" e como objeto dos comandos utilizamos "ventilador", "luz", "tudo" para ligar ou desligar os dois últimos e "enfermagem". Desta forma, a DragonBoard pode interpretar comandos como "ligar ventilador", "chamar enfermagem" ou "desligar tudo".

Para a detecção de voz, utilizamos um microfone USB, que é detectado pelo Windows IoT de forma automática. No Windows IoT, utilizamos a biblioteca Windows.Media.SpeechRecognition, que é responsável por decodificar e interpretar a voz.

Na nossa aplicação, adicionamos ícones para mostrar quando a voz é detectada e é interpretada, dando um retorno visual aos usuários.

É necessário construir um arquivo XML com a gramática a ser interpretada, de forma que possamos criar variações dos comandos de voz e deixando a interpretação sem ambiguidades.

Inicialmente, declaramos o arquivo de gramática que conterá os comandos, bem como as constantes a serem utilizadas no código principal para executar os comandos, como Ligar Luz.

	private const string SRGS_FILE = "Gramatica\\gramatica.xml";<br>        private const string TAG_CMD = "cmd";
        private const string TAG_DEVICE = "device";
        private const string STATE_ON = "LIGADO";
        private const string STATE_OFF = "DESLIGADO";
        private const string DEVICE_LUZ = "LUZ";
        private const string DEVICE_VENT = "VENT";
        private const string DEVICE_ENFERMEIRA = "ENFERMAGEM";
        private const string DEVICE_TUDO = "TUDO";
        private const string DEVICE_CHAMAR = "CHAMAR";
        private const string DEVICE_EXIBIR = "EXIBIR";
        private const string DEVICE_PARAR_EXIBIR = "PARAR_EXIBIR";
        private const string DEVICE_FILME = "FILME";
        private SpeechRecognizer recognizer;

Criamos um método para inicializar o reconhecimento de voz. No momento da escrita deste Instructables, não conseguimos colocar a localização em português, mas a interpretação tem funcionado adequadamente:

private async void InicializaVoz()<br>        {
            var idioma = new Windows.Globalization.Language("en-US");
            recognizer = new SpeechRecognizer(idioma);<br>            recognizer.StateChanged += RecognizerStateChanged;<br>            recognizer.ContinuousRecognitionSession.ResultGenerated += RecognizerResultGenerated;<br>            string fileName = String.Format(SRGS_FILE);<br>            StorageFile grammarContentFile = await Package.Current.InstalledLocation.GetFileAsync(fileName);<br>            SpeechRecognitionGrammarFileConstraint grammarConstraint = new SpeechRecognitionGrammarFileConstraint(grammarContentFile);<br>            recognizer.Constraints.Add(grammarConstraint);<br>            SpeechRecognitionCompilationResult compilationResult = await recognizer.CompileConstraintsAsync();<br>            if (compilationResult.Status == SpeechRecognitionResultStatus.Success)            {<br>                await recognizer.ContinuousRecognitionSession.StartAsync();<br>            } else { Debug.WriteLine("Status: " + compilationResult.Status);}         }

Uma vez inicializado o reconhecimento, temos o método RecognizerResultGenerated, que recebe os comandos interpretados pelo reconhecedor de voz. No método abaixo é onde podemos executar os comandos. Caso o interpretador detecte que o comando é DEVICE_LUZ, ele irá verificar a constante STATE_ON. Se estiver ligado, ele irá alternar o estado da porta pinoLuz através do método EscreveGPIOPin, ligando-a ou desligando-a. O método mudaImagem é utilizado para alternar a imagem na tela da aplicação, dando um retorno visual sobre o estado da luz ou do ventilador.

private void RecognizerResultGenerated(SpeechContinuousRecognitionSession session, SpeechContinuousRecognitionResultGeneratedEventArgs args)<br>        {          int count = args.Result.SemanticInterpretation.Properties.Count;<br>             String cmd = args.Result.SemanticInterpretation.Properties.ContainsKey(TAG_CMD) ? args.Result.SemanticInterpretation.Properties[TAG_CMD][0].ToString() : "";<br>            String device = args.Result.SemanticInterpretation.Properties.ContainsKey(TAG_DEVICE) ? args.Result.SemanticInterpretation.Properties[TAG_DEVICE][0].ToString() :  "";<br>            // Verifica se o estado do comando é ligado ou desligado<br>            bool isOn = cmd.Equals(STATE_ON);<br>            if (device.Equals(DEVICE_LUZ))<br>            {<br>                EscreveGPIOPin(pinoLuz, isOn ? GpioPinValue.High : GpioPinValue.Low);<br>                if (isOn)<br>                {<br>                    mudaImagem(imgLuz, "luzOn");<br>                }<br>                else<br>                {<br>                    mudaImagem(imgLuz, "luzOff");<br>                }<br>            }<br>            else if (device.Equals(DEVICE_VENT))<br>            {        EscreveGPIOPin(pinoVent, isOn ? GpioPinValue.High : GpioPinValue.Low)<br>		     if (isOn)                {<br>                    mudaImagem(imgVent, "venton");<br>                }<br>                else<br>                {<br>                    mudaImagem(imgVent, "ventoff");<br>                }<br>            }<br>            else if (device.Equals(DEVICE_TUDO))<br>            {<br>                EscreveGPIOPin(pinoVent, isOn ? GpioPinValue.High : GpioPinValue.Low);<br>                EscreveGPIOPin(pinoLuz, isOn ? GpioPinValue.High : GpioPinValue.Low);<br>                if (isOn)<br>                {<br>                    mudaImagem(imgLuz, "luzOn");<br>                    mudaImagem(imgVent, "venton");<br>                }<br>                else
                {<br>                    mudaImagem(imgLuz, "luzOff");<br>                    mudaImagem(imgVent, "ventoff");<br>                }<br>            }<br>            else if (device.Equals(DEVICE_ENFERMEIRA))<br>            {<br>                if (cmd.Equals(DEVICE_CHAMAR))<br>                    mudaEnfermeira();  }
            else<br>            { Debug.WriteLine("Dispositivo Desconhecido");  }        }

O método mudaEnfermeira é chamado apenas para demonstrar a funcionalidade e mostra a imagem de uma enfermeira na tela.

No arquivo de gramática, Gramatica.xml, temos as regras de interpretação. O arquivo está em anexo.

Step 7: Comunicando Com O Azure

Para comunicar com o Azure, no Visual Studio temos a praticidade de conectar automaticamente o chamado Connected Services, que é um plugin instalado através do Nuget. Através do Connected Services, conseguimos selecionar qual o IoT Hub de uma conta no Azure iremos utilizar para a comunicação com a nuvem.

Ao instalar o Azure IoT Connected Services, automaticamente é criado um arquivo com a string de conexão do IoT Hub do Azure e dois métodos, um para enviar os dados para a nuvem e outro para receber dados da nuvem. Na atual etapa de nosso projeto, estamos utilizando apenas a comunicação dispositivo->nuvem.

<p>// String de conexão gerada pelo Azure IoT Hub e capturada automaticamente pelo IoT Connected Services do Visual Studio</p><p>const string deviceConnectionString = "HostName=xxxxx.azure-devices.net;DeviceId=xxxxx;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";</p>
public static async Task SendDeviceToCloudMessageAsync(TelemetriaPaciente telemetria)<br>    {
        var messageString = JsonConvert.SerializeObject(telemetria);
        var message = new Message(Encoding.ASCII.GetBytes(messageString));
        var deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Mqtt);<br>	try {
            await deviceClient.SendEventAsync(message);  // Aqui a mensagem é enviada para o Azure
            } 
	catch (Exception azureError)<br>		{ Debug.WriteLine("Erro de conexão:" + azureError.ToString()); }}

Os dados são enviados através de um objeto denominado TelemetriaPaciente, onde encapsulamos todos os dados pertinentes para o monitoramento do paciente. Um exemplo de código mostrando o envio dos dados para a nuvem está abaixo:

...
<p>telemetria = new TelemetriaPaciente {</p>     		    hospitalId = txtCodHospital.Text,
                    pacienteId = txtCodPaciente.Text,
                    temperaturaAmbiente = txtTempAmbiente.Text,
                    temperaturaCorporal = txtTemperaturaCorporal.Text,
                    umidadeAmbiente = txtUmidade.Text,
                    pressaoArterial = txtPressaoArterial.Text,
                    oxigenacao = txtOximetro.Text,
                    batimento = txtFrequenciaCardiaca.Text,
                    statusLuz = Convert.ToString(pinoLuz.Read() == GpioPinValue.High ? true : false),
                    statusVentilador = Convert.ToString(pinoVent.Read() == GpioPinValue.High ? true : false),
                    horaEnvio = DateTime.Now.ToString(),
                    horaSomente = DateTime.Now.ToString("HH:mm:ss"),
                    contador =conta.ToString() 
                };<br>		try {<br>                    // Envia os dados da telemetria para a nuvem
		    await AzureIoTHub.SendDeviceToCloudMessageAsync(telemetria);<br>                    txtConexao.Text = "Azure:" + telemetria.horaEnvio;<br>                    ultimoEnviado = DateTime.Now;<br>                }<br>                catch (Exception exy)<br>                {<br>                    Debug.WriteLine("Erro Azure:" + exy.ToString());<br>                }<br>                finally { telemetria = null; }<br>            }
...


-Através de um IoT Hub, recebemos os dados enviados pelo DragonBoard em formato JSON.

-Crie um serviço de servidor MS SQL Server ou com a base de dados de sua preferência, onde será hospedado o banco de dados.

Crie a tabela, com os campos que serão recebidos no Stream e enviados para essa base. É interessante usar essa tabela como uma STAGE, para que posteriormente os dados possam ser trabalhados dentro de um ETL.

- Utilizando o Stream Analytics job, configuramos o recebimento dos dados do IoT Hub e transportamos para a base de dados, no caso um MS SQL Server.

- Utilizando o Stream Analytics job, para transportar os dados recebidos no Iot Hub dentro de um pacote JSON, para o nosso deposito de dados, no caso será um MS SQL Server. O primeiro passo é configurar a entrada desses dados, dentro do Stream Analytics job. Nesse caso, a nossa entrada de dados é o IoT Hub. Clicando em Imputs, selecionando as entradas já existentes dentro da plataforma. Nesse caso, apontamos para o Iot Hub.

- O passo seguinte é bem parecido, porem clicando em output e apontando para a base de dados que será utilizado

- Aqui o primeiro passo é criar a QUERY, onde definimos de onde e para onde irão os dados.
Clicando em Query. Utilizando o padrão SQL, selecionamos os campos recebidos no input e direcionamos para output.
Query SQL extraindo dados do Hub IoT para o banco SQL, dentro do Stream Analytics job:

SELECT pacienteId,hospitalId,batimento
    ,temperaturaCorporal,pressaoArterial
    ,oxigenacao,temperaturaAmbiente
    ,umidadeAmbiente,statusLuz,
    statusVentilador,horaEnvio
INTO
    [outsaS2M]
FROM
    [IotS2M]

-Os dados serão armazenados na base de dados criada anteriormente, no servidor MS SQL Server, com tabela apontada na QUERY do passo anterior.

- Pronto, com os dados armazenados e organizados, podemos acessar facilmente de qualquer outra interface. No caso, estamos utilizando uma interface Web escrita em PHP, com acesso direto à nossa base SQL Server, tudo hospedado no Azure.
-Usando qualquer API para gerar os gráficos, podemos facilmente apresentar as informações de forma muito mais interessante ao usuário.

Step 8: Lendo Os Dados Do Azure Para O Website Safe2Med

Os dados do Azure IoT Hub são recebidos no formato Json. Um tutorial de como capturar os dados do Azure IoT Hub e utilizá-los em uma aplicação estão no PDF em anexo.

Devemos criar um serviço com SQL server no Azure ou em qualquer SGBD que queira hospedar sua solução. Esse banco de dados irá receber os dados do serviço Stream Analytics do Azure.

Você deverá criar uma tabela do SGBD, com os campos que serão recebidos no Stream Analytics. É interessante usar essa tabela como uma STAGE, para que posteriormente os dados possam ser trabalhados dentro de um ETL.

Utilizando o Stream Analytics job, configuramos o recebimento dos dados do IoT Hub e transportamos para a base de dados. Deverá ser selecionado qual IoT Hub será utilizado dentro do Stream Analytics job, escolhendo quais campos serão utilizados como Inputs (entradas) no sistema.

Utilizando a linguagem SQL, você cria uma Query, selecionando quais os dados serão buscados pela aplicação web que deseje usar os dados do Stream Analytics. Com isso, é possível utilizar uma aplicação, no nosso caso, em PHP, para mostrar os dados capturados pelo IoT Hub.

Step 9: Considerações Finais

O projeto Saúde Certa, da startup Safe2Med continua em evolução. O protótipo desenvolvido como parte do Programa de Parcerias Qualcomm conseguiu atingir seus objetivos de capturar os dados dos sensores, enviá-los para a nuvem.

Neste projeto, conseguimos utilizar vários recursos da DragonBoard, como utilizar comandos de voz, captura de sinais analógicos e digitais, exibição em uma tela de LCD e o posterior envio para a nuvem para monitoramento remoto. Fizemos testes com a execução de videos através de comandos de voz e também a comunicação através de bluetooth com smartphones, devendo este último ficar para a próxima versão do software do protótipo.

Não obtivemos uma boa precisão no sensor de batimentos cardíacos, adquirimos outro modelo que possui também o oxímetro integrado, mas não chegou a tempo para a apresentação. Começamos, também, a pesquisa para o sensor de pressão arterial.

No ponto de vista de apresentação do produto, tivemos até o momento 750 visitas no blog e cerca de 45 apoiadores. Foi realizada uma campanha nas redes sociais LinkedIn e Facebook para mostrar o andamento, obtendo mais de 200 likes no Facebook e envolvimento de cerca de 723 pessoas.Os vídeos publicados até o momento tiveram, no total, cerca de 300 visualizações.

No LinkedIn, tivemos contato de empresas de Home Care interessadas em conhecer melhor o serviço e isso tem sido um bom retorno sobre o potencial de mercado de nossa solução.

Finalizando, gostaríamos de agradecer à Qualcomm, Arrow, Linaro, 96boards, Baita e ao Embarcados pela realização deste evento e pelo apoio no desenvolvimento de nossas ideias.

Equipe Saúde Certa