cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Help us improve the PTC Community by taking this short Community Survey! X

IoT Tips

Sort by:
  Convey information about IoT data effectively by customizing style definitions and implementing event-based logic   Guide Concept   This project will help you identify how you would like to create an experience for Users.   Following the steps in this guide, you will use color schemes to convey information quickly and effectively, for example to alert users of critical events. With ThingWorx Composer, you can implement Styles and States in your Mashups to enhance your user experience.   We will teach you how to create an affective IoT application experience that looks great and easy to navigate. How the UI is presented can influence users and their enjoyment of the application.   You'll learn how to   Create a Style Definition Customize Style Definitions Create and implement State Definitions Implement event-based state changes   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 60 minutes       Step 1: Completed Example   Download the StylesAndStates.xml attached to this guide.  Within this file, you will find Entities referenced in this lesson, including a finished application.  Import and utilize this file to see a finished example and return to it as a reference if you become stuck during this guide and need some extra help or clarification.   Keep in mind, this download uses the exact names for entities used in this tutorial. If you would like to import this example and also create entities on your own, change the names of the entities you create.     Step 2: Create Style Definition   A Style Definition is a collection of HTML styling elements that can be applied to a Widget just as you would apply a CSS definition to an HTML tag. With Style Definitions, you can control the look and feel, such as colors, fonts, and color context of individual Widgets in your Mashup.   In the ThingWorx Composer, click the + New at the top of the screen.   Select Style Definition in the dropdown.   Enter a name for the Style Definition, such as StyleDefinition. Set the Project to an existing Project (ie, PTCDefaultProject).   Click Style Information.   The Style Information page shows the options for images, colors, lines, and display text. See the table below for information on what each field controls.   6. Type PlaygroundBackground in the Display String field.   NOTE: If you go back to the HelloWorldPlayground, clear the Mashup Style property, then search for StyleDefinition again, you will see the PlaygroundBackground descriptive text.   7. Select Background Color. A color pallet will appear. Select White and click Select.   8. Select Text Color. A color pallet will appear. Select Black and click Select.   9. Click Save.     You have now created your first Style Definition. To ensure a consistent user experience, we recommend creating a Style Definition that you can use throughout your application.    Option                                    Description Display String Descriptive string that can be displayed to indicate the current applied style definition Background Color Background for charts, buttons, panels, etc Secondary Background Color Meant for widgets that support gradients Foreground Color Used for foreground characteristics such as button text and label text Font Bold For text, whether the text should be bold or not Font Italic For text, whether the text should be italicized or not Font Underline For text, whether the text should be underlined or not Image Add images Line Color Pen styling in charts Line Thickness Pen styling in charts Line Style Generally refers to borders. ThingWorx provides the following options: Solid, Dashed, Dotted, None Text Size Choose a font size from 9-72px   In the next part of this exercise, you’ll learn how to use Style Definitions to create an engaging experience for your application users.       Step 3: Customize Style Definitions   Open the HelloWorldPlayground Mashup in Composer, and click View Mashup.   It shows a Button that sends an Event to a Gauge Widget, which then updates a Line Chart.     Modify Style Definition   In this part of the lesson, we'll make some changes to this Mashup. We will use Style Definitions to change the background of the Mashup, change the colors used in the Line Chart in order information stand out, and add color to the Gauge Widget.   In the Explorer tab, select the Mashup. Select the Style Properties tab, then click the X button to clear the Style Mashup Properties.   When editing a Mashup, you can either use a Style Definition Thing that you created earlier OR you can click the wand in a style property for a Mashup or Widget followed by clicking the + Custom button to create a one-time-use style. 3. With the Style Property clear, enter the Style Definition you created in the last section. Update the Background Color to #FF9082 to have the color pop in the Mashup.   4. Click Save and View Mashup to see the changes. You have now updated the background for the HelloWorldPlayground. The style properties you define in the Style Definition will be consitent for any Mashup that references this Style Definition. Change the style around or create a custom style and see the changes in the Mashup. Below is what we'll be working to create. Get ideas of things you might want to see differently in your styling.     Customize Widget Style   ThingWorx provides a default Style Definition for many of its Widgets. Before editing the Style Definitions of a Widget, click the Style Definition property then click View. This enables you to see what the current values are and what you might want to change. If the changes are slight, create a copy of the original Style Definition and update the new version.   Until you are sure of the color schemes you would like to implement, use the default Style Definitions as a guide when creating your own versions.   Default Style Definitions   Next, we will update the colors and style of the Line Chart.   Open the HelloWorldPlayground and select the Line Chart in the Workspace pane. Click the Style Properties tab to see the chart styles section.   Update the Legend->Color property to Blue.     Customize Chart Style Theme   In this part of the lesson, we will update the Series1 and StyleTheme properties of the Line Chart. This is how you'll also set the colors for the chart titles.   The Series1 property will update the look and feel of the line for the count value being used. The Line Chart is a line graph, thus the only property you need to change is the Line Color property.   The StyleTheme property will update the background look of the Line Chart grid.   Clear the StyleTheme and click the + button to create a new theme. Create a theme with the name CustomTheme.   Click the Style tab and edit the feel of the items as you see fit.   After open the Style Theme to be editable, click on colors. Here you'll see all the options and fields that you can make up your own color options and be as conservative as you like or as free as you like.     Click Text Colors, then click on the Grids and Lists tab on the right. This is where we will be shaping our colors for the chart. When you're done with this, update the Core Colors section to make your mashup pop even more.     You may also notice a more focused method of updating grids and lists. In the below Elements section, you'll have a more focused experience for updated.     NOTE: As an extension, after completing the previous steps, try to use Style Definitions to customize the sections of the UI on your own.     Click here to view Part 2 of this guide.
View full tip
  Connect a Raspberry Pi to ThingWorx using the Edge Micro Server (EMS).   Guide Concept   This project will introduce you to the Edge MicroServer (EMS) and how to connect your ThingWorx server to a Raspberry Pi device.   Following the steps in this guide, you will be able to connect to the ThingWorx platform with your Raspberry Pi. The coding will be simple and the steps will be very straight forward.   We will teach you how to utilize the EMS for your Edge device needs. The EMS comes with the Lua Script Resource, which serves as an optional process manager, enabling you to create Properties, Services, Events, and Subscriptions for a remote device on the ThingWorx platform.   You'll learn how to   Set up Raspberry Pi Install, configure and launch the EMS Connect a remote device to ThingWorx   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 30 minutes.    Step 1: Setup Raspberry Pi   Follow the setup instructions to get your Raspberry Pi up and running with the Raspberry Pi OS operating system. Ensure that your Pi has a valid Ethernet or Wifi connection. If your Pi is connected to a monitor/keyboard, run ifconfig from the Command Line Interface (CLI) to determine the IP address. If you are connecting remotely, probe your local network to find your Pi using one of these methods to determine the IP address. Log into your Raspberry Pi using the userid/password combination pi/raspberry.   Step 2: Install the EMS Download the MED-61060-CD-054_SP10_Microserver-Linux-arm-hwfpu-openssl-5-4-10-1509.zip attached here directly to the Raspberry Pi, or transfer it using a SFTP application such as WinSCP. After downloading the EMS zip file, unzip the archive in a suitable location on the Pi using the command below. Use the Tab key to automatically complete file names. unzip /MED-61060-CD-054_SP9_Microserver-Linux-arm-hwfpu-openssl-5-4-10-1509.zip After unzipping the distribution, a sub-directory named /microserver will be created inside the parent directory. Verify that microserver directory was created with the command ls -l   Switch into the microserver directory with the command cd microserver The microserver directory includes the following files.        File Name                    Description wsems An executable file that runs the Edge MicroServer luaScriptResource The Lua utility that is used to run Lua scripts, configure remote things, and integrate with the host system     Step 3: Create Application Key   In this step, you will be using the ThingWorx Composer to generate an Application Key. The Application Key will be used to identify the Edge Agent. The Application Key is tied to a user and has the same entitlements on the server.   Using the Application Key for the default User (Administrator) is not recommended. If administrative access is absolutely necessary, create a User and place the user as a member of the SecurityAdministrators and Administrators User Groups.   Create the User the Application Key will be assigned to.   On the Home screen of Composer click + New.   In the dropdown list, click Applications Key.   Give your Application Key a name (ie, MyAppKey). Set the User Name Reference to a User you created.   Update the Expiration Date field, otherwise it will default to 1 day. Click Save.   Step 4: Configure the EMS   The EMS consists of two distinct components that do slightly different things and communicate with each other. The first is the EMS which creates an AlwaysOn™ connection to the ThingWorx server. It binds things to the platform and automatically provides features like file transfer and tunneling.   The second is the Lua Script Resource (LSR). It is used as a scripting language so that you can add properties, services, and events to the things that you create in the EMS. The LSR communicates with your sensors or devices. The LSR can be installed on the same device as the EMS or on a separate device. For example, one LSR can be a gateway and send data from several different things to a single EMS.     Open a terminal emulator for the Raspberry Pi. Change directory to microserver/etc. cd microserver/etc Create a config.json file. EMS comes with two sample config files that can be used as a reference for creating your config.json file. The config.json.minimal file provides minimum and basic options for getting started. The config.json.complete provides all of the configuration options.   Create the config.json file in the etc folder. sudo nano config.json Edit the config.json file ws_servers - host and port address of the server hosting the ThingWorx Platform. If you are using a Developer Portal hosted server, your server hostname is listed on the dashboard. {"host":"<TwX Server IP>", "port":443} http_server - host and port address of the machine running the LSR. In this case it will be your localhost running on the raspberry pi. {"host":"127.0.0.1","port":8080, "use_default_certificate": true,"ssl": false, "authenticate": false} appKey - the application key generated from the ThingWorx server. Use the keyId generated in the previous step "Create Application Key". "appKey":"<insert keyId>" logger - sets the logging level for debugging purposes. Set to log at a DEBUG level. ("level":"INFO"} certificates - for establishing a secure websocket connection between the ThingWorx server and the EMS. A valid certificate should be used in a production environment but for debugging purposes you can turn off validation and allow self signed certificates. {"validate":false, "disable_hostname_validation": true} NOTE: To ensure a secure connection, use valid certificates, encryption and HTTPS (port : 443) protocol for establishing a websocket connection between the EMS and the ThingWorx Platform. 5. Exit and Save. ctrl x   Sample config.json File   Replace host and appKey with values from your hosted server.   { "ws_servers": [{ "host": "pp-2007011431nt.devportal.ptc.io", "port": 443 }], "appkey": "2d4e9440-3e51-452f-a057-b55d45289264", "http_server": { "host": "127.0.0.1", "port": 8080, "use_default_certificate": true, "ssl": false, "authenticate": false }, "logger": { "level": "INFO" }, "certificates": { "validate": false, "disable_hostname_validation": true } }     Click here to view Part 2 of this guide. 
