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

Community Tip - Need to share some code when posting a question or reply? Make sure to use the "Insert code sample" menu option. Learn more! X

IoT Tips

Sort by:
    Step 2: Creating Machine Templates   Creating machine templates allows us to have specific levels of consistency with all of our machinery, no matter the purpose of the machine. As it goes towards more specific a machine, it will have it's own unique features and properties.   In the ThingWorx Composer, click the + New in the top left of the screen.   Select Data Shape in the dropdown.   In the name field, enter Fizos.MachineInspections.DataShape and set a Project (ie, PTCDefaultProject).   Click Save. All of our machine inspections will be based on this Data Shape. Add the list of fields below: Name Base Type Aspects Description GUID GUID Primary key String used as unique identifier for the inspection FactoryID Integer 0 minimum Factory identifier at time of inspection DateRequest Date N/A Date the inspection was requested DateCompleted Date N/A Date the inspection was completed Report JSON N/A This will hold the inspection report data   The properties for the Fizos.MachineInspections.DataShape Data Shape are as follows:   Create Machine Template In the ThingWorx Composer, click the + New in the top left of the screen.   Select Thing Template in the dropdown.   In the name field, enter Fizos.Machine.ThingTemplate. All of our machines will be based off this template. In the Base Template field, enter GenericThing and set a Project (ie, PTCDefaultProject). In real world examples, you would likely use a RemoteThing. 5. Open the Properties section. Create the following list of properties.   Name Base Type Aspects Description FactoryID Integer 0 minimum, default 0 The factory ID in which this machine is currently located Type String N/A Type of machine SerialNo String N/A Serial number of the machine Model String N/A Machine make and model State String Default: Idle Machine state (Idle, Working, Warning, Failed) Status String Default: Active Machine status (Active, Inactive, etc) Inspections InfoTable DataShape: Fizos.MachineInspections.DataShape List of inspection reports These properties should match the following: 6. Open the Alerts section. Create the following list of alerts.                     Name Property Configuration StateFailedAlert State Equal Failed StateWarningAlert State Equal Warning StatusInactiveAlert Status Equal Inactive These alerts should match the following: Create Machine Template By Product   Here at Fizos, we specialize in brauts and regular sausages. That being said, we will have some machines that are specific to each product. We will also have machines that are generic in nature and shared between the two systems. The template we just created will work for the machines that are common between both product lines. We'll now create two templates that will be specific to brauts and regular sausages. We are doing this to show the levels of granularity that can be done. In some cases, you might not want to create another template level based on your design.   In the ThingWorx Composer, click the + New in the top left of the screen.   Select Thing Template in the dropdown.   In the name field, enter Fizos.BrautsMachine.ThingTemplate. All of our brauts machines will be based off this template. In the Base Template field, enter Fizos.Machine.ThingTemplate and set a Project (ie, PTCDefaultProject).   Open the Properties section. Create the following list of properties.                                       Name Base Type Aspects Description CookTemperature Number default 155, units - minutes The standard the machine cooking temperature CookTime Number default 78.5, units - minutes The standard the machine cooking temperature EggLevel Number 0 minimum, 100 maximum, default 0, % units The percentage of eggs left in the machine CreamLevel Number 0 minimum, 100 maximum, default 0, % units The percentage of cream left in the machine   6. Open the Alerts section. Create the following list of properties. Name Property Configuration EggLevelWarningAlert EggsLevel Below 20 EggLevelDepletedAlert EggsLevel Below 5 CreamLevelWarningAlert CreamLevel Below 20 CreamLevelDepletedAlert CreamLevel Below 5   Now for the more general sausages. In the ThingWorx Composer, click the + New in the top left of the screen.   Select Thing Template in the dropdown.   In the name field, enter Fizos.SausageMachine.ThingTemplate. All of our sausage machines will be based off this template. In the Base Template field, enter Fizos.Machine.ThingTemplate and set a Project (ie, PTCDefaultProject).   Open the Properties section. Create the following list of properties. Name Base Type Aspects Description CookTemperature Number default 150, units - minutes The standard the machine cooking temperature CookTime Number default 72.5, units - minutes The standard the machine cooking temperature   Next, we'll create our services for how these machines will work.         Click here to view Part 3 of this guide.  
View full tip
  Step 5: Launch the EMS   1. Navigate to the microserver directory. cd .. 2. Ensure that you have ownership to the executable wsems and executable privileges. To check ownership. Ls -la -rwxrwxr-x 1 pi pi 769058 Jun 9 17:46 wsems NOTE: The account that owns the wsems executable should be used to log into the Raspberry Pi.   3. Confirm that you have executable privileges by run the following command: sudo chmod 775 wsems 4. Run the EMS. sudo ./wsems 5. Validate that your EMS successfully connected.   Depending on your logger level, your wsems execution should indicate Websocket connected in the log and the following INFO message: [INFO ] 2016-10-11 14:22:54,770 Main: Succesfully connected. Saving .booted config file   Troubleshoot Connectivity Issues   If the websocket does not connect successfully, check the following:    Issue                                               Solution WEBSOCKET CLOSED - Warning seen immediately after Websocket gets connected. Ensure that the host IP address, port and appKey of the ThingWorx composer instance are accurately set. If in the config.json you have selected the option to validate certification, then make sure the path to the certificate file is correctly set. twWs_Connect - Error trying to connect. Ensure that the host IP address, port running the ThingWorx Composer is accurately set. Check if the certification parameter is set or not. By default the WS EMS validates certificates. To ensure that the validation is performed correctly without errors, ensure that the certificates configuration parameters are set accurately with the correct path to the certificate file. If you do not wish to validate the certificate, you may explicitly set the validate parameter in certificates parameter set to false. twTlsClient_Connect - Error intializing TLS connection. Invalid certificate. Check if the ws_encryption parameter is present in your config.json file. By default, WS EMS enables TLS connection to ThingWorx platform. Ensure that the certificate file mentioned in the config.json is valid and stored in the path specified in the config.json. For debugging purposes, you can set the ssl parameter to none in ws_encryption configuration parameter. [WARN ] ... Main - Unable to connect to server. Trying .booted config file. Ensure that the host is up and running at the IP address and port number mentioned in the config.json file. Ensure that ThingWorx is running on the host address at the correct port number. Ensure that all appropriate networking ports are open and available.     Step 6: Configure Lua Script Resource (LSR)   The Lua Script Resource (LSR) is used to implement Things on the Edge device. Using the Lua Script Resource, you can define for your Raspberry Pi: Data Shapes Properties Services Tasks NOTE: The steps in this guide install the LSR on the same server (Raspberry Pi) as the EMS but it could also be installed on another server.   Launch a new terminal session that will be used to configure and launch the LSR. Navigate to etc folder. cd microserver/etc Create the config.lua file. sudo nano config.lua Set the logger level. scripts.log_level = "INFO" Turn off encryption for connection to EMS. This should only be used for testing. scripts.script_resource_ssl = false scripts.script_resource_authenticate = false Create the Edge RemoteThing. scripts.PiThing = { file = "thing.lua", template = "PiTemplate", scanRate = 1000, taskRate = 30000 }   NOTE: This configuration tells the Lua Script Resource to create a Thing called PiThing whose template definition is in PiTemplate.lua file in the path etc/customs/templates/PiTemplate.lua. You will create the template file PiTemplate.lua in the next section.   Property    Description scanRate Controls how frequently (milliseconds) properties are evaluated and pushed to the server. In our example, the Pi will check every 1 second if the values have changed. If so, the values will be pushed to the server. taskRate Controls how frequently the tasks specified in the Thing's template should be executed. In our example, the task will run every 30 seconds.   7.  Set the IP and port address of the LSR host server. scripts.rap_host = "127.0.0.1" scripts.rap_port = 8080   Sample config.lua File   Here is an example of a complete config.lua that can be used to configure the Lua Script Resource.   scripts.log_level = "INFO" scripts.script_resource_ssl = false scripts.script_resource_authenticate = false scripts.PiThing = { file = "thing.lua", template = "PiTemplate", scanRate = 1000, taskRate = 30000 } scripts.rap_host = "127.0.0.1" scripts.rap_port = 8080     Step 7: Configure Template File (Properties)   The template file is located in the microserver/etc/custom/templates directory. The template file provides a base configuration for defining Properties, Services, tasks, etc. This section will focus on defining the template file and adding Properties.   Navigate from the installation directory to the templates folder at microserver/etc/custom/templates . cd microserver/etc/custom/templates Create the file PiTemplate.lua. sudo nano PiTemplate.lua NOTE: This is the same template filename used in config.lua in the previous section. 3. Define the template. The module statement is used to define the template containing the configuration for the software component of the edge device. module ("templates.PiTemplate", thingworx.template.extend)   Parameter                                   Description templates.PiTemplate refers to the name of the template file: PiTemplate.lua thingworx.template.extend identifies the file as a template and provides base Thingworx template implementation   4. Define the Properties. For this guide, we are going to use the Raspberry Pi’s system properties like CPU temperature, clock frequency and internal voltage as sensor readings for the Remote Thing. Add the properties for these in your PiTemplate.lua file. properties.cpu_temperature={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_freq={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_volt={baseType="NUMBER", pushType="ALWAYS", value=0} NOTE: This code defines the properties cpu_temperature, cpu_freq and cpu_volt with a baseType of NUMBER. Additionally, it sets each default value to null as well as sets the pushType to ALWAYS which means that the property is always pushed to the Thingworx Server from the Raspberry Pi. The pushType can be set to ALWAYS, ON, OFF, NEVER or VALUE.   Sample PiTemplate.lua File   Here is an example of a complete PiTemplate.lua that can be used to configure the Lua Script Resource. module ("templates.PiTemplate", thingworx.template.extend) properties.cpu_temperature={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_freq={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_volt={baseType="NUMBER", pushType="ALWAYS", value=0}     Click here to view Part 3 of this guide. 
View full tip
  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_RegisterOnAuthenticated Callback function before the connection is made. This handler form can also be used to do a delay bind for all Things.   void AuthEventHandler(char * credType, char * credValue, void * userdata) { if (!credType || !credValue) return; TW_LOG(TW_FORCE,"AuthEventHandler: Authenticated using %s = %s. Userdata = 0x%x", credType, credValue, userdata); /* Could do a delayed bind here */ /* twApi_BindThing(thingName); */ } … twApi_RegisterOnAuthenticatedCallback(AuthEventHandler, NULL);     Step 8: Tasks   If you are using the built-in Tasker to drive data collection or other types of repetitive or periodic activities, create a function for the task. Task functions are registered with the Tasker and then called at the rate specified after they are registered. The Tasker is a very simple, cooperative multitasker, so these functions should not take long to return and most certainly must not go into an infinite loop.   The signature for a task function is found in [C SDK HOME DIR]/src/utils/twTasker.h. The function is passed a DATETIME value with the current time and a void pointer that is passed into the Tasker when the task is registered. After creating this function, it will need to be registered using the twApi_CreateTask function after the connection is created. Below shows an example of creating this function, registering this function, and how this function can be used.   #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("message", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } /* Update the properties on the server */ sendPropertyUpdate(); } … twApi_CreateTask(DATA_COLLECTION_RATE_MSEC, dataCollectionTask); … while(1) { char in = 0; #ifndef ENABLE_TASKER DATETIME now = twGetSystemTime(TRUE); twApi_TaskerFunction(now, NULL); twMessageHandler_msgHandlerTask(now, NULL); if (twTimeGreaterThan(now, nextDataCollectionTime)) { dataCollectionTask(now, NULL); nextDataCollectionTime = twAddMilliseconds(now, DATA_COLLECTION_RATE_MSEC); } #else in = getch(); if (in == 'q') break; else printf("\n"); #endif twSleepMsec(5); }   Click here to view Part 4 of this guide
