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:
- grouting
- jet
- drilling
- anchor
- pile
- surveying
- wm (water monitoring)
- tj (tempjet temperature measurement)
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
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. |