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

Community Tip - You can subscribe to a forum, label or individual post and receive email notifications when someone posts a new topic or reply. Learn more! X

IoT Tips

Sort by:
Note: The following tutorial are based on a Thingworx/CWC 9.5. Steps and names may differ in another version. Context As a human reaction, the tracked time displayed may be misperceived by the Operator. It can lead to a reject of the solution. CWC doesn’t have (yet?) the capability to configure the visibility to hide the timer. The purpose of this tutorial is to create a quick and straight to the point customization to hide the timer in the execution screen. All other features, services and interfaces are left untouched.   As a big picture, here are the 6 modifications you will need to do: Modify the 4 mashups Modify 2 values in 2 tables of the MSSQL database   Status The mashup containing the timer is PTC.FSU.CWC.Execution.Overview_MU. It is easy to duplicate it and hide the timer widget (switch the visible property to false). But now, how to set it in the standard interface? In order to do it, you need to duplicate the mashups linked to the Execution.Overview_MU mashup. PTC.FSU.CWC.Execution.Overview_MU is directly referenced by the following entities: PTC.FSU.CWC.Authoring.Preview_MU PTC.FSU.CWC.Execution.WorkInstructionStart_MU PTC.FSU.CWC.GIobalUI.ApplicationSpecificHeader_HD PTC.FSU.CWC.WorkDefinitionExecution.StationSelectionContainer_EP   Customization Duplicate all those mashups except Authoring.Preview_MU because we will focus only on the authoring side of CWC. Hereafter it will be called the same as the original + _DUPLICATE. Perform the following modifications.   Open PTC.FSU.CWC.GlobalUI.ApplicationSpecificHeader_HD_DUPLICATE, then in Functions: open the expression named NavigateToStationSelection. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.WorkDefinitionExecution.StationSelectionContainer_EP_DUPLICATE open the validator named ShowRaiseHand. Change the name of the 2 mashups to the relevant ones, example: PTC.FSU.CWC.Execution.WorkInstructionStart_MU_DUPLICATE and PTC.FSU.CWC.Execution.Overview_MU_DUPLICATE open the validator named ShowStationSelection. Change the name of the 2 mashups to the relevant ones, example: PTC.FSU.CWC.Execution.WorkInstructionStart_MU_DUPLICATE   Open PTC.FSU.CWC.Execution.Overview_DUPLICATE, then in Functions: open the expression named SetMashupToWorkInstructionStart. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.Execution.WorkInstructionStart_MU_DUPLICATE open the expression named SetMashupToStationSelection. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.WorkDefinitionExecution.StationSelectionContainer_EP_DUPLICATE   Open PTC.FSU.CWC.Execution.WorkInstructionStart_MU_DUPLICATE, then in Functions: open the expression named NavigateToStart. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.Execution.Overview_MU_DUPLICATE open the expression named NavigateToStationSelection. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.WorkDefinitionExecution.StationSelectionContainer_EP_DUPLICATE   Open PTC.FSU.CWC.WorkDefinitionExecution.StationSelectionContainer_EP_DUPLICATE, in functions: open the expression named NavigateToStart. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.Execution.Overview_MU_DUPLICATE open the expression named NavigateToWorkInstructionStart. Change the name of the mashup to the relevant one, example: PTC.FSU.CWC.Execution.WorkInstructionStart_MU_DUPLICATE   Now, let’s change the database value. In MSSQL, navigate to the thingworxapps database, and edit the dbo.menu table. Look the line for AssemblyExecution (by default line 22) and look the value in column targetmashuplink. Switch the original value PTC.FSU.CWC.WorkDefinitionExecution.StationSelectionContainer_EP to the name of the duplication of this mashup. Lastly, edit the dbo.menucontext table. Look the line related to CWC (application UID = 5) and look the value in column targetmashuplink. Switch the original value PTC.FSU.CWC.GlobalUI.ApplicationSpecificHeader_HD to the name of the duplication of this mashup.   Result After this modification, you can start and check an operation. You should see the following result:
View full tip
The use of non-optimized Data queries in ThingWorx can lead to performance issue and even system outage (OutOfMemory for example).   I'm sharing some observations that I have collected while reviewing customers code in the context of RCAs. This was initially tested in ThingWorx 8.4.5 using  PostgreSQL and MSSQL Persistence Providers, but it is still applicable to 9.0.2.   Observation 1 : the query filter is always applied in-memory on the platform, it is never used by the SQL statement.   var query = { "filters": { "type": "EQ", "fieldName": "firstname", "value": "Doe" } }; var result = Things["myDataTable"].QueryDataTableEntries({query: query}); The code above is fetching the entire Data Table from the DB, the filter is then applied in-memory on the platform. Applies to :  QueryDataTableEntries, QueryStreamData, QueryStreamEntries, QueryStreamEntriesWithData Alternative : (data table) use the values param on FindDataTableEntries and QueryDataTableEntries   Observation 2 : maxItems on QueryDataTableEntries is applied in-memory on the platform, it is not used by the SQL statement var result = Things["myDataTable"].QueryDataTableEntries({maxItems: 1 }); The code above is fetching the entire Data Table from the DB, the limit is then applied in-memory on the platform. Behavior is different for Stream Query APIs, see  Observation 3 below.   Observation 3 : maxItems on Stream query services is applied in-memory on the platform when used in conjunction with the query filter (always in-memory for Data Tables, see Observation 2)   var query = {...}; var result = Things["myStream"].QueryStreamEntriesWithData({maxItems: 1, query: query});  The code above is fetching the entire stream from the DB var result = Things["myStream"].QueryStreamEntriesWithData({maxItems: 1, source: "myThing"});  The code above is fetching only one record from the DB since the query param is not used.
View full tip
There have been a number of questions from customers and partners on when they should use different tools for calculation of descriptive analytics within ThingWorx applications. The platform includes two different approaches for the implementation of many common statistical calculations on data for a property: descriptive services and property transforms. Both of these tools are easy to implement and orchestrate as part of a ThingWorx application. However, these tools are targeted for handling different scenarios and also differ in utilization of compute resources. When choosing between these two approaches it is important to consider the specific use case being implemented along with how the implemented approach will fit into the overall design and architecture of the ThingWorx environment. This article will provide some guidance on scenarios to use each of these approaches in ThingWorx applications and things to consider with each approach.   Let's look at the two different approaches and some guidelines for when they should be used.   Descriptive services (click for more details) provide a set of ThingWorx services to analyze a data set and perform many common data transformations.  These services are targeted for performing calculations and transformations on recent operating history of a single property.  Descriptive services are called on demand to perform batch calculations. Scenarios to use descriptive services: On demand calculations performed within a mashup, a service call or an event to determine action and calculation results are not (always) stored Regular occurring calculations on logged property values or generated datasets (batch calculations) Calculations are done regularly in minutes, hours or days on a discrete set of data.  Examples: average value in last hour, median value in last day, or max value in last half hour.  Time between data creation and analysis is minutes or hours.  Some latency in the calculation result is acceptable for the use case. Input data set has 10s to 100s to 1000s of values.  Keep the size of the input data at 10,800 values or less.  If larger data sizes are required, then break them into micro batches if possible or use other tools to handle the processing. Multiple calculations need to be done from the same set of input data.  Examples: average value in last hour, max value in the last hour and standard deviation value in the last hour are all required to be calculated. Things to consider when using descriptive services Requires input dataset to be in the specific datashape format that is used by descriptive services.  If property values are logged in a value stream, there is a service to query the values and prepare the dataset for processing.  If scenarios where the data is not for a logged property, then another service or sql query can be used to prepare the dataset for processing. Requires javascript development work to implement.   This includes creation of a service to execute the descriptive services and usage of subscriptions and events to orchestrate calculations. An example of the javascript to execute descriptive services is available in the help center (here) Typically retrieval of the input data from value stream (QueryTimedValuesForProperty) is slowest part of the process. The input data is sent to an out of process platform analytics service for all calculations. Broader set of calculation services available (see table at the end of this article) Remember that these services are not meant to be used for big data calculations or big data preparation.  Look for other approaches if the input data sets grow larger than 10,800 values Property Transforms (click for more details) provide a set of transformation services for streaming data as it enters ThingWorx.   Property transforms are targeted for performing continuous calculations on recent values in the stream of a single property and delivering results in (near) real-time.  Since property transforms are continuous calculations, they are always running and using compute resources. Before implementing property transforms review the information in the property transform sizing guide to better understand factors that impact the scaling of property transforms. Scenarios to use: Continuous calculations on a stream for a single property as new data comes into ThingWorx New values enter the stream faster than one value per minute (as a general guideline) Calculations required to be done in seconds or minutes.  Examples: average electrical current in last 10 seconds, median pressure in the last 10 readings,  or max torque in last minute Time between data creation and analysis is small (in seconds).  Results of property transform is required for rapid decisions and action so reducing latency is critical Data sets used for calculation are small and contain 10s to 100s of values.  Calculated results are stored in a new property in the ThingModel Things to consider when using property transforms Codeless process to create new property transforms on a single property in the ThingModel Does not require input property values to be logged as calculations are performed on streaming data as it enters ThingWorx Unlike descriptive services which only execute when called, each property transform creates a continuously running job that will always be using compute resources.  Resource allocations for property transforms must be included in the overall system architecture.  Before selecting the property transform approach, refer to the Property Transform Sizing Guide for more information about how different parameters affect the performance of Property Transforms and results of performance load test scenarios. Let’s apply these guidelines to a few different use cases to determine which approach to select. 1. Mashup application that allows users to calculate and view median temperature over a selected time window In this scenario, the calculation will be executed on-demand with a user defined time window. Descriptive services are the only option here since there is not a pre-defined schedule and the user can select which data to use for the calculation.   2. Calculate the max torque (readings arriving one per second) on a press over each minute without storing all of the individual readings. In this scenario, the calculation will be executed without storing the individual readings coming from the machine. The transformation is made to the data on its way into ThingWorx and continuously calculating based on new values. Property transforms are the only option here since the individual values are not being stored.   3. Calculation of average pressure value (readings arriving one per second) over a five minute window to monitor conditions and raise an alert when the median value is more than two standard deviations from expected. In this scenario, both descriptive services and property transforms can perform the calculation required. The calculation is going to occur every 5 minutes and each data set will have about 300 values. The selection of batch (descriptive services) or streaming (property transforms) will likely be determined by the usage of the result. In this case, the calculation result will be used to raise an alert for a specific five minute window which likely will require immediate action. Since the alert needs to be raised as soon as possible, property transforms are the best option (although descriptive services will handle this case also with less compute resource requirements).   4, Calculation of median temperature (readings each 20 seconds) over 48 hour period to use as input to predict error conditions in the next week. In this scenario, the calculation will be performed relatively infrequently (once every 48 hours) over a larger data set (about 8,640 values). Descriptive services are the best option in this case due to the data size and calculation frequency. If property transforms were used, then compute resources would be tied up holding all of the incoming values in memory for an extended period before performing a calculation. With descriptive services, the calculation will only consume resource when needed, or once every 48 hours.   Hopefully this information above provides some more insight and guidelines to help choose between property transforms and descriptive services. The table below provides some additional comparisons between the two approaches.     Descriptive Services Property Transforms Purpose Provide a set of ThingWorx services to analyze a data set and perform many common data transformations. Provide a set of prescribed transformation services for streaming data as it enters ThingWorx. Processing Mode Batch Streaming / Continuous Delivery API / Service Composer interface API / Service Input Data Discrete data set Must be logged Single property Configurable by time or lookback Rolling data set on property X Persistence is optional Single property Configurable by time or lookback Output Data Return object handled programmatically Single output for discrete data set New property f_X in the input model Continuous output at configurable frequency Output time aligned with input data Available Services Statistics (min, max, mean, median, mode, std deviation) SPC calculations (# continuous data points: above threshold, in / out of range, increasing / decreasing, alternating) Data distribution: count by bins (histogram) Five numbers (min, lower quartile, median, upper quartile, max) Confidence interval Sampling frequency Frequency transform (FFT) Statistics (min, max, mean, median, mode, std deviation) SPC calculations (# continuous data points: above threshold, in / out of range, increasing / decreasing, alternating)
View full tip
    Step 3: Monitor SPC Properties   Once the properties have been configured, you are ready to progress on to SPC monitoring.   This is done by viewing the PTC.SPC.Monitoring_MU Mashup.   NOTE: Once a property has been configured for SPC monitoring, 2-5 minutes must pass before the accelerator has collected enough streaming values to perform SPC calculations. During this time, you may see an item that has 2 OOC rules violated; “Collecting Enough Data to Begin Monitoring” and “… to Compute Capability”.     Within Property SPC Status, click an item from the grid that has 0 in the OOC column. See that the Out of Control Rules area is blank, since there are no currently-violated SCP rules for that selected property. Both CP and CPK are above 1.0, showing that the process is capable. All the points in the charts are blue, as they do not violate any OOC rules. Within Property SPC Status, click an item from the grid that has a nonzero number in the OOC column.   See that the Out of Control Rules area has one or more rules listed that are currently being violated. Here, the rule being violated is Range Out of Control. One or more of the charts may have point(s) that are red. Here, you can see one of the points in the R chart is red, as it is above the Upper Control Limit. In the bottom-left, click Refresh Now.   Note that the datetime value of the date picker in the lower-left indicates the period to which the Mashup has updated. It is possible that Properties that were previously not in violation are now violating OOC rules; the opposite is also possible. Note that not all points that violate an OOC rule will display in red. Here, you can see that the rule 8 Consecutive Points Above Center Line is violated, but the corresponding points in the X-Bar Chart are not red. View the SPC status at a time from the recent past. In the lower-left, click date picker. Choose a datetime of 2-3 minutes in the past. You will see that the date picker reflects the datetime value you selected. All the Widgets in the Mashup are updated to reflect their status at that point in time. Enter continuous monitoring mode. Select any of the eight (8) items from the Property SPC Status area. To the left of the Refresh Now button, click the toggle. This will enable the Mashup to auto-refresh every 30 seconds. In the upper-right corner of the Property SPC Status area, click the gray arrow to expand the monitoring display.   Every 30 seconds, the monitoring display will update to show the most recent status for the item you selected.       Step 4: Next Steps   Congratulations! You’ve successfully completed the Deploy Statistical Process Control guide, and learned how to:   Configure multiple properties for SPC monitoring Identify abnormalities in streaming property values   Learn More   We recommend the following resources to continue your learning experience:    Site              Link Wikipedia Western Electric Rules Wikipedia Process Capability   Additional Resources If you have questions, issues, or need additional information, refer to:    Resource       Link Community Developer Community Forum Support ThingWorx Help Center  
View full tip
    Configure streaming asset properties for SPC monitoring.   Guide Concept   Note: This guide is intended only as a starting point and is not a fully developed or supported solution. This accelerator has been developed using ThingWorx 8.5 and should not be used with any previous versions of the software.   This project introduces you to configuring Properties from your connected streaming assets for Statistical Process Control (SPC) monitoring.   Following the steps in this guide, you will learn how multiple connected assets and their Properties can be displayed in a hierarchy tree.   You will then configure these Properties using predetermined set points, and upper and lower control points for the assets.   Finally, you will learn to navigate the monitoring of the Properties.   We introduce some of the basic building blocks of an SPC accelerator, including important Things and Mashups. You will also use ThingWorx Timers to simulate streaming data.     You'll learn how to   Configure multiple properties for SPC monitoring Identify abnormalities in streaming property values   NOTE: The estimated time to complete this guide is 30 minutes     Step 1: Import SPC Accelerator   Before exploring Statistical Process Control (SCP) within ThingWorx Foundation, you must first import some Entities via the top-right Import / Export button.   Download and unzip PTC_StatisticalCalculations_PJ.zip and PTC_SPC_PJ.zip. These two files each contain a ThingWorx project of a similar name. Import PTC_StatisticalCalculations_PJ.twx first. Import PTC_SPC_PJ.twx once the other import has completed. Explore the imported entities.   Each of the projects contain multiple entities of various types. The most important entities you will use in this guide are as follows:    Entity Name                                   Description Motor_Pump1 Timer to simulate streaming data Motor_Blower1 Timer to simulate streaming data PTC.SPC.ConfigurationHelper Thing that manages the accelerator PTC.SPC.Configuration_MU Mashup for configuring SPC properties PTC.SPC.Monitoring_MU Mashup for monitoring SPC properties   Step 2: Configure Properties for SPC monitoring   You may configure SPC monitoring for multiple production lines, connected assets on those lines, and time-series Properties on those assets using the SPC accelerator.   This is done by viewing the PTC.SPC.Configuration_MU Mashup.   Follow these steps to configure an SPC Property.   Create a new production line   In the Enter New Production Line Name text field, type Line100. Click Add New Line.   Now you will see the new production line added to the Asset Hierarchy tree along the left. All production lines you’ve created (as well as their assets and the assets’ Properties) will be shown here.   In the lower-right, the SPC Property Configuration area has disappeared because the item selected in the Asset Hierarchy tree is the new line; only assets within lines can have streaming Properties.   Add a streaming asset to Line100   Within the Select Asset Thing entity picker, type Motor_Blower1. Click Add Asset for Line.   This asset has Properties that are streaming into ThingWorx. Multiple assets can be added to the same production line by selecting the line from the Asset Hierarchy tree and following the steps above.   If you select the new asset from the Asset Hierarchy tree, you will see that the list of Properties Eligible for SPC Monitor is shown in the SPC Property Configuration area. All Properties have the same default configuration associated with them.   Configure a property for SPC Monitoring   Below is a brief description of each of the configuration parameters:    Parameter           Description Sample Size Number of consecutive property values to average together. For example, a Sample Size of 5 will tell the accelerator to group every 5 property values together and calculate their average value. XBar Points Number of the most recent sample aggregations to display in the SPC Monitoring Mashup. This also affects SPC calculations. Capability Points Number of the most recent sample aggregations to use when populating the Capability Histogram in the SPC Monitoring Mashup. Set Point Value determined to be the set point for that particular property on the asset. Lower Design Spec Value determined to be the lower design spec for that particular property on the asset. This is used for capability calculations. Upper Design Spec Value determined to be the upper design spec for that particular property on the asset. This is used for capability calculations.   Select Pressure1 from the list of eligible properties. Enter the following values:  Properties                      Values Sample Size 5 Xbar Points 30 Capability Points 60 Set Point 73 Lower Design Spec 68 Uppder Design Spec 78   3, Select Xbar-R Chart. 4. Click Add or Update SPC Monitoring. 5. Pressure1 is added to the Asset Hierarchy tree underneath the Motor_Blower1 asset. 6. If you select this Property, you can modify the configuration and save it by clicking Add or Update SPC Monitoring.   Configure assets and Properties   Follow these steps using the following parameters:                                     Line Asset  Property  Sample Size Xbar Point Capability Points Set Points Lower Design Spec Upper Design Spec Chart Type 100 Motor_Blower1 Pressure1 5 30 60 73 68 78 Xbar-R 100 Motor_Blower1 Pressure2 5 30 60 78 68 89 Xbar-R 100 Motor_Blower1 Temperature1 5 30 60 50 44 56 Xbar-s 100 Motor_Blower1 Temperature2 5 30 60 85 73 97 Xbar-s 100 Motor_Pump1 Vibration10 5 30 60 150 108 190 Xbar-s 100 Motor_Pump1 Vibration11 8 60 100 200 168 220 Xbar-s 100 Motor_Pump1 Pressure100 5 30 60 100 84 118 Xbar-R 100 Motor_Pump1 Pressure200 5 30 60 90 84 97 Xbar-R   As you add assets to Line100 and configure their Properties, you will see the Asset Hierarchy tree grow. If you need to remove an asset or its associated Properties from the Asset Hierarchy tree, you may select that item, and click Remove Selected. For any item you remove, its child-items will also be removed.   Click here to view Part 2 of this guide.
View full tip
  PLEASE NOTE DataConnect has now been deprecated and no longer in use and supported.   We are regularly asked in the community how to send data from ThingWorx platform to ThingWorx Analytics in order to perform some analytics computation. There are different ways to achieve this and it will depend on the business needs. If the analytics need is about anomaly detection, the best way forward is to use ThingWatcher without the use of ThingWorx Analytics server. The ThingWatcher Help Center is an excellent place to start, and a quick start up program can be found in this blog. If the requirement is to perform a full blown analytics computation, then sending data to ThingWorx Analytics is required. This can be achieved by Using ThingWorx DataConnect, and this is what this blog will cover Using custom implementation. I will be very pleased to get your feedback on your experience in implementing custom solution as this could give some good ideas to others too. In this blog we will use the example of a smart Tractor in ThingWorx where we collect data points on: Speed Distance covered since last tyre change Tyre pressure Amount of gum left on the tyre Tyre size. From an Analytics perspective the gum left on the tyre would be the goal we want to analyse in order to know when the tyre needs changing.   We are going to cover the following: Background Workflow DataConnect configuration ThingWorx Configuration Data Analysis Definition Configuration Data Analysis Definition Execution Demo files   Background For people not familiar with ThingWorx Analytics, it is important to know that ThingWorx Analytics only accepts a single datafile in a .csv format. Each columns of the .csv file represents a feature that may have an impact on the goal to analyse. For example, in the case of the tyre wear, the distance covered, the speed, the pressure and tyre size will be our features. The goal is also included as a column in this .csv file. So any solution sending data to ThingWorx Analytics will need to prepare such a .csv file. DataConnect will perform this activity, in addition to some transformation too.   Workflow   Decide on the properties of the Thing to be collected, that are relevant to the analysis. Create service(s) that collect those properties. Define a Data Analysis Definition (DAD) object in ThingWorx. The DAD uses a Data Shape to define each feature that is to be collected and sends them to ThingWorx Analytics. Part of the collection process requires the use of the services created in point 2. Upon execution, the DAD will create one skinny csv file per feature and send those skinny .csv files to DataConnect. In the case of our example the DAD will create a speed.csv, distance.csv, pressure.csv, gumleft.csv, tyresize.csv and id.csv. DataConnect processes those skinny csv files to create a final single .csv file that contains all these features. During the processing, DataConnect will perform some transformation and synchronisation of the different skinny .csv files. The resulting dataset csv file is sent to ThingWorx Analytics Server where it can then be used as any other dataset file.     DataConnect configuration   As seen in this workflow a ThingWorx server, DataConnect server and a ThingWorx Analytics server will need to be installed and configured. Thankfully, the installation of DataConnect is rather simple and well described in the ThingWorx DataConnect User’s guide. Below I have provided a sample of a working dataconnect.conf file for reference, as this is one place where syntax can cause a problem:   ThingWorx Configuration The platform Subsystem needs to be configured to point to the DataConnect server . This is done under SYSTEM > Subsystems > PlatformSubsystem:     DAD Configuration The most critical part of the process is to properly configure the DAD as this is what will dictate the format and values filled in the skinny csv files for the specific features. The first step is to create a data shape with as many fields as feature(s)/properties collected.   Note that one field must be defined as the primary key. This field is the one that uniquely identifies the Thing (more on this later). We can then create the DAD using this data shape as shown below   For each feature, a datasource needs to be defined to tell the DAD how to collect the values for the skinny csv files. This is where custom services are usually needed. Indeed, the Out Of The Box (OOTB) services, such as QueryNumberPropertyHistory, help to collect logged values but the id returned by those services is continuously incremented. This does not work for the DAD. The id returned by each services needs to be what uniquely identifies the Thing. It needs to be the same for all records for this Thing amongst the different skinny csv files. It is indeed this field that is then used by DataConnect to merge all the skinny files into one master dataset csv file. A custom service can make use of the OOTB services, however it will need to override the id value. For example the below service uses QueryNumberPropertyHistory to retrieve the logged values and timestamp but then overrides the id with the Thing’s name.     The returned values of the service then needs to be mapped in the DAD to indicate which output corresponds to the actual property’s value, the Thing id and the timestamp (if needed). This is done through the Edit Datasource window (by clicking on Add Datasource link or the Datasource itself if already defined in the Define Feature window).   On the left hand side, we define the origin of the datasource. Here we have selected the service GetHistory from the Thing Template smartTractor. On the right hand side, we define the mapping between the service’s output and the skinny .csv file columns. Circled in grey are the output from the service. Circled in green are what define the columns in the .csv file. A skinny csv file will have 1 to 3 columns, as follow: One column for the ID. Simply tick the radio button corresponding to the service output that represents the ID One column representing the value of the Thing property. This is indicated by selecting the link icon on the left hand side in front of the returned data which represent the value (in our example the output data from the service is named value) One column representing the Timestamp. This is only needed when a property is time dependant (for example, time series dataset). On the example the property is Distance, the distance covered by the tyre does depend on the time, however we would not have a timestamp for the TyreSize property as the wheel size will remain the same. How many columns should we have (and therefore how many output should our service has)? The .csv file representing the ID will have one column, and therefore the service collecting the ID returns only one output (Thing name in our smartTractor example – not shown here but is available in the download) Properties that are not time bound will have a csv file with 2 columns, one for the ID and one for the value of the property. Properties that are time bound will have 3 columns: 1 for the ID, one for the value and one for the timestamp. Therefore the service will have 3 outputs.   Additionally the input for the service may need to be configured, by clicking on the icon.   Once the datasources are configured, you should configure the Time Sampling Interval in the General Information tab. This sampling interval will be used by DataConnect to synchronize all the skinny csv files. See the Help Center for a good explanation on this.   DAD Execution Once the above configuration is done, the DAD can be executed to collect properties’ value already logged on the ThingWorx platform. Select Execution Settings in the DAD and enter the time range for property collection:   A dataset with the same name as the DAD is then created in DataConnect as well as in ThingWorx Analytics Server Dataconnect:     ThingWorx Analytics:   The dataset can then be processed as any other dataset inside ThingWorx Analytics.   Demo files   For convenience I have also attached a ThingWorx entities export that can be imported into a ThingWorx platform for you to take a closer look at the setup discussed in this blog. Attached is also a small simulator to populate the properties of the Tractor_1 Thing. The usage is : java -jar TWXTyreSimulatorClient.jar  hostname_or_IP port AppKey For example: java -jar TWXTyreSimulatorClient.jar 192.168.56.106 8080 d82510b7-5538-449c-af13-0bb60e01a129   Again feel free to share your experience in the comments below as they will be very interesting for all of us. Thank you
View full tip
Overview REST stands for representational state transfer and is a software architectural style common in the World Wide Web. Anything with a RESTful interface can be communicated with using standard REST syntax. ThingWorx has such an interface built-in to make viewing and updating Thing properties as well as executing services easy to do independently of the Web UI.   How to Use REST API The ThingWorx REST API is entirely accessible via URL using the following syntax:    (Precision LMS. Getting Started With ThingWorx 5.4 (Part 1 of Introduction to ThingWorx 5.4). PTC University. https://precisionlms.ptc.com/viewer/course/en/21332822/page/21332905.)   The above example shows how to access a service called “GetBlogEntriesWithComments” found on the “ThingWorxTrainingMaintenanceBlog” Thing. Notice that even though this service gets XML formatted data, the method is type “POST” and “GET” will not work in this scenario (Further reading: https://support.ptc.com/appserver/cs/view/solution.jsp?n=CS214689&lang=en_US).   In order to be able to run REST API calls from the browser, one must allow request method switching. This can be enabled by checking the box “Allow Request Method Switch” in PlatformSubsystem (Further reading: https://support.ptc.com/appserver/cs/view/solution.jsp?n=CS224211&lang=en_US).   Access REST API from Postman Postman is a commonly used REST client which can ping servers via REST API in a manner which mimics third party software. It is free and easy-to-use, with a full tutorial located here: https://www.getpostman.com/docs/   In order to make a request, populate the URL field with a properly formatted REST API call (see previous section). Parameters will not automatically be URL-encoded, but right-clicking on a highlighted portion of the URL and selecting EncodeURIComponent encodes the section.   Next click the headers tab. Here is where the content-type, accept, and authorization are set for the REST call. Accept refers to which response format the REST call is expecting while content-type refers to the format of the request being sent to the server. Authhorization is required for accessing ThingWorx, even via REST API (see previous section for examples authenticating using an app key, but in Postman you can also use Basic Auth using a username and password)   In Postman, there is also ample opportunity to modify the request body under the Body tab. There are several options here for setting parameters. Form-data and x-www-form-urlencoded both allow for setting key value pairs easily and cleanly, and in the latter case, encoding occurs automatically (e.g. “Hello World” becomes %22Hello%20World%22). Raw request types can contain anything and Postman will not touch anything entered except to replace environment variables. Whatever is placed in the text area under raw will get sent with the request (normally XML or JSON, as specified by content-type). Finally, binary allows for sending things which cannot normally be entered into Postman, e.g. image, text, or audio files.     REST API Examples For introductory level examples, see the previous Blog document found here: https://community.thingworx.com/docs/DOC-3315   Retrieving property values from “MyThing” using GET, the default method type (notice how no “method=GET” is required here, though it would still work with that as well): http://localhost/Thingworx/Things/MyThing/Properties/   Updating “MyProperty “with the value “hello” on “MyThing” using PUT: http://localhost/Thingworx/Things/MyThing/Properties/MyProperty?method=PUT&value=hello In Postman, you can send multiple property updates at once via query body (in this case updating all of the properties, the string “Prop1” and the number “Prop2” on MyThing) § Query: http://localhost/Thingworx/Things/MyThing/Properties/* § Query Type: PUT § Query Headers: Content-Type: application/json Authorization: Basic Auth (input username and password on Authorization tab and this will auto-populate) § Body JSON: {"Prop1":"hello world","Prop2":10} Note: you can also specify multiple properties as shown, but only update one at a time in Postman by utilizing the browser syntax given above   Calling “MyService” (a service on “TestThing)” with a String input parameter (“InputString”): http://localhost/Thingworx/Things/TestThing/Services/MyService?method=post&InputString=input   It is easier to pass things like XML and JSON into services using Postman. This query calls “MyJSONService” on “MyThing” with a JSON input parameter § Query: http://localhost/Thingworx/Things/MyThing/Services/MyJSONService § Query Type: § Queries Headers: Accept should match service output (text/html for String) Content-Type: application/json or Authorization: Basic Auth (input username and password on Authorization tab and this will auto-populate) Body JSON: {"InputJSON":"{\"JSONInput\":{\"PropertyName\":\"TestingProp\",\"PropertyValue\":\"Test\"}}"} Body XML:{"xmlInput": "<xml><name>User1</name></xml"}   Viewing “BasicMashup” using AppKey authentication (so no login is required because this Application Key is set-up to login as a user who has permissions to view the Mashup): http://localhost/Thingworx/Mashups/BasicMashup?appKey=b101903d-af6f-43ae-9ad8-0e8c604141af&x-thingworx-session=true Read more here: https://support.ptc.com/appserver/cs/view/solution.jsp?n=CS227935   Downloading Log Information from “ApplicationLog” (or other log types): http://localhost/Thingworx/Logs/ApplicationLog/Services/QueryLogEntries?method=POST   In Postman, more information can be passed into some queries via query body § Query: http://localhost/Thingworx/Logs/ApplicationLog/Services/QueryLogEntries Query Type: POST Query Headers: Accept: application/octet-stream or Content-Type: application/json Authorization: Basic Auth (input username and password on Authorization tab and this will auto-populate) Body: {\"searchExpression\":\"\",\"origin\":\"\",\"instance\":\"\",\"thread\":\"\", \"startDate\":1462457344702,\"endDate\":1462543744702,\"maxItems\":100}   Downloading “MyFile.txt” from “MyRepo” FileRepository (here, “/” refers to the home folder of this FileRepository and the full path would be something like “C:\ThingworxStorage\repository\MyRepo\MyFolder\MyFile.txt”): http://localhost/Thingworx/FileRepositoryDownloader?download-repository=MyRepo&download-path=/MyFolder/MyFile.txt   Uploading files to FileRepository type Things is a bit tricky as anything uploaded must be Base64 encoded prior to making the service call. In Postman, this is the configuration to used to send a file called “HelloWorld.txt”, containing the string “Hello World!”, to a folder called “FolderInRepo” on a FileRepository named “MyRepo”:   Query: http://localhost/Thingworx/Things/MyRepo/Services/SaveBinary Query Type: POST Query Headers: Accept: application/json Content-Type: application/json Authorization: Basic Auth (input username and password on Authorization tab and this will auto-populate) Body: {"path" : "/FolderInRepo/HelloWorld.txt", "content" : "SGVsbG8gV29ybGQh"} Notice here that the content has been encoded to Base64 using a free online service. In most cases, this step can be handled by programming language code more easily and for more challenging file content   Resources and other built-in Things can be accessed in similar fashion to user-created Things. This query searches for Things with the “GenericThing” ThingTemplate implemented: http://localhost/Thingworx/Resources/SearchFunctions/Services/SearchThingsByTemplate?method=POST&thingTemplate=GenericThing   Deleting “MyThing” (try using services for this instead when possible since they are likely safer): http://localhost/Thingworx/Things/MyThing1?method=DELETE&content-type=application/JSON   Exporting all data within ThingWorx using the DataExporter functionality: http://localhost/Thingworx/DataExporter?Accept=application/octet-stream   Exporting all entities which have the Model Tag “Application.TestTerm” within ThingWorx using the Exporter functionality: http://localhost/Thingworx/Exporter?Accept=text/xml&searchTags=Applications:TestTerm
View full tip
  Connect an ESP8266 WiFi module using the Arduino programming environment and the ThingWorx REST API.   This information was created for a previous version of ThingWorx and may not be fully accurate. Report any issues with this article here.   Guide Concept   This project will introduce the utilities ThingWorx provides for connections to an Adafruit Feather.   Following the steps in this guide, you will have a fully configured setup between your Adafruit Feather and the ThingWorx platform to begin your IoT development.   We will teach you how to utilize the ThingWorx REST API and the Arduino programming language to connect your Adafruit Feather for IoT application development.   You'll learn how to   Connect an ESP8266 WiFi module to a ThingWorx server Use the Arduino programming environment with the ThingWorx REST API   NOTE:  The estimated time to complete this guide is 30 minutes.      Step 1: Install Software   Arduino   There are three pieces of software to install before getting started with the ThingWorx-specfic code: Install FTDI USB driver. If you have connected development boards to your PC in the past you probably already have this installed. The latest Arduino IDE full install will also install the driver. NOTE: SparkFun has an excellent FTDI Driver Installation guide.   3. Arduino IDE - version 1.6.4 or later recommended. 4. Install ESP8266 addon into Arduino IDE. 5. The SparkFun Setting Up the Arduino IDE Tutorial is a great guide to getting started with their board. 6. Adafruit also has a great with their board Testing a Wifi Connection Tutorial.   When everything is set-up correctly and you are able to upload and see the Blink demo flashing the LED on the board you are ready to move to the next step.   ThingWorx Foundation Server   Start, and Launch your ThingWorx Foundation server. Log into Composer.  You will need a ThingWorx appKey to authorize the board.  Follow these instructions in Create an Application Key to create an appKey that you will copy into the source code in the next step.       Step 2: Set up Arduino IDE, Developer Board, and ThingWorx Server   Once you are able to run the blink test sketch, your IDE and board are set-up correctly. To learn how to run the blink test, read the SparkFun Board Instructions and the Adafruit board instructions.   Arduino IDE   Before you will be able to run the code below that connects a developement board to a ThingWorx Foundation server, you will need to modify the code with four pieces of information specific to your environment. You will need:   A WiFi access point SSID The correct password for the WiFi access point The IP address or URL of a ThingWorx Foundation Server A valid appKey created by your ThingWorx Foundation Server. To create an appKey, follow these instructions to Create An Application Key   Create a new sketch in the Arduino IDE then copy and paste the code below into the IDE.   Modify the WiFi Definitions and the ThingWorx server definitions shown in the code with your specficic information then save the sketch with a new name. The next step will describe what you should see when you upload and run the code on your developer board.   /** * * ESP8266_ThingWorx_REST_Demo.ino * * * (c) PTC, Inc. 2016-2020 * */ #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClientSecureBearSSL.h> ////////////////////// // WiFi Definitions // ////////////////////// const char WiFiSSID[] = "Liberty454"; // WiFi access point SSID const char WiFiPSK[] = "Flutie22"; // WiFi password - empty string for open access points ////////////////////////////////////////////// // ThingWorx server definitions // // modify for a specific platform instance // ////////////////////////////////////////////// const char TWPlatformBaseURL[] = "https://pp-2007011431nt.devportal.ptc.io"; const char appKey[] = "2d4e9440-3e51-452f-a057-b55d45289264"; //////////////////////////////////////////////////////// // Pin Definitions - board specific for Adafruit board// //////////////////////////////////////////////////////// const int RED_LED = 0; // Thing's onboard, red LED - const int BLUE_LED = 2; // Thing's onboard, blue LED const int ANALOG_PIN = A0; // The only analog pin on the Thing const int OFF = HIGH; const int ON = LOW; // this will set as the Accept header for all the HTTP requests to the ThingWorx server // valid values are: application/json, text/xml, text/csv, text/html (default) #define ACCEPT_TYPE "text/csv" ///////////////////// //Attempt to make a WiFi connection. Checks if connection has been made once per second until timeout is reached //returns TRUE if successful or FALSE if timed out ///////////////////// boolean connectToWiFi(int timeout){ Serial.println("Connecting to: " + String(WiFiSSID)); WiFi.begin(WiFiSSID, WiFiPSK); // loop while WiFi is not connected waiting one second between checks uint8_t tries = 0; // counter for how many times we have checked while ((WiFi.status() != WL_CONNECTED) && (tries < timeout) ){ // stop checking if connection has been made OR we have timed out tries++; Serial.printf(".");// print . for progress bar Serial.println(WiFi.status()); delay(2000); } Serial.println("*"); //visual indication that board is connected or timeout if (WiFi.status() == WL_CONNECTED){ //check that WiFi is connected, print status and device IP address before returning Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); return true; } else { //if WiFi is not connected we must have exceeded WiFi connection timeout return false; } } ////////////////////////// //create a name for the board that is probably unique by appending last two bytes of MAC address //return name as a String /////////////////////////////// String getUniqueDeviceName(){ String uniqueName; uint8_t mac[WL_MAC_ADDR_LENGTH]; WiFi.macAddress(mac); // WiFi does NOT need to be connected for this call String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX); macID.toUpperCase(); uniqueName = "ESP8266Board-" + macID; Serial.println("DeviceID>" + uniqueName); return uniqueName; } /////////////////////////////// // make HTTP GET to a specific Thing and Propertry on a ThingWorx server // thingName - Name of Thing on server to make GET from // property - Property of thingName to make GET from // returns HTTP response code from server and prints full response /////////////////////////////// int httpGetPropertry(String thingName, String property){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[httpsGetPropertry] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Things/"+ thingName +"/Properties/"+ property +"?appKey=" + String(appKey); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); Serial.println("GET URL>" + fullRequestURL +"<"); // start connection and send HTTP header httpCode = https.GET(); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[httpGetPropertry] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[httpGetPropertry] failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } /////////////////////////////// // makes HTTP POST to platform to CreateThing service using input string as the new Things's name. // Returns server response code /////////////////////////////// int createThing(String nameOfThing){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[createThing] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Resources/EntityServices/Services/CreateThing?appKey=" + String(appKey); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); https.addHeader("Content-Type","application/json",false,false); Serial.println("POST URL>" + fullRequestURL + "<"); // start connection and send HTTP header httpCode = https.POST("{\"name\": \""+ nameOfThing +"\",\"thingTemplateName\": \"GenericThing\"}"); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[createThing] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[createThing] POST... failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } /////////////////////////////// // make HTTP POST to ThingWorx server Thing service // nameOfThing - Name of Thing to POST to // endPoint - Services URL to invoke // postBody - Body of POST to send to ThingWorx platform // returns HTTP response code from server /////////////////////////////// int postToThing(String nameOfThing, String endPoint, String postBody){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[postToThing] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Things/"+ nameOfThing +"/Services/"+ endPoint +"?appKey=" + String(appKey); Serial.println("URL>" + fullRequestURL + "<"); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); https.addHeader("Content-Type","application/json",false,false); Serial.println("[postToThing] POST body>" + postBody + "<"); // start connection and send HTTP header httpCode = https.POST(postBody); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[postToThing] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[postToThing] POST... failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } void setup() { pinMode(RED_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); Serial.begin(115200); Serial.setDebugOutput(true); Serial.println(); Serial.println(); Serial.println(); Serial.printf("Starting...\n"); for(uint8_t t = 4; t > 0; t--) { Serial.printf(" WAIT %d...\n", t); Serial.flush(); delay(1000); } connectToWiFi(10); } void loop() { String thingName = getUniqueDeviceName(); //unique name for this Thing so many work on one ThingWorx server while (WiFi.status() == WL_CONNECTED) { //confirm WiFi is connected before looping as long as WiFi is connected int getResponseCode = httpGetPropertry(thingName, "SomeNumber"); if (getResponseCode == 404){ // a 404 means connected, but either no Thing or no property // first we will try to create a new Thing on the platform int postResp = createThing(thingName); // saving the response code for retry logic in the future // the newly crated Thing has to be enabled postResp = postToThing(thingName,"EnableThing",""); //POST to EnableThing endpoint with no body // after the new Thing is enabled it must be restarted postResp = postToThing(thingName,"RestartThing",""); //POST to RestartThing endpoint with no body // add a property to the Thing 3rd parameter is ugly because required quotes are escaped with backslashes postResp = postToThing(thingName,"AddPropertyDefinition", "{\"name\":\"SomeNumber\",\"type\":\"NUMBER\"}"); //POST body contains JSON object with property name and property type // after changes to a Thing's structure it must be restarted postResp = postToThing(thingName,"RestartThing",""); //POST to RestartThing endpoint with no body } delay(2000); }// end WiFi connected while loop Serial.printf("****Wifi connection dropped****\n"); WiFi.disconnect(true); delay(10000); connectToWiFi(10); }     Step 3: Run Arduino Demo   Click on the right arrow in the Arduino IDE toolbar to upload and start the sketch. Note:The compile and upload process will take almost a minute and will show [ 100% ] when it is completed successfully. 2. After the upload is complete, click on Tools > Serial Monitor and select 115200 baud from the drop down in the lower right.            Check Connection on ThingWorx Server   Open the Composer window of your ThingWorx Foundation server and click on the browse folder icon, then Things.   You will see a Thing named "ESP8266Board-XXXX" with XXXX replaced by the last 4 digits of your boards WiFi MAC address. Click on the Thing then click the Properties and Alerts tab in the left column. Click the pencil "Set value" icon in the value column and enter a number in the text box. Click the "Check" button to set the value.   Open the Arduino Serial monitor window, and you will see the value you just entered on the platform shown in the serial output.   Step 4: Next Steps   Congratulations! You've successfully completed the Connect an Arduino Developer Board Quickstart.   This guide has given you the basic tools to:   Set up Arduino IDE Run Arduino demo Check connection on ThingWorx Server   Learn More   We recommend the following resources to continue your learning experience:    Capability Guide Connect Use REST API to Access ThingWorx Build Data Model Introduction   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource Link Community Developer Community Forum Support REST API Help Center
View full tip
This video is Module 11: ThingWorx Analytics Mashup Exercise of the ThingWorx Analytics Training videos. It shows you how to create a ThingWorx project and populate it with entities that collectively comprise a functioning application. 
View full tip
As of May 24, 2023, ThingWorx 9.4.0 is available for download!  Here are some of the highlights from the recent ThingWorx release.   What’s new in ThingWorx 9.4? Composer and Mashup Builder  New Combo chart and Pie chart based on modern Web Components architecture along with several other widget enhancements such as Grid toolbar improvements for custom actions, highlighting newly added rows for Grid widget and others Ability to style the focus on each widget when they are selected to get specific styling for different components Absolute positioning option with a beta flag to use by default is available now Several other Mashup improvements, such as Export function support is made available; improved migration dialogue (backported to 9.3 as well) to allow customers to move to new widgets; and legacy widgets language changes   Foundation  Heavily subscribed events could now be distributed across the ThingWorx HA cluster nodes to be scaled horizontally for better performance and processing of ThingWorx subscriptions. Azure Database for PostgreSQL Flex Server GA support with ThingWorx 9.4.1 for customers deploying ThingWorx Foundation on their own Azure Cloud infrastructure Improved ThingWorx APIs for InfluxDB to avoid Data loss at a high scale with additional monitoring metrics in place for guardrails Several security fixes and key third-party stack updates   Remote Access and Control (RAC) Remote Service Edge Extension (RSEE) for C-SDK, currently under Preview and planned to be Generally Available (GA) by Sept 2023, would allow ThingWorx admins to use Remote Access and Control with the C-SDK based connected devices to use Global Access Server (GAS) for a stable, secure, and large number of remote sessions With 9.4, a self-signed certificate or certificate generated by the trusted certificate authority can be used for RAC with the ThingWorx platform Ability to use parameter substitution to update Auto Launch commands dynamically based on data from the ThingWorx platform is now available   Software Content Management  Support for 100k+ assets with redesigned and improved performance on Asset Search Better control over package deployment with redesigned package tracking, filtering, and management Improved overall SCM stability, performance, and scalability and a more user-friendly and intuitive experience   Analytics  Improvements to the scalability of property transforms to enable stream processing of the larger number of properties within a ThingWorx installation Refactoring of Analytics Builder UI to use updated widgets and align with the PTC design system Updates to underlying libraries to enable the creation and scoring of predictive models in the latest version of PMML (v4.4) End of Support for Analytics Manager .NET Agent SDK     View release notes here and be sure to upgrade to 9.4!     Cheers, Ayush Tiwari Director, Product Management, ThingWorx      
View full tip
  Build authentications extensions quickly and add to the security of your application.   GUIDE CONCEPT   Extensions enable you to quickly and easily add new functionality to an IoT solution. Extensions can be service (function/method) libraries, connector templates, functional widgets, and more.   These pointers and steps will enable you to maintain focus on development of your own application and still utilize the power of ThingWorx for other purposes at the same time.   When to Utilize:   You have your own login from outside of ThingWorx but you want to leverage ThingWorx user management You are using an identity provider other than ThingWorx You need to support passing of credentials in headers/query string parameters which ThingWorx doesn’t support out-of-the-box   Concept   Whether you would like ThingWorx to handle the security for your application, have an application you want ThingWorx to pump data into, or would just like to utilize ThingWorx features in your own application, external authentication can be a great way to integrate your application with ThingWorx. This guide will focus in on how to create an authentication middle man between a system you have already developed (or are in the middle of creating) and connect it to the ThingWorx Platform. In a provided demo website, you will login (with the provided credentials) and validate your user profile and password with ThingWorx. This setup shows the simple integration between ThingWorx and an application you would like to connect to the ThingWorx Platform.   YOU'LL LEARN HOW TO   Install the Eclipse plugin and extension SDK Create authentication application Build and import an extension   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 60 minutes.        Step 1: Completed Example   Download the completed files for this tutorial: AuthenticationExtension.zip   This tutorial will guide you through security concepts within ThingWorx. Utilize this file to see a finished example and return to it as a reference if you become stuck creating your own fully flushed out application.   Keep in mind, this download uses the exact names for entities used in this tutorial. If you would like to import this example and also create entities on your own, change the names of the entities you create. The download contains three directories (Source, CompletedExtension, and Demo). See below for the information about each directory.     Directory Description Source The completed project and source code to be utilized as a comparison or ready to go pre-built extension. CompletedExtension A completed and built extension that is based on the steps utilized in the latter steps. The zip file in this directory can be imported directly. Demo A demo web page that shows easy integration of an external application and ThingWorx authentication.       Step 2: Understanding Authenticators   Authentication between ThingWorx and custom outside applications begins with Authenticators.  Authenticators are the component integration point that allows for custom authentication schemes to be added into the ThingWorx platform. Authenticators can be used to retrieve content, parameters, headers, etc from HTTP requests.   The retrieved data can be verified by the authenticator using its implemented/configured verification  algorithm(s). If that data is of a username/password credential type the authenticator can choose to pass validation of that data to the configured list of Directory Services. For example, the internal ThingWorx username/password store, or delegate to an external Active Directory set of username/passwords.   ThingWorx tries to authenticate in increasing order of priority. In example, starting with  ThingworxBasicAuthenticator, unless a custom authenticator is given higher priority than that, ThingWorx will continue trying enabled authenticators by priority until one succeeds.   If an authenticator has priority 1, it will be consulted first in the chain of authenticators. If the authenticator has a priority of 101, it will be consulted after the ThingworxBasicAuthenticator (with priority of 100) fails to authenticate the HTTP request. There are several built-in authenticators   Authenticator Priority Editable ThingworxBasicAuthenticator 100 No ThingworxMobileTokenAuthenticator 150 Yes ThingworxApplicationKeyAuthenticator 200 No ThingworxSSOAuthenticator 250 Yes ThingworxFormAuthenticator 300 No ThingworxMobileAuthorizationAuthenticator 350 Yes ThingworxHttpBasicAuthenticator 400 No   When all configured and enabled authenticators fail to validate the data provided by an HTTP request, an authentication failure response is sent back to the requesting client. Custom Authenticators can be given priority such that they fit into any part of this process.   For setting the priority follow the instructions below:   Navigate to and select Security > Authenticators.   Select the Authenticator you would like to edit (ie, ThingworxSSOAuthenticator). If you do not see a specific Authenticator you would like to VIEW ONLY, check the Show System Objects checkbox in your search filter.   Update the Priority field with a new value. Click Save.       Step 3: Download Plugin and SDK   The ThingWorx Extension SDK provides supported classes and APIs to build Java-based extensions. The APIs included in this SDK allow manipulation of ThingWorx platform objects to create Java based extensions that can extend the capability of the existing ThingWorx platform.   The Eclipse Plugin assists in working with the Extension SDK to create projects, entities, and samples.   Download the Eclipse Plugin. Download Extensions SDK. Make a note of the directory where the plugin and the extension SDK are stored. The path of the directory will be required in upcoming steps. Do not extract the zip files.     Click here to view Part 2 of this guide.
View full tip
Learn how to use the DBConnection building block to create your own DB tables in ThingWorx.
View full tip
Important change in ThingWorx 9.3.2   Since 9.3.2, Transaction behavior depends on the type of database opration: Model operations which acquire a transaction and hold it until the top-level service finishes - same behavior as pre-9.3.2. Once a connection is retrieved for performing model operations, it cannot be released until the service terminates. Data read operations which have been updated to eagerly release their transaction (Data write operations, such as property writes, are always batched and processed asynchronously from a different thread). Performing Data read operations before model operations allows a connection to be retrieved for querying, then released while other work is being completed. Sample services with that use Eager Transactions: DataTable, Stream, ValueStream get/find/query/search   The post below is valid for all ThingWorx versions until 9.3.1 TL;DR   The transaction API is not exposed as ThingWorx scripting API (Service script). When servicing a request, that acquire a database connection, a transaction is automatically created by the Platform. A basic understanding of those automatic transactions (scope and lifecycle) is important to build a scalable ThingWorx solution.   Scope   The transactions discussed here are in the context of persistence provider operations This post does not apply to Database Things and  SQL Services   Transaction Handling   Any of the following request handlers will automatically register the intent to participate in a transaction: EventInstance (Subscriptions) AsyncHandler (Asynchronous services) APIProcessor (WS Requests) BaseService (REST Requests), ... However, the actual transaction is initiated if and when a database connection is acquired. The entire transaction is managed by the local (i.e. NOT distributed/XA) JDBC transaction support available with the connection.   All the above-mentioned service invocations would initiate a single transaction automatically and commit or rollback at the end of the service invocation. Note that the database transaction remains open until the request invocation completes. Therefore, it’s advised to write efficient/modular custom services and avoid long running monolithic services to avoid holding database connections for too long, which would result in running out of database connections.   The transaction API is not exposed as ThingWorx scripting API and therefore, not accessible from the JavaScript based custom services or scripts.   Most of persisted data changes (Stream, Value Stream, Data Table, Persisted Properties) are queued and batched to improve data ingestion throughput. Therefore, the actual writing to the database is performed by a separate executor thread (Data Processing Subsystem). This thread pool will create its own transaction and thus will not be part of the transaction initiated by the originating service request.   Model changes (modeled entities CRUD operations) in contrast are not queued or batched and hence would be performed as part of the transaction initiated by the originating service request. It should also be noted that any and all database operations including reads (i.e. via select statements) require a transaction as per the JDBC specification. While typical applications may use ‘auto commit’ feature with reads ThingWorx does not treat them as separate request since it complicates transaction handling when multiple reads and writes are interlaced in service invocations. Thus transactions initiated by a Read operation will also remain open until the request invocation completes.   When there are more than one database instances are involved (usually with multiple Persistence Providers) there will be a separate connection acquired for each database and those transactions will be handled independently per connection. ThingWorx does not support distributed transactions with two phase commit protocol which means that the commit and rollback would be just best effort.   Lets consider a couple of use cases   A. Long running service (the pauses represent for example calls to an external system)   pause(5000); // 5 sec result = MyDataTable.GetDataTableEntryCount(); // Start DB Transaction pause(10000); // 10 sec   This service is invoked via REST : The HTTP request reaches the platform The platform automatically creates a transaction context The custom Service is invoked GetDataTableEntryCount() hits the persistence provider, a DB transaction is started pause(10000) does not interact with the DB, but the previous transaction remains open (idle) The DB transaction is closed only after the entire request is complete   B. Request that involves multiple threads   me.prop1 = 10; // logged property with data change subscription, the subscription queries a Data Table myAsyncSrc(); // Asynchronous service that also queries a Data Table   This service is invoked via REST : The HTTP request reaches the platform The platform automatically creates a transaction context The custom Service is invoked: me.prop1 = 10; In-memory property update is not atomic nor transactional A subscription that access the persistence provider is triggered, but it is executed by a different thread and an new transaction context  is created (not nested) The property value is logged into a value stream, the persistence is performed by an other thread asynchronously myAsyncSrv() This asynchronous service is executed by a different thread and an new transaction context is created (not nested) The request is complete without ever starting a persistence transaction since the service/thread itself did not acquire a database connection   Notes   The Transactions API are  available in the Extension JSDK - TransactionFactory
View full tip
  Learn how to create solutions the can help take you to the next level     Guide Concept   This project will introduce more complex aspects of the ThingWorx application and solution building.   Following the steps in this guide, you will develop your own IoT application or get a jump start in how to utilize ThingWorx for your needs.   We will teach you how to create a focused rules engine or service level logic to be used with the ThingWorx Platform.     You'll learn how to   Create automated processing, data, and endpoints that can handle that data without manual interaction Use services, alerts, and subscriptions to increase performance Begin making your data model and cornerstone entities to understand how a complex business logic is built   NOTE:  The estimated time to complete this guide is 60 minutes     Step 1: Completed Example   Download the attached FoodIndustry.zip and extract/import the contents. These are to be used as you work through this learning path. For the completed example, download the FoodIndustryComplete.zip. Unzip the download and import the Entities included.   In this tutorial we walk you through a real-world scenario for a food company looking to improve their processes. We manufacture the best sausages in town! We sell directly to people and through participating store locations. The focus will be to provide meaningful data for decision making, constant updates on food quality, logistics, transparency, and safety. See the below table for the list of mashups that we will create in this guide and included in the download.    Name                           Description Fizos.LandingPage The main page that showcases highlights and possibly important information Fizos.Deliveries A look into product delivery and logistics Fizos.Alerts Details about any important actionable information Fizos.Factory.User A user to be used for our automated process   There is a large set of Entities provided in this download. The application created in this guide is a part of a final version of what we will create throughout this learning path. If you have not learned about Services, Events/Alerts, and Subscriptions, please take a walk through our Implementing Services, Events, and Subscriptions.   This guide will begin the base of our data model, create data for our factories, and show how we can create automated processes using that data. We will then expand on these items as we move forward in this learning path.     Step 2: Utilizing IoT in the Food Industry   Whenever creating a product in ThingWorx, you should evaluate whether to create them using the data model (Things, Thing Templates, Thing Shapes, etc) or create them using Data Tables and Data Shapes. You have to decide the method that works best for you. One way to think about this is whether to have a single ThingWorx entity to encapsulate your product data OR having so many products (especially when easily volatile), that you rather track it at a higher level.   In our scenario, we won't need to track sausages as the individual level, so we can track the machines creating, holding, and packaging them. This also allows for us to run analytics on the data and export the data into our favorite tools to further process the data.   In the ThingWorx Composer, click the + New in the top left of the screen.   Select Data Shape in the dropdown.     3. In the name field, enter Fizos.DataShapes.Products. This data shape will form high level information about our differing products as a whole. 4. Set the Project (ie, PTCDefaultProject) and click Save to store all changes.     5. Click on the Field Definitions tab. 6. Click the + Add button and enter Name in the Name field of the new Field Definition.    7. Setup your Field Definitions to match the below definitions:  Name      Base Type       Aspects ID Integer Primary Key. Default 0. Minimum 0. Name String N/A State String N/A SKU String N/A Price Number Minimum 0. Mass Number Default 0. Minimum 0. Volume Number Default 0. Minimum 0.     We now have the data shape for products. We can go two different routes here as we create the data table for the products. We can make one data table for ALL company products or we can create a data table for each machine that houses these products. If you wanted the latter options, you could have the machine properties and services assocoated directly on the data table. This is a great option to condense the number of entities being used.   The level of granularity or simplicity is up to you. For this guide, we'll keep things simple and have one data table for all products. When we create the machine entities, we will have a table of the product IDs to help keep track of what products are contained in the machine. In the ThingWorx Composer, click the + New in the top left of the screen.   Select Data Table in the dropdown and select Data Table in the prompt.   In the pop-up, select Data Table.   In the name field, enter Fizos.DataTables.Products. All of our product line will fit this abstract entity. For the Data Shape field, select Fizos.DataShapes.Products. Set the Project field with an existing Project (ie, PTCDefaultProject) and click Save to store all changes.   We now have our setup complete for company products. Now let's create a DataShape for any Event involving this product template. 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.ProductsEvent and in the Project field, select an existing Project (ie, PTCDefaultProject). All of our product line will use this DataShape as an alert/event. Click Save to store all changes, then click Edit. Performed the steps used earlier to create the below properties for the Fizos.ProductsEvent Data Shape:  Name           Base Type        Aspects State String N/A SKU String N/A Price Number Minimum 0. Name String N/A     Now let's create a Thing Template, Stream, and a ValueStream to track some of what is happening with our products at a high level. The ValueStream will automatically track our data. The Stream, we will add data in the latter sections. In the ThingWorx Composer, click the + New in the top left of the screen.   Select Thing Template in the dropdown.   3. In the name field, enter Fizos.Products as the name and GenericThing as the Base Thing Template. 4. Select a Project (ie, PTCDefaultProject) and click Save to store all changes.       Now, our new Stream. In the ThingWorx Composer, click the + New in the top left of the screen.   Select Stream in the dropdown.   3. Select Stream in the pop-up.   4. In the name field, enter Fizos.ProductsStream and set the Project field (ie, PTCDefaultProject). 5. In the Data Shape field, select Fizos.ProductsEvent.   6. Click Save to store all changes.   Now, the Value Stream.   In the ThingWorx Composer, click the + New in the top left of the screen.   Select Value Stream in the dropdown.   3. Select ValueStream in the pop-up.   4. In the name field, enter Fizos.ProductsValueStream. 5. Set the Project field (ie, PTCDefaultProject) and click Save to store all changes.   6. Open the Fizos.Products Thing Template and set the Fizos.ProductsValueStream as the Value Stream.   We're all set with high level tracking of all of our products. At this point, we can start the creation of the entity that will help provide the business logic for all products. In the ThingWorx Composer, click the + New in the top left of the screen.   Select Thing in the dropdown.   In the name field, enter Fizos.ProductsBusinessLogic. All of our product line will fit this abstract entity. For the Base Thing Template field, select GenericThing and set the Project field to an existing Project (ie, PTCDefaultProject). Click Save to store all changes.   Click on the Services tab. Click the + Add button and create the two Services below.  Name                          InputReturn Type           Override Async  Desc InspectFactory Integer - factoryID Nothing Yes Yes Start an inspection for a specific factory ReceiveInspection JSON - report/ String - guid Nothing Yes Yes Log/Store an inspection for a specific factory   At this point, you have the building blocks to begin your industry business logic and rules engine. In the next section, we'll do more development and further build out our model.     Click here to view Part 2 of this guide.  
View full tip
  Expedite your application development with new ThingWorx features.   GUIDE CONCEPT   This project will introduce you to a variety of features designed to expedite the IoT application development workflow. In particular, there are several features that make the creation of custom Services quicker and easier when writing and testing your code.   Following the steps in this guide, you will learn how to access features that will help you throughout your software development lifecycle: development, execution, and testing.   We will teach you how to became a faster and more efficient IoT application developer.     YOU'LL LEARN HOW TO   Use Snippets to generate code Execute and test Services Save Service test cases to facilitate QA process Utilize the code auto-completion feature Test code at design time with Lint warnings and errors   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 30 minutes.        Step 1: Completed Example   Download and extract the completed files for this tutorial attached to this article: ToolsTipsTricks.zip file.   The file provided to you contains a completed example of the Entities covered in this guide. Utilize this file to see a finished example and return to it as a reference if you become stuck during this guide and need some extra help or clarification.   Keep in mind, this download uses the exact names for Entities used in this tutorial. If you would like to import this example and also create Entities on your own, change the names of the Entities you create.       Step 2: Templates and Using Code Snippets    Expedite your application development process by utilizing code Snippets provided in ThingWorx. The JavaScript code snippets will give you insight into best practices for performing common development tasks.   Follow the steps below to create a Service that will: Check a list of Things Find Things with a temperature over an input parameter threshold, and Return the captured list of Things   Create a Thing Template   Utilizing a Thing Template expedites your development process because the Things inherit properties from the Template. In the steps below, it can relate to a real-world scenario where Things might represent parts that belong to an assembly line.   In the top left of the Home screen of Composer, click the + button.       In the dropdown list, click Thing Template.       For the Name field, enter LinePartTemplate. Select GenericThing as the Thing Template and select a Project (ie, PTCDefaultProject).       Click Properties and Alerts. Create a number Property named PartTemperature. Create a string Property named PartName.     Click Save. Now that you've saved the Template, you can create Things that inherit the properties PartTemperature and PartName. Create a couple new Things with LinePartTemplate as the Thing Template. For testing purposes, set a different value for the PartTemperature Property of each Thing. NOTE: When you run the Service later, you'll be able to see the different Things with values - some within a temperature threshold based on the conditions we set.   Using Service Call Setup   Code Snippets help shorten time to develop Services, but you are also provided with a way to call Services from an entity plus the default input parameters needed to make the call.   In the top left of the Home screen of Composer, click the + button.       In the dropdown list, click Thing.       For the Name field, enter LineCheckSystem. Select GenericThing as the Thing Template and select a Project (ie, PTCDefaultProject).     Switch to the Services tab. Create a Service called ListHotLineParts. Switch to the Me/Entities tab.   Select the Other entity radio option. Enter LinePartTemplate into the search field and select it when it pops up.   Expand the Services section.  Enter GetImplementingThingsWithData into the search field and select the arrow next to it.   You should now see a Snippet of JavaScript inserted into the Service code window. The GetImplementingThingsWithData Service is used to get all the Things with a specific Thing Template as it's base template. The return of this call will provide you with an InfoTable of all the Things you created on your own in the last section. Refer to LineTemplateThing1 in the completed download for an example.     Using Code Snippets   Lets's update the Snippet inserted in the last section.   Update the variable name from result to partsList. Switch to the Snippets tab of the Service. In the search bar, enter/filter Infotable for loop. Expand the Info Table section and click the arrow next to Infotable for loop.   All places where yourInfotableHere is located, replace it with the name of your list, partsList.   Click Done. Click Save.   At this point, you have created a loop that will iterate through the set of Things created with LinePartTemplate set as the Thing Template.   Since the JavaScript snippets were provided and all you had to do was update the variable names, now you must retrieve the input from the user on what the temperature threshold will be. This will be handled in the next section.     Build Return Value List   You can set the threshold to what is considered a "Hot" part in two different ways. Use a static value in order to keep things standardized OR create an input variable to make things more flexible. In the steps below, we are adding an input variable to finish off our Service.   Go to the Inputs tab of the Service. Add an input parameter called TemperatureThreshold that is a Number. Keep the other settings clear. Go to the Outputs tab, select INFOTABLE in the dropdown.  In the Data Shape search field, use the + New Data Shape sign to create a new DataShape. An example is shown below. I’ve named this Data Shape LinePartDataShape. Switch to the Snippets tab of the Service. In the JavaScript code, put your cursor on a new line before the for loop (ie, line 1). In the search bar, filter for Create Infotable from datashape and select it in the Infotable section by clicking the arrow next to it. Select the newly created LinePartDataShape DataShape when a popup appears and click Insert Code Snippet. You will see the newly inserted snippet that creates an Info Table from our new Data Shape.   Add a check inside of the for loop for the PartTemperature of the current item in the list of parts. if(row.PartTemperature > TemperatureThreshold){ } Move the cursor inside of the condition we just added. In the search bar, filter and select Create infotable entry from datashape in the Info Table section by clicking the arrow next to it. Select the newly created LinePartDataShape Data Shape when a popup appears and click Insert Code Snippet. You will see the newly inserted snippet that creates an entry for the Info Table. Update the inserted code snippet to assign the new entry values to that of a row in the Info Table. After updating the with code below, ensure to keep your cursor inside the conditional on a new line. var newEntry = new Object(); newEntry.PartName = row.PartName; // STRING newEntry.PartTemperature = row.PartTemperature; // NUMBER Your entire code thus far should match the following: var params = { infoTableName : "InfoTable", dataShapeName : "LinePartDataShape" }; // CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(LinePartDataShape) var result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params); // result: INFOTABLE dataShape: "RootEntityList" var partsList = ThingTemplates["LinePartTemplate"].GetImplementingThingsWithData(); var tableLength = partsList.rows.length; for (var x=0; x < tableLength; x++) { var row = partsList.rows[x]; if(row.PartTemperature > TemperatureThreshold){ var newEntry = new Object(); newEntry.PartName = row.PartName; // STRING [Primary Key] newEntry.PartTemperature = row.PartTemperature; // NUMBER } } In the search bar, filter and select AddRow by clicking the blue arrow next to it. Update the inserted code snippet to add the newEntry object to the result Info Table created earlier. result.AddRow(newEntry); Save your work. You now have a fully-functional Service that you were able to create faster because of code snippets and pre-loaded Services. See the below to confirm your code matches up after removing some commented lines. Click here to view Part 2 of this guide.
View full tip
  Learn how to create factory line solutions the can help take you to the next level     Guide Concept   This project will introduce more complex aspects of the ThingWorx application and solution building.   Following the steps in this guide, you will develop your own IoT application or get a jump start in how to utilize ThingWorx for your needs.   We will teach you how to create a focused rules engine or service level logic to be used with the ThingWorx Platform.     You'll learn how to   Create automated machine processes Use Services, Alerts, and Subscriptions to handle processes without human interaction Integrating complex logic with straight forward step by step systems   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 60 minutes     Step 1: Examples and Strategy   Download the attached FoodIndustry.zip and extract/import the contents. This is to be used as you work through this learning path. For the completed example, download, extract, and import FoodIndustryComplete.zip. These downloads provide three Users and a Security Group. Please watch your count for Users or the import could fail. If you're at your User count limit, delete Users before attempting to import these downloads. Unzip the download and import the Entities included.   In this tutorial we continue with our real-world scenario for the Fizos food company. We should already have our factory data in data tables and will expand on how we can make the factory line smarter. The best processed are built on great timing, quality materials, a great design, and a method to keep track of everything that is happening. We won't have control of materials here, but we can formulate a simple, but great design. Our design will be based on Alerts, Subscriptions, and Schedules.   One of the same questions we will need to ask ourselves that we did in the last guide pertaining to products, is whether to create an entity per machine used in the factory OR create data entries in a data table and process everything through services. Since we would like to have more detailed and up to date information about our machines, I will create a data model that is tied back to our factories.   We will need to start by creating our templates for overall machines, templates for specialized machines, and then entities for the particular machines we have in our factories.       Click here to view Part 2 of this guide.
View full tip
    Learn how to connect, query, insert, and handle data from an external database.   GUIDE CONCEPT   This project will introduce how to utilize and incorporate an external database with the ThingWorx Platform.   Following the steps in this guide, you will connect the ThingWorx Platform to a database, insert data, execute stored procedures, and query data.      YOU'LL LEARN HOW TO   Connect ThingWorx to external databases Query databases and and handling results Insert data and running stored procedures   NOTE: The estimated time to complete this guide is 60 minutes.     Step 1: Completed Example   Download the attached DatabaseApplication.zip and import it into ThingWorx Composer. This download will provide examples that can be used as a reference or as a final copy as you walk through this guide.   In this tutorial, you will learn how to query data and write data to live external databases. The zip file provided contains the following files and entities as a completed version of the scenario to be covered. Import the .twx files into ThingWorx in any order. Run the SQL Server table scripts in a database you have setup followed by the stored procedures.      Name                                                 Description                                                                      Type SQLServerDatabaseController A connected entity for use with an SQL Server database ThingWorx Entity OracleDatabaseController A connected entity for use with an Oracle database ThingWorx Entity AddStudentToCourse.sql Stored procedure to add students to a course in a SQL Server database Database Stored Procedure GetStudentInCourse.sql Stored procedure to information about students in a course in SQL Server database Database Stored Procedure Course.sql SQL Server table representing Courses Database Stored Procedure Person.sql SQL Server table representing Students Database Stored Procedure PersonCourses.sql SQL Server table representing the connection between Students and Courses Database Stored Procedure     This guide will use connections to a SQL Server database, however you can use ANY database that can be used with the Java programming language. Based on the database you will be using, please perform the installation process for that database and create a user with READ, WRITE, and EXECUTE permissions. Ensure the password is set for this user and keep in mind that a UI for the database connection is not needed, but it can make things a bit simpler.      Database Download                       Installation Documentation           Jar File Download SQL Server Download SQL Server Installation SQL Server Jar File Oracle Download Oracle Installation Oracle Jar File     Please follow the below steps to enable a connection between ThingWorx and your database of choice: Ensure the user you created has read, write, and execute permissions. If you would rather split roles, you can create multiple users to handle each aspect. The execute permission for stored procedures is not necessary. Download the database driver/.jar file and move it to the lib directory of the Tomcat installation (ie, /lib). Restart the Tomcat server to load the JDBC driver to make it available for the ThingWorx web application.   Step 2: Connect to External Database   ThingWorx is based on java programming language and can make connections to any database that supports a java-based connection. All that is needed is to add the .jar file for the database to the lib folder of Tomcat folder and setup the connection in the ThingWorx Platform. Follow the below steps to get started creating the connection.   Create Connection   To create a connection and begin working with an external database, you will need to create a database Thing and set up the connection string and credentials. (To see the final version of this entity, you can look at SQLServerDatabaseController.)   In ThingWorx Composer, click the + New at the top of the screen.   Select Thing in the dropdown.   Name the Thing DatabaseController and select Database as the base type. Set the Project field (ie, PTCDefaultProject).   Click Save and go to the Configurations tab. In this tab, you will enter the class name of your driver, the connection string for that database connection, and the credentials to access the database. Keep in mind, the JDBC Driver Class Name, JDBC Connection String, and the connectionValidationString values are all database type specific. For example, to connect to a SQL Server database, the below configuration can be used.      Title                                              Description                    Example JDBC Driver Class Name The specific class name of the driver being used for the connection. net.sourceforge.jtds.jdbc.Driver (SQL Server) or oracle.jdbc.driver.OracleDriver (Oracle) JDBC Connection String The connection string to locate the database by host/port/database name. jdbc:jtds:sqlserver://server:port/databaseName (SQL Server) or jdbc:oracle:thin:@hostname:port:databaseName (Oracle) connectionValidationString A simple query that should always work in a database. SELECT GetDate() (SQL Server) or SELECT SYSDATE FROM DUAL (Oracle) After entering credentials, click Save. Go the Properties and Alerts tab. You'll see properties showing the connection validation similar to the image below. If you don't have a connection as yet, work on your configuration information and validate the credentials being used. If you're still having troubles after that, see the examples section below or use the next section for help to try a query of the database.   Help and Troubleshooting For help finding the correct configuration for you, check out these JDBC Configuration Examples or try out this Connection String Reference for help with your connection string.   You've just created your first database connected Thing! Now jump to the next section and let's begin to query the database for information. Step 3: Query Data from External Database Now that you're connected to the database, you can begin querying the database for information and the flow of data. The queries and data shown below are based on the table scripts provided in the download. Examples of how the ThingWorx entity should look can be seen in the SQLServerDatabaseController and OracleDatabaseController entities. Running a Query As you may have noticed by working in ThingWorx and developing applications, an InfoTable is often used to work with large sets of data. An InfoTable is also how data is returned from a database query. If you're expecting only 1 value in the result set, the data will be held in the first index of the InfoTable. If you're expecting rows of data coming back, expect there to be rows of information inside of the InfoTable. Follow the steps below to set up a helper service to perform queries for the database. While other services might generate the query to be used, this helper service will be a shared execution service. In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Query) called RunDatabaseQuery.   3. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. 4. Add the following parameter:  Name            Base Type   Required query String True 5. Add the following code to the new service: <<query>> 6. Click Save and Continue. Your service signature should look like the below example.   You now have a service that can run queries to the database. This is also a simple method to test/troubleshoot the database connection or a quick query. Run your service with a simple query. You might notice that no matter the fields in the result set, the InfoTable will match it based on field type and field name. There are two ways you can go from here. You can either query the database using services that call this service, or you can create more SQL command services that query the database directly. Let's go over each method next, starting with a service to call our helper. In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service JavaScriptQuery_PersonsTable. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following code to your new service: try { var query = "SELECT * FROM Persons"; logger.debug("DatabaseController.JavaScriptQuery_PersonsTable(): Query - " + query); var result = me.RunDatabaseQuery({query:query}); } catch(error) { logger.error("DatabaseController.JavaScriptQuery_PersonsTable(): Error - " + error.message); }   5. Click Save and Continue. Any parameter, especially those that were entered by users, that is being passed into an SQL Statement using the Database Connectors should be fully validated and sanitized before executing the statement! Failure to do so could result in the service becoming an SQL Injection vector. This is a simple way to query the database since much of your development inside of ThingWorx was already based in JavaScript. Now, let's utilize the second method to create a query directly to the database. You can use open and close brackets to create parameters for your query. You can also use <> as a method to mark a value that will need to be replaced. As you build your query, use [[Parameter Name]] for parameters/variables substitution and <> for string substitution. In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service SQLQuery_GetPersonByEmail. Ensure the Output is InfoTable. Add the following code to your new service: SELECT * FROM Persons WHERE person_email = [[email]]; 5. Add the following parameter:  Name          Base Type    Required email String True 6. Click Save and Continue. An example of using the string replacement is as follows:         DELETE FROM <> WHERE (FieldName = '[[MatchName]]'); DELETE FROM << TableName >> WHERE ( FieldName = [[MatchNumber]]);             Click here to view Part 2 of this guide.
View full tip
    Use Analytics Manager to automatically perform engine analytical calculations.   Guide Concept   This guide will use ThingWorx Analytics Manager to compare external-data from an Edge MicroServer (EMS) "Engine Simulator" to a previously-built analytical model.   Following the steps in this guide, you will learn how to deploy the model which you created in the earlier Builder guide.   We will teach you how to utilize this deployed model to investigate whether or not live data indicates a potential engine failure.   You'll learn how to   Deploy and execute computational models Define and trigger Analysis Events Map incoming data to the Model Map analytic outputs to applications   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 60 minutes       Step 1: Scenario   In this guide, we're continuing the same MotorCo scenario, where an engine can fail catastrophically in a low-grease condition.   In previous guides, you've gathered and exported engine vibration-data from an Edge MicroServer (EMS) and used it to build an engine analytics model.   The goal of this guide is to now operationalize that previously-created model to analyze individual, external readings to see if the "low grease" condition is currently happening.     Analytical model creation can be extremely helpful for the automotive segment in particular. For instance, each car that comes off the factory line could have an EMS constantly sending data from which an analytical model could automatically detect engine trouble.   This could enable your company to offer an engine monitoring subscription service to your customers.   This guide will show you how to put an analytic model of your engine into service to actively monitor performance.       Step 2: Configure Provider   In ThingWorx terminology, an Analysis Provider is a mathematical analysis engine.   Analytics Manager can use a variety of Providers, such as Excel, Mathcad, or even Analytics Server pre-built ones.   In this guide, we use the built-in AnalyticsServerConnector, a Provider that has been specifically created to work seamlessly in Manager and to use Builder Models.   From the ThingWorx Composer Analytics tab, click Analytics Manager > Analysis Providers > New....   In the Provider Name field, type Vibration_Provider. In the Connector field, search for and select TW.AnalysisServices.AnalyticsServer.AnalyticsServerConnector.   Leave the rest of the options at default and click Save.     Step 3: Publish Analysis Model   Once you have configured an Analysis Provider, you can publish Models from Analytics Builder to Analytics Manager. On the ThingWorx Composer Analytics tab, click Analytics Builder > Models.   Select vibration_model_s1_only and click Publish.   On the Publish Model? pop-up, click Yes. A new browser tab will open with the Analytics Manager's Analysis Models menu. Close that new browser tab, and instead click Analysis Models in the ThingWorx Composer Analytics navigation. This is the same interface as the auto-opened tab which you closed.   Click the model to select it. At the top, click Enable. Note the pop-up indicating that the Enable was successful.       Step 4: Modify EdgeThing   In previous guides in this Vehicle Predictive Pre-Failure Detection Learning Path, you have created various Entities, including Things such as EdgeThing.   In order to automate the process of pushing data from EdgeThing to Analytics Manager, we need to add a few more Properties to EdgeThing.   These Properties are simple STRING variables, and we'll also set Default Values for them to configure parameters of Analytics Manager.   The first is causalTechnique, which tells Analytics Manager which criteria to use when measuring the impact of a feature on a range of goal values.   The second is goalField, which is simply the data field for which Analytics Manager should try to identify the correlation. In this case, it'll be our primary issue, i.e. low_grease.   It is not mandatory that these suggested Property names match, but they are the names used within ThingWorx Analytics. You could use any Property name you wanted, as you'll be mapping from a particular Property to the functionality within Analytics in a later step.   Return to EdgeThing > Properties and Alerts.   Click + Add.   In the Name field, type causalTechnique. Check Has Default Value. In the text field under "Has Default Value", type FULL_RANGE. Note that you MUST type FULL_RANGE, including capitalization, as that is a command within Analytics Server.   Click the "Check with a +" icon for Done and Add. In the Name field, type goalField. Check Has Default Value. In the text field under "Has Default Value", type low_grease. Note that you MUST type low_grease, including being all lower-case, as that is the exact name of the Analytics Server goal.   Click the "Check" icon for Done. Click Save.   Results Storage   We also need a place in which to store the results that Analytics Manager returns. We'll utilize a few additional Properties for that as well.   On the EdgeThing > Properties and Alerts tab, click + Add. In the Name field, type Result_low_grease. Check the Base Type to BOOLEAN. Check Persistent.   Click the "Check with a +" icon for Done and Add. In the Name field, type Result_low_grease_mo. Change the Base Type to NUMBER. Check Persistent.   Click the "Check" icon for Done. Click Save.       Step 5: Create Event   Events are automatic analysis jobs which are submitted based on a pre-defined condition. In this step, we'll configure an Analysis Event, which will execute automatically whenever there is a data-change in our simulated engine.   On the ThingWorx Composer Analytics tab, click Analytics Manager > Analysis Events.   Click New.... If not already selected, change Source Type (Required) to Thing.   In Source, search for and select EdgeThing. In Event, select DataChange. In Property, select s1_fb1. If there are multiple s1_fb1 Properties, select the first one, as the second one is the s1_fb1 entry in the Info Table Property. In Provider Name, select Vibration_Provider. In Model Name, select the published Model.   Click Save.       Click here to view Part 2 of this guide.  
View full tip
    Step 6: Map Data   Now that the event is created, we need to map the Properties of EdgeThing to the fields required to invoke an Analysis Job.   We'll start with the Inputs.   Select the previously-created Event, and click Map Data....   Click Inputs Mapping.   In Source Type, select Thing. In Source, search for and select EdgeThing.   On the left, scroll down and select s1_fb1. Note that you do NOT want the s1_fb1 that is part of the InfoTable Property, because the Info Table Property only stores recorded data, not live data. On the right, select _s1_fb1, the first frequency band required for the Model to make a prediction.   Click the Map button in the center.   Repeat this mapping process for for s1_fb2 through s1_fb5.   Map causalTechnique to causalTechnique in the same manner. This is a String Property in EdgeThing with a Default Value of "FULL_RANGE". Map goalField to goalField in the same manner. This is a String Property in EdgeThing with a Default Value of "low_grease".   Map Results   Now that the Inputs are mapped, we also want to map the Results.   Click Results Mapping on the left.   Map _low_grease to Result_low_grease. Map _low_grease_mo to Result_low_grease_mo.   Click Close to close the mapping pop-up.   Enable Event   Now that we've done the mapping from Foundation to Analytics, let's Enable the Analysis Event so that it can automatically generate and process Analysis Jobs. Select the mapped Analysis Event. Select Enable.   Now that you have enabled the Analysis Event, the new data will be submitted to Analytics Manager whenever EdgeThing's s1_fb1 Property changes.   An Analysis Job will automatically run, with a predictive score sent back and stored in EdgeThing's Result_low_grease (Boolean) and Result_low_grease_mo (Number) Properties.     Step 7: Check Jobs   In this step, we'll confirm that the automatic analysis of information coming from remote devices is operational.   On the ThingWorx Composer Analytics tab, click Analytics Manager > Analysis Jobs.   Uncheck Filter Completed Jobs.   Select a Job and click View.... Click Results.   NOTE: You will see true or false, corresponding to either a low grease or no low grease condition. Using this technology, you could create a paid customer service, where you offered to monitor remote engines, in return for automatically shutting them down before they experience catastrophic engine failure.   For that example implementation, you would utilize the EdgeThing.Result_low_grease BOOLEAN Property to trigger other actions.   For instance, you could create an Alert Event which would be triggered on a true reading.   You could then have a Subscription which paid attention to that Alert Event, and performed an action, such as sending an automatic shutdown command to the engine when it was experiencing a likely low grease event.   NOTE: We recommend that you return to the ThingWorx Composer Analytics > Analytics Manager > Analysis Events tab and Disable the Event prior to continuing. Since the simulator generates an Event every ~1 seconds, this can create a large number of Events, which can fill up your log.       Step 8: Next Steps   Congratulations. You've completed the Manage an Engine Analytical Model guide. In this guide you learned how to:   Define an Analysis Provider that uses the built-in Analytics Server Connector Publish a Model from Analytics Builder to Manager Create an Analysis Event which takes data from ThingWorx Foundation and decides whether or not a failure is likely   The next guide in the Vehicle Predictive Pre-Failure Detection with ThingWorx Platform learning path is Engine Failure-Prediction GUI.   Learn More   We recommend the following resources to continue your learning experience:    Capability     Guide Build Implement Services, Events, and Subscriptions Guide   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource              Link Community Developer Community Forum Support Analytics Manager Help Center      
View full tip
  Connect to an existing database and design a connected data model.   GUIDE CONCEPT   There are times you already have your database designed and only need to integrate the ThingWorx environment.   These concepts and steps will allow you to focus on development of your application while still allowing the ability to utilize the power of ThingWorx!   We will teach you how to create a data model around your database design and connect to that database.     YOU'LL LEARN HOW TO   How to connect an external database and created services to be used with it How to design and implement a new data model based on an external resource Using data models with database services   Note: The estimated time to complete this guide is 30 minutes.      Step 1: Examples and Strategy   If you’d like to skip ahead, download and unzip the completed example of the Aerospace and Defense learning path attached to this guide:  AerospaceEntitiesGuide1.zip.   By now, you likely know how to create a data model from scratch. You have likely already created services that work with Info Tables. What you might not have completed, is combining both a new data model, handling data in services, and connecting it all to an external database.   Our organization, PTC Defense Department, has existed for years and has an existing database setup. Developers in our organization refuse to remodel the database, so we must model the ThingWorx data model to our database schema. With ThingWorx, this is not a difficult task, but there are numerous decisions and options that we will explore in this guide.     Step 2: Database Connections   ThingWorx is based on the Java programming language and can make connections to any database that supports a Java-based connection. Dropping the JAR file for the database JDBC driver to the lib folder of Tomcat is all that is needed for connection to the ThingWorx Platform. Follow the below steps to get started creating the connection.   To establish the connection and begin working with an external database, you will need to create a Database Thing and configure the connection string and credentials. Let us start with our database connection. If you have not done so already, download the Aerospace and Defense database scripts: DatabaseApplication.zip. Use the README.txt file to create the database schema. It is based on Microsoft SQL Server, but you can configure the scripts to your database preferences.   NOTE: You will not need to connect to a database to utilize this guide as a learning utility. For your services to work, you will need to connect to a database.   1. In ThingWorx Composer, click the + New at the top-left of the screen.     2. Select Thing in the dropdown.     3. Name the Thing `DatabaseController.Facilities` and select Database as the Base Thing Template.     4.Click Save and go to the Configurations tab.   In this tab, you will enter the class name of your driver, the connection string for that database connection, and the credentials to access the database.   Keep in mind, the JDBC Driver Class Name, JDBC Connection String, and the connection Validation String values are all database type specific. For example, to connect to a SQL Server database, the below configuration can be used.   Title Description  Example   JDBC Driver Class Name  The specific class name of the driver being used for the connection.  net.sourceforge.jtds.jdbc.Driver (SQL Server) or oracle.jdbc.driver.OracleDriver (Oracle)  JDBC Connection String  The connection string to locate the database by host/port/database name.  jdbc:jtds:sqlserver://server:port/databaseName (SQL Server) or jdbc:oracle:thin:@hostname:port:databaseName (Oracle)  connectionValidationString  A simple query that should always work in a database.  SELECT GetDate() (SQL Server) or SELECT SYSDATE FROM DUAL (Oracle)   5. After entering credentials, click Save.     6. Go the Properties and Alerts tab.   The connected Property should be checked. This property informs us of the current connection to the database. The lastConnection Datetime Property should show a current timestamp. This property informs us of the last time there was a valid connection to the database. This is an easy way to confirm the connection to the database.   If you do not have a connection, work on your configurations in the Configurations tab and validate the credentials being used. If you are still having troubles, see the examples section below or use the next section for help to try a query of the database.   Help and Troubleshooting   For help finding the correct configuration for you, check out these JDBC Configuration Examples or try out this Connection String Reference for help with your connection string.   You have just established your first database connection! Now jump to the next section and let us begin to build a data model to match the database schema.   Step 3: Query Data from External Database   Now that you're connected to the database, you can begin querying the database for information and the flow of data. The queries and data shown below are based on the table scripts provided in the download.   Examples of how the ThingWorx entity should look can be seen in the SQLServerDatabaseController and OracleDatabaseController entities.   Running a Query   As you may have noticed by working in ThingWorx and developing applications, an InfoTable is often used to work with large sets of data. An InfoTable is also how data is returned from a database query. If you're expecting only 1 value in the result set, the data will be held in the first index of the InfoTable. If you're expecting rows of data coming back, expect there to be rows of information inside of the InfoTable.   Follow the steps below to set up a helper service to perform queries for the database. While other services might generate the query to be used, this helper service will be a shared execution service.   In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Query) called RunDatabaseQuery.           3. Set the Output as InfoTable, but do not set the DataShape for the InfoTable.       4. Add the following parameter: Name Base Type Required query String True       5. Add the following code to the new service:   <<query>>       6. Click Save and Continue. Your service signature should look like the below example.       You now have a service that can run queries to the database. This is also a simple method to test/troubleshoot the database connection or a quick query.   Run your service with a simple query. You might notice that no matter the fields in the result set, the InfoTable will match it based on field type and field name.   There are two ways you can go from here. You can either query the database using services that call this service, or you can create more SQL command services that query the database directly. Let's go over each method next, starting with a service to call our helper.   In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service JavaScriptQuery_PersonsTable. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following code to your new service: try { var query = "SELECT * FROM Persons"; logger.debug("DatabaseController.JavaScriptQuery_PersonsTable(): Query - " + query); var result = me.RunDatabaseQuery({query:query}); } catch(error) { logger.error("DatabaseController.JavaScriptQuery_PersonsTable(): Error - " + error.message); }       5. Click Save and Continue.   Any parameter, especially those that were entered by users, that is being passed into an SQL Statement using the Database Connectors should be fully validated and sanitized before executing the statement! Failure to do so could result in the service becoming an SQL Injection vector.   This is a simple way to query the database since much of your development inside of ThingWorx was already based in JavaScript.   Now, let's utilize the second method to create a query directly to the database. You can use open and close brackets to create parameters for your query. You can also use <> as a method to mark a value that will need to be replaced. As you build your query, use [[Parameter Name]] for parameters/variables substitution and <> for string substitution.   In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service SQLQuery_GetPersonByEmail. Ensure the Output is InfoTable. Add the following code to your new service: SELECT * FROM Persons WHERE person_email = [[email]];       5. Add the following parameter:   Name Base Type Required email String True         6. Click Save and Continue.   An example of using the string replacement is as follows: DELETE FROM <> WHERE (FieldName = '[[MatchName]]'); DELETE FROM << TableName >> WHERE ( FieldName = [[MatchNumber]]);       Click here to view Part 2 of this guide.
