Skip to content

Proposal: Manageable actions and data mapping using semantic annotations #2166

@benfrancis

Description

@benfrancis

Before we take the first step on the slippery slope of turning Thing Descriptions into a turing complete programming language by adding "variables" as a top level member of Thing Descriptions, I wanted to re-visit an old idea of using semantic annotations to describe dynamic resources in a declarative way.

What if we created a semantic context that defined some special terms that can be used in data schemas (including URI variables) to explain their semantic meaning in the context of the WoT information model?

Specifically, I'm thinking about terms such as:

  • wot:propertyName
  • wot:propertyValue
  • wot:actionName
  • wot:actionInput
  • wot:actionOutput
  • wot:actionStatus
  • wot:actionID
  • wot:eventName
  • wot:eventData

To make this work I would also suggest adding a status member to ActionAffordance as per @relu91's suggestion in #2068.

These special semantic annotations could be used to specify particular URI variables and specific members of data payloads as action IDs, and also point to which part of an action status is its output.

In more complicated bindings with data wrappers in their payloads they may also be used to point out which part of a payload is the actual value of a property or data from an event, and potentially also details like how to enumerate property names in a readmultipleproperties request.

Below I have provided an example which attempts to solve the long term problem of how to describe the HTTP Basic Profile protocol bindings (particularly the action protocol bindings) declaratively in a Thing Description!

{
  "@context": [
    "https://www.w3.org/ns/wot-next/td",
    "wot": "https://www.w3.org/ns/wot-next/"
  ],
  "id": "https://mywebthingserver.com/things/lamp",
  "base": "https://mywebthingserver.com/things/lamp/",
  "title": "My Lamp",
  "description": "A web connected lamp",
  "securityDefinitions": {
    "oauth2": {
      "scheme": "oauth2",
      "flow": "code",
      "authorization": "https://mywebthingserver.com/oauth/authorize",
      "token": "https://mywebthingserver.com/oauth/token"
    }
  },
  "schemaDefinitions": {
    "error": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "format": "uri"
        },
        "title": {
          "type": "string"
        },
        "status": {
          "type": "number"
        },
        "detail": {
          "type": "string"
        },
        "instance": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "actionStatus": { 
      "@type": "wot:actionStatus",
	  "type": "object",
	  "properties": {
	    "state": {
	      "type": "string",
		  "emum": ["pending", "running", "completed", "failed"]
		},
		"output": {
		  "@type": "wot:actionOutput"
		},
		"error": {
		  "$ref": "#/schemaDefinitions/error"
		},
		"href": {
		  "@type": "wot:actionID",
                  "type": "string"
		},
		"timeRequested": {
		  "type": "string",
		  "format": "date-time"
		},
		"timeEnded": {
		  "type": "string",
		  "format": "date-time"
		}
	  }
	},
	"actionStatuses": {
	  "type": "object",
	  "propertyNames": {
	    "type": "string",
	    "@type": "wot:actionName"
	  },
	  "additionalProperties": {
	    "type": "array",
	    "items": {
	      "$ref": "#/schemaDefinitions/actionStatus"
	    }
	  }
	}
  },
  "security": "oauth2",
  "properties": {
    "on": {
      "type": "boolean",
      "title": "On/Off",
      "description": "Whether the lamp is turned on",
      "forms": [{"href": "properties/on"}]
    },
    "level" : {
      "type": "integer",
      "title": "Brightness",
      "description": "The level of light from 0-100",
      "unit": "percent",
      "minimum" : 0,
      "maximum" : 100,
      "forms": [{"href": "properties/level"}]
    }
  },
  "actions": {
    "fade": {
      "title": "Fade",
      "description": "Fade the lamp to a given level",
      "synchronous": false,
      "input": {
        "type": "object",
        "properties": {
          "level": {
            "title": "Brightness",
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "unit": "percent"
          },
          "duration": {
            "title": "Duration",
            "type": "integer",
            "minimum": 0,
            "unit": "milliseconds"
          }
        }
      },
      "status": {
        "schema": "actionStatus"
      },
      "uriVariables": {
        "actionID": {
          "type": "string",
          "@type": "wot:actionID"
        }
      },
      "forms": [
        {
          "href": "actions/fade",
          "op": "invokeaction"
        },
        {
          "href": "{actionID}",
          "op": "queryaction"
        },
        {
          "href": "{actionID}",
          "op": "cancelaction"
        }
      ],
    }
  },
  "forms": [
    {
      "op": ["readallproperties", "writemultipleproperties"],
      "href": "properties"
    },
    {
      "op": "queryallactions",
      "href": "actions",
      "additionalResponses": [{
        "success": "true",
        "schema": "actionStatuses"
      }]
    }
  ]
}

This example makes use of JSON pointers (I hope I got that part right!) assumes that a queryaction request and an invokeaction request for an asynchronous action would get a response according to the status data schema. It also uses additionalResponses to define a data schema for the queryallactions operation which is a bit of a hack, but I'm hoping we might come up with something cleaner than that for TD 2.0. It also assumes default HTTP verbs for queryaction (GET), cancelaction (DELETE) and queryallactions (GET).

Please let me know what you think.

P.S. If we were very brave we might even consider defining the data schemas from schemaDefinitions as default data schemas for the queryaction and queryallactions operations in the HTTP Binding for if a TD doesn't specify something itself. That would make TDs using future HTTP-based Profiles much cleaner!

Metadata

Metadata

Assignees

No one assigned

    Labels

    data mappingworkitem: discussions on data mapping conceptsmanageable affordancesdiscussions on representing long running affordances that need to be managed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions