Many people asked me this question: What are the differences between OGC SensorThings API and OGC Sensor Observation Service?  As one of the contributors of the very first version of OGC SOS specification back in 2005 and the editor of the OGC SensorThings API, I think I am eligible to offer my view of the two specifications. 🙂

In fact, SensorUp’s team has experiences in implementing multiple SOS clients and servers. We also published more than 10 peer-reviewed research papers on this topic. When we designed SensorThings API, our goal is to apply the lessons we learned so that SensorThings API can provide better scalability, performance, discoverability, real-time capability, and most importantly, better developer experiences!!

This blog post provides a high level technical comparison between the two OGC standard specifications. I will detailed my view and experiences of the two specifications in a future blog (maybe more than one).

From a technical and functional perspective, the differences between the two specifications can be summarized as follows:

[table class=”table table-striped”] ,OGC SensorThings API,OGC Sensor Observation Service (SOS)
Encoding,JSON,XML
Architectural Style,Resource Oriented Architecture,Service Oriented Architecture
Binding,REST,SOAP
Insert new Sensors and Observations,HTTP POST,SOS specific interface: RegisterSensor() and InsertObservation()
Deleting Existing Sensors,HTTP DELETE,SOS specific interface: DeleteSensor()
Pagination,$top/$skip/$nextLink,Not supported

Pub/Sub Support,MQTT and SensorThings MQTT Extension,Not supported
Updating Properties of Existing Sensors or Observations,HTTP PATCH and JSON PATCH,Not supported
Deleting Existing Observations,HTTP DELETE,Not supported
Linked Data Support,JSON-LD,Not supported[/table]

Supporting real-time sensing applications

As you can see, SensorThings API supports several critical use cases that are not supported in SOS specification. Experienced SOS (or any OGC developers) would agree with me, the #1 feature missing in the SOS specification is the lacking of publish and subscribe support.  That means in order to receive the latest Observations from sensors, an SOS client needs to repeatedly and frequently send redundant requests to the server . It creates unnecessary burdens to clients, servers, and network. SensorThings API addresses the issue elegantly with a well-defined mapping between HTTP Resource Path and MQTT Topic. That means SensorThings developers can use the same resource path structure to retrieve/filter historical data (via HTTP/CoAP) or to receive future updates (via MQTT). I would say this is a very significant improvement over the SOS specification. Although “hacks” exist and attempt to achieve the same goal, these hacks are not standard-compliant and even worse they break the existing SOS specification and create confusions.

Great developer experience

In my opinion, the other great improvement of SensorThings is its great developer experience. Let’s use one of the most common use case in IoT as an example: Create a new sensor and insert new readings.

First I would like to show you an example insertObservation request of the SOS (p.56 of the SOS 2.0 specification)

<br />
 <?xml version="1.0" encoding="UTF-8"?><br />
 <soap12:Envelope xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xsi:schemaLocation="http://www.w3.org/2003/05/soap-envelope http://www.w3.org/2003/05/soap-envelope/soap-envelope.xsd<br />
http://www.opengis.net/sos/2.0 http://schemas.opengis.net/sos/2.0/sos.xsd" xmlns:sos="http://www.opengis.net/sos/2.0" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:swe="http://www.opengis.net/swe/2.0" xmlns:swes="http://www.opengis.net/swes/2.0" xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:ogc="http://www.opengis.net/ogc" xmlns:om="http://www.opengis.net/om/2.0" xmlns:xlink="http://www.w3.org/1999/xlink"><br />
 <soap12:Header><br />
 <wsa:To>http://www.ogc.org/SOS </wsa:To><br />
 <wsa:Action>http://www.opengis.net/def/serviceOperation/sos/obsInsertion/2.0/InsertObservation </wsa:Action><br />
 <wsa:ReplyTo><br />
 <wsa:Address>http://www.w3.org/2005/08/addressing/anonymous </wsa:Address><br />
 </wsa:ReplyTo><br />
 <wsa:MessageID>http://my.client.com/uid/msg-0010 </wsa:MessageID><br />
 </soap12:Header><br />
 <soap12:Body><br />
 <sos:InsertObservation service="SOS" version="2.0.0"><br />
 <sos:offering>http://www.my_namespace.org/water_gage_2_observations </sos:offering><br />
 <sos:observation><br />
 <om:OM_Observation gml:id="obsTest1"><br />
 <om:type<br />
 xlink:href="http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement"/><br />
 <om:phenomenonTime><br />
 <gml:TimeInstant gml:id="phenomenonTime"><br />
 <gml:timePosition>2010-08-31T17:45:15.000+00:00 </gml:timePosition><br />
 </gml:TimeInstant><br />
 </om:phenomenonTime><br />
 <om:resultTime xlink:href="#phenomenonTime"/><br />
 <om:procedure xlink:href="http://www.my_namespace.org/sensors/Water_Gage_2"/><br />
 <om:parameter><br />
 <om:NamedValue><br />
 <om:name xlink:href="http://www.opengis.net/req/omxml/2.0/data/samplingGeometry"/><br />
 <om:value><br />
 <gml:Point gml:id="SamplingPoint2"><br />
 <gml:pos srsName="http://www.opengis.net/def/crs/EPSG/0/4326">54.9 10.52 </gml:pos><br />
 </gml:Point><br />
 </om:value><br />
 </om:NamedValue><br />
 </om:parameter><br />
 <om:observedProperty xlink:href="http://sweet.jpl.nasa.gov/2.0/hydroSurface.owl#WaterHeight"/><br />
 <om:featureOfInterest xlink:href="http://wfs.example.org?request=getFeature&amp;amp;amp;amp;featureid=river1"/><br />
 <om:result xsi:type="gml:MeasureType" uom="urn:ogc:def:uom:OGC:m">0.28 </om:result><br />
 </om:OM_Observation><br />
 </sos:observation><br />
 </sos:InsertObservation><br />
 </soap12:Body><br />
 </soap12:Envelope><br />

And below is an example request to create a new Observation with SensorThings API (example 27 of the SensorThings API specification):

POST /Observations HTTP/1.1<br />
Host: example.org/v1.0/Observations<br />
Content-Type: application/json<br />
{<br />
 "Datastream":{<br />
 "@iot.id":1<br />
 },<br />
 "phenomenonTime":"2013-04-18T16:15:00-07:00",<br />
 "result":124,<br />
 "FeatureOfInterest":{<br />
   "@iot.id":2<br />
 }<br />
}

I believe it is very clear to see that SensorThings API is more clear and efficient.  It is clear in that it follows the HTTP standard (RFC2616), and the request and response behaviours of a POST request follows RFC2616.  It is efficient in that SensorThings uses a linking structure, so that the request is very compact. In fact, the above request can be further reduced to a even more compact version. (Note that the resource path updated from /Observations to Datastreams(1)/Observations). Such efficiency is very important for IoT applications as the IoT devices are constrained by battery-power and bandwidth.

<br />
POST Datastreams(1)/Observations HTTP/1.1<br />
Host: example.org/v1.0/<br />
Content-Type: application/json<br />
{<br />
 "result":124,<br />
}

There are more use cases that differentiate SensorThings API from SOS. I will write them in future blogs entires.