View full tip
    Step 5: Collection Widget   A Collection widget is used to display information from a collection of Things. Similar to a Grid Widget, the Collection widget gives you complete control over how data is displayed by binding data to an embedded static Mashup.   In the first part of this step we will create a static Mashup with Parameters bound to its widgets. Next, we will configure a Collection widget to use the static Mashup we create. In the next step we will customize the Collection styling.   Create Static Mashup   Click the Browse tab on the far left of Composer, in the Visualizations section, click Mashups . Click + New to create a Mashup. Select Static Mashup, then click OK.   Name your Mashup TractorListFormat If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. Click Save. Click the Design tab If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. In the Layout tab, under Container > Positioning, Click Static, then scroll to Container Size, and click Fixed Size NOTE: A Static Mashup maintains fixed widget sizes and spacing, as opposed to a Responsive Mashup that will dynamically change widget sizes and spacing to use the available window area. Click the Width property and set it to 200 and the Height property to 60   In the lower left panel, click the Style tab and click the X to remove the default Style. Click the + icon, then select DefaultImageBorderStyle to remove all styling. NOTE: The default Mashup styling is removed so it will not override the sidebar and parent Mashup styling. Scroll to the Width property and set it to 200 and the Height property to 60 Click the Widgets tab and type label in the filter text box. Drag and drop two Label Widgets onto the upper left of your static Mashup.   Add Parameters to Mashup Select the Explorer tab then select the top level Mashup Click Configure Mashup Parameters from the drop-down menu in the upper left of the Mashup canvas.   Click the Add Parameter button. Type firstLine in the Name field and select a Base Type of STRING. Click Add Parameter again and name this parameter secondLine also with a Base Type STRING.   Click Done to return to Mashup Builder.   Bind Parameters to Widgets   Click the drop-down in the upper left of the Mashup canvas, then select Configure Bindings Click firstLine from the Properties list on the left. Clicking the drop-down arrow and click Add Source to display the Mashup entities that can be bound to the Mashup parameter named firstLine.   Select the checkbox next to the top LabelText property.   Click Done to return to the Configure Bindings pop-up. Click secondLine, then Binding Targets, and select the checkbox next to the bottom Label Text property, then click Done Click Done to close Configure Bindings pop-up and return to Mashup builder. NOTE: The Mashup parameters and bindings are displayed in the Connections panel at the bottom. Click Save before continuing to the next step.   Bind Data to Collection   Return to the main Mashup then drag and drop a Collection widget onto the top area of the left side bar. In the Collection Properties panel, set the View property to Table Scroll to the Mashup property, click the wand icon and browse to the name of the static Mashup created above. Drag the All Data source from the data panel on the right onto the Collection widget, then click Data in the Select Binding Target pop-up.   Set UIDField property and SortField to SerialNumber.   Drag the All Data source from the data panel on the right onto the Collection widget, then click Data in the Select Binding Target pop-up.   In the Collection Properties panel, scroll to MashupPropertyBinding and click *Add Enter the text below, then click Done: { "SerialNumber": "firstLine", "ModelNumber": "secondLine" } NOTE: This JSON property binds the SerialNumber and ModelNumber properties in the data source to the the firstLine and secondLine parameters in the embedded mashup   9. Save the Mashup and click View Mashup.   10. Test the Mashup and you will see the navigation panel on the left is showing data and is linked to the Google Map widget in the center.       Step 6: Customize Collection   The Collection uses default styling and no images. In this part of the exercise, we will replace the blue bar that indicates the selected row with a custom icon and modify the default styles so that the left panel's background color is shown.   Right-click on each of the images below to download and save them for use in the next step.     We will upload these images to create new Media entities and apply them to the Repeater widget.   Select the Browse folder icon on the far left of Composer, in the Visualization section click Media Click the + New to create a new Media entity and enter a name for the un-selected tractor image. Click Change in the Image section, then browse to the saved image. Click Open, then Save. Repeat these steps to create a Media entity for a selected tractor Open the static TractorListFormat mashup that controls the Collection widget formating Click and drag an Image widget onto the mashup In the lower left panel, in the SourceURL property, click the wand icon to select the unselected tractor image. Change both the Width and Height properties to 50 pressing Tab after each entry to record them.   Click the Explorer tab in the top left, click the top-most Mashup entity, then click the Style Properties tab Cick the X in the Style property and select DefaultImageBorderStyle to remove all styling, then click Save Click the More drop-down at the top of Composer and click Duplicate   Enter TractorListSelectFormat for the name and click Save then click the Design tab Click on the tractor image, then, the lower left, click the wand icon in the SourceURL property and select the selected tractor image and Click Save   Open your original Mashup and click on the Collection widget in the Mashuo Builder canvas. Scroll to the SelectedMashupName Property and click the + to select TractorListSelecteFormat.   Click Save for the Mashup, then View Mashup to see your Mashup with customized icons.   The default black text on green is a little hard to read. The steps below will change the text colors to make the data more readable. Open the TractorListSelectFormat Mashup then click on the top Label widget to change the color of the text. Click the Style Properties tab and expand Base and Label In color property select yellow and select Bold in the font-weight property before clicking Save. Select the other Label widget and assign a light grey color for the color then save the embedded Mashup. Reload the runtime view of the Mashup to see the results.     Step 7: Detail Panel   The right sidebar has a simple Image of a tractor along with product-specific information shown in Gauges and Value Displays.   The right sidebar contains two tabs in a Tabs - Responsive widget. The tabs are used to selectively hide and display groups of functions and data. The orange button labeled "View Vehicle Specs" is a Navigation widget that opens a pop-up window with other detailed product information. The colored range indications on the right Gauge were created by configuring the gauges ValueFormatter property to use State Formatting.   Add Tab Widget   Open the original, main Mashup and enter tab in the Widget panel search field. Drag and drop a Tabs widget onto the Right Sidebar.   Scroll to the Tab1Name property and enter Tractor Details. NOTE: This guide only covers configuring one of the two tabs added to the Mashup. Using the skills you've practiced thus far, feel free to add additional information to the tabs on your Mashup. Uncheck the RoundedCorners property. Click the Layout tab and click the radio button under Container > Orientation > Vertical   Add ValueDisplay Widgets   Type value in the Widget search box then click and drag a Value Display Widget onto Tab 1. In the Property panel, scroll to the Label property and enter Serial Number In the Data panel, expand Selected Row(s) then drag the SerialNumber property onto the Value Display widget and click Data when the Select Binding Target pop-up is displayed.   Drag another Value Display Widget onto the tab widget below to the first one and enter Name for the Label property. Drag name from the Selected Row(s) onto the second Value Display and then click Data. NOTE: Be sure to select data sources under Selected Row(s) so that data displayed will correspond to the tractor selected from either the map or the left side menu. Save the Mashup then click View Mashup to see all three panels working together to show data.   Add Gauges   Enter gauge in the Widget search box then click and drag a Gauge Widget onto Tab 1. In the Properties panel, enter 3000 for the MaxValue property and RPM in the Legend property. In the Data panel, expand Selected Row(s) then drag CurrentRPM onto the Gauge widget and click Data when the Select Binding Target pop-up is displayed. Drag another Gauge widget onto the canvas next to the first one and enter MPH for the Legend property. Drag CurrentSpeed from the Selected Row(s) onto the second Gauge, then click Data.   Click here to view Part 3 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: The estimated time to complete ALL 4 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. 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        5. 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      5. Run the CMake command listed below. This assumes CMake is already on your PATH. cmake ..      6. CMake has now produced a set of project files which should be compatible with your development environment.   Operating System Command Note 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 ..       7. 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     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    10. You should be able to see a Thing in your ThingWorx Composer called SimpleThing_1 with updated last Connection 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 2 of this guide
View full tip
    Step 5: Limiting Composer Access   If you would like to limit a User even more, there are a few things you can do. Go back to the Administrator account and open one of the accounts we created, such as User.OtherAgencies, you will notice the Enabled and Locked checkboxes. Enabled allows you to set whether an account can be used in ThingWorx during runtime. Locked dictates whether an account can be logged into at all.     Suppose we would like for the user to only see emptiness when they try to access the Composer. Follow the below steps to limit ThingWorx Composer access even more.   1. Open one of the Users we created earlier, ie User.OtherAgencies and click on the User Profile tab.  The user profile configuration allows an administrator to control which categories and entities should be displayed for an individual User.     2. You will see various sections and checkboxes. Uncheck all of them to stop access to importing, exporting, creating new Entities, being able to see existing Entities, and much more.     3. Click Save.   Now if you attempt to log into the ThingWorx Composer, you will notice a very difference experience without the ability to see current Entities. Perform this update for all the Users we created, except for User.IT and User.AgencySuperUser.     Step 6: Creating Clearance Levels   ThingWorx does not include default security clearance levels for you. What it does include are Thing Groups. Thing Groups are a reference-able entity type in ThingWorx that allow for Things and Thing Groups as its members. They also provide ThingWorx administrators the ability to manage at scale exposure of Things to only those that require access.   Before we create out first Thing Group, let us create some Entities that will house resources. The first will be an image that is top secret (shown below). In ThingWorx, this would be of type Media. After, we will create a file repository that will contain super-secret documents, a repository for job applications, and another repository for documents that are publicly accessible.   Our Top Secret Image:     Create the Media Entity    Let us store our image in ThingWorx. This image will need extra credentials to access it. This authentication can be performed with a basic username/password setup or SSO utilizing your own configurations.   1.  In the ThingWorx Composer, click the + New button in the top left.    2. In the dropdown list, click Media.   3. In the Name field, use TopSecretImage.   4. Set the Project field to an existing Project (ie, PTCDefaultProject) and click Save. 5. Click Change and add an image or use the image above.     6. Click on the Configuration tab.     7. For the Authentication Type field, select basic. You can select other types based on your Single Sign On and server level configurations, but we will keep this scenario simple.     8. Set a Username and Password that would be used to access our top secret Media.     9. Click Save.   Create the File Repositories   Let us create the setup for our repositories.   1.  In the ThingWorx Composer, click the + New button in the top left.    2. In the dropdown list, click Thing.     3. In the Name field, use TopSecretDocuments and FileRepository as the Base Thing Template.     4. Click Save.  5. Repeat steps 1-4 to create two File Repositories titled JobApplications and PublicDocuments.     Security Levels and Resource Lockdown    We now have our several resources and areas for differing levels of access. We will create 3 Thing Groups to mimic security levels. Our top-secret image will exist independently on ThingWorx, but also inside of a file repository for some level of redundancy. That file repository will belong to one Thing Group, while the other two file repositories will have their own separate Thing Groups.   1. Open the TopSecretDocuments File Repository Thing.  2. Click on the Services tab.     3. Scroll down to the SaveImage and click the play button.      4. Enter a path (such as /SecretImage.png) for the image to reside on the server and click Change to add an image.     5. Click the Execute button.    You now have your image in a File Repository. Let us add this Entity to a Thing Group, then configure the permissions at the Thing Group level.   1.  In the ThingWorx Composer, click the + New button in the top left.      2. In the dropdown list, click Thing Group.     3. In the Name field enter Clearance.Top.     4. Set the Project field to an existing Project (ie, PTCDefaultProject) and click Save. 5. Click the Services tab and click the play button to execute the AddMembers Service.     6. Click on the members Input Info Table and click the + Add button.      7. Enter TopSecretDocuments as the name of the member and Thing as the type. 8. Click Add and Save. Set the Project field to an existing Project (ie, PTCDefaultProject).      9. With you members set, click Execute. 10. Repeat steps 1-9 to create two more Thing Groups and add the other File Repository Entities that we created earlier. Name these Thing Groups Clearance.Public and Clearance.HumanResources. If we wanted to, we could create a Thing Group to add here as a member of another Thing Groups’ hierarchy.   Thing Group Permissions    Time to set the permissions. With the Clearance.Top Thing Group selected, follow the below instructions. As mentioned before, in a production system, you would have more Users and User Groups to completely setup this scenario.   1. Click Permissions. 2. For Visibility, enter PTCDefenseDepartment into the filter.  3. Expand the Organization and select the Agents unit and click Save. 4. Click the Run Time tab. 5. Set the permissions for the Agency.Agents User Group to have full access as shown below:  6. Click Save.  7. Repeat steps 1-6 for our other security clearance Thing Groups. Set the permissions to a department and User Group that you see fit.     Step 7: Next Steps   Congratulations! You've successfully completed the Securing Resources and Private Data guide. In this guide, you learned how to:   Securing data and private information Use Services, Alerts, and Subscriptions to handle processes without human interaction Handling group and organization permissions   The next guide in the Utilizing ThingWorx to Secure Your Aerospace and Defense Systems learning path is Connecting External Databases and Model.    Learn More   We recommend the following resources to continue your learning experience:   Capability Guide Build ThingWorx Solutions in Food Industry Build Design Your Data Model Build Implement Services, Events, and Subscriptions   Additional Resources   If you have questions, issues, or need additional information, refer to:   Resource Link Community Developer Community Forum
