Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

 


Tip
iconfalse


 Related docs
Model-to-Model SubscriptionIP device APIs Type
Composite attributes Composit
attributesHelper tags 
FacetScriptHTTP Invoke 




Tip
iconfalse


 Related docs
Model-to-Model SubscriptionDevice Manager 
TypeMacros Composit attributes
Execute Query Macro FacetScript
Multiple Invokes 



 

Hardware Setup

Philip Hue is a system of 4 components:

  1. Apps – These are ways to control the lights to make them do smart things. 
  2. Bridge – This is used to enable your smart bulbs to communicate with each other and the Portal via the internet. The main set of APIs are those offered by the bridge. These allow you to control all settings of the lights in your system. These APIs require direct access to your bridge so you’ll only be able to access them when your app and bridge are on the same local network.
  3. Portal – This is a web based control panel which connects your home to the internet. It delivers control commands from outside and keeps your software in the bridge up-to-date. The portal presents a utility API to help you discover the address of your bridge.
  4. Lights – This is the output of the system. These smart bulbs contain 3 types of LED specifically chosen to produce a range of colors and intensities. Lights create a mesh network with each other which enables each light to pass on messages to the next extending the range and making everything more robust. They are connected to the bridge via an open standards protocol called ZigBee Light Link.

We will be controlling the lights using Philip Bridge HTTP APIs.

Philip Bridge HTTP Requests

http://10.0.2.16/api/newdeveloper/lights

Request Name: Get the list of lights

Code Block
titleGet Lights JSON
linenumberstrue
{
    "1": {
        "state": {
            "on": true,
            "bri": 144,
            "hue": 13088,
            "sat": 212,
            "effect": "none",
            "xy": [
                0.5128,
                0.4147
            ],
            "ct": 467,
            "alert": "none",
            "colormode": "hs",
            "reachable": true
        },
        "type": "Extended color light",
        "name": "Hue Lamp 1",
        "modelid": "LCT001",
        "uniqueid": "00:17:88:01:00:b6:c6:f0-0b",
        "swversion": "66009663",
        "pointsymbol": {
            "1": "none",
            "2": "none",
            "3": "none",
            "4": "none",
            "5": "none",
            "6": "none",
            "7": "none",
            "8": "none"
        }
    },
    "2": {
        "state": {
            "on": true,
            "bri": 144,
            "hue": 13088,
            "sat": 212,
            "effect": "none",
            "xy": [
                0.5128,
                0.4147
            ],
            "ct": 467,
            "alert": "none",
            "colormode": "ct",
            "reachable": true
        },
        "type": "Extended color light",
        "name": "Hue Lamp 2",
        "modelid": "LCT001",
        "uniqueid": "00:17:88:01:00:b9:38:7c-0b",
        "swversion": "66009663",
        "pointsymbol": {
            "1": "none",
            "2": "none",
            "3": "none",
            "4": "none",
            "5": "none",
            "6": "none",
            "7": "none",
            "8": "none"
        }
    },
    "3": {
        "state": {
            "on": true,
            "bri": 144,
            "hue": 13088,
            "sat": 212,
            "effect": "none",
            "xy": [
                0.5128,
                0.4147
            ],
            "ct": 467,
            "alert": "none",
            "colormode": "hs",
            "reachable": true
        },
        "type": "Extended color light",
        "name": "Hue Lamp 3",
        "modelid": "LCT001",
        "uniqueid": "00:17:88:01:00:b9:38:5c-0b",
        "swversion": "66009663",
        "pointsymbol": {
            "1": "none",
            "2": "none",
            "3": "none",
            "4": "none",
            "5": "none",
            "6": "none",
            "7": "none",
            "8": "none"
        }
    }
}

Request Name:  Change the state of Light

http://10.0.2.16/api/newdeveloper/lights/1/state

Code Block
titleGet Lights JSON
linenumberstrue
{"on":true}

Write a ThingFacet, Workflow and Device Logic (Message Transformation)

Write a ThingFacet 

To abstract the interactions with the Philip Light Bulbs, we create a PhilipLightFacet ThingFacet. 

Expand
titleThingFacet
Info Include PageThingFacetsThingFacets

Go to page

We add two types of attributes in this ThingFacet

  1. Parameters required to make a protocol specific invocation 

 

Attributes to store the information received from the light. 

