Integração de dados

A plataforma mySense tem como pressuposto básico a integração de dados de várias fontes e múltiplos formatos para que o utilizador os possa de alguma forma visualizar e interpretar. Estando estes dados disponíveis na plataforma, vários métodos foram criados para os aceder através da API.


Envio de dados

Envio de dados binários

Existem vários métodos de um qualquer dispositivo enviar dados para a plataforma mySense, nomeadamente recorrendo a pedidos HTTP POST e GET. Uma ferramenta de utilidade para testar o envio de dados através da linha de comandos é o cURL, exemplificado abaixo.


curl
    --request POST
    --data-binary @send_data_json_example1.json
    --header "X-ApiKey:6g0NRGc3TVecBVUeX8dUA9u2VSQwPGzW"
    --verbose http://mysense.utad.pt/api/datain/AWU0TZwb8IFCc0xK.json
    --insecure
    

Neste exemplo, o utilizador executa um pedido POST do conteúdo do ficheiro local JSON send_json_example1.json para o recurso http://mysense.utad.pt/api/datain/AWU0TZwb8IFCc0xK.json (Objecto mySense AWU0TZwb8IFCc0xK), autenticado através da chave APIKey 6g0NRGc3TVecBVUeX8dUA9u2VSQwPGzW.

Envio de dados em JSON

Todos os dados numéricos (por exemplo, leituras de sensores) são enviados para a plataforma mySense no formato JSON (JavaScript Object Notation). Abaixo está ilustrado o payload mais básico usado para transferir dados para a mySense. A palavra reservada dataarray é utilizada para dar a indicação de que se está perante um vetor de dados numéricos associados aos canais definidos para estas entradas.


{
    "formatver": "1.0",
    "dataarray":
        [
            {"ch": 1,"value": 14.35},
            {"ch": 2,"value": 34.35},
            {"ch": 3,"value": 5.35}
        ]
}
    

Neste caso mais simples, os valores numéricos associados aos canais 1, 2 e 3, são enviados sem data/hora, que será adicionada pelo servidor antes de serem armazenados. Esta funcionalidade é particularmente útil em muitas aplicações onde o dispositivo IoT não contenha um relógio em tempo real para conferir a data/hora da amostra.

Uma outra ferramenta de desenvolvimento bastante útil e usada é a aplicação Postman, onde se podem gerir/guardar todos os pedidos HTTP efetuados. Rapidamente se contrói um pedido POST para o mesmo efeito do descrito acima com o cURL, de enviar dados para a plataforma mySense, sabendo de antemão as credenciais de acesso.


POST /api/datain/AWU0TZwb8IFCc0xK.json HTTP/1.1
Host: mysense.utad.pt
X-ApiKey: 6g0NRGc3TVecBVUeX8dUA9u2VSQwPGzW
Cache-Control: no-cache
Postman-Token: b969a520-f112-2a3d-0f69-4ce035c4e53f

{
    "formatver": "1.0",
    "timestamp": "2016-06-10 14:30:00",
    "lat": 41.286657,
    "long": -7.741023,
    "dataarray":
        [
            {"ch": 1,"value": 14.35},
            {"ch": 2,"value": 34.35},
            {"ch": 3,"value": 5.35}
        ]
}
    

Quer no exemplo acima e no abaixo, foi incluído o rótulo timestamp que indica a data/hora a que foram adquiridas as amostras para aqueles canais de dados, não sendo, portanto, necessário ser incluído pelo servidor aquando da receção do payload.


{
    "formatver": "1.0",
    "timestamp": "2016-06-10 14:30:00"
    "dataarray":
        [
            { "ch": 1, "value": 14.35 },
            { "ch": 2, "value": 34.35 },
            { "ch": 3, "value": 5.35 }
        ]
}
    

No caso de ser um objeto em movimento e que haja interesse em registar as suas coordenadas a cada momento, bastará incluir no payload os rótulos lat e long, representando as coordenadas GPS (formato decimal), como ilustrado abaixo.


{
    "formatver": "1.0",
    "timestamp": "2016-06-10 14:30:00",
    "lat": 41.286657,
    "long": -7.741023,
    "dataarray":
        [
            { "ch": 1, "value": 14.35 },
            { "ch": 2, "value": 34.35 },
            { "ch": 3, "value": 5.35 }
        ]
}
    

