![](logos/snon_small.png) ## 1. Introducing SNON SNON 2 is the second generation of the Sensor Network Object Notation (SNON), a lightweight sensor data representation for interchange and storage. Why use SNON? * SNON is easy for humans to read and write * SNON is easy for machines to parse and generate * SNON is highly compressible to reduce storage and network usage * SNON is based on [JSON](http://json.org/), which is widely supported by most platforms and programming languages * SNON is sensor independent, and uses conventions familiar to programmers who have worked with common sensor platforms * SNON is self-describing and extensible, with features only required when needed * SNON makes sensor interoperabilty and "plug and play" easy These properties make SNON ideal for: * Discovery and lifecycle management of sensors and sensor topologies * Encapsulation of sensor data for eventing systems such as [CloudEvents](https://github.com/cloudevents/spec/blob/v0.3/primer.md) * Delivery of sensor data over lightweight message protocols such as [MQTT](http://mqtt.org/) * Summarization and aggregation of sensor data * Efficient storage in key/value and columnar time-series databases ## 1.1 What does SNON look like? Here are some examples of SNON in action: Example 1.1 - A single temperature value [ { "eID":"urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e", "v":["28.15"], "vT":["2014-08-20T14:32:57.126Z"] } ] SNON provides a standardized representation for describing values measured by sensors. In this example, the "eID" field indicates the identity of the sensor (the entity ID), the "v" field indicates the value, and the "vT" field indicates the time for the value. Example 1.2 - A definition for a temperature sensor [ { "entityID": "urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e", "entityType": "sensor", "entityName": { "jp": "冷却水の温度", "*": "Cooling Water Temperature" }, "measureUnit": "°C", "measureType": "numeric", "measureAcquire": "sample", "measureDisplayUnit": { "en-us": "°F", "*": "°C" }, "measureUnitPrefix": { "jp": "摂氏" }, "measureUnitSuffix": { "jp": "度", "en-us": " ℉", "*": " ℃" }, "measureUnitSuffixEx": { "en-us": " degrees Fahrenheit", "*": " degrees Celsius" } } ] Sensor data needs context to be meaningful. SNON provides a standardized representation for describing entities, such as sensors, devices and locations. A entity catalog can use SNON to enable discovery of sensors that match certain criteria, including sensor type, characteristics, and relationships with other entities. Example 1.3 - CloudEvents encapsulation { "specversion": "0.3", "type": "org.snon.v2", "schemaurl": "http://www.snon.org/v2/snon-schema.json", "source": "urn:uuid:407ec909-2519-4a2a-980b-ee75a47020ad", "id": "urn:uuid:f4dfec0c-259b-4f1b-9eba-9070a4d64b7b", "time": "2014-08-20T14:34:56.125Z", "data" : { "eID":"urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e", "v":["28.15","28.14","28.15","28.15","28.14","28.14","28.13","28.13","28.12","28.11"], "vT":["2014-08-20T14:32:57.126Z","/PT10S","/PT20S","/PT30S","/PT40S","/PT50S","/PT60S","/PT70S","/PT80S","/PT90S"] } } In this example, a series of sensor values and times are wrapped in a CloudEvent. SNON Messages (which include an message ID) can be sent over message-based protocols, such as UDP, MQTT or various real-time transports. SNON Fragments can be sent over stream-based protocols, such as TCP/IP, HTTP long-polling, or Websockets, where the source is associated with the connection. More examples can be found in section [3.0 SNON Examples](#examples). ## 1.2 Where does SNON Fit? In a typical sensor system, physical values are measured by sensors, which are managed by gateways. Gateways use SNON as a representation to send measured values over a transport protocol (e.g. MQTT and HTTP) to sensor data processing engines, storage repositories, and display/HMI systems. <center> ![SNON Data Flow](images/snon_flow.png) <br> Figure 1 - Reference Data Flow <br><br></center> SNON allows all of these components to work together. For example, real-time post-processing of sensor data, such as quantization, summarization, filtering, and multi-sensor fusion can be performed on SNON data, with the resulting derived values again being represented as SNON data, and forwarded on to later processing elements. ## 2. SNON Data Model SNON defines a JSON-based representation used to exchange data between entities within a sensor network. There are three different JSON data types defined: 1. SNON fragments contain information related to entities, measurements and/or values. 2. SNON messages uniquely identify a SNON fragment. 3. SNON collections contain one or more SNON messages and/or SNON fragments. SNON collections can also be signed and/or encrypted using the JOSE JWE and JWS standards. See [Section 5](#security) for more details on how SNON works with JOSE. SNON fragments can be encapsulated in other event data structures, such as [CloudEvents](https://github.com/cloudevents/spec/blob/v0.3/primer.md). See [Section 6](#encapsulation) for more details on how SNON works with CloudEvents. <center> ![SNON Model](images/snon_model.png) <br> Figure 2 - SNON JSON Model <br><br></center> SNON messages contain the following fields: * [Message Fields](#mfields) - Outer encapsulation of SNON Fragments SNON fragments contain the following fields: * [Entity Fields](#dfields) - Entity Definitions * [Measurement](#mefields) Fields - Measurement Definitions * [Value Fields](#vfields) - Measured Values ## <a name="mfields"></a>2.1 Message SNON Fields Each SNON message shall contain one or more of the following JSON fields: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | messageID<br>(mID) | JSON String | Globally unique identifier of an SNON message.<br><br>Uniquely identifies the message, allowing message receivers to identify duplicates. Every message generator shall ensure that each Message ID is globally unique by using a technique such as random or MAC-based UUID generation, as described in [RFC 4112](https://tools.ietf.org/html/rfc4122)<br><br>The value of this field shall be formatted as an [RFC 8141](https://tools.ietf.org/html/rfc8141) URN.<br><br>When used with CloudEvents, the message ID shall be used as the value of the CloudEvents "id" field.<pre>Example 2.1.1<br><br>{<br> "mID":"urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e"<br>}</pre> | Mandatory | | messageTime<br>(mT) | JSON String | Creation time of an SNON message.<br><br>Indicates when an SNON message was created, allowing message receivers to determine if messages are missing or are received out of order.<br><br>The value of this field shall be formatted in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) extended representation date/time format.<br><br>When used with CloudEvents, the message time shall be used as the value of the CloudEvents "time" field.<pre>Example 2.1.2<br><br>{<br> "mID":"urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e",<br> "mT":"2014-08-20T14:32:57.126Z"<br>}</pre> | Mandatory | | message<br>(m) | JSON Objects | Contains an SNON Fragment to be included in the message.<br><br>Contains the SNON fragment included in the message.<br><br>The value of this field shall be a JSON Object containing SNON Device, Sensor, Measurement or Value fields.<br><br>When used with CloudEvents, the SNON fragment shall be used as the value of the CloudEvents "data" field.<pre>Example 2.1.4<br><br>{<br> "mID":"urn:uuid:c01ceb9ef-6e75-409d-be81-337609e58aa1",<br> "mT":"2014-08-20T14:32:57.126Z"<br> "m":{...}<br>}</pre> | Mandatory | Each SNON message shall be considered immutable once created. ## <a name="dfields"></a>2.2 Entity SNON Fields A SNON Fragment may contain one or more of the following JSON fields: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | entityID<br>(eID) | JSON String | Globally unique identifier of the entity.<br><br>Uniquely identifies the entity, allowing message receivers to determine which device the message contents or relation applies to. Every message generator shall ensure that each entity ID is globally unique by using a technique such as random or MAC-based UUID generation, as described in [RFC 4112](https://tools.ietf.org/html/rfc4122)<br><br>The value of this field shall be formatted as an [RFC 8141](https://tools.ietf.org/html/rfc8141) URN.<pre>Example 2.2.1<br><br>{<br> "entityID":"urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e"<br>}</pre> | Optional | | entityClass<br>(eC) | JSON String | Entity type indicator.<br><br>Identifies what the entity represents.<br><br>The value of this field shall be one of the following strings:<br><br>a) "sensor"<br>b) "device"<br>c) "location"<br><br>If this field is not present, the default value shall be "sensor".<pre>Example 2.2.2<br><br>{<br> "entityClass":"device"<br>}</pre> | Optional, requires entityID | | entityName<br>(eN) | JSON Object | Descriptive Name of the entity.<br><br>Provides a set of human-readable names that describe the entity, allowing message receivers to list and identify the entity to end users.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a descriptive name of the entity in that language-region. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.2.3:<br><br>{<br> "entityName": {<br> "jp": "冷却水の温度",<br> "en": "Cooling Water Temperature"<br> }<br>}</pre> | Optional, requires entityID | | entityTag<br>(eTag) | JSON Object | Identification tag for the entity.<br><br>The value of this field shall be a string containing the P&ID letters and loop number as defined in [ANSI/ISA-S5.1](https://www.isa.org/isa5-1/).<pre>Example 2.2.4:<br><br>{<br> "entityTag": "TT1123"<br>}</pre> | Optional, requires entityID | | entityType<br>(eT) | JSON Object | Descriptive Name of the type of the entity.<br><br>Provides a set of human-readable names that describe the entity type, allowing message receivers to list and identify the device by type to end users.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a descriptive name of the sensor in that language-region. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.2.5:<br><br>{<br> "entityType": {<br> "jp": "温度センサー",<br> "en": "Temperature Sensor"<br> }<br>}</pre> | Optional, requires entityID | | entityRelations<br>(dR) | JSON Object containing JSON Arrays of JSON Strings | Globally unique identifiers of related entities.<br><br>Identifies relationships between entities. Each relationship is a JSON object with the name specifying the type of relationship, and the value containing an array of URIs specifying the related entities. Entity relationships are described in table 2.9.<br><br>The value of each ID shall be formatted as an [RFC 8141](https://tools.ietf.org/html/rfc8141) URN.<pre>Example 2.2.6<br><br>{<br> "entityRelations": {<br> "parent":["urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e"]<br> }<br>}</pre> | Optional, requires entityID | | precedentID<br>(pID) | JSON String | Globally unique identifier of a preceding SNON message.<br><br>Identifies a prior message to inherit fields from, allowing message senders to reduce network traffic by not repeating fields already accessible to a message receiver. SNON messages with a precedentID do not need to repeat information that has not changed. If an omitted field is present in the precedent message, the field from the precedent is inherited, and treated as if it were directly included in the message.<br><br>The value of this field shall be formatted as an [RFC 8141](https://tools.ietf.org/html/rfc8141) URN.<pre>Example 2.2.7<br><br>{<br> "precedentID": "urn:uuid:cd9f930e-a3b4-423a-850b-3c81135f0f7e"<br>}</pre> | Optional | When a SNON Fragment contains a precedentID, the message sender should ensure that the message receiver has access to the specified message in order to permit the message to be "resolved". Fragments with a precedentID that cannot be accessed is "unresolvable", and shall not be used. Figure 3 shows how fields from preceding messages are inherited: <center> ![SNON Precedents](images/snon_precedents.png) <br> Figure 3 - SNON Messages with Precedents <br><br></center> Figure 4 shows the corresponding resolved SNON messages. Message senders may optionally resolve messages before sending them, and message receivers may optionally resolve messages before storing them. <center> ![SNON Inheritance](images/snon_inheritance.png) <br> Figure 4 - Corresponding Resolved SNON Messages <br><br></center> When resolving a precedentID, the following conditions shall be handled: * The message receiver shall convert short names into long names, or long names into short names, as required. * The message receiver shall perform cycle detection. If a cycle is detected, the fragment is unresolvable. ## <a name="mefields"></a>2.4 Measurement SNON Fields Measurement fields define the characteristics of the value being measured. These are typically used to determine how to process and store sensor values. Each SNON Fragment may contain one or more of the following JSON fields: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | measureUnit<br>(meU) | JSON String | Unit indicator for the value measured by the sensor.<br><br>Identifies what physical or calculated quantity is being measured.<br><br>The value of this field shall be formatted as either:<br>a) an [ISO 80000-1:2009](https://www.iso.org/standard/30669.html) special symbol (or [SI unit symbol](http://www.bipm.org/en/si/si_brochure/)),<br> b) a combination of symbols for units, as defined in 7.2.2 of [ISO 80000-1:2009](https://www.iso.org/standard/30669.html),<br>c) an empty string, representing a unitless value, or,<br>d) a custom (non-SI) value.<br><br>If this field is not present, the default value shall be an empty string.<br><br>NOTE: While SI prefix conversion may be performed for display (e.g. 27.8 m/s -> 100 km/h), SNON measureUnit fields should always specify units without metric prefixes.<pre>Example 2.4.1<br><br>{<br> "measureUnit": "m/s"<br>}</pre> | Optional | | measureType<br>(meT) | JSON String | Data type indicator for the value measured by the sensor.<br><br>Identifies what data type is stored in the value associated with a measurement.<br><br>The value of this field shall be contain one of the following:<br>a) "enumeration" &ndash; The sensor value shall contain a string representation of an integer, which corresponds to a string specified in the measureLabel field.<br>b) "numeric" &ndash; The sensor value shall contain a string representation of a number,<br>c) "string" &ndash; The sensor value shall consist of a UTF-8 string value, or, <br>d) "url" &ndash; The sensor value shall contain a string representation of a URL (including data URIs as defined in [RFC 2397](https://tools.ietf.org/html/rfc2397)).<br><br>If this field is not present, the default value shall be "numeric".<pre>Example 2.4.2<br><br>{<br> "measureType": "numeric"<br>}</pre> | Optional | | measureAcquire<br>(meAq) | JSON String | Data Acquisition indicator for the value measured by the sensor.<br><br>Identifies what method is used by the sensor to acquire a value.<br><br>The value of this field shall be contain one of the following:<br><br>a) "sample" &ndash; The value represents a measurement made at the start of valueTime.<br>b) "count" &ndash; The value represents an increasing count, measured the start of valueTime.<br>c) "triggered" &ndash; The value represents a measurement, captured at the end of valueTime.<br>d) "summary" &ndash; the value represents a summarization of measurements that occurred during the valueTime range.<br>e) "derived" &ndash; The value represents calculations of measurements, valid for the start of valueTime.<br><br>If this field is not present, the default value shall be "sample".<pre>Example 2.4.3<br><br>{<br> "measureType": "sample"<br>}</pre> | Optional | ## 2.5 Measurement Descriptive SNON Fields Measurement descriptive fields provide additional information about how the measurement made by the sensor is displayed and organized. These are typically used for sensor discovery and cataloging. Each SNON Fragment may contain one or more of the following JSON fields: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | measureUnitPrefix<br>(meUP) | JSON Object | Descriptive Name of the prefix to be displayed before the measured value.<br><br>Provides a set of human-readable prefixes that come before the value measured by the sensor, allowing message receivers to display sensor measurements to end users.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a prefix in that language-region, to be displayed before the value of the measurement. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.5.1<br><br>{<br> "measureUnitPrefix": {<br> "jp": "摂氏",<br> "&#42;": ""<br> }<br>}</pre> | Optional | | measureUnitSuffix<br>(meUS) | JSON Object | Descriptive Name of the suffix to be displayed after the measured value.<br><br>Provides a set of human-readable suffixes that come after the value measured by the sensor, allowing message receivers to display sensor measurements to end users.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a suffix in that language-region, to be displayed before the value of the measurement. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.5.2<br><br>{<br> "measureUnitSuffix": {<br> "jp": "度",<br> "en-us": " ℉",<br> "&#42;": " ℃"<br> }<br>}</pre> | Optional | | measureUnitPrefixEx<br>(meUPx) | JSON Object | Extended descriptive Name of the prefix to be displayed before the measured value.<br><br>Provides a long-form set of human-readable prefixes that come before the value measured by the sensor, allowing message receivers to display sensor measurements to end users.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a long-form prefix in that language-region, to be displayed before the value of the measurement. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.5.3<br><br>{<br> "measureUnitPrefixEx": {<br> "jp": "摂氏",<br> "&#42;": ""<br> }<br>}</pre> | Optional | | measureUnitSuffixEx<br>(meUSx) | JSON Object | Extended descriptive Name of the suffix to be displayed after the measured value.<br><br>Provides a long-form set of human-readable suffixes that come after the value measured by the sensor, allowing message receivers to display sensor measurements to end users.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a long-form suffix in that language-region, to be displayed before the value of the measurement. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.5.4<br><br>{<br> "measureUnitSuffixEx": {<br> "jp": "度",<br> "en-us": " degrees Fahrenheit",<br> "&#42;": " degrees Celsius"<br> }<br>}</pre> | Optional | | measureLabel<br>(meL) | JSON Object of JSON Objects | Descriptive Name of enumeration values.<br><br>Provides a set of human-readable values corresponding to enumerated values of a sensor of type "enumerated", allowing message receivers to display sensor measurements to end users.<br><br>The value of this field shall contain a JSON Object, with each object contained being a JSON Object containing one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing a long-form suffix in that language-region, to be displayed before the value of the measurement. <br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.5.5<br><br>{<br> "measureLabel": {<br> "0":{<br> "jp": "開弁",<br> "en-us": " Opened Valve"<br> },<br> "1":{<br> "jp": "閉鎖弁",<br> "en-us": " Closed Valve"<br> }<br> }<br>}</pre> | Optional | | measureSpanLow<br>(meSL) | JSON String | Indication of the minimum operating value.<br><br>Provides an indication of the lowest operating value where the sensor is rated to be within its normal error band.<br><br>The value of this field shall match the value specified in the sensor's measureType field.<pre>Example 2.5.6<br><br>{<br> "measureSpanLow":"-100"<br>}</pre> | Optional | | measureSpanHigh<br>(meSH) | JSON String | Indication of the maximum operating value.<br><br>Provides an indication of the highest operating value where the sensor is rated to be within its normal error band.<br><br>The value of this field shall match the value specified in the sensor's measureType field.<pre>Example 2.5.7<br><br>{<br> "measureSpanHigh":"100"<br>}</pre> | Optional | | measureDisplayLow<br>(meDL) | JSON String | Indication of the minimum value for display purposes.<br><br>Provides an indication of the lowest value the sensor is expected to return during normal operation. This permits a message receiver to size charts and other display outputs appropriately.<br><br>The value of this field shall match the value specified in the sensor's measureType field.<pre>Example 2.5.8<br><br>{<br> "measureDisplayLow":"0"<br>}</pre> | Optional | | measureDisplayHigh<br>(meDH) | JSON String | Indication of the maximum value for display purposes.<br><br>Provides an indication of the highest value the sensor is expected to return during normal operation. This permits a message receiver to size charts and other display outputs appropriately.<br><br>The value of this field shall match the value specified in the sensor's measureType field.<pre>Example 2.5.9<br><br>{<br> "measureDisplayHigh":"50"<br>}</pre> | Optional | | measureDisplayUnit<br>(meDU) | JSON Object | Indication of the unit used for display purposes.<br><br>Provides an indication of what unit should be used for display purposes. This permits a specific directive for how a message receiver should convert from SI base units.<br><br>The value of this field shall contain one or more JSON Strings, each with a name specifying the language tag as defined in [RFC 5646](https://tools.ietf.org/html/rfc5646), and a value containing either:<br><br>a) a combination of [ISO 80000-1:2009](https://www.iso.org/standard/30669.html) special symbol (or [SI unit symbol](http://www.bipm.org/en/si/si_brochure/)), optionally including SI prefixes,<br> b) an SI prefix, or,<br>c) a custom (non-SI) value.<br><br>A name of "*" is used as a default language-region, as defined in [RFC 4647](https://tools.ietf.org/html/rfc4647).<pre>Example 2.5.10<br><br>{<br> "measureUnit": "m/s",<br> "measureDisplayUnit": {<br> "en-us":"mile/hr",<br> "&#42;":"km/hr"<br> }<br>}</pre> | Optional | | measureUpdateRate<br>(meUR) | JSON String | Indication of the maximum rate at which a sensor value will be updated.<br><br>Provides an indication of the shortest interval that a sensor value can be polled to obtain a new reading. This permits a message sender to determine the rate at which values should be generated.<br><br>The value of this field shall be a string containing a numeric value measured in seconds.<pre>Example 2.5.11<br><br>{<br> "measureUpdateRate":"0.1"<br>}</pre> | Optional | | measureTimeout<br>(meTo) | JSON String | Indication of the timeout associated with each measurement.<br><br>If the specified time duration since the valueTime has been exceeded, the corresponding value shall no longer be considered valid.<br><br>The value of this field shall be a string containing a numeric value measured in seconds.<pre>Example 2.5.12<br><br>{<br> "measureTimeout":"10"<br>}</pre> | Optional | | measureResolution<br>(meR) | JSON String | Indication of the smallest detectable change measurable by the sensor.<br><br>Provides an indication of the smallest detectable change of the value being measured that will result in a different value reading. This permits a message sender to determine significant figures.<br><br>The value of this field shall be a string containing a numeric value corresponding to the units defined for the sensor.<pre>Example 2.5.13<br><br>{<br> "measureResolution":"0.1"<br>}</pre> | Optional<br><br>Only valid for sensors of type "numeric" | | measureAccuracy<br>(meAc) | JSON String | Indication of range of possible measurement error.<br><br>Provides an indication of the largest difference (+/-) expected to exist between the measured value and the actual value. This permits a message sender to determine significant figures.<br><br>The value of this field shall be a string containing a positive numeric value corresponding to the units defined for the sensor. Accuracy shall be +/- the specified value.<pre>Example 2.5.14<br><br>{<br> "measureAccuracy":"0.1"<br>}</pre> | Optional<br><br>Only valid for sensors of type "numeric" | ## <a name="vfields"></a>2.6 Value SNON Fields Value fields carry information about measurements taken by a sensor. Each SNON Fragment may contain the following value JSON fields: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | valueTime<br>(vT) | JSON Array of JSON Strings | Indication of one or more times associated with measured values.<br><br>Provides an indication of when values were measured.<br><br>The value of this field shall contain one or more JSON Strings, with the contents of each string corresponding to the time a value was measured, in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) extended representation date/time format ("YYYY-MM-DDTHH:MM:SS.MMMZ"), or time interval format ("/PTxx.xxxS"). All value array fields shall have the same number of entries, with the order consistent across fields. <pre>Example 2.6.1<br><br>{<br> "value": ["10", "11"],<br> "valueTime": ["2014-08-20T14:32:56.125Z", "/PT0.100S"]<br>}</pre> | Optional, requires entityID | | value<br>(v) | JSON Array of JSON Strings | Indication of one or more values measured from the sensor.<br><br>Provides an indication of a measured value at a given point in time.<br><br>The value of this field shall contain one or more JSON Strings, with the contents of each string corresponding to the type of the sensor. All value array fields shall have the same number of entries, with the order consistent across fields.<br><br>If a min and max are provided, the value represents the average value over the acquisition period specified in the valueTime field. <pre>Example 2.6.2<br><br>{<br> "value": ["10"],<br> "valueTime": ["2014-08-20T14:32:56.125Z"]<br>}</pre> | Optional, requires valueTime | | valueMax<br>(vMax) | JSON Array of JSON Strings | Indication of one or more maximum values measured from the sensor.<br><br>Provides an indication of a maximum measured value during a given interval in time. Min/Max/Average values are typically used when sensor samples a value at a higher rate then is reported, and when the envelope contains important information.<br><br>The value of this field shall contain one or more JSON Strings, with the contents of each string corresponding to the type of the sensor. All value array fields shall have the same number of entries, with the order consistent across fields.<pre>Example 2.6.3<br><br>{<br> "value": ["10"],<br> "valueMax": ["12"],<br> "valueMin": ["8"],<br> "valueTime": ["2014-08-20T14:32:56.125Z"]<br>}</pre> | Optional, requires valueTime | | valueMin<br>(vMin) | JSON Array of JSON Strings | Indication of one or more minimum values measured from the sensor.<br><br>Provides an indication of a minimum measured value during a given interval in time. Min/Max/Average values are typically used when sensor samples a value at a higher rate then is reported, and when the envelope contains important information.<br><br>The value of this field shall contain one or more JSON Strings, with the contents of each string corresponding to the type of the sensor. All value array fields shall have the same number of entries, with the order consistent across fields.<pre>Example 2.6.4<br><br>{<br> "value": ["10"],<br> "valueMax": ["12"],<br> "valueMin": ["8"],<br> "valueTime": ["2014-08-20T14:32:56.125Z"]<br>}</pre> | Optional, requires valueTime | | valueTimeout<br>(vTo) | JSON Array of JSON Strings | Indication of the timeout associated with each value.<br><br>Provides an measure of how long a given value should be considered valid. If the specified time duration since the valueTime has been exceeded, the corresponding value shall no longer be considered valid.<br><br>When present, this field overrides a measureTimeout field.<br><br>The value of this field shall contain one or more JSON Strings, with the contents of each string containing a numeric value measured in seconds.<pre>Example 2.6.5<br><br>{<br> "value": ["10"],<br> "valueTime": ["2014-08-20T14:32:56.125Z"],<br> "valueTimeout": ["0.1"]<br>}</pre> | Optional, requires valueTime | ## 2.7 Value Descriptive SNON Fields Value descriptive fields provide additional information about how specific value measurements made by the sensor are displayed and organized. Each SNON Fragment may contain the following JSON field: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | valueError<br>(vE) | JSON String | Indication that errors are present.<br><br>Provides an indication of errors associated with value or set of values.<br><br>The value of this field shall contain a string describing the error. The contents of the error string is sensor-dependent. <pre>Example 2.7.1<br><br>{<br> "value": ["10"],<br> "valueTime": ["2014-08-20T14:32:56.125Z"],<br> "valueError": "Out of Calibration"<br>}</pre> | Optional, requires valueTime | ## 2.8 User-Defined SNON Fields SNON permits arbitary user-defined fields to be added to fragments, under the "extensions" object. Each SNON Fragment may contain the following JSON field: | Field&nbsp;Name<br>(Short&nbsp;Name) | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | extensions<br>(ext) | JSON Object | Contains user-defined fields extending a fragment.<br><br>These fields are inherited according to the same rules as other SNON fields.<pre>Example 2.8.1<br><br>{<br> "extensions": {<br> "modbus": {<br> "address": "7000"<br> }<br> }<br>}</pre> | Optional | ## 2.9 Entity Relationships ### 2.9.1 Device to Device Relationships The following relationships between entities of class "device" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "parent" | This relationship is used to create composite devices. Each "parent" relationship indicates that a device has a organizational relationship with another device.<br><br>Figure 5 shows how parent relationships can be used to define composite devices, where bold entities are devices:<center>![SNON Parents](images/snon_rel_parents.png)<br>Figure 5 - SNON "parent" Relationships<br><br></center> | | "timesource" | This relationship is used to indicate time distribution. Each "timesource" relationship indicates that a device acquires its time from another device.<br><br>Figure 6 shows an example of a timesource relationship:<center>![SNON Parents](images/snon_rel_ts.png)<br>Figure 6 - SNON "timesource" Relationships<br><br></center> | | "powered_by" | This relationship is used to indicate source of power. Each "powered_by" relationship indicates that a specific device has power supplied by another device.<br><br>Figure 7 shows an example of a "powered_by" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_power.png)<br>Figure 7 - SNON "powered_by" Relationships<br><br></center> | | "connected_to"| This relationship is used to indicate network connectivity. Each "connected_to" relationship indicates that a specific device has a communication connection to another device.<br><br>Figure 8 shows an example of a "connected_to" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_conn.png)<br>Figure 8 - SNON "connected_to" Relationships<br><br></center> | ### 2.9.2 Sensor to Device Relationships The following relationships between entities of class "sensor" and entities of class "device" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "parent" | This relationship is used to create composite sensors. Each "parent" relationship indicates that a sensor has a organizational relationship with another device.<br><br>Figure 9 shows how parent sensor relationships can be used to define devices, where bold entities are devices:<center>![SNON Parents](images/snon_rel_parents_s.png)<br>Figure 9 - SNON "parent" Relationships<br><br></center> | | "timesource" | This relationship is used to indicate time distribution. Each "timesource" relationship indicates that a sensor acquires its time from another device.<br><br>Figure 10 shows an example of a timesource relationship:<center>![SNON Parents](images/snon_rel_ts_s.png)<br>Figure 10 - SNON "timesource" Relationships<br><br></center> | | "powered_by" | This relationship is used to indicate source of power. Each "powered_by" relationship indicates that a specific sensor has power supplied by by another device.<br><br>Figure 11 shows an example of a "powered_by" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_power_s.png)<br>Figure 11 - SNON "powered_by" Relationships<br><br></center> | | "connected_to"| This relationship is used to indicate network connectivity. Each "connected_to" relationship indicates that a specific sensor has a communication connection to another device.<br><br>Figure 12 shows an example of a "connected_to" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_conn_s.png)<br>Figure 12 - SNON "connected_to" Relationships<br><br></center> | | "located_at" | This relationship is used to indicate absolute location. Each "located_at" relationship indicates that the specified entity is located at a specific location, as defined by a sensor.<br><br>Figure 13 shows an example of a "located_at" relationship, where bold entities are devices, bold+italic entities are locations, and non-bold entities are sensors:<center>![SNON Parents](images/snon_rel_loc_s.png)<br>Figure 13 - SNON "located_at" Relationships<br><br></center> | ### 2.9.3 Sensor to Sensor Relationships The following relationships between entities of class "sensor" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "health" | This relationship is used to indicate sensor health. Each "health" relationship indicates that the health of a specific sensor is indicated by a second sensor.<br><br>Figure 14 shows an example of a "health" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_health_s.png)<br>Figure 14 - SNON "health" Relationships<br><br></center> | | "setpoint" | This relationship is used to indicate the sensor setpoint. Each "setpoint" relationship indicates that the desired value/range of a specific sensor is indicated by a second sensor.<br><br>Figure 15 shows an example of a "setpoint" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_setpoint_s.png)<br>Figure 15 - SNON "setpoint" Relationships<br><br></center> | | "alarms" | This relationship is used to indicate the sensor alarm thresholds. Each "alarms" relationship indicates that the desired high and/or low values where an alarm should be triggered is indicated by a second sensor.<br><br>Figure 16 shows an example of a "alarms" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_alarms_s.png)<br>Figure 16 - SNON "alarms" Relationships<br><br></center> | | "alarm_inhibit" | This relationship is used to indicate if a sensor alarm should be inhibited. Each "alarm_inhibit" relationship indicates that if alarm should be inhibited is indicated by a second sensor.<br><br>Figure 17 shows an example of a "alarm_inhibit" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_inhibit_s.png)<br>Figure 17 - SNON "alarm_inhibit" Relationships<br><br></center> | | "indeterminate" | This relationship is used to indicate if a sensor value should be considered to be indeterminate, where indeterminate is defined to mean that the value is not known. Each "indeterminate" relationship indicates that the state of indeterminacy is indicated by a second sensor.<br><br>Figure 18 shows an example of a "indeterminate" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_indeterminate_s.png)<br>Figure 18 - SNON "indeterminate" Relationships<br><br></center> | | "flag" | This relationship is used to indicate flags (labels) associated with a sensor. Each "flag" relationship indicates that flags should be added when indicated by a second sensor.<br><br>Figure 19 shows an example of a "flags" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_flags_s.png)<br>Figure 19 - SNON "flags" Relationships<br><br></center> | | "derived_from" | This relationship is used to indicate when a sensor value is derived from one or more other sensor values. Each "derived_from" relationship indicates the sources of information used to derive the sensor value.<br><br>Figure 20 shows an example of a "derived_from" relationship, where bold entities are devices:<center>![SNON Parents](images/snon_rel_derived_s.png)<br>Figure 20 - SNON "derived_from" Relationships<br><br></center> | ### 2.9.4 Location to Location Relationships The following relationships to entities of class "location" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "located_in" | This relationship is used to indicate relative location. Each "located_in" relationship indicates that the specified "location" is located within another "location" entity, which has an entityClass of "location", and an entityName describing the location.<br><br>Figure 21 shows an example of a "located_in" relationship, where bold+italic entities are locations:<center>![SNON Parents](images/snon_rel_loci_l.png)<br>Figure 21 - SNON "located_in" Relationships<br><br></center> | ### 2.9.5 Device to Location Relationships The following relationships to entities of class "location" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "located_in" | This relationship is used to indicate relative location. Each "located_in" relationship indicates that the specified device is located within a "location" entity, which has a deviceID, a deviceName describing the location, and a deviceType field of "location".<br><br>Figure 22 shows an example of a "located_in" relationship, where bold entities are devices, and bold+italic entities are locations:<center>![SNON Parents](images/snon_rel_loci.png)<br>Figure 22 - SNON "located_in" Relationships<br><br></center> | ### 2.9.6 Location to Device Relationships The following relationships to entities of class "location" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "located_at" | This relationship is used to indicate absolute location. Each "located_at" relationship indicates that the specified location is located at a specific location, as defined by a device.<br><br>Figure 23 shows an example of a "located_at" relationship, where bold entities are devices, bold+italic entities are locations, and non-bold entities are sensors:<center>![SNON Parents](images/snon_rel_loc.png)<br>Figure 23 - SNON "located_at" Relationships<br><br></center> | ### 2.9.7 Sensor to Location Relationships The following relationships to entities of class "location" are defined: | Relationship&nbsp;Name | Description | | ------------- | ------------- | | "located_in" | This relationship is used to indicate relative location. Each "located_in" relationship indicates that the specified entity is located within a "location" entity, which has an entityClass of "location", and an entityName describing the location.<br><br>Figure 24 shows an example of a "located_in" relationship, where bold entities are devices, and bold+italic entities are locations:<center>![SNON Parents](images/snon_rel_loci_s.png)<br>Figure 24 - SNON "located_in" Relationships<br><br></center> | ### 2.9.8 User-Defined Relationships SNON permits arbitrary user-defined relationships to be defined. It is up to the implementer to manage the namespace of user-defined relationship names to prevent collisions. ## <a name="examples"></a>3.0 SNON Examples A single measured value from a sensor: Example 3.1 [ { "entityID": "urn:uuid:1635a44f-b770-4418-8f05-e721823e8e41", "value" : ["29.3"], "valueTime" : ["2014-08-20T14:32:46.125Z"] } ] Compact form of Example 3.1: Example 3.2 [{"eID":"urn:uuid:1635a44f-b770-4418-8f05-e721823e8e41","v":["29.3"],"vT":["2014-08-20T14:32:56.125Z"]}] Two additional values, measured at different times: Example 3.3 [ { "entityID": "urn:uuid:1635a44f-b770-4418-8f05-e721823e8e41", "value" : ["29.3", "30.3"], "valueTime" : ["2014-08-20T14:32:56.125Z", "2014-08-20T14:33:06.125Z"] } ] Two values, with the second time expressed as a duration since the first time: Example 3.4 [ { "entityID": "urn:uuid:e129c1d6-0ac9-474a-948e-813ff3dc4e31", "value" : ["29.3", "30.3"], "valueTime" : ["2014-08-20T14:32:56.125Z", "/PT10S"] } ] A single measured value from a sensor, including message ID and time: Example 3.5 [ { "messageID": "urn:uuid:d244c281-52a1-4265-952a-294f56af3a05", "messageTime": "2014-08-20T14:32:56.125Z", "message": { "entityID": "urn:uuid:319e1420-fd4e-49e9-9d43-a24b2cf98486", "value" : ["29.3"], "valueTime" : ["2014-08-20T14:32:56.125Z"] } } ] A single measured value from two sensors, sent atomically: Example 3.6 [ { "messageID": "urn:uuid:15b4615a-b736-4e55-9d19-35b2ec807439", "messageTime": "2014-08-20T14:32:56.125Z", "message": { "entityID": "urn:uuid:319e1420-fd4e-49e9-9d43-a24b2cf98486", "value" : ["29.3"], "valueTime" : ["2014-08-20T14:32:56.125Z"] } }, { "messageID": "urn:uuid:1c265c77-9baf-4b3d-ba39-6efd9f33bf41", "messageTime": "2014-08-20T14:32:56.125Z", "message": { { "entityID": "urn:uuid:322ea74e-d914-44be-a95f-bb97b60b140b", "value" : ["-102.2"], "valueTime" : ["2014-08-20T14:32:56.125Z"] } } ] A self-describing sensor with a single measured value: Example 3.7 [ { "messageID": "urn:uuid:be422ea8-289d-49fa-bd39-6a48f4711c75", "messageTime": "2014-08-20T14:32:56.125Z", "message": { "sentityID": "urn:uuid:8f5308d5-a1ca-4ad4-9a7f-3a70d4177551", "entityName": {"*":"Temperature"}, "measureType" : "numeric", "measureAcquire" : "sample", "measureUnit" : "°C", "value" : ["29.3"], "valueTime" : ["2014-08-20T14:32:56.125Z"] } } ] A value that will use the same sensor information defined in Example 3.7: Example 3.8 [ { "entityID": "urn:uuid:8f5308d5-a1ca-4ad4-9a7f-3a70d4177551", "value" : ["28.8"], "valueTime" : ["2014-08-20T14:32:57.126Z"] } ] An update to the sensor information defined in Example 3.7: Example 3.9 [ { "messageID": "urn:uuid:be422ea8-289d-49fa-bd39-6a48f4711c75", "messageTime": "2014-08-20T14:32:56.125Z", "message": { "entityID": "urn:uuid:8f5308d5-a1ca-4ad4-9a7f-3a70d4177551", "precedentID": "urn:uuid:be422ea8-289d-49fa-bd39-6a48f4711c75", "sensorName": {"*":"Outside Temperature"} } } ] A summary of a minute's worth of values from a temperature sensor: Example 3.10 [ { "messageID": "urn:uuid:75a82b1b-d617-4c06-9b27-db2abea3bb14", "messageTime": "2014-08-20T14:32:56.125Z", "message": { "entityID": "urn:uuid:461bc368-0925-484b-ad96-c03fef490ece", "entityName": {"*":"Temperature"}, "measureType" : "numeric", "measureAcquire" : "summary", "measureUnit" : "°C", "value" : ["28.0"], "valueMax" : ["29.1"], "valueMin" : ["27.5"], "valueTime" : ["2014-08-20T14:33:00.000Z/PT01M"] } } ] Composite GPS device: Example 3.11 [ { "entityID": "urn:uuid:bd34facd-636f-4218-8a81-b99576d363ff", "entityClass": "Device", "entityName": {"*":"GPS"} } [ Status of a GPS sensor: Example 3.12 [ { "entityID": "urn:uuid:3459c049-c4fc-42ca-b3f1-b22f5667cd1b", "entityClass": "sensor", "entityRelations": { "parent":["urn:uuid:bd34facd-636f-4218-8a81-b99576d363ff"] }, "entityName": {"*":"GPS Status"}, "measureType" : "enumeration", "measureAcquire" : "sample", "measureLabel" : {"0":{"*":"Unlocked"}, "1":{"*":"Locked"}}, "value" : ["1"], "valueTime" : ["2014-08-20T14:32:57.126Z"] } [ Latitude of a GPS sensor: Example 3.13 [ { "entityID": "urn:uuid:eb203e89-5d38-4d7b-a772-4188beac43b7", "entityClass": "sensor", "entityRelations": { "parent":["urn:uuid:bd34facd-636f-4218-8a81-b99576d363ff"] }, "entityName": {"*":"GPS Latitude"}, "measureType" : "enumeration", "measureAcquire" : "sample", "value" : ["34.017161"], "valueTime" : ["2014-08-20T14:32:57.126Z"] } ] Longitude of a GPS sensor: Example 3.14 [ { "entityID": "urn:uuid:c195d9fe-625b-4597-9a3a-4cbcc8f4a0c4", "entityClass": "sensor", "entityRelations": { "parent":["urn:uuid:bd34facd-636f-4218-8a81-b99576d363ff"] }, "entityName": {"*":"GPS Longitude"}, "measureType" : "enumeration", "measureAcquire" : "sample", "value" : ["-118.269397"], "valueTime" : ["2014-08-20T14:32:57.126Z"] } ] Heading sensor, linked to the GPS sensor: Example 3.15 [ { "entityID": "urn:uuid:2432dc10-877b-4506-bf85-6fe78cfb3633", "entityClass": "sensor", "entityRelations": { "location":["urn:uuid:bd34facd-636f-4218-8a81-b99576d363ff"] }, "entityName": {"*":"Heading Angle"}, "measureType" : "numeric", "measureAcquire" : "sample", "measureUnit" : "radian", "value" : ["48.4"], "valueTime" : ["2014-08-20T14:32:57.126Z"] } ] ## <a name="schema"></a>4.0 SNON Schema SNON messages and fragments can be validated using the below [JSON schema](http://json-schema.org): { "$schema": "http://json-schema.org/draft-04/schema#", "id": "http://snon.org/v2/snon-schema.json#", "definitions": { "message": { "type": "object", "properties": { "messageID": { "$ref": "#/definitions/type_id" }, "mID": { "$ref": "#/definitions/type_id" }, "messageTime": { "$ref": "#/definitions/type_iso8601_time" }, "mT": { "$ref": "#/definitions/type_iso8601_time" }, "message": { "$ref": "#/definitions/fragment_long" }, "m": { "$ref": "#/definitions/fragment_short" } }, "dependencies": { "messageID": {"required": ["messageTime", "message"], "not":{"anyOf":[ {"required":["mID"]}, {"required":["mT"]}, {"required":["m"]} ]}}, "mID": {"required": ["mT", "m"], "not":{"anyOf":[ {"required":["messageID"]}, {"required":["messageTime"]}, {"required":["message"]} ]}}, "messageTime": ["messageID", "message"], "mT": ["mID", "m"], "message": ["messageID", "messageTime"], "m": ["mID", "mT"] }, "additionalProperties": false }, "fragment_long": { "type": "object", "properties": { "entityID": { "$ref": "#/definitions/type_id" }, "entityClass": { "type": "string" }, "entityName": { "$ref": "#/definitions/type_intl_name" }, "entityType": { "$ref": "#/definitions/type_intl_name" }, "entityRelations": { "$ref": "#/definitions/type_relations" }, "precedentID": { "$ref": "#/definitions/type_id" }, "measureUnit": { "type": "string" }, "measureType": { "type": "string" }, "measureAcquire": { "type": "string" }, "measureUnitPrefix": { "$ref": "#/definitions/type_intl_name" }, "measureUnitSuffix": { "$ref": "#/definitions/type_intl_name" }, "measureUnitPrefixEx": { "$ref": "#/definitions/type_intl_name" }, "measureUnitSuffixEx": { "$ref": "#/definitions/type_intl_name" }, "measureLabel": { "$ref": "#/definitions/type_intl_enum" }, "measureSpanLow": { "$ref": "#/definitions/type_numeric_string" }, "measureSpanHigh": { "$ref": "#/definitions/type_numeric_string" }, "measureDisplayLow": { "$ref": "#/definitions/type_numeric_string" }, "measureDisplayHigh": { "$ref": "#/definitions/type_numeric_string" }, "measureDisplayUnit": { "$ref": "#/definitions/type_intl_name" }, "measureUpdateRate": { "$ref": "#/definitions/type_numeric_string" }, "measureTimeout": { "$ref": "#/definitions/type_numeric_string" }, "measureResolution": { "$ref": "#/definitions/type_numeric_string" }, "measureAccuracy": { "$ref": "#/definitions/type_numeric_string" }, "valueTime": { "$ref": "#/definitions/type_ISO8601_timeduration_array" }, "value": { "$ref": "#/definitions/type_string_array" }, "valueMax": { "$ref": "#/definitions/type_string_array" }, "valueMin": { "$ref": "#/definitions/type_string_array" }, "valueTimeout": { "$ref": "#/definitions/type_numeric_string" }, "valueError": { "type": "string" }, "extensions": { "type": "object" } }, "dependencies": { "entityName": ["entityID"], "entityClass": ["entityID"], "entityRelations": ["entityID"], "valueTime": ["entityID"], "value": ["valueTime"], "valueMax": ["valueTime"], "valueMin": ["valueTime"], "valueTimeout": ["valueTime"], "valueError": ["valueTime"] }, "additionalProperties": false }, "fragment_short": { "type": "object", "properties": { "eID": { "$ref": "#/definitions/type_id" }, "eC": { "type": "string" }, "eN": { "$ref": "#/definitions/type_intl_name" }, "eT": { "$ref": "#/definitions/type_intl_name" }, "eR": { "$ref": "#/definitions/type_relations" }, "pID": { "$ref": "#/definitions/type_id" }, "meU": { "type": "string" }, "meT": { "type": "string" }, "meAq": { "type": "string" }, "meUP": { "$ref": "#/definitions/type_intl_name" }, "meUS": { "$ref": "#/definitions/type_intl_name" }, "meUPx": { "$ref": "#/definitions/type_intl_name" }, "meUSx": { "$ref": "#/definitions/type_intl_name" }, "meL": { "$ref": "#/definitions/type_intl_enum" }, "meSL": { "$ref": "#/definitions/type_numeric_string" }, "meSH": { "$ref": "#/definitions/type_numeric_string" }, "meDL": { "$ref": "#/definitions/type_numeric_string" }, "meDH": { "$ref": "#/definitions/type_numeric_string" }, "meDU": { "$ref": "#/definitions/type_intl_name" }, "meUR": { "$ref": "#/definitions/type_numeric_string" }, "meTo": { "$ref": "#/definitions/type_numeric_string" }, "meR": { "$ref": "#/definitions/type_numeric_string" }, "meAc": { "$ref": "#/definitions/type_numeric_string" }, "vT": { "$ref": "#/definitions/type_ISO8601_timeduration_array" }, "v": { "$ref": "#/definitions/type_string_array" }, "vMax": { "$ref": "#/definitions/type_string_array" }, "vMin": { "$ref": "#/definitions/type_string_array" }, "vTo": { "$ref": "#/definitions/type_numeric_string" }, "vE": { "type": "string" }, "ext": { "type": "object" } }, "dependencies": { "eN": ["eID"], "eC": ["eID"], "eR": ["eID"], "vT": ["eID"], "v": ["vT"], "vMax": ["vT"], "vMin": ["vT"], "vTo": ["vT"], "vE": ["vT"] }, "additionalProperties": false }, "type_id": { "type": "string" }, "type_intl_name": { "type": "object", "minProperties": 1, "additionalProperties": { "type": "string" } }, "type_intl_enum": { "type": "object", "minProperties": 1, "patternProperties": { "^.*": { "$ref": "#/definitions/type_intl_name" } }, "additionalProperties": false }, "type_iso8601_time": { "type": "string", "pattern": "^[1-9][0-9]{3}-(0[1-9]|1[0-2])-([0][1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])([.,][0-9]{3})Z(/PT(([01][0-9]|2[0-3])H)?(([0-5][0-9])M)?(([0-9]*)([.,][0-9]{3})?S)?)?$" }, "type_iso8601_duration": { "type": "string", "pattern": "^/PT(([01][0-9]|2[0-3])H)?(([0-5][0-9])M)?(([0-9]*)([.,][0-9]{3})?S)?$" }, "type_ISO8601_time_array": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/type_iso8601_time" } }, "type_ISO8601_duration_array": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/type_iso8601_duration" } }, "type_ISO8601_timeduration_array": { "type": "array", "minItems": 1, "items": { "anyOf": [ { "$ref": "#/definitions/type_iso8601_time" }, { "$ref": "#/definitions/type_iso8601_duration" } ] } }, "type_numeric_string": { "type": "string", "pattern": "^[-+]?[0-9]*\\.?[0-9]+$" }, "type_string_array": { "type": "array", "minItems": 1, "items": { "type": "string" } }, "type_relations": { "type": "object", "minProperties": 1, "patternProperties": { "^.*": { "type": "array", "minItems": 1, "items": { "type": "string" } } }, "additionalProperties": false }, "jose_encrypted": { "type": "object", "required": ["protected", "ciphertext"], "properties": { "protected": { "type": "string" }, "iv": { "type": "string" }, "ciphertext": { "type": "string" }, "encrypted_key":{ "type": "string" }, "tag": { "type": "string" } }, "additionalProperties": false }, "jose_signed": { "type": "object", "required": ["payload", "protected", "signature"], "properties": { "header": { "type": "object", "properties": { "kid": { "type": "string" } }, "additionalProperties": false }, "payload": { "type": "string" }, "protected": { "type": "string" }, "signature": { "type": "string" } }, "additionalProperties": false } }, "type": "array", "minItems": 1, "items": { "anyOf": [ { "$ref": "#/definitions/message" }, { "$ref": "#/definitions/fragment_long" }, { "$ref": "#/definitions/fragment_short" }, { "$ref": "#/definitions/jose_encrypted" }, { "$ref": "#/definitions/jose_signed" } ] } } The following constraints are not validated by this schema, and shall be validated by the SNON receiver: * Resolvability of precedentID * Equal number of array items in valueTime, value, valueMax, valueMin and valueTimeout * First item in valueTime shall be an ISO 8601 time (subsequent items may be an ISO 8601 duration) * If there is a valueTime, at least one of value, valueMax or valueMin shall be present * Contents of value, valueMax and valueMin shall correspond to resolved measureType * Validity of SNON fragments or messages contained within a JWS "payload" or JWE "ciphertext" field ## <a name="security"></a>5.0 SNON Security Sensor data often must be encrypted to protect confidentiality, and signed to protect integrity and demonstrate the authenticity of the source of the data. SNON specifies the use of JSON Object Signing and Encryption (JOSE) as described in [RFC 7516](https://tools.ietf.org/html/rfc7516) and [RFC 7515](https://tools.ietf.org/html/rfc7515), although other encryption and signing standards may also be used. An SNON collection shall be used as the plaintext, and JWE or JWS JSON Serialization shall be used for the encrypted or signed representation, as shown in the below example: Original SNON collection: Example 5.1 [{"entityID":"urn:uuid:fa164ee2-f1b7-43ee-8202-e61bc005db2b","value":["1"],"valueTime":["2017-11-29T03:32:03.752Z"]},{"entityID":"urn:uuid:c4c0b0b6-f1c5-4695-9370-d925f8370c07","value":["0"],"valueTime":["2017-11-29T03:32:03.752Z"]},{"entityID":"urn:uuid:d90526a1-4e62-493e-870c-6216216a03c8","value":["0"],"valueTime":["2017-11-29T03:32:03.752Z"]},{"entityID":"urn:uuid:12b976ea-4867-42b1-bcc6-f6b1d5e938e7","value":["0"],"valueTime":["2017-11-29T03:32:03.752Z"]}] JWE representation when encrypted using RSA v1.5, according to [RFC 7520](https://tools.ietf.org/html/rfc7520#section-5.1): Example 5.2 [{"tag":"5DlAaLHKrg5JBCh604TtfQ","protected":"eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4R0NNIn0","iv":"QIuWxaOOwgIfw6oo","ciphertext":"fwk4KeCiC6rItJ_TD5kn7ymRn7eX-Ckqi0k3N18sEsksF39f2KBezt609IeZQuIqxFBheeLWucwuWa-tpYiWv-zDVUkQ-AhDNwdzo1tPevLOiUytU2NkCjK0uX6yazdaBHxVXFUbwa1HDQ_9-8H_wbpF1pPMrs5kBXt2cHUBdjpTopSfn0Q_rD8iHgz0s7eyMjWjSGqM5Fhg7T79qMwvRtqlyWIuqHVR40U2Gmhk4gy9VOXomq_P7qHeYB507zlAAxggsbYSJvwq6biluilqW5lPbDCR9MSsWjYFggSPr_aGDw6VN-_kXjkVvnBqRkq1B2AU6aKwD47CuBYSCBJDqcHMhKdwQmJ_M4xyg4k0EYl2iwEd7UDKkylzlxi0kfQ4sClW6DHyc_tiymT1ntPkL0l5cerK47kr8CarmJyRCWlQk_kasXr9AXsB9w6mu7obXzdX80FBQJmjzgXYhPC_mcVj6gKQNIyXoFIhlr7ZIEKnYRAwddvtk04Y5amCgBw0sDpS1j-GDimGmZ3iVCV4wsLeih0Ybv5oEqbgE3HiOteLl-8Q4fqP034rTtgNfT0ZxkmnybZyres1C3hwrmfmu-Z1srZ5HsIQuOqovhFE_68i","encrypted_key":"fCeHnQCXO5KqBeYaoqoJ6iFuVTHRcvhh6p7k5LrS6iA3f9XhExjLybggze8v_QpJzLoVXbD31aT1uUTiAyQ93GzsswbMR1X7jWeZnehX8cUbccjkhW2udoXYHe1Du-QibCBgc2K-Psp2Mt17Wg1rqmgGkJ5R36V_uOyBKthY_8AbXabzhgGN9H-A8WwfD6-iB69WjeLrHlmE0psn6jF07cPNzFV2j8rgaED6ejULCE54y3qh6f-9AAMdNH1G2GyjYBhbEg2rSJC80-q95prpnscjUKrNspdV8QzTlg1_AVBEqOqLvEAwWschDMgIFU-Y1HWWSm1JeftxpHfERCySXQ"}] JWS representation when signed using RSA v1.5, according to [RFC 7520](https://tools.ietf.org/html/rfc7520#section-4.1): Example 5.3 [{"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"EyRkR84B0GJiOtVETZI6tj2biUJzACY2MBcggz3NWu8uCm5FWYfndwJw0pI7ouGaAhpgre3YmK1XoFZhWDFlrPBAx5vKaAsiqIGPvaNX3PTjnw4auEaETSraW5bT1Zg9ZOCGg3o6jwWVVjQecGevZulqfCiEe3bKV48cRHu4WOQG_PoqYdHC4Jw1ugOgpiqCqzaRi34Fek2h3lisufD5dFBJG36UZStYfpSNComfbdhNxe-zQhl42hyE_SG_qUIIHVFmKCOiSLJMPM3TWXKKFWL-B3jNC1Gx79c0mPgfncuXZUCgK8YhD7qOlyR-HXtwdzJ2z7lja186uzdoTnoV9w","header":{"kid":"urn:uuid:bd8dd740-ccd9-4e80-aae9-f1c9ebea754f"},"payload":"W3siZW50aXR5SUQiOiJ1cm46dXVpZDpmYTE2NGVlMi1mMWI3LTQzZWUtODIwMi1lNjFiYzAwNWRiMmIiLCJ2YWx1ZSI6WyIxIl0sInZhbHVlVGltZSI6WyIyMDE3LTExLTI5VDAzOjMyOjAzLjc1MloiXX0seyJlbnRpdHlJRCI6InVybjp1dWlkOmM0YzBiMGI2LWYxYzUtNDY5NS05MzcwLWQ5MjVmODM3MGMwNyIsInZhbHVlIjpbIjAiXSwidmFsdWVUaW1lIjpbIjIwMTctMTEtMjlUMDM6MzI6MDMuNzUyWiJdfSx7ImVudGl0eUlEIjoidXJuOnV1aWQ6ZDkwNTI2YTEtNGU2Mi00OTNlLTg3MGMtNjIxNjIxNmEwM2M4IiwidmFsdWUiOlsiMCJdLCJ2YWx1ZVRpbWUiOlsiMjAxNy0xMS0yOVQwMzozMjowMy43NTJaIl19LHsiZW50aXR5SUQiOiJ1cm46dXVpZDoxMmI5NzZlYS00ODY3LTQyYjEtYmNjNi1mNmIxZDVlOTM4ZTciLCJ2YWx1ZSI6WyIwIl0sInZhbHVlVGltZSI6WyIyMDE3LTExLTI5VDAzOjMyOjAzLjc1MloiXX1d"}] Nesting of signatures and encryption is defined in section 6 of [RFC 7520](https://tools.ietf.org/html/rfc7520#section-6). When traversing relationships or resolving precedents, it is important to verify the signature of each message in the chain. Since Sensor IDs are typically used as MQTT topic names, it is strongly recommended that these be opaque (or hashes) to ensure that information is not leaked. This is why the use of hierarchical MQTT topic names are not recommended, as this will leak information about relationships between sensors. ## <a name="encapsulation"></a>6.0 SNON Encapsulation The Cloud Native Computing Foundation (CNCF) [CloudEvents standard](https://github.com/cloudevents/spec/blob/v0.3/spec.md) provides a standard way to connect systems where the change of state in one system causes code to execute in another system. When used to encapsulate an SNON fragment, CloudEvents fields are used in place of the fields in a SNON message. | Field&nbsp;Name | Data Type | Description | Mandatory | | ------------- | ------------- | ------------- | --------- | | specversion | JSON String | The version of the CloudEvents specification which the event uses. This enables the interpretation of the context. Compliant event producers shall use the value "0.3". | Mandatory | | type | JSON String | Type of occurrence which has happened.<br><br>Shall be set to the value "org.snon.v2". | Mandatory | | schemaurl | JSON Objects | A link to the schema that the data attribute adheres to.<br><br>Shall be set to the value "http://www.snon.org/v2/snon-schema.json". | Optional | | id | JSON String | Identifies the event.<br><br>Shall be set to the messageID. | Mandatory | | source | JSON String | Identifies the context in which an event happened.<br><br>Shall be set to the ID of the entity that is sending the event. | Mandatory | | subject | JSON String | This describes the subject of the event in the context of the event producer (identified by source).<br><br>If used, shall be set to entityID specified in the encapsulated SNON fragment. | Optional | | time | JSON String | Timestamp of when the event happened.<br><br>Shall be set to the messageTime. | Mandatory (1) | | data | JSON Object | The event payload.<br><br>Shall be set to the message (SNON Fragment). | Mandatory | (1) While the time field is optional in CloudEvents, it is mandatory when being used to encapsulate SNON fragments. An example of an SNON fragment encapsulated in a CloudEvent is shown below in Example 6.1: Example 6.1 - CloudEvents encapsulation { "specversion": "0.3", "type": "org.snon.v2", "schemaurl": "http://www.snon.org/v2/snon-schema.json", "source": "urn:uuid:407ec909-2519-4a2a-980b-ee75a47020ad", "id": "urn:uuid:f4dfec0c-259b-4f1b-9eba-9070a4d64b7b", "time": "2014-08-20T14:34:56.125Z", "data" : { "entityID": "urn:uuid:1635a44f-b770-4418-8f05-e721823e8e41", "value" : ["29.3"], "valueTime" : ["2014-08-20T14:32:46.125Z"] } } ## 7.0 SNON License Clear BSD License Copyright (c) – 2019, NetApp, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of NetApp, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## 8.0 SNON Changelog SNON 2.1 2019-08-15 * Added encapsulation guidance for CNCF [CloudEvents](https://github.com/cloudevents/spec/blob/v0.3/primer.md) * Added Entity Tag for ISA-5.1 naming conventions [SNON 2.0 2017-11-28](v2/index.html) * Added JSON schema * Specified where user-defined fields are allowed * Relaxation of field restrictions to improve linked messages * SNON Messages now can contain multiple SNON Fragments * sensorHierarchy deprecated. Replaced by deviceID and sensorRelations/deviceRelations * valueUncertainty, valueSequence, valueSession and valueHealth deprecated * location field deprecated, replace with sensorRelations/deviceRelations * Relations added for thresholds, setpoints, alarms, inhibit, indeterminate and flags * Added Sensor Catalog use cases * Internationalization support [SNON 0.3 2015-08-04](v1/index.html) * Added additional detail on how to use SNON with MQTT * Retired messageHash and messageSignature in favor of [JOSE](https://tools.ietf.org/html/rfc7520) * Addition of field short names for low-resource platforms * Additional examples added SNON 0.2 2015-07-05 * Addition of valueTimeout and valueSequence fields * Clarification of measureUnit and measureLabel fields SNON 0.1 2014-09-24 Please report errors, suggestions, etc, at https://github.com/dslik/snon-spec