PnP-X Simple Thermostat Sample

Last Updated: February 2009

 

Demonstrates

This sample demonstrates an end-to-end scenario using PnP-X. It includes device samples using UPnP and WSD, a driver to install the devices in PnP, proxies to talk with the devices, and a client application that uses the devices through the proxies. Developers will find this sample useful when implementing end-to-end scenarios using PnP-X or just implementing a small portions of a scenario, like a PnP-X compliant device.

This sample uses the following technologies: PnP-X, Function Discovery (FD), Web Services on Devices (WSD), Universal Plug and Play (UPnP), and Windows Plug and Play (PnP).

The following diagram shows how all the parts of the scenario fit together from a process perspective. The brown colored components are the components this sample contains and the blue colored components are built into Windows (Vista and later). The names of brown components directly correspond to the Visual Studio projects in the sample.  The numbers on the arrows correspond to  the steps involved in running the scenario (see 'Running the Sample' further down in this document).

Windows 7 Notes:

The new way to pair a device in Windows 7 is via Devices and Printers' Add a device wizard instead of the Network folder.  Start Menu -> Devices and Printers -> Add a device.  For this sample, when you see the Network folder referred to, you can replace that with the 'Add a device' wizard.  Further, PnP-X devices will be shown (and can be managed) from Devices and Printers after they have been paired and installed.

 

Scenario Diagram 

 

Prerequisites

 

Languages

C++

 

Folders and Files

  1. \
    1. readme.htm - This file.
    2. scenario.jpg - Diagram showing the scenario layout from a process perspective.
    3. SimpleThermostat.sln - Visual Studio 2008 solution file. This solution file encapsulates all the projects for this sample. Each folder under the root defines a project and contains a Visual Studio project file.
  2. SimpleThermostatClient\
    1. main.cpp - Implements a client application that uses ISimpleThermostat devices.
  3. SimpleThermostatDriver\
    1. SimpleThermostat.inf - INF file used when installing the sample devices.
  4. SimpleThermostatInterface\
    1. SimpleThermostat.idl - Defines ISimpleThermostat.  ISimpleThermostat is the interface this sample revolves around: from devices supporting ISimpleThermostat functionality to the client that uses ISimpleThermostat. 
  5. SimpleThermostatProxy\
    1. common.h - Common header used by all source files in this project.
    2. CSimpleThermostatProviderFactory.h - Defines the CSimpleThermostatProviderFactory class.
    3. CSimpleThermostatServiceProvider.h - Defines the CSimpleThermostatServiceProvider class.
    4. CSimpleThermostatProviderFactory.cpp - Implements the CSimpleThermostatProviderFactory class which is used to create CSimpleThermostatServiceProvider objects.
    5. CSimpleThermostatServiceProvider.cpp - Implements the CSimpleThermostatServiceProvider class which is used by FD to create the device proxies.
    6. dllmain.cpp - Standard functions needed to implement and register the dll.
    7. helpers.cpp - Helper functions used by CSimpleThermostatServiceProvider.
    8. SimpleThermostatProxy.def - Defines the exports for the dll.
    9. SimpleThermostatProxy.idl - Defines the type library and CoClass for the SimpleThermostatProxy.
  6. UPnP\UPnPSimpleThermostatDevice\
    1. main.cpp - Implements control code for the UPnP device.
  7. UPnP\UPnPSimpleThermostatDeviceDLL\
    1. common.h - Common header used by all the source files in this project.
    2. CSimpleThermostatDevice.h - Defines the CSimpleThermostatDevice class.
    3. CSimpleThermostatDeviceFactory.h - Defines the CSimpleThermostatDeviceFactory class.
    4. CSimpleThermostatService.h - Defines the CSimpleThermostatService class.
    5. CSimpleThermostatDevice.cpp - Implements the CSimpleThermostatDevice class which is the core UPnP device class. This is the object that will be registered with the UPnPHost.
    6. CSimpleThermostatDeviceFactory.cpp - Implements the CSimpleThermostatDeviceFactory class which is used to create CSimpleThermostatDevice objects.
    7. CSimpleThermostatService.cpp - Implements the CSimpleThermostatService class which is the service for the UPnP device. This service contains the ISimpleThermostat functionality.
    8. dllmain.cpp - Standard functions needed to implement and register the dll.
    9. SimpleThermostatDevice.def - Defines the exports for the dll.
    10. SimpleThermostatDevice.idl - Defines the type library, coclass, and service interface for the UPnP device.
    11. SimpleThermostatDevice.xml - Description document for the UPnP device. Defines the metadata for the device.
    12. SimpleThermostatService.xml - Description document for the UPnP service. Defines the metadata for the service.
  8. UPnP\UPnPSimpleThermostatProxy\
    1. CUPnPSimpleThermostatProxy.h - Defines the CUPnPSimpleThermostatProxy class.
    2. CUPnPSimpleThermostatProxy.cpp - Implements the CUPnPSimpleThermostatProxy class which is used by client applications to communicate with the device's service. This class exposes ISimpleThermostat to the client, which then knows how to talk with the device using protocol specific commands.
  9. WSD\WSDSimpleThermostatContract\
    1. codegen.config - WsdCodeGen configuration file. This file essentially describes everything about the WSD device. WsdCodeGen can consume this file to auto generate C++ code that implements the device.
    2. SimpleThermostat.wsdl - WSDL file used by WsdCodeGen to create a template codegen.config file.
  10. WSD\WSDSimpleThermostatDevice\
    1. CSimpleThermostatService.h - Defines the CSimpleThermostatService class.
    2. CSimpleThermostatService.cpp - Implements the CSimpleThermostatService class which is the service for the WSD device. This service contains the ISimpleThermostat functionality.
    3. main.cpp - Implements the control code for the WSD device.
  11. WSD\WSDSimpleThermostatGenerated\
    1. SimpleThermostat_WSDProxy.h - GENERATED by WsdCodeGen. Defines the CSimpleThermostat_WSDProxy class.
    2. SimpleThermostat_WSDTypes.h - GENERATED by WsdCodeGen. Defines all the custom types used by the device, proxy, and stub.
    3. SimpleThermostat_WSD.idl - GENERATED by WsdCodeGen. Defines the WSD protocol specific version of the ISimpleThermostat interface: ISimpleThermostat_WSD.
    4. SimpleThermostat_WSDProxy.cpp - GENERATED by WsdCodeGen. Implements the CSimpleThermostat_WSDProxy class, which is used by the CWSDSimpleThermostatProxy class. 
    5. SimpleThermostat_WSDStub.cpp - GENERATED by WsdCodeGen. Implements the stub code for the device's service.
    6. SimpleThermostat_WSDTypes.cpp - GENERATED by WsdCodeGen. Implements the custom types used by the device, proxy, and stub.
  12. WSD\WSDSimpleThermostatProxy\
    1. CWSDSimpleThermostatProxy.h - Defines the CWSDSimpleThermostatProxy class.
    2. CWSDSimpleThermostatProxy.cpp - Implements the CWSDSimpleThermostatProxy class which is used by the client application to communicate with the device's service. This class exposes ISimpleThermostat to the client, which then knows how to talk with the device using protocol specific commands.

 