View full tip
  Discover how ThingWorx advance tree grids and grids 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 Mashup grids and JavaScript services.   Following the steps in this guide, you will build a web application with advanced data displays. We will teach you how to create a professional user interface that effectively conveys information to users.   You'll learn how to   Create dynamic tree grids to display hierarchy. Create dynamic grids to display growing data number of data points.   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 30 minutes       Step 1: What Are Dynamic Grids   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 A Dynamic Grid   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 maybe 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
    Use ThingWorx Kepware Server as an OPC UA Client   GUIDE CONCEPT   This guide will explain how ThingWorx Kepware server can function as both an OPC UA Server, and a client to a remote OPC UA Server.   Following the steps in this guide, you will create a OPC UA server in Azure, then we will teach you how to use data from the OPC UA server in ThingWorx.       YOU'LL LEARN HOW TO   Create an OPC UA Server in Azure Configure Kepware as on OPC UA Client Connect Kepware to ThingWorx Foundation Monitor OPC UA data in ThingWorx Composer   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 60 minutes     Step 1: Overview Diagram   In this guide, ThingWorx Kepware Server will serve as both an OPC UA client, and a ThingWorx Foundation client. ThingWorx Kepware Server is able to connect through firewalls to provide a seamless, end-to-end connection from an OPC UA server to ThingWorx Composer. Two ThingWorx Kepware Server instances can be configured to provide a tunnel for transporting machine data across the internet.       This guide will show how to create an OPC UA server in Azure, then browse the server data using Kepware. We will create a ThingWorx Thing with a Property that dynamically represents the value on the remote server.     Step 2: Install ThingWorx Kepware Server   In addition to OPC UA, ThingWorx Kepware Server includes over 150 factory-automation protocols. ThingWorx Kepware Server communicates between industrial assets and ThingWorx Foundation, providing streamlined, real-time access to OT and IT data — whether that data is sourced from on-premise web servers, off-premise cloud applications, or at the edge. This step will download and install ThingWorx Kepware Server. Download the ThingWorx Kepware Server executable installer. Right-click on the installer and select Run as administrator. Click Yes in the pop-up asking if you want to proceed. Select your Language and click OK.     On the "Welcome" screen, click Next.     Accept the End-User License Agreement and click Next.     Set the destination folder for the installation and click Next.     Set the Application Data Folder location and click Next. Note that it is recommended NOT to change this path.     Select whether or not you'd like a Shortcut to be created and click Next.     On the "Vertical Suite Selection" screen, keep the default of Typical and click Next.     On the "Select Features" screen, keep the defaults and click Next.     The "External Dependencies" screen simply lists everything that will be installed; click Next.     On the "Default Application Settings" screen, leave the default of Allow client applications to request data through Dynamic Tag address and click Next.     On the “User Manager Credentials” screen, set a unique strong password for the Administrator account and click Next. Note that skipping setting a password can leave your system less secure and is not recommended in a production environment.     Click Install to being the installation.     Click Finish to exit the installer.       Step 3: Create Industrial Gateway   To make a connection between ThingWorx Kepware Server and ThingWorx Foundation, you must first create a Thing.    In ThingWorx Composer, click Browse. On the left, click Modeling -> Things.     Click + NEW. In the Name field, enter IndConn_Server, including matching capitalization.     If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. In the Base Thing Template field, enter indus, then select the IndustrialGateway Thing template from the sorted list. Click Save.   Step 4: Connect Kepware to ThingWorx   This step will get ThingWorx Kepware Server set-up and connected to ThingWorx Foundation.   Now that you have created an Industrial Gateway Thing, you can configure ThingWorx Kepware Server to connect to ThingWorx Foundation.   Follow the steps to Create an Application Key and note the value. The appKey will be used in the the next step. Open the ThingWorx Kepware Server Configuration Windows application, then right-click on Project.     Select Properties….     In the Property Editor pop-up, click ThingWorx. In the Enable field, select Yes from the drop-down. In the Host field, enter the URL or IP address of your ThingWorx Foundation server, without http:// or https://. Enter the Port number.       In the Application Key field, copy and paste the Application Key you just created. In the Trust self-signed certificates field, select Yes from the drop-down. In the Trust all certificates field, select Yes from the drop-down. In the Disable encryption field, select No from the drop-down if you are using another server that uses TLS - URL begins with https://. Select Yes if you are using a ThingWorx Foundation server without TLS - URL begins with http:// Type IndConn_Server in the Thing Name field, including matching capitalization. If you are connecting with a remote instance of ThingWorx Foundation and you expect any breaks or latency in your connection, enable Store and Forward. Click Apply in the pop-up. Click Ok.   In the ThingWorx Kepware Server Event window at the bottom, you should see a message indicating Connected to ThingWorx.     NOTE: If you do not see the “Connected” message, repeat the steps above, ensuring that all information is correct. In particular, check the Host, Port, and Thing name fields for errors.     Step 5: Connect OPC UA Server to Kepware   Now that you have created an Industrial Gateway Thing, and ThingWorx Kepware Server is connected to ThingWorx Foundation, we can connect an OPC UA server to Kepware   Follow the steps to create an OPC UA server in Azure. Enter Resource Group, click Review + create.     Click Create.     In about a minute, the deployment success screen will be displayed.     Click Go to resource, and copy FQDN.     Open ThingWorx Kepware Server Configuration.     Right-click, then click New Channel. Scroll down to select OPC UA Client, then click Next.     Click Next twice to accept default settings, then enter the FQDN copied earlier. Add :50000 to the end of the domain name.     Click Next to accept all defaults. Click Yes to trust the certificate.   Click here to view Part 2 of this guide.
View full tip
  Use the Statistical Calculation Thing Shape to Execute Common Statistical Functions   GUIDE CONCEPT   This project will introduce the Statistical Calculation Thing Shape.   The steps in this guide outline how to utilize Descriptive Analytics in ThingWorx Analytics to perform common mathematical analyses on data sets. You will learn how to use the Statistical Calculation Thing Shape's built-in functionality to calculate the mean, median, mode, and other useful insights.     YOU'LL LEARN HOW TO   Create a Value Stream and Data Shape Create a Thing with the Statistical Calculation Thing Shape Modify a Property to record values to the Value Stream Utilize various built-in services to perform the Mean, Median, Mode, and Standard Deviation calculations   NOTE: The estimated time to complete this guide is 30 minutes.     Step 1: Introduction   Descriptive Analytics enables users to perform on-demand common statistical calculations and enable statistical monitoring. Output from these Services can then easily be added to IoT applications built with the ThingWorx platform.   For example, output generated by Descriptive Analytics can be used to build solution-specific visualizations (Mashups or Widgets), create Alerts based on logged Property values, or generate transformed data for machine learning processes.   Descriptive Analytics includes two microservers, each with its own set of statistical Services. This guide will deal specifically with the Statistical Calculation Thing Shape.   This Thing Shape will add a variety of built-in Services to any Thing or Thing Template you choose, such as calculations for Mean, Median, Mode, or Standard Deviation.   To perform these statistical calculations, a Property must have time-series data logged to a Value Stream.   In addition, the Statistical Calculation Thing Shape has been optimized to perform calculations only on particular time ranges and with a maximum entry-count. This helps minimize some of the performance hits that can occur from repeatedly accessing Value Streams.   You perform this "data grooming" via the QueryTimedValuesForProperty Service, which is also part of the Statistical Calculation Thing Shape.   In addition to the name of a Property with values logged to a Value Stream, you also provide a Start Date, End Date, and Max Item Count.   The QueryTimedValuesForProperty Service then formats the values from the Value Stream to work with for the other built-in statistical calculation Services.   Step 2: Create Prerequisites   The inputs to the built-in Services of the Statistical Calculation Thing Shape require time-series data stored in a Value Stream. Setting a Thing's Properties to be Logged will store valid time-series data on which to perform Descriptive Analytics.   Create Value Stream   Follow the steps below to create a Value Stream that you will later tie to a Thing.   On the ThingWorx Composer Browse tab, click DATA STORAGE > Value Streams, + New.   Select ValueStream and click OK.   In the Name field, enter scts_valuestream. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Save.   Create Data Shape   You will need a Data Shape to format the timed_values Property we will create in the next step.   On the ThingWorx Composer Browse tab, click MODELING > Data Shapes, + New.   In the Name field, enter scts_timed_values_datashape. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Field Definitions.   Click + Add. On the right slide-out, in the Name field, enter value. Change the Base Type to NUMBER.   At the top-right, click the "check with a +" icon for Done and Add. In the Name field, enter timestamp. Change the Base Type to LONG.   At the top-right, click the "check" icon for Done. At the top, click Save.       Step 3: Create Thing   Next, you will create a Thing and tie the previously-created Value Stream to it.   You will assign the Statistical Calculation Thing Shape to get a variety of built-in analytics Services to manipulate the data. You will also create a series of Properties to facilitate the new Services.   On the ThingWorx Composer Browse tab, click MODELING > Things, + New.   In the Name field, enter scts_thing. If Project is not already set, search for and select PTCDefaultProject. In the Base Thing Template field, search for and select GenericThing. In the Implemented Shapes field, search for and select StatisticalCalculationThingShape. In the Value Stream field, search for and select scts_valuestream.   At the top, click Save.   Add Properties   Next, you will add a series of Properties to scts_thing.   Perform the following steps repeatedly until all Properties have been added.   At the top, click Properties and Alerts.   Click + Add. On the right slide-out, in the Name field, enter numbers. Change the Base Type to NUMBER. Click Persistent. Click Logged.   At the top-right, click the "check with a +" icon for Done and Add. Repeat steps 3-7 until all of the properties in the table below have been added. NOTE: For the final standarddev_result Property, do NOT click Done and Add; you'll just click the check for Done instead. Property Name Base Type Data Shape Persistent  Logged start_time DATETIME N/A Checked NOT checked end_time DATETIME N/A Checked NOT checked timed_values INFOTABLE scts_timed_values_datashape Checked NOT checked mean_result NUMBER N/A Checked NOT checked median_result NUMBER N/A Checked NOT checked mode_result INFOTABLE none, i.e. leave it blank Checked NOT checked standarddev_result NUMBER N/A Checked NOT checked     At the top-right, click the "check" icon for DONE. At the top, click Save.   Step 4: Set Properties   You will now set the properties to guarantee that each calculation gives us a different answer.   Mean is the average. Median is the "middle" number from the dataset. Mode is the most common number. Standard Deviation is a measure of the "dispersion" of the dataset.   You will use the following dataset: 1, 5, 9, 5, 9, 1, 9.   The mean is 39 / 7 = 5.571...   The median is 5, as 5 is the middle of 1, 5, and 9.   Mode is 9, because 9 appears most commonly in the dataset.   Standard Deviation is 3.5989...   Perform the following steps to enter the above values into the numbers property.   Set numbers   Under the Value column and on the numbers property row, click the "pencil" icon for Set value of property.   On the right slide-out, enter 1.   At the top-right, click the "check" icon for Done. At the top, click Save.   Repeat steps 1-4 above, changing the value each time according to the table below: Value Change Count  Entered Value 2nd 5 3rd 9 4th 5 5th 9 6th 1 7th 9   You also need to set the start_time and end_time. These are dates used to define the time-period in which the Statistical Calculation Thing Shape will search for values.   For instance, you could set the calculations to run at midnight, and then use the past 24-hours as your time-period.   For this example, set dates to be 24 hours prior to the time at which you set the above values of the numbers property, through 24 hours in the future.   Set start_time   Under the Value column and on the start_time Property row, click the "pencil" icon for Set value of property.   On the right slide-out, search for and select the previous day.   At the top-right, click the "check" icon for Done. At the top, click Save.   Set end_time   Under the Value column and on the end_time property row, click the "pencil" icon for Set value of property.   On the right slide-out, search for and select the following day. At the top-right, click the "check" icon for Done. At the top, click Save.     Click here to view Part 2 of this guide.