Sempre que um payload deste tipo é recebido, com indicação de coordenadas GPS, estas são inseridas como sendo a localização atual do objeto referenciado e ilustradas na página do Integrador de Objeto. Dado que apenas as últimas 6 localizações são guardadas, cada coordenada que entra, empurra a mais antiga para fora, sendo descartada.


Envio de imagens

A plataforma mySense IoT++ oferece uma funcionalidade inovadora que permite a um dispositivo IoT enviar imagens para o repositório de imagens. Esta funcionalidade é particularmente relevante em aplicações onde imagens são dados fundamentias. Exemplos incluem deteção de doenças, deteção de animais, armadilhas de insectos e outras aplicações onde imagens valham mais do que 1000 palavras.
Numa primeira versão do serviço de upload de imagens, apenas são permitidas imagens em formato JPG, limitadas a um comprimento máximo de aproximadamente 300kB. No cabeçalho do pedido HTTP POST, podem ser incluídas, opcionalmente, coordenadas GPS. O exemplo seguinte ilustra recorrendo a um cURL.


curl
-X POST
-F "file=@IMG_7433.JPG"
-H "X-ApiKey: PUnRa3fK0Vl4nRGNCNqK8mmmwUK0KmO5"
-H "X-Lat: 41.286657"
-H "X-Long: -7.741023"
http://mysense.utad.pt/api/imagein/hkxu7swriHVCVyV5
    

O hkxu7swriHVCVyV5 representa o identificador único do canal de imagem usado e PUnRa3fK0Vl4nRGNCNqK8mmmwUK0KmO5 a APIKey do objeto ao qual o canal de imagem pertence. Se forem incluídas no cabeçalho HTTP as coordenadas GPS, a localização do objeto é atualizada, permitindo visualizar o seu posicionamento na página do Integrador de Objeto.
Como script de referência, o código PHP abaixo apresentado ilustra a forma de como uma imagem pode ser enviada para a plataforma mySense IoT++. Os dados obrigatórios são o identificador único de canal e a APIKey do objeto a que o canal pertence. Para que a funcionalidade de envio de imagens possa ser usada, o utilizador tem de definir um canal de imagem no objeto correspondente, caso contrário não será possível receber a imagem.


//-------------------------------------------------------------------------------------
// SENDING IMAGE FILES TO MYSENSE PLATFORM
// @MYSENSE,
// BASIC EXAMPLE
// MAX UPLOAD: APROX 300kb
//-------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------
// Relevant data (random values)
//-------------------------------------------------------------------------------------
$apikey 		= '6g0NRGc3TVe56VUeX8dUA9u2VSQwPGzW';
$channeluid 	= 'AWU0TZwb8IF3c0xK';
//-------------------------------------------------------------------------------------
// Optional data
//-------------------------------------------------------------------------------------
$lat 			= 42.444;
$lng 			= -7.741;
$imgts 			= '2019-08-01 07:00:00';
//-------------------------------------------------------------------------------------
// Local filename to send
//-------------------------------------------------------------------------------------
$imgfile 		= 'myimage.jpg';
//-------------------------------------------------------------------------------------
// Resource path
//-------------------------------------------------------------------------------------
$apipath 		= 'http://mysense.utad.pt/api/imagein/';
//-------------------------------------------------------------------------------------
// Processing
//-------------------------------------------------------------------------------------
$handle    = fopen($imgfile, "r");
$data      = fread($handle, filesize($imgfile));
$post_data = array('file' => base64_encode($data));

$request_headers = array();

$header_X_APIKEY = 'X-APIKEY: '.$apikey;
array_push($request_headers, $header_X_APIKEY);

if (isset($lat)) {
    $header_X_LAT = 'X-LAT: '.$lat;
    array_push($request_headers, $header_X_LAT);
}
if (isset($lng)) {
    $header_X_LONG = 'X-LONG: '.$lng;
    array_push($request_headers, $header_X_LONG);
}
if (isset($image_ts)) {
    $header_X_IMGTS = 'X-IMGTS: '.$image_ts;
    array_push($request_headers, $header_X_IMGTS);
}