View full tip
  Step 3: Create Validation and Status   With our MyFunctionsMashup Mashup open, let's add a Validation. A Validation is similar to an Expression, except you have the added capability of triggering Events based on a True or False outcome of your validation. We will use the Validation to check and confirm the Text Field we created only has the values we added in our Functions. Let's also add two Status Message Functions that will show whether or not a user has added any text outside of what we want.   Open the MyFunctionsMashup Mashup to the Design tab. Click the green + button in the Functions area.    In the New Function modal, select Validator.   Set the Name to isDataClean.   Click Next.  Click Add Parameter. Set the Name to text and ensure the Base Type is STRING.   Add the following code to the Expression are: if(text === "NO") { result = true; } else if(text === "YES") { result = true; } else { let array = text.split("YES").join(""); array = array.split(",").join(""); let count = array.trim().length; if(count) { result = false; } else { result = true; } }   9. Click Done.   We have our Validator in place, now we need our two Status Message Functions. Why two? You can setup one Status Message to perform the task, but for this case, we're keeping things simple.   Click the + button in the Functions area. Select Status Message in the dropdown.    Set the Name to GoodInputProvided.   Click Next. Ensure Message Type is Info. In the Message field, enter Text is all good!.   Click Done. Let's create another Status Message Function. Set the Name to BadnputProvided.   Click Next. Change Message Type to Error. In the Message field, enter Text is BAD!.   Click Done.   We now have two Status Message Functions and a Validator to help with checking our text data. Let's connect everything together. This time, let's use the Bind button.   Expand the Validator section in the Functions tab. Click the Bind (arrows) button on the isDataClean Validator. This window will help us configure connections a bit easier.    Click the down arrow by the True Event. Click Add Trigger Service.   Click Functions. Check the checkbox by GoodInputProvided.   Click Next. Click the down arrow by the False Event. Click Add Trigger Service.   Click Functions. Check the checkbox by BadInputProvided.   Click Next. You should currently have the following setup:    Let's add in our connections to the Text Field and when we'll run this Validation.    Click the down arrow by the text Property.   Click Add Source. With the Widgets tab selected, scroll down and select the Text Property of our Text Field.   Click Next. Click the down arrow by Evaluate Service. Select Add Event Trigger.   With the Widgets tab selected, scroll down and select the Clicked Property of our Button.   Click Next. You should currently have the following setup:   Click Done. Click Save and view your updated Mashup.   Your Validator is complete. You now have a way to tell when a user has inputed their own text into the text box. To try things out, add some crazy characters, hit the button, and see what happens. You might notice that you have your Expressions running at the same time as your Validator. Switch up the bindings to get it to run the way you want it to.     Step 4: Create Confirmation Modal   With our MyFunctionsMashup Mashup open, let's add a Confirmation Function. A Confirmation Function provides a quick modal that will give users a method to confirm actions or events before they take place. If you've ever almost deleted a production database (don't judge me!), then you know how handy a confirmation screen can be. Let's add a button that will trigger a confirmation as to whether we would like to run the Validator we created in the last section.   Open the MyFunctionsMashup Mashup to the Design tab. Click the + button in the Functions panel. Select Confirmation in the dropdown.   Set the Name to confirmDataValidation. Click Next.   Set the Title Text to Confirm Data Validation?. Set the Message Text to Would you like to perform a data validation?.   Set the Cancel Button Label to No Thanks!. Scroll down and set the Action Button Label to Yes Sir!.   Click Done. Click the Widgets tab in the top left. Filter for and select a Button Widget.   Drag and drop a Button Widget onto the Canvas.   With the new Button selected, click the down arrow that appears on the Button. Drag and drop the Clicked Event of the Button to the OpenConfirmation Service of our Confirmation Function.     We now have our Confirmation Function and a Button that will open the Confirmation when clicked. Let's add the final step by connecting the Confirmation to our Validation Function.   Click the Bind (arrows) button for our isDataClean Validator.   Click the down arrow by the Evaluate Service. Select Add Event Trigger.   Click the Functions tab. Select the ActionClick Event of our Confirmation Function.   Click Next. Click Done. Click Save for our Mashup.   We now have a way to independently validate that the text in our text box does not contain random values added by the user. View the Mashup and test things out by clicking on the second button and adding some crazy characters to our text box.       Step 5: Create Navigation   Thus far, we have been sticking to one Mashup. Let's venture out a bit by showing a different Mashup. Inside of our MyFunctionsMashup Mashup, we will add a Navigation Function. This will allow us to go to or just show a different UI based on some kind of user input or event. For our example, when a user clicks No Thanks! in our Confirmation Function, let's send them to a different Mashup.   Follow the steps to create a Navigation Function, a destination Mashup, and tie the two together.    Create Destination Mashup Navigate to Browse > Visualization > Mashups.   Click + New. Keep the defaults and click OK. In the Name field, type MyNavigationDestination.   Click Save. Click the Design tab at the top to open the Mashup canvas. Click the Widgets tab.   Filter and search for the word Label. Drag and drop a Label Widget to the Mashup canvas. If you like, enlarge the Label sizing.    In the Label Widget Properties section, scroll down to the LabelType Property.       Click the dropdown and select Large Header.   In the LabelText Property field, type MY DESTINATION UI SCREEN. Click Save. You have now created a simple UI that we will go to when we click our navigation button. Next, we'll tie together our navigation button and our freshly created Mashup.   Create Navigation Function Reopen the MyFunctionsMashup Mashup to the Design tab. Click the + button in the Functions panel. Select Navigation in the dropdown.   Set the Name to travelToDestination.   Click Next. Set the Target Window Type to ModalPopup. Set the Pop-up Title to New Popup Here.   Set the Pop-up Width to 400. Set the Pop-up Height to 400.   Click the + button at Target Mashup. Type MyNavigationDestination into the search bar. Select the MyNavigationDestination Mashup when it appears.   Click Done. Select the Bind (arrows) button for our new travelToDestination Navigation Function.   Click the down arrow next to Navigate Service. Click Add Event Trigger.   Click the Functions tab. Select the CancelClick Event of our confirmDataValidation Confirmation Function.   Click Done. Click Save for the Mashup.   We now have a modal that will appear after we click the No Thanks! button in our Confirmation Function. View the Mashup and try out what you've done by clicking the bottom button, then clicking No Thanks!     Click here to view Part 3 of this guide.  
View full tip