View full tip
    Step 5: Verify Connectivity    The EMS is now attempting to talk to the ThingWorx platform.   However, ThingWorx does not have detailed information about the Edge device that is attempting to connect to it, so it will show up in the Unbound category.   Open ThingWorx Composer.     On the left, click Monitoring.     Click STATUS > Remote Things.     Click Unbound.     Confirm that you see the EdgeThing listed in the Unbound section. NOTE: The name EdgeThing comes from the config.lua script. EdgeThing is simply the name that is in that script, hence the name that you see in ThingWorx. To change the name of the device, you could stop both wsems.exe and luaScriptResource.exe, edit config.lua to use a different Thing name other than EdgeThing, and then restart both of the WSEMS programs. At that point, the Thing showing up in Remote Things -> Unbound would be whatever name you changed to in config.lua.   Create a Remote Thing   Now that the EMS is communicating with Foundation, let's create a Remote Thing to which Foundation can tie said connection.   In ThingWorx Composer, click Browse > MODELING > Things, + New.     In the Name field, enter EdgeThing. Note that the name must match the spelling and capitalization of the Thing's name that you entered in the EMS's config.lua for it to auto-connect.  If Project is not already set, search for and select PTCDefaultProject. In the Base Thing Template field, search for and select RemoteThingWithTunnelsAndFileTransfer.   At the top, Click Save. Note the status-indication pop-up indicating that EdgeThing is now connected.   Use Services to Explore EMS Files   Now that your Remote Thing is Saved and Connected, we can use some of the built-in Services to explore the EMS folders and files which we previously created for testing purposes.   At the top of EdgeThing, click Services.   Under the Execute column, click the Play Symbol for BrowseDirectory.   In the top-left path field, type / and click the bottom-right Execute button. Note the other and tw folders which we previously created for testing.     In the top-left path field, type /tw and click the bottom-right Execute button. Note the tw_test_01.txt file which we previously created for testing.     As the tw_test_01.txt file (and its parent folder) were items which we custom-created for this guide, you should now be 100% convinced that connectivity between Foundation and the EMS is dynamically working.   If so desired, you could explore into other folders (or even add additional files to these folders), run the BrowseDirectory Service again, and confirm that Foundation is now aware of the EMS and actively communicating.     Step 6: Next Steps   Congratulation! You've completed the Install the Edge MicroServer (EMS) guide.   In this guide, you learned how to:   Install the EMS Configure the EMS Connect the EMS to ThingWorx Foundation   The next guide in the Medical Device Service learning path is Setup a Raspberry Pi as an IoT Device.    The next guide in the Vehicle Predictive Pre-Failure Detection with ThingWorx Platform learning path is Use the EMS to Create an Engine Simulator.   Learn More   We recommend the following resources to continue your learning experience:   Capability Guide Connect Connect Industrial Devices and Systems   Additional Resources   If you have questions, issues, or need additional information, refer to the:   Resource Link Community Developer Community Forum
View full tip
    Step 3: Configure EMS   Now that you have "installed" (i.e. downloaded, unzipped, and moved to an appropriate location) the EMS on your Windows computer, it needs to be configured.   The primary method of doing so is via the config.json and config.lua files.   In this step, we'll create these files and paste some JSON / Lua configuration into them.   Navigate to the C:\CDEMO_EMS\etc directory.     Right-click inside the folder’s white-space and select New -> Text Document.     Change the name of New Text Document.txt to config.json. Here are instructions on how to configure your computer to display file extensions if you are not currently doing so.   Click Yes in the Rename Popup to confirm the file extension change.   Open config.json in your preferred text editor. NOTE: You will need a text editor of some type to modify the config.json file. Notepad++ is one such editor. However, the default Windows text editor, Notepad, is sufficient.     Copy and Paste the following code into the empty config.json file: { "ws_servers": [{ "host": "YOUR_IP_ADDRESS_HERE", "port": 443 }], "appKey": "YOUR_APP_KEY_HERE", "logger": { "level": "INFO", "publish_directory": "C:\\CDEMO_EMS\\logs", "publish_level": "INFO", "max_file_storage": 2000000, "auto_flush": true }, "http_server": { "ssl": false, "authenticate": false }, "ws_connection": { "encryption": "ssl" }, "certificates": { "validate": false, "disable_hostname_validation": true }, "tunnel": { "buffer_size": 8192, "read_timeout": 10, "idle_timeout": 300000, "max_concurrent": 4 }, "file": { "buffer_size": 8192, "max_file_size": 8000000000, "virtual_dirs": [ {"other": "C:\\CDEMO_EMS\\other"}, {"tw": "C:\\CDEMO_EMS\\tw"}, {"updates": "C:\\CDEMO_EMS\\updates"} ], "staging_dir": "C:\\CDEMO_EMS\\staging" } } When the EMS runs, the config.json file will answer the following questions: Code Section Question Answered ws_servers At what IP address / port is the ThingWorx Server located? appKey What is your Application Key? logger Where, and at what level, should we log errors? http_server What port should the WSEMS use to setup an HTTP server? ws_connection Should we use encryption? certificates Are we using Security Certificates? tunnel What are the configuration parameters for remote-tunneling? file What are the configuration parameters for file-transfer? We pre-defined the parameters for everything that we could, but you will still need to tell the WSEMS the IP address where the ThingWorx instance is located and a valid Application Key you either created earlier or may create now. TIP: You may have noticed the pre-existing config.json.complete and config.json.minimal files. These are example files that come with the WSEMS and are provided as an aid. The code above which you copied into your own config.json file is simply a customization of these aids. In particular, you may wish to look through the config.json.complete file, as it shows every available option which you might want to configure if you choose to make a custom application with the WSEMS. The config.json.complete file also contains comments for each of these options. However, a functional config.json file may NOT contain comments of any kind, so you would need to remove all comments if you choose to copy/paste some code from that file into a functional config.json of your own making.   Modify config.json to point to ThingWorx Foundation   Change YOUR_IP_ADDRESS_HERE to the IP address of your hosted ThingWorx instance. Note that you may use a URL, such as "pp-180207xx36jd.devportal.ptc.io". Either way, the IP or URL must be enclosed in quotation marks (""). Also, Port 443 is the appropriate port for the hosted ThingWorx trial. Other Ports may be needed for local installs. Change YOUR_APP_KEY_HERE to an Application Key which you have previously created. Or create a new Application Key now... and remember to set the Expiration Date far enough into the future.     Save and exit the file.   Create a config.lua file   Navigate to the C:\CDEMO_EMS\etc directory. Right-click inside the folder’s white-space and select New -> Text Document. Change the name of New Text Document.txt to config.lua . Click Yes on whether you want to change the filename extension. Open config.lua in your preferred text editor. Copy and Paste the following code into the empty config.lua file: scripts.log_level = "WARN" scripts.script_resource_ssl = false scripts.script_resource_authenticate = false scripts.EdgeThing = { file = "thing.lua", template = "YourEdgeThingTemplate", scanRate = 120000, sw_update_dir = "C:\\CDEMO_EMS\\updates" } Save and exit the file.   Create a Custom Template for the EdgeThing   Navigate to C:\CDEMO_EMS\etc\custom\templates. Right-click inside the folder’s white-space and select New -> Text Document. Change the name of New Text Document.txt to YourEdgeThingTemplate.lua. Click Yes on whether you want to change the filename extension. Open YourEdgeThingTemplate.lua in your preferred text editor. Copy and Paste the following code into the empty YourEdgeThingTemplate.lua file: require "shapes.swupdate" module ("templates.YourEdgeThingTemplate", thingworx.template.extend) Save and exit the file.     Step 4: Connect EMS   In this step, you'll launch the EMS so that it can communicate with your ThingWorx Foundation platform.   Navigate to the C:\CDEMO_EMS directory. Hold Shift and right-click in the white space of the folder to open an options menu.     Click Open PowerShell window here. Note that this guide assumes Windows 10, but older versions of Windows have similar command-line interfaces.     In the PowerShell window, enter the command .\wsems.exe and press the Enter key. Note: Do not close this window, or the connection to the ThingWorx platform will close. Also, please look through the output in the wsems.exe window. The final line should indicate Successfully connected. Saving .booted config file. If you do not see the Saving .booted comment, then you likely have an error in your config.json file. Close the wsems.exe application with a Ctrl+C and delete any .booted file before making further changes.     Open another PowerShell window as per the above instructions. In the second PowerShell window, enter the command .\luaScriptResource.exe and press the Enter key. Note: Do not close this second PowerShell window, or the connection to the ThingWorx platform will close.     NOTE: When the scripts start running, the WSEMS attempts to talk to the ThingWorx platform. However, at this point in the tutorial, ThingWorx does not have detailed information about the Edge device that is attempting to connect to it so you will see an error message. This is the expected behavior which we will resolve in the next step. The wsems.exe program runs through the config.json file in order to extract the basic connectivity information to reach the ThingWorx platform. The luaScriptResource.exe runs through the config.lua file to extract to which Thing the WSEMS should be connecting. Both .exes must be running in order to achieve connectivity with ThingWorx. Program File Accessed Purpose wsems.exe config.json Extracts basic connectivity information to reach the ThingWorx platform. luaScriptResource.exe config.lua Determines to which Thing the WSEMS should connect. NOTE: Since the luaScriptResource.exe file which we created above has a reference to a custom template, it goes also accesses the YourEdgeThingTemplate.lua file to extend the base functionality. Both .exes must be running in order to achieve connectivity with ThingWorx.       Click here to view Part 3 of this guide.