$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, $request_headers );
curl_setopt($curl, CURLOPT_URL, $apipath.$channeluid);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_POST, 1);

curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, $post_data);
$response = curl_exec($curl);
$response_info = curl_getinfo($curl);
curl_close ($curl);

// VIEW HTTP REQUEST RESPONSE
header('Content-type: application/json; charset=utf-8');
echo json_encode($response, JSON_UNESCAPED_UNICODE);
    

Caso as coordenadas GPS válidas (formato decimal) sejam incluídas no cabeçalho do pedido, o objeto correspondente será marcado nessa posição na página do Integrador de Objeto, como ilustrado na figura seguinte.

Envio de imagens para a plataforma mySense com inclusão de coordenadas GPS.

A cada objeto podem estar associadas 6 posições GPS e respetiva imagem associada caso uma imagem seja enviada com coordenadas. Sempre que é adicionada uma imagem para além das 6, a mais antiga coordenada GPS é eliminada, assim como o respetivo ficheiro de imagem (associado à geolocalização).


Acesso a dados mySense

Todos os dados inseridos e armazenados na plataforma mySense podem ser acedidos através da API mySense. Trata-se de uma interface RESTful que permite um acesso rápido e estruturado aos serviços Web oferecido para manuseamento dos dados.
Os dados privados de um utilizador só podem ser acedidos se no cabeçalho HTTP do pedido estiver declarada a APIKey do objeto acedido. Caso contrário, apenas dados categorizados de públicos é que poderão ser acedidos.

Dados numéricos de todos os canais de um objeto

Retornar os dados de todos os canais (X-Channelnum: 0) de um objecto entre as datas X-Startdate a X-Enddate. Retornar apenas os últimos X-Reclimit: 200 registos.


curl
--request GET
--header "X-ApiKey: 6g0NRGc3TVecBVUeX8dUA9u2VSQwPGzW"
--header "X-Startdate: 2016-06-08 15:00:00"
--header "X-Enddate: 2016-06-11 15:00:00"
--header "X-Channelnum: 0"
--header "X-Reclimit: 200"
--header "User-Agent: mySense/1.0"
--verbose http://mysense.utad.pt/api/dataout/AWU0TZwb8IFCc0xK.json
--insecure
    

Dados numéricos de apenas um canal de um objeto

Retornar os dados de apenas o canal 1 (X-Channelnum: 1) de um objecto entre as datas X-Startdate a X-Enddate. Retornar apenas os últimos X-Reclimit: 200 registos.

        
curl
--request GET
--header "X-ApiKey: 6g0NRGc3TVecBVUeX8dUA9u2VSQwPGzW"
--header "X-Startdate: 2016-06-08 15:00:00"
--header "X-Enddate: 2016-06-11 15:00:00"
--header "X-Channelnum: 1"
--header "X-Reclimit: 200"
--header "User-Agent: mySense/1.0"
--verbose http://mysense.utad.pt/api/dataout/AWU0TZwb8IFCc0xK.json
--insecure
        
    

Obter dados de um canal, invocando diretamente o seu recurso

Neste caso, o URL invocado identifica o canal pretendido, bem como o formato desejado para os dados (JSON no exemplo).

        
curl
--request GET
--header "X-ApiKey: 6g0NRGc3TVecBVUeX8dUA9u2VSQwPGzW"
--header "X-Startdate: 2016-06-08 15:00:00"
--header "X-Enddate: 2016-06-11 15:00:00"
--header "X-Reclimit: 200"
--header "User-Agent: mySense/1.0"
--verbose http://mysense.utad.pt/api/dataout/AWU0TZwb8IFCc0xK/channel/1.json
--insecure
        
    

Acesso a dados públicos de um canal

A filosofia da plataforma mySense IoT++ assenta na partilha de dados recolhida por dispositivos e que posteriormente podem ser partilhados. Para que isso possa ser possível, o proprietário do objeto deve definir o tipo de privacidade de um determinado canal. Por exemplo, o canal 1 de um objeto pode ser privado, pode ser acedido apenas por um conjunto de utilizadores ou ser acedido por qualquer utilizador. Neste último caso, o acesso aos seus dados vem facilitado já que não é necessário especificar a APIKey do objeto a que esse canal pertence.

        
curl
--request GET
--header "X-Startdate: 2016-06-09 12:25:44"
--header "X-Enddate: 2016-06-12 12:25:44"
--header "X-Reclimit: 100"
--header "User-Agent: mySense-Lib/1.0"
--verbose http://mysense.utad.pt/api/channeldata/rvsPHQcnSBF3eqxx.json
--insecure
        
    