View full tip
  Use the ThingWorx Azure IoT Hub Connector with simulated appliances.   Guide Concept   This project will introduce how to integrate ThingWorx with Azure IoT Hub. The combination of these two platforms extends the ThingWorx utilities to Azure IoT Hub edge devices and allows integration with Azure Blob Storage accounts.   Following the steps in this guide, you will install the ThingWorx Azure IoT Hub Connector and run a simulated Azure device.   We will teach you how to build powerful and scalable IoT applications by integrating ThingWorx and Azure IoT Hub.   You'll learn how to   Install, configure, and run the ThingWorx Azure IoT Hub Connector Import devices that exist in Azure into ThingWorx Connect a simulated Azure device to ThingWorx Foundation server   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 60 minutes       Step 1: Overview Diagram   The ThingWorx Azure IoT Hub Connector maintains a network connection to both an Azure IoT and a ThingWorx Foundation instance:        The ThingWorx Azure IoT Hub Connector enables remote devices that connect to the Azure IoT Hub, to connect to the ThingWorx Foundation server. The Azure IoT Connector handles message routing for the devices that communicate through the Azure IoT system. It also handles message routing from the ThingWorx Foundation server to devices via the Azure IoT Hub.   The ThingWorx Azure IoT Connector is a separate, stand-alone application that must be run on a server that can connect to both the ThingWorx server and the Azure IoT service.     Step 2: Configure Azure IoT Hub   In order to use the ThingWorx Azure IoT Connector, you must first configure an IoT Hub and a storage account in Microsoft Azure. You can provision a free tier account for these resources. In this step, we will create the Azure resources and gather the configuration information that enable you to connect to ThingWorx with the required credentials.   Log into Azure Portal   If you do not already have an Azure account you can create a free account that will work with this guide.   Create Azure IoT Hub   Follow the Microsoft documentation to create an Azure IoT Hub, accepting any defaults.   TIP: The name your IoT Hub must be globally unique and include only lowercase letters and numbers.   1. Create message routes to direct DeviceLifecycleEvents and TwinChangeEvents events to the built-in events endpoint. For a tutorial, refer to Tutorial: Use the Azure CLI and Azure portal to configure IoT Hub message routing 2. Register at least one Azure IoT Device or Azure IoT Edge Device to your Azure IoT Hub. For a tutorial, refer to Register an IoT Edge device in IoT Hub     Create Storage Account   Follow the Microsoft documentation to create an Azure Storage account.   NOTE: Select Blob storage as the account type and the Hot Access Tier.       Step 3: Import Extensions   The ThingWorx Azure IoT Hub Connector distribution bundle comes packaged with all the software you will need to connect ThingWorx and Azure. Download the Azure IoT Hub Connector from PTC Support Extract the application bundle to a directory on the system where it will run. (where v.v.v represents the release number) On Linux, this guide uses the base directory, /opt. The subdirectories and files should reside in the directory, /opt/ThingWorx-Azure-IoTHub-Connector-4.2.0. On Windows, extract the bundle so that the subdirectories and files reside in C:\ThingWorx-Azure-IoT-Hub-Connector-4.2.0 In the lower-left side of Composer, click Import/Export, then Import.  In the Import From File pop-up, under Import Option select Extension from the drop-down, then click Browse. Navigate to the /extensions directory and click on ConnectionServicesExtension-2.2.4.zip file.   Click Import in the Import From File pop-up, then click Close after file is successfully imported. Repeat the above steps for the azure-iot-hub-adapter-extension-4.2.0.4.zip file. Follow the steps to Create an Application Key and note the value, it will be used in the the next step.     Step 4: Install Azure Connector   Configure Connection Server   The Connection Server component of ThingWorx Azure IoT Connector must be configured with information specific to both your Azure IoT Hub and your ThingWorx Foundation server.   Copy the file azure-iot-sample.conf in the connector > conf directory and save the file with the name azure-iot.conf Edit the configuration file to replace the ten placeholder values for the parameters listed below with values copied from your Azure control panel. consumerPolicyName - Whether you have a new or existing hub, you need to provide the name of the consumer policy and its related Primary or Secondary key. The policy to select is typically the built-in, pre-defined policy called service. Navigate to All Resources > your hub > Settings > Shared access policies > service. If you added a custom service policy to your hub with the permission service connect select that policy.   consumerPolicyKey - Once you find the policy name, stay in the Shared access policies screen, and click the name. Copy the content of the Primary key. This key supplies the credentials to access services that are specified in the related policy. registryPolicyName - Specify a policy name that is related to the registryPolicyKey. This policy is typically a built in, predefined policy called registryReadWrite, but it is possible to use a custom policy if you add it to your hub. The shared access policy requires the registry read and registry write permissions. registryPolicyKey - The key that supplies credentials to access services in the policy specified in registryPolicyName. hubName - A name that defines the Azure IoT Hub related to this ThingWorx Connector. This Azure IoT Hub manages your things and their related messages. Hubs can be scaled via hub units at different price tiers per unit. Hubs are related to a resource group, which is related to a subscription Id and a cloud Location. TIP: To find the name associated with your Azure IoT Hub that the ThingWorx Connector will use to communicate with it, navigate to All Resources > your hub > Settings > Properties > NAME eventHubName - The Event Hub-compatible name that is used by SDKs and integrations that expect to read from Event Hubs. An Event Hub is an internal component of an Azure IoT Hub that handles device-to-cloud events for related things. In many cases, the IoT Hub name and Event Hubcompatible name are the same, so this property defaults to the Azure IoT Hub name (hubName). Navigate to All Resources > your hub > Settings > Built-in endpoints > Events > Event Hub-compatible name to find this name.   eventHubNamespace - To find the endpoint that is used by SDKs and integrations that expect to read from Event Hubs, navigate to All resources > your hub > Settings > Built-in endpoints > Events > Event Hub-compatible endpoint, and copy the host name, without the rest of the address (".servicebus.windows.net"). The ThingWorx Azure IoT Connector uses this endpoint to read messages from your hub. consumerGroup - To find a consumer group name to enable the Connector to pull data from the Azure IoT Hub, navigate to All Resources > your hub > Messaging > Endpoints > Built-in endpoints > Events > Consumer groups. To use the $Default consumer group, set this property to null. hubHostname - To find the host name for your hub, navigate to All Resources > your hub > Overview > Hostname. The host name is defined by the hubName plus a domain name that is chosen by Azure, typically azuredevices.net.   blob-storage.account-name - The blob-storage section specifies the settings for an Azure blob storage account. The storage provides containers that are used for device export of an Azure IoT Hub to ThingWorx via the Connector and can also be created by the Connector if you create AzureStorageContainerFileRepository things in ThingWorx. If you do not have one, create a Storage Account in the Azure portal. To find the name of an existing account, navigate to Settings > Access Keys > Storage account name.   blob-storage.account-key - The key to associate with the name of the blob storage account. To find the key for an existing account, navigate to Settings > Access Keys > Primary or secondary key Enter your ThingWorx Foundation server host, port, and appKey  in the transport.websockets section. transport.websockets { app-key = "6d70dfca-fe88-4d8c-83aa-686449b52cb2" platforms = "ws://45.23.12.112:80/Thingworx/WS" }   NOTE: If you are using an SSL connection to your ThingWorx Foundation server use wss in place of ws in the platform parameter. If the URL for the ThingWorx Foundation server does not include a port, use 80 for http connections and 443 for https.       Step 5: Launch IoT Hub Connector   Open a shell or a command prompt window. On a Windows machine, open the command prompt as Administrator. The AZURE_IOT_OPTS environment variable must be set before starting the Azure IoT Hub Connector. Below are sample commands using the default installation directory. On Windows: set AZURE_IOT_OPTS=-Dconfig.file=C:\ThingWorx-Azure-IoT-Connector-<version>\azure-iot-<version>-application\conf\azure-iot.conf -Dlogback.configurationFile=C:\ThingWorx-Azure-IoT-Connector-<version>\azure-iot-<version>-application\conf\logback.xml On Linux: export AZURE_IOT_OPTS="-Dconfig.file=/var/opt/ThingWorx-Azure-IoT-Connector-<version>/azure-iot-<version>-application/conf/azure-iot.conf -Dlogback.configurationFile=/var/opt/ThingWorx-Azure-IoT-Connector-<version>/azure-iot-<version>-application/conf/logback.xml" NOTE: You must run the export command each time you open a shell or command prompt window. Change directories to the bin subdirectory of the Azure IoT Hub Connector installation. Start the Azure IoT Hub Connector with the appropriate command for your operating system. On Windows: azure-iot.bat On Linux: /azureiot NOTE: On Windows you may have to shorten the installation directory name or move the bin directory closer to the root directory of your system to prevent exceeding the Windows limit on the classpath length.   The Connection Server should start with no errors or stack traces displayed. If the program ends, check the following: Java version is 1.8.0, update 92 or greater and is Java(TM) not OpenJDK. Open azure-iot.conf and confirm ThingWorx Foundation is set to the correct URL and port. Confirm the platform scheme is ws if http is used to access ThingWorx. Confirm all Azure credentials are correct for your Azure account. In ThingWorx Foundation click the Monitoring tab then click Connection Servers. You should see a server named azure-iot-cxserver-{server-uuid}, where {server-uuid} is a unique identifier that is assigned automatically to the server.       Step 6: Import Device from Azure   With the ThingWorx Azure IoT Connector, you can import into ThingWorx any existing devices that are currently provisioned to the Azure IoT Hub.   Add Device Azure IoT Hub   If you have not provisioned any devices to your Azure IoT Hub you can learn more about Azure IoT Hub device identity before following the steps below to create a test device.   In your Azure Portal, click All Resources, then select the name of your IoT Hub. Under Explorers click IoT devices, then click + Add. Enter a name for your device, then click Save. When the device name appears in the list it is ready to use.   Import Device into ThingWorx   We will manually execute a service in ThingWorx that will import Azure IoT Hub devices into ThingWorx.   In ThingWorx Composer, navigate to the ConnectionServicesHub Thing. Click Services tab and scroll to the ImportAzureIotDevices service and click the execute Arrow. NOTE: The * in the pattern field will act as a wildcard and import all devices, you can enter a string to match that will only import a subset of all available devices. Click Execute to import the devices then click Done. Click Things in the left column to see the Things that were created.   Click here to view Part 2 of this guide.
View full tip
  Utilize the Menu Widget to navigate between multiple Mashups.   Guide Concept   Frequently, your application needs to display more information than can comfortably fit on a single page, but manually linking to multiple Mashups can be tedious.   Instead, you can utilize a Menu Entity, Menu Widget, and a Master Mashup to provide consistent navigation between all the pages of your application.      You'll learn how to   Create a Mashup to be used as a "Home" page Create more Mashups as subpages Create a Menu Entity to track Mashups Create a Master Mashup as a Header Utilize a Menu Widget for navigation   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 30 minutes     Step 1: Scenario   In this guide, we'll assume a scenario where you're an application designer for LightCo, a company that designs and sells smart, connected street, interior, and other lighting products.    In particular, LightCo is interested in using ThingWorx Foundation to operate and control lighting for industrial and city applications.    There's a tentative deal in the works with a city park replacing all their path lighting with high-efficiency models. There's also an outdoor amphitheater in the park that could be added to the deal if the functionality to properly control it is present.     LightCo's intention is to use Foundation to provide a level of control for this application that otherwise wouldn't be possible, as a differentiator versus the competition bidding on the same project.   Since control of both the park-lighting and amphitheater lighting needs to be separate, putting both controls on the same Mashup page would not only be counterintuitive but could possibly lead to errors.    So, in this guide, we'll setup our base page layout for this lighting application. We'll create both a homepage (where we could add login or other elements), as well as separate pages for the park vs the amphitheater. We'll then create a Master Mashup with a Menu for easy navigation between these three initial pages.       Step 2: Create Home Page   First, we want to create a Mashup to represent our homepage.    There doesn't have to be much to it, as we could come back later to develop it further. We just need it to be pre-created to later include it in our Menu.    In Foundation, click Browse > Visualization > Mashups.   At the top-left, click +New.   Leave the defaults and click OK.   In the Name field, type MNWM_Homepage_Mashup. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Save.   At the top, click Design.     Homepage Layout   As mentioned, we don't really want to design our final Homepage right now. Instead, we're simply getting it started to leave ourselves a relatively blank canvas that we can utilize later.    Still, we need to add something. If nothing else, we need something that we can see so that we know we're on the correct page when we click through our Menu options.   We know we'll want our company's name, i.e. LightCo, and probably an image, login, or something else below. So let's subdivide the Mashup into a smaller top part for the name and a bigger bottom section for future functionality.   In the top-left, ensure that the Layout tab is active.   Click Add Top.   Scroll down in the Layout tab to reveal Container Size.   With the top-section of the Canvas selected, click Fixed Size.   In the Height field, type 100 and hit your keyboard's Tab key to apply the change.   Click Save.   Add Company Name   In the top section, we'll add a Label Widget for our company's name.   At the top-left, click the Widgets tab.   Drag-and-drop a Label Widget onto the top section of the Canvas.   With the Label Widget selected, in the bottom-left Properties tab, change LabelText to LightCo and hit your keyboard's Tab key to apply it.   With the Label Widget still selected, in the bottom-left, click the Style Properties tab.   Under Style Properties, expand Base > Label.   Change font-size to 48px.   Click Save.     Step 3: Create Subpage One   Now that we have a basic LightCo homepage in-place, we need subpages to separately control the park-lighting vs the amphitheater-lighting.    But, yet again, we're not designing the actual pages yet. We're just creating them so we can reference them in a Menu.    An easy way to create additional Mashups that have similar layouts is with the Duplicate action. We'll do so now.    Return to Browse > Mashups.   To the left of MNWM_Homepage_Mashup, click the checkbox.   At the top, click Duplicate.   In the Name field, type MNWM_ParkLighting_Mashup. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Save. At the top, click Design.   Change Label Title   Since we used Duplicate to clone the homepage, we see the same header/page Layout which we previously designed. That Layout can be useful for separating page-titles from functionality, so let's keep it.   But we also see the LightCo LabelText we previously created. Since this is the Park Lighting Control page, we need to change it.   In the top section of the Canvas, click the Label Widget to select it.   In the bottom-left, return to the Properties tab.   In the LabelText field, replace the current text with Park Lighting Control, and hit your keyboard's Tab key to apply the change.   At the top, click Save.     Step 4: Create Subpage Two   In the same way that we used Duplicate to mirror the homepage into a park-lighting page, we'll now do the same for the amphitheater-lighting page.    Return to Browse > Mashups. To the left of MNWM_Homepage_Mashup, click the checkbox. At the top, click Duplicate. In the Name field, type MNWM_AmphitheaterLighting_Mashup. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Save. At the top, click Design.   Change LabelText   Just as we did with the Park Lighting Control LabelText, we now want to change this duplicate to read Amphitheater Lighting Control.   In the top section of the Canvas, click the Label Widget to select it. In the bottom-left, return to the Properties tab (if you're not already there). In the LabelText field, replace the current text with Amphitheater Lighting Control, and hit your keyboard's Tab key to apply the change.   Click Save.     Step 5: Create Menu   Having created all three of our starting Mashups, we'll now create a Menu Entity which provides links to each of them.   We'll be able to use this Menu Entity later to configure a Menu Widget for navigation.    Navigate to Browse > Visualization > Menus.   Click +New.    In the Name field, type MNWM_Menu. If Project is not already set, search for and select PTCDefaultProject.    At the top, click Save.   Menu Definitions   Now that we have created the Menu Entity, we can add Menu Definitions with links to all the previously-created pages.   At the top, click Menu Definition. Click +Add.   On the right-side slide-out, in the Title field, type Home. In the Link field, search for and select MNWM_Homepage_Mashup.   In the top-right, click the "check with a plus" button for Done and Add.   In the Title field, type Park. In the Link field, search for and select MNWM_ParkLighting_Mashup.   In the top-right, click the "check with a plus" button for Done and Add. In the Title field, type Amphitheater. In the Link field, search for and select MNWM_AmphitheaterLighting_Mashup.   At the top-right, click the "check" button for Done. At the top, click Save.     Click here to view Part 2 of this guide.
View full tip
    Step 3: Streams Mass data is typically stored in a structure functionally similar to a spreadsheet. Each separate column of the spreadsheet is exclusively one type of data (with each field directly beneath it holding different entries of that same type), while the rows determine the specific entry. Combine a column’s “type” with the row’s “index”, and you have the particular piece of data about which you care. ThingWorx mass data storage functions in roughly the same way. However, ThingWorx does have one differentiation from many spreadsheet implementations. In ThingWorx, the type that defines each column is not held internally to the data structure itself. Instead, it is abstracted out as a Data Shape. A Data Shape is the definition of what each column contains. A Stream requires a Data Shape in order to define its structure. Create Data Shape On the ThingWorx Composer Browse tab, click Modeling -> Data Shapes, + New.   In the Name field, enter Test_Data_Shape.   If Project is not already set, search for and select PTCDefaultProject.  At the top, click Field Definitions.   Click + Add. On the right in the Name field, enter Index_Field . Change the Base Type to INTEGER. Check the Is Primary Key checkbox. All Data Shapes must have a Primary Key, and Index_Field is an appropriate choice, as it will keep track of the number of entries.   At the top-right, click the "Check with a +" button for Done and Add. In the Name field, enter Value_Field. Change the Base Type to NUMBER.   At the top-right, click the "Check" button for Done. At the top, click Save. Once again, the Data Shape does nothing by itself. It simply defines that some other mass data structure (such as a Stream) follows the particular format of the Data Shape. So a Stream assigned the Test_Data_Shape above would have two fields per entry, i.e. an Index and a Value. Create Stream Streams are a mass data storage option optimized for Time-Series data. They are utilized in much the same way as Value Streams, but possess additional functionality.   For one, Streams do not have to be tied to Things in the way that Value Streams are. They can be entirely independent, or even accept inputs from multiple different Things. This can be useful when you want to have a master list of what every similar Thing was doing at particular points throughout some timeframe. On the ThingWorx Composer Browse tab, click DATA STORAGE -> Streams, + New.   On the Choose Template pop-up, select Stream and click OK.   In the Name field, enter Test_Stream.   If Project is not already set, search for and select PTCDefaultProject. In the Data Shape field, search for and select Test_Data_Shape. At the top, click Save.   Create Thing Now that the Stream is created, you'll create a Thing from which you can log some Properties. On the ThingWorx Composer Browse tab, click MODELING -> Things, + New.   In the Name field, enter Stream_Test_Thing. If Project is not already set, search for and select PTCDefaultProject. In the Thing Template field, search for and select GenericThing.   At the top, click Properties and Alerts.   Click + Add. In the Name field, enter Index_Property. Change the Base Type to Integer. Check the Persistent checkbox.   At the top-right, click the "Check with a +" button for Done and Add. In the Name field, enter Value_Property. Change the Base Type to Number. Check the Persistent checkbox.   At the top-right, click the "Check" button for Done. Add Service Since you now have both a Thing and a Stream, we can write a Service which logs the Properties' values when the Service is executed. At the top, click Services.   At the top, click + Add. In the Name field, enter Add_Stream_Entry_Service.   On the left under New Service, click the Snippets tab.   In the Filter field, type add str.   Expand the Stream, Blog, Data Table section to reveal the Add Stream Entry Snippet.   Click the right arrow beside Add Stream Entry. An Add Stream Entry pop-up will open.   In the Search Streams field, enter test.   Select Test_Stream.   Click the Insert Code Snippet button. Note that a section of Javascript code has now been added to the Script window.     Modify Snippet The inserted Javascript Snippet has already done most of the work of creating a custom Service for us. All which you need to do now is modify the code Snippet to store the particular Property values from your Thing. On the 10th line of code, double-click undefined to select it.   On the left, click the Me/Entities tab.   Under the Me/Entities tab, expand Properties. Note that this is not the Properties and Alerts at the top of Composer.   Click the right arrow beside Value_Property. Note that undefined has been replaced by me.Value_Property.   On the 11th line of code, double-click the remaining undefined to select it.   Click the right arrow beside Index_Property. Note that the second “undefined” has been replaced by “me.Index_Property”.   At the top, click Done to close the Add_Stream_Entry_Service editing window.   At the top, click Save.     Click here to view Part 3 of this guide.