View full tip
  Remotely administer Windows Edge IoT Devices without coding.   GUIDE CONCEPT   Learn how to download, install, and configure the Edge Microserver (EMS) to create an AlwaysOn (TM) connection between Edge IoT Devices and ThingWorx Foundation.       YOU'LL LEARN HOW TO   Install the Edge MicroServer (EMS) Configure the EMS Connect the EMS to ThingWorx Foundation   NOTE: The estimated time to complete all parts of this guide is 30 minutes.     Step 1: Description   The Web Socket Edge MicroServer (WSEMS... or just EMS for short) is a pre-compiled application based on the C SDK.     Typically, the EMS is used on devices "smart" enough to have their own operating system, such as a Raspberry Pi or personal computer.   Rather than editing code and compiling into a custom binary (as with the SDKs), the EMS allows you to simply edit some configuration files to point the Edge IoT device towards the appropriate ThingWorx Foundation instance.   In addition, the EMS utilizes the PTC-proprietary AlwaysOn protocol to "phone-home", rather than having Foundation reach out to it. As such, the EMS will typically not require port forwarding/opening, and can easily communicate from a more-secure Edge environment to the Foundation server.     Step 2: Install EMS   In this step, you'll download and extract the EMS onto your personal Windows computer.   Versions of the EMS are available for Linux running on both x86 and ARM processors. Those are outside the scope of this guide, but require only minor modifications versus the instructions presented here.   Download the EMS.   Navigate to the directory where you downloaded the .zip file.     Extract the .zip file and explore into the extracted folder.     Navigate into and Copy all contents inside the \microserver directory.     Navigate to the C:\ root directory.     Create a C:\CDEMO_EMS folder. Note that this directory is not mandatory, but will be used throughout the rest of this guide.      Paste the contents of the extracted \microserver directory into C:\CDEMO_EMS.       Create Additional Directories   New folders may be added to the \CDEMO_EMS directory for various purposes.   Some of these will be utilized within this guide, while others may be utilized in future guides using the EMS.   Note that these particular names are not mandatory, and are simply the names used within this guide.    Create a C:\CDEMO_EMS\other directory. Create a C:\CDEMO_EMS\tw directory. Create a C:\CDEMO_EMS\updates directory.         Create Test Files   It can also be helpful during testing to have some small files in these folders to further demonstrate connectivity.   As these files were custom-created for the guide, seeing them within ThingWorx Foundation ensures that the connection between Foundation and the EMS is real and current.   In the C:\CDEMO_EMS\tw directory, create a text file named tw_test_01.txt. In the C:\CDEMO_EMS\other directory, create a text file named other_test_01.txt.     Click here to view Part 2 of this guide.
View full tip
    Step 3 : Sending and Receiving JSON Objects   The ThingWorx platform handles REST requests by default. This enables all services to be outsourced to REST requests based on the permissions of the user.   Nevertheless, part of the problem with allowing the default JSON result might be the organization of the response. For example, making a request to a service with an InfoTable response will return information for the DataShape used by the InfoTable and a 'rows' field containing the data of the InFoTable. This can be troublesome or a nuisance when creating efficient B2B communication or parsers for the ThingWorx response.   Receiving JSON   First, let's handle the necessary security measures and configure our permissions to create a new User and Application Key. Then, handle how to parse a JSON object in the body of the POST REST request to the ThingWorx Platform. As an example, you will create a service that will take in a person JSON object and perform some simple calculations for the response. The simple JSON object is as follows: { "person": { "first_name": "John", "last_name": "Doe", "dob": "03/16/1989", "roles": [ { "role": "Manager" }, { "role": "Executive" } ] } }   Follow the steps below to set up a helper function to perform age calculations, and another to take this JSON object and simply return a response based on the age of the person: In ThingWorx Composer, click the + New at the top of the screen. Select Thing in the dropdown. Name the Thing JSONResponseExample and click Save. Click the Services tab. Create a new service called CalculatePersonAge. Set the Output as Integer. Add the following Input: Name Base Type Required dob String True   8. Add the following JavaScript to help encode the string and return an HTML friendly string. var result = 0; try { if(dob) { var today = new Date(); var birthDate = new Date(dob); var age = today.getFullYear() - birthDate.getFullYear(); var month = today.getMonth() - birthDate.getMonth(); if (month < 0 || (month === 0 && today.getDate() < birthDate.getDate())) { age--; } result = age; } } catch(err) { logger.error("JSONResponseThing.CalculatePersonAge(): An error occured while calculating an age - " + err.message); }   9. Click Done. 10. Click Save and you're all done with this helper service. This is a simple function to calculate a person's age with limited error handling for simplicity. Now let's handle the JSON object coming in the request and our response.   In the Services tab of the JSONResponseExample Thing, create a new service called HandleJSONRequest. The service will have the below properties as parameters. Name Base Type Required person JSON True   3. Set the Output as JSON. 4. Add the following JavaScript to help encode the string and return an HTML friendly string. var result = {}; result.message = ""; if(!person) { result.message = "We need a person to calculate their age."; } else if(!person.dob) { result.message = "We need the person's date of birth to calculate their age."; } else { if(!person.first_name) { result.message = "The person you provided is " + me.CalculatePersonAge({dob: person.dob}) + " years old"; } else { result.message = person.first_name + " is " + me.CalculatePersonAge({dob: person.dob}) + " years old"; } }   5. Click Done and go to the Permissions tab. 6. Configure the permissions of the JSONResponseExample thing to allow access to the User you created earlier. This user will need to have runtime permissions to execute the service and must belong in an organization with visibility (ie, Everyone). 7. Click Save, and you're done.   You've just created a service that takes JSON and returns JSON. There are numerous services to work with JSON objects. There is also a service to convert your JSON object to an InfoTable, FromJSON in the InfoTableFunctions Resource. Keep in mind, you will need to set the JSON to a form that can be translated to an InfoTable. If this format is unknown, use the ToJSON service from this Resource to see an example.   Running REST Request   If you need a quick refresher on how to run a REST request to the ThingWorx Platform, please see our REST API guide. The request to the ThingWorx Platform will be a POST method and you will need to set your Application Key in the header.   Sending JSON   Because services are based on JavaScript (Rhino JavaScript Engine), you can create objects the same way you would anywhere else. This is a very simple concept, but it becomes more complex as you try to create data based on ThingWorx-specific entities or models.   To convert an InfoTable to a better-formed JSON object, you will need to process the InfoTable rows based on the DataShape fields. The following code will do that: /* ...Perform code that creates an InfoTable called values... */ //Begin Processing the rows of data var result = {}; result.some_information = "some values"; result.data = []; var fields = values.dataShape.fields; for (var index = 0; index < values.getRowCount(); index++) { var entry = {}; for (var name in fields) { entry[name] = values.rows[index][name]; } result.data.push(entry); } Looking for a quick translation to JSON? Try the ReadEntityAsJSON service of the EntityServices Resource. You can use this to respond with complex ThingWorx models or just to see the setup for the JSON object in order to translate it to something simple the way the code above handles InfoTables. For a quick example, create a User, then create a service based on the below JavaScript (set the name field of the parameter to the name of the user you create): var params = { name: 'NameOfUserYouCreated' /* STRING */, type: 'Users' /* STRING */, key: 'SomeValue /* STRING - Encryption-Decrption Key Name is Optional*/ }; // result: JSON var result = Resources["EntityServices"].ReadEntityAsJSON(params);     Step 4: Sending XML Based Requests    There are many B2B services and applications that prefer to use XML over JSON. ThingWorx can send/receive XML via SOAP requests (POST) using the ContentLoaderFunctions Resource.   To get started, create a Thing using the below steps. You will create new services in this Thing to make SOAP requests.   NOTE: Examples of these services can be found in the XMLRequestThing entity, which is provided in the download.   You will use the PostXML service of the ContentLoaderFunctions Resource. This service takes parameters from the proxy information to handle SSL issues. All of the parameters are optional.   Perform the following steps to create your ThingWorx service to make requests.   In the ThingWorx Composer, click the + New at the top of the screen. Select Thing in the dropdown. Name the Thing XMLRequestExample and click Save. Click the Services tab and create a service called SendXMLRequest. The service will have the below properties as parameters. Name Base Type Required url String True body XML True   6. In the Snippets section, filter and search for PostXML. 7. Once you’ve found PostXML under the ContentLoaderFunctions section, add it to the editor. You’ll see all of the possible parameters for the request. In this example, you will set only the url and content values. 8. Update the code snippet to include the parameters. Use the below code as a reference: try { var params = { url: url /* STRING */, content: body /* XML */, }; // result: XML var result = Resources["ContentLoaderFunctions"].PostXML(params); logger.info(" XMLRequestThing.SendXMLRequest(): Results From Calling Service - " + JSON.stringify(result)); } catch(error) { logger.error(" XMLRequestThing.SendXMLRequest(): Error Calling Service - " + error.message); }   9. Click Save and you’re done with your first SOAP request. You can now enter your XML string as a parameter to call your new service. You can also assign your XML string directly to a variable in the service.   /*jshint multistr: true */ var body = ' \ <?xml version="1.0" encoding="UTF-8"?> \ <menu> \ <header> \ <title>A Cool Title</title> \ </header> \ <body> \ <lunch_menu> \ <food> \ <name>Belgian Waffles</name> \ <price>$5.95</price> \ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description> \ <calories>650</calories> \ </food> \ <food> \ <name>Strawberry Belgian Waffles</name> \ <price>$7.95</price> \ <description>Light Belgian waffles covered with strawberries and whipped cream</description> \ <calories>900</calories> \ </food> \ </lunch_menu> \ <breakfast_menu> \ <food> \ <name>Belgian Waffles</name> \ <price>$5.95</price> \ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description> \ <calories>650</calories> \ </food> \ <food> \ <name>Strawberry Belgian Waffles</name> \ <price>$7.95</price> \ <description>Light Belgian waffles covered with strawberries and whipped cream</description> \ <calories>900</calories> \ </food> \ <food> \ <name>Berry-Berry Belgian Waffles</name> \ <price>$8.95</price> \ <description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description> \ <calories>900</calories> \ </food> \ <food> \ <name>French Toast</name> \ <price>$4.50</price> \ <description>Thick slices made from our homemade sourdough bread</description> \ <calories>600</calories> \ </food> \ <food> \ <name>Homestyle Breakfast</name> \ <price>$6.95</price> \ <description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description> \ <calories>950</calories> \ </food> \ </breakfast_menu> \ </body> \ </menu>'; ```   Click here to view Part 3 of this guide.