Acesso a dados privados de um canal

No caso de um canal estar definido como privado, torna-se necessário especificar a APIKey do objeto que o detém.

        
curl
--request GET
--header "X-ApiKey: 7Hke4YZTalqegIhjiByN0prO0VWkUJeN"
--header "X-Startdate: 2019-04-20 00:00:00"
--header "X-Reclimit: 5"
--header "User-Agent: mySense-Lib/1.0"
--verbose http://mysense.utad.pt/api/channeldata/opM6jldOHXG2GDnS.json
--insecure
        
    

O resultado é o seguinte:

        
{
    "httpcode": 200,
    "servertime": "2019-08-05 18:28:51",
    "msgver": 2,
    "mysense_agent": "mySense-Lib-1.0",
    "startdate": "2019-08-05 12:28:51",
    "enddate": "2019-08-05 18:28:51",
    "object_name": "PVV0 - Testes",
    "object_location": "Laboratório I1.02",
    "channel_name": "ADC1",
    "channel_number": 1,
    "channel_uid": "2khFp8DXFzcvW90n",
    "records": 5,
    "reclimit": 5,
    "samples": [
        {
            "ts": "2019-08-05 18:15:00",
            "val": -1.92
        },
        {
            "ts": "2019-08-05 18:00:00",
            "val": -1.92
        },
        {
            "ts": "2019-08-05 17:45:00",
            "val": -1.92
        },
        {
            "ts": "2019-08-05 17:30:00",
            "val": -1.92
        },
        {
            "ts": "2019-08-05 17:15:00",
            "val": -1.92
        }
    ]
}
        
    

Retornar dados de um canal público

No caso de acesso público, o pedido GET é feito diretamente ao canal (invocando o UID do canal e o formato pretendido).

        
curl
--request GET
--header "X-Startdate: 2016-04-20 00:00:00"
--header "X-Reclimit: 5"
--header "User-Agent: mySENSE-Lib/1.0"
--verbose http://mysense.utad.pt/api/channeldata/opM6jldOHXG2GDnS.json
--insecure
        
    

Obtenção de informação de um objeto

Todos os meta-dados de um objeto podem ser consultados através da API mySense. Para tal, é feito um pedigo GET ao recurso http://mysense.utad.pt/api/objectinfo/3ryRARNoY2TRzBco.json onde é especificado o objeto e o formato JSON para a resposta.

        
curl
--request GET
--header "X-ApiKey: EyDXD9PFnQA2BA7WuIppRJctedtJ2eJc"
--verbose http://mysense.utad.pt/api/objectinfo/3ryRARNoY2TRzBco.json
--insecure
        
    

Como resultado deste tipo de pedido, é devolvida a seguinte mensagem JSON.

        
{
    "server_time": "2019-08-06 00:16:57",
    "object_uid": "3ryRARNoY2TRzBco",
    "object_name": "Monitorização bateria no lab",
    "object_location": "Laboratório",
    "object_created": "2016-01-28 23:00:00",
    "object_owner": "mySense tutorials",
    "object_model": "Modelo",
    "object_sn": "SN",
    "network_address": "34:34:34:34",
    "network_connection": "N\/D",
    "default_object_group": "Default_mySense_tutorials",
    "account_type": "Unlimited",
    "total_channels": 5,
    "channel_info": {
        "1": {
            "channel_name": "Temperatura",
            "channel_uid": "AlhJXJwe45eWYaTu",
            "channel_privacy": "Public",
            "transducer": "SHT71 Temperature",
            "unit": "ºC",
            "data_format": "Float with decimal point",
            "total_triggers": 4,
            "total_samples_3days": 0
        },
        "2": {
            "channel_name": "Humidade relativa",
            "channel_uid": "scZq27hdu8olorfv",
            "channel_privacy": "Public",
            "transducer": "SHT71 Humidity",
            "unit": "%RH",
            "data_format": "Float with decimal point",
            "total_triggers": 1,
            "total_samples_3days": 0
        },
        "3": {
            "channel_name": "Radiação solar",
            "channel_uid": "VUDK12ju5sBNaNYT",
            "channel_privacy": "Public",
            "transducer": "TSL230",
            "unit": "W\/m^2",
            "data_format": "Float with decimal point",
            "total_triggers": 0,
            "total_samples_3days": 0
        },
        "4": {
            "channel_name": "Teste de saída",
            "channel_uid": "56juvXGv7F5fupEC",
            "channel_privacy": "Private",
            "transducer": "Atuador genérico",
            "unit": "N\/A",
            "data_format": "Inteiro",
            "total_triggers": 0,
            "total_samples_3days": 0
        },
        "56": {
            "channel_name": "23",
            "channel_uid": "cXGt76sJO7dj5@8s",
            "channel_privacy": "Private",
            "transducer": "Imaging device",
            "unit": "N\/A",
            "data_format": "JPG image",
            "total_triggers": 0,
            "total_samples_3days": 55
        }
    }
}
        
    