Building the Sample (using Visual Studio)

  1. Open SimpleThermostat.sln in Visual Studio.
  2. In the Build menu, select Build Solution. The application will be built in the default \Debug or \Release directory.

 

Building the Sample (from SDK build environment)

  1. Open the SDK command shell.
  2. Navigate to the sample folder where SimpleThermostat.sln is located.
  3. Type vcbuild SimpleThermostat.sln. The application will be built in the default \Debug or \Release directory.

 

Running the Sample

All files can be used from the binplaced location from the build (typically \debug or \release). Note that the driver package is built to support both x86 and x64, so you'll find the driver package in a folder called "DriverPackage".

The step numbers here directly correspond to the arrow labels on the scenario diagram above. As you run the sample you can look at the scenario diagram to better understand what's happening.

  1. Pre-install the Simple Thermostat Driver package.
    1. From the \DriverPackage folder run pnputil -a SimpleThermostat.inf .
    2. A Windows Security dialog will pop-up because the driver is not signed. Click Install this driver software anyway.
    3. After several seconds the driver installation will complete, resulting in SimpleThermostatProxy.dll being copied to <windir>\system32 and being registered as a COM object.
       
  2. Start the simple thermostat devices. You can run one or both of the UPnP and WSD devices.
    1. Run WSDSimpleThermostatDevice.exe.
    2. Run regsvr32 UPnPSimpleThermostatDevice.dll (you must have administrative rights to do this).
    3. Run UPnPSimpleThermostatDevice.exe. Note: If this returns a FILE_NOT_FOUND error (0x80070002) then UPnPHost most likely does not have rights to access the device's description documents. To fix this you need to change permissions on the folder where the description documents are located. From Windows Explorer, right click the folder and click Properties. Click the Security tab and click Edit. Click Add and in the text box type "LOCAL SERVICE". Click OK on all three dialog boxes and rerun the device.
       
  3. Install the devices from the Network folder.
    1. Open the Network folder by clicking Start Menu -> Network.
    2.  After a few seconds you should see the two devices listed in the Network folder. One is named 'UPnP Simple Thermostat' and the other 'WSD Simple Thermostat'.
    3. If for some reason you are unable to see the devices in the list after a short period, have the devices start again. You can perform this by pressing the 'p' key and then the 's' key for each device.
    4. Install each device by double clicking it, or by selecting it and clicking install from the command bar. Windows will ask for your permission to install the device.
       
  4. The IPBusEnum service communicates with the device to get the metadata needed for installation in PnP.
     
  5. The IPBusEnum service installs the device in PnP after several seconds.
     
  6. Find installed ISimpleThermostat devices using the client application.
    1. Run SimpleThermostatClient.exe.
    2. The client asks FD for all the ISimpleThermostat devices in PnP. It should list the two devices you just installed. Select the one you want to use.
       
  7. Use ISimpleThermostat devices using the client application.
    1. After selecting one of the devices the client will attempt to call some of the ISimpleThermostat functions on the device using the SimpleThermostatProxy.dll.
    2. The client will display the name, ID, current temperature setting, and desired temperature of the thermostat device. It will also display a small list of options you can choose from.
    3. From the menu you can refresh device info, make a call to the device to set the desired temperature, or exit the client.

 

Removing the Sample

  1. Before shutting down the devices, select them in the Network folder and click Uninstall from the command bar.
  2. Run regsvr32 -u UPnPSimpleThermostatDevice.dll.
  3. From <windir>\system32 run regsvr32 -u SimpleThermostatProxy.dll.
  4. Find the oemXX.inf file in <windir>\inf that corresponds to SimpleThermostat.inf. The INF file will contain the comment description "INF for WSD and SSDP ISimpleThermostat devices".
  5. Run pnputil -f -d [oemxx.inf file from above]. You do not need the path to the .inf file. (Example: pnputil -f -d oem99.inf).
  6. Delete <windir>\system32\SimpleThermostatProxy.dll.