View full tip
    Modernize your Mashups with CSS to enhance the presentation of your application.   GUIDE CONCEPT   This project will introduce using CSS to create a customized, consistent look and feel for your IoT application.   Following the steps in this guide, you will create a custom CSS class definitions and bind these classes to Mashup features.   We will teach you how to present a professional-looking user interface and ensure consistency of style treatments within your application by implementing Cascading Style Sheets (CSS) in Mashups.     You'll learn how to   Create custom CSS classes using the integrated CSS editor Bind CSS classes to a Mashup and to individual Widgets Use Media queries to dynamically apply styling     Step 1: Custom CSS Benefits   You now have more flexibility to customize your application’s UI and improve the user experience using industry-standard web techniques. You can implement CSS in ThingWorx to control the visualization of your Mashup.   Feature                   Benefit Text Treatments Optimize text with shadow, color, font, and border Responsive UI Customize layout based on user actions and the data being displayed Media Queries Accommodate many screen sizes with flexboxes and other standard containers Animations Implement standard CSS key frames Customizations Modify application appearance without changing source Mashup Linting Expedite development with code auto-completion and design-time syntax warnings       Step 2: Access Sample Files   We created sample entities you can use to complete the steps in this guide. Download the attached Mashups_CustomCssTutorialMashup.xml From the Home page of Composer, click the Import/Export icon, then choose Import   Keep the default options and click Browse. Locate and select the CustomCssTutorialMashup.xml file you downloaded and extracted, click Open then Import.   Click Close after the Import successful message is displayed. Click the Browse tab in the left navigation panel, then click Mashups.                     6. Select the CustomCssTutorialMashup.                 7. Click View Mashup to view the Mashup.     NOTE: This is a simple Mashup designed to demonstrate how the UI changes when CSS is applied.       Step 3: Create CSS Rule Block   In this step, you will use the built-in editor to create a custom CSS class that will be used in the next step to modify the appearance of three buttons grouped by the Fieldset Widget.   Open the CustomCssTutorialMashup in Edit and Design view.     Click Custom CSS.     Copy the CSS class below and paste it into the Custom CSS editor: .myMashupClass .widget-fieldset .widget-ptcsbutton { box-shadow: 5px 5px 5px #888888; } NOTE: This class will create a shadow around all of the buttons that are in a Fieldset container  only after it is bound to a Mashup,   4. Click Save.     Tips   Press Ctrl -> Space to use the Auto-complete feature and see code snippets, which can expedite your development time.     The Linting feature will warn you if there are errors in your code, so you can fix them at design time.       Step 4: Apply Custom Class to Mashup   In this step we will demonstrate how to modify the look and feel of a Mashup without changing the Mashup itself. The myMashupClass we just created chains two selectors: the widget-fieldset and the widget-button. Only Widgets that are in both selector categories will be modified.   Click Design and select the Explorer tab, then select the top-level Mashup.     In the property panel in the lower left, locate the CustomClass property and type myMashupClass as the value. Press Tab to save the value change.     WARNING: You must press Tab after every property change in order for the new value to be saved.   4. Click Save then View Mashup to see that the buttons in the Field Set have shadow borders.       Step 5: Apply Custom Class to Widget   In addition to the Mashup level, you can apply style treatments directly to a Widget in your Mashup. In ThingWorx, the following Widgets have a CustomClass property you can modify:     For this example, we will make the text on one of the buttons all caps.   In the CustomCssTutorialMashup, click Custom CSS. Add the following css code: .myButtonClass .widget-ptcsbutton { text-transform: uppercase; }     Return to the Design view, and In the Explorer tab, click the button-3.     In the Property panel, enter myMashupClass to the CustomClass field, then press tab     Save then View Mashup the Mashup to see that the button text is now all caps.       Step 6: Bind Custom Class   The UI of a Mashup can be dynamically updated at runtime by binding the value of the CustomClass property to a dynamic data source such as: Services Mashup parameters Widgets (expression widgets for example)   In this portion of the guide, we will demonstrate modifying a Mashup in response to user actions:   Return to the Design view for the CustomCssTutorialMashup. In the Mashup Builder, click the Functions tab in the lower right, then expand Event Routers and expand eventsrouter-6     Click Output property and drag it onto the bottom button of the group of three buttons.     Select the CustomClass property from the pop-up to bind it to Button-4   In Mashup Builder click Custom CSS tab. Add the following css code: .myBoundButtonClass1 .widget-ptcsbutton { text-transform: lowercase; } .myBoundButtonClass2 .widget-ptcsbutton { text-transform: uppercase; }           7. Click Save and then View Mashup.           8. Click on each of the Apply buttons to see the results of a CSS class applied to in response to user actions.     Step 7: Use Media Queries   You can use Media queries to apply styling based on the characteristics of the device being used to access the application. For this example, we will use a CSS Class to hide three elements when the browser’s width is less than 600 pixels wide.   1. Open the CustomCssTutorialMashup in Edit and Design view, then click Custom CSS.     2. Copy the CSS class below and use the Custom CSS editor to add it to the top of the existing  CSS, then click Save. @media screen and (max-width: 1000px) { #root_ptcslabel-10-bounding-box { visibility: hidden; } #root_ptcstextfield-7-bounding-box{ visibility: hidden; } #root_ptcstextfield-12-bounding-box { visibility: hidden; } }   NOTE: The ID selector in your CSS must add root_ to the beginning, and -bounding-box to the end of the element’s ID shown in Mashup Builder.   3. Click View Mashup, then click and drag the edge of the browser window to reduce the width below 600 pixels.     NOTE: The three Widgets selected in the media class added in the last step will disappear as soon as the browser is less than 600 pixels wide.       Click here to view Part 2 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 push 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 AuthEventHandler(char * credType, char * credValue, void * userdata) { if (!credType || !credValue) return; TW_LOG(TW_FORCE,"AuthEventHandler: Authenticated using %s = %s. Userdata = 0x%x", credType, credValue, userdata); /* Could do a delayed bind here */ /* twApi_BindThing(thingName); */ } … twApi_RegisterOnAuthenticatedCallback(AuthEventHandler, NULL);     Click here to view Part 3 of this guide.
View full tip
    Step 6: Configure EMS   The EMS consists of two distinct components that perform slightly different operations and communicate with each other.   The first is the EMS itself which creates an AlwaysOn™ connection to ThingWorx Foundation. 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.     Now that you have "installed" (i.e. downloaded, unzipped, and moved to an appropriate location) the EMS on your Raspberry Pi, it needs to be configured.   The primary method of doing so is via the config.json and config.lua files.   In this step, we'll create these files and paste some JSON / Lua configuration into them.   Navigate to the /etc directory.       Right-click inside the folder’s white-space and select New File.... Enter config.json and click OK.   Right-click on the new config.json file and select Text Editor.     Copy and Paste the following code into the empty config.json file: Note that the backslashes (\) in the JSON below are escape characters necessary to properly address special characters, such as the forward-slashes (/) indicating path directories. { "ws_servers": [{ "host": "YOUR_IP_ADDRESS_HERE", "port": 443 }], "appKey": "YOUR_APP_KEY_HERE", "logger": { "level": "INFO", "publish_directory": "\/home\/pi\/Downloads\/microserver\/logs", "publish_level": "INFO", "max_file_storage": 2000000, "auto_flush": true }, "http_server": { "ssl": false, "authenticate": false }, "ws_connection": { "encryption": "ssl" }, "certificates": { "validate": false, "disable_hostname_validation": true }, "tunnel": { "buffer_size": 8192, "read_timeout": 10, "idle_timeout": 300000, "max_concurrent": 4 }, "file": { "buffer_size": 8192, "max_file_size": 8000000000, "virtual_dirs": [ {"other": "\/home\/pi\/Downloads\/microserver\/other"}, {"tw": "\/home\/pi\/Downloads\/microserver\/tw"}, {"updates": "\/home\/pi\/Downloads\/microserver\/updates"} ], "staging_dir": "\/home\/pi\/Downloads\/microserver\/staging" } } When the EMS runs, the config.json file will answer the following questions: Code Section Questions Answered ws_servers At what IP address / port is the ThingWorx Server located? appKey What is your Application Key? logger Where, and at what level, should we log errors? http_server What port should the WSEMS use to setup an HTTP server? ws_connection Should we use encryption? certificates Are we using Security Certificates? tunnel What are the configuration parameters for remote-tunneling? file What are the configuration parameters for file-transfer? We pre-defined the parameters for everything that we could, but you will still need to tell the WSEMS the IP address where the ThingWorx instance is located and a valid Application Key you either created earlier or may create now.   TIP: You may have noticed the pre-existing config.json.complete and config.json.minimal files. These are example files that come with the WSEMS and are provided as an aid. The code above which you copied into your own config.json file is simply a customization of these aids. In particular, you may wish to look through the config.json.complete file, as it shows every available option which you might want to configure if you choose to make a custom application with the WSEMS. The config.json.complete file also contains comments for each of these options. However, a functional config.json file may NOT contain comments of any kind, so you would need to remove all comments if you choose to copy/paste some code from that file into a functional config.json of your own making.     Modify config.json to point to ThingWorx Foundation   Change YOUR_IP_ADDRESS_HERE to the IP address of your hosted ThingWorx instance. You may wish to e-mail yourself the Foundation IP address using a web-mail account so that you can copy/paste on the Pi from your e-mail to the config.json file. Note that you may use a URL, such as "pp-180207xx36jd.devportal.ptc.io". Either way, the IP or URL must be enclosed in quotation marks (""). Also, Port 443 is the appropriate port for the ThingWorx hosted server. Ports for local-install may vary. 2. Change YOUR_APP_KEY_HERE to an Application Key which you have previously created. Or create a new Application Key now. You may wish to e-mail yourself the Application Key using a web-mail account so that you can copy/paste on the Pi from your e-mail to the config.json file.   3. Save and exit the file.   Create a config.lua file   Navigate to the /etc directory. Right-click inside the folder’s white-space and select New File.... Enter config.lua and click OK. Right-click on the new config.lua file and select Text Editor. Copy and Paste the following code into the empty config.lua file: scripts.log_level = "WARN" scripts.script_resource_ssl = false scripts.script_resource_authenticate = false scripts.PiThing = { file = "thing.lua", template = "YourEdgeThingTemplate", scanRate = 120000, sw_update_dir = "\/home\/pi\/Downloads\/microserver\/updates" } Save and exit the file.   Create a Custom Template for the EdgeThing   Navigate to /etc/custom/templates. Right-click inside the folder’s white-space and select New File.... Enter YourEdgeThingTemplate.lua and click OK. Right-click on the new YourEdgeThingTemplate.lua file and select Text Editor. Copy and Paste the following code into the empty YourEdgeThingTemplate.lua file: require "shapes.swupdate" module ("templates.YourEdgeThingTemplate", thingworx.template.extend) Save and exit the file.      Step 7: Connect EMS   In this step, you'll launch the EMS so that it can communicate with your ThingWorx Foundation platform.   On the Raspberry Pi , open a Terminal by clicking the Terminal icon in the top-left.   Navigate to the EMS's root folder, i.e. /home/pi/Downloads/microserver , by issuing the following command and then pressing Enter : cd /home/pi/Downloads/microserver   In the Terminal window, enter the command sudo ./wsems and press Enter . Note: Do not close this window, or the connection to the ThingWorx platform will close. Also, look through the output in the wsems window. Near the end, you should see Successfully connected. Saving .booted config file . If you do not see the Saving .booted comment, then you likely have an error in your config.json file... especially with either the address or Application Key .   Open another Terminal window as per the above instructions.   In this second Terminal window, Navigate to the EMS's root directory, i.e. /home/pi/Downloads/microserver , by issuing the following command and pressing Enter : cd /home/pi/Downloads/microserver In the second Terminal window, enter the command sudo ./luaScriptResource and press Enter . Note: Do not close this second Terminal window, or the connection to the ThingWorx platform will close.   NOTE: When the scripts start running, the EMS attempts to talk to the ThingWorx platform. However, at this point in the tutorial, ThingWorx does not have detailed information about the Edge device that is attempting to connect to it, so you will see an error message. This is the expected behavior which we will resolve in the next step. The wsems program runs through the config.json file in order to extract the basic connectivity information to reach the ThingWorx platform. The luaScriptResource program runs through the config.lua file to extract to which Thing the WSEMS should be connecting. Both programs must be running in order to achieve connectivity with ThingWorx. Program File Accessed Purpose wsems config.json Extracts basic connectivity information to reach the ThingWorx platform. luaScriptResource config.lua Determines to which Thing the WSEMS should connect. NOTE : Since the config.lua file which we previously created has a reference to a custom template, it also accesses the YourEdgeThingTemplate.lua file to extend the base functionality. Both programs must be running in order to achieve connectivity with ThingWorx. Troubleshoot Connectivity Issues   If the websocket does not connect successfully, check the following:   Issue Solution WEBSOCKET CLOSED - Warning seen immediately after Websocket gets connected. Ensure that the host IP address, port, and appKey of the ThingWorx composer instance are accurately set. If, in config.json, you have selected the option to validate certification, then make sure the path to the certificate file is correctly set. twWs_Connect - Error trying to connect. Ensure that the host IP address and port running the ThingWorx Composer is accurately set. Check if the certification parameter is set or not. By default, the WS EMS validates certificates. To ensure that the validation is performed correctly without errors, ensure that the certificates configuration parameters are set accurately with the correct path to the certificate file. If you do not wish to validate the certificate, you may explicitly set the validate parameter in certificates parameter set to false. twTlsClient_Connect - Error intializing TLS connection. Invalid certificate. Check if the ws_encryption parameter is present in your config.json file. By default, WS EMS enables TLS connection to the ThingWorx Platform. Ensure that the certificate file mentioned in config.json is valid and stored in the path specified. For debugging purposes, you can set the ssl parameter to none in ws_encryption configuration parameter. [WARN ] ... Main - Unable to connect to server. Trying .booted config file. Ensure that the host is up and running at the IP address and port number mentioned in the config.json file. Ensure that ThingWorx is running on the host address at the correct port number. Ensure that all necessary ports are open for communication.     Click here to view Part 4 of this guide.