Últimos dados de um objeto

Uma outra funcionalidade disponível consiste em obter o último dado de um determinado objeto. O exemplo seguinte ilustra um desses pedidos, assim como uma resposta típica.

        
curl
--request GET
--header "X-ApiKey: EyDXD9PFnQA2BA7WuIppRJctedtJ24rt"
--header "User-Agent: mySense-Lib/1.0"
--verbose http://mysense.utad.pt/api/datain/3ryRARNoY2TRzBco/channel/1.JSON
--insecure
        
    

Como pode ser observado, o pedido contém explicitamente os dados do canal 1.

        
{
    "http_code": 265,
    "server_time": "2019-08-07 18:38:44",
    "object_name": "Monitorização bateria no lab ",
    "object_uid": "47wRARNoY2TRzBco",
    "channel_name": "Temperatura",
    "channel_number": 1,
    "channel_uid": "AlhJXJwS2ReWYaTu",
    "last_sample_time": "2019-08-07 12:26:00",
    "value": 13,
    "warnings": "none",
    "exec_time_ms": 592
}
        
    

No caso em que se pretendam os dados relativos a todos os canais do objecto, o pedido deve ser feito da seguinte forma:

        
curl
--request GET
--header "X-ApiKey: EyDXD9PFnQA2BA7WuIppRJctedtJ24rt"
--header "User-Agent: mySense-Lib/1.0"
--verbose http://mysense.utad.pt/api/datain/3ryRARNoY2TRzBco.JSON
--insecure
        
    

Cujo resultado típico está na mensagem JSON abaixo apresentada.

        
{
    "http_code": 266,
    "server_time": "2019-08-07 18:44:39",
    "object_name": "Monitorização bateria no lab",
    "object_uid": "5twRARNoY2TRzBco",
    "warnings": "none",
    "exec_time_ms": 2944,
    "last_data": [
        {
            "channel_name": "Temperatura",
            "channel_number": "1",
            "channel_uid": "qrTJXJwS2ReWYaTu",
            "ts": "2019-08-07 12:26:00",
            "value": 13
        },
        {
            "channel_name": "Humidade relativa",
            "channel_number": "2",
            "channel_uid": "56yq27hOitolorfv",
            "ts": "2019-08-02 15:45:00",
            "value": 15.42
        },
        {
            "channel_name": "Radiação solar",
            "channel_number": "3",
            "channel_uid": "vuDK80xB5sBNaNYT",
            "ts": "2019-08-02 15:45:00",
            "value": 41
        },
        {
            "channel_name": "23",
            "channel_number": "56",
            "channel_uid": "c5tKZE8JO7dj5@8s",
            "ts": "2019-08-05 15:04:01",
            "value": "https://mysense.utad.pt/img/myimages/channels_data/ChannelUID_c5tKZE8JO7dj5@8s/20190805_150401_5d4837512236c.jpg"
        },
        {
            "channel_name": "Teste de saída",
            "channel_number": "4",
            "channel_uid": "VVg3vXGv7F5fupEC",
            "ts": null,
            "value": null
        }
    ]
}
        
    
n