Skip to main content

HTTP (JSON)

If compute resources is not a restriction, you would probably prefer to use either a graphgql client or a regular http client. See below for an example of how to send data as a standard json formatted http post.

How

Posting to a graphql api using json is very straight forward.

  1. Format your query as a single string with variables.
  2. Add an object with variables to replace.
  3. Send the json body as {"query": query, "variables": variables}.

Query string with variables

const query = `mutation createPoint($name: String!) {
point {
create(input: {
name: $name
}){
id
name
}
}
}

Variables object

const variables = {
name: "my-point-name",
};

JSON payload

const json = {
query: query,
variables: variables,
};

Examples

Before getting started

To follow the steps below you need to have followed the steps in :

  1. auth section to get tenant-id and token
  2. getting started to get a point-id

Javascript (browser)

Requirements

A modern browser.

Code

<!-- index.html -->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World</title>
</head>
<body>
<h1>Hello World</h1>
<div id="counter" class="counter">
<div id="number" class="number"></div>
</div>
<div id="error" class="error"></div>
</body>

<style>
html {
font-family: Arial, Helvetica, sans-serif;
background-color: blanchedalmond;
}

.counter {
background-color: blueviolet;
max-width: fit-content;
min-width: 40px;
height: 22px;
display:flex;
align-items: center;
justify-content: center;
border-radius: 5px;
font-size: large;
font-weight: bold;
color:white
}

.number {
padding: 5px;
}

.error {
color:red;
}

</style>

<script>
const TENANT_ID = "<tenant-id>";
const TENANT_KEY = "<tenant-key>";

const QUERY = `
query LATEST_SIGNAL_FROM_MY_DEVICE(
$deviceName: String!
$type: String!
) {
points(where: { name: { _EQ: $deviceName } }) {
edges {
node {
temperature: signals(
where: { type: { _EQ: $type }}
paginate: { last:1 }
){
edges {
node {
id
timestamp
createdAt
type
unit
pointId
data {
numericValue
rawValue
}
}
}
}
}
}
}
}`

let variables = {
deviceName: "Our device with sensors",
type: "air temperature"
}

function showError(error) {
let holder = document.getElementById("error")
holder.innerHTML = holder.innerHTML + JSON.stringify(error);
let _x = document.getElementById("error");
_x.style.display = "block";
}

fetch("https://iot.dimensionfour.io/graph", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-tenant-id": TENANT_ID,
"x-tenant-key": TENANT_KEY
},
body: JSON.stringify({query: QUERY, variables: variables}),
})
.then(response => {
if (response.ok) {
return response.json()
} else {
console.error("ERR 0:", response.statusText);
showError(response.statusText)
}
})
.catch((error) => {
console.error("ERR 1:", error);
showError(error)
return Promise.reject(error)
})
.then(data => {
if (data.errors) {
console.error("ERR 2:", data.errors);
showError(data.errors)
} else {
let count = data.data.points.edges[0].node.temperature.edges[0].node.data.rawValue;
document.getElementById("number").innerHTML = count;
}
})
.catch((error) => {
console.error("ERR 3:", error);
showError(error.toString());
});
</script>
</html>

Javascript (node.js)

Requirements

axios (tested with v.0.24.0)

npm install axios

Code

/*
// sendSignal.js
Environment variables: TENANT_ID, TENANT_KEY, POINT_ID
Set them before or when running script:
$ TENANT_ID=myid TENANT_KEY=mykey POINT_ID=123 node sendSignal.js
*/
const axios = require("axios");

const target = "https://iot.dimensionfour.io/graph";

if (
process.env.TENANT_ID == null ||
process.env.TENANT_KEY == null ||
process.env.POINT_ID == null
) {
console.log("Error, environment variables not set!");
process.exit(1);
}

const TENANT_ID = process.env.TENANT_ID;
const TENANT_KEY = process.env.TENANT_KEY;
const POINT_ID = process.env.POINT_ID;

const headers = {
"x-tenant-id": TENANT_ID,
"x-tenant-key": TENANT_KEY,
};

const query = `mutation CREATE_SIGNAL(
$timestamp: Timestamp!
$pointId: ID!
$value: String!
){
signal {
create(input: {
pointId: $pointId
signals: [
{
unit: CELSIUS_DEGREES
value: $value
type: "testtemp"
timestamp: $timestamp
}
]
}) {
id
timestamp
createdAt
pointId
unit
type
data {
numericValue
rawValue
}
}
}
}`;

const json = {
query: query,
variables: {
pointId: POINT_ID,
timestamp: "2021-12-17T14:30:21.000+00:00",
value: "123.45",
},
};

sendPost(target, json);

async function sendPost(target, json) {
console.log("Sending data...");
const res = await axios.post(target, json, { headers: headers });
if (res.error) {
console.log("Send error!");
console.log(res.error);
} else if (res.data) {
if (res.data.errors) {
console.log("Query error!");
console.log(res.data.errors);
} else {
console.log("Success!");
console.log(res.data.data);
}
}
}

Python

Requirements

requests (tested with v2.26.0)

pip install requests

Code

# send_signal.py
# Environment variables: TENANT_ID, TENANT_KEY, POINT_ID
# Set them before or when running script:
# $ TENANT_ID=myid TENANT_KEY=mykey POINT_ID=123 python send_signal.py

import requests
import os

target = "https://iot.dimensionfour.io/graph"

TENANT_ID = os.environ["TENANT_ID"]
TENANT_KEY = os.environ["TENANT_KEY"]
POINT_ID = os.environ["POINT_ID"]

headers = {
"x-tenant-id": TENANT_ID,
"x-tenant-key": TENANT_KEY,
}

query = """mutation CREATE_SIGNAL(
$timestamp: Timestamp!
$pointId: ID!
$value: String!
){
signal {
create(input: {
pointId: $pointId
signals: [
{
unit: CELSIUS_DEGREES
value: $value
type: "testtemp"
timestamp: $timestamp
}
]
}) {
id
timestamp
createdAt
pointId
unit
type
data {
numericValue
rawValue
}
}
}
}"""

json = {
"query": query,
"variables": {
"pointId": POINT_ID,
"timestamp": "2021-12-17T14:30:21.000+00:00",
"value": "123.45",
},
}


def send_post(target, json):
print("Sending data...")
try:
res = requests.post(target, json=json, headers=headers)
except Exception as e:
print(f"Error!: {e}")

if res.status_code != 200:
print("Send error!")
print(res.text)

else:
res_json = res.json()
if "errors" in res_json.keys():
print("Query error!")
print(res_json["errors"])
else:
print("Success!")
print(res_json["data"])


send_post(target, json)

Arduino / C++ (ESP32)

Requirements

Arduino IDE (tested with v1.8.16)
ESP32 (tested with Adafruit Huzzah32)
arduino-esp32
ArduinoJson (tested with v6.18.5)

Code

// secrets.h

#define SECRET_WIFI_SSID "wifissid";
#define SECRET_WIFI_PASSWORD "wifipassword";
#define SECRET_TENANT_ID "tenantid";
#define SECRET_TENANT_KEY "tenantkey";
#define SECRET_POINT_ID "pointid";
// d4gqlesp32.ino
// Uncomment if not using Arduino IDE
//#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include "secrets.h"

const char* SERVER = "https://iot.dimensionfour.io/graph";
const char* WIFI_SSID = SECRET_WIFI_SSID;
const char* WIFI_PASSWORD = SECRET_WIFI_PASSWORD;
const char* TENANT_ID = SECRET_TENANT_ID;
const char* TENANT_KEY = SECRET_TENANT_KEY;
const char* POINT_ID = SECRET_POINT_ID;

const char* rootCACertificate = "add certificate here in production";

void setup() {
Serial.begin(115200);
delay(100);

Serial.println();
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

void loop() {
WiFiClientSecure *client = new WiFiClientSecure;
if (client) {
//client -> setCACert(rootCACertificate); // Use to verify server certificate in production
client -> setInsecure();
{
HTTPClient https;
Serial.print("[HTTPS] begin...\n");
if (https.begin(*client, SERVER)) {
https.addHeader("Content-Type", "application/json");
https.addHeader("x-tenant-id", TENANT_ID);
https.addHeader("x-tenant-key", TENANT_KEY);

String query = R""""(
mutation CREATE_SIGNAL(
$timestamp: Timestamp!
$pointId: ID!
$value: String!
){
signal {
create(input: {
pointId: $pointId
signals: [
{
unit: CELSIUS_DEGREES
value: $value
type: "testtemp"
timestamp: $timestamp
}
]
}) {
id
timestamp
createdAt
pointId
unit
type
data {
numericValue
rawValue
}
}
}
}
)"""";

String postData;
DynamicJsonDocument doc(2048);

doc["query"] = query;

JsonObject variables = doc.createNestedObject("variables");
variables["pointId"] = POINT_ID;
variables["timestamp"] = "2021-12-17T14:30:21.000+00:00";
variables["value"] = "123.45";

serializeJson(doc, postData);
serializeJsonPretty(doc, Serial);

Serial.print("[HTTPS] POST...\n");
int httpCode = https.POST(postData);

if (httpCode > 0) {
Serial.printf("[HTTPS] POST... code: %d\n", httpCode);

if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = https.getString();
Serial.println(payload);
}

} else {
Serial.printf("[HTTPS] POST... failed, error: %s\n", https.errorToString(httpCode).c_str());
}

https.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
}
}

delete client;
} else {
Serial.println("Unable to create client");
}

Serial.println();
Serial.println("Waiting 10s before repeating...");
delay(10000);
}

Arduino / C++ (Opla / MKR 1010 WiFi / ARM Cortex M0+)

Requirements

Arduino IDE (tested with v1.8.16)
Opla (tested with Arduino Opla)
Arduino SAMD Boards (32-bits ARM Cortex-M0+) (install using board manager)
ArduinoJson (tested with v6.18.5)
ArduinoHttpClient (tested with v0.2.0)

Code

// secrets.h

#define SECRET_WIFI_SSID "wifissid";
#define SECRET_WIFI_PASSWORD "wifipassword";
#define SECRET_TENANT_ID "tenantid";
#define SECRET_TENANT_KEY "tenantkey";
#define SECRET_POINT_ID "pointid";
// d4gqlmkr1010.ino
#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include <ArduinoHttpClient.h>
#include <Arduino_MKRIoTCarrier.h>
#include "secrets.h"


const char* SERVER = "iot.dimensionfour.io";
const char* WIFI_SSID = SECRET_WIFI_SSID;
const char* WIFI_PASSWORD = SECRET_WIFI_PASSWORD;
const char* TENANT_ID = SECRET_TENANT_ID;
const char* TENANT_KEY = SECRET_TENANT_KEY;
const char* POINT_ID = SECRET_POINT_ID;

MKRIoTCarrier carrier;
WiFiSSLClient wificlient;
HttpClient client = HttpClient(wificlient, SERVER, 443);

void setup() {
Serial.begin(115200);
delay(100);

carrier.begin();

Serial.println();
Serial.print("Connecting to wifi: ");
Serial.println(WIFI_SSID);

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

void loop() {
String query = R""""(
mutation CREATE_SIGNAL(
$timestamp: Timestamp!
$pointId: ID!
$value: String!
){
signal {
create(input: {
pointId: $pointId
signals: [
{
unit: CELSIUS_DEGREES
value: $value
type: "testtemp"
timestamp: $timestamp
}
]
}) {
id
timestamp
createdAt
pointId
unit
type
data {
numericValue
rawValue
}
}
}
}
)"""";

String postData;
DynamicJsonDocument doc(2048);

doc["query"] = query;

JsonObject variables = doc.createNestedObject("variables");
variables["pointId"] = POINT_ID;

float temperature = carrier.Env.readTemperature();
temperature = round(temperature * 100) / 100;
variables["value"] = String(temperature);
variables["timestamp"] = "2022-02-28T13:37:00+00:00";

serializeJson(doc, postData);
serializeJsonPretty(doc, Serial);

Serial.println("making POST request");
client.beginRequest();
client.post("/graph");
client.sendHeader(HTTP_HEADER_CONTENT_TYPE, "application/json");
client.sendHeader(HTTP_HEADER_CONTENT_LENGTH, postData.length());
client.sendHeader("x-tenant-id", TENANT_ID);
client.sendHeader("x-tenant-key", TENANT_KEY);
client.endRequest();
client.print(postData);

int httpCode = client.responseStatusCode();
if (httpCode > 0) {
Serial.print("[HTTPS] POST... code: ");
Serial.println(httpCode);

if (httpCode == 200) {
String payload = client.responseBody();
Serial.println(payload);
} else {
Serial.println("[HTTPS] POST... failed");
String payload = client.responseBody();
Serial.println(payload);
}
}

Serial.println();
Serial.println("Waiting 10s before repeating...");
delay(10000);
}

Subscription Examples

Python

Requirements

gql (tested with v3.3.0)

pip install gql[all]

Code

# subscription.py
# set environment variables before running, eg
# TENANT_ID=mytenant TENAND_KEY=mykey python subscription.py

import os
from gql import gql, Client
from gql.transport.websockets import WebsocketsTransport

URL = "wss://iot.dimensionfour.io/subscription"
TENANT_ID = os.environ["TENANT_ID"]
TENANT_KEY = os.environ["TENANT_KEY"]

transport = WebsocketsTransport(
url=URL,
headers={
"x-tenant-id": TENANT_ID,
"x-tenant-key": TENANT_KEY,
},
)

client = Client(
transport=transport,
fetch_schema_from_transport=True,
)

query = gql(
"""
subscription UPDATE {
signalAdded {
id
unit
type
}
}
"""
)

for result in client.subscribe(query):
print(result)