View full tip
  Discover how ThingWorx Functions can be implemented in a compelling Mashup design.   Guide Concept   This project will introduce how to create complex user interfaces that are built by using simple Mashup functions.   Following the steps in this guide, you will build a web application with multiple layers. We will teach you how to create a professional user interface that effectively conveys information to users.     You'll learn how to   Navigate to other UIs Create expressions and validations Create event routers and data handling Create confirmation modals/pop-ups Create status messages   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 60 minutes     Step 1: What Are Functions   In the Mashup Builder, we utilize Functions to create added capabilities in our Mashups. Whether we are navigating to another Mashup or triggering events based on some action. Functions are your best friends when creating more advanced Mashups.   Function  Description   Auto Refresh  Refreshes data automatically for widgets in a mashup.  Confirmation  Displays a confirmation dialog box.  Events Router  Routes multiple input sources to one output of the same type.  Expression  Evaluates JavaScript expressions.  Logout  Ends the current user session and redirects to a mashup or a Web page.  Navigation  Navigates from one mashup to another.  Status Message  Displays information, error, or warning messages in a mashup.  Validator  Validates data from input parameters by using JavaScript expressions.   In the next sections, we will cover some of these Functions and showcase how to add them to your Mashups.     Step 2: Create an Expression   Let's start things off by creating a simple Expression Function. This Expression will show or hide a label based on whether a checkbox is checked or not. This simple expression can be expanded to your use case.   It is VERY important to note that in an Expression Function (and also found in Services and Validation Functions) the output of the Function will be the result variable. Let's create our Mashup, then go over what is involved in an Expression.   In the ThingWorx Composer, click the + New at the top of the screen.   Select Mashup in the dropdown.   Select the Responsive layout then hit OK.   Set the Name to  MyFunctionsMashup. For the Project, click the + button and select PTCDefaultProject.    Under Project, click the blue Set as project context option. This will stop us from having to set the Project on every Thing we create. It should now match the following.    Click Save. Click on the Design tab at the top.   This Mashup will be where we create the Majority of our Functions and capabilities. Let's start adding to our Mashup.   Click the Layout tab. Scroll down and set the Orientation to Horizontal.   Click on the Widgets tab. Type in the Filter text box for Checkbox.   Drag and drop a Checkbox Widget to the Mashup Canvas. This Checkbox will dictate whether what we show for the coming Labels and Textbox. Type in the Filter text box for Button. This Button will dictate the event that triggers our Functions. Drag and drop a Button Widget to the Mashup Canvas.   Type in the Filter text box for Label. Drag and drop TWO (2) Label Widgets to the Mashup Canvas. We will only show one Label at a time and I'll show you how.   Type in the Filter text box for Text Field. Drag and drop a Text Field Widget to the Mashup Canvas.     We have the Widgets we need to show our Expression example. Let's start with connecting the Widgets to Functions.   Click the + button in the Functions section in the bottom right.    In the New Function popup, select Expression. Set the Name of the new Expression to isCheckboxChecked.   Click Next. In the new screen, click Add Parameter. Set the Name to this new parameter as checked. Set the Base Type as BOOLEAN.   Switch the Data Change Type to ALWAYS. Switch Output Base Type to BOOLEAN.   Add the following code to the Expression area.  if(checked) { result = true; } else { result = false; }   11. Click Done.   You've now created your first expression. This expression is an example of how easy it can be done. Let's add three three additional Expressions to have some fun.   Repeat steps 1-11 in the last section for TWO (2) new Expressions. Name these Expressions setFirstLabelVisbility and setSecondLabelVisbility. You should now have three total. Repeat steps 1-8 in the last section for ONE (1) new Expression. Name this Expression setTextFieldText. We should have a Parameter called checked. Click Add Parameter again to add a Parameter named input. This fourth Expression should match the following thus far:     Switch Output Base Type to STRING. Add the following code to the Expression area:  if(checked) {     if(input && input.indexOf("YES") >= 0) {     result = input + ", YES";     } else {         result = "YES";     } } else {     result = "NO";     }   6. Click Done.   This expression will see whether or not the Checkbox is checked, then output a string of YES or a simple NO. Let's setup our connections between Widgets and Expressions.   Ensure Expressions are visible and match the following.   Click on the Checkbox in the Mashup Canvas. Click the dropdown that appears.   Drag and drop the State Property to the checked Parameter of all FOUR (4) of the Expressions.   Your bindings should match the following after you're done with setting all four.   Expand the setFirstLabelVisibility Expression (if not already expanded).   Drag the Output to the first Label and select Visible   Expand the setSecondLabelVisibility Expression (if not already expanded).   Drag the Output to the second Label and select Visible.   Our labels are configured. Now let's setup our Text Field Widget.    Expand the setTextFieldText Expression (if not already expanded). Drag the Output to the Text Field and select Text.   Select the Button Widget in the Mashup Canvas.  Click the dropdown for the Button Widget. Drag and drop the Clicked Event to all FOUR (4) of the Expressions.   Your Button Widget should look like the following:   Select the Text Field Widget in the Mashup Canvas Click the dropdown for the Text Field Widget. Drag and drop the Text Property to the input Parameter of the setTextFieldText Expression. Click Save. Click View Mashup. Play around and see all the work you've done. You may notice that both Label Widgets show or hide at the same time. To split when they will show or hide, update the code for one of the Label visibility Expressions to the following:    if(checked) {     result = false; } else {     result = true;     }   Click here to view Part 2 of this guide.
View full tip
    Explore the Value Stream, Stream, Data Table, and Info Table storage methods.     GUIDE CONCEPT   This guide will introduce Values Streams, Streams, Data Tables, and Info Tables.   Value Streams and Streams are methods of storage for time-series data, while Data Tables and Info Tables are methods of storage for non-time-series data.   You will learn how to create and utilize these mass data storage methods.   YOU'LL LEARN HOW TO   Differentiate between data storage methods Create a Data Shape to format a Stream, Data Table, and Info Table Create a Value Stream and Stream to store Time-Series Data Create a Data Table and Info Table to store non-Time-Series Data Use built-in methods to log data to a Value Stream or Info Table Create custom Services which log data to a Stream or Data Table Confirm data storage value changes via a built-in Service or Grid Widget   NOTE:  The estimated time to complete this guide is 60 minutes.     Step 1: Choosing Storage   If your data is largely composed of current values of remote IoT devices (and historical values are unimportant), then the simplest solution is most likely to store them as Properties of Things.   However, as opposed to instantaneous current values, there is also “mass data”. Mass data can include large datasets composed of historical records or spreadsheet-like grids.   Properties (at least by themselves) aren’t really appropriate in that case, as they typically only store the most recent value.   When it comes to mass data, different storage methods are good for different types.   At an extremely high level, ThingWorx divides mass data into roughly two categories: Time-Series - The Timestamp of the data is one of the most important elements. Non-Time-Series - The Timestamp of data changes is relatively insignificant.   In addition, ThingWorx also subdivides these two categories into either 1) tied to a Thing or 2) independent of any one Thing. Mass data storage that is tied to a Thing will logically only accept information from that one Thing, while independent storage may be used to aggregate information from many Things into a single location.    Storage Solution      Time-Series        Tied to a single Thing Value Streams YES YES Streams YES NO Data Tables NO NO Info Tables NO YES   The following pages will address these storage types in-depth.     Step 2: Value Streams   In this step, we'll create a Value Stream to be used as a storage location.   Value Streams by themselves do nothing. Instead, they must be tied to a Thing.   Create Value Stream On the ThingWorx Composer Browse tab, click Data Storage > Value Streams, + New.   In the Choose Template pop-up, select ValueSteam and click OK.   In the Name field, enter Test_Value_Stream . If Project is not already set, search for and select PTCDefaultProject. At the top, click Save. Create Thing Since Value Streams must be tied to a Thing, we'll create one now and then attach the previously-created Value Stream. On the ThingWorx Composer Browse tab, click MODELING > Things, + New .   In the Name field, enter Value_Stream_Test_Thing. If Project is not already set, search for and select PTCDefaultProject. In the Thing Template field, search for and select GenericThing. In the Value Stream field, search for and select Test_Value_Stream.   At the top, click Save.   Create Property   Now that we have a Thing with an attached Value Stream, we'll create a Property of that Thing and set it to be Logged.   If a Value Stream is attached to a Thing, value-changes of all Logged Properties will get automatically recorded along with a timestamp.   At the top, click Properties and Alerts.   Click + Add. In the Name field, enter Value_Property. Change the Base Type to Number. Check the Persistent checkbox. This causes the value of the Property to persist through system reboots. Check the Logged checkbox. This causes all value changes to be logged to the attached Value Stream.   At the top-right, click the "Check" button for Done. At the top, click Save. Set Property Values In a real-world application, Property value changes would likely occur through a connection to a remote IoT device. For simplicity, we'll instead manually change the values. Because the Property is Logged and there is a connected Value Stream, each change will be recorded and timestamped. Under the Value column for Value_Property, click the "pencil icon" for Set value of property.   At the top-right in the Set value of property field, enter 1.   At the top-right, click the "Check" button for Done. Again, click the "pencil icon" for Set value of property. At the top-right in the Set value of property field, enter 2.   At the top-right, click the "Check" button for Done. Again, click the "pencil icon" for Set value of property. At the top-right in the Set value of property field, enter 3.   At the top-right, click the "Check" button for Done. At the top, click Save. Retrieve Logged Values One of the most common ways to retrieve time-series information is with the built-in QueryPropertyHistory Service. QueryPropertyHistory may be used to retrieve logged value-changes for usage in a different, custom Service which could manipulate the data, as well as in Mashups for Widgets like a Grid or Line Chart. At the top, click Services.   Expand the Generic section.   Scroll down and find the QueryPropertyHistory Service.   Click the "Play" button for Execute service.   In the bottom-right of the Execute Service: QueryPropertyHistory pop-up, click Execute. Note the previously entered values of 1, 2, and 3, as well as their associated timestamps.   At the bottom-right, click Done.   A Value Stream is a simple and easy way to record all time-series changes of a particular Thing Property's values.   The QueryPropertyHistory built-in Service may be used both in a custom Service to extract the value changes and Timestamps from a Value Stream, as well as in a Mashup to display how values change over time (in a Line Chart, for instance).     Click here to view Part 2 of this guide.  
View full tip
  Create An Application Key Guide   Overview   In order for a device to send data to the Platform, it needs to be authenticated. One authentication method is to use an Application Key. Application Keys, or appKeys, are security tokens used for authentication in ThingWorx. They are associated with a given User and have all of the permissions granted to the User with which they are associated. This is one of the most common ways of assigning permission control to a connected device. NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 30 minutes.    Step 1: Learning Path Overview   This guide explains the steps to create a ThingWorx Application Key, and is part of a Learning Path. You can use this guide independently from the full Learning Path. If you want to learn to create a ThingWorx Application Key, this guide will be useful to you. When used as part of the Industrial Plant Learning Path, you should already have installed ThingWorx Kepware Server. We will use the Application Key to send information from ThingWorx Kepware Server into ThingWorx Foundation. Other guides demonstrate Foundation's Mashup Builder to construct a website dashboard that displays information from ThingWorx Kepware Server. We hope you enjoy this Learning Path.   Step 2: Create Application Key   Application Keys are assigned to a specific User for secure access to the platform. Using the Application Key for the default User (Administrator) is not recommended. If administrative access is absolutely necessary, create a User and place the User as a member of the SecurityAdministrators and Administrators User groups. Create the User the Application Key will be assigned to. 1. On the Home screen of Composer click + New. 2. In the dropdown list, click Applications Key. 3. Give your application key a name (i.e. MyAppKey). 4. If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. 5. Set the User Name Reference to a User you created. 6. Update the Expiration Date field, otherwise it will default to 1 day. 7. Click Save. A Key ID has been generated and can be used to make secure connections.   IP Whitelisting for Application Keys   One of the features of an Application Key is the ability to set an IP whitelist. This allows the server to specify that only certain IP addresses should be able to use a given Key ID for access. This is a great way to lock down security on the platform for anything that will maintain a static IP address. For example, connected Web-based business systems may have a static IP from which all calls should be made. Similarly, you can use wildcards to specify a network to narrow the range of IP addresses allowed while still offering some flexibility for devices with dynamic IP addresses. Extremely mobile devices should likely not attempt to implement this, however, as they will often change networks and IP addresses and may lose the ability to connect when the IP whitelist feature is used.   Interact with Application Keys Programmatically Service Name Description GetKeyID Returns the ID of this Application Key GetUserName Get the username associated with this Application Key IsExpired Returns if this Application Key is expired ResetExpirationDateToDefault Resets the expiration date of the Application Key to the default time based on configuration in the UserManagement subsystem SetClientName Sets the client name for this Application Key SetExpirationDate Sets the expiration date of this Application Key to a provided date SetIPWhiteList Sets the values for the IP whitelist for this Application Key SetUserName Sets the associated user name for this Application Key   Tip: To learn more about Application Keys, refer to the Help Center   Step 3: Next Steps   Congratulations! You have successfully created an application key. We hope you found this guide useful.     The next guide in the Connect and Monitor Industrial Plant Equipment learning path is Install ThingWorx Kepware Server.    The next guide in the Azure MXChip Development Kit learning path is Connect Azure IoT Devices.   The next guide in the Medical Device Service learning path is Use the Edge MicroServer (EMS) to Connect to ThingWorx.   The next guide in the Using an Allen-Bradley PLC with ThingWorx learning path is Model an Allen-Bradley PLC.