There are two important patterns to look for:
Mapping of Device Vendor Complex Structure: The response from GetLights is a complex hierarchical response.
Helper Tags: Tags that are helpful in simplifying long name as well as parameterizing the Protocol Parameters instead of attributes of a ThingFacet

 

Let's create Types (Def) to match to the response structure of Lights REST API

Code Block
languagexml
titlePhilipLightState Definition
linenumberstrue
<Def Name="PhilipLightState">
  <Boolean Name="On"/>
  <Integer Name="bri"/>
  <Integer Name="hue"/>
  <Integer Name="sat"/>
  <String Name="effect"/>
  <Double Name="xy" cardinality="2"/>
  <Integer Name="ct"/>
  <String Name="alert"/>
  <String Name="colormode"/>
  <Boolean Name="reachable"/>
</Def>

Helper Tag - 1: Simply define the Philip Light Bridge API URL using PhilipLightBaseURI Tag

Code Block
languagexml
titlePhilipLightBaseURI Tag
linenumberstrue
<PhilipLightBaseURI>http://10.0.2.16/api/newdeveloper</PhilipLightBaseURI>

Lets now create a ThingFacet using the PhilipLightState type and rest of the parameters like - Type, modelId, etc as parameters of the PhilipLightFacet ThingFacet. Now the entire ThingFacet definition maps to the exact Response of the GetLight structure.

Helper Tag - 2: Tag AA to designate Event.Argument

Code Block
languagexml
titlePhilipLightBaseURI Tag
linenumberstrue
 <ThingFacet Name="PhilipLightFacet">
  <String Name="LightNumber"/>
  <PhilipLightState Name="State"/>
  <String Name="Type"/>
  <String Name="modelid"/>
  <String Name="uniqueid"/>
  <String Name="swversion"/>
  <!-- Helper Tag -->
  <AA>[:#o#Event.Argument:]</AA>
 </ThingFacet>

Write a Action with Workflow

The next step in ThingFacet is writing a Action which contains a workflow responsible for making external protocol specific call and store the output in the appropriate ThingFacet attribute.  An important decision while writing Action is correct protocol selection. See the /wiki/spaces/TQLDocs/pages/1179871 in the Working with Things section. For this Philip Light we need simple HTTP request, which is part of the TQLEngine.

1. Write an Action name as PhilipLightAction

Go to page

Code Block
languagexml
titlePhilipLightAction
linenumberstrue
<ThingFacet Name="PhilipLightFacet">
	...
	<Action Name="PhilipLightAction">
		...
	</Action>
</ThingFacet>
Expand
titleAction
Info
Include Page
ActionsActions

 

2. Create a Workflow within the Action, with one single continuous running Task and waiting for the Event with its ActionArgument.

Go to page

expandinfo

Go to page

<Action
Expandcode
titleWorkflow
Info
Include Page
WorkflowsWorkflows
languagexml
titleWorkflow structure
linenumbers
Include Page
Structure of a workflowStructure of a workflow
Code Block
languagexml
titleWorkflow
linenumberstrue
true
<Action Name="PhilipLightAction">
	<Workflow Limit="1" Live="1" Timeout="-1">
    	<Task name="Main" while="true">
        	<Event name="Argument" as="ActionArgument"/>
			...
    	</Task>
	</Workflow>
</Action>

Here we used three modifiers for this workflow. Limit = "1" means there can be at most one instance of this workflow waiting. Live = "1" means there can be at most one instance of this workflow running. Timeout ="-1" means this workflow will never be timed out. We used a modifier while = "true" with the Task to make the workflow running in a continuous loop, because it needs to run repeatedly, not just once. For more details, refer to workflow modifiers and the lifecycle of a workflow.

The task will be activated by the event handler Event called ActionArgument. "ActionArgument" is the event generated whenever the attribute(s) associated with this Action is modified (See Associate Action with a ThingFacet Attribute). ActionArgument carries all the current values of the ThingFacet attributes, which can be used in the task if needed.

 

Expand
titleActionArgument
Info Include PageActionArgumentActionArgumentGo to page

3. Invoke HTTP call: Method of HTTP is PUT. We use Invoke modifier Put for this purpose. The parameters required for HTTP PUT are passed as part of <Message> and <Value>.

Note that: xmlns="something" is added to disable tag normalization. Tag normalization is performed any time an XML (or JSON) text is converted into a ListMap structure. To prevent normalization you can specify a non-default XML namespace on the element you want normalization to be disabled. Example: <Message xmlns="PLight" to disable normalization for the whole query).

