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: ABC123XYZ987" \
--verbose \
https://mosquitto.utad.pt/api/v3/datain/OBJ123ABC987
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/v3/datain/OBJ123ABC987 HTTP/1.1
Host: mosquitto.utad.pt
X-ApiKey: ABC123XYZ987
Cache-Control: no-cache
Postman-Token: 12345678-abcd-efgh-ijkl-1234567890ab
{
"formatver": "1.0",
"timestamp": "2024-07-06 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",
"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": "2024-07-06 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++ disponibiliza uma funcionalidade que permite a um dispositivo IoT enviar imagens para o repositório de imagens. Esta funcionalidade é particularmente relevante em aplicações onde as imagens constituem dados fundamentais, como por exemplo deteção de doenças, deteção de animais, armadilhas de insetos e outras aplicações em que uma imagem pode conter informação crítica.
O serviço de upload de imagens recebe os dados através de um pedido HTTP POST, sendo a autenticação realizada por APIKey. A imagem pode ser enviada em binário puro (recomendado) e a plataforma procede à sua validação, normalização e armazenamento no formato JPG, incluindo a criação automática de uma miniatura (thumbnail). No cabeçalho do pedido HTTP podem ser incluídas, opcionalmente, coordenadas GPS e um timestamp associado à imagem. O exemplo seguinte ilustra o envio de uma imagem recorrendo a um comando cURL.
curl --ssl-no-revoke -sS -X POST "https://mosquitto.utad.pt/api/imagein/hkxu7swriHVCVyV5" \
-H "X-Apikey: PUnRa3fK0Vl4nRGNCNqK8mmmwUK0KmO5" \
-H "Content-Type: image/jpeg" \
-H "X-Imgts: 2025-07-06 07:00:00" \
-H "X-Lat: 42.444" \
-H "X-Long: -7.741" \
--data-binary "@./myimage.jpg" \
-i
O hkxu7swriHVCVyV5 representa o identificador único do canal de imagem utilizado (channeluid) e PUnRa3fK0Vl4nRGNCNqK8mmmwUK0KmO5 a APIKey de escrita do objeto ao qual esse canal 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 apresentado de seguida ilustra a forma como uma imagem pode ser enviada para a plataforma mySense IoT++, utilizando o envio de dados em binário puro. Os dados obrigatórios são o identificador único do canal de imagem e a APIKey do objeto a que o canal pertence. Para que a funcionalidade de envio de imagens possa ser utilizada, é necessário que o utilizador tenha previamente definido um canal de imagem no objeto correspondente; caso contrário, o serviço rejeitará o pedido.
Códigos HTTP e resposta do serviço
A API devolve um código HTTP normalizado e uma resposta JSON sanitizada.
O campo request_id permite correlacionar o pedido com os logs internos
em caso de necessidade de suporte.
| HTTP | Quando ocorre | Campos JSON | Ação recomendada |
|---|---|---|---|
201 Created |
Imagem recebida, validada e armazenada com sucesso. | filename, muid, request_id |
Nenhuma (sucesso). |
401 Unauthorized |
APIKey inválida ou canal não autorizado. | error, request_id |
Verificar APIKey e canal. |
413 Payload Too Large |
Imagem excede o limite configurado. | error, request_id |
Reduzir tamanho da imagem. |
422 Unprocessable Entity |
Payload não é uma imagem válida. | error, request_id |
Verificar o ficheiro enviado. |
503 Service Unavailable |
Indisponibilidade temporária do serviço. | error, request_id |
Repetir mais tarde. |
//-------------------------------------------------------------------------------------
// SENDING IMAGE FILES TO MYSENSE PLATFORM (RECOMMENDED)
// Endpoint: POST https://mosquitto.utad.pt/api/imagein/{imagechannel_uuid}
// Sends RAW binary (no base64) and reads HTTP status codes
//-------------------------------------------------------------------------------------
$apikey = 'object_write_apikey';
$channeluid = 'imagechannel_uuid';
$lat = 42.444;
$lng = -7.741;
$imgts = '2025-07-06 07:00:00';
$imgfile = __DIR__ . '/myimage.jpg';
$url = 'https://mosquitto.utad.pt/api/imagein/' . rawurlencode($channeluid);
// Read file bytes
$data = file_get_contents($imgfile);
if ($data === false) {
die("Cannot read file: $imgfile\n");
}
// Detect Content-Type (fallback)
$mime = mime_content_type($imgfile) ?: 'image/jpeg';
$headers = [
'X-Apikey: ' . $apikey,
'Content-Type: ' . $mime,
];
if ($lat !== null) $headers[] = 'X-Lat: ' . $lat;
if ($lng !== null) $headers[] = 'X-Long: ' . $lng;
if ($imgts !== null) $headers[] = 'X-Imgts: ' . $imgts;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POSTFIELDS => $data, // raw binary body
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true, // capture headers + body
CURLOPT_TIMEOUT => 30,
]);
$raw = curl_exec($ch);
if ($raw === false) {
$err = curl_error($ch);
curl_close($ch);
die("cURL error: $err\n");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
$responseBody = substr($raw, $headerSize);
echo "HTTP $httpCode\n";
echo $responseBody . "\n";
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 Objeto mySense, 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 -X GET \
-H "X-ApiKey: ABC123XYZ987" \
-H "X-Startdate: 2025-07-01 15:00:00" \
-H "X-Enddate: 2025-07-06 15:00:00" \
-H "X-Channelnum: 0" \
-H "X-Reclimit: 200" \
-H "User-Agent: mySense/1.0" \
-v \
https://mosquitto.utad.pt/api/dataout/OBJ123ABC987.json
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 -X GET \
-H "X-ApiKey: ABC123XYZ987" \
-H "X-Startdate: 2025-07-01 15:00:00" \
-H "X-Enddate: 2025-07-06 15:00:00" \
-H "X-Channelnum: 1" \
-H "X-Reclimit: 200" \
-H "User-Agent: mySense/1.0" \
-v \
https://mosquitto.utad.pt/api/dataout/OBJ123ABC987.json
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 -X GET \
-H "X-ApiKey: ABC123XYZ987" \
-H "X-Startdate: 2025-07-01 15:00:00" \
-H "X-Enddate: 2025-07-06 15:00:00" \
-H "X-Reclimit: 200" \
-H "User-Agent: mySense/1.0" \
-v \
https://mosquitto.utad.pt/api/dataout/OBJ123ABC987/channel/1.json
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 -X GET \
-H "X-Startdate: 2025-07-01 12:25:44" \
-H "X-Enddate: 2025-07-06 12:25:44" \
-H "X-Reclimit: 100" \
-H "User-Agent: mySense-Lib/1.0" \
-v \
https://mosquitto.utad.pt/api/channeldata/CHAN123XYZ987.json
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 -X GET \
-H "X-ApiKey: ABC123XYZ987" \
-H "X-Startdate: 2025-07-01 12:25:44" \
-H "X-Enddate: 2025-07-06 12:25:44" \
-H "X-Reclimit: 100" \
-H "User-Agent: mySense-Lib/1.0" \
-v \
https://mosquitto.utad.pt/api/channeldata/CHAN123XYZ987.json
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 -X GET \
-H "X-ApiKey: ABC123XYZ987" \
-H "X-Startdate: 2025-07-01 00:00:00" \
-H "X-Reclimit: 5" \
-H "User-Agent: mySense-Lib/1.0" \
-v \
https://mosquitto.utad.pt/api/channeldata/CHAN123XYZ987.json
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 -X GET \
-H "X-ApiKey: ABC123XYZ987" \
-v \
https://mosquitto.utad.pt/api/objectinfo/OBJ123ABC987.json
Como resultado deste tipo de pedido, é devolvida a seguinte mensagem JSON.
{
"server_time": "2025-07-06 14:00:00",
"object_uid": "OBJ123ABC987",
"object_name": "Monitorização Estação Demo",
"object_location": "Laboratório Central",
"object_created": "2023-01-01 12:00:00",
"object_owner": "mySense Demo",
"object_model": "Modelo-X",
"object_sn": "SN-00123",
"network_address": "AA:BB:CC:DD:EE:FF",
"network_connection": "WiFi",
"default_object_group": "Demo_Group",
"account_type": "Standard",
"total_channels": 5,
"channel_info": {
"1": {
"channel_name": "Temperatura",
"channel_uid": "CHAN123TEMP456",
"channel_privacy": "Public",
"transducer": "SHT71 Temperature",
"unit": "ºC",
"data_format": "Float with decimal point",
"total_triggers": 4,
"total_samples_3days": 12
},
"2": {
"channel_name": "Humidade relativa",
"channel_uid": "CHAN234HUMID567",
"channel_privacy": "Public",
"transducer": "SHT71 Humidity",
"unit": "%RH",
"data_format": "Float with decimal point",
"total_triggers": 2,
"total_samples_3days": 15
},
"3": {
"channel_name": "Radiação solar",
"channel_uid": "CHAN345SOLAR678",
"channel_privacy": "Public",
"transducer": "TSL230",
"unit": "W/m^2",
"data_format": "Float with decimal point",
"total_triggers": 1,
"total_samples_3days": 10
},
"4": {
"channel_name": "Teste de saída",
"channel_uid": "CHAN456ACTU789",
"channel_privacy": "Private",
"transducer": "Atuador Genérico",
"unit": "N/A",
"data_format": "Integer",
"total_triggers": 0,
"total_samples_3days": 0
},
"56": {
"channel_name": "Câmara de Imagem",
"channel_uid": "CHAN567IMG890",
"channel_privacy": "Private",
"transducer": "Imaging Device",
"unit": "N/A",
"data_format": "JPG image",
"total_triggers": 5,
"total_samples_3days": 50
}
}
}
Ú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 -X GET \
-H "X-ApiKey: APIKEY123EXAMPLE" \
-H "User-Agent: mySense-Lib/1.0" \
-v \
https://mosquitto.utad.pt/api/datain/OBJ123ABC987/channel/1.JSON
Como pode ser observado, o pedido contém explicitamente os dados do canal 1.
{
"http_code": 265,
"server_time": "2025-07-06 18:38:44",
"object_name": "Monitorização Estação Demo",
"object_uid": "OBJ123ABC987",
"channel_name": "Temperatura",
"channel_number": 1,
"channel_uid": "CHAN123TEMP456",
"last_sample_time": "2025-07-06 12:26:00",
"value": 22.5,
"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 -X GET \
-H "X-ApiKey: APIKEY123EXAMPLE" \
-H "User-Agent: mySense-Lib/1.0" \
-v \
https://mosquitto.utad.pt/api/datain/OBJ123ABC987.JSON
Cujo resultado típico está na mensagem JSON abaixo apresentada.
{
"http_code": 266,
"server_time": "2025-07-06 18:44:39",
"object_name": "Demo Object",
"object_uid": "OBJ123ABC987",
"warnings": "none",
"exec_time_ms": 2944,
"last_data": [
{
"channel_name": "Temperatura",
"channel_number": "1",
"channel_uid": "CH123TEMP456",
"ts": "2025-07-06 12:26:00",
"value": 22.5
},
{
"channel_name": "Humidade relativa",
"channel_number": "2",
"channel_uid": "CH789HUM012",
"ts": "2025-07-06 12:26:00",
"value": 55.2
},
{
"channel_name": "Radiação solar",
"channel_number": "3",
"channel_uid": "CH345SOL678",
"ts": "2025-07-06 12:26:00",
"value": 750
},
{
"channel_name": "Imagem",
"channel_number": "56",
"channel_uid": "CH999IMG333",
"ts": "2025-07-06 12:26:00",
"value": "https://mosquitto.utad.pt/img/myimages/channels_data/CH999IMG333/20250706_122600_example.jpg"
},
{
"channel_name": "Teste de saída",
"channel_number": "4",
"channel_uid": "CH444OUT555",
"ts": null,
"value": null
}
]
}