View full tip
    Use the Pareto Chart Widget to visualize how issues compound to cause problems.   GUIDE CONCEPT   The Pareto Chart Widget is a useful method of displaying aggregate information.  In particular, it is often used to display multiple issues and how they combine to form an overall, larger problem.    This can be helpful when trying to determine "easy wins" by pointing out where your efforts will have the greatest impact.       YOU'LL LEARN HOW TO   Create a Data Shape Create a Thing Create an Info Table Property Populate an Info Table with appropriate data for a Pareto Chart Create a Mashup Utilize a Pareto Chart to display issue-aggregation   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 a factory is being automated using ThingWorx Foundation. In particular, this factory has some known issues with a robot arm that performs welding at a point along a conveyor belt.    When this welding robot has these issues, the factory line has to come to a complete halt while maintenance is performed on it.   Management has decided that these slow-downs are costing enough money that the robot arm needs some extra attention, up to and including modification to help alleviate these maintenance stops.    However, they're not sure what to tackle first. Every issues leads to a slow down, but some happen more frequently than others.    After talking with maintenance, four primary issues are identified, i.e.   Excess temperature on the welding end has caused some welds to fail due to simply burning through the material. Some of the joints need regular lubrication, preventing the arm from getting to the correct location in time as the part moves down the conveyor belt. The welding filler-material sometimes runs out, causing a stop while more is reloaded. The welding shielding gas sometimes runs out, causing a stop while more is reloaded.   Your task, then, is to start counting the number of times each of these failures occur. In addition, you need to create a small GUI which displays both how often these errors occur, and how they contribute to the overall downtime.    To accomplish this, you'll use a Pareto Chart Widget.     Step 2: Create Data Shape   In this scenario, we'll store the Pareto Chart's data in a Property type called an Info Table.   An Info Table is a spreadsheet-like Property, but in order to define the columns of the table, we first have to define a Data Shape. We'll do that in this step.   In the left-side navigation, click Browse > Modeling > Data Shapes. At the top, click + New. In the Name field, type TIPC_DataShape. If Project is not already set, search for and select PTCDefaultProject. At the top, click Field Definitions. At the top-left, click + Add. On the right-side slide-out, in the Name field, type month. Note that you want to leave "Base Type" as the default of "STRING". Check Is Primary Key. Click the "check with a plus" button for Done and Add. Add each of the following Field Definitions, entering the Name and selecting the Base Type from the drop-down as described in the table: Note that you will NOT enable "Is Primary Key" on any other Field Definitions, as you only need one Primary Key. Note that you will simply click the "check" button for Done after the last entry . Name Base Type  excess_temperature NUMBER  need_lubricant NUMBER  low_filler NUMBER  low_gas NUMBER At the top, click Save.   Step 3: Create Thing   Now that we have our Data Shape, we can create a Thing to hold the collected counts of various issues.   As already mentioned, we'll use an Info Table Property, formatted by the previously-created Data Shape, to do so.   Click Browse > Modeling > Things.   Click + New. In the Name field, type TIPC_Thing. If Project is not already set, search for and select PTCDefaultProject. In the Base Thing Template field, search for and select GenericThing.   At the top, click Save.     Add Info Table Property   Now that we have our Thing instantiated, we want to both add an Info Table Property, as well as set some Default Values.   At the top, click Properties and Alerts.   Click + Add.   On the right-side slide-out, in the Name field, type InfoTable_Property. Change Base Type to INFOTABLE. In the Data Shape field, search for and select TIPC_DataShape. Note that the Data Shape field will not appear until you set Base Type to INFOTABLE. Check Persistent.   At the top-right, click the "check" button for Done. At the top, click Save.   Set Value of Property Now that we have a place in which to store spreadsheet-like values, we'll do so manually for testing.   On the InfoTable_Property row, under the Value column, click the "pencil" icon for Set value of property.   On the pop-up, click + Add.   Enter the following values in each field as per the table below: Field Name Value month  January excess_temperature 5 need_lubricant 2 low_filler 1 low_gas 2   Click Add.   Click + Add again, enter the following values, and finish input by clicking Add, as per above. Field Name Value month February excess_temperature 7 need_lubricant 1 low_filler 3 low_gas 2 6. Click + Add again, enter the following values, and finish input by clicking Add, as per above. Field Name Value month March excess_temperature 6 need_lubricant 2 low_filler 1 low_gas 1   7. On the pop-up, click Save.   8. At the top, click Save.   Step 4: Create Mashup   Now that we have our data in-place for testing (and could be connected to automated systems after we finish testing), we need to visualize the data.   As mentioned, we'll use a Pareto Chart Widget, but first, we need to create a Mashup into which we can place the Widget.   Click Browse > Visualization > Mashups.   Click + New.   Leave the defaults and click OK.   In the Name field, type TIPC_Mashup. If Project is not already set, search for and select PTCDefaultProject. At the top, click Save .   At the top, click Design.   At the top-left, click the Widgets tab.   Drag-and-drop a Pareto Chart Widget onto the central Canvas.   At the top, click Save.   Click here to view Part 2 of this guide.
View full tip
    Step 8: Tasks   If you are using the built-in Tasker to drive data collection or other types of repetitive or periodic activities, create a function for the task. Task functions are registered with the Tasker and then called at the rate specified after they are registered. The Tasker is a very simple, cooperative multitasker, so these functions should not take long to return and most certainly must not go into an infinite loop.   The signature for a task function is found in [C SDK HOME DIR]/src/utils/twTasker.h. The function is passed a DATETIME value with the current time and a void pointer that is passed into the Tasker when the task is registered. After creating this function, it will need to be registered using the twApi_CreateTask function after the connection is created. Below shows an example of creating this function, registering this function, and how this function can be used.   #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("message", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } /* Update the properties on the server */ sendPropertyUpdate(); } … twApi_CreateTask(DATA_COLLECTION_RATE_MSEC, dataCollectionTask); … while(1) { char in = 0; #ifndef ENABLE_TASKER DATETIME now = twGetSystemTime(TRUE); twApi_TaskerFunction(now, NULL); twMessageHandler_msgHandlerTask(now, NULL); if (twTimeGreaterThan(now, nextDataCollectionTime)) { dataCollectionTask(now, NULL); nextDataCollectionTime = twAddMilliseconds(now, DATA_COLLECTION_RATE_MSEC); } #else in = getch(); if (in == 'q') break; else printf("\n"); #endif twSleepMsec(5); }      Step 9: File Transfer Example    To handle file transfers, a virtual directory is created in the SteamSensor1 entity and in the [C SDK HOME DIR]/examples/FileTransferExample application directory. The source code used for this example is found in [C SDK HOME DIR]/examples/FileTransferExample/src/main.c.   Inside of the [C SDK HOME DIR]/examples/FileTransferExample folder, create the folder structure shown below: /transfer/ /transfer/incoming/ /transfer/outgoing/ Inside of the /transfer/outgoing/ directory, create and open a file with the name outgoing.txt. Once the outgoing.txt document is open, add the following text, save, and close the file: Hello. This is a file coming from the client application. Navigate to the [C SDK HOME DIR]/examples/FileTransferExample/src/main.c code and update the lines below with the appropriate information for your IP, port, and the “admin_key” Application Key’s keyId value in the ThingWorx Composer: /* Server Details */ #define TW_HOST "127.0.0.1" #define TW_PORT 80 #define TW_APP_KEY "ce22e9e4-2834-419c-9656-ef9f844c784c" To support file transfers in your client application, you must use the twFileManager_AddVirtualDir function in order to create the virtual directories in the entity with such a capability. It will also define the directories available for file operations. A virtual directory maps a unique name to an absolute path of a directory in the file system. All subdirectories of the specified directory are exposed to the server. You can define multiple virtual directories. The directories do not need to be contiguous.   Staging Directory   As an optional, but recommended step, you should set the directory that the application should use for staging when performing file transfers. This can be seen in the line below and should be done before initializing the FileManager. The default directory of the FileManager is most likely owned by root and will require a change to either the location of the staging directory and the ownership of the staging directory, or running the application as a User with the correct permissions.   twcfg.file_xfer_staging_dir = "staging"; The example provided uses the TW_SHARE_DIRECTORY macro to create two virtual directories that will act as the root directories in the virtual file system of this application are added. The client is then started as follows with the necessary TW_ADD_FILE_TRANSFER_SHAPE function being called: TW_ADD_FILE_TRANSFER_SHAPE(); TW_SHARE_DIRECTORY("in", "/transfer/incoming/"); TW_SHARE_DIRECTORY("out", "/transfer/outgoing/"); The creations of the payloads used to create the remote directories on the platform have been moved to a helper function below to make the design cleaner: int setupSystemRepo(const char * remoteInPath, const char * remoteOutPath, const char * remoteFile); After our remote directories and files have been setup, it is time to perform the file transfers. Normally, this would mean invoking the Copy service for a Subsystem, but two functions have been created to make this process easier: int twFileManager_GetFile(const char * sourceRepo, const char * sourcePath, const char * sourceFile, const char * targetRepo, const char * targetPath, const char * targetFile, uint32_t timeout, char asynch, char ** tid) int twFileManager_SendFile(const char * sourceRepo, const char * sourcePath, const char * sourceFile, const char * targetRepo, const char * targetPath, const char * targetFile, uint32_t timeout, char asynch, char ** tid) The table below displays an example of the first set of parameters:    Parameter     Example                             Description sourceRepo SystemRepository The name of FileRepository or RemoteThing to transfer the file FROM. sourcePath outgoing The path specifying the location of the source file. sourceFile The name of the source file.   targetRepo SteamSensor1 The name of FileRepository or RemoteThing to transfer the file TO. targetPath incoming The path specifying the destination location of the file. targetFile incoming.txt The name of the file at the target. This name can differ from the sourceName. timeout 15,000 The amount of time (in seconds) to wait for a synchronous transfer to complete before cancelling the transfer. async false If false, the service call will block for timeout seconds or until the transfer completes. tid incoming0123 The unique TID associated with the file.   The C SDK also provides the ability to create a FileCallback function that the FileManager will call that function when any file transfer events occur. You can provide a wildcard filter so that only file transfer Events of files that match the filter call the callback function. In addition, callbacks can be set up as “one-shots” such that the callback is unregistered automatically after it is invoked the first time.   NOTE: An optional file transfer callback is registered in the code and provided. You will see the output from the function as files are sent and received.   After running this application, you will notice a new file in the transfer/incoming folder after refreshing. This is the file that we created in the ThingWorx Composer file system for the SystemRepository Entity and was able to copy from that location to our local project. We have also sent a file to the server’s SystemRepository. The BrowseFileSystem and GetFileListing services can be used to check for the folders and files created.   twFileManager_RegisterFileCallback(fileCallbackFunc, NULL, FALSE, NULL);     Step 10: Support Other Platforms   All Websocket errors indicate some general issue communicating with the ThingWorx platform. If you experience an issue connecting, refer to the table below for a list of websocket errors, their corresponding codes, and an explanation of the issue.    Code     Message                                                                      Troubleshooting 200 TW_UNKNOWN_WEBSOCKET_ERROR An unknown error occurred on the websocket. 201 TW_ERROR_INITIALIZING_WEBSOCKET An error occurred while initializing the websocket. Check your websocket configuration parameters for validity. 202 TW_TIMEOUT_INITIALIZING_WEBSOCKET A timeout occurred while initializing the websocket. Check the status of the connection to ThingWorx. 203 TW_WEBSOCKET_NOT_CONNECTED The websocket is not connected to ThingWorx. The requested operation cannot be performed. 204 TW_ERROR_PARSING_WEBSOCKET_DATA An error occurred while parsing websocket data. The parser could not break down the data from the websocket. 205 TW_ERROR_READING_FROM_WEBSOCKET An error occurred while reading data from the websocket. Retry the read operation. If necessary, resend the data. 206 TW_WEBSOCKET_FRAME_TOO_LARGE The SDK is attempting to send a websocket frame that is too large. The Maximum Frame Size is set when calling twAPI_Initialize and should always be set to the Message Chunk Size (twcfg.message_chunk_size). 207 TW_INVALID_WEBSOCKET_FRAME_TYPE The type of the frame coming in over the websocket is invalid. 208 TW_WEBSOCKET_MSG_TOO_LARGE The application is attempting to send a message that has been broken up in to chunks that are too large to fit in a frame. You should not see this error. 209 TW_ERROR_WRITING_TO_WEBSOCKET An error occurred while writing to the Web socket. 210 TW_INVALID_ACCEPT_KEY The Accept key sent earlier from ThingWorx is not valid.     Step 11: Next Steps   Congratulations! You've successfully completed the Low Level Device Connect Guide, and learned how to utilize the resources provided in the Edge SDK to create your own application.   The next guide in the Utilizing ThingWorx to Secure Your Aerospace and Defense Systems learning path is Tracking Activities and Statistics.    Learn More   We recommend the following resources to continue your learning experience:    Capability      Guide Build Design Your Data Model Build Implement Services, Events, and Subscriptions   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource       Link Community Developer Community Forum Support C Edge SDK Help Center      
