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

ThingWorx Navigate is now Windchill Navigate Learn More

IoT & Connectivity Tips

Sort by:
  Discover how ThingWorx advance tree grids and grids can be implemented in a compelling Mashup design.   Guide Concept   This project will introduce how to create complex user interfaces that are built by using Mashup grids and JavaScript services.   Following the steps in this guide, you will build a web application with advanced data displays. We will teach you how to create a professional user interface that effectively conveys information to users.   You'll learn how to   Create dynamic tree grids to display hierarchy. Create dynamic grids to display growing data number of data points.   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 30 minutes       Step 1: What Are Dynamic Grids   In the Mashup Builder, we utilize Functions to create added capabilities in our Mashups. Whether we are navigating to another Mashup or triggering events based on some action. Functions are your best friends when creating more advanced Mashups.   Function  Description   Auto Refresh  Refreshes data automatically for widgets in a mashup.  Confirmation  Displays a confirmation dialog box.  Events Router  Routes multiple input sources to one output of the same type.  Expression  Evaluates JavaScript expressions.  Logout  Ends the current user session and redirects to a mashup or a Web page.  Navigation  Navigates from one mashup to another.  Status Message  Displays information, error, or warning messages in a mashup.  Validator  Validates data from input parameters by using JavaScript expressions.   In the next sections, we will cover some of these Functions and showcase how to add them to your Mashups.     Step 2: Create A Dynamic Grid   Let's start things off by creating a simple Expression Function. This Expression will show or hide a label based on whether a checkbox is checked or not. This simple expression can be expanded to your use case.   It is VERY important to note that in an Expression Function (and also found in Services and Validation Functions) the output of the Function will be the result variable. Let's create our Mashup, then go over what is involved in an Expression.   In the ThingWorx Composer, click the + New at the top of the screen.   Select Mashup in the dropdown.   Select the Responsive layout then hit OK.   Set the Name to  MyFunctionsMashup. For the Project, click the + button and select PTCDefaultProject.    Under Project, click the blue Set as project context option. This will stop us from having to set the Project on every Thing we create. It should now match the following.    Click Save. Click on the Design tab at the top. This Mashup will be where we create the Majority of our Functions and capabilities. Let's start adding to our Mashup.   Click the Layout tab. Scroll down and set the Orientation to Horizontal.   Click on the Widgets tab. Type in the Filter text box for Checkbox.   Drag and drop a Checkbox Widget to the Mashup Canvas. This Checkbox will dictate whether what we show for the coming Labels and Textbox. Type in the Filter text box for Button. This Button will dictate the event that triggers our Functions. Drag and drop a Button Widget to the Mashup Canvas.   Type in the Filter text box for Label. Drag and drop TWO (2) Label Widgets to the Mashup Canvas. We will only show one Label at a time and I'll show you how.   Type in the Filter text box for Text Field. Drag and drop a Text Field Widget to the Mashup Canvas.       We have the Widgets we need to show our Expression example. Let's start with connecting the Widgets to Functions.   Click the + button in the Functions section in the bottom right.    In the New Function popup, select Expression. Set the Name of the new Expression to isCheckboxChecked.   Click Next. In the new screen, click Add Parameter. Set the Name to this new parameter as checked. Set the Base Type as BOOLEAN.   Switch the Data Change Type to ALWAYS. Switch Output Base Type to BOOLEAN.   Add the following code to the Expression area.  if(checked) { result = true; } else { result = false; }   11. Click Done.   You've now created your first expression. This expression is an example of how easy it can be done. Let's add three three additional Expressions to have some fun.   Repeat steps 1-11 in the last section for TWO (2) new Expressions. Name these Expressions setFirstLabelVisbility and setSecondLabelVisbility. You should now have three total. Repeat steps 1-8 in the last section for ONE (1) new Expression. Name this Expression setTextFieldText. We should have a Parameter called checked. Click Add Parameter again to add a Parameter named input. This fourth Expression should match the following thus far:     Switch Output Base Type to STRING. Add the following code to the Expression area:  if(checked) {     if(input && input.indexOf("YES") >= 0) {     result = input + ", YES";     } else {         result = "YES";     } } else {     result = "NO";     } 6. Click Done.   This expression will see whether or not the Checkbox is checked, then output a string of YES or a simple NO. Let's setup our connections between Widgets and Expressions.   Ensure Expressions are visible and match the following.   Click on the Checkbox in the Mashup Canvas. Click the dropdown that appears.   Drag and drop the State Property to the checked Parameter of all FOUR (4) of the Expressions.   Your bindings should match the following after you're done with setting all four.   Expand the setFirstLabelVisibility Expression (if not already expanded).   Drag the Output to the first Label and select Visible.   Expand the setSecondLabelVisibility Expression (if not already expanded).   Drag the Output to the second Label and select Visible.   Our labels are configured. Now let's setup our Text Field Widget.    Expand the setTextFieldText Expression (if not already expanded). Drag the Output to the Text Field and select Text.   Select the Button Widget in the Mashup Canvas.  Click the dropdown for the Button Widget. Drag and drop the Clicked Event to all FOUR (4) of the Expressions.   Your Button Widget should look like the following:   Select the Text Field Widget in the Mashup Canvas Click the dropdown for the Text Field Widget. Drag and drop the Text Property to the input Parameter of the setTextFieldText Expression. Click Save. Click View Mashup. Play around and see all the work you've done.   You maybe notice that both Label Widgets show or hide at the same time. To split when they will show or hide, update the code for one of the Label visibility Expressions to the following:    if(checked) {     result = false; } else {     result = true;     }   Click here to view Part 2 of this guide.  
View full tip
This video continues Module 1: ThingWorx Analytics Overview of the ThingWorx Analytics Training videos. It covers some of the functionality of the ThingWorx platform, as well as ThingWorx Analytics capabilities.
View full tip
  Use the Statistical Calculation Thing Shape to Execute Common Statistical Functions   GUIDE CONCEPT   This project will introduce the Statistical Calculation Thing Shape.   The steps in this guide outline how to utilize Descriptive Analytics in ThingWorx Analytics to perform common mathematical analyses on data sets. You will learn how to use the Statistical Calculation Thing Shape's built-in functionality to calculate the mean, median, mode, and other useful insights.     YOU'LL LEARN HOW TO   Create a Value Stream and Data Shape Create a Thing with the Statistical Calculation Thing Shape Modify a Property to record values to the Value Stream Utilize various built-in services to perform the Mean, Median, Mode, and Standard Deviation calculations   NOTE: The estimated time to complete this guide is 30 minutes.     Step 1: Introduction   Descriptive Analytics enables users to perform on-demand common statistical calculations and enable statistical monitoring. Output from these Services can then easily be added to IoT applications built with the ThingWorx platform.   For example, output generated by Descriptive Analytics can be used to build solution-specific visualizations (Mashups or Widgets), create Alerts based on logged Property values, or generate transformed data for machine learning processes.   Descriptive Analytics includes two microservers, each with its own set of statistical Services. This guide will deal specifically with the Statistical Calculation Thing Shape.   This Thing Shape will add a variety of built-in Services to any Thing or Thing Template you choose, such as calculations for Mean, Median, Mode, or Standard Deviation.   To perform these statistical calculations, a Property must have time-series data logged to a Value Stream.   In addition, the Statistical Calculation Thing Shape has been optimized to perform calculations only on particular time ranges and with a maximum entry-count. This helps minimize some of the performance hits that can occur from repeatedly accessing Value Streams.   You perform this "data grooming" via the QueryTimedValuesForProperty Service, which is also part of the Statistical Calculation Thing Shape.   In addition to the name of a Property with values logged to a Value Stream, you also provide a Start Date, End Date, and Max Item Count.   The QueryTimedValuesForProperty Service then formats the values from the Value Stream to work with for the other built-in statistical calculation Services.   Step 2: Create Prerequisites   The inputs to the built-in Services of the Statistical Calculation Thing Shape require time-series data stored in a Value Stream. Setting a Thing's Properties to be Logged will store valid time-series data on which to perform Descriptive Analytics.   Create Value Stream   Follow the steps below to create a Value Stream that you will later tie to a Thing.   On the ThingWorx Composer Browse tab, click DATA STORAGE > Value Streams, + New.   Select ValueStream and click OK.   In the Name field, enter scts_valuestream. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Save.   Create Data Shape   You will need a Data Shape to format the timed_values Property we will create in the next step.   On the ThingWorx Composer Browse tab, click MODELING > Data Shapes, + New.   In the Name field, enter scts_timed_values_datashape. If Project is not already set, search for and select PTCDefaultProject.   At the top, click Field Definitions.   Click + Add. On the right slide-out, in the Name field, enter value. Change the Base Type to NUMBER.   At the top-right, click the "check with a +" icon for Done and Add. In the Name field, enter timestamp. Change the Base Type to LONG.   At the top-right, click the "check" icon for Done. At the top, click Save.       Step 3: Create Thing   Next, you will create a Thing and tie the previously-created Value Stream to it.   You will assign the Statistical Calculation Thing Shape to get a variety of built-in analytics Services to manipulate the data. You will also create a series of Properties to facilitate the new Services.   On the ThingWorx Composer Browse tab, click MODELING > Things, + New.   In the Name field, enter scts_thing. If Project is not already set, search for and select PTCDefaultProject. In the Base Thing Template field, search for and select GenericThing. In the Implemented Shapes field, search for and select StatisticalCalculationThingShape. In the Value Stream field, search for and select scts_valuestream.   At the top, click Save.   Add Properties   Next, you will add a series of Properties to scts_thing.   Perform the following steps repeatedly until all Properties have been added.   At the top, click Properties and Alerts.   Click + Add. On the right slide-out, in the Name field, enter numbers. Change the Base Type to NUMBER. Click Persistent. Click Logged.   At the top-right, click the "check with a +" icon for Done and Add. Repeat steps 3-7 until all of the properties in the table below have been added. NOTE: For the final standarddev_result Property, do NOT click Done and Add; you'll just click the check for Done instead. Property Name Base Type Data Shape Persistent  Logged start_time DATETIME N/A Checked NOT checked end_time DATETIME N/A Checked NOT checked timed_values INFOTABLE scts_timed_values_datashape Checked NOT checked mean_result NUMBER N/A Checked NOT checked median_result NUMBER N/A Checked NOT checked mode_result INFOTABLE none, i.e. leave it blank Checked NOT checked standarddev_result NUMBER N/A Checked NOT checked     At the top-right, click the "check" icon for DONE. At the top, click Save.   Step 4: Set Properties   You will now set the properties to guarantee that each calculation gives us a different answer.   Mean is the average. Median is the "middle" number from the dataset. Mode is the most common number. Standard Deviation is a measure of the "dispersion" of the dataset.   You will use the following dataset: 1, 5, 9, 5, 9, 1, 9.   The mean is 39 / 7 = 5.571...   The median is 5, as 5 is the middle of 1, 5, and 9.   Mode is 9, because 9 appears most commonly in the dataset.   Standard Deviation is 3.5989...   Perform the following steps to enter the above values into the numbers property.   Set numbers   Under the Value column and on the numbers property row, click the "pencil" icon for Set value of property.   On the right slide-out, enter 1.   At the top-right, click the "check" icon for Done. At the top, click Save.   Repeat steps 1-4 above, changing the value each time according to the table below: Value Change Count  Entered Value 2nd 5 3rd 9 4th 5 5th 9 6th 1 7th 9   You also need to set the start_time and end_time. These are dates used to define the time-period in which the Statistical Calculation Thing Shape will search for values.   For instance, you could set the calculations to run at midnight, and then use the past 24-hours as your time-period.   For this example, set dates to be 24 hours prior to the time at which you set the above values of the numbers property, through 24 hours in the future.   Set start_time   Under the Value column and on the start_time Property row, click the "pencil" icon for Set value of property.   On the right slide-out, search for and select the previous day.   At the top-right, click the "check" icon for Done. At the top, click Save.   Set end_time   Under the Value column and on the end_time property row, click the "pencil" icon for Set value of property.   On the right slide-out, search for and select the following day. At the top-right, click the "check" icon for Done. At the top, click Save.     Click here to view Part 2 of this guide.
View full tip
    Step 4: Write Data to External Database You’ve connected to the database, you’re able to query the database. Now let’s handle inserting new data into the database. The update statements 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 an Insert 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 your shared execution service. In the DatabaseController entity, go to the Services tab.   Create a new service of type SQL (Command) called RunDatabaseCommand. Keep the Output as Integer. Add the following parameter:  Name           Base Type       Required command String True 5. Add the following code to your new service: <<command>> 6. Click Save and Continue. Your service signature should look like the below example. You now have a service that can run commands to the database. Run your service with a simple insert. There are two ways to 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 the helper. In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service JavaScriptInsert_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 command = "INSERT INTO Persons (person_key, person_name_first, person_name_last, person_email, person_company_name, " + "person_company_position, person_addr1_line1, person_addr1_line2, person_addr1_line3, person_addr1_city, person_addr1_state, " + "person_addr1_postal_code, person_addr1_country_code, person_addr1_phone_number, person_addr1_fax_number, person_created_by, " + "person_updated_by, person_created_date, person_updated_date) VALUES ('" + key + "', '" + name_first + "', '" + name_last + "', '" + email + "', '" + company_name + "', '" + company_position + "', '" + addr1_line1 + "', '" + addr1_line2 + "', '" + addr1_line3 + "', '" + addr1_city + "', '" + addr1_state + "', '" + addr1_postal_code + "', '" + addr1_country_code + "', '" + addr1_phone_number + "', '" + addr1_fax_number + "', '" + created_by + "', '" + updated_by + "', '" + created_date + "', '" + updated_date + "')"; logger.debug("DatabaseController.JavaScriptInsert_PersonsTable(): Query - " + command); var result = me.RunDatabaseCommand({command: command}); } catch(error) { logger.error("DatabaseController.JavaScriptInsert_PersonsTable(): Error - " + error.message); } 5. Add the following parameter:  Name                                   Base Type           Required key String True name_first String True name_last String True company_name String True company_position String True addr1_line1 String True addr1_line2 String True addr1_line3 String True addr1_city String True addr1_state String True addr1_postal_code String True addr1_country_code String True addr1_phone_number String True addr1_fax_number String True created_by String True updated_by String True created_date String True updated_date String True 6. Click Save and Continue. Any parameter, especially those that were entered by users, that is being passed into a 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. Now, let’s utilize a second method to create a query directly to the database. You can use open and close brackets for parameters for the insert. You can also use <> as a method to mark a value that will need to be replaced. As you build your insert statement, use [[Parameter Name]] for parameters/variables substitution and <<string replacement >> for string substitution. In the Services tab of the DatabaseController entity, create a new service of type SQL (Command).   Name the service SQLInsert_PersonsTable. Add the following code to your new service: INSERT INTO Persons (person_key ,person_name_first ,person_name_last ,person_email ,person_company_name ,person_company_position ,person_addr1_line1 ,person_addr1_line2 ,person_addr1_line3 ,person_addr1_city ,person_addr1_state ,person_addr1_postal_code ,person_addr1_country_code ,person_addr1_phone_number ,person_addr1_fax_number ,person_created_by ,person_updated_by ,person_created_date ,person_updated_date) VALUES ([[key]] ,[[name_first]] ,[[name_last]] ,[[email]] ,[[company_name]] ,[[company_position]] ,[[addr1_line1]] ,[[addr1_line2]] ,[[addr1_line3]] ,[[addr1_city]]]] ,[[addr1_state]] ,[[addr1_postal_code]] ,[[addr1_country_code]] ,[[addr1_phone_number]] ,[[addr1_fax_number]] ,[[created_by]] ,[[updated_by]] ,[[created_date]] ,[[updated_date]]); 4. Add the following parameter:  Name                                  Base Type       Required key String True name_first String True name_last String True company_name String True company_position String True addr1_line1 String True addr1_line2 String True addr1_line3 String True addr1_city String True addr1_state String True addr1_postal_code String True addr1_country_code String True addr1_phone_number String True addr1_fax_number String True created_by String True updated_by String True created_date String True updated_date String True 5. Click Save and Continue. Examples of insert services can be seen in the provided downloads.   Step 5: Executing Stored Procedures There will be times when a singular query will not be enough to get the job done. This is when you'll need to incorporate stored procedures into your database design. ThingWorx is able to use the same SQL Command when executing a stored procedure with no data return and a SQL query when executing a stored procedure with an expected result set. Before executing these services or stored procedures, ensure they exist in your database. They can be found in the example file provided. Execute Stored Procedure Now, let's create the service to handle calling/executing a stored procedure. If you are expecting data from this stored procedure, use EXEC to execute the stored procedure. If you only need to execute the stored procedure and do not expect a result set, then using the EXECUTE statement is good enough. You're also able to use the string substitution similar to what we've shown you in the earlier steps. In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Command) called RunAssignStudentStoredProcedure. Add the following parameter:  Name                      Base Type        Required student_key String True course_key String True 4. Add the following code to your new service: EXECUTE AddStudentsToCourse @person_key = N'<<person_key>>', @course_key = N'<<course_key>>';   You can also perform this execute in a service based on JavaScript using the following code: try { var command = "EXECUTE AddStudentsToCourse " + " @student_key = N'" + student_key + "', " + " @course_key = N'" + course_key + "'"; logger.debug("DatabaseController.RunAssignStudentStoredProcedure(): Command - " + command); var result = me.RunDatabaseCommand({command:command}); } catch(error) { logger.error("DatabaseController.RunAssignStudentStoredProcedure(): Error - " + error.message); } 5. Click Save and Continue. Execute Stored Procedure for Data Let's create the entity you will use for both methods. This can be seen in the example below:   In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Query) called GetStudentCoursesStoredProcedure. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following parameter:  Name                    Base Type        Required course_key String True 5. Add the following code to your new service: EXEC GetStudentsInCourse @course_key = N'<<course_key>>'   You can also perform this execute in a service based on JavaScript using the following code: try { var query = "EXEC GetStudentsInCourse " + " @course_key = N'" + course_key + "'"; logger.debug("DatabaseController.GetStudentCoursesStoredProcedure(): Query - " + query); var result = me.RunDatabaseQuery({query:query}); } catch(error) { logger.error("DatabaseController.GetStudentCoursesStoredProcedure(): Error - " + error.message); } 6. Click Save and Continue. You've now created your first set of services used to call stored procedures for data. Of course, these stored procedures will need to be in the database before they can successfully run. Step 6: Next Steps Congratulations! You've successfully completed the guide for External Database, and learned how to use the ThingWorx Platform to connect to database, query for data, and write new data. Learn More We recommend the following resources to continue your learning experience:  Capability       Guide Build Design Your Data Model Build Configure Permissions Additional Resources If you have questions, issues, or need additional information, refer to:  Resource           Link Community Developer Community Forum
View full tip
    Step 6: Power Grid Example   In the Power Grid application, there are three Generator Things and three Consumers. Each Thing has a number of Properties based on its location, wattage, and its power lines provided with power. In this design, when a generator goes offline, comes back online, or one of the other power grid aspects are updated/created/deleted, the Property values are updated. The GeneratorThing class extends the VirtualThing class and based on the Generator entities in the Composer. After extending VirtualThing, there are a number of steps necessary to get going. For the GeneratorThing and SimpleThing classes, there are a number of methods for creating Properties, Events, Services, and Data Shapes for ease of use.   The constructor for the GeneratorThing takes in the type of electricity generator, name of the Thing, the description of the Thing, and the ConnectedThingClient instance used to make the connection. It then sends these values to the VirtualThing constructor as shown below. public GeneratorThing(String type, String name, String description, ConnectedThingClient client) { super(name, description, client); ...   We use the initializeFromAnnotations method to initialize all of the annotations that we will create in this class. This is done as follows and a necessary call for VirtualThings in the constructor:   initializeFromAnnotations();   Create Properties   You can create Properties in two ways. Using annotations is the recommended method, but there are times in which programmatically creating properties is the best option. For example, constructing dynamic features or allowing inline functionality would call for the coding style of Property creation. The following shows the Properties that correlate to those in the DeliveryTruck Entities in the Composer. To do this within the code, you would use a PropertyDefinition instance as shown in the SimpleThing.java property1 creation.   With Annotation @ThingworxPropertyDefinition(name="GeneratorType", description="Type of generator", baseType="STRING", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="Wattage", description="Wattage produced", baseType="NUMBER", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="Amps", description="Amps", baseType="NUMBER", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="Voltage", description="Voltage", baseType="NUMBER", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="UpTime", description="Number of minutes since the generator connected online", baseType="NUMBER", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="Status", description="Status of the generator", baseType="NUMBER", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="Location", description="Location of the generator", baseType="LOCATION", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="LastSync", description="The last time we performed a sync", baseType="DATETIME", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="ConnectedSince", description="Time where we last performed a successful connection", baseType="DATETIME", aspects={"isReadOnly:false"}),@ThingworxPropertyDefinition(name="TransmissionLines", description="An infotable of power lines", baseType="INFOTABLE", aspects={"isReadOnly:false"}) Without Annotation //Create the property definition with name, description, and baseType PropertyDefinition property1 = new PropertyDefinition(property, "Description for Property1", BaseTypes.BOOLEAN); //Create an aspect collection to hold all of the different aspects AspectCollection aspects = new AspectCollection(); //Add the dataChangeType aspect aspects.put(Aspects.ASPECT_DATACHANGETYPE, new StringPrimitive(DataChangeType.NEVER.name())); //Add the dataChangeThreshold aspect aspects.put(Aspects.ASPECT_DATACHANGETHRESHOLD, new NumberPrimitive(0.0)); //Add the cacheTime aspect aspects.put(Aspects.ASPECT_CACHETIME, new IntegerPrimitive(0)); //Add the isPersistent aspect aspects.put(Aspects.ASPECT_ISPERSISTENT, new BooleanPrimitive(false)); //Add the isReadOnly aspect aspects.put(Aspects.ASPECT_ISREADONLY, new BooleanPrimitive(false)); //Add the pushType aspect aspects.put("pushType", new StringPrimitive(DataChangeType.NEVER.name())); //Add the defaultValue aspect aspects.put(Aspects.ASPECT_DEFAULTVALUE, new BooleanPrimitive(true)); //Set the aspects of the property definition property1.setAspects(aspects); //Add the property definition to the Virtual Thing this.defineProperty(property1); Property values can either be set with defaults using the aspects setting. Nevertheless, setting a default value will affect the Property in the ThingWorx platform after binding. It will not set a local value in the client application. In this example, we make a request to the ThingWorx Composer for the current values of the generator properties using our getter methods: //Get the current values from the ThingWorx Composer wattage = getGeneratorWattage(); voltage = getGeneratorVoltage(); location = getLocation();   Create Event Definitions   As with Properties, Events can be created using annotations or code as shown in SimpleThing.java. Here we create the GeneratorOffline event that is in the Generator instances.   With Annotation   @ThingworxEventDefinitions(events = { @ThingworxEventDefinition(name="GeneratorOffline", description="The event of a generator going offline", dataShape="GeneratorShape", isInvocable=true, isPropertyEvent=false) })   Without Annotation   //Create the event definition with name and description EventDefinition event1 = new EventDefinition(event, "Description for Event1"); //Set the event data shape event1.setDataShapeName("SimpleDataShape"); //Set remote access event1.setLocalOnly(false); //Add the event definition to the Virtual Thing this.defineEvent(event1);   Create Remote Services   With remote Services, the implementation is handled by the Java application and can be called either within the application or remotely, by the Composer while a connection is established. The GetTruckReadings Service, a dummy Service used as an example of how to create a remote Service, populates an Info Table and returns that Info Table for whoever would like to use it. You can see how it is possible to define remote Services that can later be bound to Things in the Composer. A Service is defined using @ThingworxServiceDefinition annotation and its result is defined using @ThingworxServiceResult. These annotations take various parameters among including:   Name Description baseType Aspects In the second line, you can see the name of the result being set by the CommonPropertyNames field to keep development consistent with creating Things in the Composer. With Annotation @ThingworxServiceDefinition(name="OhmsLawCalculator", description="Get the watts/power (W) based on input voltage (V) and current (I)") @ThingworxServiceResult(name=CommonPropertyNames.PROP_RESULT, description="Result", baseType="NUMBER")   Without Annotation //Create the service definition with name and description ServiceDefinition service1 = new ServiceDefinition(service, "Description for Service1"); //Create the input parameter to string parameter 'name' FieldDefinitionCollection fields = new FieldDefinitionCollection(); fields.addFieldDefinition(new FieldDefinition("name", BaseTypes.STRING)); service1.setParameters(fields); //Set remote access service1.setLocalOnly(false); //Set return type service1.setResultType(new FieldDefinition(CommonPropertyNames.PROP_RESULT, BaseTypes.STRING)); //Add the service definition to the Virtual Thing this.defineService(service1); //Service1 Definition public String Service1(String name) throws Exception { String result = "Hello " + name; return result; }   Create Data Shapes   Data Shapes must be created using code as seen in GeneratorThing.java as shown below:   // Data Shape definition that is used by the generating going offline event   FieldDefinitionCollection fields = new FieldDefinitionCollection();fields.addFieldDefinition(new FieldDefinition(TYPE_FIELD, BaseTypes.STRING));fields.addFieldDefinition(new FieldDefinition(WATTAGE_FIELD, BaseTypes.STRING));fields.addFieldDefinition(new FieldDefinition(AMPS_FIELD, BaseTypes.NUMBER));fields.addFieldDefinition(new FieldDefinition(VOLTAGE_FIELD, BaseTypes.NUMBER));fields.addFieldDefinition(new FieldDefinition(UP_TIME_FIELD, BaseTypes.NUMBER));fields.addFieldDefinition(new FieldDefinition(STATUS_FIELD, BaseTypes.NUMBER));fields.addFieldDefinition(new FieldDefinition(LOCATION_FIELD, BaseTypes.LOCATION));fields.addFieldDefinition(new FieldDefinition(LAST_SYNC_FIELD, BaseTypes.DATETIME));fields.addFieldDefinition(new FieldDefinition(CONNECTED_SINCE_FIELD, BaseTypes.DATETIME));fields.addFieldDefinition(new FieldDefinition(POWER_LINES_FIELD, BaseTypes.INFOTABLE));defineDataShapeDefinition("GeneratorShape", fields); NOTE: It is possible to create a Data Shape, and then use it in a Service definition within your code as StringIndex property, StringMap Data Shape, and StringMapService Service in SimpleThing.java.     Scan Cycles   To complete the implementation of the VirtualThing class, we recommend you provide an override and implementation to the processScanRequest method. This method provides a universal method for all VirtualThing implementations. This method could be used or a new method could be created for this purpose. The processScanRequest method in VirtualThing.java does not have an implementation of its own. An implementation from DeliveryTruckThing.java can be seen below:   // The processScanRequest is called by the PowerGrid class every scan cycle @Override public void processScanRequest() throws Exception { // Execute the code for this simulation every scan this.scanDevice(); this.updateSubscribedProperties(1000); this.updateSubscribedEvents(1000); }   Bound Properties in Cycle   The scanDevice method in GeneratorThing.java performs a number of tasks from retrieving Property values to firing Events. To retrieve a Property using binding, a request is made to the client using the name of the Property. A good programming practice is to handle how these Properties are accessed and set. Note that the update method for Properties and Events must be used after queueing an Event or setting a Property value. In the example below (used within the Delivery Truck Example), getter and setter methods are used for added control. The getProperty() call is used on the VirtualThing: public Double getSpeed() { return (Double) getProperty("Speed").getValue().getValue(); } public void setSpeed() throws Exception { setProperty("Speed", this.speed); } public Location getLocation() { return (Location) getProperty("Location").getValue().getValue(); } public void setLocation() throws Exception { setProperty("Location", this.location); }     Click here to view Part 4 of this guide.
View full tip
    Use a Timer to record mass amounts of test data, and then export it as a Comma-Separated Values file.   GUIDE CONCEPT   Having an Edge MicroServer (EMS) Engine Simulator has allowed you to begin work on using ThingWorx Foundation for instrumenting a prototype engine.   However, the end goal is not to inspect the data manually, but to have ThingWorx Analytics perform an automatic notification for any issues.   In this guide, you’ll create a Timer to generate thousands of data points, and then export the dataset as a Comma-Separated Values (.csv) file for future use in building an analytical model of the engine.     YOU'LL LEARN HOW TO   Create a Timer Subscribe to a Timer to Trigger a Service Generate Mass Amounts of Test Data Import the CSV Parser Extension Create a File Repository Export the Test Data as a Comma-Separated Values (.csv) file Download from a File Repository   NOTE:  The estimated time to complete all parts of this guide is 30 minutes.     Step 1: Scenario   In this guide, we're finishing up with the 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. You've even put that analytical model into service to give near-immediate results from current engine-vibration readings.   The goal of this guide is to create a GUI to visualize those predicted "low grease" conditions to facilitate customer warnings.     This is a necessary step, as the end-goal is to automate failure analysis by utilizing ThingWorx Analytics, which builds an analytical model by importing a .csv file with several thousand data points.   Data storage, export, and formatting in this manner 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.   But to enable automatic comparison of engine data to an analytical model, you must first generate and format sample data to build said model, and this guide will show you exactly how to do that.     Step 2: Create a Timer   In the previous Use the EMS to Create an Engine Simulator guide, you ended up with an EMS engine simulator from which Foundation could capture individual readings and store them in an Info Table Property.   But for ThingWorx Analytics, we need thousands of data points, if not tens-of-thousands.   Manually triggering the Service to generate that many data points would be tedious.   Instead, we'll create a Timer Thing off which we can trigger the automatic calling of the data-capture Service.   This guide assumes that you have already completed the Use the Edge MicroServer (EMS) to Connect to ThingWorx and Use the EMS to Create an Engine Simulator guides and have a working, active connection from the EMS Engine Simulator to ThingWorx Foundation.       1. Return to the ThingWorx Foundation Browse > All navigation.          2. Click MODELING > Timers.       3, Click + New.       4. On the Choose Template pop-up, select Timer and click OK.     5. In the Name field, type ESDS_Timer.       6. If Project is not already set, search for and select PTCDefaultProject.        7. In the Run As User field, search for and select Administrator.       8. On the Warning pop-up, click Yes.   Note that the Administrator user should only be utilized for testing and never in a production system.       9. Set the Update Rate to 2000.   The EMS updates values around every second, i.e. 1000ms, so we want a time longer than that.     10. At the top, click Save.       Step 3: Subscribe to the Timer   Now that we have a Timer, we can use its 2000ms (two seconds) Event generation to trigger something else.   In this case, we’ll use it to trigger the data-capture Service we created in the previous guide.      1. Click Browse > MODELING > Things.      2. Open EdgeThing and click Properties and Alerts.      3. Scroll down past the custom Properties to the Inherited Properties.      4. Under the Value column, ensure that isConnected is checked. If not, return to the previous guides and confirm that your EMS engine simulator is running.     Having ensured that the EMS engine simulator is still providing values to ThingWorx Foundation, we now want to create a Subscription, which will trigger off our earlier timer.      1. At the top, click Subscriptions.      2. Click + Add.      3. In the Name field, type ESDS_Timer_Subscription.      4. Under Source, select the Other entity radio-button.      5. In the Search Entities field, search for and select ESDS_Timer.      6. Check the Enabled box.      7. Expand the Inputs section.      8. In the Select an Event field, search for and select Timer.      9. Expand the Me/Entities section.      10. Expand the Services sub-section.      11. Scroll down until you find the custom recordService, and click the right-arrow beside it.      12. Click Save and Continue. Note that you should NOT click the top “Save”, as that will erase the Subscription.                     Step 4: Data Acquisition   With the progress so far, another entry is captured and added to the Info Table Property ever two seconds. We'll confirm that now.   The longer that you let the Subscription run, the more entries will be automatically captured in the infoTableProperty. ThingWorx Analytics can use this information to build an analytical model.   To do so, though, it needs thousands of entries. For example, we’ve gotten good model results with 30,000 data points. In general, more is better.   As such, your Subscription would need to run until you have gathered 30,000 entries in the infoTableProperty. Unfortunately, this can take roughly 15-16 hours.   You can simply let the timer run for a short time and then continue with this guide immediately.       1. At the top, click Properties and Alerts.       2. Click the Refresh button several times. Note that both the identifier Property and the count of the number of entries in the infoTableProperty are continually increasing.       3. Under the Value column, click the “pencil icon” for infoTableProperty to select Set value of property. It may take a few moments for the pop-up to load.         4. Note that various values coming from the EMS engine simulator.       5. At the top-right of the pop-up, click the X button.   Stop Data Gathering After achieving the dataset size you desire, you should stop gathering to prevent your dataset from growing arbitrarily large.        1. At the top of EdgeThing, click Subscriptions.       2. If it is not already expanded, click ESDS_Timer_Subscription.       3. Expand Subscription Info.       4. Uncheck the Enabled box.        5. Click Save and Continue.       Click here to view Part 2 of this guide.    
View full tip
    Step 7: Add Grid   It might also be helpful to display the data you've used to build the ThingWorx Analytics model.   In the future, this might be split out into an entirely separate page/Mashup that is exclusively devoted to backend model creation, but that would be beyond the scope of this guide.   For now, we'll simply display that collected data via the Grid Widget      1. On the EEFV_Mashup, drag-and-drop a Grid Advanced Widget onto the bottom-left Canvas section..     2. On the top-right Data tab, click the green </> button beside Things_EdgeThing. Note that this will open the Add Data pop-up, but with EdgeThing pre-selected.   3. In the Services Filter field, type getproperties.   4. Click the right-arrow beside GetProperties to add it to Selected Services on the right.   5. Check Execute on Load.     6. Click Done.   7. Under the Data tab, expand GetProperties to reveal the options.     8. Drag-and-drop Things_EdgeThing > GetProperties > infoTableProperty onto the Grid Advanced Widget.     9. On the Select Binding Target pop-up, click Data.     10. Click Save.   11. Click View Mashup.         Step 8: Add Controls   Throughout this Learning Path, it has been recommended that you stop Analysis Events when not actively using their functionality.   However, this requires going into the backend of ThingWorx Analytics to disable the event, which is not ideal.   Instead, let's enable or disable the Analysis Event from inside the Mashup by adding some Button Widgets to directly interface the Analytics backend for us.       1. Click the bottom-right Canvas section to select it.         2. In Mashup Builder top-left, click the Layout tab.         3. Under Positioning, click the Static radio-button.         4. Click the Widgets tab.       5. Drag-and-drop a Button Widget onto the bottom-right section.         6. Drag-and-drop another Button Widget onto the bottom-right section.       7. Drag-and-drop a Text Field Widget onto the bottom-right section.       8. Click Save.       Bring in More Data   Now that we have Buttons to trigger enable/disable, as well as a Text Field to display information, we now need to bring in some additional Mashup Data Services to interact with the ThingWorx Analytics backend.       1. Click the green + button at the top of the Data tab.       2. In the Entity Filter field, search for and  select TW.AnalysisServices.EventManagementServicesAPI.       3. In the Services Filter field, search for and add QueryAnalysisEvents by clicking the right arrow.       4. Check Execute on Load.         5. In Services Filter, search for and select EnableAnalysisEvent by clicking the right arrow. Note that you should NOT check "Execute on Load", as we'll trigger this Service only when the Button is clicked.     6. In Services Filter, search for and select DisableAnalysisEvent by clicking the right arrow. Likewise, do NOT check "Execute on Load" here either.       7. Click Done.         8. Click Save.     Display Event Key   To enable or disable Analytics Events, we need to know the eventId, which is returned by QueryAnalysisEvent Service as the parameter labeled key.   We'll bind that to the Text Field Widget for later usage in enabling/disabling.        1. Change the top-button's Label Property to Enable Analytics Event.       2. Change the bottom-button's Label Property to Disable Analytics Event.         3. Under the Data tab, expand QueryAnalysisEvents > Returned Data > All Data to reveal the options. .       4. Drag-and-drop QueryAnalysisEvents > Returned Data > All Data > key to the TextField Widget.         5. On the Select Binding Target pop-up, click Text.         6. Click Save.     Enable/Disable Analytics Events   Now that we know the key/eventId, we can call the EnableAnalysisEvent and DisableAnalysisEvent services.       1. Under the Data tab, expand EnableAnalysisEvent > Parameters to reveal eventId.       2. Click the Text Field Widget to select it, and then click the top-left drop down to reveal the options.         3. Drag-and-drop the Text Field's Text Property onto EnableAnalysisEvent > Parameters > eventId.         4. Repeat steps 1-3 for DisableAnalysisEvent.         5. Click the Enable Analytics Event Button Widget to select it, then click the top-left to reveal the drop down option .       6. Drag-and-drop the Clicked Event onto the EnableAnalysisEvent Service under the Data tab.         7. Repeat steps 5-6 for DisableAnalysisEvent, using the other Button Widget.         8. Click Save     Step 9: View Mashup   Throughout this guide, we've added various additional functionality to our MVP Mashup. At this point, you could continue to update the Mashup as you see fit.   For instance, you could change the background color of the top-left section to better match the header. Or you could further modify the original Mashup shown in the Contained Mashup Widget so that it better fits in the allowed space. You could add another Label Widget to the Header section to also display the company's motto / tag-line.   Regardless, when you are done with modifications, Save and click View Mashup.     Note that you can left-click-and-drag on the Time Series Chart to select particular time ranges. Or you could add a Time Selector Widget to the bottom-right section to control it there.   Similarly, you could add controls for the Grid Widget to only show the Identifier ranges in which you were interested.   Or you could split out the Model-creation values to a completely separate Mashup as previously discussed.   The extent to which you develop your Mashup is entirely up to you.        Step 10: Next Steps   Congratulations. You've completed the Enhanced Engine Failure Visualization guide. In this guide, you learned how to:   Create a Mashup with a Header Divide your Mashup into Sub-sections Use a Contained Mashup to reuse development Store historical data in a Value Steam Display historical data in a Line Chart Show spreadsheet data via a Grid Advanced Widget Tie Mashup controls into the ThingWorx backend   This is the last guide in the Vehicle Predictive Pre-Failure Detection with ThingWorx Platform learning path.   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
This is just a quick note/reminder that starting 7.4, the utilities installation process has slightly changed. Several extensions are no longer bundled with ThingWorx Utilities and must be downloaded from the ThingWorx Marketplace and installed separately. For more information, see the “Prerequisites” topic in the ThingWorx Utilities Installation Guide: http://support.ptc.com/WCMS/files/172616/en/ThingWorxUtilitiesInstall.pdf The following extensions must be installed prior to installing ThingWorx Utilities available at ThingWorx IoT Marketplace ○ Google Maps Widget ○ Mail Extension ○ Web Sockets Tunnel Widget and Library
View full tip
  Learn how to store and display medical device data for a Service opportunity.   Guide Concept   In this guide, you’ll learn how to combine information from multiple Edge devices into a single, logical Thing.   You’ll then create a GUI to display this combined information (as well as retrieve new information on demand) to facilitate a “Medical Service Play”.     You'll learn how to   Create a Data Shape and Info Table Property to store Medical Data Create a Service to combine data from multiple Edge devices into a single, logical Thing Create a Mashup to view and retrieve Medical data   NOTE:  The estimated time to complete ALL parts of this guide is 60 minutes     Step 1: Medical Learning Path   So far in this Learning Path, you've been able to connect both an embedded controller (simulated by a Raspberry Pi) and a PC to ThingWorx Foundation.   This is important, as medical devices can be complicated pieces of technology controlled by multiple "intelligent" subsystems. It is not always practical (or desirable) to have these subsystems communicate with each other, even if they all need to work together to function optimally.   Fortunately, Foundation has the capability to combine relevant data from multiple Edge devices into a single, logical Thing.   In this step of the Learning Path, you will do just that to facilitate a "Service Play".   The scenario is that your company manufactures and services Magnetic Resonance Imaging (MRI) devices.     Rather than simply servicing the MRI when there is an issue (and after a very expensive device has been damaged from something going wrong), your company maintains a continuing service contract with the hospital to monitor the MRI and perform preventative maintenance on it BEFORE anything goes wrong.   The value proposition to the hospital is the ability to keep their expensive investment in perfect operating order rather than suffering an unexpected failure. In turn, your company reaps the benefits of receiving a steady source of income from said service contract.   In order to achieve this level of preventative maintenance, your company needs to constantly monitor the MRI's various functions.   The MRI is composed of multiple working parts, but for this scenario, we'll limit our Minimum Viable Product (MVP) Service Application to the following:   An embedded device which monitors various hardware elements (such as magnet temperature and remaining coolant) A Windows PC (common in hospital equipment) which is used by a Medical Technician to control the MRI In particular, it's important to note that this PC has access to patient medical data, which can be subject to Health Insurance Portability and Accountability Act (HIPAA) violations. Fortunately here again, it's possible to segregate this information into protected and non-protected sections to limit your company's liability. We'll only propogate non-protected, generalized information to Foundation, such as the total number of scans that have been run thus far. This can facilitate your company getting a connected device approved by a hospital worried about HIPAA-compliance.   To help you run through this guide, we'll also utilize a pair of "simulators" to mimic data coming from the EMS-es on the Pi and PC, rather than directly taking information from them. So if you had any issues with the previous steps getting the EMS running on these devices, you can still complete this guide without issue.     Step 2: Import Simulators   As mentioned, we'll be using a pair of simulators to mimic connections to both an embedded microcontroller and a PC, both of which are part of the MRI.   Perform the following steps to import the simulators.   Download and unzip the MDSD_Entities.zip file attached to this article. In the bottom-left of Foundation Composer, click Import/Export.   Click Import.   On the Import pop-up, click Browse. Navigate to the download location and select the MDSD_Entities.twx file.   Click Open.   Click Import.   Click Close.   Note how there are now several MDSD Entities. These represent Things connected to different parts of the MRI which are communicating to Foundation via the EMS Agent (as per the previous guides in this Learning Path).   Investigate Simulators   Since there are multiple sub-systems which are all communicating directly to Foundation (but we really only want to check the status of the MRI as one logical entity), we need to know what exactly is being communicated back.   What is being communicated was likely determined by your company's Edge Developers when they implemented the EMS agent on said sub-systems.   Perform the following steps to investigate the simulators.   Click MDSD_Embedded_Thing.   Click Properties and Alerts.   So the embedded microcontroller has sensors which are tracking the following:    Property                           Units                       Description Coolant Percent Percent Amount of coolant left to refrigerate the super-conducting magnets Field Strength Tesla Strength of the magnetic field Magnet Temperature Degrees Celsius Temperature of the magnets   Next, let's look at the other simulator. Return to Browse > All. Click MDSD_PC_Thing. Click Properties and Alerts.   The PC is tracking information from the MRI controlling software, including the following:   Property Units  Description Number of Scans Scans Aggregate count of all scans the MRI has performed since last reset SSD Space Open Megabytes Amount of space left on the hard-drive Unused RAM Megabytes Amount of RAM still available to the system   Both of these remote devices are communicating valuable information.   The embedded microcontroller is feeding us information about the hardware of the MRI itself. Refilling coolant as needed is likely one of the service contract stipulations and will be a regular service need. And a Field Strength drop or Magnet Temperature rise could indicate more significant issues which could damage the MRI if not promptly addressed.   The PC gives us information about the operation of the MRI. Hard-drive or RAM running low could indicate that the hardware specs of the PC need to be upgraded, while the Number of Scans can give us a rough estimate of how much refrigerant should have been used versus the currently available level. If only a handful of Scans have been run, but the amount of coolant has dropped by a significant amount, then there could be a leak somewhere which would need to be addressed.   The combination of the Embedded and PC data is enough for us to begin working on a constantly-monitoring application which will facilitate our Service Play.       Step 3: Create Data Shape   Now that we're aware of what information is coming from the separate sub-systems of the MRI, we need to combine them into a single, logical Thing for the purposes of a Service Play.   To do so, we'll create a Thing which represents the MRI as a whole. Additional sub-systems can be added to to the collective information of this Thing as is necessary. But, as stated, this is simply an MVP, so we'll stick to the embedded and PC sub-systems at present.   A good way to aggregate multiple data points into a single item is via an Info Table Property. However, any time you create an Info Table, you also need a Data Shape to format the "columns" of the spreadsheet-like Property.   For more information on the storage of "mass-data", please refer to the Methods for Data Storage guide.   Perform the following steps to create a Data Shape.   Click Browse > Modeling > Data Shapes.   Click + New. In the Name field, type MDSD_DataShape.   If Project is not already set, search for and select PTCDefaultProject. At the top, click Field Definitions.   Click + Add.   Embedded Definitions   We now want to add Field Definitions to the Data Shape which map the information that we want to collate between the various sub-systems.   We'll start with the Embedded Microcontroller Properties.   On the far-right in the Name field, type Coolant_Percent. Change the Base Type to Number.   At the top-right, click the "Check with a +" for Done and Add. In the Name field, type Field_Strength. Change the Base Type to Number.   Click the "Check with a +" for Done and Add. In the Name field, type Magnet_Temperature. Change the Base Type to Number.   Click the "Check" button for Done. At the top, click Save.   PC Definitions   Additional Definitions can be added at anytime as other sub-systems are included.   We'll now include the PC Properties.   Click + Add. In the Name field, type Number_of_Scans. Change the Base Type to Number.   Click the "Check with a +" for Done and Add. In the Name field, type SSD_Space_Open. Change the Base Type to Number.   Click the "Check with a +" for Done and Add. In the Name field, type Unused_RAM. Change the Base Type to Number.   Click the "Check" button for Done. At the top, click Save.   Timestamp   It might also be benificial to include a Timestamp of when the values of both the embedded microcontroller and PC were added.   Click + Add. In the Name field, type Timestamp. Change the Base Type to DATETIME.   Click the Check button for Done. Click Save.     Click here to view Part 2 of this guide.
View full tip
    Step 5: Handling and Receiving XML Objects   Working with JSON with JavaScript can be easy and simple. Working with XML while using JavaScript can be more challenging, because XML is so tightly structured. This can affect how you setup code and how you use the Rhino JavaScript engine for your needs.   NOTE: Examples of these services can be found in the ** XMLProcessorThing** entity, which is provided in the download.   Handling XML   XML can be handled using two methods. The first method is converting the XML string to an XML object. The second methos is creating an XML object, then assigning the raw XML to that variable.   The simple XML object is as follows: <note> <to>Janice</to> <from>Billy</from> <heading>Please Remind Me</heading> <body>Take out the trash this weekend!</body> </note> First, create the entity you will use for both methods. In ThingWorx Composer, click the + New at the top of the screen. Select Thing in the dropdown. Name the Thing XMLProcessorThing and click Save. Click the Services tab. Click Save and let’s begin with the first method of handling XML in ThingWorx.   Parsing XML Using Method 1   Now, you will create the service to handle the first method of XML handling. This is a simple method to easily convert XML string and grabbing a field in the XML.   In the Services tab of the XMLProcessorThing Thing, create a new service called ParseXML. The service will have no parameters. Set the Output as String. Add the following JavaScript to help encode the string and return an HTML friendly string. /*jshint multistr: true */ var xml = new XML("<note> \ <to>Janice</to> \ <from>Billy</from> \ <heading>Please Remind Me</heading> \ <body>Take out the trash this weekend!</body> \ </note>"); var result = "Sending note to " + String(xml.*::to);   5. Click Save and you’re all done with this service to parse XML string and grab information from it.   Parsing XML Using Method 2   The second method will show errors and warnings, if you’re using the Lint setting in your service JavaScript code window. This method will be very helpful in handling XML responses from a service call.   In the Services tab of the XMLProcessorThing Thing, create a new service called ParseRawXML. The service will have no parameters. Set the Output as String. Add the following JavaScript to help encode the string and return an HTML friendly string. var xml = new XML(); xml = <note> <to>Janice</to> <from>Billy</from> <heading>Please Remind Me</heading> <body>Take out the trash this weekend!</body> </note> var result = "Sending note to " + String(xml.to);   5. Click Save and you’re all done.     Step 6: Next Steps   Congratulations! You've successfully completed the Sending and Receiving JSON and XML guide, and learned how to use the ThingWorx Platform to handle REST requests and send payload for external SOAP and REST services.   Learn More   We recommend the following resources to continue your learning experience:   Capability Guide Build Design Your Data Model Build Use REST API to Access ThingWorx   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
    Step 5: Collection Widget   A Collection widget is used to display information from a collection of Things. Similar to a Grid Widget, the Collection widget gives you complete control over how data is displayed by binding data to an embedded static Mashup.   In the first part of this step we will create a static Mashup with Parameters bound to its widgets. Next, we will configure a Collection widget to use the static Mashup we create. In the next step we will customize the Collection styling.   Create Static Mashup   Click the Browse tab on the far left of Composer, in the Visualizations section, click Mashups . Click + New to create a Mashup. Select Static Mashup, then click OK.   Name your Mashup TractorListFormat If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. Click Save. Click the Design tab If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. In the Layout tab, under Container > Positioning, Click Static, then scroll to Container Size, and click Fixed Size NOTE: A Static Mashup maintains fixed widget sizes and spacing, as opposed to a Responsive Mashup that will dynamically change widget sizes and spacing to use the available window area. Click the Width property and set it to 200 and the Height property to 60   In the lower left panel, click the Style tab and click the X to remove the default Style. Click the + icon, then select DefaultImageBorderStyle to remove all styling. NOTE: The default Mashup styling is removed so it will not override the sidebar and parent Mashup styling. Scroll to the Width property and set it to 200 and the Height property to 60 Click the Widgets tab and type label in the filter text box. Drag and drop two Label Widgets onto the upper left of your static Mashup.   Add Parameters to Mashup Select the Explorer tab then select the top level Mashup Click Configure Mashup Parameters from the drop-down menu in the upper left of the Mashup canvas.   Click the Add Parameter button. Type firstLine in the Name field and select a Base Type of STRING. Click Add Parameter again and name this parameter secondLine also with a Base Type STRING.   Click Done to return to Mashup Builder.   Bind Parameters to Widgets   Click the drop-down in the upper left of the Mashup canvas, then select Configure Bindings Click firstLine from the Properties list on the left. Clicking the drop-down arrow and click Add Source to display the Mashup entities that can be bound to the Mashup parameter named firstLine.   Select the checkbox next to the top LabelText property.   Click Done to return to the Configure Bindings pop-up. Click secondLine, then Binding Targets, and select the checkbox next to the bottom Label Text property, then click Done Click Done to close Configure Bindings pop-up and return to Mashup builder. NOTE: The Mashup parameters and bindings are displayed in the Connections panel at the bottom. Click Save before continuing to the next step.   Bind Data to Collection   Return to the main Mashup then drag and drop a Collection widget onto the top area of the left side bar. In the Collection Properties panel, set the View property to Table Scroll to the Mashup property, click the wand icon and browse to the name of the static Mashup created above. Drag the All Data source from the data panel on the right onto the Collection widget, then click Data in the Select Binding Target pop-up.   Set UIDField property and SortField to SerialNumber.   Drag the All Data source from the data panel on the right onto the Collection widget, then click Data in the Select Binding Target pop-up.   In the Collection Properties panel, scroll to MashupPropertyBinding and click *Add Enter the text below, then click Done: { "SerialNumber": "firstLine", "ModelNumber": "secondLine" } NOTE: This JSON property binds the SerialNumber and ModelNumber properties in the data source to the the firstLine and secondLine parameters in the embedded mashup   9. Save the Mashup and click View Mashup.   10. Test the Mashup and you will see the navigation panel on the left is showing data and is linked to the Google Map widget in the center.       Step 6: Customize Collection   The Collection uses default styling and no images. In this part of the exercise, we will replace the blue bar that indicates the selected row with a custom icon and modify the default styles so that the left panel's background color is shown.   Right-click on each of the images below to download and save them for use in the next step.     We will upload these images to create new Media entities and apply them to the Repeater widget.   Select the Browse folder icon on the far left of Composer, in the Visualization section click Media Click the + New to create a new Media entity and enter a name for the un-selected tractor image. Click Change in the Image section, then browse to the saved image. Click Open, then Save. Repeat these steps to create a Media entity for a selected tractor Open the static TractorListFormat mashup that controls the Collection widget formating Click and drag an Image widget onto the mashup In the lower left panel, in the SourceURL property, click the wand icon to select the unselected tractor image. Change both the Width and Height properties to 50 pressing Tab after each entry to record them.   Click the Explorer tab in the top left, click the top-most Mashup entity, then click the Style Properties tab Cick the X in the Style property and select DefaultImageBorderStyle to remove all styling, then click Save Click the More drop-down at the top of Composer and click Duplicate   Enter TractorListSelectFormat for the name and click Save then click the Design tab Click on the tractor image, then, the lower left, click the wand icon in the SourceURL property and select the selected tractor image and Click Save   Open your original Mashup and click on the Collection widget in the Mashuo Builder canvas. Scroll to the SelectedMashupName Property and click the + to select TractorListSelecteFormat.   Click Save for the Mashup, then View Mashup to see your Mashup with customized icons.   The default black text on green is a little hard to read. The steps below will change the text colors to make the data more readable. Open the TractorListSelectFormat Mashup then click on the top Label widget to change the color of the text. Click the Style Properties tab and expand Base and Label In color property select yellow and select Bold in the font-weight property before clicking Save. Select the other Label widget and assign a light grey color for the color then save the embedded Mashup. Reload the runtime view of the Mashup to see the results.     Step 7: Detail Panel   The right sidebar has a simple Image of a tractor along with product-specific information shown in Gauges and Value Displays.   The right sidebar contains two tabs in a Tabs - Responsive widget. The tabs are used to selectively hide and display groups of functions and data. The orange button labeled "View Vehicle Specs" is a Navigation widget that opens a pop-up window with other detailed product information. The colored range indications on the right Gauge were created by configuring the gauges ValueFormatter property to use State Formatting.   Add Tab Widget   Open the original, main Mashup and enter tab in the Widget panel search field. Drag and drop a Tabs widget onto the Right Sidebar.   Scroll to the Tab1Name property and enter Tractor Details. NOTE: This guide only covers configuring one of the two tabs added to the Mashup. Using the skills you've practiced thus far, feel free to add additional information to the tabs on your Mashup. Uncheck the RoundedCorners property. Click the Layout tab and click the radio button under Container > Orientation > Vertical   Add ValueDisplay Widgets   Type value in the Widget search box then click and drag a Value Display Widget onto Tab 1. In the Property panel, scroll to the Label property and enter Serial Number In the Data panel, expand Selected Row(s) then drag the SerialNumber property onto the Value Display widget and click Data when the Select Binding Target pop-up is displayed.   Drag another Value Display Widget onto the tab widget below to the first one and enter Name for the Label property. Drag name from the Selected Row(s) onto the second Value Display and then click Data. NOTE: Be sure to select data sources under Selected Row(s) so that data displayed will correspond to the tractor selected from either the map or the left side menu. Save the Mashup then click View Mashup to see all three panels working together to show data.   Add Gauges   Enter gauge in the Widget search box then click and drag a Gauge Widget onto Tab 1. In the Properties panel, enter 3000 for the MaxValue property and RPM in the Legend property. In the Data panel, expand Selected Row(s) then drag CurrentRPM onto the Gauge widget and click Data when the Select Binding Target pop-up is displayed. Drag another Gauge widget onto the canvas next to the first one and enter MPH for the Legend property. Drag CurrentSpeed from the Selected Row(s) onto the second Gauge, then click Data.   Click here to view Part 3 of this guide.
View full tip
  Step 5: Properties In the Delivery Truck application, there are three Delivery Truck Things. Each Thing has a number of Properties based on its location, speed, and its deliveries carried out. In this design, when a delivery is made or the truck is no longer moving, the Property values are updated. The deliveryTruck.c helper C file is based on the DeliveryTruck Entities in the Composer. After calling the construct function, there are a number of steps necessary to get going. For the SimpleThing application, there are a number of methods for creating Properties, Events, Services, and Data Shapes for ease of use. Properties can be created in the client or just registered and utilized. In the SimpleThingClient application, Properties are created. In the DeliveryTruckClient application, Properties are bound to their ThingWorx Platform counterpart. Two types of structures are used by the C SDK to define Properties when it is seen fit to do so and can be found in [C SDK HOME DIR]/src/api/twProperties.h:   Name                    Structure             Description Property Definitions twPropertyDef Describes the basic information for the Properties that will be available to ThingWorx and can be added to a client application. Property Values twProperty Associates the Property name with a value, timestamp, and quality. NOTE: The C SDK provides a number of Macros located in [C SDK HOME DIR]/src/api/twMacros.h. This guide will use these Macros while providing input on the use of pure function calls.   The Macro example below can be found in the main source file for the SimpleThingClient application and the accompanying helper file simple_thing.c. TW_PROPERTY("TempProperty", "Description for TempProperty", TW_NUMBER); TW_ADD_BOOLEAN_ASPECT("TempProperty", TW_ASPECT_ISREADONLY,TRUE); TW_ADD_BOOLEAN_ASPECT("TempProperty", TW_ASPECT_ISLOGGED,TRUE); NOTE: The list of aspect configurations can be seen in [C SDK HOME DIR]/src/api/twConstants.h. Property values can be set with defaults using the aspects setting. Setting a default value in the client will affect the Property in the ThingWorx platform after binding. It will not set a local value in the client application.   For the DeliveryTruckClient, we registered, read, and update Properties without using the Property definitions. Which method of using Properties is based on the application being built.   NOTE: Updating Properties in the ThingWorx Platform while the application is running, will update the values in the client application. To update the values in the platform to match, end the Property read section of your property handler function with a function to set the platform value.   The createTruckThing function for the deliveryTruck.c source code takes a truck name as a parameter and is used to register the Properties, functions, and handlers for each truck. The updateTruckThing function for the deliveryTruck.c source code takes a truck name as a parameter and is used to either initialize a struct for DeliveryTruck Properties, or simulate a truck stop Event, update Properties, then fire an Event for the ThingWorx platform. Connecting properties to be used on the platform is as easy as registering the property and optionally adding aspects. The following shows the properties that correlate to those in the DeliveryTruck entities in the Composer. To do this within the code, you would use the TW_PROPERTY macro as shown in the deliveryTruck.c. This macro must be proceeded by either TW_DECLARE_SHAPE, TW_DECLARE_TEMPLATE or TW_MAKE_THING because these macros declare variables used by the TW_PROPERTY that follow them. //TW_PROPERTY(propertyName,description,type) TW_PROPERTY(PROPERTY_NAME_DRIVER, NO_DESCRIPTION, TW_STRING); TW_PROPERTY(PROPERTY_NAME_DELIVERIES_LEFT, NO_DESCRIPTION, TW_NUMBER); TW_PROPERTY(PROPERTY_NAME_TOTAL_DELIVERIES, NO_DESCRIPTION, TW_NUMBER); TW_PROPERTY(PROPERTY_NAME_DELIVERIES_MADE, NO_DESCRIPTION, TW_NUMBER); TW_PROPERTY(PROPERTY_NAME_LOCATION, NO_DESCRIPTION, TW_LOCATION); TW_PROPERTY(PROPERTY_NAME_SPEED, NO_DESCRIPTION, "TW_NUMBER); Read Properties Reading Properties from a ThingWorx platform Thing or the returned Properties of a Service can be done using the TW_GET_PROPERTY macro. Examples of its use can be seen in all of the provided applications. An example can be seen below: int flow = TW_GET_PROPERTY(thingName, "TotalFlow").number; int pressue = TW_GET_PROPERTY(thingName, "Pressure").number; twLocation location = TW_GET_PROPERTY(thingName, "Location").location; int temperature = TW_GET_PROPERTY(thingName, "Temperature").number; Write Properties Writing Properties to a ThingWorx platform Thing from a variable storing is value uses a similarly named method. Using the TW_SET_PROPERTY macro will be able to send values to the platform. Examples of its use can be seen in all of the provided applications. An example is shown below: TW_SET_PROPERTY(thingName, "TotalFlow", TW_MAKE_NUMBER(rand() / (RAND_MAX / 10.0))); TW_SET_PROPERTY(thingName, "Pressure", TW_MAKE_NUMBER(18 + rand() / (RAND_MAX / 5.0))); TW_SET_PROPERTY(thingName, "Location", TW_MAKE_LOC(gpsroute[location_step].latitude,gpsroute[location_step].longitude,gpsroute[location_step].elevation)); This macro utilizes the twApi_PushSubscribedProperties function call to pushe all property updates to the server. This can be seen in the updateTruckThing function in deliveryTruck.c. Property Change Listeners Using the Observer pattern, you can take advantage of the Property change listener functionality. With this pattern, you create functions that will be notified when a value of a Property has been changed (whether on the server or locally by your program when the TW_SET_PROPERTY macro is called). Add a Property Change Listener In order to add a Property change listener, call the twExt_AddPropertyChangeListener function using the: Name of the Thing (entityName) Property this listener should watch Function that will be called when the property has changed void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } void test_simplePropertyChangeListener() { { TW_MAKE_THING("observedThing",TW_THING_TEMPLATE_GENERIC); TW_PROPERTY("TotalFlow", TW_NO_DESCRIPTION, TW_NUMBER); } twExt_AddPropertyChangeListener("observedThing",TW_OBSERVE_ALL_PROPERTIES,simplePropertyObserver); TW_SET_PROPERTY("observedThing","TotalFlow",TW_MAKE_NUMBER(50)); } NOTE: Setting the propertyName parameter to NULL or TW_OBSERVE_ALL_PROPERTIES, the function specified by the propertyChangeListenerFunction parameter will be used for ALL properties.   Remove a Property Change Listener In order to release the memory for your application when done with utilizing listeners for the Property, call the twExt_RemovePropertyChangeListener function. void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } twExt_RemovePropertyChangeListener(simplePropertyObserver);   Step 6: Data Shapes Data Shapes are an important part of creating/firing Events and also invoking Services. Define With Macros In order to define a Data Shape using a macro, use TW_MAKE_DATASHAPE.   NOTE: The macros are all defined in the twMacros.h header file.   TW_MAKE_DATASHAPE("SteamSensorReadingShape", TW_DS_ENTRY("ActivationTime", TW_NO_DESCRIPTION ,TW_DATETIME), TW_DS_ENTRY("SensorName", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Temperature", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("Pressure", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("FaultStatus", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("InletValve", TW_NO_DESCRIPTION ,TW_BOOLEAN), TW_DS_ENTRY("TemperatureLimit", TW_NO_DESCRIPTION ,TW_NUMBER), TW_DS_ENTRY("TotalFlow", TW_NO_DESCRIPTION ,TW_INTEGER) ); Define Without Macros In order to define a Data Shape without using a macro, use the twDataShape_CreateFromEntries function. In the example below, we are creating a Data Shape called SteamSensorReadings that has two numbers as Field Definitions. twDataShape * ds = twDataShape_Create(twDataShapeEntry_Create("a",NULL,TW_NUMBER)); twDataShape_AddEntry(ds, twDataShapeEntry_Create("b",NULL,TW_NUMBER)); /* Name the DataShape for the SteamSensorReadings service output */ twDataShape_SetName(ds, "SteamSensorReadings");   Step 7: Events and Services Events and Services provide useful functionality. Events are a good way to make a Service be asynchronous. You can call a Service, let it return, then your Entity can subscribe to your Event and not keep the original Service function waiting. Events are also a good way to allow the platform to respond to data when it arrives on the edge device without it having to poll the edge device for updates. Fire Events To fire an Event you first need to register the Event and load it with the necessary fields for the Data Shape of that Event using the twApi_RegisterEvent function. Afterwards, you would send a request to the ThingWorx server with the collected values using the twApi_FireEvent function. An example is as follows: twDataShape * ds = twDataShape_Create(twDataShapeEntry_Create("message", NULL,TW_STRING)); /* Event datashapes require a name */ twDataShape_SetName(ds, "SteamSensorFault"); /* Register the service */ twApi_RegisterEvent(TW_THING, thingName, "SteamSensorFault", "Steam sensor event", ds); …. struct { char FaultStatus; double Temperature; double TemperatureLimit; } properties; …. properties. TemperatureLimit = rand() + RAND_MAX/5.0; properties.Temperature = rand() + RAND_MAX/5.0; properties.FaultStatus = FALSE; if (properties.Temperature > properties.TemperatureLimit && properties.FaultStatus == FALSE) { twInfoTable * faultData = 0; char msg[140]; properties.FaultStatus = TRUE; sprintf(msg,"%s Temperature %2f exceeds threshold of %2f", thingName, properties.Temperature, properties.TemperatureLimit); faultData = twInfoTable_CreateFromString("message", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } Invoke Services In order to invoke a Service, you will use the twApi_InvokeService function. The full documentation for this function can be found in [C SDK HOME DIR]/src/api/twApi.h. Refer to the table below for additional information.   Parameter         Type                   Description entityType Input The type of Entity that the service belongs to. Enumeration values can be found in twDefinitions.h. entityName Input The name of the Entity that the service belongs to. serviceName Input The name of the Service to execute. params Input A pointer to an Info Table containing the parameters to be passed into the Service. The calling function will retain ownership of this pointer and is responsible for cleaning up the memory after the call is complete. result Input/Output A pointer to a twInfoTable pointer. In a successful request, this parameter will end up with a valid pointer to a twInfoTable that is the result of the Service invocation. The caller is responsible for deleting the returned primitive using twInfoTable_Delete. It is possible for the returned pointer to be NULL if an error occurred or no data is returned. timeout Input The time (in milliseconds) to wait for a response from the server. A value of -1 uses the DEFAULT_MESSAGE_TIMEOUT as defined in twDefaultSettings.h. forceConnect Input A Boolean value. If TRUE and the API is in the disconnected state of the duty cycle, the API will force a reconnect to send the request.   See below for an example in which the Copy service from the FileTransferSubsystem is called:   twDataShape * ds = NULL; twInfoTable * it = NULL; twInfoTableRow * row = NULL; twInfoTable * transferInfo = NULL; int res = 0; const char * sourceRepo = "SimpleThing_1"; const char * sourcePath = "tw/hotfolder/"; const char * sourceFile = "source.txt"; const char * targetRepo = "SystemRepository"; const char * targetPath = "/"; const char * targetFile = "source.txt"; uint32_t timeout = 60; char asynch = TRUE; char * tid = 0; /* Create an infotable out of the parameters */ ds = twDataShape_Create(twDataShapeEntry_Create("sourceRepo", NULL, TW_STRING)); res = twDataShape_AddEntry(ds, twDataShapeEntry_Create("sourcePath", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("sourceFile", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("targetRepo", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("targetPath", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("targetFile", NULL, TW_STRING)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("async", NULL, TW_BOOLEAN)); res |= twDataShape_AddEntry(ds, twDataShapeEntry_Create("timeout", NULL, TW_INTEGER)); it = twInfoTable_Create(ds); row = twInfoTableRow_Create(twPrimitive_CreateFromString(sourceRepo, TRUE)); res = twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(sourcePath, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(sourceFile, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(targetRepo, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(targetPath, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromString(targetFile, TRUE)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromBoolean(asynch)); res |= twInfoTableRow_AddEntry(row, twPrimitive_CreateFromInteger(timeout)); twInfoTable_AddRow(it,row); /* Make the service call */ res = twApi_InvokeService(TW_SUBSYSTEM, "FileTransferSubsystem", "Copy", it, &transferInfo, timeout ? (timeout * 2): -1, FALSE); twInfoTable_Delete(it); /* Grab the tid */ res = twInfoTable_GetString(transferInfo,"transferId",0, &tid); Bind Event Handling You may want to track exactly when your edge Entities are successfully bound to or unbound from the server. The reason for this is that only bound items should be interacting with the ThingWorx Platform and the ThingWorx Platform will never send any requests targeted at an Entity that is not bound. A simple example that only logs the bound Thing can be seen below. After creating this function, it will need to be registered using the twApi_RegisterBindEventCallback function before the connection is made. void BindEventHandler(char * entityName, char isBound, void * userdata) { if (isBound) TW_LOG(TW_FORCE,"BindEventHandler: Entity %s was Bound", entityName); else TW_LOG(TW_FORCE,"BindEventHandler: Entity %s was Unbound", entityName); } …. twApi_RegisterBindEventCallback(thingName, BindEventHandler, NULL); OnAuthenticated Event Handling You may also want to know exactly when your Edge device has successfully authenticated and made a connection to the ThingWorx platform. Like the bind Event handling, this function will need to be made and registered. To register this handler, use the twApi_RegisterOnAuthenticatedCallback function before the connection is made. This handler form can also be used to do a delay bind for all Things. void simplePropertyObserver(const char * entityName, const char * thingName,twPrimitive* newValue){ printf("My Value has changed\n"); } twExt_RemovePropertyChangeListener(simplePropertyObserver);   Click here to view Part 4 of this guide. 
View full tip
Applicable Releases: ThingWorx Navigate 1.6.0 to 1.7.0     Description:   How to use InfoEngine tasks to retrieve and take actions on Windchill data to use in Navigate services The following agenda is reviewed in the session: Use case introduction Create I*E task Create service Create Mashups Execute I*E Task       The concepts of this session are still valid for newer Navigate versions, but the session was recorded using old Composer
View full tip
We will host a live Expert Session: "5 Common Mistakes for Developing Scalable IoT Applications" on June 22nd, 11h00 EST.   Please find below the description of the expert session and the registration link.   Expert Session: 5 Common Mistakes for Developing Scalable IoT Applications Date and Time: June 22nd, 11h00 EST Duration: 1 hour Host: Tori Firewind, Mike Jasperson and Prachi Rath - Enterprise Deployment Center Registration Here: https://www.ptc.com/en/resources/iiot/webcast/5-common-dev-mistakes-for-scalable-iot-applications    Description: To build scalable applications, it’s necessary to identify the common mistakes made and ensure to avoid them at the early stages of development.   In this expert session, the PTC Enterprise Deployment Team will elaborate on why scalability is important and how one can avoid the common development pitfalls in IoT.    Existing Recorded sessions can be found on support portal using the keyword ‘Expert Sessions’. You can also suggest topics for upcoming sessions using this small form.   Here are some recorded sessions that might be of your interest. You can find recordings for the full library of webinars using the keyword ‘Expert Sessions’ in PTC support portal search Thingworx Active Active Clustering This session will cover the main aspects of the High Availability Clustering feature launched with the ThingWorx 9.0 release.   Recoding Link Upgrade to Thingworx 9 – How to Plan / Evaluate Impacts This session highlights the key points you should evaluate to properly plan your upgrade to Thingworx 9. Recording Link Top 5 items to check for Thingworx Performance Troubleshooting How to troubleshoot performance issues in a Thingworx Environment? Here we cover the top 5 investigation steps that will help you understand the source of your environment issues and allow better communication with PTC Technical Support     Recording Link
View full tip
Applicable Releases: ThingWorx Platform 7.0 to 8.5   Description:   Covers how to apply patch upgrades to ThingWorx installation, with the following agenda: How to read ThingWorx version Upgrading to a major/minor version of the platform Focus on upgrading to a patch version of the platform Upgrading extensions       Always check the patch release notes for additional information and specific steps
View full tip
Applicable Releases: ThingWorx Platform 8.3 to 8.5   Description:   Installation walkthrough of ThingWorx foundation using PostgreSQL, materializing some main steps that might be difficult to read in the installation guides       Reference installation guides for each version
View full tip
    Step 8: Tasks   If you are using the built-in Tasker to drive data collection or other types of repetitive or periodic activities, create a function for the task. Task functions are registered with the Tasker and then called at the rate specified after they are registered. The Tasker is a very simple, cooperative multitasker, so these functions should not take long to return and most certainly must not go into an infinite loop.   The signature for a task function is found in [C SDK HOME DIR]/src/utils/twTasker.h. The function is passed a DATETIME value with the current time and a void pointer that is passed into the Tasker when the task is registered. After creating this function, it will need to be registered using the twApi_CreateTask function after the connection is created. Below shows an example of creating this function, registering this function, and how this function can be used.   #define DATA_COLLECTION_RATE_MSEC 2000 void dataCollectionTask(DATETIME now, void * params) { /* TW_LOG(TW_TRACE,"dataCollectionTask: Executing"); */ properties.TotalFlow = rand()/(RAND_MAX/10.0); properties.Pressure = 18 + rand()/(RAND_MAX/5.0); properties.Location.latitude = properties.Location.latitude + ((double)(rand() - RAND_MAX))/RAND_MAX/5; properties.Location.longitude = properties.Location.longitude + ((double)(rand() - RAND_MAX))/RAND_MAX/5; properties.Temperature = 400 + rand()/(RAND_MAX/40); /* Check for a fault. Only do something if we haven't already */ if (properties.Temperature > properties.TemperatureLimit && properties.FaultStatus == FALSE) { twInfoTable * faultData = 0; char msg[140]; properties.FaultStatus = TRUE; properties.InletValve = TRUE; sprintf(msg,"%s Temperature %2f exceeds threshold of %2f", thingName, properties.Temperature, properties.TemperatureLimit); faultData = twInfoTable_CreateFromString("message", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } /* Update the properties on the server */ sendPropertyUpdate(); } … twApi_CreateTask(DATA_COLLECTION_RATE_MSEC, dataCollectionTask); … while(1) { char in = 0; #ifndef ENABLE_TASKER DATETIME now = twGetSystemTime(TRUE); twApi_TaskerFunction(now, NULL); twMessageHandler_msgHandlerTask(now, NULL); if (twTimeGreaterThan(now, nextDataCollectionTime)) { dataCollectionTask(now, NULL); nextDataCollectionTime = twAddMilliseconds(now, DATA_COLLECTION_RATE_MSEC); } #else in = getch(); if (in == 'q') break; else printf("\n"); #endif twSleepMsec(5); }      Step 9: File Transfer Example    To handle file transfers, a virtual directory is created in the SteamSensor1 entity and in the [C SDK HOME DIR]/examples/FileTransferExample application directory. The source code used for this example is found in [C SDK HOME DIR]/examples/FileTransferExample/src/main.c.   Inside of the [C SDK HOME DIR]/examples/FileTransferExample folder, create the folder structure shown below: /transfer/ /transfer/incoming/ /transfer/outgoing/ Inside of the /transfer/outgoing/ directory, create and open a file with the name outgoing.txt. Once the outgoing.txt document is open, add the following text, save, and close the file: Hello. This is a file coming from the client application. Navigate to the [C SDK HOME DIR]/examples/FileTransferExample/src/main.c code and update the lines below with the appropriate information for your IP, port, and the “admin_key” Application Key’s keyId value in the ThingWorx Composer: /* Server Details */ #define TW_HOST "127.0.0.1" #define TW_PORT 80 #define TW_APP_KEY "ce22e9e4-2834-419c-9656-ef9f844c784c" To support file transfers in your client application, you must use the twFileManager_AddVirtualDir function in order to create the virtual directories in the entity with such a capability. It will also define the directories available for file operations. A virtual directory maps a unique name to an absolute path of a directory in the file system. All subdirectories of the specified directory are exposed to the server. You can define multiple virtual directories. The directories do not need to be contiguous.   Staging Directory   As an optional, but recommended step, you should set the directory that the application should use for staging when performing file transfers. This can be seen in the line below and should be done before initializing the FileManager. The default directory of the FileManager is most likely owned by root and will require a change to either the location of the staging directory and the ownership of the staging directory, or running the application as a User with the correct permissions.   twcfg.file_xfer_staging_dir = "staging"; The example provided uses the TW_SHARE_DIRECTORY macro to create two virtual directories that will act as the root directories in the virtual file system of this application are added. The client is then started as follows with the necessary TW_ADD_FILE_TRANSFER_SHAPE function being called: TW_ADD_FILE_TRANSFER_SHAPE(); TW_SHARE_DIRECTORY("in", "/transfer/incoming/"); TW_SHARE_DIRECTORY("out", "/transfer/outgoing/"); The creations of the payloads used to create the remote directories on the platform have been moved to a helper function below to make the design cleaner: int setupSystemRepo(const char * remoteInPath, const char * remoteOutPath, const char * remoteFile); After our remote directories and files have been setup, it is time to perform the file transfers. Normally, this would mean invoking the Copy service for a Subsystem, but two functions have been created to make this process easier: int twFileManager_GetFile(const char * sourceRepo, const char * sourcePath, const char * sourceFile, const char * targetRepo, const char * targetPath, const char * targetFile, uint32_t timeout, char asynch, char ** tid) int twFileManager_SendFile(const char * sourceRepo, const char * sourcePath, const char * sourceFile, const char * targetRepo, const char * targetPath, const char * targetFile, uint32_t timeout, char asynch, char ** tid) The table below displays an example of the first set of parameters:    Parameter     Example                             Description sourceRepo SystemRepository The name of FileRepository or RemoteThing to transfer the file FROM. sourcePath outgoing The path specifying the location of the source file. sourceFile The name of the source file.   targetRepo SteamSensor1 The name of FileRepository or RemoteThing to transfer the file TO. targetPath incoming The path specifying the destination location of the file. targetFile incoming.txt The name of the file at the target. This name can differ from the sourceName. timeout 15,000 The amount of time (in seconds) to wait for a synchronous transfer to complete before cancelling the transfer. async false If false, the service call will block for timeout seconds or until the transfer completes. tid incoming0123 The unique TID associated with the file.   The C SDK also provides the ability to create a FileCallback function that the FileManager will call that function when any file transfer events occur. You can provide a wildcard filter so that only file transfer Events of files that match the filter call the callback function. In addition, callbacks can be set up as “one-shots” such that the callback is unregistered automatically after it is invoked the first time.   NOTE: An optional file transfer callback is registered in the code and provided. You will see the output from the function as files are sent and received.   After running this application, you will notice a new file in the transfer/incoming folder after refreshing. This is the file that we created in the ThingWorx Composer file system for the SystemRepository Entity and was able to copy from that location to our local project. We have also sent a file to the server’s SystemRepository. The BrowseFileSystem and GetFileListing services can be used to check for the folders and files created.   twFileManager_RegisterFileCallback(fileCallbackFunc, NULL, FALSE, NULL);     Step 10: Support Other Platforms   All Websocket errors indicate some general issue communicating with the ThingWorx platform. If you experience an issue connecting, refer to the table below for a list of websocket errors, their corresponding codes, and an explanation of the issue.    Code     Message                                                                      Troubleshooting 200 TW_UNKNOWN_WEBSOCKET_ERROR An unknown error occurred on the websocket. 201 TW_ERROR_INITIALIZING_WEBSOCKET An error occurred while initializing the websocket. Check your websocket configuration parameters for validity. 202 TW_TIMEOUT_INITIALIZING_WEBSOCKET A timeout occurred while initializing the websocket. Check the status of the connection to ThingWorx. 203 TW_WEBSOCKET_NOT_CONNECTED The websocket is not connected to ThingWorx. The requested operation cannot be performed. 204 TW_ERROR_PARSING_WEBSOCKET_DATA An error occurred while parsing websocket data. The parser could not break down the data from the websocket. 205 TW_ERROR_READING_FROM_WEBSOCKET An error occurred while reading data from the websocket. Retry the read operation. If necessary, resend the data. 206 TW_WEBSOCKET_FRAME_TOO_LARGE The SDK is attempting to send a websocket frame that is too large. The Maximum Frame Size is set when calling twAPI_Initialize and should always be set to the Message Chunk Size (twcfg.message_chunk_size). 207 TW_INVALID_WEBSOCKET_FRAME_TYPE The type of the frame coming in over the websocket is invalid. 208 TW_WEBSOCKET_MSG_TOO_LARGE The application is attempting to send a message that has been broken up in to chunks that are too large to fit in a frame. You should not see this error. 209 TW_ERROR_WRITING_TO_WEBSOCKET An error occurred while writing to the Web socket. 210 TW_INVALID_ACCEPT_KEY The Accept key sent earlier from ThingWorx is not valid.     Step 11: Next Steps   Congratulations! You've successfully completed the Low Level Device Connect Guide, and learned how to utilize the resources provided in the Edge SDK to create your own application.   The next guide in the Utilizing ThingWorx to Secure Your Aerospace and Defense Systems learning path is Tracking Activities and Statistics.    Learn More   We recommend the following resources to continue your learning experience:    Capability      Guide Build Design Your Data Model Build Implement Services, Events, and Subscriptions   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource       Link Community Developer Community Forum Support C Edge SDK Help Center      
View full tip
This video continues Module 6: Predictive Models & Model Validation of the ThingWorx Analytics Training videos. It covers some modeling techniques to help build better predictive models. It discusses the dangers of models that overfit data, and how to avoid overfitting. 
View full tip
Announcing: ThingWorx Solution Central 3.1.0 and its New API Written by: Tori Firewind of the IoT EDC   Solution Central 3.1.0 ThingWorx Solution Central (SC) is the solution management tool for ThingWorx and Digital Performance Management (DPM), the latest version of which (DPM 1.1) can now be deployed directly from the PTC Solutions menu of SC. Streamlining packaging strategies and ensuring efficient solution deployment can now be done for all kinds of ThingWorx solutions, even those with heavy customization. The new API allows for updated building blocks from within the PTC Solutions menu to be easily discovered and deployed right alongside custom solutions. Even the most advanced developers can now house their deployment management process within SC.   As discussed in a previous article, Solution Central forms a necessary part of a mature DevOps pipeline, usually as a set of services within Foundation which finalize and publish the solution to the Solution Central servers. The recommendation to utilize Solution Central from within Foundation remains a best practice for ThingWorx DevOps because the vast majority of solutions benefit from using the ThingWorx APIs, which scan and check for dependencies and proper XML formatting on each included entity.   Packaging and publishing the solution from within ThingWorx is the easiest and most straightforward way recommended by PTC, but it is now possible to publish to Solution Central using a standard API for those who need to publish from Jenkins or other build jobs. If there are legacy extensions, 3rd party tool dependencies, or other customizations within the ThingWorx application, then it may be beneficial to use this new API instead.   The new API also allows for editable extensions and entities within a published solution, though PTC still recommends avoiding this as a general practice. It is usually better for purposes of maintainability and ease of upgrades to just publish the solution again (with an incremented) version each time any changes are made.   How to Use the API Within Solution Central, a new menu option has been added to review the API, with information about the different types of requests and their parameters and responses. To access this within the Solution Central UI, open the help menu and navigate to “Public APIs” (see the image on the right). To see a sample response, select a request type and scroll down to the “Responses” section (shown below). Examples of error responses are also provided, and it’s important to ensure that whatever makes these requests can properly report or log any errors for troubleshooting and maintenance of the DevOps process.   The general steps for making use of this API are as follows: Create the solution resource with a POST Add some files to that solution with PUTs First, create the solution archive with the right Solution Identifiers; this should contain at least one project XML and all of the entities belonging to that ThingWorx project Next, compute MD5 using a tool like DigestUtils on the contents of the archive; this checksum is required for Solution Central Compute the SHA hash on the archive and save it; this will need to be provided along with the archive in the PUT requests Compute MD5 on the hash file also Finally, make the two PUT requests, one for the archive and one for its hash; for example cURL requests, see the Help Center Publish the solution using a PUT So, with a little more work it is now possible to make use of SC in a more custom DevOps process. It is now possible to build JSON or XML solutions using development tools outside of ThingWorx and still publish these customizations to Solution Central. The process of DevOps Management just became more versatile, and with the ease of deployment of DPM and other PTC building blocks as well, ThingWorx is now more accessible and easy to use than ever before.
View full tip
Suppose, if you have uninstalled ThingWorx Flow successfully with appropriate steps. And, tried re-installing which is failing with below error in the flow installation logs,      " FATAL: SystemCallError: windows_service[RabbitMQ] (orchestration::rabbitmq line 120) had an error: SystemCallError: The specified service does not exist as an installed service. - OpenService: The specified service does not exist as an installed service."     This is due to the registry problem. To resolve this, need to delete the registry key. Following steps are need to be performed:    Go to Start-> Search and Run 'regedit' as an Administrator Navigate to 'Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Ericsson' Delete Ericsson key and its sub key Restart your machine Install ThingWorx Flow again and it will be successful.   Here is the article link on this subject: https://www.ptc.com/en/support/article/CS328600     Thanks, Vibhuti Angne
View full tip
  Create an Engine Failure Prediction GUI to warn about customer issues.   GUIDE CONCEPT   This guide will use ThingWorx Foundation's Mashup Builder to create a Graphical User Interface (GUI) to display results from Analytics Manager comparisons of your analytical model to real-time data.   Following the steps in this guide, you will learn how to utilize Widgets and backend data to quickly visualize customer failure conditions.     YOU'LL LEARN HOW TO   Create a Mashup Add Widgets to represent different data Bring Backend Data into the Mashup Tie data to Widgets View Analytical Results in a convenient GUI   NOTE:  The estimated time to complete all parts of this guide is 30 minutes.     Step 1: Scenario   In this guide, we're finishing up with the 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. You've even put that analytical model into service to give near-immediate results from current engine-vibration readings.   The goal of this guide is to create a GUI to visualize those predicted "low grease" conditions to facilitate customer warnings.     GUI-creation to visualize analytical model deployment can be extremely helpful for the automative 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 visualize the results of an engine analytic model for a "smart, connected products" play.     Step 2: Create Mashup   Mashups are ThingWorx Foundation's method of creating Graphical User Interfaces (GUIs).   Mashups are created through the Mashup Builder interface.   Before you can use this drag-and-drop interface, you must first create a new Mashup.      1. In ThingWorx Foundation Composer, click Browse > Visualization > Mashups.      2. Click + New.        3. Leave the defaults and click OK.        4. In the Name field, type EFPG_Mashup.      5. If Project is not already set, search for and select PTCDefaultProject.        6. At the top, click Save.        7. At the top, click Design. You are now in the Mashup Builder interface, where you can drag-and-drop graphical elements (Widgets) to create your GUI.      8. At the top-left, click the Layout tab.        9. Change Positioning to Static. This removes any auto-positioning or dynamic-sizing from our Mashup, so that we can place and size Widgets manually.      10. At the top, click Save again.       Step 3: Add Widgets   We now want to add several Widgets to our Mashup by dragging-and-dropping them into the central Canvas area.   Return to the Widgets tab in the top-left.       2. In the Filter Widgets field, type label.        3. Drag-and-drop five (5) Label Widgets onto the central Canvas area.      4. Select the Label Widgets, go to the Properties in the bottom-left, and change the Label's LabelText to s1_fb1 through s1_fb5.         5. Filter Widgets for text field, and then drag-and-drop five (5) Text Field Widgets onto the central Canvas area.        6. Drag-and-drop two (2) more Label Widgets onto the central Canvas area.      7. Change their LabelText Properties to Result_low_grease and Result_low_grease_mo.        8. Drag-and-drop two (2) more Text Field Widgets onto the central Canvas area.        9. In the top-left Widget's tab, change Category to Legacy.      10. Drag-and-drop an Auto Refresh Widget onto the Canvas.        11. At the top, click Save.         Step 4: Add Data   Now that we have a rough set of Widgets in place to display Data in our Mashup, we need to bring in backend Data from Composer.      1. In the top-right, ensure the Data tab is active.      2. Click the green + button.        3. In the Entity Filter field, search for and select EdgeThing.      4. In the Services Filter field, type getprop.      5. Click the right-arrow beside GetProperties.      6. On the right, check Execute on Load.        7. In the bottom-right, click Done.      8. On the right, expand GetProperties.        9. At the top, click Save.       Step 5: Bind Data   Now that backend Data is accessible inside Mashup Builder, we need to bind it to the various Widgets.   Drag-and-drop Data > Things_EdgeThing > GetProperties > s1_fb1 to the top-left Text Field under the s1_fb1 Label Widget.           2. On the Select Binding Target pop-up, click Text.         3. Repeat for s1_fb2 through s1_fb5 on the 2nd-5th Text Field Widgets.       4. Drag-and-drop Data > Things_EdgeThing > GetProperties > Result_low_grease to the top-right Text Field under the Result_low_grease Label Widget, and select Text on the Binding pop-up.       5. Repeat for Result_low_grease_mo on the Text Field just below.       6. Click the Auto Refresh Widget to select it.       7. In the bottom-left Properties, set RefreshInterval to 1.         8. With the Auto Refresh Widget still selected, click the top-left corner to reveal a drop-down.       9. Drag-and-drop the Refresh Event onto Things_EdgeThing > GetProperties.       10. On the right, click the GetProperties Mashup Data Service to reveal all of its interactions in the bottom-center Connections window.              11. At the top, click Save.       Step 6: View Mashup   In the last guide, we disabled the Analysis Event after confirming that appropriate analytical jobs were being created and completed whenever new data from our EMS Engine Simulator entered Foundation.   We now need to re-enable that Event so that we can see the results in our Mashup.       1. Return to Analytics > Analytics Manager > Analysis Events.       2. Select the Event, and click Enable.   View Analytical Results   With the Analysis Event enabled, we can now view our Mashup to watch engine-failure-predictions be displayed in real time.       1. Return to EFPG_Mashup.       2. At the top, click View Mashup.       3. Wait and notice how the refresh occurs every second, including both true and false analytics results for the "low grease" condition.      4. When you are satisfied that you have observed enough true/false results, return to Analytics > Analytics Manager > Analysis Events and Disable the event.   Through this Learning Path, you have done all of the following:   Connect a remote device to Foundation using the Edge MicroServer (EMS) Fed relevant product-data to the Foundation backend Formatted and exported that data in a manner which Analytics could understand Imported that data and used it to build an Analytics Model of your remote device Started feeding real-time remote data into the model to achieve immediate failure-prediction results Create a GUI to easily visualize those results   You now have a completed Minimum Viable Product (MVP) for a Service Play with MotorCo's new engines.   These new engines may have a known-failure condition, but (because you've instrumented those engines to provide constant data) you can monitor them and predict failures before they actually happen.   This could easily be an up-sell scenario for MotorCo's customers. They could simply purchase the engine. Or they could both purchase the engine and enroll in a service contract where you notified them of impending issues.   What was originally a single-point source of income is now ongoing        Step 7: Next Steps   Congratulations. You've completed the Engine Failure-Prediction GUI guide. In this guide you learned how to:   Create a Mashup Add Widgets to represent different data Bring Backend Data into the Mashup Tie data to Widgets View Analytical Results in a convenient GUI   The next guide in the Vehicle Predictive Pre-Failure Detection with ThingWorx Platform learning path is Enhanced Engine Failure Visualization.   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
Announcements