View full tip
  Use the statistical calculation Thing Shape to execute useful analysis services   GUIDE CONCEPT   This project will introduce the Statistical Monitoring Thing Shape.   This guide demonstrates using Descriptive Analytics from ThingWorx Predictive Analytics to perform common statistical monitoring analysis on time-series data. You will learn to use the Statistical Monitoring ThingShape's built-in services to return the number of values in a data set that are: above or below a threshold, inside or outside a defined range, or following a trend that is: increasing, decreasing, or alternating.       YOU'LL LEARN HOW TO   Create a Thing with the Statistical Monitoring Thing Shape Create a Property and Value Stream to record changes in Property values Use Services that perform Standard Analytical Monitoring   NOTE: The estimated time to complete this guide is 30 minutes.     Step 1: Introduction   Descriptive analytics lets you perform common statistical monitoring calculations on changes in a Property value over time.   Output from monitoring Services can be used in IoT applications built with ThingWorx to provide trend and numerical limits feedback.   This guide introduces the Statistical Monitoring Thing Shape which adds Services to Things and Thing Templates for reporting Property values that are: above or below a threshold, inside or outside a defined range, or following a trend that is: increasing, decreasing, or alternating.     These Services analyze time-series data which is stored in ThingWorx Foundation as changes to a Property value logged to a Value Stream.   To ensure optimum performance, both a time range and a maximum number of value changes must be specified.     Step 2: Create Prerequisites   Statistical monitoring Services operate on Property values that change over time. To create this time series data, Property value changes are logged in a Value Stream. In this step, you will create a Value Stream, then a Thing with a Property that logs changes to that Value Stream.   Create Value Stream   Follow the steps below to create a value stream which you will later tie to a Thing.       1. On the ThingWorx Composer Browse tab, click Data Storage > Value Streams, then click the +New button         2. Select ValueStream and click OK.         3. In the Name field, enter scts_valuestream.         4. If Project is not already set, click the + in the Project text box and select the PTCDefaultProject.       5. At the top, click Save.   Create Thing   Now, you will create a Thing with a property and configure it to use the previously-created value stream. You will also apply the statistical monitoring Thing Shape to the Thing, which makes the built-in analytics services available.       1. On the ThingWorx Composer Browse tab, click MODELING > Things then click the + New button          2. In the Name field, enter scts_thing.       3. If Project is not already set, click the + in the Project text box and select the PTCDefaultProject.       4. In the Base Thing Template field, search for and select GenericThing.       5. In the Implemented Shapes field, search for and select StatisticalMonitoringThingShape.       6. In the Value Stream field, search for and select scts_valuestream.         7. At the top, click Save.    Add Property   You will now add a property to scts_thing.       1. At the top, click Properties and Alerts         2. Click + Add.       3. In the right slide-out's Name field, enter numbers.       4. Change the Base Type to NUMBER.       5. Click Persistent.       6. Click Logged.         7. Click Advanced Settings to open the bottom panel, in the Data Change Type drop-down select Always.         8. At the top-right, click the "check" icon for DONE.         9. At the top, click Save.     Step 3: Enter Sample Data   In this step, you will enter sample data that will illustrate the available Services.   This dataset: 2, 3, 4, 3, 2, 2, 1, 2, 1, 1, 2, 3, 3, 4, 3, 2 is shown graphed.      Enter Data   Perform the steps below to enter the above values into the Numbers Property.       1. Under the Value column and on the Numbers property row, click the "pencil" icon for Set value of property.         2. In the right-side slide-out, enter 2.         3. At the top-right, click the "check" icon for Done.       4. At the top, click Save.       5. Repeat steps 1-4 above, but changing the value each time as per the table below:   Value Change Count Entered Value 2nd 3 3rd 4 4th 3 5th 2 6th 2 7th 1 8th 2 9th 1 10th 1 11th 2 12th 3 13th 3 14th 4 15th 3 16th 2     Step 4: Test Monitoring Services   Now that value changes to the numbers Property have been logged in a Value Stream, you can use the built-in Services of the Statistical Monitoring Thing Shape to return how many of values meet different monitoring criteria.   Trend Service   You will test the built-in GetNumberOfConsecutivePointsFollowingATrend Service. This Service will return how many of points in the largest group of values following one of the three trend types INCREASING, DECREASING, and ALTERNATING.       1. Click the Service tab in the scts_thing Thing.       2. Click the GetNumberOfConsecutivePointsFollowingATrend Service.         3. In the PropertyName field enter numbers.       4. In the NumberOfPoints field enter 16 to check all entered points.       5. In the Trend field enter INCREASING to find the largest number of points with an increasing trend.       6. Click the green Execute button and note the Result property in the Output panel has the value 6         7. Repeat the steps above changing the Trend to DECREASING and note the result is 5.     Range Service   We'll now test the built-in GetNumberOfPointsBasedOnARange Service. This Service will return the number of points INSIDE or OUTSIDE a range of values specified by a MIN and MAX value.       1. Click the Close button in the Services tab in the scts_thing Thing.       2. Click the GetNumberOfPointsBasedOnARange Service.         3. In the PropertyName field enter numbers.       4. In the NumberOfPoints field enter 16 to check all entered points.       5. In the Min field enter 1.5 to set the lower end of the range criteria.       6. In the Max field enter 2.5 to set the upper end of the range criteria.       7. In the RegionOfInterest field enter INSIDE to find the largest number of points with an increasing trend.       8. Keep the default IncludeMin and IncludeMax set to True.       9. Click the green Execute button and note the Result property in the Output panel has the value 6.         10. Repeat the steps above changing the RegionOfInterest to OUTSIDEand note the result is 10.     Threshold Service   You will now test the built-in GetNumberOfPointsBeyondAThreshold Service. This Service will return the number of points ABOVE or BELOW a specified value.       1. Click the Services tab in the scts_thing Thing.       2. Click the GetNumberOfPointsBeyondAThreshold Service.         3. In the PropertyName field enter numbers.       4. In the NumberOfPoints field enter 16 to check all entered points.       5. In the Threshold field enter 3 to set the threshold criteria.       6. In the Direction field enter ABOVE to find the number of points above the threshold value.       7. Keep the default IncludeThreshold set to True.       8. Click the green Execute button and note the Result property in the Output panel has the value 7.       9. Repeat the steps above changing the Direction to BELOWand note the result is 14.       Click here to view Part 2 of this guide.
View full tip
    Step 3: Streams (cont.) Store to Stream Now that the Stream, the Thing (and its Properties), and the Thing's Service are all in place, we can execute the Service (along with some Property changes) to demonstrate that the values are getting archived externally to the Stream. At the top, click Properties and Alerts. Note the previously-created Index_Property and Value_Property.   For Index_Property's Value column, click the "pencil" icon for Set value of property.   In the slide-out on the right, enter 1.   At the top-right, click the "Check" button for Set. For Value Property, click the "Pencil" icon for Set value of property.   In the slide-out on the right, enter 10.   At the top-right, click the "Check" button for Set. At the top, click Save.   With the Thing's Properties set to new values, you can now call your custom Service to store those values to the external Stream (along with an auto-generated timestamp). At the top, click Services.   On the Add_Stream_Entry_Service line, click the "Play" button for Execute Service.   At the bottom-right of the pop-up, click the Execute button.   At the bottom-right, click the Done button.   Retrieve from Stream To confirm that our Thing's custom Service is correctly logging our Property values, we'll now use a built-in Service of the Stream to retrieve the stored values. This same QueryStreamEntriesWithData Service could alternately be used to populate various Mashup Widgets to view the data in a more convenient format. Return to the Test_Stream Entity.   On the top, click Services.   Scroll down and locate the QueryStreamEntriesWithData Service's Execute service button.   At the bottom-right of the pop-up, click Execute. Note that you should see a single entry, showing the Index_Field at 1, the Value_Field at 10, and a timestamp of when the information was pushed to the Stream.   At the bottom-right, click Done. To further confirm external storage to the Stream, you may repeat the previous steps to confirm additional Property Value Storage with timestamping. Furthermore, you could create a Mashup utilizing either the Time-Series Chart or a Grid to display the data stored within the Stream. Step 4: Data Tables Just like with Streams, you also need a Data Shape to format a Data Table. In this example, we'll actually use the exact same Data Shape we previously created for the Stream. Create Data Table Both Data Tables and Info Tables may be appropriate for your non-time-series mass data storage needs. However, a Data Table is not tied to a Thing as an Info Table Property would be. If your non-time-series information is coming from multiple different sources, then it would generally be appropriate to use a Data Table. On the ThingWorx Composer Browse tab, click Data Storage > Data Tables, + New. On the Choose Template pop-up, select DataTable, and click OK. In the Name field, enter Test_Data_Table If Project is not already set, search for and select PTCDefaultProject. In the Data Shape field, search for and select Test_Data_Shape. This is the same Data Shape we previously created for the Stream. We're just reusing it for formatting the Data Table.  At the top, click Save. Create Thing Now that we have a Data Table, let's create a Thing with some Properties that we'll eventually log to the external Data Table. On the ThingWorx Composer Browse tab, click MODELING -> Things, + New. In the Name field, enter Data_Table_Test_Thing. If Project is not already set, search for and select PTCDefaultProject. In the Thing Template field, search for and select GenericThing. At the top, click Properties and Alerts. Click + Add. In the Name field, enter Index_Property. Change the Base Type to Integer. Check the Persistent checkbox. At the top, click the "Check with a +" button for Done and Add. In the Name field, enter Value_Property. Change the Base Type to Number. Check the Persistent checkbox. At the top-right, click the "Check" button for Done. Create Service We now have both a Data Table and a Thing with Properties that we want logged. Now we need to create a Service which does the logging. At the top, click Services. Click + Add. In the Name field, enter Add_Data_Table_Entry_Service. Under New Service on the left, click the Snippets tab. In the Filter field, type data table. Expand the Stream, Blog, Data Table section. A pop-up will open. Beside Add/Update Data Table, click the right arrow. In the Search Data Tables field, type test. Select Test_Data_Table. Note that a section of Javascript code has now been added to the Script window. Click the green Insert Code Snippet button. Modify Snippet On the 6th line of code, double-click undefined to select it. On the left, expand the Me/Entities tab. Under the Me/Entities tab, expand Properties. Note that this is not the Properties and Alerts at the top of Composer Click the right arrow beside Value_Property. Note that undefined has been replaced by me.Value_Property. On the 7th line of code, double-click the remaining undefined to select it. Click the right arrow beside Index_Property. Note that the second undefined has been replaced by me.Index_Property.   Click Done to stop editing the custom Service.   At the top, click Save.     Click here to view Part 4 of this guide.
View full tip
    Build a remote monitoring application with our developer toolkit for real-time insight into a simulated SMT assembly line.   Guide Concept   This project will introduce methods to creating your IoT application with the ability to analyze real time information as the goal. Following the steps in this guide, you will create an IoT application with the ThingWorx Java SDK that is based on the functionality of an SMT assembly line. We will teach you how to use the ThingWorx Java SDK, ThingWorx Composer, and the ThingWorx Mashup Builder to connect and build a fully functional IoT application running numerous queues and "moving parts".   You'll learn how to   Use ThingWorx Composer to build an application that uses simulated data Track diagnostics and performance in real-time   NOTE: The estimated time to complete this guide is 60 minutes       Step 1: Completed Example   Download the completed files for this tutorial attached here: ManagementApplication.zip.   In this tutorial, we walk through a real-world scenario for a Raspberry Pi assembly line. The ManagementApplication.zip file provided to you contains a completed example of an SMT application. Utilize this file to see a finished example and return to it as a reference if you become stuck creating your own fully flushed out application. Keep in mind, this download uses the exact names for Entities used in this tutorial. If you would like to import this example and also create Entities on your own, change the names of the Entities you create. The download contains the following Java classes that support this scenario:    Name                          Description Motherboard Abstract representation of a Thing inheriting from a MotherboardTemplate AssemblyLine Abstract representation of a Thing inheriting from a SMTAssemblyLineTemplate AssemblyMachine Abstract representation of a Thing inheriting from a AssemblyMachineTemplate   Once you complete the Java environment setup by installing a Java JDK, import the Entities/ThingWorxEntities.xml file into ThingWorx Composer. This file contains various Data Shapes, Mashups, Value Streams, Things, and Thing Templates necessary to support the application. The more important Entities are as follows:    Feature                                                 Entity Type          Description RaspberryPi 1 - 6 Thing Things that inherit from the motherboard template SolderPasteAssemblyMachine Thing A Thing that inherits from the assembly machine template PickPlaceAssemblyMachine Thing A Thing that inherits from the assembly machine template ReflowSolderAssemblyMachine Thing A Thing that inherits from the assembly machine template InspectionAssemblyMachine Thing A Thing that inherits from the assembly machine template RaspberryPiSMTAssemblyLine Thing A Thing that inherits from the assembly line template MotherboardTemplate ThingTemplate A template used for building motherboard devices AssemblyMachineTemplate ThingTemplate A template used to create the various types of SMT assembly machines SMTAssemblyLineTemplate ThingTemplate A template used to represent the entire assembly line and all devices in it Advisor User User created to be used with the Java SDK examples   NOTE: An Application Key is NOT included in the zip file you downloaded. You will need to create your Application Key and assign it to the Advisor user provided in the ThingWorxEntities.xml file, the Administrator (which is not recommended for production applications), or any user you've created. If you do not know how to create one or just need a refresher, visit the Create An Application Key guide, then come back to this guide.       Step 2: Run Application   The Java code provided in the download is pre-configured to run and connect to the entities in the ThingWorxEntities.xml file. Open the Executable/Script in a text editor, and edit the script with your host and port.  Operating System   File Name Mac/Linux Script.sh Windows Script.bat Update the <HOST> and <PORT> arguments to that of your ThingWorx Composer and update the Application Key argument to the one you have created. Use the examples in the file for assistance. NOTE: If you are using the hosted trial server, follow the HTTPS example and use 443 as the port. After updating the script that pertains to your operating system, double-click or run Script.sh (Linux, Mac) or Script.bat (Windows) to run the Java program. In your browser, proceed to the following URL (replace the host field with your ThingWorx Composer host) in order to see the application work:   <host>/Thingworx/Runtime/index.html#master=AssemblyLineMaster&mashup=RaspberryPiAssemblyLine   You can also open the RaspberryPiAssemblyLine Mashup in the Composer and click View Mashup.   You should be able to see rows of assembly machines with buttons. Click the Start button to start the assembly line. Click the Add Board button to add Raspberry Pi motherboards.   NOTE: The screen will not update and properties cannot be changed until the Java backend starts running. Ensure the connection is made before attempting to start the assembly line.   Functional Breakdown   At runtime, the Mashup executes the following functions:                Mashup Component        Function 1  Assembly Machines Selecting an assembly machine will provide you with information on the diagnostic status of that assembly machine and access to charts highlighting its performance. 2  Start Button Start up the assembly line and all assembly machines. 3  Shutdown Button Stop the assembly line and shutdown all assembly machines. Queues will not be purged. 4  Motherboard Add Dropdown A dropdown that shows the available motherboards that can be added to the assembly line. 5  Add Boards Button If a MotherboardTemplate Entity is selected in the Motherboard Add dropdown, that Raspberry Pi will be added to the assembly line. If no Motherboard is selected, this will add a new Raspberry Pi Thing to the assembly line. 6  Motherboard Image Show all motherboards currently inside the assembly line queue of Raspberry Pi. 7  Motherboard Pick Up Dropdown A dropdown that shows the motherboards in the assembly line that are not in a Complete Stage. 8  Add Pick Up Button If a MotherboardTemplate entity is selected in the Motherboard Pick Up dropdown, that Raspberry Pi will be removed from the assembly line and no longer be available. This can be done if a Raspberry Pi is slowing down the other queues. 9  Box Image Show all motherboards currently in the Complete Stage.         Step 3: Services and Java Implementation   JavaScript using ThingWorx Services   To support and run the application quickly, ThingWorx Services are utilized as much as possible. This ensures the speed and quality of the application are maintained while also ensuring code changes can be made quickly.   Opening and Starting Up   Open the RaspberryPiAssemblyLine Mashup by going to the URL provided in the last section. The machines will all be in a shut-down (RED) state. This is ensured by a call to the Shutdown service within the SMTAssemblyLineTemplate ThingTemplate. This method begins the process of resetting the Motherboards to their default states and AssemblyMachines to a shutdown state.   Click the Start button to call the StartUp Service. This call will notify the Java Code to turn the simulated machines on and begin waiting for any motherboards to be added to the queue.   INFO: The StartUp and Shutdown services call other services, some of which can be overrided. If you would like to make a change to the implementation, make the change in an implementation of the SMTAssemblyLineTemplate ThingTemplate. You can use RaspberryPiSMTAssemblyLine as an example.   New Raspberry Pi Names   The CommonServices Entity provides services that can be reused by other entities easily. The GenerateRandomThingName service is utilized to create a psuedo-random name for a new Motherboard. You can use this service to create names - names may start with “Raspberry,” but not necessarily - they are based on how you set the parameters.   Creating and Adding Boards   Select the Add Board button to make a call to the AddBoard service of the SMTAssemblyLineTemplate ThingTemplate. This service will call the CommonServices Thing to create a new name for the Motherboard, then begin the process of creating, enabling, and adding that Motherboard to the simulated devices in the Java code.   Pickup Boards   Select the Pickup Board button to make a call to the PickUpMotherboard service of the SMTAssemblyLineTemplate ThingTemplate. This service will remove a Motherboard from the assembly line, update the status to having been picked up, and ensure the simulated devices are updated with this new information.   Queue Processing   Add a Motherboard to the available queue of a machine when the Motherboard is ready to be worked on that machine. A machine will NOT know information about a Motherboard until that motherboard is ready for that stage of processing.   The Motherboard is then added to the internal queue of the machine based on the size of the internal queue of that machine. Being in the internal queue of a machine does not mean it is being worked on. The Motherboard is ONLY being worked on when the machine has added the Motherboard to it’s working queue. The size of the working queue is based on the machine’s placement heads. You can play with these values to increase or descrease queue performance.   INFO: The heads, speeds, and queue sizes of the machines are created in the RaspberryPiSMTAssemblyLine Thing. To change these configurations, update the AddStartingMachines service with new values or new machines.   Java Implementation using ThingWorx Java SDK   The Java code we created for the Assembly Line scenario creates a connection to the ThingWorx Composer as any ThingWorx SDK utility would. This code is used to allow extended functionality for the application, and mimics the behavior of devices or machines connected to the ThingWorx Composer.   Motherboard Class   The Motherboard Class contains several methods to ensure the location of the motherboard is known at all times. It also updates the status level from 0 to 100 as the motherboard is being assembled.   AssemblyMachine Class   The fields in the AssemblyMachine class ensure that the queues handled by the machine are working correctly. When an AssemblyMachine is created, it will load both the available queue and the internal queue if the machine will be the first stage in the assembly line (Soldering). If not a solder machine, the queues will be empty, as no device is pending its task. If the machine is on, it will continue to work based on its current status of the motherboards in its queue. When a machine is turned on or the current task is complete, the AssemblyMachine will re-evaluate the queues to optimize timing and decrease idle time.   Challenge: Find a way to improve the timing of the queue and reduce the idle time even more. Think of a problem an assembly line might have when machines are waiting on a prior machine to complete a task.   SMTAssemblyLine Class   The SMTAssemblyLine class handles the overall process and controls how motherboards are handled when entering and exiting the assembly line. There are also listeners to start up the assembly machines.   When a board is added to the queue of the assembly line, it will instantly be added to the available queue for a solder machine to begin processing. This is the only machine that will have immediate access to the motherboard. When a board is picked up from the assembly line queue, the status of the board is set to “PICKED UP”. That motherboard will be available later for processing by the assembly line.     Click here to view Part 2 of this guide.  
