NAV
shell python

Introduction

Welcome to the eguana SCALES API! You can use our API to access SCALES API endpoints.

We have language bindings in Shell and Python! View code examples in the dark area to the right, and switch the programming language of the examples with the tabs in the top right.

Authentication

SCALES uses API keys to allow access to the API. You can request new developer credentials (username and password) by sending an email to eguana office. SCALES expects an API Token to be included in all API requests to the server in the request header.

POST login

This endpoint will return the API Token which is required for every further API request.

HTTPS Request

Before you can send data to our endpoints you need to authorize first. You can use this code:

import hashlib
import requests
import json

def passwordHash(user_password):
    password = hashlib.md5()
    password.update(user_password.encode("utf-8"))
    return password.hexdigest()

headers = {'Content-Type': 'application/json'}
auth = {'username': 'username', 'password': passwordHash('password')}
request_url = 'https://dev.eguana.rocks/api/default/users/login'

try:
    r = requests.post(request_url, headers=headers, data=json.dumps(auth))
    if (r.ok):
        response = r.json()
        token = response['id'].strip()
        userid = response['userId']
        taskid = response['taskId']
        endpoint = response['api'].strip() + '/tasks/upload'
        return {'token': token, 'endpoint': endpoint, 'userid': userid, 'taskid': taskid}
except:
    raise Exception('Login to endpoint failed')
curl -X POST "https://dev.eguana.rocks/api/default/users/login" \
    -H 'Content-Type: application/json' \
    -d '{"username": "username", "password": "md5(password)"}'

The above command returns JSON structured like this:

[
    {
        "id": "wFvkPATJHf9Si3f5ldüw05Lkycd92oQGDKzhMa2ByZVkBLcJwb2sPGIi80rATGn2",
        "ttl": 1209600,
        "created": "2021-01-01T00:00:01.001Z",
        "userId": 100,
        "taskId": 10,
        "api": "https://dev.eguana.rocks/api/default"
    }
]

POST /api/default/users/login

Query Payload

Parameter Description
username Username
password Password (must be md5 hashed!!!)

Response JSON

If the POST request was succesfull (status code 200) the response will contain a json string with this information:

Parameter Description
id API token (must be supplied with each request!)
ttl Time to live - Time in seconds in which the token is valid (usual 2 weeks = 1209600 seconds)
created Creation time of the API token
userId User ID
taskId Task ID of the construction site
api API endpoint where all future requests must be pointed to

Sites & Tasks

GET all sites

This endpoint will return all available sites a user can access.

HTTPS Request

GET /tasks/externalTasks

import requests

api = '<endpoint-returned-from-login>/tasks/externalTasks'
headers = {'Authorization': 'API Token','Content-Type': 'application/json', 'user-agent': '<your device name>'}

try:
    r = requests.get(api, headers = headers)
except:
    raise Exception(f'Site fetch failed')
curl "<endpoint-returned-from-login>/tasks/externalTasks" \
  -H "Authorization": "API Token" \
  -H "user-agent": "<your device name>"

Response JSON

The above command returns JSON structured like this:

[
  {
    "siteid": "1",
    "taskid": "1",
    "site": "Demo Site 1",
    "name": "Drilling Task",
    "type": "drilling"
  },
  {
    "siteid": "1",
    "taskid": "2",
    "site": "Demo Site 1",
    "name": "Grouting Task",
    "type": "grouting"
  },
  ...
]

If the GET request was succesfull (status code 200) the response will contain a json string with this information:

Parameter Description
taskid a unique Task ID (must be supplied with each request!)
siteid a unique Site ID
site The name of the site
name The name of the task
type The type of the task

Points

GET all points

This endpoint will return the id and name of all points (default limit = 200) Start and end parameter limit the searched period If minId is provided, only points with an Id > minId will be returned (can be used to get new points since last fetch)

HTTPS Request

import requests

api = '<endpoint-returned-from-login>/tasks/externalPoints'
headers = {'Authorization': 'API Token','Content-Type': 'application/json', 'user-agent': '<your device name>'}

try:
    r = requests.get(api, headers = headers)
except:
    raise Exception(f'Points fetch failed')
curl "<endpoint-returned-from-login>/tasks/externalPoints" \
  -H "Authorization": "API Token"

GET /tasks/externalPoints

Query Parameters

Parameter Description
limit limit of the returned points, default 200, ordered by time of creation
offset offset
taskid id of the task, where the points are fetched from (required)
start string, starttime of period, 'YYYYMMDD HH:mm:ss'
end string, endtime of period, 'YYYYMMDD HH:mm:ss'
minId number, largest Id of already read points

Response JSON

The above command returns JSON structured like this:

[
  {
    "pointId": "1",
    "name": "Testpoint 1",
  },
  {
    "pointId": "2",
    "name": "Testpoint 2",
  },
  ...
]

If the GET request was succesfull (status code 200) the response will contain a json string with this information:

Parameter Description
pointId a unique point ID
name The name of the point

GET one Point

This endpoint will return the details of one specified point by id.

HTTPS Request

import requests

point_id = 1
api = f'<endpoint-returned-from-login>/tasks/externalPoint/{point_id}'
headers = {'Authorization': 'API Token','Content-Type': 'application/json', 'user-agent': '<your device name>'}

try:
    r = requests.get(api, headers = headers)
except:
    raise Exception(f'Point fetch failed')
curl "<endpoint-returned-from-login>/tasks/externalPoint/1" \
  -H "Authorization": "API Token"

GET /tasks/externalPoint/{id}

Response JSON

The above command returns JSON structured like this depending on the point type:

{
  "pointId": "1",
  "name": "Testpoint 1",
  "type": "grouting",
  "site": "construction site",
  "task": "task 5",
  "device": "boom1",
  "machine": "C-321-001",
  "location": [ 48.197708, 16.345615 ],
  "comment": "hello world!",
  "pmax": 30.00,
  "vmax": 200.00,
  "pset": 50.00,
  "maxPressure": 18,
  "vend": 190,
  "flushvol": 0,
  "jetvol": 0,
  "rinsevol": 0,
  "mixture": "dolomix 0.9",
  "properties": {"test": 1, "wert": 2},
  "rev": "trial 2",
}

If the GET request was succesfull (status code 200) the response will contain a json string with this information:

Parameter Description
pointId a unique point ID
name The name of the point
type The type of the point
other see optional meta-data

POST create a point (update)

This endpoint will create a new point if it doesn't exist!

HTTPS Request

import requests

api = '<endpoint-returned-from-login>/tasks/externalPoint'
headers = {'Authorization': 'API Token','Content-Type': 'application/json', 'user-agent': '<your device name>'}
payload = { 'type': 'grouting', 'name': 'Testpoint', ...}

try:
    r = requests.post(api, headers = headers, data=payload)
except:
    raise Exception(f'Upload to endpoint {api} failed')
curl "<endpoint-returned-from-login>/tasks/externalPoint" \
  -H "Authorization": "API Token"
  -d { "type": "grouting", "name": "Testpoint", ...}

POST /tasks/externalPoint

Required / Optional Meta-Data

type (required)

The type must be one of the following:

name (required)

The name of the measurement point

e.g.: "GPF-001"

site (required)

The name of the construction site

e.g.: "Zieglergasse 2"

task (required)

Kind of task done; can also be a sub-site on the construction site

e.g.: "DSV"

measurementtype (required)

measurementtype: [
                    ["depth", "m"],
                    ["status", ""],
                    ["pressure", "bar"],
                    [...],

                    ...
                  ]

Array of arrays. This declares the label and unit of the data sent in the data array.

device

specific device; can be part of a bigger machine assembly

e.g.: "boom1"

machine

unique machine identifier; can be the serial number

e.g.: "C-321-001"

location

The location of the machine / point. Has to be an array in the form [ latitude, longitude ]. The reference system must be WGS84 to be displayed correct in our system. Longitude and latitude must be expressed in Decimal Format.

e.g.: [ 48.197708, 16.345615 ]

pset

Set pressure, in bar

e.g.: 200.00

pmax

Maximum pressure, in bar

e.g.: 250.00

vmax

Maximum Volume, in liter

e.g.: 200.00

vend

End Volume, actual injected volume in liter

e.g.: 150.00

rev

Revision; number of trial at the same point

e.g.: 2

gin

Grouting Intensity Number

e.g.: 500.0

jetvol

Jet volume, in l

e.g.: 50.0

flushvol

Flush volume during drilling or jetting, in m³

e.g.: 10.0

rinsevol

Rinse volume for cleaning purposes, in m³

e.g.: 10.0

tilt

Tilt, in degrees

e.g.: 2.3

azimut

Azimut, in degrees

e.g.: 60.3

holdtime

Holdtime, in seconds

e.g.: 120.0

stepheight

Stepheight, in m

e.g.: 0.50

diameter

Diameter, in m

e.g.: 5.0

exectec

Execution technology

e.g.: "SOB"

mixture

Mixture of the used material

e.g.: "Acrylat"

properties

User properties; JSON Object with arbitrary keys and values e.g.: { "key1": "value1", "key2": "value2", "key3": "value3", ... }

comment

User comment; the string can contain up to 255 characters

e.g.: "User comment with multiple lines\nAnd another line"

The payload JSON must be structured like this:

{
  "type": "grouting",
  "name": "Testpoint",
  "site": "construction site",
  "task": "task 5",
  "device": "boom1",
  "machine": "C-321-001",
  "location": [ 48.197708, 16.345615 ],
  "comment": "hello world!",
  "pmax": 180.00,
  "vmax": 200.00,
  "pset": 50.00,
  "rev": "trial 2",
  "measurementtype": [ ["depth", "m"], ["status", ""], ["pressure", "bar"], [...], ... ],
  "data": [
            [ 1609491600000, 1.90, 2, 34.5789, ... ],
            [ ... ],
            ...
          ]
}
field type unit example grouting jet drilling anchor piling surveying wm tj
type string "grouting"
name string "Testpoint"
site string "construction site"
task string "task 5"
device string "boom1"
machine string "C-321-001"
location array [float, float] [long, lat] [ 48.197708, 16.345615 ]
pset float [bar] 180.00
pmax float [bar] 200.00
vmax float [l] 50.00
vend float [l] 150.00
rev integer 2
gin float 500.00
jetvol float [m³] 50.00
flushvol float [m³] 60.00
rinsevol float [m³] 70.00
tilt float [deg] 6.054
azimut float [deg] 22.22
holdtime float [sec] 120.00
stepheight float [m] 0.50
diameter float [m] 5.0
exectec string "Kelly"
mixture string "Acrylat"
properties JSON { key: value }
comment string "comment"

✔ required
✅ optional
❌ not supported

Measurement Data

GET measurement data

This endpoint returns the measurement data for one point (pointId)

HTTPS Request

import requests

point_id = 1
api = f'<endpoint-returned-from-login>/tasks/externalPointData/{point_id}'
headers = {'Authorization': 'API Token','Content-Type': 'application/json', 'user-agent': '<your device name>'}

try:
    r = requests.get(api, headers = headers)
except:
    raise Exception(f'Upload to endpoint {api} failed')
curl "<endpoint-returned-from-login>/tasks/externalPointData/1" \
  -H "Authorization": "API Token" \
  -H "user-agent": "<your device name>"

GET /tasks/externalPointData/{id}

Query Parameters

Parameter Description
start string, starttime of period, 'YYYYMMDD HH:mm:ss'
end string, endtime of period, 'YYYYMMDD HH:mm:ss'
detailed boolean, if true, all measurementvalues are returned, mandatary to be true for grouting, jetting, drilling
daily boolean, if true, daily avg values are calculated, useful for surveying or watermanagement

Response JSON

If the GET request was succesfull (status code 200) the response will contain a json string with a data property being an array of measurements. Each entry consists of an object with unit, label and values. Values being an array of objects, containing ts, an epoch timestamp and a value.

{
  "pointId": "1",
  "start": "2024-01-01 15:00", //start of values, only if start was provided
  "end": "2024-01-02 15:00", //end of values, only if end was provided
  "data": [
            {
              "unit": "bar",
              "label": "Pressure",
              "values": [
                {
                  "ts": 1609491600000,
                  "value": 0
                },
                ...
              ]
            },
            ...
          ]
}

POST measurement data

This endpoint adds the supplied measurement data to the specified point (pointId)

HTTPS Request

import requests

point_id = 1
api = f'<endpoint-returned-from-login>/tasks/externalPointData/{point_id}'
headers = {'Authorization': 'API Token','Content-Type': 'application/json', 'user-agent': '<your device name>'}
payload = {'id': '', 'data': [[ 1609491600000, 1.90, 2, 34.5789, ...], ...]}

try:
    r = requests.post(api, headers = headers, data = payload)
except:
    raise Exception(f'Upload to endpoint {api} failed')
curl "<endpoint-returned-from-login>/tasks/externalPointData/1" \
  -H "Authorization": "API Token" \
  -H "user-agent": "<your device name>" \
  -d payload

POST /tasks/externalPointData

Query payload

example payload:

{
  "id": "278bfb63-4ba0-33a2-80c5-75255b45ddb0",
  "data": [
          [ 1609491600000 , // timestamp in ms e.g.: GMT Friday, 1. January 2021 09:00:00
            1.90 ,          // depth
            2 ,             // status
            34.5789 ,       // pressure
            ... ],
          ...
        ]
}

The pointId must be in the payload data!!! Array of measurement data. The data has to be structured as defined in the measurementtype array. Element [0] has to be the epoch timestamp of the measurement in ms. Usually followed by depth and status.

status

Status can be specified within the measurement data. It is mandatory for types drilling and jetting.

Status Code Meaning
1 idle / pause
2 drilling
3 precutting
4 jetting
5 rod manipulation
6 pulling
7 rinsing / flushing

Errors

The eguana SCALES API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
403 Forbidden -- This request is not allowed!
404 Not Found -- The specified endpoint could not be found.
405 Method Not Allowed -- You tried to access a ressource with an invalid method.
466 Not Acceptable -- Your request didn't meet our requirements. See the documentation again.
418 I'm a teapot.
429 Too Many Requests -- You are requesting too much! Slow down!
500 Internal Server Error -- We had a problem with our server. Please try again.
502 Service Unavailable -- We are temporarily offline for maintenance. Please try again later.
503 Service Unavailable -- We are temporarily offline for maintenance. Please try again later.