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

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

IoT Tips

Sort by:
Applicable Releases: ThingWorx Platform 7.0 to 8.5   Description:   Covers the main topics that need to be considered when evaluating or designing a scalability strategy for the environment and applications The agenda contains the following topics: Introduction Connection Server Federation High Availability       Some of the databases mentioned in the presentation are no longer supported Please refer to the compatibility matrix to check supported databases Related Articles How to configure a Federate architecture Is high availability supported in ThingWorx  
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
This video continues Module 6: Predictive Models & Model Validation of the ThingWorx Analytics Training videos. It then begins to describe some of the performance metrics used to evaluate predictive models. 
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
    Step 5: Tie Data to Widgets   The Mashup now has access to the backend data via get/set Data Services.   In this step, you will tie these Data Services to the Checkbox Widgets to pull and push information.   Click the Data tab in the upper right   Under GetProperties, click and drag the arrow next to Channel2_myPLC_Coil2 onto the Left Checkbox. On the Select Binding Target pop-up, click State.   Click the Data tab again Drag Channel2_myPLC_Coil3 onto the right Checkbox. On the Select Binding Target pop-up, click State.   Enable Automatic Updates   The GetProperties Mashup Data Service will now propagate the State of Coil2 and Coil3 from the PLC onto these Checkbox Widgets.   The GetProperties Service will be called automatically when the Mashup loads, so the Checkboxes states will be accurate on initial viewing.   However, the backend data state changes, you will need the GetProperties Service to be automatically called again to update the Checkbox Widgets.   Fortunately, it is simple to trigger this behavior.   Click the Data tab Click GetProperties to select it.   On the right of the Mashup Builder, Click the Data Properties tab     Click the Automatically Update Values checkbox   Allow Bidirectional Sets   You also want to enable bi-directional communication, not only displaying the current value of the PLC, but also setting it via the Mashup GUI.   The SetProperties Mashup Data Service can accomplish this.   Click the Right Checkbox to select it.   Click the Checkbox Widget's top-left drop-down menu to expose the available options.   Drag State over the Data tab to expand it. Drop onto SetProperties > Channel2_myPLC_Coil3.   Click the right Checkbox drop-down menu again.   Click Configure Bindings.   Click the down arrow to the right of Changed.   Click Add Trigger Service. Click the Data tab. Select the setProperties check box.   Click Next to close the Trigger Services window. Click Done to close the Configure Bindings pop-up. At the top, click Save.     Step 6: View Mashup    Your Mashup is now complete with two Checkbox Widgets and connections from those Widgets to the backend data.   The left Checkbox represents Coil2, and will change its state depending on whether you have touched the lead to the appropriate input on the PLC.   The right Checkbox represents Coil3, and will display the current status as well as allow you to set the status of Output Coil 3 via checking or unchecking the box.   At the top, click View Mashup to display your web application. You may need to set your browser to allow pop-ups.     Select the right checkbox. Note how the PLC's Output Coil 3 will immediately turn on.   Touch the lead to the PLC's I-02, i.e. Input 2. The left checkbox will indicate the status of Input 2 within a couple of seconds. Step 7: Troubleshooting   If the connection to the PLC stops working and there is a Thumbs Down icon next to your properties, the ThingWorx Kepware Server trial edition drivers are not connected to your PLC. The trial edition stops running after 2 hours and must be stopped and restarted. Right-click on ThingWorx Kepware Server icon in system tray.     Click Stop Runtime service. Wait a minute for the process to stop, then click Start Runtime service. If Connected Components Workbench does not connect to PLC, check the IP address of the PLC using RS Linx Classic software that was installed as part of Connected Components Workbench. RS Linx Classic is located Start > All Programs > Rockwell Software > RSLinx > RSLinx Classic Click AB_ETHIP-1, Ethernet and IP addresses of connected PLCs will be discovered NOTE: A changed PLC IP Address (typically seen through Connected Components Workbench) will require an IP Address change in ThingWorx Kepware Server settings.     Step 8: Next Steps   Congratulations! You've successfully completed the Visualize an Allen-Bradley PLC guide.   In addition, assuming you have been utilizing this guide as part of the Rockwell Automation Learning Path, this represents the end of your journey.   You've learned how to:   Create a Mashup Add Widgets Access backend data via Mashup Data Services Tie data to Widgets Create a simple web application that monitors and controls a PLC   This is the last guide in the Using an Allen-Bradley PLC with ThingWorx learning path. Learn More   Capability Resource Analyze Monitor an SMT Assembly Line Additional Resources   For additional information on ThingWorx Kepware Server:   Resource Link Documentation Kepware documentation Support Kepware Support site
View full tip
  Use the Edge MicroServer (EMS) to simulate an engine with vibration sensors.   GUIDE CONCEPT   The Edge MicroServer (EMS) facilitates connectivity from Edge devices to ThingWorx Foundation.   It’s often easier, though, to start development with simulated Edge values rather than hooking up sensors.   This guide will show you how to simulate vibration values of an engine using the EMS.     YOU'LL LEARN HOW TO   Modify an EMS Template Provision Thing Properties and Values from an EMS rather than Foundation Send information from an EMS to Foundation Store large amounts of data in an InfoTable Property Create a simulator for testing   NOTE:  The estimated time to complete all parts of this guide is 30 minutes.     Step 1: Scenario   MotorCo manufactures, sells, and services commercial motors.   Recently, MotorCo has been developing a new motor, and they already have a working prototype.   However, they’ve noticed that the motor has a chance to FAIL CATASTROPHICALLY if it’s not properly serviced to replace lost grease on a key moving part.     In order to prevent this type of failure in the field, MotorCo has decided to instrument their motors with sensors which record vibration.   The hope is that these sensors can detect certain vibrations which indicate required maintenance before a failure occurs.   In this guide, you’ll begin this monitoring process by using ThingWorx Foundation to monitor and record vibration data from the prototype motor. In particular, you will learn how to provision Thing Properties and Values from an EMS, as well as how to permanently store these values for analysis in an Info Table Property.   These types of modifications to an EMS can be extremely helpful for the automotive segment in particular. For instance, each car that comes off the factory line could have custom, auto-generated EMS scripting that would dynamically create Foundation information for each car in the fleet. This could be a massive time-savings versus manually generating Thing Properties directly within Foundation.   Because the motor is still in the process of being instrumented with sensors, you’ll get all the functionality in-place beforehand by constructing a motor simulator using the Edge MicroServer (EMS).     Step 2: Modify config.lua   In the previous Use the Edge MicroServer (EMS) to Connect to ThingWorx  guide, you installed the EMS on a Windows PC, configured it to talk to ThingWorx Foundation, and then created an EdgeThing on Foundation to complete the connectivity.   This guide assumes that you have already completed that Windows EMS guide and have an active EMS connection to the EdgeThing.   Perform the following steps to modify this connection to increase the task rate of the EMS, which we'll use in the following steps to update Properties more quickly.   On your Windows PC, select the Windows PowerShell window where the luaScriptResource.exe program is running.   Type Ctrl-C to close the luaScriptResource.exe operation, i.e. hold the Control key and hit the C key.   Minimize the luaScriptResource.exe PowerShell window, and activate the wsemse.exe PowerShell window.   Type Ctrl-C to close the wsems.exe operation.   Return to Foundation, and note that EdgeThing is not connected.   Navigate to the C:\CDEMO_EMSE\etc directory.   Open config.lua in your prefered text-editor.   Change scanRate to 1000. Add the following line below the scanRate line: taskRate = 1000,   The final code of config.lua should be the following Note that the EMS may have slightly modified your config.lua file, such as adding a data_security_key line. Leave these EMS-generated modifications alone. scripts.log_level = "WARN" scripts.script_resource_ssl = false scripts.script_resource_authenticate = false scripts.EdgeThing = { file = "thing.lua", template = "YourEdgeThingTemplate", scanRate = 1000, taskRate = 1000, sw_update_dir = "C:\\CDEMO_EMS\\updates" } Save the config.lua file.     Click here to view Part 2 of this guide.
View full tip
    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
  Setup user interfaces and ways to track events   GUIDE CONCEPT   Being able to view your logs is an important part of knowing what is happening in your system. You can't keep things secure if you don't know who is doing what.   These concepts and steps will allow you to focus on development of your application while still allowing the ability to utilize the power of ThingWorx!   We will teach you how to access the system in a way you might not have done much of before.     You'll learn how to   How to design and implement meaningful user interfaces View different logs and search for data NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 30 minutes   Step 1: Example and Strategy   If you’d like to skip ahead, download the completed example of the Aerospace and Defense learning path attached: AerospaceEntitiesGuide1.zip. Import the .twx files included.   In an ever-changing world, you are going to need to protect everything that is considered private. In order to do this, you need to be able to track every bit of what is happening in your system. ThingWorx does not provide an out of the box method to log when users open a Mashup window. What if this Mashup contains secure documents? Well, we can work with you on getting that logged and tracked.   Let us start working on securing our system by adding some Mashups that are simple, but we will add complexity around them. Before designing our Mashups, we will set permissions and go from there.      Step 2: Setting Mashup Permissions We will create a Mashup, but the focus will be the security of the Mashup, not the Design and UI itself. Follow the steps below to get started. In the ThingWorx Composer, click the + New at the top of the screen. Select Mashup  in the dropdown. 3, Select Responsive for the layout option. 4. Click Ok.   5. Enter a name for the Mashup Template, such as SecureMashupExample.   6. Click Save then click the Permissions tab. 7. On the Visibility tab, in the Search Organization text box, begin typing and select PTCDefenseDepartment. This allows anyone in the organization to be able to access this Mashup.    8. On the Runtime tab, in the Search Users and User Groups text box, begin typing and select Agency.IT.  9. Set all permissions to Allow (check). This allows a User Group to run services during Runtime of your application. Keep in mind, this gives permissions to all parts of the Mashup (Events, Subscriptions, Services, Parameters). 10. If you would like to be more specific, in the Search Properties, Services, or Events text box, select a service, ie GetHomeMashup. In the text box that appears below for Users and User Groups, select Agency.HumanResources.  11. On the Design Time tab, the Search Users and User Groups text box, begin typing and select Agency.IT.  12. In the Search Users and User Groups text box, begin typing and select Agency.HumanResource. 13. For Agency.IT, set the permissions to allow Read, Update, and Delete. For the Agency.HumanResource User Groups allow Read and deny Update and Delete.   You have just begun the process to securing the application from users looking to view specific secure pages. Next, let's create a simple page and show how we can log who accesses specific pages.      Step 3: Designing Tracked Mashups We will be creating a simple Mashup with the focus of showing how to add logging to a Mashup. Let's start by opening up the Mashup we just created.   Open the SecureMashupExample Mashup and click on the Design tab. Click the Layout panel in the top left and add a Bottom Container. In the Widgets panel, drag and drop a Blog Widget to the top container.   Drag and drop a Web Frame Widget to the bottom container.   Select the Blog Widget in the top container. In the Properties panel, update the Blog property to any existing or new Blog entity (there is a Blog in the provided download).    Select the Web Frame Widget in the bottom container. In the Properties panel, update the URL field to a website you trust. In this case, I'll be using https://www.ptc.com/.   Click Save and View Mashup.   When accessing this Mashup, nothing is logged. We'll be changing that in the next steps with a service that will be called and log who is using the Mashup.   In the ThingWorx Composer, click the + New at the top of the screen.   Select Thing in the dropdown.   In the name field, enter SecureServices and select GenerticThing as the Base Thing Template. Click Save and go to the Services and Alerts tab. Click the New button. Enter LogMashupAccess as the Service name.   Click the Input section and add a required String parameter named MashupName. Click Done and Add.   Add a second String parameter named Username that is required. Click Done.   Enter the below lines of code into the canvas. It will be a simple log statement for tracking. We can add a lot more to this method if we liked. logger.trace(MashupName  +  " accessed by " + Username); Click the green Save and Continue button to save your work.   Add Log Service to Mashup   We'll now need to call this logging service to see whenever a user has logged into our secure page. Of course, this is a simplified example and much more could be done here. Go back to the SecureMashupExample Mashup. In the Data panel, click the + button to add a service. Search for our new SecureServices Entity, then add the LogMashupAccess service. Ensure the Execute on Load checkbox is checked.  Click Done. Select the LogMashupAccess service. In the Data Properties panel in the lower right. In the MashupName text box, enter SecureMashupExample.   Select the User panel in the top right. Drag and drop the name field to the Username parameter. 9. Click Save.   You now have a Mashup that will log the UI being opened and the user accessing that UI whenever it is opened. Click View Mashup and go to the ScriptLog in order to test. You filter will need to be set to All or at least Trace to see the log statement.   In the next section we'll see how we can test this and do a bit more.     Step 4: Viewing and Filtering Logs   Data logging and filtering is one of your most powerful tools not only in the ThingWorx environment, but in developing solutions. The next section of this learning path will go in depth about what each of these items in a Monitoring screen does. It will also cover tricks to help your search. For now, let's look at how we can view logs and filter them to find what we need.   No.  Item Usage  1  Search Bar  Search the log for key words and phrases. 2  Filter Button  Provides a list of options to fine tune your search. This menu is very powerful. 3  Log Configurations  Select what level of logging you'd like to see. 4  Date Range  A date range filter to help limit or set your specific date options. 5  Max Row Count  The max number of rows to search for and return. The search will continue until this number is met or your other search filters have been met (ie, date range). 6   Apply/Reset Buttons  Apply the changes for your date range and max account or reset these values to their defaults. 7  Refresh/Auto Refresh Buttons Allow the log to continue based on your filters (if any) without you having to refresh. You can also refresh it on your own. 8  Log Header and List  The logs that were found based on your filters or settings. 9  Selected Log View  After selecting a log item in the list, it will be shown here.   The are some tricks to finding what you want and need faster. We dive into that in the next guide in this learning path.     Step 5: Next Steps Congratulations! You've successfully completed the Tracking Activities and Stats guide, and learned how to use the ThingWorx Platform to help track what is happening in your application.   If you wish to return to the learning path, click Utilizing ThingWorx to Secure Your Aerospace and Defense Systems   Learn More We recommend the following resources to continue your learning experience: Capability Guide Build Design Your Data Model Manage Data Model Implementation Guide 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 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: Map Data   Now that the event is created, we need to map the Properties of EdgeThing to the fields required to invoke an Analysis Job.   We'll start with the Inputs.   Select the previously-created Event, and click Map Data....   Click Inputs Mapping.   In Source Type, select Thing. In Source, search for and select EdgeThing.   On the left, scroll down and select s1_fb1. Note that you do NOT want the s1_fb1 that is part of the InfoTable Property, because the Info Table Property only stores recorded data, not live data. On the right, select _s1_fb1, the first frequency band required for the Model to make a prediction.   Click the Map button in the center.   Repeat this mapping process for for s1_fb2 through s1_fb5.   Map causalTechnique to causalTechnique in the same manner. This is a String Property in EdgeThing with a Default Value of "FULL_RANGE". Map goalField to goalField in the same manner. This is a String Property in EdgeThing with a Default Value of "low_grease".   Map Results   Now that the Inputs are mapped, we also want to map the Results.   Click Results Mapping on the left.   Map _low_grease to Result_low_grease. Map _low_grease_mo to Result_low_grease_mo.   Click Close to close the mapping pop-up.   Enable Event   Now that we've done the mapping from Foundation to Analytics, let's Enable the Analysis Event so that it can automatically generate and process Analysis Jobs. Select the mapped Analysis Event. Select Enable.   Now that you have enabled the Analysis Event, the new data will be submitted to Analytics Manager whenever EdgeThing's s1_fb1 Property changes.   An Analysis Job will automatically run, with a predictive score sent back and stored in EdgeThing's Result_low_grease (Boolean) and Result_low_grease_mo (Number) Properties.     Step 7: Check Jobs   In this step, we'll confirm that the automatic analysis of information coming from remote devices is operational.   On the ThingWorx Composer Analytics tab, click Analytics Manager > Analysis Jobs.   Uncheck Filter Completed Jobs.   Select a Job and click View.... Click Results.   NOTE: You will see true or false, corresponding to either a low grease or no low grease condition. Using this technology, you could create a paid customer service, where you offered to monitor remote engines, in return for automatically shutting them down before they experience catastrophic engine failure.   For that example implementation, you would utilize the EdgeThing.Result_low_grease BOOLEAN Property to trigger other actions.   For instance, you could create an Alert Event which would be triggered on a true reading.   You could then have a Subscription which paid attention to that Alert Event, and performed an action, such as sending an automatic shutdown command to the engine when it was experiencing a likely low grease event.   NOTE: We recommend that you return to the ThingWorx Composer Analytics > Analytics Manager > Analysis Events tab and Disable the Event prior to continuing. Since the simulator generates an Event every ~1 seconds, this can create a large number of Events, which can fill up your log.       Step 8: Next Steps   Congratulations. You've completed the Manage an Engine Analytical Model guide. In this guide you learned how to:   Define an Analysis Provider that uses the built-in Analytics Server Connector Publish a Model from Analytics Builder to Manager Create an Analysis Event which takes data from ThingWorx Foundation and decides whether or not a failure is likely   The next guide in the Vehicle Predictive Pre-Failure Detection with ThingWorx Platform learning path is Engine Failure-Prediction GUI.   Learn More   We recommend the following resources to continue your learning experience:    Capability     Guide Build Implement Services, Events, and Subscriptions Guide   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource              Link Community Developer Community Forum Support Analytics Manager Help Center      
View full tip
  Step 3: Creating Machine Processes   Having data and properties without moving parts would be useless. We already setup services on how to perform an inspection in the last guide. This time around, let's form processes to create our products and generate any alerts whenever we've finished production. We won't show too much into our recipe (it's a family secret), but we will highlight some concepts to help with making our machine process smoother. We won't go into creating an SMT line. For a complete guide on how to create such an application you can view our Monitor an SMT Assembly Line guide.   Events and Subscriptions   Let's create events for the cook time being done and a subscriptions on how to handle these scenarios.   Open the Fizos.BrautsMachine.ThingTemplate template and go to the Events tab. Click the + Add button and create the below alerts. Name Data Shape Description CookCompleted AlertEvent This alert is fired when the machine has completed a batch of our product TemperatureReached AlertEvent This alert is fired when the machine has reached the desired temperature.   3. Save these changes and replicate them with the Fizos.SausageMachine.ThingTemplate template. We now have alerts for the machines (alerts on properties and custom alerts). We can create subscriptions on the individual machines that will later inherit these alerts. One way to have a standard amongst these machines is to create a service in the template that will be called from subscriptions.   Let's create the simple services from now, and later, we will call these services from subscriptions. We will also use Schedules initiate the overall process. This can be a daily process, a timed process, or a process based on alerts and subscriptions. To keep this guide simple, we'll make this a process that runs every 3 hours. Create the below services in each of the Fizos.BrautsMachine.ThingTemplate and Fizos.SausageMachine.ThingTemplate templates:     Name InputReturn Type Override Async Description StartCookingProcess N/A Nothing Yes Yes Start overall product cooking process.Triggedby schedule. StartCookingIngredients N/A Nothing Yes Yes Start cooking the ingredients for the product.Triggedby subscription.   Add the following code for the StartCookingProcess service: // Mix our family secret recipe // Add in meats // Add heat me.TemperatureReached({ aackTimestamp: new Date(), alertType: "Completed", ackBy: "CookUser", ack: true, name: "TemperatureAlert", sourceProperty: "Service", description: "Optimal cooking temperature reached", message: "The desired cooking temperature has been reached. Begin next process.", priority: 1 }); // Perform top secret cooking techniques   2. Add the following code for the StartCookingIngredients service: // Temperature has already been reached if(true) { // IF COOK COMPLETED me.CookCompleted({ ackTimestamp: new Date(), alertType: "Information", ackBy: "CookUser", ack: true, name: "CookingAlert", sourceProperty: "Service", description: "Cooking process has completed", message: "The cooking time has completed. Move to next machine.", priority: 1 }); } else { //ELSE IF COOKING FAILED OR HALTED me.CookCompleted({ ackTimestamp: new Date(), alertType: "Exception", ackBy: "CookUser", ack: true, name: "CookingAlert", sourceProperty: "Service", description: "Cooking process has failed", message: "The cooking process has stopped. See logs for failure cause.", priority: 1 }); }   Let's keep in mind, these services will be triggered by by a schedule or a subscription to an alert. There will be no manual processed performed here. We also allowed for these services to be overridden, in order to allow more customization for machines that might need to be treated differently. These services are also not on the main machine templates, which allows us to create templates for machines that might have a different role in the process, ie, packaging or freeze drying.       Step 4: Automating Processes   Let's create the schedule that will start the cooking process. In the ThingWorx Composer, click the + New in the top left of the screen.   Select Schedules in the dropdown.   3. Name the new Schedule Fizos.MachineCooking.Schedule and set the Project (ie, PTCDefaultProject). 4. For the Run As User field, select the Fizos.Machine.User that was provided in the download. 5. Click Save and your entity should match the below configuration.     6. For the Schedule field, set it to 0 0 0/3 * * ?. This will run the process every 3 hours. 7. Switch to the Subscriptions tab and add a new subscription. 8. Name this new subscription StartCooking and select ScheduledEvent as the event input.   9. Add the following code to the source section:   var index = 0; var brauts = Resources["SearchFunctions"].SearchThingsByTemplate({ thingTemplate: "Fizos.BrautsMachine.ThingTemplate" }); var sausage = Resources["SearchFunctions"].SearchThingsByTemplate({ thingTemplate: "Fizos.SausageMachine.ThingTemplate" }); for(index = 0; index < brauts.rows.length; index++) { brauts.StartCookingProcess(); } for(index = 0; index < brauts.rows.length; index++) { sausage.StartCookingProcess(); } // This will begin the process to start each machines cooking process. // The process itself will then be ran by alerts, subscriptions, and services   So far the process will go as the following: A scheduler will search for all Things that inherit from the Fizos.BrautsMachine.ThingTemplate and Fizos.SausageMachine.ThingTemplate templates. Each list of these entities will have it's StartCookingProcess service called. When a temperature value is reached inside of the StartCookingProcess service, the TemperatureReached alert will be triggered. A subscription waiting for this event at the Thing level (which we create in the next section), will call the StartCookingIngredients service. This StartCookingIngredients service will finish the cooking part of the process and trigger a CookCompleted alert with a status update. A subscription waiting for this event at the Thing level (which we create in the next section), can call for another machine to take over the process.   We now have our moving parts. Let's create some examples to see how it can unfold.       Step 5: Handling Cooking Machines   We have many of our main features compeleted. Now we need to handle situations where our machine status needs to be a part of how we handle the cooking process. While much of this work can be handled in a remote process using one of our SDKs or extensions, our events and subscriptions can be a great method to do this also.   Creating Cooking Entities   In the ThingWorx Composer, click the + New in the top left of the screen.   Select Thing in the dropdown.   Set the Project (ie, PTCDefaultProject) and in the name field, enter Fizos.BrautsMachine.M02X35. In the Base Thing Template field, enter Fizos.BrautsMachine.ThingTemplate. Click Save.   6. In the ThingWorx Composer, click the + New in the top left of the screen.     7. Select Thing in the dropdown.     8. In the name field, enter Fizos.SausageMachine.KGYX20. 9. In the Base Thing Template field, enter Fizos.SausageMachine.ThingTemplate. 10, Click Save.     Creating Cooking Subscriptions   These steps will need to be in both of the entities we just created.   Switch to the Subscriptions tab and add a new subscription. Name this new subscription TemperatureReady and select TemperatureReached as the event input.   3. Add the following code to the source section: //The temperature is high enough. Start cooking me.StartCookingIngredients();   You now have a system (when enabled) will run every three hours. It will start our secret cooking process (that can be added in the service or created remotely).   To make things more fun. Add some logging or fun code to see how this works step by step.   To make things more realistic to a real world scenario, add subscriptions for our property alerts on the status or state properties.       Step 6: Next Steps   Congratulations! You've successfully completed the Factory Line Automation guide. In this guide, you learned how to:   Create automated machine processes Use services, alerts, and subscriptions to handle processes without human interaction Integrating complex logic with straight forward step by step systems   The next guide in the Complex and Automatic Food and Beverage Systems learning path is Automated Distribution and Logistics.    Learn More   We recommend the following resources to continue your learning experience:    Capability     Guide Build ThingWorx Solutions in Food Industry Build Design Your Data Model Build Implement Services, Events, and Subscriptions   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource       Link Community Developer Community Forum  
View full tip
    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 7: Delivery Truck Model    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 DeliveryTruckThing class extends the VirtualThing class and based on the DeliveryTruck Entities in the Composer. After extending VirtualThing, there are a number of steps necessary to get going. For the DeliveryTruckThing 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 DeliveryTruckThing takes in the 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 DeliveryTruckThing(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 @SuppressWarnings("serial") @ThingworxPropertyDefinitions(properties = { @ThingworxPropertyDefinition(name="Driver", description="The name of the driver", baseType="STRING", aspects={"isReadOnly:false"}), @ThingworxPropertyDefinition(name="DeliveriesLeft", description="The number of deliveries left", baseType="NUMBER", aspects={"isReadOnly:false"}), @ThingworxPropertyDefinition(name="Speed", description="The speed of the truck", baseType="NUMBER", aspects={"isReadOnly:false"}), @ThingworxPropertyDefinition(name="Location", description="The location of the truck", baseType="LOCATION", aspects={"isReadOnly:false"}), @ThingworxPropertyDefinition(name="TotalDeliveries", description="The number of deliveries", baseType="NUMBER", aspects={"isReadOnly:false"}), @ThingworxPropertyDefinition(name="DeliveriesMade", description="The number of deliveries made", baseType="NUMBER", 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 delivery truck properties using our getter methods:   //Get the current values from the ThingWorx Composer deliveriesMade = getDeliveriesMade(); deliveriesLeft = getDeliveriesLeft(); totalDeliveries = getTotalDeliveries(); driver = getDriver(); speed = getSpeed(); 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 DeliveryStop event that is in the DeliveryTruck instances.   With Annotation @ThingworxEventDefinitions(events = { @ThingworxEventDefinition(name="DeliveryStop", description="The event of a delivery truck stopping to deliver a package.", dataShape="DeliveryTruckShape", 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="GetTruckReadings", description="Get Truck Readings") @ThingworxServiceResult(name=CommonPropertyNames.PROP_RESULT, description="Result", baseType="INFOTABLE", aspects={"dataShape:DeliveryTruckShape"})   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 DeliveryTruckThing.java as shown below:   // Data Shape definition that is used by the delivery stop event // The event only has one field, the message FieldDefinitionCollection fields = new FieldDefinitionCollection(); fields.addFieldDefinition(new FieldDefinition(ACTIV_TIME_FIELD, BaseTypes.DATETIME)); fields.addFieldDefinition(new FieldDefinition(DRIVER_NAME_FIELD, BaseTypes.STRING)); fields.addFieldDefinition(new FieldDefinition(TRUCK_NAME_FIELD, BaseTypes.BOOLEAN)); fields.addFieldDefinition(new FieldDefinition(TOTAL_DELIVERIES_FIELD, BaseTypes.NUMBER)); fields.addFieldDefinition(new FieldDefinition(REMAIN_DELIVERIES_FIELD, BaseTypes.NUMBER)); fields.addFieldDefinition(new FieldDefinition(LOCATION_FIELD, BaseTypes.LOCATION)); defineDataShapeDefinition("DeliveryTruckShape", 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 DeliveryTruckClient 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 DeliveryTruckThing.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, 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); }     Step 8: Services and Events   Events and Services can be very useful. Events are a good way to make a Service be asynchronous. You’re able to call a Service, let it return and 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. The DeliveryTruck Entities in the Composer contains a remote Event. You can find a remote Service within the SimpleThing_1 entity.   Fire Event To fire an Event, create a ValueCollection instance, and load it with the necessary fields for the Data Shape of that Event. Then, send the client the request to fire the Event with the collected values, the Event, and information to find the Entity the Event belongs to as shown below in DeliveryTruckThing.java:   // Set the event information of the defined data shape for a truck stop event ValueCollection payload = new ValueCollection(); // Set values to the fields payload.put(LOCATION_FIELD, new LocationPrimitive(location)); payload.put(REMAIN_DELIVERIES_FIELD, new NumberPrimitive(deliveriesLeft)); payload.put(ACTIV_TIME_FIELD, new DatetimePrimitive(DateTime.now())); payload.put(TOTAL_DELIVERIES_FIELD, new NumberPrimitive(totalDeliveries)); payload.put(DRIVER_NAME_FIELD, new StringPrimitive(driver)); payload.put(TRUCK_NAME_FIELD, new StringPrimitive(super.getBindingName())); // This will trigger the 'DeliveryStop' of a remote thing // on the platform. super.queueEvent("DeliveryStop", new DateTime(), payload);   Execute Service   To execute a Service, you must create a ValueCollection instance, and load it with the necessary parameters of the Service. The ValueCollection is created only when Services and Events are not defined by annotations. Afterwards, you would send the client the request to execute the Service with the parameter values, the Service name, the timeout setting in milliseconds for the Service to finish executing, and information to find the Entity the Service belongs to as shown below in SimpleThingClient.java:   public String callService(String name) throws Exception{ ValueCollection payload = new ValueCollection(); payload.put("name", new StringPrimitive("Timothy")); InfoTable table = handleServiceRequest(service, payload); return table.getFirstRow().getStringValue("name"); }   TIP: The code for creating the Service and Event should be in the constructor of the extended VirtualThing (or a method called from the constructor). Also, the Service code examples will work as long as the actual Service is defined. You can see from the examples that the annotation method is much cleaner.     Click here view Part 5 of this guide.
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
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
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
Recently I have been accompanying an integration partner and end customer around an issue experienced with ThingWorx resource exhaustion.  Early on it seemed like this was an issue with the ThingWorx Azure IoT Hub Connector as it would freeze up and become unresponsive.  Following a root cause analysis it became clear that it was actually caused by a lack of a number of standard cloud design patterns, which if used would have automatically adapted operation of the overall solution to be far more resilient as well as resource optimized.   The way that the logic was structured, it prioritized job execution on entities with the oldest last success time and would continue to retry these executions (IoT Direct Methods) every few seconds until successful.  There were a number of problems here, but I'll unpack a few in order to tie the problem to the solution via design patterns.   1) No exception handling When the direct method execution failed/timed out or the system reported being unable to execute the remote service, this response was not used to adapt the solutions behavior. 2) No backoff retry mechanism As exceptions were not caught, an adaptive retry mechanism with incremental or exponential backoff could not be leveraged to limit the impact of the build up of the failing retries. 3) No exception tracking Tracking that exceptions were occurring and counting them would allow powering an exponential backoff retry algorithm (with jitter), a Cancel or Circuit Breaker pattern (stop doing something which is just broken), as well as provided alerting to address specific areas of the distributed solution experiencing issues. 4) Conflicting priorities It was interesting to see the manifestation of the conflicting interests of wanting to ensure checks and balances (had all needed data) and system resiliency.  Retries and resource usage built up exponentially due to the transient error instead of backing them off.  Trying so hard to get the needed data from failing sensors meant that operational sensors were deprioritized and their data was not received either - spreading the localized issue to the whole system.   Around the time that I shared my recommendations and some examples of how to make the solution more resilient, one of my technical colleagues at Microsoft shared some extremely interesting and relevant design patterns documented by Microsoft as a part of the "Microsoft Azure Well-Architected Framework".  This framework with included Design Patterns for specific cloud application goals allows applying well-known industry standard approaches to dealing with the challenges of large scale distributed enterprise systems (reliability, performance, cost optimization).   She later then shared this blog post describing exactly the exponential backoff retry with jitter pattern which we had together recommended to the systems integrator.   What's interesting for us ThingWorx people is that this framework from Microsoft is about well-architected cloud solutions and does not specifically reference the Azure stack, and as such many of these approaches and design practices can be employed in your ThingWorx applications.  What are you waiting for?  Go check them out!
View full tip
We will host a live Expert Session: "Top 5 Thingworx environment monitoring best practices" on March 25th, 10h00 EST.   Please find below the description of the expert session and the registration link.   Expert Session: Top 5 Thingworx environment monitoring best practices Date and Time: March 25th, 10h00 EST Duration: 1 hour Host: Tori Firewind, Tim Atwood and Dave Bernbeck from Enterprise Deployment Center Registration Here: https://www.ptc.com/en/resources/iiot/webcast/top-5-thingworx-monitoring-best-practices    In this session, we will be reviewing the main monitoring practices to keep a heathy environment and discuss the main issues from the audience. Bring your questions!.   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
Hi All,   We will host a live Expert Session: "Thignworx Active Active Clustering" on January 21th 8h00 EST. Please find below the description of the expert session and the registration link.   Expert Session: Thignworx Active Active Clustering Date and Time: January 21th 8h00 EST Duration: 1 hour Host: Ayush Tiwari - IoT Product Manager Registration Here: https://www.ptc.com/en/customer-success/expert-sessions-for-thingworx-foundation-webcasts (scroll down, the session is in the bottom of the page)   Description: This session will cover the main aspects of the High Availability Clustering feature for High Availability configuration launched with the ThingWorx 9.0 release. Join us and bring your questions with you!    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 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 Thingworx Flow Overview Flow is a powerful component of the ThingWorx platform.  This session will take the Flow discussion beyond basic applications and into more customized and complex solutions.​ This will focus on use cases, main features such as triggers, connector options, main enhancements for Thingworx 9.0 and a short demonstration   Recoding Link
View full tip
Applicable Releases: ThingWorx Navigate 1.8.0 to 1.9.0     Description:   New improvements of the ThingWorx Navigate Installer with the following agenda: What's new Load Balancer Multiple Windchill Systems Integration Runtime NSSM How to select files to download Installer installation steps Demo Questions         Additional information How to install PTC Navigate
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
Announcements