2019年10月21日，作者在“W3C万维物联网标准简介”一文中简单介绍了W3C Web of Things（WoT）工作组制定的WoT标准以及它们的最新状态：规范当前状态WoT ArchitectureCRWoT Thing DescriptionCRWoT Scripting APIWD，Working DraftWoT Binding TemplatesWorking Group NoteWoT Security and Privacy ConsiderationsWorking Group Note本系列将从WoT标准本身出发，对目前已经进入CR阶段（W3C标准的阶段参见下图）的WoT Architecture（WoT架构）、WoT Thing Description（WoT物描述）以及处于WD阶段的WoT Scripting API（WoT编程API）进行一次快速解析。如下图所示，标准进入CR阶段意味着内容已经相对稳定，WD阶段则意味着较大的不确定性，而Working Group Note（工作组备忘）则变数很大。因此处于CR阶段的“架构”和“物描述”是值得花时间了解的（成为正式推荐标准REC的可能性很大），而处于WD阶段的编程API在2019年10月28日做了一次大的内容改版，几乎完全废弃了上一版的内容，只能说接近稳定状态，但编程API始终是开发者所喜闻乐见的，所以本系列也会介绍。W3C Process Document，https://www.w3.org/2019/Process-20190301/#recs-and-notes1. 编程API简介WoT Scripting API描述如何通过脚本暴露和消费物体，同时定义了通用的物发现API。基于WoT架构定义的“消费体”（consumed thing）和“暴露体”（consumed thing），这个规范提供了不同层次的交互操作能力。首先，客户端通过消费TD（Thing Description）可以创建一个本地运行时资源模型，即消费体。消费体支持访问远程设备上的服务端物体暴露的属性、动作和事件。其次，服务端负责暴露物体，为此需要：定义TD初始化一个实现该TD所定义WoT接口的软件栈，以服务于对暴露属性、动作和事件的请求最终发布TD（比如发布到一个物体目录，以便消费者发现）2. 支持的场景编程API支持以下脚本使用场景。2.1 消费物消费物体的TD，如基于暴露WoT交互的TD创建一个编程对象：读取一或多个属性的值设置一或多个属性的值观察属性值的变化调用动作观察物体发出的事件推断（内省）TD，包括基于TD链接的资源2.2 暴露物暴露物体包括生成协议绑定以便访问底层功能基于提供的字符串序列化格式的TD或既有物体对象创建本地要暴露的物体给物体添加属性定义从物体删除属性定义给物体添加动作定义从物体删除动作定义给物体添加事件定义从物体删除事件定义发送事件，如通知订阅了该事件的所有监听程序为外部请求注册处理程序取得属性的值更新属性的值执行动作：接收来自请求的参数，执行定义的动作，返回结果2.3 发现物通过发送广播请求在WoT网络中发现所有物体发现在本地WoT运行时中运行的物体发现邻近的物体，如通过NFC或蓝牙连接的物体通过向一个注册表服务发送发现请求发现物体通过物体描述定义的过滤器发现物体通过语义查询发现物体停止或阻止进行中的发现过程可选地给发现过程指定超时时间，超时后停止/阻止继续发现3. 接口及类型定义3.1 ThingDescription类型typedef object ThingDescription;下面是通过URL获取一个ThingDescription类型实例的示例：例1：获取TDtry { let res = await fetch('https://tds.mythings.biz/sensor11'); // ... 可以对res.headers进行额外检查 let td = await res.json(); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.getThingDescription().title); } catch (err) { console.log("Fetching TD failed", err.message); }此外，规范也定义了如何扩展TD和验证TD。3.2 WOT接口[SecureContext, Exposed=(Window,Worker)] interface WOT { // methods defined in UA conformance classes Promise<ConsumedThing> consume(ThingDescription td); Promise<ExposedThing> produce(ThingDescription td); ThingDiscovery discover(optional ThingFilter filter = null); };WOT接口的实例将以某种名称暴露在window和worker中。由上面定义可知，WOT接口包含3个方法：consume()：以td为参数，返回Promise，解决为ConsumedThing对象，表示操作物体的客户端接口；produce()：以td为参数，返回Promise，解决为ExposedThing对象，该对象扩展包含服务器端接口的ConsumedThing对象；discover()：启动发现流程，并提供匹配filter参数的ThingDescription对象。这3个方法可分别用于在客户端、服务端创建消费体、产生暴露体和发现TD。3.3 ConsumedThing接口ConsumedThing接口的定义如下所示，ConsumedThing的实例即消费体，拥有一系列操作物体的客户端API。[SecureContext, Exposed=(Window,Worker)] interface ConsumedThing { constructor(ThingDescription td); Promise<any> readProperty( DOMString propertyName, optional InteractionOptions options = null ); Promise<PropertyMap> readAllProperties( optional InteractionOptions options = null ); Promise<PropertyMap> readMultipleProperties( sequence<DOMString> propertyNames, optional InteractionOptions options = null ); Promise<void> writeProperty( DOMString propertyName, any value, optional InteractionOptions options = null ); Promise<void> writeMultipleProperties( PropertyMap valueMap, optional InteractionOptions options = null ); Promise<any> invokeAction( DOMString actionName, optional any params = null, optional InteractionOptions options = null ); Promise<void> observeProperty( DOMString name, WotListener listener, optional InteractionOptions options = null ); Promise<void> unobserveProperty(DOMString name); Promise<void> subscribeEvent( DOMString name, WotListener listener, optional InteractionOptions options = null ); Promise<void> unsubscribeEvent(DOMString name); ThingDescription getThingDescription(); }; dictionary InteractionOptions { object uriVariables; }; typedef object PropertyMap; callback WotListener = void(any data);下面我们简单看一看ConsumedThing接口定义的成员。constructor()构造函数：在取得JSON对象表示的TD后，就可以以之为参数创建ConsumedThing对象。getThingDescription()方法：返回表示ConsumedThing对象的TD。在使用物体前，应用可以先检查TD中的元数据，以确定其能力。InteractionOptions字典：保存根据TD而决定需要暴露给应用脚本的交互选项。在当前版本的规范中，只支持URI模板变量，表现为WoT-TD中定义的解析之后的JSON对象。PropertyMap类型：代表字符串类型的属性名与该属性取值的映射。用于一次性操作多个属性。readProperty()方法：读取一个属性的值。接收字符串参数propertyName和可选的InteractionOptions类型的options参数。返回any类型的属性值。readMultipleProperties()方法：以一或多个请求读取多个属性的值。接收一个字符串序列参数propertyNames和一个可选的InteractionOptions类型的options参数。返回一个对象，键为propertyNames中的字符串，值为相应属性的值。readAllProperties()方法：以一或多个请求读取物体全部属性的值。接收一个字符串序列参数propertyNames和一个可选的InteractionOptions类型的options参数。返回一个对象，键为propertyNames中的字符串，值为相应属性的值。writeProperty()方法：写入一个属性。接收字符串参数propertyName、值参数value和可选的InteractionOptions类型的options参数。返回成功或失败。writeMultipleProperties()方法：一个请求写入多个属性。接收对象类型的properties参数，键为属性名，值为属性值，和可选的InteractionOptions类型的options参数。返回成功或失败。WotListener回调：用户提供接收any参数的回调，用于观察属性变化和处理事件通知。observeProperty()方法：请求订阅某个属性值变化的通知。接收一个字符串参数propertyName、一个WotListener回调listener和一个可选的InteractionOptions类型的options参数。返回成功或失败。unobserveProperty()方法：请求取消订阅某个属性值变化的通知。接收一个字符串参数propertyName，返回成功或失败。invokeAction()方法：请求调用某个动作并返回结果。接收一个字符串参数actionName、一个可选的any类型的参数params和一个可选的InteractionOptions类型的options参数。返回动作的结果或错误。subscribeEvent()方法：请求订阅事件通知。接收一个字符串参数eventName、、一个WotListener回调listener和一个可选的InteractionOptions类型的options参数。返回成功或失败。unsubscribeEvent()方法：请求取消订阅事件通知。接收一个字符串参数eventName，返回成功或失败。下面是一个客户端脚本的例子，展示了如何通过URL获取TD、创建ConsumedThing、读取元数据（title）、读取属性值、订阅属性变化、订阅WoT事件以及取消订阅。例2：客户端API示例try { let res = await fetch("https://tds.mythings.org/sensor11"); let td = res.json(); let thing = new ConsumedThing(td); console.log("Thing " + thing.getThingDescription().title + " consumed."); } catch(e) { console.log("TD fetch error: " + e.message); }, }; try { // 订阅属性“temperature”变化的通知 await thing.observeProperty("temperature", value => { console.log("Temperature changed to: " + value); }); // 订阅TD中定义的“ready”事件 await thing.subscribeEvent("ready", eventData => { console.log("Ready; index: " + eventData); // 返回TD中定义的“startMeasurement”动作 await thing.invokeAction("startMeasurement", { units: "Celsius" }); console.log("Measurement started."); }); } catch(e) { console.log("Error starting measurement."); } setTimeout( () => { console.log("Temperature: " + await thing.readProperty("temperature")); await thing.unsubscribe("ready"); console.log("Unsubscribed from the 'ready' event."); },10000);3.4 ExposedThing接口ExposedThing接口是用于操作物体的服务器API，支持定义请求处理程序、属性、动作和事件接口。[SecureContext, Exposed=(Window,Worker)] interface ExposedThing: ConsumedThing { ExposedThing setPropertyReadHandler( DOMString name, PropertyReadHandler readHandler ); ExposedThing setPropertyWriteHandler( DOMString name, PropertyWriteHandler writeHandler ); ExposedThing setActionHandler( DOMString name, ActionHandler action); void emitEvent(DOMString name, any data); Promise<void> expose(); Promise<void> destroy(); }; callback PropertyReadHandler = Promise<any>( optional InteractionOptions options = null ); callback PropertyWriteHandler = Promise<void>( any value, optional InteractionOptions options = null ); callback ActionHandler = Promise<any>( any params, optional InteractionOptions options = null );ExposedThing接口扩展ConsumedThing接口，可以基于一个完整的或不完整的ThingDescription对象构建实例。ExposedThing从ConsumedThing继承了以下方法：readProperty()readMultipleProperties()readAllProperties()writeProperty()writeMultipleProperties()writeAllProperties()这些方法跟ConsumedThing中的方法拥有同样的算法，不同之处在于对底层平台发送请求可能会以本地方法或库实现，不一定需要调用网络操作。ExposedThing中ConsumedThing接口的实现提供默认的方法与ExposedThing交互。构建ExposedThing之后，应用脚本可以初始化它的属性并设置可选的读、写和动作请求处理程序（即由实现提供的默认值）。应用脚本提供的处理程序可以使用默认处理程序，从而扩展默认行为，但也可以绕过它们，重写默认行为。最后，应用脚本会在ExposedThing上调用expose()，以便开始服务外部请求。以下是ExposedThing接口定义的成员。PropertyReadHandler回调：在收到外部读取某个属性的请求时调用的函数，定义如何处理该请求。返回承诺Promise并在name参数与属性匹配时解决为属性的值，或者未找到属性或者无法获取属性的值时以一个错误拒绝。setPropertyReadHandler()方法：接收字符串参数name和PropertyReadHandler类型的参数readHandler。设置在读取匹配name的属性时执行的处理程序。出错则抛出。返回this对象以支持连缀调用。readHandler回调函数应该实现读取属性的逻辑，且应该在底层平台收到读取属性的请求时由实现调用。对任意属性，必须最多有一个处理程序，因此新加的处理程序必须替换之前的处理程序。如果给定属性不存在任何 初始的处理程序，实现应该基于TD实现一个默认属性读取处理程序。PropertyWriteHandler回调：在收到外部写入某个属性的请求时调用的函数，定义如何处理该请求。参数中需要包含新的value并返回承诺Promise，在匹配name的属性更新为value时解决，如果没找到属性或者值无法更新则拒绝。setPropertyWriteHandler()方法：接收字符串参数name和PropertyWriteHandler类型的参数writeHandler。设置在写入匹配name的属性时执行的处理程序。出错则抛出。返回this对象以支持连缀调用。对任意属性，必须最多有一个处理程序，因此新加的处理程序必须替换之前的处理程序。如果给定属性不存在任何 初始的处理程序，实现应该基于TD实现一个默认属性更新处理程序。ActionHandler回调：在收到外部执行某个动作的请求时调用的函数，定义如何处理该请求。参数中需要包含params字典。返回承诺Promise，出错时拒绝，成功时解决。setActionHandler()方法：接收字符串参数name和ActionHandler类型的参数action。设置在匹配name的动作执行的处理程序。出错则抛出。返回this对象以支持连缀调用。action回调函数应该实现动作的逻辑，且应该在底层平台收到执行动作的请求时由实现调用。对任意动作，必须最多有一个处理程序，因此新加的处理程序必须替换之前的处理程序。emitEvent()方法：接收字符串参数name表示事件名称和any类型的参数data。expose()方法：开始服务外部对物体的请求，从而支持属性、动作和事件的WoT交互。destroy()方法：停止服务外部对物体的请求并销毁对象。注意，最终的取消注册应该在调用这个方法之前完成。以下示例展示了如何基于先构造的不完全的TD对象创建ExposedThing。例3：创建包含简单属性的ExposedThingtry { let temperaturePropertyDefinition = { type: "number", minimum: -50, maximum: 10000 }; let tdFragment = { properties: { temperature: temperaturePropertyDefinition }, actions: { reset: { description: "Reset the temperature sensor", input: { temperature: temperatureValueDefinition }, output: null, forms: [] }, }, events: { onchange: temperatureValueDefinition } }; let thing1 = await WOT.produce(tdFragment); // 初始化属性 await thing1.writeProperty("temperature", 0); // 添加服务处理程序 thing1.setPropertyReadHandler("temperature", () => { return readLocalTemperatureSensor(); // Promise }); // 启动服务 await thing1.expose(); } catch (err) { console.log("Error creating ExposedThing: " + err); }下面的例子展示了如何在已有的ExposedThing上添加或修改属性定义：取得其td属性，增加或修改，然后再用它创建另一个ExposedThing。例4：添加对象属性try { // 创建thing1 TD的深拷贝 let instance = JSON.parse(JSON.stringify(thing1.td)); const statusValueDefinition = { type: "object", properties: { brightness: { type: "number", minimum: 0.0, maximum: 100.0, required: true }, rgb: { type: "array", "minItems": 3, "maxItems": 3, items : { "type" : "number", "minimum": 0, "maximum": 255 } } }; instance["name"] = "mySensor"; instance.properties["brightness"] = { type: "number", minimum: 0.0, maximum: 100.0, required: true, }; instance.properties["status"] = statusValueDefinition; instance.actions["getStatus"] = { description: "Get status object", input: null, output: { status : statusValueDefinition; }, forms: [...] }; instance.events["onstatuschange"] = statusValueDefinition; instance.forms = [...]; // update var thing2 = new ExposedThing(instance); // TODO: add service handlers await thing2.expose(); }); } catch (err) { console.log("Error creating ExposedThing: " + err); }3.5 ThingDiscovery接口发现是分布式应用，需要网络节点（客户端、服务器、目录服务）的供应与支持。这个API对多种IoT部署场景支持的典型发现模式的客户端进行建模。ThingDiscovery对象接收一个过滤器参数，并提供了控制发现过程的属性和方法。[SecureContext, Exposed=(Window,Worker)] interface ThingDiscovery { constructor(optional ThingFilter filter = null); readonly attribute ThingFilter? filter; readonly attribute boolean active; readonly attribute boolean done; readonly attribute Error? error; void start(); Promise<ThingDescription> next(); void stop(); };发现结果对应的内部槽位是一个内部队列，用于临时存储发现的ThingDescription对象，直到应用通过next()方法消费掉。filter属性表示针对此次发现指定的ThingFilter类型的发现过滤器。action属性在发现流程使用协议查找的过程中（如正在接收新TD）为true，否则为false。done属性在发现已经完成、没有更多结果且发现结果为空时为true。error属性表示发现过程中发生的最后一个错误。通常是导致发现停止的关键错误。构建ThingDiscovery的过程如下。start()方法将active属性设置为true。stop()方法将active属性设置为false，但如果发现结果中的ThingDescription对象还没有被next()消费，done属性仍然可能是false。在成功调用next()方法时，active属性可能是true或false，但done属性只有在active为false且发现结果为空时才会被设置为true。下面总结一下start()、next()和stop()方法。start()方法：启动发现流程。next()方法：提供下一个发现的ThingDescription对象。stop()方法：停止或阻止发现过程。可能无法被所有发现方法或端点支持，不过任何后续发现的结果或错误都会被抛弃，而且发现对象也会被标记为不活跃。3.5.1 DiscoveryMethod枚举typedef DOMString DiscoveryMethod;表示要发现的类型：any：不限制local：只发现当前设备或通过有线/无线连接到当前设备的设备上定义的物体。directory：通过物体目录提供的服务发现multicast：使用设备所在网络支持的多播协议发现3.5.2 ThingFilter字典包含发现物体限制类型名值对的对象。dictionary ThingFilter { (DiscoveryMethod or DOMString) method = "any"; USVString? url; USVString? query; object? fragment; };method属性表示发现过程应该使用的发现类型。可能的值由DiscoveryMethod枚举定义，可以由解决方案以字符串值扩展（但不保证互操作性）。url属性表示当前发现方法的额外信息，如服务当前发现请求的目标实体的URL，比如一个物体目录（method值为"directory"时）或物体（method为其他值时）的URL。query属性表示实现接收的查询字符串，比如SPARQL或JSON查询。fragment属性表示用于逐个属性匹配发现物体的模板对象。3.5.3 ThingDiscovery示例以下例子展示了发现本地硬件暴露的物体的ThingDescription的过程，不考虑本地硬件上运行着多少WoT运行时。注意，发现对象可能在内部发现结果队列变空之前告终（变不活跃），因此需要持续读取ThingDescription对象，直到done属性为true。这是典型的本地和目录类型的发现过程。例5：发现本地硬件上暴露的物体let discovery = new ThingDiscovery({ method: "local" }); do { let td = await discovery.next(); console.log("Found Thing Description for " + td.title); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.getThingDescription().title); } while (!discovery.done);下面的例子展示如何发现一个物体目录服务上列出的物体的ThingDescription。为安全起见，设置了超时。例6：通过目录发现物体let discoveryFilter = { method: "directory", url: "http://directory.wotservice.org" }; let discovery = new ThingDiscovery(discoveryFilter); setTimeout( () => { discovery.stop(); console.log("Discovery stopped after timeout."); }, 3000); do { let td = await discovery.next(); console.log("Found Thing Description for " + td.title); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.getThingDescription().title); } while (!discovery.done); if (discovery.error) { console.log("Discovery stopped because of an error: " + error.message); }接下来的例子展示了一个开放式的多播发现过程，可能不会很快结束（取决于底层协议），因此最好通过超时来结束。这种情况也倾向于一个一个地交付结果。例7：在网络上发现物体let discovery = new ThingDiscovery({ method: "multicast" }); setTimeout( () => { discovery.stop(); console.log("Stopped open-ended discovery"); }, 10000); do { let td = await discovery.next(); let thing = new ConsumedThing(td); console.log("Thing name: " + thing.getThingDescription().title); } while (!discovery.done);4. 扩展阅读关于W3C成立WoT工作组制定WoT标准的初衷，可以参考该文章。W3C万维物联网解析：物描述篇W3C万维物联网解析：架构篇“W3C万维物联网标准简介”知乎用户“尧以俊德”的回答：https://www.zhihu.com/question/26469697/answer/5370984455. 相关链接WoT Architecture：https://www.w3.org/TR/wot-architecture/WoT Thing Description：https://www.w3.org/TR/wot-thing-description/WoT Scripting API：https://www.w3.org/TR/wot-scripting-api/WoT Binding Templates:https://www.w3.org/TR/wot-binding-templates/WoT Security and Privacy Considerations：https://www.w3.org/TR/wot-security/WoT兴趣组：https://www.w3.org/2019/07/wot-ig-2019.htmlWoT工作组：https://www.w3.org/2016/12/wot-wg-2016.html
2019年10月21日，作者在“W3C万维物联网标准简介”一文中简单介绍了W3C Web of Things（WoT）工作组制定的WoT标准以及它们的最新状态：规范当前状态WoT ArchitectureCRWoT Thing DescriptionCRWoT Scripting APIWD，Working DraftWoT Binding TemplatesWorking Group NoteWoT Security and Privacy ConsiderationsWorking Group Note本系列将从WoT标准本身出发，对目前已经进入CR阶段（W3C标准的阶段参见下图）的WoT Architecture（WoT架构）、WoT Thing Description（WoT物描述）以及处于WD阶段的WoT Scripting API（WoT编程API）进行一次快速解析。如下图所示，标准进入CR阶段意味着内容已经相对稳定，WD阶段则意味着较大的不确定性，而Working Group Note（工作组备忘）则变数很大。因此处于CR阶段的“架构”和“物描述”是值得花时间了解的（成为正式推荐标准REC的可能性很大），而处于WD阶段的编程API最近（2019年10月28日）刚刚做了一次大的内容改版，几乎完全废弃了上一版的内容，只能说接近稳定状态，但编程API始终是开发者所喜闻乐见的，所以本系列也会介绍。W3C Process Document，https://www.w3.org/2019/Process-20190301/#recs-and-notes1. 物描述简介WoT物描述，即Thing Description，简称TD，是WoT的核心组件。顾名思义，物描述（TD）就是对物的描述，其序列化（文本化）形式是一个JSON文档。简单起见，可以将TD看成是描述物及其能力的入口（就像一个网站的index.html）。一个TD的实例由4个部分组成：关于物体本身的元数据、表示如何使用物体的交互可识别功能、方便机器理解的数据交互模式和与物体相关的其他物体或资源的链接。WoT交互模型定义了三种交互可识别功能：属性、动作和事件 。其中，属性（在TD中以PropertyAffordance类表示），可用于检测和控制参数，如取得当前属性的值或设置某个操作状态。动作（在TD中以ActionAffordance 类表示），对物理（因而耗时的）流程建模，也可用于抽象类似RPC的对既有平台的调用。事件（在TD中以EventAffordance类表示），用于推送通信模型，异步将通知、离散事件或值流发送给接收者。详情可参考WoT架构。TD提供由URI模式（如http、coap等）标识的不同协议绑定的元数据、基于媒体类型（如application/json、 application/cbor）的内容类型和安全机制（用于认证、授权、保密等）。TD实现的序列化是基于JSON的，其中JSON中的名称（属性/字段）引用预定义词汇表中的术语，同样也在WoT物描述标准中定义。此外，TD的JSON序列化遵循JSON-LD 1.1语法，可以方便扩展和进行富语义处理。下面展示了一个TD的示例，描述了名称为MyLampThing的物体。{ "@context": "https://www.w3.org/2019/wot/td/v1", "id": "urn:dev:ops:32473-WoTLamp-1234", "title": "MyLampThing", "securityDefinitions": { "basic_sc": {"scheme": "basic", "in":"header"} }, "security": ["basic_sc"], "properties": { "status" : { "type": "string", "forms": [{"href": "https://mylamp.example.com/status"}] } }, "actions": { "toggle" : { "forms": [{"href": "https://mylamp.example.com/toggle"}] } }, "events":{ "overheating":{ "data": {"type": "string"}, "forms": [{ "href": "https://mylamp.example.com/oh", "subprotocol": "longpoll" }] } } }没错，这就是一个标准的JSON文档。看了这个TD示例，我们知道有一个名为status的属性可识别功能。而且，还有额外信息表明可以通过（安全形式的）HTTP协议的GET方法访问URI https://mylamp.example.com/status（在forms结构的href成员中声明）来访问这个属性，返回的是一个字符串值。使用GET方法并未明确说明，而是本文档定义一个假设默认值。类似地，这个TD还指定了一个动作可识别功能，用于以POST方法请求资源https://mylamp.example.com/toggle来切换开关状态。这里的POST方法则是调用动作的一个默认假设值。还有一个事件可识别功能，表示物体具有发送异步消息的机制。在此，通过使用HTTP的长轮询子协议轮询https://mylamp.example.com/oh，可以获得灯可能过热的事件。这个例子也规定了一个基本的安全模式，即要求用户名和密码才能访问。注意，安全模式的名称首先在securityDefinitions中给出，然后通过在security项指定来激活。结合HTTP协议，这个例子示范了HTTP Basic Authentication的应用。至少一个顶级安全模式是强制性的，它是访问每个资源的默认条件。物描述支持在某些命名空间中添加上下文相关的定义。这种机制可用于在物描述实例的内容中集成额外的语义，只要在给定命名空间下可以找到特定应用领域的规范信息（如逻辑规则）即可。下面的例子扩展了前面的TD，在@context项中增加了第二个定义，声明以saref前缀来引用SAREF词汇表的命名空间。SAREF词汇表包含描述照明设备及其他家居自动化设备的术语，这样术语可以作为@type属性中的语义标签嵌入在TD内。在这个例子中，物体被打上了saref:LightSwitch标签，status属性可识别功能的表单被打上了saref:GetCommand的标签，toggle动作可识别功能的表单被打上了saref:ToggleCommand的标签，overheating事件可识别功能被打上了saref:NotifyComman的标签。{ "@context": [ "https://www.w3.org/2019/wot/td/v1", { "saref": "https://w3id.org/saref#" } ], "id": "urn:dev:ops:32473-WoTLamp-1234", "title": "MyLampThing", "@type": "saref:LightSwitch", "securityDefinitions": {"basic_sc": { "scheme": "basic", "in": "header" }}, "security": ["basic_sc"], "properties": { "status": { "@type": "saref:OnOffState", "type": "string", "forms": [{ "href": "https://mylamp.example.com/status" }] } }, "actions": { "toggle": { "@type": "saref:ToggleCommand", "forms": [{ "href": "https://mylamp.example.com/toggle" }] } }, "events": { "overheating": { "data": {"type": "string"}, "forms": [{ "href": "https://mylamp.example.com/oh" }] } } }2. 命名空间如前所述，物描述或TD的直观表示就是一个JSON-LD文档，而这个JSON文档中的名称（属性）来自预定义的几个词汇表。所有这些词汇表中的术语之间的关系，由物描述规范的信息模型定义。当前，物描述信息模型的版本由如下IRI定义：https://www.w3.org/2019/wot/td/v1物描述信息模型中用到的其他几个词汇表如下：词汇表命名空间IRI核心https://www.w3.org/2019/wot/td#数据模式https://www.w3.org/2019/wot/json-schema#安全https://www.w3.org/2019/wot/security#超媒体控件https://www.w3.org/2019/wot/hypermedia#3. 信息模型TD信息模型构建于以下相互独立的词汇表之上：核心TD词汇表，反映属性、动作和事件等交互可识别功能的交互模型；数据模型词汇表，包括JSON Schema定义的部分术语；WoT安全词汇表，标识安全机制和配置要求；超媒体控件词汇表，使用Web链接和表单编码REST风格通信的主要规范。以上这些词汇表本质上都是一套术语，可以用来构建数据结构，在传统面向对象意义上可以理解为对象。对象是类的实例，拥有属性。在WoT的语境下，对象指的是物体及其交互可识别功能。以下UML图展示了TD信息模型的概要，其中的表格表示类。从Thing类开始，带箭头的曲线表明了类之间的关系。为方便阅读，我们将全图分成4部分，每部分对应一个基本的词汇表。图1 TD核心词汇表图2 JSON模式词汇表图3 WoT安全词汇表图4 超媒体控件词汇表3.1 预定义内容为了让TD信息模型既适合树形文档的简单规则处理（即原始JSON处理）又适合富语义Web工具处理（如JSON-LD处理），物描述规范作出了一系列正式定义，以供构建TD信息模型。下文中所有定义都会用到“集”（set）。直观来讲，集就是一组元素的集合，而其中的元素自身也可以是一个集。任何复杂的数据结构都可以以集来定义。特别地，对象是一个像下面这样递归定义的数据结构：一个术语，可能属于也可以不属于某个词汇表，是一个对象。一组名值对，其中名称是一个术语，而值是另一个对象，也是一个对象。虽然以上定义不能避免对象包含同名名值对，但物描述规范通常不会考虑重名问题。元素名称都是数值的对象称为数组。类似地，元素名称都是（不属于任何词汇表的）术语的对象称为映射。映射包含的名值对中的所有名称在映射作用域内假设是唯一的。另外，对象可以是某个类的实例。类（由一个词汇表术语表示）会使用被称为签名的一组词汇表术语预先定义。签名为空的类称为简单类型。类的签名支持构建两个函数以进一步定义类：赋值函数和类型函数。类的赋值函数以构成类签名的词汇表术语作为参数，返回true或false。简单地理解，赋值函数的返回值表明签名中的元素在类实例化时是必需的还是可选的。类的类型函数同样以构成类签名的词汇表术语作为参数，返回另一个（表示该术语类型的）类。这两个函数是局部的（partial），即它们的作用域被限定为类签名。在这两个函数的基础上，可以定义一个对象和类的实例关系（Instance Relation）。这个关系表示必须满足的约束。换句话说，如果满足下列两个条件，就可以说一个对象是一个类的实例。对每一个类的赋值函数返回true的术语，对象都包含一个以该词汇表术语作为名称的名值对；对每一个在对象名值对中被用作名称的类签名词汇表术语，这个名值对的值都是以该词汇表术语作为参数的该类的类型函数返回的类的实例。根据以上定义，对象是所有简单类型的实例，无论其结构如何。为此，我们也为简单类型定义了一个实例关系：如果对象是一个符合给定词法形式（如boolean类型的true、false，unsignedInt类型的1、2、3等）的术语，则称其为相应简单类型的实例。此外，基于通用的映射和数组结构可以派生出限定类/参数化类。说某对象是某个类的映射，或者是被某个类限定后映射的实例，那么这个对象作为映射，它包含的所有名值对的值都必须是这个类的实例。同样，对数组也一样。最后，如果一个类的所有实例也都是另一个类的实例，则称前一个类为后一个类的子类。有了以上定义，就可以将TD信息模型理解为一组类定义，包含一个类名（词汇表术语）、一个签名（一组词汇表术语）、一个赋值函数和一个类型函数。这些类定义分别由5.3节“类定义”中的多个表给出。每个表“赋值”列中的值“必需”或“可选”表示赋值函数对相应的词汇表术语返回true或false。按照约定，简单类型由小写字母开头的名称表示。TD信息模型引用如下在XML Schema中定义的简单类型：string、anyURI、dateTime、integer、unsignedInt、double和boolean。它们的定义（如它们的词法形式的规范）超出了TD信息模型的范围。另外，TD信息模型还定义了一个与词汇表术语对应的全局函数。这个函数接收一个类名和另一个词汇表术语作为参数，返回一个对象。如果返回的对象不是null，则该对象表示对该类实例的该词汇表术语赋值时使用的默认值。这个函数可以放宽前面提到的赋值函数的约束：如果对象包含所有必需的赋值且未赋值的有默认值，则该对象就是某个类的实例。所有默认值在“3.3 默认值定义”中的表里给出。在“3.2 类定义”的每个表中，如果TD信息模型中相应类与词汇表术语的组合有默认值，则“赋值”列的值就是“有默认值”。这里引入的形式化不考虑作为抽象数据结构的对象与物理世界对象如物体之间可能存在的关系。不过，物描述规范也考虑到了TD信息模型在作为RDF资源集成到物理世界中更大的模型（ontology，存在）时需要重新解释所有词汇的可能性。规范的附录D.2“物描述存在”对此给出了解决方案。3.2 举例：Thing如前所述，TD信息模型定义了4个词汇表：核心词汇表、数据模式词汇表、安全词汇表和超媒体控件词汇表。为简单起见，本文仅以核心词汇表中的Thing为例，介绍与Thing相关的词汇表术语。Thing是对物或虚拟实体的抽象，其元数据和接口由WoT物描述来描述。虚拟实体是一或多个物的组合体。词汇表术语描述赋值类型@contextJSON-LD关键字，定义在TD文档中使用被称为术语的简写名称必需anyURI或数组@typeJSON-LD关键字，用语义标记（或类型）给对象打上标签可选string或string数组id物体的唯一标识符（URI，如自定义URN）必需anyURItitle默认语言的人类友好的名称（在UI上显示的文本）必需stringtitles多语言人类友好的名称（以不同语言在UI上显示的文本）可选MultiLanguagedescription默认语言的人类友好的附加信息可选stringdescriptions多语言人类友好的附加信息可选MultiLanguageversion版本信息可选VersionInfocreated创建TD实例的时间可选dateTimemodified最后一次修改TD实例的时间可选dateTimesupport以URI模式（如mailto、tel）表示的TD维护者的信息可选anyURIbase为TD文档中所有相对URI定义基准URI。在TD实例中，所有相对URI都使用RFC3986中定义的算法相对于基准URI解析base不影响@context中使用的URI，以及在对TD实例进行语义处理时链接数据中使用的IRI可选anyURIproperties物体所有基于属性的交互可识别功能可选PropertyAffordance的映射actions物体所有基于动作的交互可识别功能可选ActionAffordance的映射events物体所有基于事件 的交互可识别功能可选EventAffordance的映射links指向与与TD相关的任意资源的Web链接可选Link的数组forms描述如何执行操作的一组超媒体控件。表单是协议绑定序列化之后的形式。在当前TD版本中，所有可以在物体级别描述的操作均为一次性批量操作的物体属性可选Form的数组security从securityDefinitions中选取的安全定义的名称。访问资源时必须全部满足必需string或string数组securityDefinitions安全配置（仅定义）名称的集合。除非在security项中使用，否则不会真正应用必需SecurityScheme的映射其他词汇表及词汇，有兴趣的读者可以自行参考WoT物描述规范。4. 扩展阅读关于W3C成立WoT工作组制定WoT标准的初衷，可以参考该文章。W3C万维物联网解析：架构篇“W3C万维物联网标准简介”知乎用户“尧以俊德”的回答：https://www.zhihu.com/question/26469697/answer/5370984455. 相关链接WoT Architecture：https://www.w3.org/TR/wot-architecture/WoT Thing Description：https://www.w3.org/TR/wot-thing-description/WoT Scripting API：https://www.w3.org/TR/wot-scripting-api/WoT Binding Templates:https://www.w3.org/TR/wot-binding-templates/WoT Security and Privacy Considerations：https://www.w3.org/TR/wot-security/WoT兴趣组：https://www.w3.org/2019/07/wot-ig-2019.htmlWoT工作组：https://www.w3.org/2016/12/wot-wg-2016.html
2019年10月21日，作者在“W3C万维物联网标准简介”一文中简单介绍了W3C Web of Things（WoT）工作组制定的WoT标准以及它们的最新状态：规范当前状态WoT ArchitectureCRWoT Thing DescriptionCRWoT Scripting APIWD，Working DraftWoT Binding TemplatesWorking Group NoteWoT Security and Privacy ConsiderationsWorking Group Note本系列将从WoT标准本身出发，对目前已经进入CR阶段（W3C标准的阶段参见下图）的WoT Architecture（WoT架构）、WoT Thing Description（WoT物描述）以及处于WD阶段的WoT Scripting API（WoT编程API）进行一次快速解析。如下图所示，标准进入CR阶段意味着内容已经相对稳定，WD阶段则意味着较大的不确定性，而Working Group Note（工作组备忘）则变数很大。因此处于CR阶段的“架构”和“物描述”是值得花时间了解的（成为正式推荐标准REC的可能性很大），而处于WD阶段的编程API最近（2019年10月28日）刚刚做了一次大的内容改版，几乎完全废弃了上一版的内容，只能说接近稳定状态，但编程API始终是开发者所喜闻乐见的，所以本系列也会介绍。W3C Process Document，https://www.w3.org/2019/Process-20190301/#recs-and-notes1. WoT架构WoT架构规范的核心分别从7个方面描述了WoT相关的术语及这些术语之间的相关关系。架构的本质就是术语及其关系。术语代表业界约定俗成的概念，是架构的骨骼和肌肉；关系描述术语的交互与特性，是架构的血液和神经。Overview（概述）Affordances（可识别功能）Web Thing（Web物）Interaction Model（交互模型）Hypermedia Controls（超媒体控件）Protocol Bindings（协议绑定）WoT System Components and Their Interconnectivity（组件及互联）2. 概述这一部分从宏观上定义了Thing、Consumer和Intermediary三个基础概念及其相互关系。Thing（物）：指的是某个物理或虚拟实体（如设备或房间）的抽象表示，由标准化的元数据描述。在W3C WoT中，描述元数据必须是WoT Thing Description（TD）。Consumer（消费者）：消费者必须能够解析和处理基于JSON的TD。Intermediary（中介）：可以充当物体的代理，此时中介拥有与背后的物类似的TD，但指向的是由这个中介提供的WoT接口。中介也可以给背后的物添加额外的能力或者将多个可用的物体组合起来，从而构成虚拟实体。对消费者而言，中介看起来就像一个物，因为它拥有TD且提供WoT接口。消费者与物直接交互是最简单直观的方式：物TD中可以包含指向其他物或资源的链接：互联网无法访问本地网络是实际部署中面临的一个典型问题，通常是因为存在IPv4 NAT（Network Address Translation）或防火墙。为解决这个问题，W3C WoT允许物与消费者之间存在中介。上述几个概念适用于IoT应用的各个层面：设备层、边缘层和云计算层。在这些层面应用上述概念能够促进跨层级通用接口和API的产生，进而促成IoT应用间不同的交互模式如物与物、物与网关、物与云、网关与云，甚至云联盟（如两个或多个服务提供商的云计算环境互联）。3. 可识别功能Affordance（可识别功能）是借用认知心理学领域的一个术语，“指的是某物可察觉且实际存在的属性，而且特指决定怎么使用它们的根本属性。”（Donald Norman）比如，看到门边有一块板，就知道需要推开它。（参见：https://communitywiki.org/wiki/WhatIsAffordance）可识别功能在TD中用于描述物的能力。WoT将以下4个概念归为可识别功能：导航属性动作事件其中，导航使用的是超链接。对超链接的描述（比如链接关系类型和链接目标属性）就是一种功能，它告诉Web客户端如何导航以及怎么处理链接的资源。换句话说，链接提供了导航这种可识别功能。而属性、动作和事件使用另一个超媒体控件，表单来描述。相对于超链接，表单能实现与物的更复杂的交互。4. Web物Web物涉及4个方面：Behavior（行为）Interaction Affordance（交互可识别功能）Security Configuration（安全配置）Protocol Binding（协议绑定）如下图所示，除了行为之外，交互可识别功能、安全配置和协议绑定都需要在TD中体现。这里的行为，可以理解为在其他3方面之上的基于场景的控制逻辑。TD中描述的交互可识别功能可以为消费者提供了一个交互模型，但不涉及特定网络协议或数据编码。交互可识别功能到特定协议消息的映射由协议绑定来提供。一般来说，不同协议通常用于支持不同的交互可识别功能。而物的安全配置则代表交互可识别功能的访问控制机制，以及对相关公共或私有元数据的管理。物架构5. 交互模型如前所述，WoT在导航的基础之上，又正式规定了3种交互可识别功能：属性动作事件属性作为一种交互可识别功能，用于暴露物体的状态。属性暴露的状态必须可获取（可读）。可选地，属性暴露的状态可以被更新（可写）。物体可以通过在某个变化之后推送新状态让属性可观察（参见Observing Resources [RFC7641]）。只写状态应该通过某个动作来更新。属性的例子有传感器的值（只读）、有状态执行器（读写）、配置参数（读写）、物体状态（只读或读写），以及计算结果（只读）。动作作为一种交互可识别功能，允许激活物体的某个功能。动作可以操作直接暴露的状态（参见属性）、同时操作多个属性或基于内部逻辑操作属性（如切换）。触发动作也可以触发物体上某个随时间推移而操作状态（包括通过执行器改变物理状态）的流程。动作的例子包括同时改变多个属性、随时间推移或通过一个不应泄露的流程（如专有控制循环算法）改变属性（如调暗灯光），或者启动一个持续较长时间的流程（如打印文件）。事件作为一种交互可识别功能，描述异步把数据从物体推送到消费者的事件来源。这里重点不在于传送状态，而在于传送状态变化（如事件）。事件可以通过未暴露为属性的条件触发。事件的例子包括警报等离散事件，也包括定时推送的时序采样事件。无论属性、动作，还是事件，如果交互过程中的数据没有被协议绑定（通过媒体类型）完全定义，那么它们都可以额外包含相应的数据模式（Data Schema）。6. 超媒体控件W3C WoT用到了两种超媒体控件：众所周知的在网上冲浪的Web链接（RFC8288）和更强大的可以支持任意操作的Web表单。链接在其他IoT标准和IoT平台中已经被用到了，比如CoRE Link Format [RFC6690]、OMA LWM2M [LWM2M]、OCF [OCF]。表单则是一个新概念，除了W3C WoT，IETF的Constrained RESTful Application Language (CoRAL) [CoRAL]也用到了它。6.1 链接链接让消费者（或者更宽泛地讲Web客户端）改变当前上下文（Web浏览器当前呈现的各种资源）或者在当前上下文中包含更多资源，取决于上下文与链接目标的关系。消费者通过对目标URI解引用也就是通过跟进链接来获取资源表示来实现这一操作。W3C WoT遵循Web链接（[RFC8288]）的定义，也就是说一个链接包含：链接上下文关系类型链接目标目标属性（可选）在WoT中，链接用于发现和表示物体之间的关系（如层次关系或功能关系），以及物体与Web上其他文档的关系（如手册或CAD模型等替代表示）。6.2 表单表单让消费者（或者更宽泛地讲Web客户端）执行超出解引用URI以外的操作（如操作物体的状态）。消费者通过填充并将表单提交给提交目标来实现上述操作。这通常需要比链接更详细的（请求）消息细节（如方法、首部字段或其他协议选项）。可以将表单看成一个请求模板，提供商会根据自己的接口和状态预先填充部分信息，剩余的字段由消费者（或Web客户端）填写。W3C WoT把表单定义为一种新的超媒体控件。注意，CoRAL（ [CoRAL]）中的定义也差不多，可以看成是一致的。表单包含：表单上下文操作类型提交目标请求方法表单字段（可选）表单可以看成这么一句话：“在表单上下文中执行指定操作类型的操作，以指定的请求方法向提交目标发送请求”，然后可选的字段用于进一步描述请求。 WoT的常见操作类型操作类型说明readproperty标识属性可识别功能的读操作，用于获取相应数据writeproperty标识属性可识别功能的写操作，用于更新相应数据observeproperty标识属性可识别功能的观察操作，当属性被更新时会收到包含新数据的通知unobserveproperty标识属性可识别功能的取消观察操作，停止接收相应的通知invokeaction标识动作可识别功能的调用操作，以执行相应的动作subscribeevent标识事件可识别功能的订阅操作，当物体的事件发生时会收到通知unsubscribeevent标识事件可识别功能的取消订阅操作，停止接收相应的通知readallproperties标识物体的读取全部属性操作，用于一次性获取所有属性的数据writeallproperties标识物体的写入全部属性操作，用于一次性写入所有属性的数据readmultipleproperties标识物体的读取多个属性操作，用于一次性获取选择属性的数据writemultipleproperties标识物体的写入多个属性操作，用于一次性写入选择属性的数据7. 协议绑定协议绑定就是从一个交互可识别功能到某个特定协议（如HTTP [RFC7231]、CoAP [RFC7252]或MQTT [MQTT]）具体消息的映射。协议绑定让消费者知道如何通过面向网络的接口激活交互可识别功能。为支持互操作，协议绑定遵循REST（[REST] ）的统一接口规范。WoT对协议绑定从如下几方面做出了限制。7.1 超媒体驱动交互可识别功能必须包含一或多个协议绑定。协议绑定必须被序列化为超媒体控件，能够自解释如何激活交互可识别功能。超媒体控件必须由提供交互可识别功能的物体主体给出。所谓主体可以是物体自身，在运行时产生TD文档（基于自己当前状态并包含IP地址等网络参数），也可以从内存里给出（只包含当前网络参数）。主体也可以是能全面且实时掌握物体及其网络参数、内部结构的外部实体（如软件栈）。这可以让物体与消费者实现松散耦合，从而让它们拥有独立的生命周期并独立演进。超媒体控件可以被缓存在物体外部，以便离线时使用缓存的尚在有效期的元数据。7.2 URI符合W3C WoT要求的协议必须具有在IANA（[RFC4395]）注册的URI模式。超媒体控件依赖URI辨别链接和提交目标。因此，URI模式（冒号前的第一个组件）表示与物体的交互可识别功能通信时使用的协议。W3C WoT称这些协议为传输协议。7.3 标准方法符合W3C WoT要求的协议必须基于众所周知的标准方法。标准方法让消息可以自解释，从而让交互可识别功能可以进行中间处理，如通过代理来处理或者从一个协议绑定转换为另一个协议绑定[REST]。另外，还可能让消费者拥有可重用的传输协议栈，如HTTP、CoAP或MQTT，避免消费者编写特定于物体的代码或插件。7.4 媒体类型在激活交互可识别功能时交换的所有数据（或者说内容）都必须通过协议绑定中的媒体类型[RFC6838] 来标识。媒体类型表示内容格式，如application/json for JSON [RFC8259] or application/cbor for CBOR [RFC7049]。媒体类型由IANA管理。有些媒体类型可能需要提供额外参数才能完整指定内容使用的格式。如text/plain; charset=utf-8 or application/ld+json; profile="http://www.w3.org/ns/json-ld#compacted"。在描述发送给物体的数据时，需要特别注意这一点。传输过程中可能需要对数据进行标准的转换，如内容编码 [RFC7231]。协议绑定可以包含额外信息，用于在媒体类型之外提供更具体的信息以供确定内容格式。注意，很多媒体类型只标识一种通用的序列化格式，并不能对内容组成（如XML、JSON、CBOR）提供更多语义。因此，对应的交互可识别功能应该声明数据模式，以便为数据交换提供更具体的语法级元数据。8. 组件及其互联概述中从抽象WoT架构组件角度描述了WoT架构，包括物、消费者和中介。在把这些抽象的架构组件实现为软件栈，而这些软件栈在WoT架构中扮演相应角色时，这些软件栈就被称为服务套件（Servient）。这一部分通过示意图来说明服务套件如何协同工作以构成基于WoT架构的系统。首先，物可以被实现为服务套件。我们称包含物表示（TD）的服务套件软件栈为暴露体（Exposed Thing），该软件栈对物的消费者暴露WoT接口。暴露体可以由服务套件上的其他软件组件使用，以实现物的行为。物服务套件其次，消费者则始终会通过服务套件实现，因为它们必须能够处理TD，而且必须有一个可以通过TD中包含的协议绑定信息来配置的协议栈。在消费者中，我们称提供物表示的服务套件软件栈为消费体（Consumed Thing），该软件栈让运行于这个服务套件之上、需要处理TD的应用可以与物体交互。消费者服务套件服务套件软件栈中消费体的实例旨在从应用中分离协议级别的复杂性，代替应用与暴露体进行通信。最后，中介也是由服务套件实现的一个WoT架构组件。中介位于物与消费者之间，同时扮演消费者（对物而言）和物（对消费者而言）的角色。在中介服务套件中，软件栈既包含消费者（消费体）也包含物（暴露体）。中介服务套件8.1 直接通信下图展示了物与消费者之间的直接通信，物通过TD暴露交互可识别功能，消费者通过该交互可识别功能来使用物。直接通信适用于双方的服务套件使用相同网络协议，且可以相互访问的场景。消费者与物直接通信暴露体是物抽象的软件表示，为物提供的交互可识别功能暴露WoT接口。消费体是被消费者消费的一个远程物的软件表示，作为应用访问远程物的接口。消费者可以通过解析和处理TD生成一个消费体实例。消费者与物的交互通过消费体与暴露体直接连接并交换数据实现。8.2 间接通信下图展示了消费者和物通过中介相互连接在一起。如果实现消费者与物的服务套件使用不同协议，或者消费者与物位于需要认证才能访问的不同网络，则它们之间必须通过中介实现通信。通过中介通信中介同时包含暴露体和消费体的功能。中介的功能包括为消费者和物的交互可识别功能转发消息、可选地缓存物体的数据以加速响应，以及在物的功能被中介扩展的情况下进行通信转换。在中介里，消费体会创建物的暴露体的代理对象，消费者可以通过自己的消费体访问这个代理对象（即中介的暴露体）。中介与消费者通信使用的协议可以不同于与物通信使用的协议。比如，使用CoAP的物与使用HTTP的消费者可以通过中介作为桥梁。即使中介与物之间使用多种不同协议，消费者也可以只使用一种协议通过中介与这些物通信。同样，在认证的时候也是这样。消费者的消费体只需使用一种安全机制与中介的暴露体进行认证，而中介则可能需要通过多种安全机制对不同的物进行认证。通常，中介会根据原始物的TD来创建其代理对象的TD。根据用例的需求，这个代理对象的TD可以使用与原始物TD相同的标识符，也可以被赋予一个新标识符。必要情况下，中介生成的TD可以包含支持其他通信协议的接口。9. 小结本文作为“W3C万维物联网标准解析”系列的第一篇，主要讲解了WoT架构的核心概念。架构的本质是概念及其关系。WoT架构描述了很多概念，包括物、中介、消费者、可识别功能（属性、动作、属性）、超媒体控件（链接、表单）、服务套件、暴露体、消费体，等等。其中物是对物理或虚拟设备的抽象，代表服务端功能。消费者是对WoT应用的抽象，代表客户端功能。而中介则兼具物的抽象和应用的抽象。物、消费者和中介的实现称为服务套件，有直接和间接两种通信模式。WoT架构的核心是规定了物描述（TD）包含交互可识别功能、安全配置和协议绑定。物可以拥有导航、属性、动作和属性等4种交互可识别功能，并通过超媒体控件（链接、表单）提供。这就是所谓的交互模型。WoT架构当前定义了12用常用交互操作，其中8种与属性相关、1种与动作相关，2种与事件相关。协议绑定是交互可识别功能到具体协议调用的映射。安全配置代表交互可识别功能的访问控制机制。10. 扩展阅读关于W3C成立WoT工作组制定WoT标准的初衷，可以参考该文章。“W3C万维物联网标准简介”知乎用户“尧以俊德”的回答：https://www.zhihu.com/question/26469697/answer/53709844511. 相关链接WoT Architecture：https://www.w3.org/TR/wot-architecture/WoT Thing Description：https://www.w3.org/TR/wot-thing-description/WoT Scripting API：https://www.w3.org/TR/wot-scripting-api/WoT Binding Templates:https://www.w3.org/TR/wot-binding-templates/WoT Security and Privacy Considerations：https://www.w3.org/TR/wot-security/WoT兴趣组：https://www.w3.org/2019/07/wot-ig-2019.htmlWoT工作组：https://www.w3.org/2016/12/wot-wg-2016.html
10月20日，第六届世界互联网大会在浙江乌镇开幕。国家主席习近平致贺信。习近平指出，今年是互联网诞生50周年。当前，新一轮科技革命和产业变革加速演进，人工智能、大数据、物联网等新技术新应用新业态方兴未艾，互联网迎来了更加强劲的发展动能和更加广阔的发展空间。发展好、运用好、治理好互联网，让互联网更好造福人类，是国际社会的共同责任。各国应顺应时代潮流，勇担发展责任，共迎风险挑战，共同推进网络空间全球治理，努力推动构建网络空间命运共同体。（新华社北京10月20日电：http://www.xinhuanet.com/politics/2019-10/20/c_1125127764.htm）社交媒体实现了“人联网”，在线支付实现了“财联网”。如今，人工智能、大数据技术的发展正有力地推动“物联网”的兴起。不难想象，物联网将在智能家庭、产业、城市，乃至智能国家、智能地球的建设中发挥基础性作用，为未来的人类和社会造福。然而，由于联网设备的制造厂商不同、接入互联网使用的协议不同，如今的物联网（IoT，Internet of Things）依旧呈现“一盘散沙”、“各自为政”的状态。IoT平台和生态虽然层出不穷，快速演进，但各家协议栈和软件应用之间缺乏互通，形成了千千万万个专有IoT“孤岛”。W3C称IoT的这种状态为“碎片化”（fragmentation）。碎片化导致用户与供应商绑定、开发交付成本高昂、软件组件难以复用，这些问题成为阻碍IoT向更深、更广领域应用迈进的巨大障碍。为实现IoT基于Web技术的互联互通，W3C决定在已有IoT平台/生态基础上“做一些填补空隙”的工作，并于2015年1月成立WoT兴趣组（https://www.w3.org/2019/07/wot-ig-2019.html），又于2016年12月成立WoT工作组（https://www.w3.org/2016/12/wot-wg-2016.html），正式开始WoT（Web of Things，万维物联网）标准的制定。截止到2019年5月，WoT工作组已经发布5份文档，其中2份已经进入“CR”（Candidate Recommendation，候选推荐）状态：注意上述这些规范文档并不是最终标准。W3C标准的最终状态是“REC”，即Recommendation（推荐标准）。在到达“REC”阶段之前，以上所有规范内容都可能被修改，并且也不排除某份文档被废弃的可能。换句话说，以上规范文档均不能作为正式实现文档在产品中使用。规范当前状态WoT ArchitectureCRWoT Thing DescriptionCRWoT Scripting APIWD，Working DraftWoT Binding TemplatesWorking Group NoteWoT Security and Privacy ConsiderationsWorking Group Note本文将对上述W3C公开发布的规范进行概要介绍，仅供参考。1. WoT架构WoT Architecture（候选推荐）：https://www.w3.org/TR/wot-architecture/WoT Architecture（编辑草案）：https://w3c.github.io/wot-architecture/物体，指的是某个物理或虚拟实体（如设备或房间）的抽象表示，由标准化的元数据描述。在W3C WoT中，描述元数据必须是WoT Thing Description（TD）。消费者必须能够解析和处理基于JSON的TD。WoT物体WoT物体描述是标准化的、机器友好的表示格式，消费者可以通过这种格式发现和解释物体的能力（通过语义注解），在与物体交互时适应不同实现（如不同的协议和数据结构）， 而达到跨IoT平台（如不同的生态或标准）互操作的目的。消费者与物体交互物体必须托管在联网的系统组件上，基于一个软件栈通过（面向网络的）WoT接口实现交互。互联网无法访问本地网络是实际部署中面临的一个典型问题，通常是因为存在IPv4 NAT（Network Address Translation）或防火墙。为解决这个问题，W3C WoT允许物体与消费者之间存在中介层（intermediary）。中介层中介层（intermediary）可以充当物体的代理，此时中介层拥有与背后的物体类似的WoT物体描述，但指向的是由这个中介层提供的WoT接口。中介层也可以给背后的物体添加额外的能力或者将多个可用的物体组合起来，从而构成一个虚拟实体。对消费者而言，中介层看起来就像一个物体，因为它们拥有WoT物体描述，而且提供WoT接口。W3C WoT的概念适用于IoT应用的各个层面：设备层、边缘层和云计算层。这样可以促进跨层级通用接口和API的产生，进而促成IoT应用间不同的交互模式如物与物、物与网关、物与云、网关与云，甚至云联盟（如两个或多个服务提供商的云计算环境互联）。WoT的抽象架构2. WoT物体描述WoT Thing Description（候选推荐）：https://www.w3.org/TR/wot-thing-description/WoT Thing Description（编辑草案）：https://w3c.github.io/wot-thing-description/WoT物体描述（TD）基于一个语义词汇表定义了一个信息模型，同时基于JSON定义了一种序列化表示。TD提供有关物体的丰富的元数据，这些元数据既对人类友好，也对机器友好。物体描述（TD）用元数据来描述物体的实例，包括名称、ID、说明等，还可以链接到相关物体和其他文档以提供相关元数据。TD中也包含（基于WoT架构定义的交互模型的）交互可识别功能的元数据、公共安全配置元数据和定义协议绑定的通信元数据。可以把TD看成物体的index.html，因为它为了解物体提供的服务及其相关资源提供了一个入口，而物体提供的服务及其相关资源都使用超媒体控件来描述。理想情况下，TD由物体自己创建并/或托管，可以从物体目录检索到。不过，在物体资源有限（如内存有限、电量有限）或将既有设备改造为WoT时，TD也可以托管到外部。将TD注册到一个目录是改进物体发现（如对于受限设备）和方便设备管理的一个常见做法。消费者同时采用一种TD缓存机制和一种通知机制（在物体更新时，可以通知消费者获取新版本的TD）是推荐的做法。为实现语义上的互操作，TD可以利用领域特定的词汇表，并明确提供扩展入口。不过，制定领域特定的词汇表已经超出当前W3C WoT标准化任务的范围。总的来说，WoT物体描述组件从两方面增进互操作能力。首先，TD让WoT实现机器与机器通信；其次，TD本身可以作为一个通用、统一的格式，让开发者记录和获取所有必要细节以创建应用去访问IoT设备和利用其数据。3. WoT绑定模板WoT Binding Templates（备忘录）：https://www.w3.org/TR/wot-binding-templates/WoT Binding Templates（编辑草案）：https://w3c.github.io/wot-binding-templates/IoT使用很多不同协议访问设备，因为没有一种协议是通用的。为此，WoT最重要的挑战就是让各种不同的IoT平台（如OCF、oneM2M、OMA LWM2M、OPC UA）和不符合任何特定标准但可以基于合适的网络协议提供够用接口的设备之间能够对话。WoT应对这种多样挑战的方案就是协议绑定，但必须满足一些约束条件。非标准性的WoT绑定模板规范提供了一套通信元数据蓝图，以指导如何与不同的IoT平台交互。在描述一个特定的IoT设备或服务时，可以查询与相应IoT平台对应的绑定模板，获得为支持该平台而必须在物体描述中提供的通信元数据。从绑定模板到协议绑定上图展示了如何使用绑定模板。WoT绑定模板对每个IoT平台只创建一次，然后就可以在该平台所有设备的TD中重用了。处理TD的消费者必须实现必要的协议绑定，通过包含一个对应的协议栈并根据TD中给出的信息配置该栈（或其消息）。协议绑定的元数据分五个维度：IoT平台IoT平台经常会在应用层引入专有的修改，比如特定于平台的HTTP首部字段或CoAP选项。表单中除了为应用层协议使用而定义的字段，还可能包含应用这些修改的必要信息。媒体类型IoT平台交换的数据经常出现不同格式（也就是序列化方式）。媒体类型用于标识这些格式，而参数可以进一步明确格式。表单中除了已知的如HTTP的内容类型（包含媒体类型和可选参数，如text/plain; charset=utf-8）字段外，还可以包含媒体类型和其他可选参数。传输协议WoT使用传输协议来指代底层、标准化的应用层协议，不包含应用特定的选项或子协议机制。表单（提交）目标的URI模式包含确定传输协议的必要信息，如HTTP、CoAP或WebSocket。子协议传输协议可以有扩展机制，但必须已知可以成功交互。这种子协议不能在URI模式中体现，必须显式声明。相关的例子有HTTP的推送通知补丁如长轮询或服务端推送事件Server-Sent Events 。表单可以包含必要的信息以标识额外表单字段中的子协议。安全通信栈的不同层次可以有各自的安全机制，而多个安全机制也可以一块使用，以互为补充。例子包括(D)TLS、IPSec、OAuth和ACE。由于安全是贯穿所有规范的，应用正确安全机制的必要信息可以在物体的通用元数据中给出。4. WoT编程APIWoT Scripting API（编辑草案）：https://www.w3.org/TR/wot-scripting-api/WoT Scripting API（编辑草案：新）：https://w3c.github.io/wot-scripting-api/WoT编程API是W3C WoT组件中可选的“便利”组件，可以通过提供类似Web浏览器API一样基于ECMAScript的API让开发IoT应用更容易。通过在WoT运行时内集成一个脚本运行时，WoT编程API可以让编写可移植应用脚本成为可能，这些脚本定义物体、消费者与中介层的行为。过去，IoT设备逻辑都在固件中实现，这就导致了类似嵌入式开发的低效率，而且升级过程也相对复杂。现在，WoT编程API让一个IoT应用的设备逻辑可以通过在运行时中执行可重用脚本来实现，与在Web浏览器中运行脚本没什么不同，因此可以提升生产力，降低集成成本。不仅如此，标准化的API也让开发可以移植的应用模块成为可能。这样，把计算密集型逻辑从设备迁移到本地网关，或者把时效性要求高的逻辑从云端迁移到本地网关或其他边缘节点就都很容易了。非标准性的WoT编程API定义了相应编程接口的结构和算法，让脚本可以发现、获取、消费、生成和暴露WoT物体描述。WoT编程API的运行时负责实例化本地对象，作为访问物体及其交互可识别功能（属性、动作和事件）的接口。同时脚本也可以通过运行时暴露物体，即定义和实现交互可识别功能并发布物体描述。5. WoT安全与隐私指南WoT Security and Privacy Considerations（备忘录）：https://www.w3.org/TR/wot-security/WoT Security and Privacy Guidelines（编辑草案）：https://w3c.github.io/wot-security/安全是贯穿所有规范的主题，系统设计的方方面面都要考虑。在WoT架构中，某些显而易见的特性都有安全保护措施，比如TD中支持公共安全元数据、设计WoT编程API时分离关注点。每个组件的标准也都包含各自安全与隐私的议题。写在最后W3C是开放的国际标准组织，所有工作组标准的制定都在Github上公开进行。如果你对正在制定中的WoT标准感兴趣，欢迎通过下面的链接找到并参与ISSUE讨论，帮助W3C制定出更好的Web标准。相关链接WoT Architecture：https://www.w3.org/TR/wot-architecture/WoT Thing Description：https://www.w3.org/TR/wot-thing-description/WoT Scripting API：https://www.w3.org/TR/wot-scripting-api/WoT Binding Templates:https://www.w3.org/TR/wot-binding-templates/WoT Security and Privacy Considerations：https://www.w3.org/TR/wot-security/WoT兴趣组：https://www.w3.org/2019/07/wot-ig-2019.htmlWoT工作组：https://www.w3.org/2016/12/wot-wg-2016.html