Code Block
languagexml
titleInvoke HTTP Handler
linenumberstrue
<Invoke Name="SetState" waitFor="ActionArgument" Put="[:PhilipLightBaseURI:]/lights/[%:[:AA:].LightNumber.Value:%]/state">
  <Message xmlns="PLight" Type="json">
    <on_true>
      <on>true</on>
    </on_true>
    <on_false>
      <on>false</on>
    </on_false>
    <Value>
      <Include>[:@WFRT:]on_[%:[:AA:].state.On.Value:%]</Include>
    </Value>
  </Message>
</Invoke>

Note that PhilipLightBaseURI is referenced using TP tag: [:PhilipLightBaseURI:] The notation [%: is part of the /wiki/spaces/TEACH/pages/21170773. More details on /wiki/spaces/TEACH/pages/21170773 can be found in the Developer's Guide.

TagResolution
[:PhilipLightBaseURI:]
http://10.0.2.16/api/newdeveloper
[:AA:]
Event.Argument
[%:[:AA:].LightNumber.Value:%]
Runtime value of structure: Event.Argument.LightNumber.Value
<on_true> and <on_false>contains <on>true</on> and <on>false</on>; this is stop gap to avoid string to boolean conversion in TP
[:@WFRT:]

Delay processing of Tags at Workflow execution time. Note the TQLEngine goes through number of

processing / pre-processing phases. Prefixing it with WFRT tells the Engine to delay resolving the Tags until

the execution of the workflow

[%:[:AA:].state.On.Value:%]
Runtime value of structure: Event.Argument.state.On.Value
<Include>[:@WFRT:]on_[%:[:AA:].state.On.Value:%]</Include>Includes the content of either <on_true> or <on_false>


4. Process the message received from the Philip Light Bridge

Code Block
languagexml
titleMessage parsing using TP and XPath
<Output name="Result" as="ActionResult">
   <Value>
     <State>
        <On>[%:[:AA:].state.Value:%]</On>
     </State>
  </Value>
</Output>

 

Anchor
Associate Action with a ThingFacet Attribute
Associate Action with a ThingFacet Attribute

Associate Action with a ThingFacet Attribute

We will now have to associate a ThingFacet Attribute (State) with the Action using the KnownBy modifier. When State is "KnownBy" PhilipLightAction, any State value changes will activate the PhilipLightAction.

Actionable attributes

Go to page

Code Block
languagexml
titleAttribute State tied to Action
linenumberstrue
<ThingFacet Name="PhilipLightFacet">
	...
    <PhilipLightState Name="State" KnownBy="PhilipLightAction"/>
</ThingFacet>
Expand
title
Info
Include Page
Actionable attributesActionable attributes

The attribute modifier update= "auto" makes sure that once the action associated with this attribute is triggered, its workflow continues to run and wait for subsequent sensor events (not just the first event). This modifier is only used with actionable attributes. For more details, refer to Automatic Action trigger.

Combining ThingFacet with a ThingModel

Finally, in order to use ThingFacet we have to combine it with a ThingModel. We define ThingModel to contain only a unique system identifier.

Go to page

Go to page
Code Block
languagexml
titleThingModel PhilipLightModel
linenumberstrue
 <ThingModel Name="PhilipLightModel" Combines="PhilipLightFacet">
 <Sid Name="LightId"/>
</ThingModel>
Expand
titleModels
Info
Include Page
ModelsModels
Expand
titleThingModels
Info
Include Page
ThingModelsThingModels

 

PhilipLightFacet can only be instantiated (and write TQL Queries) when it is combined with PhilipLightModel. PhilipLightModel will inherit all the attributes from PhilipLightFacet, in addition to its own attributes. The ThingFacet PhilipLightFacet hence serves as a reusable component.

More details on the use of "combines" can be found here. Information on Sid can be found here.

Initializing Lights

Typically ThingModels are instantiated by writing external Create or Save Queries. In this case the Lights data is itself coming from another Provider API. Number of device vendors follow the pattern of providing metadata loading APIs. This is a common approach. In PhilipLight example, we can load PhilipLightModel data by invoking HTTP Get on Lights. Let's create another ThingFacet and ThingModel for the purpose of loading the data. We also have to call the Create Query within the ThingFacet.

The building blocks to Loading Lights are:

  • Ability to run Create TQL Query from ThingFacet
  • Ability to Load lights at any given time

TQLEngine allows us to run TQL Queries from the Model itself using <OnRequest> Tag. We need to provide the Target ID to make this request. Since queries can be called any number of times, it is always a good idea to wrap calling of a TQL Query in a generic Macro Definition. Let's call this ExecuteQuery.

Generic Macro to Execute a TQL Query

Code Block
languagexml
titleMacro Definition to run any Query
linenumberstrue
<Macro Name="ExecuteQuery">
   <Argument>
     <QueryString>
       <Query/>
     </QueryString>
    </Argument>
    <Result>
      <OnRequest>
        <Target>[:RuntimeParams.FacetIDName:]</Target>
         <Process>
           <Message>
             <Value>[:$Macro.Argument.QueryString:]</Value>
           </Message>
         </Process>
       </OnRequest>
    </Result>
</Macro>

Macro to Create Light

Since creating of light can be called multiple times, we can wrap the creating of Light itself in another Macro definition called AddLight. In AddLight we can in turn use ExecuteQuery Macro.

Code Block
languagexml
titleAddLight Macro
linenumberstrue
<Macro Name="AddLight">
      <Argument>
        <LightNumber/>
        <On/>
        <bri/>
        <hue/>
        <sat/>
      </Argument>
      <Result>
        <ExecuteQuery>
          <QueryString>
            <DeleteAll>
              <PhilipLightModel>
                <LightNumber Eq="[:$Macro.Argument.LightNumber:]"/>
              </PhilipLightModel>
            </DeleteAll>
            <Create>
              <PhilipLightModel>
                <LightNumber>[:$Macro.Argument.LightNumber:]</LightNumber>
                <State>
                  <On>[:$Macro.Argument.On:]</On>
                  <bri>[:$Macro.Argument.bri:]</bri>
                  <hue>[:$Macro.Argument.hue:]</hue>
                  <sat>[:$Macro.Argument.sat:]</sat>
                </State>
              </PhilipLightModel>
            </Create>
          </QueryString>
        </ExecuteQuery>
      </Result>
</Macro>

ThingFacet to Load Lights

We need a trigger mechanism to load the lights. For this purpose we can write another PhilipLightManagerFacet ThingFacet with an LoadLightsAction Action against a LoadLights Attribute. This ThingFacet is similar to any other ThingFacet except that the Invoke is to the AddLight Macro using FacetScript.

Code Block
languagexml
titlePhilipLightManagerFacet
linenumberstrue
<ThingFacet Name="PhilipLightManagerFacet">
      <String Name="LoadLights" KnownBy="LoadLightsAction"/>
      <Action Name="LoadLightsAction">
        <Workflow Limit="1" Live="1" Timeout="-1">
          <Task Name="Main" While="True">
            <Event Name="Argument" As="ActionArgument"/>
            <Invoke Name="GetLights" waitFor="ActionArgument" Get="[:PhilipLightBaseURI:]/lights"/>
            <Log Message="Lights Loaded...[:Invoke.GetLights.Message.Value:]"/>
            <Invoke Name="ParseGetLightsResult">
              <FacetScript>
                <AddLight>
                  <LightNumber>1</LightNumber>
                  <On>[:Invoke.GetLights.Message.Value.1.State.On:]</On>
                  <bri>[:Invoke.GetLights.Message.Value.1.State.bri:]</bri>
                  <hue>[:Invoke.GetLights.Message.Value.1.State.hue:]</hue>
                  <sat>[:Invoke.GetLights.Message.Value.1.State.sat:]</sat>
                </AddLight>
                <AddLight>
                  <LightNumber>2</LightNumber>
                  <On>[:Invoke.GetLights.Message.Value.2.State.On:]</On>
                  <bri>[:Invoke.GetLights.Message.Value.2.State.bri:]</bri>
                  <hue>[:Invoke.GetLights.Message.Value.2.State.hue:]</hue>
                  <sat>[:Invoke.GetLights.Message.Value.2.State.sat:]</sat>
                </AddLight>
                <AddLight>
                  <LightNumber>3</LightNumber>
                  <On>[:Invoke.GetLights.Message.Value.3.State.On:]</On>
                  <bri>[:Invoke.GetLights.Message.Value.3.State.bri:]</bri>
                  <hue>[:Invoke.GetLights.Message.Value.3.State.hue:]</hue>
                  <sat>[:Invoke.GetLights.Message.Value.3.State.sat:]</sat>
                </AddLight>
              </FacetScript>
            </Invoke>
            <Output Name="Result" As="ActionResult">
              <Value>
                <LoadLights>True</LoadLights>
              </Value>
            </Output>
          </Task>
        </Workflow>
      </Action>
    </ThingFacet>

Let's combine PhilipLightManagerFacet with a PhilipLightManagerModel.

Code Block
languagexml
titlePhilipLightManagerModel
linenumberstrue
<ThingModel Name="PhilipLightManagerModel" Combines="PhilipLightManagerFacet">
      <Sid Name="ManagerId"/>
</ThingModel>

Query and subscription

Queries we need are:

  • Trigger Loading of Lights using PhilipLightManagerModel
  • Change the state of Light using PhilipLightModel
  • Find the Light and Manager models.

Queries

Code Block
languagexml
titleFind Lights
linenumberstrue
 <Query>
  <Find format="all">
    <PhilipLightModel>
      <LightNumber eq="1"/>
    </PhilipLightModel>
  </Find>
</Query>


Code Block
languagexml
titleGetLightManager
linenumberstrue
<Query>
  <Find format="All">
    <PhilipLightManagerModel>
      <ManagerId ne=""/>
    </PhilipLightManagerModel>
  </Find>
</Query>


Code Block
languagexml
titleInitManager
linenumberstrue
<Query>
  <DeleteAll>
    <PhilipLightManagerModel>
      <ManagerId ne=""/>
    </PhilipLightManagerModel>
  </DeleteAll>
  <Create>
    <PhilipLightManagerModel>
      <LoadLights>
        True
      </LoadLights>
    </PhilipLightManagerModel>
  </Create>
</Query>


Code Block
languagexml
titleToggleLight
linenumberstrue
<Query>
  <Find format="All">
    <PhilipLightModel>
      <LightNumber eq="1"/>
    </PhilipLightModel>
  </Find>
  <SetResponseData>
    <Key>
      Message.Value.Find.Result.PhilipLightModel.state.On.Value
    </Key>
    <Value>
      false
    </Value>
  </SetResponseData>
  <Update>
    <From>
      Result
    </From>
    <Include>
      $Response.Message.Value.Find
    </Include>
  </Update>
</Query>


Code Block
languagexml
titlePhilipLight Complete Model
linenumberstrue
collapsetrue
<Namespace Name="Atomiton">
  <Domain Name="Lights">
    <PhilipLightBaseURI>http://10.0.2.16/api/newdeveloper</PhilipLightBaseURI>
    <Def Name="PhilipLightState">
      <Boolean Name="On"/>
      <Integer Name="bri"/>
      <Integer Name="hue"/>
      <Integer Name="sat"/>
      <String Name="effect"/>
      <Double Name="xy" cardinality="2"/>
      <Integer Name="ct"/>
      <String Name="alert"/>
      <String Name="colormode"/>
      <Boolean Name="reachable"/>
    </Def>

    <Macro Name="ExecuteQuery">
      <Argument>
        <QueryString>
          <Query/>
        </QueryString>
      </Argument>
      <Result>
        <OnRequest>
          <Target>[:RuntimeParams.FacetIDName:]</Target>
          <Process>
            <Message>
              <Value>[:$Macro.Argument.QueryString:]</Value>
            </Message>
          </Process>
        </OnRequest>
      </Result>
    </Macro>

    <Macro Name="AddLight">
      <Argument>
        <LightNumber/>
        <On/>
        <bri/>
        <hue/>
        <sat/>
      </Argument>
      <Result>
        <ExecuteQuery>
          <QueryString>
            <DeleteAll>
              <PhilipLightModel>
                <LightNumber Eq="[:$Macro.Argument.LightNumber:]"/>
              </PhilipLightModel>
            </DeleteAll>
            <Create>
              <PhilipLightModel>
                <LightNumber>[:$Macro.Argument.LightNumber:]</LightNumber>
                <State>
                  <On>[:$Macro.Argument.On:]</On>
                  <bri>[:$Macro.Argument.bri:]</bri>
                  <hue>[:$Macro.Argument.hue:]</hue>
                  <sat>[:$Macro.Argument.sat:]</sat>
                </State>
              </PhilipLightModel>
            </Create>
          </QueryString>
        </ExecuteQuery>
      </Result>
    </Macro>

    <ThingFacet Name="PhilipLightFacet">
      <String Name="LightNumber"/>
      <PhilipLightState Name="State" KnownBy="PhilipLightAction"/>
      <String Name="Type"/>
      <String Name="modelid"/>
      <String Name="uniqueid"/>
      <String Name="swversion"/>
      <!-- Helper Tags -->
      <AA>[:#o#Event.Argument:]</AA>
      <Action Name="PhilipLightAction" Documentation="Set the state of the Light (true/false)">
        <Workflow Limit="1" Live="1" Timeout="-1">
          <Task name="Main" While="True">
            <Event name="Argument" as="ActionArgument"/>
            <Invoke Name="SetState" waitFor="ActionArgument" PUT="[:PhilipLightBaseURI:]/lights/[%:[:AA:].LightNumber.Value:%]/state">
              <Message xmlns="PLight" Type="json">
                <on_true>
                  <on>true</on>
                </on_true>
                <on_false>
                  <on>false</on>
                </on_false>
                <Value>
                  <Include>[:@WFRT:]on_[%:[:AA:].state.On.Value:%]</Include>
                </Value>
              </Message>
            </Invoke>
            <Output name="Result" as="ActionResult">
              <Value>
                <State>
                  <On>[%:[:AA:].state.On.Value:%]</On>
                </State>
              </Value>
            </Output>
          </Task>
        </Workflow>
      </Action>
    </ThingFacet>

    <ThingFacet Name="PhilipLightManagerFacet">
      <String Name="LoadLights" KnownBy="LoadLightsAction"/>
      <Action Name="LoadLightsAction">
        <Workflow Limit="1" Live="1" Timeout="-1">
          <Task Name="Main" While="True">
            <Event Name="Argument" As="ActionArgument"/>
            <Invoke Name="GetLights" waitFor="ActionArgument" Get="[:PhilipLightBaseURI:]/lights"/>
            <Log Message="Lights Loaded...[:Invoke.GetLights.Message.Value:]"/>
            <Invoke Name="ParseGetLightsResult">
              <FacetScript>
                <AddLight>
                  <LightNumber>1</LightNumber>
                  <On>[:Invoke.GetLights.Message.Value.1.State.On:]</On>
                  <bri>[:Invoke.GetLights.Message.Value.1.State.bri:]</bri>
                  <hue>[:Invoke.GetLights.Message.Value.1.State.hue:]</hue>
                  <sat>[:Invoke.GetLights.Message.Value.1.State.sat:]</sat>
                </AddLight>
                <AddLight>
                  <LightNumber>2</LightNumber>
                  <On>[:Invoke.GetLights.Message.Value.2.State.On:]</On>
                  <bri>[:Invoke.GetLights.Message.Value.2.State.bri:]</bri>
                  <hue>[:Invoke.GetLights.Message.Value.2.State.hue:]</hue>
                  <sat>[:Invoke.GetLights.Message.Value.2.State.sat:]</sat>
                </AddLight>
                <AddLight>
                  <LightNumber>3</LightNumber>
                  <On>[:Invoke.GetLights.Message.Value.3.State.On:]</On>
                  <bri>[:Invoke.GetLights.Message.Value.3.State.bri:]</bri>
                  <hue>[:Invoke.GetLights.Message.Value.3.State.hue:]</hue>
                  <sat>[:Invoke.GetLights.Message.Value.3.State.sat:]</sat>
                </AddLight>
              </FacetScript>
            </Invoke>
            <Output Name="Result" As="ActionResult">
              <Value>
                <LoadLights>True</LoadLights>
              </Value>
            </Output>
          </Task>
        </Workflow>
      </Action>
    </ThingFacet>

    <ThingModel Name="PhilipLightModel" Combines="PhilipLightFacet">
      <Sid Name="LightId"/>
    </ThingModel>

    <ThingModel Name="PhilipLightManagerModel" Combines="PhilipLightManagerFacet">
      <Sid Name="ManagerId"/>
    </ThingModel>
  </Domain>
</Namespace>