Login / Sign Up

Sending IoT Data to Holidaymaker

API Specification and concepts on sending IoT data to the holidaymaker infrastructure to then be used and rendered on various holidaymaker surfaces.

Jamie McDonald

HXP Admin

IoT Data ingestion is a useful module within the holidaymaker infrastructure. It works by a provider sending the data regually to your holidaymaker web service, which will then distribute it throughout the rest of your holidaymaker sources and surfaces.

The IoT data we receive can be any string of numbers or characters, so essentially can be any reading from any device. When the values are rendered, you have the options to add your own custom setup to each collection of data, for example adding a prefix or suffix to values.

Example data could be :

  • Current Pool or Hot Tub Temperature – Example data could be a mix of number formats, or text : 30, 31.1, 30.2C, 30.1°C 
  • Wind speed or Wind Gust – Example data could be a mix of number formats, or text : 42, 31.5, 25mph, 25 MPH 
  • How busy the restaurant or bar is – Example could be a named or numbers enumeration : ‘busy’, ‘quiet’ or 0, 1 (with preshared definition that 0 is quiet and 1 is busy etc)

 

Before you can send IoT data to a holidaymaker it must be enabled, and setup by the holidaymaker team. Please contact us if you are an IoT provider wishing to send data for a client, or are a client who wishes to have the module enabled.

When sending us data you can send as data for all devices in one packet, or each device can send its own individual packet. This is very flexible based on provider, location and context.

  • Provider: You would often have a single provider per IoT company – or if your devices require different endpoints, this can be used to segment devices or device groups
  • Location: Each endpoint can include an optional location. If a holidaymaker install is a holiday park based, and has our ‘Group Sites’ module enabled then this should match the group site key set to the park the device is on. If not then this can be set to anything to represent it’s location, or left blank for single locations.
  • Context: This is sent in the data packet rather than the endpoint. Multiple contexts can be sent in one packet if required. The context is often used to differentiate between devices.

Endpoints

You will be provided with a unique endpoint for each provider and each location you wish to send us data for. The packet you then send down determines which context the reading is for.

All requests made to our endpoint are POST with a JSON packet of data for the body.

Example 1 : Single Holiday Park with a single provider

  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany

Example 2 : Multiple Holiday Park with a single provider

  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/groupsitekey1
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/groupsitekey2
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/groupsitekey3

Example 2 : Using locations and providers so devices have unique endpoints

  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany-group1/device1
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany-group1/device2
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany-group1/device3
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany-group2/device1
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany-group2/device2
  • https://your-holidaymaker-webservice.endpoint/hooks/iotcompany-group3/device1

Authentification

The endpoints will only allow data ingestion if you have an authorised API Key setup by the holidaymaker team. This will be provided to you and will need to be included in the HTTPS headers of all data pushes. See code examples below.

Example header : ApiKey: 12345ABCDEF

Post Body / JSON Data

The body of the request contains your data readings in JSON format. These are keyed using predetermined contexts as highlighted above. You can send a single context per request, or send multiple contexts in one packet.

The packet should be a single JSON object with the values keyed using the predetermined context keys. The value is always force read as a string, however none string primitive values can be sent such as integers, doubles, and booleans, which will be forced to be read and stored as a string.

Examples

In the examples below we are sending three contexts which have been defined before sending the data:

  • Outdoor Pool Temperature – Context key = outdoorpool
  • Indoor Pool Temprature – Context key = indoorpool
  • Playfield Wind Gust – Context key = playingfieldwind
//Single Packet (note that both strings and numbers are valid)
{
  "outdoorpool": 30.1,
  "indoorpool": "31.6",
  "playingfieldwind": "34mph"
}

//Seperate Packets
{"outdoorpool": 30.1}

{"indoorpool": "31.6"}

{"playingfieldwind": "34mph"}

//Mix - Maybe one from a service check pools, and one checking weather
{
  "outdoorpool": 30.1,
  "indoorpool": "31.6"
}

{"playingfieldwind": "34mph"}

Endpoint Response

When you POST data to our endpoint we will respond accordingly. Due to the simplicity of the request and context of the endpoint the results are limited.

HTTP Code

You will receive one of two HTTP codes back

  • 200 : Success – We have received a well formed data packet and will attempt to process what we can
  • 400 : Invalid Request / Error – There has been an error before the data can even be processed