View full tip
  Step 3: Create a Base Mashup   Now that you have some data, you need to create and configure a Mashup to display the data.   Using Mashup Parameters, the Collection Widget will replicate the base Mashup multiple times, correlating to each row of data in the Info Table Property.   On the ThingWorx Composer Browse tab, click Visualization > Mashups, + New                2. Keep the default ofResponsive(without selecting any Templates), and click OK          3. In the Name field, enter cwht_base_mashup.      4. If Project is not already set, search for and select PTCDefaultProject.      5. Click Save.     Add Widgets to Design   At the top, click Design. TIP: You can click the left arrow on the divider between the Browse left-navigation and the Mashup Builder to minimize the navigation and provide more room for the Mashup Builder itself.                  2.  On the Layout tab at the top-left, select Positioning > Static. You generally want the base Mashup to be "Static" so that you know the size of the cells which  the Collection Widget will replicate.                3. From the top-left Widgets tab, drag-and-drop a Gauge Widget onto the central Canvas area.             4. Drag-and-drop an LED Display Widget onto the central Canvas area.               5. Drag-and-drop a Text Field Widget onto the central Canvas area       Reduce the Mashup Size   At the top-left on the Explorer tab, select the Container.                2. In the central Canvas area, click-and-drag the far-right side of the container to reduce its horizontal size               3. Click-and-drag the bottom of the container to reduce its vertical size     Create Mashup Parameters   On the top-left Explorer tab, select the Mashup itself. A drop-down menu indicator will appear in the top-left of the Mashup.                 2. Click the top-left drop-down menu to reveal the Mashup options               3. Select Configure Mashup Parameters to open the Configure Mashup pop-up menu                4. Click Add Parameter three times              5. For the Name fields, enter first_number, second_number, and third_number.         6. Change the Base Type to NUMBER for all three Parameters           7. Click Done to close the Configure Mashup pop-up menu   Bind Mashup Parameters to Widgets   Click the Mashup's drop-down menu in the top-left to expose the options again. There are now additional options for first_number, second_number, and third_number.              2. Drag-and-drop first_number onto the Gauge Widget               3. Select Data on the Select Binding Target pop-up menu of the Gauge Widget.         4. Drag-and-drop second_number onto the LED Display Widget. You may have to first reselect the Mashup itself to reveal the Mashup's drop-down menu to access the second_number Mashup Parameter. Remember that you can easily select the Mashup itself through the Explorer tab.                                    5. Select Data on the Select Binding Target pop-up menu of the LED Display Widget.         6. Drag-and-drop third_number onto the Text Field Widget.         7. Select Text on the Select Binding Target pop-up menu of the Text Field Widget.         8. At the top, click Save. You can expand the Connections window at the bottom and select the Mashup itself to confirm that all three Mashup Parameters have been correctly bound to each Widget.          9. Click the Right Arrow on the far-left of the Mashup Builder to re-expand the Browse navigation menu.         Click here to view Part 3 of this Guide.
View full tip
  Use the Edge MicroServer (EMS) to simulate an engine with vibration sensors.   GUIDE CONCEPT   The Edge MicroServer (EMS) facilitates connectivity from Edge devices to ThingWorx Foundation.   It’s often easier, though, to start development with simulated Edge values rather than hooking up sensors.   This guide will show you how to simulate vibration values of an engine using the EMS.     YOU'LL LEARN HOW TO   Modify an EMS Template Provision Thing Properties and Values from an EMS rather than Foundation Send information from an EMS to Foundation Store large amounts of data in an InfoTable Property Create a simulator for testing   NOTE:  The estimated time to complete all parts of this guide is 30 minutes.     Step 1: Scenario   MotorCo manufactures, sells, and services commercial motors.   Recently, MotorCo has been developing a new motor, and they already have a working prototype.   However, they’ve noticed that the motor has a chance to FAIL CATASTROPHICALLY if it’s not properly serviced to replace lost grease on a key moving part.     In order to prevent this type of failure in the field, MotorCo has decided to instrument their motors with sensors which record vibration.   The hope is that these sensors can detect certain vibrations which indicate required maintenance before a failure occurs.   In this guide, you’ll begin this monitoring process by using ThingWorx Foundation to monitor and record vibration data from the prototype motor. In particular, you will learn how to provision Thing Properties and Values from an EMS, as well as how to permanently store these values for analysis in an Info Table Property.   These types of modifications to an EMS can be extremely helpful for the automotive segment in particular. For instance, each car that comes off the factory line could have custom, auto-generated EMS scripting that would dynamically create Foundation information for each car in the fleet. This could be a massive time-savings versus manually generating Thing Properties directly within Foundation.   Because the motor is still in the process of being instrumented with sensors, you’ll get all the functionality in-place beforehand by constructing a motor simulator using the Edge MicroServer (EMS).     Step 2: Modify config.lua   In the previous Use the Edge MicroServer (EMS) to Connect to ThingWorx  guide, you installed the EMS on a Windows PC, configured it to talk to ThingWorx Foundation, and then created an EdgeThing on Foundation to complete the connectivity.   This guide assumes that you have already completed that Windows EMS guide and have an active EMS connection to the EdgeThing.   Perform the following steps to modify this connection to increase the task rate of the EMS, which we'll use in the following steps to update Properties more quickly.   On your Windows PC, select the Windows PowerShell window where the luaScriptResource.exe program is running.   Type Ctrl-C to close the luaScriptResource.exe operation, i.e. hold the Control key and hit the C key.   Minimize the luaScriptResource.exe PowerShell window, and activate the wsemse.exe PowerShell window.   Type Ctrl-C to close the wsems.exe operation.   Return to Foundation, and note that EdgeThing is not connected.   Navigate to the C:\CDEMO_EMSE\etc directory.   Open config.lua in your prefered text-editor.   Change scanRate to 1000. Add the following line below the scanRate line: taskRate = 1000,   The final code of config.lua should be the following Note that the EMS may have slightly modified your config.lua file, such as adding a data_security_key line. Leave these EMS-generated modifications alone. scripts.log_level = "WARN" scripts.script_resource_ssl = false scripts.script_resource_authenticate = false scripts.EdgeThing = { file = "thing.lua", template = "YourEdgeThingTemplate", scanRate = 1000, taskRate = 1000, sw_update_dir = "C:\\CDEMO_EMS\\updates" } Save the config.lua file.     Click here to view Part 2 of this guide.
View full tip
  Display project burn up/down via a convenient Mashup Widget.   GUIDE CONCEPT   Long term projects need to be managed. As a project is scoped, requirements get defined and delivery-timeframes are estimated. As work is done, requirements are completed.   One way to track this project progress is with a Waterfall Chart.   This guide will show you how to utilize a Waterfall Chart Widget to easily display the project workflow.        YOU'LL LEARN HOW TO   Create a Data Shape Create a Thing Create an Info Table Property Populate an Info Table with appropriate data for a Waterfall Chart Create a Mashup Utilize a Waterfall Chart to display project progress   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 30 minutes     Step 1: Create Data Shape   In this scenario, we'll store the Waterfall Chart's data in a Property type called an Info Table.   An Info Table is a spreadsheet-like Property, but in order to define the columns of the table, we first have to define a Data Shape. We'll do that in this step.   In the left-side navigation, click Browse > Modeling > Data Shapes.   At the top, click + New.   In the Name field, type TPWC_DataShape. If Project is not already set, search for and select PTCDefaultProject .   At the top, click Field Definitions.   At the top-left, click + Add.   On the right-side slide-out, in the Name field, type month. Note that you want to leave "Base Type" as the default of "STRING". Check Is Primary Key.   Click the "check with a plus" button for Done and Add.   In the Name field, type amount. Change Base Type, to NUMBER.   Click the "check" button for Done.   At the top, click Save .     Step 2: Create Thing   Now that we have our Data Shape, we can create a Thing to document the project progress over time.   As already mentioned, we'll use an Info Table Property, formatted by the previously-created Data Shape, to do so.   Click Browse > Modeling > Things.   Click + New.   In the Name field, type TPWC_Thing. If Project is not already set, search for and select PTCDefaultProject. In the Base Thing Template field, search for and select GenericThing. At the top, click Save.   Add Info Table Property Now that we have our Thing instantiated, we want to add an Info Table Property. At the top, click Properties and Alerts.   Click + Add.   On the right-side slide-out, in the Name field, type InfoTable_Property. Change Base Type to INFOTABLE. In the Data Shape field, search for and select TPWC_DataShape. Note that the Data Shape field will not appear until you set Base Type to INFOTABLE. Check Persistent.   At the top-right, click the "check" button for Done. At the top, click Save.   Set Value of Property Now that we have a place in which to store spreadsheet-like values, we'll do so manually for testing.  On the InfoTable_Property row, under the Value column, click the "pencil" icon for Set value of property.   On the pop-up, click + Add.   Enter the following values in each field as per the table below: Field Name Value month January amount 380   Click Add.   Repeat Steps 2-4 multiples times until all of the below values have been entered. Note that amount should be left blank for both Mid-Term and Total. Note that you may enter fewer than all the values listed below if so desired, though your final Waterfall Chart will not match the following screenshots. month amount February 85 March 50 April 1000 May -300 June 0 Mid-Term   July 30 August -655 September -100 October -250 November 350 December -100 Total     On the pop-up, click Save.   At the top, click Save.   Step 3: Create Mashup   Now that we have our data in-place for testing (and could be connected to automated systems after we finish testing), we need to visualize the data.   As mentioned, we'll use a Waterfall Chart Widget, but first, we need to create a Mashup into which we can place the Widget.   Click Browse > Visualization > Mashups.   Click + New.   Leave the defaults and click OK.   In the Name field, type TPWC_Mashup. If Project is not already set, search for and select PTCDefaultProject. At the top, click Save.   At the top, click Design.   At the top-left, click the Widgets tab.   Drag-and-drop a Waterfall Chart Widget onto the central Canvas.   At the top, click Save.     Click here to view Part 2 of this guide.
View full tip