> For the complete documentation index, see [llms.txt](https://docs.datacake.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.datacake.de/api/graphql-api/using-graphql.md).

# Using GraphQL

In this tutorial we will show you how you can use the powerful GraphQL API to access historical and current device data with Datacake.

## GraphQL Requests

### HTTP

You can use a cURL Command to call the GraphQL Library directly.

```graphql
curl \
-X GET \
-H "Content-Type: application/json" \
-H "Authorization: Token 1234567yourtoken1234567" \
--data '{"query": "query { allDevices(inWorkspace:\"dc578994-your-workspace-84221d0\") { currentMeasurements(allActiveFields: true) { value field { verboseFieldName fieldName } } } }"}' \
https://api.datacake.co/graphql/
```

## Libraries

### Datacake Python Wrapper

Datacake official Python GraphQL wrapper:

{% embed url="<https://github.com/datacake/python-datacake-api-wrapper>" %}

### iOS

You can use the Apollo GraphQL Library in your iOS / Swift Applications:

{% embed url="<https://github.com/apollographql/apollo-ios>" %}

### Node-RED

You can use a function node in Node-RED and create a custom GraphlQL query that forwards data directly into Node-RED as a parsed JSON-Object.

```graphql
// Datacake API Token and Workspace
var token = "123456mytoken123456";
var workspace = "1234myworkspace1234";

// GraphQL API URL
msg.url = "https://api.datacake.co/graphql";

// GraphQL Header
msg.headers = {
    "Authorization": "Token "+token,
    "Content-Type": "application/json"
};

// GraphQL Query
var query = `query {
  allDevices(inWorkspace:${workspace}) {
    id
    serialNumber
    verboseName
    currentMeasurements(allActiveFields: true) {
      field {
        fieldName
        verboseFieldName
      }
      value
    }
  }
}`;

msg.payload = {"query": query};
msg.body = {"query": query};

return msg;
```

#### Node-RED Flow Export

Copy the following Node-RED Flow of a working Datacake GraphQL Example and paste this into your Node-RED using "Import" function.

{% embed url="<https://gist.github.com/simmikolon/4a188e7347c90cfb3799ac3f8064496f>" %}

## Workspaces

### List of Workspaces

```graphql
query {
  allWorkspaces {
    id
    name
  }
}
```

### List of Devices

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    id
    verboseName
  }
}
```

## Current Measurements

### All Devices in Workspace

You can use the `currentMeasurements` option to have all the last recorded measurements of one or more devices returned.

Use the `allActiveFields` option as follows to return only those fields that are active in the database.

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurements(allActiveFields: true) {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
```