If you receive a 400 error the packet will also include a plain text error message as a returning JSON packet with the property error :

  • Unknown IoT Hook : {PROVIDER} – The provider on the endpoint is not recognised / setup
  • The IoT hook is setup incorrectly on our service: {PROVIDER} – The provider on the endpoint is recognised but it has no allowed contexts or credentials assigned to it
  • Unauthorised – Setup is correct, however the ApiKey supplied in the header is incorrect
  • No body sent – Setup and ApiKey is OK, however no JSON body was found or it was an empty string
  • Cannot parse body as JSON – Setup and ApiKey is OK, however no JSON body was found or it was an empty string

If a 200 is received it means we can attempt to process the JSON and you will receive a 200 back. This does not however mean that we have stored the data, this instead is included as information in the response back to you, so you can error handle on your own end and contextualise what has been sent.

Response Packet

  • hookKey : This is your provider key sent in the endpoint
  • groupSite : This is the location key sent in the endpoint
  • contextsStored : This is a JSON object which shows what sent contexts were then successfully stored.
  • messages : This will only be present if we were unable to store one of the sent contexts or one of them was not recognised. This will be a list of messages which will state if a context is not recognised or setup, or if a value could not be inserted into the database for some reason.

Example Responses

// 200 - Everything OK - single value sent
{
    "hookKey": "iotprovider",
    "groupSite": "single-site",
    "contextsStored": [
        {
            "value": "30.5",
            "context": "poolTemperature"
        }
    ]
}

// 200 - Everything OK - Multiple Values sent with a different internal context for HM to use
{
    "hookKey": "iotprovider",
    "groupSite": "single-site",
    "contextsStored": [
        {
            "value": "30.5",
            "context": "poolTemperature",
            "internalContext": "pooltemp"
        },
        {
            "value": "7.11",
            "context": "poolPH"
        }
    ]
}

// 200 - Everything OK - Multiple Values sent but an additional unknown context was also sent
{
    "hookKey": "iotprovider",
    "groupSite": "single-site",
    "contextsStored": [
        {
            "value": "30.5",
            "context": "poolTemperature"
        },
        {
            "value": "7.11",
            "context": "poolPH"
        }
    ],
    "messages": [
        "Unknown Context/Value Received: madeUpContext : 11"
    ]
}

// 200 - Everything OK and processed - However no contexts were actually recognised
{
    "hookKey": "iotprovider",
    "groupSite": "single-site",
    "contextsStored": [],
    "messages": [
        "Unknown Context/Value Received: poolTemperat ure : 30.5",
        "Unknown Context/Value Received: po olPH : 7.11",
        "Unknown Context/Value Received: madeUpContext : 11",
        "Error: No contexts registered in this packet!"
    ]
}

//400 - Incorrect ApiKey
{
    "error": "Unauthorised"
}

//400 - Bad Json Sent
{
    "error": "Cannot parse body as JSON"
}

Code Examples

In the below examples IoT data for multiple pool readings are being sent to a single endpoint :

  • Endpoint : https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/parkname
  • Api Key : 1122334455667788
  • Data : pooltemperature at 30.5 and poolph at 7.11

These examples are for making a generic HTTP request using CURL, or language specific using PHP, JavaScript, or Python.

These examples include the ApiKey hardcoded. Please take care when storing/using our API key and ensure that it would never be visible on any front facing script to the public (eg a JavaScript unit on a website front end)

//Generic CURL request

curl -X POST https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/parkname \
  -H "Content-Type: application/json" \
  -H "ApiKey: 1122334455667788" \
  -d '{"pooltemperature":"30.5","poolph":"7.11"}'
<?php
//PHP Using CURL

$hmEndpoint = "https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/parkname";
$iotData = [
    "pooltemperature" => "30.5",
    "poolph"                  => "7.11"
];

$ch = curl_init($hmEndpoint);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json",
    "ApiKey: 1122334455667788"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($iotData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

//Check for errors etc
$response = curl_exec($ch);
curl_close($ch);

//Do something with response if required
echo $response;
//Generic JavaScript

const hmEndpoint = "https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/parkname";
const iotData = {
  pooltemperature: "30.5",
  poolph: "7.11"
};

fetch(hmEndpoint, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "ApiKey": "1122334455667788"
  },
  body: JSON.stringify(iotData)
})
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error("Error:", error);
  });
//Python Example

import requests

hmEndpoint = "https://your-holidaymaker-webservice.endpoint/hooks/iotcompany/parkname"
iotData = {
    "pooltemperature": "30.5",
    "poolph": "7.11"
}
headers = {
    "Content-Type": "application/json",
    "ApiKey": "1122334455667788"
}

response = requests.post(hmEndpoint, json=iotData, headers=headers)

//Do something with response
print(response.text)