View full tip
    Step 10: C - Info Tables   Infotables are used for storing and retrieving data from service calls. An infotable has a DataShapeDefinition that describes the names, base types, and additional information about each field within the table.   In order to create an Infotable, you can do so with the provided macros or functions.   Define With Macros   In order to define Infotables using a macro, use TW_MAKE_INFOTABLE or TW_MAKE_IT. Both macros can be used interchangeably.   NOTE: The macros are all defined in the twMacros.h header file. twInfoTable* it; it = TW_MAKE_IT( TW_MAKE_DATASHAPE(DATSHAPE_NAME_SENSOR_READINGS, TW_DS_ENTRY("ActivationTime", TW_NO_DESCRIPTION ,TW_DATETIME), TW_DS_ENTRY("SensorName", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Temperature", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Pressure", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("FaultStatus", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("InletValve", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("TemperatureLimit", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("TotalFlow", TW_NO_DESCRIPTION ,TW_INTEGER) ), TW_IT_ROW(TW_MAKE_DATETIME_NOW,TW_MAKE_STRING("Sensor Alpha"),TW_MAKE_NUMBER(60),TW_MAKE_NUMBER(25),TW_MAKE_BOOL(TRUE),TW_MAKE_BOOL(TRUE),TW_MAKE_NUMBER(150),TW_MAKE_NUMBER(77)), TW_IT_ROW(TW_MAKE_DATETIME_NOW,TW_MAKE_STRING("Sensor Beta"),TW_MAKE_EMPTY,TW_MAKE_NUMBER(35),TW_MAKE_BOOL(FALSE),TW_MAKE_BOOL(TRUE),TW_MAKE_EMPTY,TW_MAKE_NUMBER(88)), TW_IT_ROW(TW_MAKE_DATETIME_NOW,TW_MAKE_STRING("Sensor Gamma"),TW_MAKE_EMPTY,TW_MAKE_NUMBER(80),TW_MAKE_BOOL(TRUE),TW_MAKE_BOOL(FALSE),TW_MAKE_NUMBER(150),TW_MAKE_NUMBER(99)) );   Define Without Macros   In order to define Infotables without using a macro, use the twDataShape_CreateFromEntries function.   twInfoTable * it = NULL; twInfoTableRow * row = NULL; it = twInfoTable_Create(ds); if (!it) { TW_LOG(TW_ERROR,"createNewThing: Error creating infotable"); twDataShape_Delete(ds); return TW_ERROR_ALLOCATING_MEMORY; } row = twInfoTableRow_Create(twPrimitive_CreateFromString("SimpleThing_2", TRUE)); if (!row) { TW_LOG(TW_ERROR,"createNewThing: Error creating infotable row"); twInfoTable_Delete(it); return TW_ERROR_ALLOCATING_MEMORY; } twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString("A new Thing", TRUE)); twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString("RemoteThing", TRUE)); twInfoTable_AddRow(it, row);   Retrieve With Macros   Many of the calls to services in ThingWorx will return an InfoTable of information. Below is an example of using the TW_GET_NUMBER_PARAM macro to retrieve values from an Infotable: ///Data is stored in the params variable ///Retrieve the a and b values then store them in variables twInfoTable * params double a, b; TW_GET_NUMBER_PARAM(params, "a", 0, &a); TW_GET_NUMBER_PARAM(params, "b", 0, &b);   Retrieve Without Macros   Below is an example of using the twInfoTable_GetNumber function to retrieve values from an Infotable: ///Data is stored in the params variable ///Retrieve the a and b values then store them in variables twInfoTable * params double a, b; twInfoTable_GetNumber(params, "a", 0, &a); twInfoTable_GetNumber(params, "b", 0, &b);       Step 11: C - Events   Event definitions describe interrupts that ThingWorx can subscribe to in order to receive notifications when something happens.   The parameters for an event definition are:   name description dataShape aspects   In order to create an Event, you can do so with the provided macros or functions.   Define With Macros   In order to define an Event using a macro, you will use TW_DECLARE_EVENT or TW_EVENT. Both macros can be used interchangeably. NOTE: The macros are all defined in the twMacros.h header file. TW_EVENT("SteamSensorFault", "Steam sensor event", TW_MAKE_DATASHAPE( "SteamSensorFault", TW_DS_ENTRY("message",TW_NO_DESCRIPTION,TW_STRING) ) );   Define Without Macros   In order to define an Event without using a macro, you will use the twApi_RegisterEvent function. See an example below of how to utilize the twApi_RegisterEvent function and adding a row of data: twApi_RegisterEvent(TW_THING, "SteamSensor", "SteamSensorFault", "Steam sensor event", ds);   Fire With Macros   In order to fire an Event using a macro, you will use TW_FIRE_EVENT.   NOTE: The macros are all defined in the twMacros.h header file. TW_FIRE_EVENT(thingName, "SteamSensorFault", TW_MAKE_IT(TW_MAKE_DATASHAPE( "SteamSensorFault", TW_DS_ENTRY("message", TW_NO_DESCRIPTION, TW_STRING) ), TW_IT_ROW(TW_MAKE_STRING(msg)) ));   Fire Without Macros   In order to fire an Event without using a macro, you will use the twApi_FireEvent function. See an example below of how to utilize the twApi_FireEvent function and adding a row of data: twApi_FireEvent(TW_THING, "SteamSensor", "SteamSensorFault", eventInfoTable, -1, TRUE)       Step 12: C - Services   Service Handler Callbacks The service callback function is registered to be called when a request for a specific service is received from the ThingWorx Platform. These functions must have the same signature as shown here: typedef enum msgCodeEnum (*service_cb) (const char * entityName, const char * serviceName, twInfoTable * params,twInfoTable ** content, void * userdata) Below is an example of a single service that adds two numbers that can be registered with and without macros: /***************** Service Callbacks ******************/ /* Example of handling a single service in a callback */ enum msgCodeEnum addNumbersService(const char * entityName, const char * serviceName, twInfoTable * params, twInfoTable ** content, void * userdata) { double a, b, res; TW_LOG(TW_TRACE,"addNumbersService - Function called"); if (!params || !content) { TW_LOG(TW_ERROR,"addNumbersService - NULL params or content pointer"); return BAD_REQUEST; } twInfoTable_GetNumber(params, "a", 0, &a); twInfoTable_GetNumber(params, "b", 0, &b); res = a + b; *content = twInfoTable_CreateFromNumber("result", res); if (*content) return SUCCESS; else return INTERNAL_SERVER_ERROR; }   NOTE: The return value of the function is TWX_SUCCESS if the request completes successfully or an appropriate error code if not (should be a message code enumeration as defined in twDefinitions.h).   Register Service Callback   In order to register a service handler callback using macros, utilize TW_DECLARE_SERVICE as shown below: TW_MAKE_THING(thingName,TW_THING_TEMPLATE_GENERIC); TW_DECLARE_SERVICE( "AddNumbers", "Add two numbers together", TW_MAKE_DATASHAPE(NO_SHAPE_NAME, TW_DS_ENTRY("a", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("b", TW_NO_DESCRIPTION ,TW_NUMBER)), TW_NUMBER, TW_NO_RETURN_DATASHAPE, addNumbersService );     Click here to view Part 9 of this guide
View full tip
  Use the C SDK to build an app that connects to ThingWorx with persistent bi-directional communication   Guide Concept This project will introduce more complex aspects of the ThingWorx C SDK and help you to get started with development.  Following the steps in this this guide, you will be ready to develop your own IoT application with the ThingWorx C SDK.  We will teach you how to use the C programming language to connect and build IoT applications to be used with the ThingWorx Platform.   You'll learn how to Establish and manage a secure connection with a ThingWorx server, including SSL negotiation and connection maintenance Enable easy programmatic interaction with the Properties, Services, and Events that are exposed by Entities running on a ThingWorx server Create applications that can be directly used with your device running the C programming language Basic concepts of the C Edge SDK How to use the C Edge API to build a real-world application How to utilize resources provided in the Edge SDK to help create your own application NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL 3 parts of this guide is 60 minutes.   Step 1: Completed Examples Download the completed files for this tutorial: ThingWorx C Edge SDK Sample Files.zip.  This tutorial will guide you through working with the C SDK on differing levels. Utilize this file to see a finished example and return to it as a reference if you become stuck creating your own fully fleshed out application.  Keep in mind, this download uses the exact names for Entities used in this tutorial. If you would like to import this example and also create Entities on your own, change the names of the Entities you create.   Step 2: Environment Setup In order to compile C code, you need a C compiler and the ThingWorx C Edge SDK available in the PTC Support download site.  It will be helpful to have CMake installed on your system. CMake is a build tool that will generate make or project files for many different platforms and IDEs.   Operating System      Notes Windows You will need a 3rd party compiler such as MinGW GCC, Cygwin GCC or you can follow these Microsoft instructions to download and use the Microsoft Visual C++ Build Tool. Mac Download the Apple Developer Tools. Linux/Ubuntu A compiler is included by default.   NOTE: You can use CMake, version 2.6.1 or later to build projects or make files, which then are used to build the applications that you develop with the C SDK.     Before you can begin developing with the ThingWorx C SDK, you need to generate an Application Key and modify the source code file. You can use the Create an Application Key guide as a reference.   Modify Source File Extract the files from the C SDK samples zip file. At the top level of the extracted files, you will see a folder called examples. This directory provides examples of how to utilize the C SDK. Open a terminal, go to your workspace, and create a new directory. You can also just switch to the unzipped directory in your system. After you've created this directory in your workspace, copy the downloaded files and folders into your new directory. You can start creating your connection code or open the main.c source file in the examples\SteamSensor\src directory for an example. Operating System      Code Linux/Ubuntu gedit main.c OR vi main.c Mac open –e main.c Windows start main.c Modify the Server Details section at the top with the IP address for your ThingWorx platform instance and the Application Key you would like to use. Change the TW_HOST definition accordingly. Change the TW_PORT definition accordingly. Change the TW_APP_KEY definition to the keyId value saved from the last step.         /* Server Details */ #define TW_HOST "https://pp-XXXXXXXXX.devportal.ptc.i" #define TW_PORT 80 #define TW_APP_KEY "e1d78abf-cfd2-47a6-92b7-37ddc6dd34618"​         NOTE: Using the Application Key for the default Administrator is not recommended. If administrative access is absolutely necessary, create a User and place the user as a member of Admins.   Compile and Run Code To test your connection, you will only need to update the main.c in the SteamSensor example folder. CMake can generate Visual Studio projects, make build files or even target IDEs such as Eclipse, or XCode. CMake generates a general description into a build for your specific toolchain or IDE.   Inside the specific example folder you would like to run, ie SteamSensor. Create a directory to build in, for this example call it bin. mkdir bin  cd bin Run the CMake command listed below. This assumes CMake is already on your PATH.         cmake ..​           CMake has now produced a set of project files which should be compatible with your development environment. Operating System        Command                                            Notes Unix make A set of make files Windows msbuild tw-c-sdk.sln /t:build A visual studio solution   NOTE: CMake does its best to determine what version of Visual Studio you have but you may wish to specify which version to use if you have more than one installed on your computer. Below is an example of forcing CMake to use a specific version of Visual Studio: cmake -G "Visual Studio 15 2017" .. If your version of Visual Studio or other IDE is unknown, use cmake -G to see a list of supported IDEs.   You also have the alternative of opening the tw-c-sdk.sln from within Visual Studio and building in this IDE.   NOTE: By default, CMake will generate a build for the creation of a release binary. If you want to generate a debug build, use the command:           cmake -DBUILD_DEBUG=ON ..           Once your build completes you will find the build products in the CMake directory (see example below). From here, open the project in your IDE of choice.   NOTE: You should receive messages confirming successful binding, authentication, and connection after the main.c file edits have been made.   Operating System Files Description Unix ./bin/src/libtwCSdk_static.a  Static Library Unix ./bin/src/libtwCSdk.so  Shared Library Unix ./bin/examples/SteamSensor/SteamSensor   Sample Application Windows .\bin\src\<Debug/Release>\twCSdk_static.lib  Static Library Windows .\bin\src\<Debug/Release>\twCSdk.dll  Shared Library Windows .\bin\examples\<Debug/Release>\SteamSensor\SteamSensor.exe  Sample Application   Click here to view Part 2 of this guide.  
View full tip
  Step 3: Run Sample Code The C code in the sample download is configured to run and connect to the Entities provided in the ThingWorxEntitiesExport.xml file. Make note of the IP address of your ThingWorx Composer instance. The top level of the exported zip file will be referred to as [C SDK HOME DIR]. Navigate to the [C SDK HOME DIR]/examples/ExampleClient/src directory. Open the main.c source file. Operating System          Command Linux/Ubuntu gedit main.c OR vi main.c Mac open –e main.c Windows start main.c Modify the Server Details section at the top with the IP address for your ThingWorx Platform instance and the Application Key you would like to use. Change the TW_HOST definition accordingly. NOTE: By default, TW_APP_KEY has been set to the Application Key from the admin_key in the import step completed earlier. Using the Application Key for the default Administrator is not recommended. If administrative access is absolutely necessary, create a user and place the user as a member of the Admins security group.   /* Server Details */ #define TW_HOST "127.0.0.1" #define TW_APP_KEY "ce22e9e4-2834-419c-9656-e98f9f844c784c" If you are working on a port other than 80, you will need to update the conditional statement within the main.c source file. Search for and edit the first line within the main function. Based on your settings, set the int16_t port to the ThingWorx platform port. Click Save and close the file. Create a directory to build in, for this example call it bin. Operating System           Command Linux/Ubuntu mkdir bin Mac mkdir bin Windows mkdir bin Change to the newly created bin directory. Operating System          Command Linux/Ubuntu cd bin Mac cd bin Windows cd bin Run the CMake command using your specific IDE of choice. NOTE: Include the two periods at the end of the code as shown below. Use cmake -G to see a list of supported IDEs.         cmake ..​           Once your build completes, you will find the build products in the bin directory, and you can open the project in your IDE of choice. NOTE: You should receive messages confirming successful binding, authentication, and connection after building and running the application. You should be able to see a Thing in your ThingWorx Composer called SimpleThing_1 with updated lastConnection and isConnected properties. SimpleThing_1 is bound for the duration of the application run time.     The below instructions will help to verify the connection. Click Monitoring. Click Remote Things from the list to see the connection status.   You will now be able to see and select the Entity within the list.   Step 4: ExampleClient Connection The C code provided in the main.c source file is preconfigured to initialize the ThingWorx C Edge SDK API with a connection to the ThingWorx platform and register handlers. In order to set up the connection, a number of parameters must be defined. This can be seen in the code below. #define TW_HOST "127.0.0.1" #define TW_APP_KEY "ce22e9e4-2834-419c-9656-ef9f844c784c #if defined NO_TLS #define TW_PORT = 80; #else #define TW_PORT = 443; #endif The first step of connecting to the platform: Establish Physical Websocket, we call the twApi_Initialize function with the information needed to point to the websocket of the ThingWorx Composer. This function: Registers messaging handlers Allocates space for the API structures Creates a secure websocket err = twApi_Initialize(hostname, port, TW_URI, appKey, NULL, MESSAGE_CHUNK_SIZE, MESSAGE_CHUNK_SIZE, TRUE); if (TW_OK != err) { TW_LOG(TW_ERROR, "Error initializing the API"); exit(err); } If you are not using SSL/TLS, use the following line to test against a server with a self-signed certificate: twApi_SetSelfSignedOk(); In order to disable HTTPS support and use HTTP only, call the twApi_DisableEncryption function. This is needed when using ports such as 80 or 8080. A call can be seen below: twApi_DisableEncryption(); The following event handlers are all optional. The twApi_RegisterBindEventCallback function registers a function that will be called on the event of a Thing being bound or unbound to the ThingWorx platform. The twApi_RegisterOnAuthenticatedCallback function registered a function that will be called on the event the SDK has been authenticated by the ThingWorx Platform. The twApi_RegisterSynchronizeStateEventCallback function registers a function that will be called after binding and used to notify your application about fields that have been bound to the Thingworx Platform. twApi_RegisterOnAuthenticatedCallback(authEventHandler, TW_NO_USER_DATA); twApi_RegisterBindEventCallback(NULL, bindEventHandler, TW_NO_USER_DATA); twApi_RegisterSynchronizeStateEventCallback(NULL, synchronizeStateHandler, TW_NO_USER_DATA); NOTE: Binding a Thing within the ThingWorx platform is not mandatory, but there are a number of advantages, including updating Properties while offline.   You can then start the client, which will establish the AlwaysOn protocol with the ThingWorx Composer. This protocol provides bi-directional communication between the ThingWorx Composer and the running client application. To start this connection, use the line below:   err = twApi_Connect(CONNECT_TIMEOUT, RETRY_COUNT); if(TW_OK != err){ exit(-1); }   Click here to view Part 3 of this guide.   
View full tip
  Step 5: Properties In the Delivery Truck application, there are three Delivery Truck Things. Each Thing has a number of Properties based on its location, speed, and its deliveries carried out. In this design, when a delivery is made or the truck is no longer moving, the Property values are updated. The deliveryTruck.c helper C file is based on the DeliveryTruck Entities in the Composer. After calling the construct function, there are a number of steps necessary to get going. For the SimpleThing application, there are a number of methods for creating Properties, Events, Services, and Data Shapes for ease of use. Properties can be created in the client or just registered and utilized. In the SimpleThingClient application, Properties are created. In the DeliveryTruckClient application, Properties are bound to their ThingWorx Platform counterpart. Two types of structures are used by the C SDK to define Properties when it is seen fit to do so and can be found in [C SDK HOME DIR]/src/api/twProperties.h:   Name                    Structure             Description Property Definitions twPropertyDef Describes the basic information for the Properties that will be available to ThingWorx and can be added to a client application. Property Values twProperty Associates the Property name with a value, timestamp, and quality. NOTE: The C SDK provides a number of Macros located in [C SDK HOME DIR]/src/api/twMacros.h. This guide will use these Macros while providing input on the use of pure function calls.   The Macro example below can be found in the main source file for the SimpleThingClient application and the accompanying helper file simple_thing.c. TW_PROPERTY("TempProperty", "Description for TempProperty", TW_NUMBER); TW_ADD_BOOLEAN_ASPECT("TempProperty", TW_ASPECT_ISREADONLY,TRUE); TW_ADD_BOOLEAN_ASPECT("TempProperty", TW_ASPECT_ISLOGGED,TRUE); NOTE: The list of aspect configurations can be seen in [C SDK HOME DIR]/src/api/twConstants.h. Property values can be set with defaults using the aspects setting. Setting a default value in the client will affect the Property in the ThingWorx platform after binding. It will not set a local value in the client application.   For the DeliveryTruckClient, we registered, read, and update Properties without using the Property definitions. Which method of using Properties is based on the application being built.   NOTE: Updating Properties in the ThingWorx Platform while the application is running, will update the values in the client application. To update the values in the platform to match, end the Property read section of your property handler function with a function to set the platform value.   The createTruckThing function for the deliveryTruck.c source code takes a truck name as a parameter and is used to register the Properties, functions, and handlers for each truck. The updateTruckThing function for the deliveryTruck.c source code takes a truck name as a parameter and is used to either initialize a struct for DeliveryTruck Properties, or simulate a truck stop Event, update Properties, then fire an Event for the ThingWorx platform. Connecting properties to be used on the platform is as easy as registering the property and optionally adding aspects. The following shows the properties that correlate to those in the DeliveryTruck entities in the Composer. To do this within the code, you would use the TW_PROPERTY macro as shown in the deliveryTruck.c. This macro must be proceeded by either TW_DECLARE_SHAPE, TW_DECLARE_TEMPLATE or TW_MAKE_THING because these macros declare variables used by the TW_PROPERTY that follow them. //TW_PROPERTY(propertyName,description,type) TW_PROPERTY(PROPERTY_NAME_DRIVER, NO_DESCRIPTION, TW_STRING); TW_PROPERTY(PROPERTY_NAME_DELIVERIES_LEFT, NO_DESCRIPTION, TW_NUMBER); TW_PROPERTY(PROPERTY_NAME_TOTAL_DELIVERIES, NO_DESCRIPTION, TW_NUMBER); TW_PROPERTY(PROPERTY_NAME_DELIVERIES_MADE, NO_DESCRIPTION, TW_NUMBER); TW_PROPERTY(PROPERTY_NAME_LOCATION, NO_DESCRIPTION, TW_LOCATION); TW_PROPERTY(PROPERTY_NAME_SPEED, NO_DESCRIPTION, "TW_NUMBER); Read Properties Reading Properties from a ThingWorx platform Thing or the returned Properties of a Service can be done using the TW_GET_PROPERTY macro. Examples of its use can be seen in all of the provided applications. An example can be seen below: int flow = TW_GET_PROPERTY(thingName, "TotalFlow").number; int pressue = TW_GET_PROPERTY(thingName, "Pressure").number; twLocation location = TW_GET_PROPERTY(thingName, "Location").location; int temperature = TW_GET_PROPERTY(thingName, "Temperature").number; Write Properties Writing Properties to a ThingWorx platform Thing from a variable storing is value uses a similarly named method. Using the TW_SET_PROPERTY macro will be able to send values to the platform. Examples of its use can be seen in all of the provided applications. An example is shown below: TW_SET_PROPERTY(thingName, "TotalFlow", TW_MAKE_NUMBER(rand() / (RAND_MAX / 10.0))); TW_SET_PROPERTY(thingName, "Pressure", TW_MAKE_NUMBER(18 + rand() / (RAND_MAX / 5.0))); TW_SET_PROPERTY(thingName, "Location", TW_MAKE_LOC(gpsroute[location_step].latitude,gpsroute[location_step].longitude,gpsroute[location_step].elevation)); This macro utilizes the twApi_PushSubscribedProperties function call to pushe all property updates to the server. This can be seen in the updateTruckThing function in deliveryTruck.c. Property Change Listeners Using the Observer pattern, you can take advantage of the Property change listener functionality. With this pattern, you create functions that will be notified when a value of a Property has been changed (whether on the server or locally by your program when the TW_SET_PROPERTY macro is called). Add a Property Change Listener In order to add a Property change listener, call the twExt_AddPropertyChangeListener function using the: Name of the Thing (entityName) Property this listener should watch Function that will be called when the property has changed void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } void test_simplePropertyChangeListener() { { TW_MAKE_THING("observedThing",TW_THING_TEMPLATE_GENERIC); TW_PROPERTY("TotalFlow", TW_NO_DESCRIPTION, TW_NUMBER); } twExt_AddPropertyChangeListener("observedThing",TW_OBSERVE_ALL_PROPERTIES,simplePropertyObserver); TW_SET_PROPERTY("observedThing","TotalFlow",TW_MAKE_NUMBER(50)); } NOTE: Setting the propertyName parameter to NULL or TW_OBSERVE_ALL_PROPERTIES, the function specified by the propertyChangeListenerFunction parameter will be used for ALL properties.   Remove a Property Change Listener In order to release the memory for your application when done with utilizing listeners for the Property, call the twExt_RemovePropertyChangeListener function. void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } twExt_RemovePropertyChangeListener(simplePropertyObserver);   Step 6: Data Shapes Data Shapes are an important part of creating/firing Events and also invoking Services. Define With Macros In order to define a Data Shape using a macro, use TW_MAKE_DATASHAPE.   NOTE: The macros are all defined in the twMacros.h header file.   TW_MAKE_DATASHAPE("SteamSensorReadingShape", TW_DS_ENTRY("ActivationTime", TW_NO_DESCRIPTION ,TW_DATETIME), TW_DS_ENTRY("SensorName", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Temperature", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Pressure", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("FaultStatus", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("InletValve", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("TemperatureLimit", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("TotalFlow", TW_NO_DESCRIPTION ,TW_INTEGER) ); Define Without Macros In order to define a Data Shape without using a macro, use the twDataShape_CreateFromEntries function. In the example below, we are creating a Data Shape called SteamSensorReadings that has two numbers as Field Definitions. twDataShape * ds = twDataShape_Create(twDataShapeEntry_Create("a",NULL,TW_NUMBER)); twDataShape_AddEntry(ds, twDataShapeEntry_Create("b",NULL,TW_NUMBER)); /* Name the DataShape for the SteamSensorReadings service output */ twDataShape_SetName(ds, "SteamSensorReadings");   Step 7: Events and Services Events and Services provide useful functionality. Events are a good way to make a Service be asynchronous. You can call a Service, let it return, then your Entity can subscribe to your Event and not keep the original Service function waiting. Events are also a good way to allow the platform to respond to data when it arrives on the edge device without it having to poll the edge device for updates. Fire Events To fire an Event you first need to register the Event and load it with the necessary fields for the Data Shape of that Event using the twApi_RegisterEvent function. Afterwards, you would send a request to the ThingWorx server with the collected values using the twApi_FireEvent function. An example is as follows: twDataShape * ds = twDataShape_Create(twDataShapeEntry_Create("message", NULL,TW_STRING)); /* Event datashapes require a name */ twDataShape_SetName(ds, "SteamSensorFault"); /* Register the service */ twApi_RegisterEvent(TW_THING, thingName, "SteamSensorFault", "Steam sensor event", ds); …. struct { char FaultStatus; double Temperature; double TemperatureLimit; } properties; …. properties. TemperatureLimit = rand() + RAND_MAX/5.0; properties.Temperature = rand() + RAND_MAX/5.0; properties.FaultStatus = FALSE; if (properties.Temperature > properties.TemperatureLimit && properties.FaultStatus == FALSE) { twInfoTable * faultData = 0; char msg[140]; properties.FaultStatus = TRUE; sprintf(msg,"%s Temperature %2f exceeds threshold of %2f", thingName, properties.Temperature, properties.TemperatureLimit); faultData = twInfoTable_CreateFromString("message", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } Invoke Services In order to invoke a Service, you will use the twApi_InvokeService function. The full documentation for this function can be found in [C SDK HOME DIR]/src/api/twApi.h. Refer to the table below for additional information.   Parameter         Type                   Description entityType Input The type of Entity that the service belongs to. Enumeration values can be found in twDefinitions.h. entityName Input The name of the Entity that the service belongs to. serviceName Input The name of the Service to execute. params Input A pointer to an Info Table containing the parameters to be passed into the Service. The calling function will retain ownership of this pointer and is responsible for cleaning up the memory after the call is complete. result Input/Output A pointer to a twInfoTable pointer. In a successful request, this parameter will end up with a valid pointer to a twInfoTable that is the result of the Service invocation. The caller is responsible for deleting the returned primitive using twInfoTable_Delete. It is possible for the returned pointer to be NULL if an error occurred or no data is returned. timeout Input The time (in milliseconds) to wait for a response from the server. A value of -1 uses the DEFAULT_MESSAGE_TIMEOUT as defined in twDefaultSettings.h. forceConnect Input A Boolean value. If TRUE and the API is in the disconnected state of the duty cycle, the API will force a reconnect to send the request.   See below for an example in which the Copy service from the FileTransferSubsystem is called:   twDataShape * ds = NULL; twInfoTable * it = NULL; twInfoTableRow * row = NULL; twInfoTable * transferInfo = NULL; int res = 0; const char * sourceRepo = "SimpleThing_1"; const char * sourcePath = "tw/hotfolder/"; const char * sourceFile = "source.txt"; const char * targetRepo = "SystemRepository"; const char * targetPath = "/"; const char * targetFile = "source.txt"; uint32_t timeout = 60; char asynch = TRUE; char * tid = 0; /* Create an infotable out of the parameters */ ds = twDataShape_Create(twDataShapeEntry_Create("sourceRepo", NULL, TW_STRING)); res = twDataShape_AddEntry(ds, twDataShapeEntry_Create("sourcePath", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("sourceFile", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("targetRepo", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("targetPath", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("targetFile", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("async", NULL, TW_BOOLEAN)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("timeout", NULL, TW_INTEGER)); it = twInfoTable_Create(ds); row = twInfoTableRow_Create(twPrimitive_CreateFromString(sourceRepo, TRUE)); res = twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(sourcePath, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(sourceFile, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(targetRepo, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(targetPath, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(targetFile, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromBoolean(asynch)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromInteger(timeout)); twInfoTable_AddRow(it,row); /* Make the service call */ res = twApi_InvokeService(TW_SUBSYSTEM, "FileTransferSubsystem", "Copy", it, &transferInfo, timeout ? (timeout * 2): -1, FALSE); twInfoTable_Delete(it); /* Grab the tid */ res = twInfoTable_GetString(transferInfo,"transferId",0, &tid); Bind Event Handling You may want to track exactly when your edge Entities are successfully bound to or unbound from the server. The reason for this is that only bound items should be interacting with the ThingWorx Platform and the ThingWorx Platform will never send any requests targeted at an Entity that is not bound. A simple example that only logs the bound Thing can be seen below. After creating this function, it will need to be registered using the twApi_RegisterBindEventCallback function before the connection is made. void BindEventHandler(char * entityName, char isBound, void * userdata) { if (isBound) TW_LOG(TW_FORCE,"BindEventHandler: Entity %s was Bound", entityName); else TW_LOG(TW_FORCE,"BindEventHandler: Entity %s was Unbound", entityName); } …. twApi_RegisterBindEventCallback(thingName, BindEventHandler, NULL); OnAuthenticated Event Handling You may also want to know exactly when your Edge device has successfully authenticated and made a connection to the ThingWorx platform. Like the bind Event handling, this function will need to be made and registered. To register this handler, use the twApi_RegisterOnAuthenticatedCallback function before the connection is made. This handler form can also be used to do a delay bind for all Things. void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } twExt_RemovePropertyChangeListener(simplePropertyObserver);   Click here to view Part 4 of this guide. 
View full tip
    Step 7: C - Entities and Functions   All SDKs require a RemoteThing be created in ThingWorx in order to communicate. If many Things are to be created with the same properties, services, and events, we recommend that a Thing Template be derived from one of the supplied RemoteThing templates.   NOTE: The macros are all defined in the twMacros.h header file.   Define ThingShape   ThingShapes are used in the ThingWorx object-oriented Data Model and used to create Things later on. In order to create a ThingShape, you can do so with the provided macros. In order to define a ThingShapes using a macro, you will use TW_DECLARE_SHAPE or TW_SHAPE. TW_DECLARE_SHAPE("SteamLocation","Address Shape","UniqueNameSpace");   Define ThingTemplate   ThingTemplates are used in the ThingWorx object oriented Data Model and used to create Things later on. In order to create a ThingTemplate, you can do so with the provided macros. In order to define a ThingTemplate using a macro, you will use TW_DECLARE_TEMPLATE or TW_TEMPLATE. TW_DECLARE_TEMPLATE("SteamLocationTemplate",TW_THING_TEMPLATE_GENERIC,"UniqueNameSpace");   Define Thing   Things are used in the Data Model and a staple in IoT development. In order to create a Thing, you can do so with the provided macros or functions.   Function Example In order to define a Thing with a macro, you will use TW_MAKE_THING. TW_MAKE_THING("SteamSensor", TW_THING_TEMPLATE_GENERIC); In order to define a Thing without using a macro, you will use the twExt_CreateThingFromTemplate function. twExt_CreateThingFromTemplate("SteamSensor","WarehouseTemplate", "SimpleShape", "AddressShape","InventoryShape",NULL);   Register Functions   ThingWorx provides functionality for a Thing to be bound or connected to the server. Function Notes twExt_RegisterPolledTemplateFunction Register a function to be called periodically after this Thing has been created twApi_RegisterSynchronizeStateEventCallback Called after binding to notify your application about what fields are bound on the server. Will also be called each time bindings on a Thing are edited. twApi_RegisterBindEventCallback Runs whenever a Thing is bound or unbound.   Bind & Subscribe   You will use the TW_BIND macro or the twApi_BindThing function with the Thing name provided as a parameter. The documentation can be found in [C SDK HOME DIR]/src/api/twMacro.h and [C SDK HOME DIR]/src/api/twApi.h respectfully.   NOTE: Registered properties are bound or subscribed after they have been registered.   Bind Callbacks   You may want to track exactly when your edge entities are successfully bound to or unbound from ThingWorx Core. The reason for this is that only bound items should be interacting with ThingWorx Core and it will never forward a request to a corresponding remote thing in its database when the request is targeted at an entity that is not bound. Call the twApi_RegisterBindEventCallback() function to register your bind callback function as seen below with a function we later define called BindEventHandler:   To learn about a specific bound Thing (ie, SteamSensor): twApi_RegisterBindEventCallback("SteamSensor", BindEventHandler, NULL);   To learn about all bound Things, leave the first parameter null: twApi_RegisterBindEventCallback(NULL, BindEventHandler, NULL An example of the function is below: void BindEventHandler(char *entityName, char isBound, void *userdata) { if (isBound) TW_LOG(TW_FORCE,"bindEventHandler: Entity %s was Bound", entityName); else TW_LOG(TW_FORCE,"bindEventHandler: Entity %s was Unbound", entityName); }   Create Tasks   The SDK contains a tasker framework that you can use to call functions repeatedly at a set interval. You can use the tasker to drive both the connectivity layer of your application and the functionality of your application. However, using the tasker is optional.   NOTE: The built-in tasker is a simple round-robin execution engine that will call all registered functions at a rate defined when those functions are registered. If using a multitasking or multi-threaded environment you may want to disable the tasker and use the native environment. If you choose to disable the tasker, you must call twApi_TaskerFunction() and twMessageHandler_msgHandlerTask() on a regular basis (every 5 milliseconds or so). Un-define this setting if you are using your own threads to drive the API, as you do not want the tasker running in parallel with another thread running the API.   To properly initialize the tasker, you must define ENABLE_TASKER: #define ENABLE_TASKER 1 An example of a data collection task is seen below: /*************** Data Collection Task ****************/ /* This function gets called at the rate defined in the task creation. The SDK has a simple cooperative multitasker, so the function cannot infinitely loop. Use of a task like this is optional and not required in a multithreaded environment where this functionality could be provided in a separate thread. */ #define DATA_COLLECTION_RATE_MSEC 2000 void dataCollectionTask(DATETIME now, void * params) { /* TW_LOG(TW_TRACE,"dataCollectionTask: Executing"); */ properties.TotalFlow = rand()/(RAND_MAX/10.0); properties.Pressure = 18 + rand()/(RAND_MAX/5.0); properties.Location.latitude = properties.Location.latitude + ((double)(rand() - RAND_MAX))/RAND_MAX/5; properties.Location.longitude = properties.Location.longitude + ((double)(rand() - RAND_MAX))/RAND_MAX/5; properties.Temperature = 400 + rand()/(RAND_MAX/40); /* Check for a fault. Only do something if we haven't already */ if (properties.Temperature > properties.TemperatureLimit && properties.FaultStatus == FALSE) { twInfoTable * faultData = 0; char msg[140]; properties.FaultStatus = TRUE; properties.InletValve = TRUE; sprintf(msg,"%s Temperature %2f exceeds threshold of %2f", thingName, properties.Temperature, properties.TemperatureLimit); faultData = twInfoTable_CreateFromString("msg", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } /* Update the properties on the server */ sendPropertyUpdate(); }   NOTE: The Windows-based operating systems have a tick resolution (15ms) that is higher than the tick resolutions requested by the C SDK (5ms).       Click here to view Part 6 of this guide  
View full tip
  Step 8: C - Properties (cont.)   Register Properties   Registering properties and services with the API:   Tells the API what callback function to invoke when a request for that property or service comes in from ThingWorx. Gives the API information about the property or service so that when ThingWorx browses the Edge device, it can be informed about the availability and the definition of that property or service. If you used the TW_PROPERTY macro, your property has been registered. If using function calls, to register a property, use the twApi_RegisterProperty. The documentation for this function can be found in [C SDK HOME DIR]/src/api/twApi.h.   NOTE: If you used the provided Macros to create your property, it has already been registered. Bind the Thing in order for your property to be bound.   An example of registering a property is as follows:   twApi_RegisterProperty(TW_THING, “SimpleThing_1”, "FaultStatus", TW_BOOLEAN, NULL, "ALWAYS", 0, propertyHandler, NULL); twApi_RegisterProperty(TW_THING, “SimpleThing_1”, "InletValve", TW_BOOLEAN, NULL, "ALWAYS", 0, propertyHandler, NULL); twApi_RegisterProperty(TW_THING, “SimpleThing_1”, "Pressure", TW_NUMBER, NULL, "ALWAYS", 0, propertyHandler, NULL); twApi_RegisterProperty(TW_THING, “SimpleThing_1”, "Temperature", TW_NUMBER, NULL, "ALWAYS", 0, propertyHandler, NULL); twApi_RegisterProperty(TW_THING, thingName, "BigGiantString", TW_STRING, NULL, "ALWAYS", 0, propertyHandler, NULL); twApi_RegisterProperty(TW_THING, thingName, "Location", TW_LOCATION, NULL, "ALWAYS", 0, propertyHandler, NULL);   Update Properties   Property values can be updated using the provided Macros or using the API directly.   NOTE: Update a property does not send it to the server. To Push a property after updates have been made, use the TW_PUSH_PROPERTIES_FOR function that can be found in the [C SDK HOME DIR]/src/api/twMacro.h header file.   With Macros   The TW_SET_PROPERTY macro updates a property in ThingWorx and can be found in the [C SDK HOME DIR]/src/api/twMacro.h header file. The usage can be seen in the example below: TW_SET_PROPERTY(thingName, "FlowCount", TW_MAKE_NUMBER(5)); TW_SET_PROPERTY(thingName, "TotalFlow", TW_MAKE_NUMBER(rand() / (RAND_MAX / 10.0))); TW_SET_PROPERTY(thingName, "Pressure", TW_MAKE_NUMBER(18 + rand() / (RAND_MAX / 5.0))); TW_SET_PROPERTY(thingName, "Location", TW_MAKE_LOC(gpsroute[location_step].latitude,gpsroute[location_step].longitude,gpsroute[location_step].elevation));   Without Macros   The twInfoTable_CreateFrom and twApi_SetSubscribedProperty functions updates a property in ThingWorx and can be found in the [C SDK HOME DIR]/src/api/twApi.h header file. The usage can be seen in the example below: if (strcmp(propertyName, "count") == 0) { twInfoTable_GetInteger(*value, propertyName, 0, &properties.count); twApi_SetSubscribedProperty(entityName, propertyName, twPrimitive_CreateFromNumber(properties.count), FALSE, TRUE); } if (strcmp(propertyName, "InletValve") == 0) twInfoTable_GetBoolean(*value, propertyName, 0, &properties.InletValve);   Retrieve Properties   Property values can be retrieved using the provided Macros or using the API directly.   With Macros   The TW_GET_PROPERTY macro retrieves a property in ThingWorx and can be found in the [C SDK HOME DIR]/src/api/twMacro.h header file. The usage can be seen in the example below: double temp = TW_GET_PROPERTY(thingName, "Temperature").number;   NOTE: You can use the macro TW_GET_PROPERTY_TYPE to get the property type. The signature and function information can be found in the [C SDK HOME DIR]/src/api/twMacro.h header file.   Without Macros   The twInfoTable_Get functions updates a property in ThingWorx and can be found in the [C SDK HOME DIR]/src/api/twApi.h header file. The usage can be seen in the example below:   twInfoTable **inletValue = NULL; twInfoTable **temp = NULL; twInfoTable **location = NULL; *inletValue = twInfoTable_CreateFromBoolean(propertyName, properties.InletValve); *temp = twInfoTable_CreateFromNumber(propertyName, properties.Temperature); *location = twInfoTable_CreateFromLocation(propertyName, &properties.Location);   Property Change Listeners   Using the Observer pattern, you are able to take advantage of the property change listener functionality. With this pattern, you are able to create functions that will be notified when a value of a property has been changed (whether on the server or locally by your program when the TW_SET_PROPERTY macro is called).   Add a Property Change Listener   In order to add a property change listener, you will call the twExt_AddPropertyChangeListener function using the name of the Thing (entityName), the property this listener should watch, and the function that will be called when the property has changed. The usage can be seen in the example below: void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } void test_simplePropertyChangeListener() { { TW_MAKE_THING("observedThing",TW_THING_TEMPLATE_GENERIC); TW_PROPERTY("TotalFlow", TW_NO_DESCRIPTION, TW_NUMBER); } twExt_AddPropertyChangeListener("observedThing",TW_OBSERVE_ALL_PROPERTIES,simplePropertyObserver); TW_SET_PROPERTY("observedThing","TotalFlow",TW_MAKE_NUMBER(50)); }   NOTE: Setting the propertyName parameter to NULL or TW_OBSERVE_ALL_PROPERTIES, the function specified by the propertyChangeListenerFunction parameter will be used for ALL properties.   Remove a Property Change Listener   When releasing the memory for your application or done with utilizing listeners for the property, call the twExt_RemovePropertyChangeListener function. This usage can be seen in the example below:   void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } twExt_RemovePropertyChangeListener(simplePropertyObserver);     Step 9: C - Data Shapes   DataShapes are used for Events, Services, and InfoTables. In order to create a DataShape, you can do so with the provided macros or functions.   Define With Macros   In order to define a DataShape using a macro, use TW_MAKE_DATASHAPE.   NOTE: The macros are all defined in the twMacros.h header file. TW_MAKE_DATASHAPE("SteamSensorReadingShape", TW_DS_ENTRY("ActivationTime", TW_NO_DESCRIPTION ,TW_DATETIME), TW_DS_ENTRY("SensorName", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Temperature", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Pressure", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("FaultStatus", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("InletValve", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("TemperatureLimit", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("TotalFlow", TW_NO_DESCRIPTION ,TW_INTEGER) );   Define Without Macros   In order to define a DataShape without using a macro, use the twDataShape_CreateFromEntries function.   twDataShape * ds = 0; ds = twDataShape_Create(twDataShapeEntry_Create("ID", NULL, TW_INTEGER)); twDataShape_SetName(ds, "StringMap"); twDataShape_AddEntry(ds, twDataShapeEntry_Create("Value", NULL, TW_STRING));     Click here to view Part 8 of this guide
View full tip
  Step 8: C - Properties   In the ThingWorx environment, a Property represents a data point, which has a:   Name Value Timestamp Quality (optional)   Define Properties   You can define attributes, base types and other aspects of ThingWorx properties.   Attributes   The table below provides information on the different attributes that are used to define a property.   Attribute Details name Specifies the name of the property that will appear in ThingWorx when users browse to bind the related Thing. description Provides additional information for the property. baseType Specifies the type of the property. For a list of base types supported by the SDK, refer to the BaseTypes chart below.   BaseTypes   The table below provides information on the different types of properties that can be created in ThingWorx.   BaseType  Description TW_NOTHING An empty value. TW_STRING A modified UTF8 encoded string. Data and length are stored in val.bytes and val.len, respectively. The twPrimitive owns the data pointer and will free it when deleted. TW_STRING types are null terminated. TW_NUMBER A C double value, stored in val.double. TW_BOOLEAN Represented as a single char, stored in val.boolean. TW_DATETIME A DATETIME value, which is an unsigned 64 bit value representing milliseconds since the epoch 1/1/1970. Data is stored in val.datetime. TW_INFOTABLE A pointer to a complex structure (defined in the next section) and stored in val.infotable. The twPrimitive owns this pointer and will free up the memory pointed to when the twPrimitive is deleted. TW_LOCATION A structure consisting of three double floating point values – longitude, latitude, and elevation. Stored as val.location. TW_BLOB A pointer to a character array. Data and length are stored in val.bytes and val.len, respectively. Differs from TW_STRING in that the array may contain nulls. The twPrimitive owns the data pointer and will free it when deleted. TW_IMAGE Identical to TW_BLOB except for the type difference. TW_INTEGER Assigned 4 by integral value. Stored as val.integer. TW_VARIANT Pointer to a structure that contain a type enum and a twPrimitive value. The pointer is stored as val.variant. The twPrimitive owns the pointer and will free the structure when deleted.   The following base types are all of the TW_STRING family and are stored similarly:   TW_XML,TW_JSON TW_QUERY TW_HYPERLINK TW_IMAGELINK TW_PASSWORD TW_HTML TW_TEXT TW_TAGS TW_GUID TW_THINGNAME TW_THINGSHAPENAME TW_THINGTEMPLATENAME TW_DATASHAPENAME TW_MASHUPNAME TW_MENUNAME TW_BASETYPENAME TW_USERNAME TW_GROUPNAME TW_CATEGORYNAME TW_STATEDEFINITIONNAME TW_STYLEDEFINITIONNAME TW_MODELTAGVOCABULARYNAME TW_DATATAGVOCABULARYNAME TW_NETWORKNAME TW_MEDIAENTITYNAME TW_APPLICATIONKEYNAME TW_LOCALIZATIONTABLENAME TW_ORGANIZATIONNAME   Aspects   Aspects define the ways to interact with a property. The table below provides information on details that make up the Aspects attribute of a property.   Attribute Macro Description isPersistent TW_ASPECT_ISPERSISTENT Set to TRUE for the ThingWorx server to persist the value even if it restarts. It is extremely expensive to have persistent values, so it is recommended to set this value to FALSE unless absolutely necessary. isReadOnly TW_ASPECT_ISREADONLY Set to TRUE to inform the ThingWorx server that this value is only readable and cannot be changed by a request from the server. dataChangeType TW_ASPECT_DATACHANGETYPE Describes how the ThingWorx server responds when the value changes in the client application. Subscriptions to these value changes can be modeled in ThingWorx Platform. If nothing needs to react to the property change, set this value to NEVER. dataChangeThreshold TW_ASPECT_DATACHANGETHRESHOLD Defines how much the value must change to trigger a change event. For example 0 (zero) indicates that any change triggers an event. A value of 10 (ten) for example would not trigger an update unless the value changed by an amount greater than or equal to 10. defaultValue TW_ASPECT_DEFAULT_VALUE The default value is the value that ThingWorx Platform uses when the RemoteThing connected to the device first starts up and has not received an update from the device. The value is different based on the different value for each base type. cacheTime N/A The amount of time that ThingWorx Platform caches the value before reading it again. A value of -1 informs the server that the client application always sends its value and the server should never go and get it. A value of 0 (zero) indicates that every time the server uses the value, it should go and get it from the client application. Any other positive value indicates that the server caches the value for that many seconds and then retrieves it from the client application only after that time expired. pushType TW_ASPECT_PUSHTYPE Informs ThingWorx Platform how the client application pushes its values to the server.   NOTE: cacheTime and dataChangeThreshold are for subscribed (bound) properties ONLY.   DataChangeType Values   This field acts as the default value for the data change type field of the property when it is added to the remote Thing. The possible dataChangeType values are below:   Value Description ALWAYS Always notify of the value change even if the new value is the same as the last reported value. VALUE Only notify of a change when a newly reported value is different than its previous value. ON For BOOLEAN types, notify only when the value is true. OFF For BOOLEAN types only, notify when the value is false. NEVER Ignore all changes to this value.   PushType Values   This aspect works in conjunction with cacheTime. The possible pushType values are below:   Value Description ALWAYS Send updates even if the value has not changed. It is common to use a cacheTime setting of -1 in this case. VALUE Send updates only when the value changes. It is common to use a cacheTime setting of -1 in this case. NEVER Never send the value, which indicates that ThingWorx server only writes to this value.It is common to use a cacheTime setting of 0 or greater in this case. DEADBAND Added to support KEPServer, this push type is an absolute deadband (no percentages). It provides a cumulative threshold, such that the Edge device should send an update if its current data point exceeds Threshold compared to the last value sent to ThingWorx Platform. It follows existing threshold fields limits.   With Macros   The C SDK provides a list of macros to help make development easier and faster.   The macros TW_PROPERTY and TW_PROPERTY_LONG define a property of a Thing. This macro must be preceeded by either TW_DECLARE_SHAPE,TW_DECLARE_TEMPLATE or TW_MAKE_THING macros because these macros declare variables used by the property that follow them. The functions return TW_OK on success, {TW_NULL_OR_INVALID_API_SINGLETON,TW_ERROR_ALLOCATING_MEMORY,TW_INVALID_PARAM,TW_ERROR_ITEM_EXISTS} on failure.   NOTE: The macros are defined in the file, twMacros.h.   This example shows how to utilize these functions:   TW_MAKE_THING(thingName,TW_THING_TEMPLATE_GENERIC); TW_PROPERTY("Pressure", TW_NO_DESCRIPTION, TW_NUMBER); TW_ADD_BOOLEAN_ASPECT("Pressure", TW_ASPECT_ISREADONLY,TRUE); TW_ADD_BOOLEAN_ASPECT("Pressure", TW_ASPECT_ISLOGGED,TRUE); TW_PROPERTY("Temperature", TW_NO_DESCRIPTION, TW_NUMBER); TW_ADD_BOOLEAN_ASPECT("Temperature", TW_ASPECT_ISREADONLY,TRUE); TW_ADD_BOOLEAN_ASPECT("Pressure", TW_ASPECT_ISLOGGED,TRUE); TW_PROPERTY("TemperatureLimit", TW_NO_DESCRIPTION, TW_NUMBER); TW_ADD_NUMBER_ASPECT("TemperatureLimit", TW_ASPECT_DEFAULT_VALUE,320.0); TW_PROPERTY("Location", TW_NO_DESCRIPTION, TW_LOCATION); TW_ADD_BOOLEAN_ASPECT("Location", TW_ASPECT_ISREADONLY,TRUE); TW_PROPERTY("Logfile", TW_NO_DESCRIPTION, TW_STRING); TW_ADD_BOOLEAN_ASPECT("Logfile", TW_ASPECT_ISREADONLY,TRUE);   NOTE: TW_PROPERTY_LONG performs the same actions as TW_PROPERTY, except that it offers more options. When using TW_PROPERTY to declare a property you are accepting the use of the default property handler. This property handler will allocate and manage the storage used for this property automatically.   Without Macros   Property values can be set with defaults using the aspects setting. Setting a default value in the client will affect the property in the ThingWorx platform after binding. It will not set a local value in the client application. Two types of structures are used by the C SDK to define properties.   Structure Notes Code Property Definitions Describes the basic information for the properties that are going to be available to ThingWorx and can be added to a client application. twPropertyDef *property1 = twPropertyDef_Create(property, TW_BOOLEAN, "Description for Property1", "NEVER", 0); cJSON_AddStringToObject(tmp->aspects,"isReadOnly", "FALSE"); cJSON_AddStringToObject(tmp->aspects,"isPersistent", "FALSE"); cJSON_AddStringToObject(tmp->aspects,"isPersistent", "FALSE"); Property Values Associates the property name with a value, timestamp, and quality. twPrimitive * value = twPrimitive_CreateFromNumber(properties.TempProp); twProperty * tempProp = twProperty_Create("TempProperty", value, NULL);       Click here to view Part 7 of this guide
View full tip
  Step 5: Java - Events   While connected to the server, you can trigger an event on a remote Thing. The code snippet from the Simple Thing example below shows how to use a ValueCollection to specify the payload of an event, and then trigger a FileEvent on a remote Thing.   Create Event   The two implementations of the VirtualThing.defineEvent method are used to create an event definition ThingWorx Platform. @ThingworxEventDefinitions(events = { @ThingworxEventDefinition(name = "SteamSensorFault", description = "Steam sensor fault", dataShape = "SteamSensor.Fault", category = "Faults", isInvocable = true, isPropertyEvent = false) }) public void defineEvent(String name, String description, String dataShape, AspectCollection aspects) { EventDefinition eventDefinition = new EventDefinition(name, description); eventDefinition.setDataShapeName(dataShape); if (aspects != null) { eventDefinition.setAspects(aspects); } this.getThingShape().getEventDefinitions().put(name, eventDefinition); } public void defineEvent(EventDefinition eventDefinition) { this.getThingShape().getEventDefinitions().put(eventDefinition.getName(), eventDefinition); }   Queue Event   To queue an event, create a ValueCollection instance, and load it with the necessary fields for the DataShape of that event. ValueCollection eventInfo = new ValueCollection(); eventInfo.put(CommonPropertyNames.PROP_MESSAGE, new StringPrimitive("Temperature at " + temperature + " was above limit of " + temperatureLimit)); super.queueEvent("SteamSensorFault", DateTime.now(), eventInfo); super.updateSubscribedEvents(60000);   Fire Event   You can send the client a request to fire the event with the collected values, the event, and information to find the entity the event belongs to as shown below. In order to send the Event to the ThingWorx Platform, use the VirtualThing.updateSubscribedEvents method. ValueCollection eventInfo = new ValueCollection(); eventInfo.put(CommonPropertyNames.PROP_MESSAGE, new StringPrimitive("Temperature at " + temperature + " was above limit of " + temperatureLimit)); super.queueEvent("SteamSensorFault", DateTime.now(), eventInfo); super.updateSubscribedEvents(60000);     Step 6: Java - Services   Create Services   Simply use the ThingworxServiceDefinition and ThingworxServiceResult anotations to create a service. Then, you can define the service as shown in this code: @ThingworxServiceDefinition(name = "GetSteamSensorReadings", description = "Get SteamSensor Readings") @ThingworxServiceResult(name = CommonPropertyNames.PROP_RESULT, description = "Result", baseType = "INFOTABLE", aspects = { "dataShape:SteamSensorReadings" }) public InfoTable GetSteamSensorReadings() { InfoTable table = new InfoTable(getDataShapeDefinition("SteamSensorReadings")); ValueCollection entry = new ValueCollection(); DateTime now = DateTime.now(); try { // entry 1 entry.clear(); entry.SetStringValue(SENSOR_NAME_FIELD, "Sensor Alpha"); entry.SetDateTimeValue(ACTIV_TIME_FIELD, now.plusDays(1)); entry.SetNumberValue(TEMPERATURE_FIELD, 50); entry.SetNumberValue(PRESSURE_FIELD, 15); entry.SetBooleanValue(FAULT_STATUS_FIELD, false); entry.SetBooleanValue(INLET_VALVE_FIELD, true); entry.SetNumberValue(TEMPERATURE_LIMIT_FIELD, 150); entry.SetNumberValue(TOTAL_FLOW_FIELD, 87); table.addRow(entry.clone()); // entry 2 entry.clear(); entry.SetStringValue(SENSOR_NAME_FIELD, "Sensor Beta"); entry.SetDateTimeValue(ACTIV_TIME_FIELD, now.plusDays(2)); entry.SetNumberValue(TEMPERATURE_FIELD, 60); entry.SetNumberValue(PRESSURE_FIELD, 25); entry.SetBooleanValue(FAULT_STATUS_FIELD, true); entry.SetBooleanValue(INLET_VALVE_FIELD, true); entry.SetNumberValue(TEMPERATURE_LIMIT_FIELD, 150); entry.SetNumberValue(TOTAL_FLOW_FIELD, 77); table.addRow(entry.clone()); } catch (Exception e) { e.printStackTrace(); } return table; }   NOTE: This service will be callable by the ThingWorx Platform.   Call Services   The are two types of service calls that can be made. The first type belongs to the ConnectedThingClient class. This client has methods for processing information where only the parameters for the method is necessary. The other type of call is based on services located on an Entity. For these calls, you must create a ValueCollection instance, and load it with the necessary parameters of the service.   After loading the ValueCollection instance, send the client the request to execute the service with the:   Parameter values Service name Timeout setting (in milliseconds) for the service to finish executing Information to find the entity the service belongs to   The first type of call can be seen in SimpleClient.java: InfoTable result = client.readProperty(ThingworxEntityTypes.Things, ThingName, "name", 10000); String name = result.getFirstRow().getStringValue("name");   The second type of call can be seen below: ValueCollection payload = new ValueCollection(); payload.put("name", new StringPrimitive("Timothy")); InfoTable table = handleServiceRequest("ServiceName", payload);   TIP: Put the code for creating the service and event in the constructor of the extended VirtualThing (or a method called from the constructor). Also, the service code examples will work as long as the actual service is defined. We recommend the annotation method as shown in the examples because it is much cleaner.       Click here to view Part 5 of this guide.  
View full tip
    Step 2: Java Properties   In the ThingWorx environment, a Property represents a data point, which has a:   Name Value Timestamp Quality (optional)   Define Properties   You can define attributes, base types and other aspects of ThingWorx properties.   Attributes   The table below provides information on the different attributes that are used to define a property. Attribute Details name Specifies the name of the property that will appear in ThingWorx when users browse to bind the related Thing. description Provides additional information for the property. baseType Specifies the type of the property. For a list of base types supported by the SDK, refer to the BaseTypes chart below.   BaseTypes   The table below provides information on the different types of properties that can be created in ThingWorx. BaseType Primitive Description BOOLEAN BooleanPrimitive True or false values only DATETIME DatetimePrimitive Date and time value GROUPNAME StringPrimitive ThingWorx group name HTML StringPrimitive HTML value HYPERLINK StringPrimitve Hyperlink value IMAGE ImagePrimitive Image value IMAGELINK StringPrimitive Image link value INFOTABLE InfoTablePrimitive ThingWorx infotable INTEGER IntegerPrimitive 32–bit integer value JSON JSONPrimitive JSON structure LOCATION LocationPrimitive ThingWorx location structure MASHUPNAME StringPrimitive ThingWorx Mashup name MENUNAME StringPrimitive ThingWorx menu name NOTHING N/A No type (used for services to define void result) NUMBER NumberPrimitive Double precision value STRING StringPrimitive String value QUERY N/A ThingWorx query structure TEXT StringPrimitive Text value THINGNAME StringPrimitive ThingWorx Thing name USERNAME StringPrimitive ThingWorx user name XML XMLPrimitive XML structure   Aspects   Aspects define the ways to interact with a property. The table below provides information on frequently used Aspect attributes of a property. Attribute Description isPersistent Set to TRUE for the ThingWorx server to persist the value even if it restarts. It is extremely expensive to have persistent values, so it is recommended to set this value to FALSE unless absolutely necessary. isReadOnly Set to TRUE to inform the ThingWorx server that this value is only readable and cannot be changed by a request from the server. dataChangeType Describes how the ThingWorx server responds when the value changes in the client application. Subscriptions to these value changes can be modeled in ThingWorx Core. If nothing needs to react to the property change, set this value to NEVER. dataChangeThreshold Defines how much the value must change to trigger a change event. For example 0 (zero) indicates that any change triggers an event. A value of 10 (ten) for example would not trigger an update unless the value changed by an amount greater than or equal to 10. defaultValue The default value is the value that ThingWorx Core uses when the RemoteThing connected to the device first starts up and has not received an update from the device. The value is different based on the different value for each base type. cacheTime The amount of time that ThingWorx Core caches the value before reading it again. A value of -1 informs the server that the client application always sends its value and the server should never go and get it. A value of 0 (zero) indicates that every time the server uses the value, it should go and get it from the client application. Any other positive value indicates that the server caches the value for that many seconds and then retrieves it from the client application only after that time expired. pushType Informs ThingWorx Core how the client application pushes its values to the server.   NOTE: cacheTime and dataChangeThreshold are for subscribed (bound) properties ONLY.   DataChangeType Values   This field acts as the default value for the data change type field of the property when it is added to the remote Thing. The possible dataChangeType values are below: Value Description  ALWAYS Always notify of the value change even if the new value is the same as the last reported value. VALUE Only notify of a change when a newly reported value is different than its previous value. ON For BOOLEAN types, notify only when the value is true. OFF For BOOLEAN types only, notify when the value is false. NEVER Ignore all changes to this value.   PushType Values   This aspect works in conjunction with cacheTime. The possible pushType values are below: Value Description ALWAYS Send updates even if the value has not changed. It is common to use a cacheTime setting of -1 in this case. VALUE Send updates only when the value changes. It is common to use a cacheTime setting of -1 in this case. NEVER Never send the value, which indicates that ThingWorx server only writes to this value.It is common to use a cacheTime setting of 0 or greater in this case. DEADBAND Added to support KEPServer, this push type is an absolute deadband (no percentages). It provides a cumulative threshold, such that the Edge device should send an update if its current data point exceeds Threshold compared to the last value sent to ThingWorx Core. It follows existing threshold fields limits.     Click here to view Part 3 of this guide.
View full tip
Announcements