geoffwilliams@home:~$

SensorThings REST API (register a weather station)

Now that I have a working SensorThings (FROST) server running, lets go ahead and register the Makerfabs weather station.

Have a look at the FROST guide first, then have a go yourself.

To register the weather station, we need to make multiple POST requests to the SensorThings API server.

You can do this however you like (curl, python, etc). For simplicity, I decided to use Postman for this today.

Pretty much all I need to do is configure Postman to send:

  • BASIC authentication credentials
  • Use JSON
  • Use POST
  • Send a RAW POST body

And then copy-paste the JSONs below, keeping a note of identifiers where needed as things are created and using the right URL for each item.

To get the URL to use in postman, just right-click, copy URL on the v1.1 link on the FROST server welcome page.

You then need to append the name of the API to the API endpoint address (eg /Things), or you will get the error in postman:

{
    "code": 500,
    "type": "error",
    "message": "Failed to store data."
}

And in the logs:

2025-11-15 06:42:18,326 4360694 ERROR d.f.iosb.ilt.frostserver.service.Service - Failed to handle request (details in debug): Index -1 out of bounds for length 0

Thing

Example URL: http://lab-0.lab.asio:8080/FROST-Server.MQTTP-2.6.2/v1.1/Things

{
  "name": "Makerfabs Weather Station",
  "description": "ESPHome-based weather station from Makerfabs",
  "properties": {
    "manufacturer": "Makerfabs",
    "model": "Weather Station for Home Assistant",
    "firmware": "ESPHome",
    "device": "weather-station"
  }
}

registering a thing

If you see 201 created it works. Keep a note of the ID (Headers tab in bottom half of screen) as you will need it for the rest of the JSONs, or you can look it up again with the API (execute button on welcome page).

Location

SensorThings uses WGS-84 (EPSG:4326) by default

URL: http://lab-0.lab.asio:8080/FROST-Server.MQTTP-2.6.2/v1.1/Locations

{
  "name": "Weather Station Location",
  "description": "Physical location of the Makerfabs weather station",
  "encodingType": "application/vnd.geo+json",
  "location": {
    "type": "Point",
    "coordinates": [151.20746, -33.84122]
  },
  "Things": [
    {"@iot.id": 1}
  ]
}

Observed Properties

URL: http://lab-0.lab.asio:8080/FROST-Server.MQTTP-2.6.2/v1.1/ObservedProperties

{
  "name": "Air Temperature",
  "description": "Ambient air temperature measured by the weather station",
  "definition": "http://qudt.org/vocab/quantitykind/Temperature"
}
{
  "name": "Relative Humidity",
  "description": "Relative humidity measured by the weather station",
  "definition": "http://qudt.org/vocab/quantitykind/RelativeHumidity"
}
{
  "name": "Atmospheric Pressure",
  "description": "Barometric pressure measured by the weather station",
  "definition": "http://qudt.org/vocab/quantitykind/Pressure"
}
{
  "name": "Wind Speed",
  "definition": "http://vocab.nerc.ac.uk/collection/P07/current/CFSN0332/",
  "description": "Wind speed measured in meters per second"
}
{
  "name": "Air Quality (PM2.5)",
  "description": "Particulate matter (PM2.5) concentration measured by the weather station",
  "definition": "http://qudt.org/vocab/quantitykind/MassConcentration"
}

Sensor

URL: http://lab-0.lab.asio:8080/FROST-Server.MQTTP-2.6.2/v1.1/Sensors

{
  "name": "Makerfabs Weather Station Sensor",
  "description": "Combined sensor for temperature, humidity, pressure, wind speed on Makerfabs weather station",
  "encodingType": "application/pdf",
  "metadata": "https://makerfabs.com/weather-station-for-home-assistant-esphome.html"
}

Data Streams

  • One data stream for each ObservedProperty
  • I populated the IDs I’m using

URL: http://lab-0.lab.asio:8080/FROST-Server.MQTTP-2.6.2/v1.1/Datastreams

{
  "name": "Air Temperature Datastream",
  "description": "Air Temperature readings from the Makerfabs weather station",
  "unitOfMeasurement": {
    "name": "Degree Celsius",
    "symbol": "°C",
    "definition": "http://unitsofmeasure.org/ucum.html#para-30"
  },
  "observationType": "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement",
  "Thing": {
    "@iot.id": 1
  },
  "ObservedProperty": {
    "@iot.id": 1 
  },
  "Sensor": {
    "@iot.id": 1
  }
}
{
  "name": "Relative Humidity Datastream",
  "description": "Relative Humidity readings from the Makerfabs weather station",
  "unitOfMeasurement": {
    "name": "Percent",
    "symbol": "%",
    "definition": "http://unitsofmeasure.org/ucum.html#para-65"
  },
  "observationType": "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement",
  "Thing": { "@iot.id": 1 },
  "ObservedProperty": { "@iot.id": 2 },
  "Sensor": { "@iot.id": 1 }
}
{
  "name": "Atmospheric Pressure Datastream",
  "description": "Atmospheric pressure readings from the Makerfabs station",
  "unitOfMeasurement": {
    "name": "Pascal",
    "symbol": "Pa",
    "definition": "http://unitsofmeasure.org/ucum.html#para-71"
  },
  "observationType": "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement",
  "Thing": { "@iot.id": 1 },
  "ObservedProperty": { "@iot.id": 3 },
  "Sensor": { "@iot.id": 1 }
}
{
  "name": "Wind Speed",
  "description": "Wind speed reported by the Makerfabs Weather Station",
  "unitOfMeasurement": {
    "name": "Meters per second",
    "symbol": "m/s",
    "definition": "http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#MeterPerSecond"
  },
  "observationType": "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement",
  "Thing": { "@iot.id": 1 },
  "Sensor": { "@iot.id": 1 },
  "ObservedProperty": { "@iot.id": 4 }
}
{
  "name": "Air Quality Datastream",
  "description": "PM2.5 air quality readings from the Makerfabs Weather Station",
  "unitOfMeasurement": {
    "name": "Micrograms per cubic meter",
    "symbol": "µg/m³",
    "definition": "http://qudt.org/vocab/unit#MicroGMPerM3"
  },
  "observationType": "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement",
  "Thing": { "@iot.id": 1 },
  "ObservedProperty": { "@iot.id": 5 },
  "Sensor": { "@iot.id": 1 }
}

Observations

We can now test submitting an Observation to datastream @iot.id 1 (temperature) with postman.

URL: http://lab-0.lab.asio:8080/FROST-Server.MQTTP-2.6.2/v1.1/Observations

{
  "result" : 21,
  "Datastream": {"@iot.id": 1}
}

observation ok

If we copy-paste the Location header returned from the POST in Postman to our web browser, we can cross-check the observation was saved and is readable:

crosscheck ok

You can see the JSON returned links back to the Datastream. Following this link gives us more info about the datastream:

datastream

This is part of what makes SensorThings so useful. Through this linking, we can read about sensor hardware, current and past sensor locations, find other datastreams and so on.

Contrast this with the typical old fashioned way of doing this kind of thing - CSV file on a server somewhere, or an insanely complicated XML schema that pads out that same file to multiple gigabytes - SensorThings is looking very promising as way to share interoperable sensor data with the world in an easy to understand way.

Post comment

Markdown is allowed, HTML is not. All comments are moderated.