Closed draggett closed 4 years ago
Hi all, I am student working under the supervision of Matthias, and I am looking into the possibility of using WoT in the Building Automation domain. I have been analysing the question of type system in Thing Description (from domain specific perspective). The following text are summary of notes which I have put together. Being relatively new to this topic, I might have misunderstood lot of stuff - my apologies if something is kind of naive :)
I looked up potential problems in modeling complex types known in protocol specifications like BACnet, KNX, and LonWorks. BACnet uses ASN.1 encoded PDU types, so all type mapping issues encountered with BACnet are also equally valid for protocols like IEC61850 which are based ASN.1 encoded data units. But before we go on to issues with complex types, there are some primitive types which are troublesome:
1.a. Bit-String and Octet strings: Bit-strings are used for compact representation of states. The closest map to a json primitive is number. This however will have to be accompanied by a metadata explaining the bit positions. Example:
BACnetStatusFlags ::= BIT STRING { in-alarm (0), fault (1), overridden (2), out-of-service (3) }
schema equivalent would be: "StatusFlags":{ "type": "object", "properties":{ "statusValue":{"type":"integer", "minimum":0, "maximum":15} }, "required":["statusValue"] }
-> Here representing the data-type in RDF seems more convenient.
Compared to bit-string, the octet-string requires definite out-of-band explanation of the parts. Hence, for such uses (as in case of Date, shown below), the gateway can choose to denote it using an "Interpreted" type:
Date ::= [APPLICATION 10] OCTET STRING (SIZE(4)) -- see 20.2.12
-- first octet year minus 1900 X'FF' = unspecified -- second octet month (1.. 14) 1 = January -- 13 = odd months -- 14 = even months -- X'FF' = unspecified -- third octet day of month (1..34), 32 = last day of month -- 33 = odd days of month -- 34 = even days of month -- X'FF' = unspecified -- fourth octet day of week (1..7) 1 = Monday -- 7 = Sunday -- X'FF' = unspecified
json schema: "Date":{ "title": "BACnet Date", "id": "#Date", "type": "object", "properties":{ "year":{ "type": "integer" }, "month":{ "type": "integer", "minimum": 0, "maximum": 14 }, "day":{ "type": "integer", "minimum": 0, "maximum": 34 }, "dayOfWeek":{ "type": "integer", "minimum": 0, "maximum": 7 } }, "required": ["year", "month", "day"] }
-> Though I have not prepared an example solution, I feel such types can be relatively easily described using RDF.
1.b. Format interpretation of strings: Some systems provide additional "format" interpretation of string values - for example "ip_address", "email", or "password". Swagger, a REST API specification, allows such additional annotation.
1.c. Enumeration: enumerated type specification in json-schema is rather simple. Many protocol specifications using key-value pair to represent each enumeration. As simple example in BACnet:
BACnetBinaryPV ::= ENUMERATED { inactive (0), active (1) }
An equivalent, but insufficient, would be:
"BinaryPV":{
"type": "object",
"properties":{
"statusValue":{"type":"integer", "minimum":0, "maximum":1},
"statusText":{"enum":["inactive","active"]}
},
"required":["statusValue"]
}
-> Once again describing enumerations in RDF is easier.
1.d. Ordering, uniqueness of collections: There is no way to express that a collection is a Set, Sequence, or Bag
1.e. Limited numeric types: json-schema is rather limited with "number" and "integer". Can be crucial if servients needs to reserve space based on types.
1.f. Response as file: It is not uncommon for some devices to return data in form of a file stream (example: cameras, device backup data etc.). Here the request is a json object whereas the response is a file. Swagger has an extension on json-schema to indicate this.
2. Type inheritance: None of the commonly used automation protocols use complex types in conjunction with elaborate inheritance mechanisms. The closest they come to is structural typing - i.e. an instance would be considered to be an acceptable (validated) type if it possesses the fields (of appropriate type). Hence a complex type at most chooses to include fields of another type. This fits perfectly with the construct "allOf" in json-schema. One exception which I encountered was in oBIX: oBiX allows for flattening and "mixin" of types - this is indeed very unique, and cannot be modeled using json-ld. Having said that, oBix is not used on automation level.
3. json-hyperschema: Perhaps the thing interaction can just have links as per json-hyperschema. This will not only point to the right type information, but also take care of specifying the interactions with the resource. (Example, as in my previous email: "properties": [ { "@type": "BACnet:BinaryOutput", "name": "Lamp Output", "links": "[{ "method": "PUT", "href": "lamp/output", "rel": "update", "mediaType": "application/json", "schema": {"$ref": "BACnet#BinaryPriorityCommand"} }",{ "method": "GET", "href": "lamp/output", "rel": "status", "mediaType": "application/json", "targetSchema": {"$ref": "BACnet#BinaryStatus"} }"], }, { "@type": "BACnet:File", "name": "Lamp image", "links": "[{ "method": "GET", "href": "lamp/img", "rel": "image", "mediaType": "image/gif", }"] } ]
4. Property referring to another resource: Sometimes properties are nothing but references to another thing. (in oBIX, this is called "ref", and in BACnet the StructuredView object uses this). In my opinion such properties can be remodelled as links.
5. Stream types: This is rather strange use case, perhaps easy to explain with an example. A security video camera has property called "lastIntrusionRecording" which provides the client an endpoint to connect and get a video stream. The property type can be modeled as an URI representing the endpoint. But what would be missing is the knowledge that it is a video stream. Hence in this case too this should be moved to links.
-> Here representing the data-type in RDF seems more convenient.
Could you give us more details about these RDF data types? You presented two definitions for all your examples: one from BACnet, the other in JSON Schema. Using RDF corresponds to a third definition, right?
Sorry forgot to paste the link to bacnet ontology: http://bacowl.sourceforge.net/2012/bacnet.ttl
BACnet WS (called BACnet XD in the annex) also goes in this direction using the concept of "named values".
The bit-string type represented in OWL is: BACnet:StatusFlags rdf:type owl:Class ; rdfs:subClassOf BACnet:BitString ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty skos:member ; owl:someValuesFrom [ rdf:type owl:Class ; owl:oneOf (StatusFlags:inAlarm StatusFlags:fault StatusFlags:overridden StatusFlags:outOfService ) ] ] .
StatusFlags:inAlarm rdf:type BACnet:Bit , owl:NamedIndividual ; Bit:nominal 0 ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty Bit:memberOf ; owl:someValuesFrom BACnet:StatusFlags ] . StatusFlags:fault rdf:type BACnet:Bit , owl:NamedIndividual ; Bit:nominal 1 ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty Bit:memberOf ; owl:someValuesFrom BACnet:StatusFlags ] . StatusFlags:overridden rdf:type BACnet:Bit , owl:NamedIndividual ; Bit:nominal 2 ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty Bit:memberOf ; owl:someValuesFrom BACnet:StatusFlags ] . StatusFlags:outOfService rdf:type BACnet:Bit , owl:NamedIndividual ; Bit:nominal 3 ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty Bit:memberOf ; owl:someValuesFrom BACnet:StatusFlags ] .
Discussion related to BACNet should continue at https://github.com/w3c/wot-binding-templates/issues/101
This issue concerns the type system for web of things applications, and is distinct from what takes place at the abstract messaging layer and specific protocol bindings. In addition, this particular issue avoids discussing the choice of representation for thing descriptions.
Based upon the rich experience with event driven programming, the starting point is software objects that are exposed to applications, and which stand for a physical or abstract entity. These objects are the "things" in the web of things and have a URI as part of the W3C Resource Description Framework.
Things can have properties, actions and events:
Properties Things may have zero or more properties. Each property has a distinct name and a value.
Actions These correspond to asynchronous methods. Applications can invoke named actions passing a value. Actions are associated with a sequence of zero or more responses which may carry a value. In principle, actions and responses could carry multiple values. Programming languages support positional arguments and named arguments. However, given the ability to provide compound values with named fields, this extra complexity may not be justified. The way in which responses are passed to applications could vary. One approach involves passing a call back to the action when invoking it. Another involves the action synchronously returning a "Promise" upon which the application can declare handlers.
Events Objects can raise events to notify applications when something has happened, for example, an indicator light has failed. Events have a name and a value. Applications can register call backs for events with the same name. In principle, this could be extended to allow applications can register for a named collection of event names. One way to do that is with compound names and wild cards.
Values Each value has a type. The core types include:
null: this denotes the absence of a value boolean: either true or false number: including integers and floating point string: a sequence of UTF-8 characters
The following are anonymous compound types which can be nested to arbitrary depths:
object: a set of name/value pairs, possibly empty array: a sequence of values, possibly empty
In addition, I propose to have things and streams as first class types, i.e. you can assign them to properties, pass them through events, when invoking actions or in responses to actions. Things are as defined above. Streams are an interface to a time sequence of values.
At the minimum, this interface should provide the means to iterate through the sequence. Streams may further provide metadata, e.g. the interval between streamed values or the timestamp for a value when available. Streams are often associated with a buffer, so that you can look back at past values. Streams may provide a means to query the buffer size, and to access a value at a particular time, or to obtain an iterator for a given window of time.
The type system needs to support both early and late binding, where the type is only partially known in advance and has to be fully determined at run time. This is analogous to unions in C++ where a tag value is used to determine which of the variant types applies. It would be useful to be able to declare a value as being on a given class or set of types. For late bound things, the platform will need to dereference the thing's description to construct the corresponding object.
Things may be associated with constraints. This can include constraints on single values, e.g. min and max values for a number, whether the number is a integer, the precision of a floating point number and so forth. String values could be constrained to be members of a given set.
Richer integrity constraints can be modelled as an expression over values that should evaluate to true. Such expressions should be side effect free. It is generally the case, that such expressions can include a range of predefined operators, e.g. boolean operators, numerical comparisons, string operators and so forth. A predefined set of named functions may be provided, e.g. to return the number of items in an array.
Integrity constraints can be used to restrict values and may apply across properties, actions and events. Integrity constraints may be seen as analogous to the use of "assert" statements in programming languages where the developer wants to know when something is wrong, and to avoid the programming continuing when that happens. For the web of things, integrity constraints can be used to increase resilience in the presence of faults and bad data.
Things also have metadata and semantic descriptions that state semantic constraints on given kinds of things. This is beyond the scope of this particular issue.