#### Specific Fields only

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurements(fieldNames:["BATTERY"]) {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
```

#### Single Fields only

Instead of providing an Array of Field Identifiers you can use the `currentMeasurement` Option to Query a specific field only.

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurement(fieldName:"BATTERY") {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
```

### Specific Device

The above examples are using the `allDevices` Option to query all devices in a given Workspace. If you just want to access data from a specific device only, you can use the `device` Option.

```graphql
device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a")
```

Use this as in the following example query:

```graphql
query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    currentMeasurements(allActiveFields: true) {
      value
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
```

### Working with Strings

If your fields in database store a `String`-type value you have to add the `valueString` option to return the corresponding value.

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    currentMeasurements(allActiveFields: true) {
      valueString
      modified
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
```

### Working with Maximum, Average

```graphql
maximum(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
average(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
change(average(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
```

```graphql
query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    currentMeasurements(allActiveFields: true) {
      value
      maximum(timeRangeStart:"2021-04-16T00:00", timeRangeEnd:"2021-04-17T00:00")
      field {
        verboseFieldName
        fieldName
      }
    }
  }
}
```

So will look like

```graphql
{
  "data": {
    "device": {
      "currentMeasurements": [
        {
          "value": 3.067,
          "average": 3.06697222222223,
          "maximum": 3.069,
          "change": 0,
          "modified": "2021-04-17T12:58:30.554976+00:00",
          "field": {
            "verboseFieldName": "Battery",
            "fieldName": "BATTERY"
          }
        }
      ]
    }
  }
}
```

## Historical Data

### From all Devices in Workspace

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    history(
      fields:["BATTERY"], 
      timerangestart:"2021-04-16T00:00", 
      timerangeend:"2021-04-17T00:00", 
      resolution:"120m"
    )
  }
}
```

* `fields`: Set of fields, has to be identifier of database field. Leave it out to get all fields.
* `timerangestart`: Starting of time frame, has to be before `timerangeend`.
* `timerangeend`: End of time frame, should never be in the future.
* `resolution`: Quantisation-Factor, see below.
* `aggregation`: How values are combined per time bucket, see below. Default is `AVG`.
* `locf`: Last observation carried forward. Fills time buckets without data by continuing with the last recorded value. If there is no earlier value, for example in the first bucket, the bucket stays empty (`null`). Only works with a `resolution` other than `raw`. Default is `true`.

Timestamps use the ISO 8601 format, for example `2021-04-16T00:00:00Z`. Timestamps without a timezone are read as UTC.

### From a Specific Device

```graphql
query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(fields:["BATTERY"], timerangestart:"2021-04-16T00:00", timerangeend:"2021-04-17T00:00", resolution:"raw") 
  }
}
```

Fields have to be Identifier:

```graphql
fields:["BATTERY"]
```

### Multiple Fields

```graphql
query {
  device(deviceId: "702d77a7-a292-476a-a546-d5dde80e6f5d") {
    history(
      fields: ["HUM_SHT", "TEMPC_SHT"],
      timerangestart: "2023-12-16T00:00",
      timerangeend: "2023-12-17T00:00",
      resolution: "30m"
    ) 
  }
}
```

### Working with Resolution

One of the options for the history settings is an option called resolution. This gives you two options:

* `raw` - Raw Data Export. Data will be exported as stored in the database. This is the default if you leave out `resolution`.
* A number followed by a unit - Data will be combined into time buckets of the given size. Supported units are `s`, `m`, `h`, `d` and `w`, for example `30s`, `20m`, `2h`, `1d` or `1w`.

{% hint style="info" %}
An invalid resolution does not return an error. It falls back to `30m` instead. Write minutes with a lowercase `m`, because `1M` is not accepted.
{% endhint %}

{% hint style="warning" %}
**Limits**

* Raw data returns at most the most recent 31 days of the requested time frame.
* Quantised data returns at most 1024 time buckets. If your resolution would create more, it is made coarser automatically.
* The time frame is always limited to the data retention of the device's plan.
  {% endhint %}

#### Raw Data Export

```graphql
query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(
      fields:["BATTERY"], 
      timerangestart:"2021-04-16T00:00", 
      timerangeend:"2021-04-17T00:00", 
      resolution:"raw"
      ) 
  }
}
```

#### Quantisation

```graphql
query {
  device(deviceId:"faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(
      fields:["BATTERY"], 
      timerangestart:"2021-04-16T00:00", 
      timerangeend:"2021-04-17T00:00", 
      resolution:"20m"
      ) 
  }
}
```

#### Aggregation

With a resolution other than `raw`, `aggregation` decides how the values inside each time bucket are combined. It is ignored for raw data.

| Aggregation     | Numeric fields | Boolean fields                        | String and location fields |
| --------------- | -------------- | ------------------------------------- | -------------------------- |
| `AVG` (default) | Average        | `true` if most readings were true     | `null`                     |
| `MIN`           | Minimum        | `true` only if all readings were true | `null`                     |
| `MAX`           | Maximum        | `true` if any reading was true        | `null`                     |
| `SUM`           | Sum            | Number of `true` readings             | `null`                     |
| `FIRST`         | First reading  | First reading                         | First reading              |
| `LAST`          | Last reading   | Last reading                          | Last reading               |

```graphql
{
  device(deviceId: "faf34567-5f13-4536-b3f3-a4a1e245ab2a") {
    history(
      fields: ["BATTERY"]
      timerangestart: "2021-04-16T00:00"
      timerangeend: "2021-04-17T00:00"
      resolution: "1h"
      aggregation: MAX
    )
  }
}
```

#### Response

The result is a JSON string with one row per timestamp, ordered by time. Each row has a `time` in UTC and one entry per field:

```json
[{"time": "2021-04-16T00:00:00Z", "BATTERY": 3.067}]
```

A field that has no data in the whole time frame is left out. A field without a value at a given time is `null`.

## Devices

### Metadata

The following snippet works for both `allDevices` and specific `device` Options.

```graphql
query {
  allDevices(inWorkspace:"f6331019-8978-4a86-b1bc-3522546f67d5") {
    location
    lastHeard
    claimed
    claimCode
    tags
    serialNumber
  }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.datacake.de/api/graphql-api/using-graphql.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
