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

ThingWorx Navigate is now Windchill Navigate Learn More

IoT & Connectivity Tips

Sort by:
ThingWorx community,   As part of a continuous re-evaluation of our third-party software requirements, we regularly add and remove support for versions of operating systems, persistence providers, and web browsers.   On this note, for the ThingWorx release after 9.2 (currently targeted for the end of CY 2021), we are planning to end support for Windows Server 2016. Already five years old, this product has generally been replaced by Windows Server 2019 in common usage.   As per Microsoft’s published lifecycle, this version will be going out of "Mainstream Support" approximately one year after the aforementioned ThingWorx release. PTC will continue to support Windows Server 2019 for the immediate future, and will consider supporting Windows Server 2022 once it becomes Generally Available (GA).   Please let me know if you have any questions or concerns.   Regards,   Walter Haydock ThingWorx Product Management
View full tip
Applicable Releases: ThingWorx Navigate 1.6.0 to 1.7.0   Description:   Covers how to configure ThingWorx Navigate to use Windchill Authentication: Background and Prerequisites X.509 Public Key Infrastructure (PKIX) Brief Introduction Steps to configure Thingworx Navigate with Windchill Authentication: Windchill Integration Runtime Thingworx Navigate     Additional Information Navigate SSL Configuration for Windchill Authentication General Checklist
View full tip
  Create Your Application Guide UI Part 3    Step 5: Add Widgets to Mashup    At this point, you should have an understanding of how the Widgets in your Mashup relate to the data from devices you've connected via the ThingWorx platform.   Scenario   Now, let's try to imagine a real-world scenario. For this example, assume that you are in a company developing an IoT application utilizing ThingWorx Foundation.   Developer Role Responsibility Edge Developers Utilize the Edge MicroServer, Software Development Kits, or ThingWorx Kepware Server to connect devices and bring data into the platform. Backend Developers Created Things, Thing Templates, and Thing Shapes to store and manipulate the data within ThingWorx Foundation. Frontend Developer Tasked with taking the IoT data and creating an interface with which your users can interact to gain insight from the data. In this scenario, you are the Frontend Developer. The Thing you imported previously represents those Edge and Backend Developers’ work. The data is all there. Specifically, let's assume that this Data Model represents a factory inventory system. You want to quickly build a GUI that is a Minimum Viable Product (MVP) to display the current counts of various products in your warehouse, while also allowing you to manually edit those counts if you receive a report that an IoT scanner in the warehouse has malfunctioned. Since this is a real factory, inventory is constantly increasing and decreasing as manufactured parts are completed or shipping orders are fulfilled. In this lesson, we'll simulate these changes by a 10-second-timer which will increment the counts until a shipping order has been fulfilled (100 total parts), at which point the current inventory count for that part will be reset.   Create the Mashup   Follow the subsequent steps to create an MVP GUI for the example scenario: Click Browse > VISUALIZATION > Mashups > + New. Keep the default of Responsive (with NO Responsive Templates chosen), and click OK in the pop-up window. In the Name field, enter MBQSMashup.   If the Project field is not already set, search for and select PTCDefaultProject.  At the top, click Save. At the top, click Design. On the left, click the Left Arrow to slide-back the navigation pane, leaving more room for the Mashup Builder. At the topleft on the Layout tab, for Positioning, check the radio-button for Static.   Add Labels   Follow the subsequent steps to add Labels that clarify GUI sections of the application. Select the Widgets tab, then drag-and-drop three Label Widgets onto the central Canvas.   With the top Label Widget selected (by clicking on it), change the DisplayName to label-gears-count and hit the Tab key on your keyboard to lock in the modification. NOTE: You can find the DisplayName and all other Widget Properties in the bottom-left of the Mashup Builder. Changing the Widget DisplayNames to recognizable values is highly recommended, as it assists with your logic inspection in the bottom-center Connections window.        3. With the newly-named label-gears-count still selected, type Gears Count in the LabelText field and hit the Tab key.       4. Click on the middle Label; then, in the bottom-left Widget Properties panel, change the DisplayName to label-pistons-count and LabelText to Pistons Count.       5. Similarly, change the bottom Label's DisplayName to label-wheels-count and LabelText to Wheels Count.       6. Click Save.   Add TextBoxes   Follow the subsequent steps to display some information on the various part-counts in our inventory. Drag-and-drop three Text Field Widgets onto the central Canvas.   With the top Text Field Widget selected, change the DisplayName to textfield-gears-count and hit the Tab key.   Change the middle Text Field's DisplayName to textfield-pistons-count, and hit the Tab key. Change the bottom Text Field's DisplayName to textfield-wheels-count, and hit the Tab key. Click Save.   Add Checkboxes   We want to display that inventory counts have been manually set when something went wrong, rather than have someone assume that the information is current and coming from an IoT sensor. This also allows us to flag any sensors that are experiencing issues. Follow the subsequent steps to create checkboxes. Drag-and-drop three Checkbox Widgets onto the central Canvas.   With the top Checkbox Widget selected, change the DisplayName to checkbox-gears-manual and the Label property to Gears Manually Set. Change the middle Checkbox's DisplayName to checkbox-pistons-manual and Label to Pistons Manually Set. Change the bottom Checkbox's DisplayName to checkbox-wheels-manual and Label to Wheels Manually Set.   Click Save.   Add Buttons   After our manual count has been entered, we need to trigger storing it in the backend. We can do this with a Button Widget. In addition, it would be helpful to be able to update the changing counts in the Textboxes without having to reload the entire Mashup. Follow the subsequent steps to add Buttons. Drag-and-drop two Button Widgets onto the central Canvas.   With the top Button Widget selected, change the DisplayName to button-manual-set, the Label to Manually Set Counts, and click-and-drag the right-side of the Button to expand its size.   With the bottom Button Widget selected, change the DisplayName to button-manual-retrieve, the Label to Manually Retrieve Counts, and click-and-drag the right-side of the Button to expand its size.   Click Save.   Resize the Mashup   Follow the subsequent steps to enable the Mashup to fit on a smartphone screen. Click-and-drag your Widgets around the Mashup such that they look roughly like the pictures shown above. Click-and-drag the right-side of the Mashup, pulling it to the left to reduce the horizontal size. Click-and-drag the bottom of the Mashup, pulling it up to reduce the vertical size.   Click Save.         Click here to view Part 4 of this guide.   
View full tip
The following script is a component of the Axeda Connected Configuration (CMDB) feature.  It is used to provide configuration data for controlling package deployments via Connected Content (SCM). ​ ConfigItem_CRU.groovy *Takes a POST request, not parameters import static com.axeda.sdk.v2.dsl.Bridges.* import com.axeda.drm.sdk.scripto.Request import com.axeda.services.v2.ConfigurationItem import com.axeda.services.v2.ConfigurationItemCriteria import com.axeda.services.v2.AssetConfiguration import com.axeda.services.v2.Asset import com.axeda.services.v2.ExecutionResult import groovy.json.JsonSlurper import net.sf.json.JSONObject import groovy.xml.MarkupBuilder /** * ConfigItem_CRU.groovy * ----------------------- * * Reads in json from an http post request and reads, adds, deletes or updates Configuration Items. * * * @note this parses a post and does not take any additional parameters. * * @author sara streeter <sstreeter@axeda.com> */ def contentType = "application/json" final def serviceName = "ConfigItem_CRU" def response = [:] def writer = new StringWriter() def xml = new MarkupBuilder(writer) try {     // BUSINESS LOGIC BEGIN     def assetId     def validationOnly     def validationResponse = ""     List<ConfigurationItem> configItemList     if (Request?.body != null && Request?.body !="") {         def slurper = new JsonSlurper()         def request = slurper.parseText(Request?.body)         assetId = request.result.assetId         validationOnly = request.result.validationOnly?.toBoolean()         if (request.result.items != null && request.result.items.size() > 0){             configItemList = request.result.items.inject([]) { target, item ->               if (item && item.path != "" && item.key != "" && item.path != null && item.key != null){                     ConfigurationItem configItem = new ConfigurationItem()                     configItem.path = item.path + item.key                     configItem.value = item.value                     target << configItem                 }                 target             }         }     }       if (assetId != null) {               def asset = assetBridge.find([assetId])[0]             AssetConfiguration config = assetConfigurationBridge.getAssetConfiguration(assetId, "")               def itemToDelete                        if (config == null) {                     createConfigXML(xml)                     AssetConfiguration configToCreate = assetConfigurationBridge.fromXml(writer.toString(), asset.id)                     ExecutionResult result = assetConfigurationBridge.create(configToCreate)                     AssetConfiguration config2 = assetConfigurationBridge.getAssetConfiguration(asset.id, "")                     config = config2                     itemToDelete = "/Item"                 }                 if (configItemList != null && configItemList?.size() > 0){                 List<ConfigurationItem> compareList = config.items                 def intersectingCompareItems = compareList.inject(["save": [], "delete": []]) { map, item ->                     // find whether to delete                     def foundItem = configItemList.findAll{ compare -> item?.path == compare?.path && item?.value == compare?.value  }                     map[foundItem.size() > 0 ? "save" : "delete"] << item                     map                 }               intersectingCompareItems.delete = intersectingCompareItems.delete.collect{it.path}               if (itemToDelete){                 intersectingCompareItems.delete.add(itemToDelete)               }                 def intersectingConfigItems = configItemList.inject(["old": [], "new": []]) { map, item ->                     // find whether it's old                     def foundItem = compareList.findAll{ compare -> item?.path == compare?.path && item?.value == compare?.value }                     map[foundItem.size() > 0 ? "old" : "new"] << item                     map                 }                 assetConfigurationBridge.deleteConfigurationItems(config, intersectingCompareItems.delete)                 assetConfigurationBridge.appendConfigurationItems(config, intersectingConfigItems.new)               def exResult = assetConfigurationBridge.validate(config)               if (exResult.successful){                     validationResponse = "success"                     if (!validationOnly){                         assetConfigurationBridge.update(config)                     }               }                 else {                     validationResponse = exResult.failures[0]?.details                 }             }             response = [                 assetId: assetId,                 items: config?.items?.collect { item ->                 def origpath = item.path                 def lastSlash = origpath.lastIndexOf("/")                 def key = origpath.substring(lastSlash + 1, origpath.length())                        def path = origpath.replace("/" + key, "")                 path += "/"                     [                         path: path,                         key: key,                         value: item.value                     ]                 },                 validationResponse: validationResponse             ]       }         else {             throw new Exception("Error: Asset Id must be provided.")         } } catch (Exception ex) {       logger.error ex   response = [           error:  [                   type: "Backend Application Error"                   , msg: ex.getLocalizedMessage()           ]   ] } return ['Content-Type': 'application/json', 'Content': JSONObject.fromObject(response).toString(2)] /** * Create the Success response. * * @param xml : The xml response.<br> * @param info : If this is set to "1" the info element will be included in the response.<br> * @param infos : Collection of information to include within the info element of the response.<br> */ private void createConfigXML(xml) {     xml.Item() }  
View full tip
Background Getting a performance benchmark of your running application is an important thing to do when deploying and scaling up an application in production.  This not only helps focus in on performance issues quickly, but also allows for safely planning for scaling up and resource sizing based on real concrete data.   I recently created a tool and made a post about capturing and analysing ThingWorx utilisation statistics to do such an analysis, as well as identifying potential performance bottlenecks. Although they are rich and precise, utilisation statistics fall short in a number of areas however - specifically being able to count and time specific service executions, as well as identifying and sorting based on the host executing the service.   Tomcat Access Log Analysis As ThingWorx is a Tomcat web application, Tomcat logs details of the requests being made to the application server and ThingWorx REST API.  The default settings include the host (IP address), date/timestamp, and request URI; which can be decoded to reveal relevant details like the calling entities and service executions.   Adding 3 key additional variables (%s %B %D) to the server.xml access log value also gives us the HTTP response code, service execution time, and bytes returned from Tomcat.  This is super useful as we can now determine exact time of service executions, and run statistics on their execution totals and execution time.     Once you have an access log file looking like the one above, you can attempt to load it into the access_log sheet in the analysis Excel workbook that I created.  You do this by click on the access_log table, then selecting "Data > Get Data > Data Source Settings".  You'll then be prompted with the following or similar pop-up allowing you to navigate to your access_log file to select and then load.     It should be noted that you'll have to Refresh the table after selecting the new access_log.txt file so that it is read in and populates the table.  You can do this by right-clicking on the table and saying Refresh, or using the Data > Refresh button.   This workbook relies on a number of formulas to slice and dice the timestamp, and during my attempts at importing I had significant issues with this due to some of the ways that Excel does things automatically without any manual options.  You really need to make sure that the timestamps are imported and converted correctly, or something in the workbook will likely not work as intended.  One thing that I had to do was to add 1 second to round up 00:00:00 for the first entries as this was being imported as a date without the time part, and then the next lines imported as a date/time.   Depending on how many lines your file is, you'll likely also have to "Fill Down" the formulas on the right side of the sheet which may be empty in the table after importing your new data set.  I had the best results by selecting the cells in question on the last row, then going down to the bottom corner, pushing and holding Shift, clicking on the last cell bottom right, and then selecting Home > Fill > Down to pull the formulas down from the top.   Once the data is loaded, you'll be able to start poking around.  The filters and sorting by the named columns is really helpful as you can start out by doing things like removing a particular host, sorting by longest execution times, selecting execution times greater than 4 seconds, or only showing activity aimed at a particular entity or service.     You really need to make sure that the imported data worked fine and looks perfect, as the next steps will totally break if not.  With the data loaded, you can now go to the Summary Data table and right-click on one of the tables and select Refresh.  This is reload the data in into the pivot table and re-run their calculations.   Once the refresh is complete, you should see the table summary like shown here; there are Day, Hour, and Minute expand/collapse buttons.  You should also see the Day, Hour, Month fields showing in the Field Definitions on the right.  This is the part that is painful -- if the dates are in the wrong format and Excel is unable to auto-detect everything in the same way, then you will not get these automatically created fields.     With the data reloaded, and Pivot Tables re-built, you should be able to go over to the Dashboard sheet to start looking at and analysing the graphs.  This one is showing the Top 10 services organised into hourly buckets with cumulated service execution times.     I'm not going to go into all of the workbooks features, but you can also individually select a set of key services that you want to have a look at together across both the execution count and execution time dimensions.     Next you can see the coordinated view of both total service execution time over number or service executions.  This is helpful for looking for patterns where a service may be executing longer but being triggered the same amount of times, compared to both being executed and taking more time.  I've created a YouTube video (see bottom) which goes through using all of the features as well as providing other pointers to using it.     Getting into a finer level of detail, this "bonus" sheet provides a Pivot Table and Pivot Chart which allows for exploring minimum, maximum and average execution time for a specific service.  Comparing this with the utilisation subsystem metrics taken during the same period now provide much deeper insight as we can pinpoint there the peaks were, how long they lasted, and where the slow executions were in relation to other services being executed at that time (example: identifying many queries/data processing occurring simultaneously).     Without further ado, you can download and play with my ThingWorx Tomcat Access Log Analysis Excel Workbook, and check out the recorded demonstration and explanation for more details on loading and analysis use. [YouTube] ThingWorx Tomcat Access Logs - Service Performance Analysis
View full tip
In the process of working with a customer, I was curious as to the throughput of a file sent via the Axeda Connected Content feature to one of the Axeda Agent Gateways.   I took a random 50 megabyte blob of data (/dev/urandom) and sent it to one of my test Gateways via a Package deployment: DEBUG   xgEnterpriseProxy: Enterprise Queue Empty INFO    xgSM:  ... Download percent done = 11% INFO    xgSM:  ... Download percent done = 21% INFO    xgSM:  ... Download percent done = 31% INFO    xgSM:  ... Download percent done = 41% INFO    xgSM:  ... Download percent done = 51% INFO    xgSM:  ... Download percent done = 61% INFO    xgSM:  ... Download percent done = 71% INFO    xgSM:  ... Download percent done = 81% INFO    xgSM:  ... Download percent done = 91% INFO    xgSM:  ... Download percent done = 100% DEBUG   xgSM: >>  INTERNAL DEBUG MESSAGE << :  Download time is 4 seconds DEBUG   xgSM: >>  INTERNAL DEBUG MESSAGE << :  Upgrading.  Backing up files to C:\temp\CFKGW\AxedaBackup DEBUG   xgSM: >>  INTERNAL DEBUG MESSAGE << :  Extracting downloaded files from DefaultProject\CFKGW\Downloads\141581_143281.tar.gz to directory C:\temp\CFKGW\ DEBUG   xgSM: >>  INTERNAL DEBUG MESSAGE << :  Extraction Finished About 12MB per second.  This was a sandbox in the PTC On-Demand Center.  Not bad, but not necessarily representative of a real production system.  This sandbox doesn't have 1000 devices trying to get this file at once.  So some benchmarking in your configuration and environment certainly needs to be done. So that done, I thought I'd up the ante - 700 megabytes this time! DEBUG   xgEnterpriseProxy: Enterprise Queue Empty INFO    xgSM:  ... Download percent done = 10% INFO    xgSM:  ... Download percent done = 20% INFO    xgSM:  ... Download percent done = 30% INFO    xgSM:  ... Download percent done = 40% INFO    xgSM:  ... Download percent done = 50% INFO    xgSM:  ... Download percent done = 60% INFO    xgSM:  ... Download percent done = 70% INFO    xgSM:  ... Download percent done = 80% INFO    xgSM:  ... Download percent done = 90% INFO    xgSM:  ... Download percent done = 100% DEBUG   xgSM: >>  INTERNAL DEBUG MESSAGE << :  Download time is 66 seconds So 10MB per second. Directory of C:\temp\cfkgw 05/17/2017  01:32 PM    <DIR>          . 05/17/2017  01:32 PM    <DIR>          .. 05/17/2017  01:03 PM         1,048,576 1mb.dat 05/17/2017  01:04 PM        52,428,800 50meg-randomdata.dat 05/17/2017  01:32 PM       734,003,200 700mb.dat 05/17/2017  01:03 PM    <DIR>          AxedaBackup                3 File(s)    787,480,576 bytes Not bad at all! 
View full tip
Applicable releases: 8.3 and above   Description: In this video, we will see  Basic concepts of SVM Some scenarios for a better understanding
View full tip
  Hello everyone!   We’re back with Episode 08 of ThingWorx on Air! In this episode, I sit down with Ryan Servais, one of our High Availability (HA) experts on the ThingWorx product management team. We continue our HA discussion from previous Ask Kaya tech tips and cover some frequently asked questions like what are the benefits of active-active clustering? How does active-active clustering enable horizontal scale? How can I get started? Brand-new to active-active clustering? Check out these tech tips to start: 9.0 Sneak Peek: Active-Active Clustering for ThingWorx 9.0 Sneak Peek: ThingWorx Architecture for Active-Active Clustering 9.0 Sneak Peek: Flexible Deployments of Active-Active Clustering for ThingWorx Click here to listen to how active-active clustering can help you in a variety of scenarios: If you have a request overflow in production and your servers are slowing down, try out active-active clustering! If your IT admin keeps delaying replacing the network card on your HPE rack server and you keep losing connections, check out the power of active-active clustering! If your team is challenged to provision 1000s of additional assets into your system and you’re worried one server can’t handle it, use active-active clustering for horizontal scale! Finally, if you haven’t already, check out Ryan’s LiveWorx session with Senior IoT Product Manager Ayush Tiwari where they break down availability into its core components and explain how you can leverage active-active clustering to achieve key benefits like reduced downtime, increased cost savings, and more.   Enjoy!   Stay connected, Kaya
View full tip
  Basic Mashup Widgets Guide Part 2    Step 3: Slider   A Slider allows your application users to interactively select a numeric value. When the user changes the position of the slider bar, an event is fired and the value property is changed. On the New Mashup tab, enter slider inside the Filter field in the top left. Drag-and-drop the Slider widget onto the top-right Container of your Mashup. 3. In the lower panel of the left dock, scroll to the Maximum property and change the value to 1000. 4. Change the Value property to 500 set the default position of the slider.   Add Value Display To demonstrate the Slider functionality we will add a Value Display Widget within the same Container of your Mashup as the Slider and bind the slider widget output to the input of the Value Display.         1. In the Filter field where you entered slider, enter value.        2. Drag-and-drop a Value Display widget onto the same upper-right Container as the Slider widget. 3. Click the drop-down arrow on the left side of the Slider widget. 4. Click and drag the Value property listed in the Slider drop-down onto the Value Display widget. 5. Click the Data property that is available from the Select Binding Target pop-up. 6. Click Save to save your Mashup. 7. Click View Mashup then adjust the slider to see the changing value shown in the Value Display widget.             Many properties are available that give control over how a Slider widget will be displayed. Properties can be changed both statically when designing the Mashup, and dynamically in response to changes in property values.   Bindable Name Type Default Direction Description Value Number 0 Input/Output Value defined by position of Slider that can be used by downstream widgets or services Minimum Number 0 Input/Output Value for left-most position of Slider, bottom-most position of Vertical Slider Maximum Number 100 Input/Output Value for right-most position of slider, top-most position of Vertical Slider HandleSize Number 34 Input Size in pixels of the slider handle Visible Boolean True Input Widget is visible if set to true StepSize Number 1 Input Smallest change in value when slider is moved   Static Name Type Default Direction DisplayName String None Name used for widget in user-facing interactions Description String None Description used for widget in user-facing interactions HandleIcon None/Circle/Split Circle Slider handle style SliderBar Thick/Thin Thick Slider bar style SteppingMode Boolean False When True, moves the slider by Step amount toward the click on the Slider bar TrackingMode Boolean False When True, the slider generates events as it changes value. Use with caution, this mode generates many events rapidly. DisplayMinMaxLabels Boolean True When enabled, displays the minimum and maximum values of the slider DisplayValueLabel Boolean True When enabled, displays the value of the slider   Widget Events Name Description ValueChanged Fired when Slider Value changes   Widget Services Name Description Increment Increase value of Slider by Step amount Decrement Decrease value of Slider by Step amount     Step 4: Toggle Button   A Toggle Button widget is used when a Mashup user may select only one choice from two options. On the Widgets tab in the top-left, enter button in the Filter field. Drag-and-drop the Toggle Button widget onto the lower left container of the mashup.   Scroll to the State property in the lower panel of the left dock where Toggle Button widget properties are shown. Click the check box to set the default state to true.   Add Value Display To demonstrate the toggle Button, we will add a Value Display Widget to the same Mashup container and bind the toggle Button State property to be shown by the Value Display. Drag-and-drop a Value Display Widget onto the same lower left container of the Mashup where the Toggle Button was placed. Click the drop-down arrow on the left side of the Toggle Button Widget. Click and drag the State property listed in the drop-down onto the Value Display Widget and a Select Binding Target pop-up will appear.  Click the Data property that is available from the Value Display Widget. Click Save to save your Mashup so it can be tested. Click View Mashup then click the Toggle Button to see the value of the button shown in the Value Display Widget.   Other properties are available to provide control over how a Toggle Button Widget will be displayed. Properties can be changed both statically when designing the Mashup, and dynamically in response to changes in property values.   Bindable Name Type Default Direction Description State boolean false Input/Output Value of toggle, can be used by downstream Widgets or Services Label String None Input Text that is displayed next to toggle button Visible Boolean True Input Widget is visible if set to true   Static Name Type Default Description DisplayName String auto-generated Name used to identify Widget in Mashup Builder Description String None Description used for Widget in user-facing interactions Height number autosize Sets the height of the widget in pixels LabelAlignment Left/Right Left Where label is shown relative to toggle button   Widget Events Name Description StateChanged Fired when user clicks the button   Click here to view Part 3 of this guide.
View full tip
This post is part of the series Forced Root Cause Monitoring via Mashups and Modal Popups To not feel lost or out of context, it's recommended to read the main post first. Before we start Create a new Project called "RootCausePopups" and save it. In the New Composer set the Project Context (top left box) to the "RootCausePopups" project. This will automatically add all of our new Entities into our project. Otherwise we would have to add each Entity manually on creation.
View full tip
This is a note/reminder in cross-reference to https://support.ptc.com/appserver/cs/view/solution.jsp?n=CS267248&lang=en_US Java 9 is expected to be released by Oracle September 21 2017 and is not currently supported for ThingWorx, refer to ThingWorx System Requirement guides for support details: ThingWorx 8 ThingWorx 7 ThingWorx 6
View full tip
New Framework in 8.5 -Install Builder produced installers -Installation orchestrated by Chef - UX Improvements - Cosmetic changes - Increased and improved help texts  - Documentation improvements - Changed layout for clarity - Security improvements Prerequisites:  -Install&Setup DB prior to installation -Set up ThingWorx DB User and database -DB command line tools installed & in the path (psql, msqlcmd) -Java 1.8.144 minimum -Clean machine for the install Common Issues -Command line tools not in path -DB user not set up -DB user with incorrect permissions -Java not installed or in path -Not running on a clean machine -Installed java 32bit instead of 64   Contacts: PM Mike Tresh TPM Jennifer Keane Dev Lead Mickey Kimchi   Q: The Windows/RHEL supported OS is just for installers? Running Thingworx on Ubuntu manually, is still supported? A: Yes. The matrix of supported OS for ThingWorx is larger than what we currently support for automated installs. ThingWorx can still run on Ubuntu Q: Is the support of Ubutu dropped completely , or just for the initial release? A: Support of Ubuntu is not there for the automated installers, it is still there for ThingWorx itself. Q: Would the installers provide a scrolling log or a direct link to the log file ? A: We provide the locations of the log files at the end of the install in the summary, and also the locations are noted in the documentation if you need to see log details. We also provide a progress bar with some info while install is running. The ThingWorx session will now be terminated by the Logout sequence yes. We now show a login browser prompt for TWX if they try to go back. Q: How do we upgrade a TWX 8.4 to TWX 8.5? A: For now, it's the manual upgrade process that you will already be familiar with as documented. Q: Is uninstaller available? A: Yes, there is an uninstaller for Foundation available, it should be present for you after running the installer. Q: Is Docker supported? A: We do support Docker and have samples available.
View full tip
Architecting Reason Code Trees in DPM Tori Firewind, IoT EDC   What are Machine Codes? Factory hardware devices communicate status changes to their human operators and other machines (IoT) via machine codes. The manufacturers often determine the machine codes for different types of factory hardware, so those are often pre-determined. However, how the reason trees map these machine codes to corresponding business logic in ThingWorx is entirely customizable. Knowing the best way to design your reason trees for this purpose can be challenging, so this guide is here to help with your conceptual knowledge. Using the UI to create, edit, and configure reason codes in technical detail can be found in the Help Center.    The Tree Trunk At the highest level of the reason tree, the trunk, there are really 3 categories: Availability (A), Performance or Productivity (P), and Quality (Q). These should look familiar; they are the three dimensions of OEE (Overall Equipment Effectiveness). Fg 1. Calculation of OEE Availability refers to long stops, events that stop planned production long enough that it makes sense to track a reason for being down (typically several minutes, but the threshold between a long stop and a short stop can vary depending on the ideal rate of production of materials).                  Availability = Run Time / Planned Production Time   Productivity/Performance really refers to short stops, things that cause the machine to run at less-than- optimal speeds. This can include stops caused by running out of materials for production, doing minor maintenance like switching out a single, easily-changed part, or even frequent breaks due to ill health of an operator. User error can be a cause as well, say if the machine needs a certain heat to produce parts, and the heat keeps fluctuating (requiring the machine to take the time to calibrate for this before starting on production) because operators are smoking out a back door or adjusting thermostat temperatures. Fg 2. Levels of Runnable Time   Operator influence often is a factor when it comes to the conditions that permit optimal performance from machinery, and every factory may face different challenges. Stops like these are not really outages; the amount of downtime isn’t enough to consider the production block entirely unproductive. Production was continuing and ongoing throughout most of the block despite the issues; the rate was just slower than ideal.                  Performance/Productivity = (Total Count / Run Time) / Ideal Run Rate   Quality refers mostly to the number of items that are considered scrap or rework, and it can be split into two categories: start up scrap (that which is expected because the machine is in the process of warming up or being fine-tuned by the operator) and production scrap (things which come out wrong and must be tossed or reworked because the conditions under which they were produced weren’t ideal; this is called first-pass yield only, meaning it's only a "good" product if it passes inspection the first time).                  Quality = Good Count / Total Count​   The Branches and the Leaves of the Tree The “leaves” are the reason codes which directly map to machine codes , and the “branches” are the method of categorization that connects them to the trunk. Both the leaves and the trees, the children and the parent nodes of the tree, are split into two states: planned versus unplanned downtime. Changeovers, maintenance, and even scrap, can be broken down into this dichotomy.   For scrap, there are startup rejects (planned, because the machines have ramp up periods) and production rejects (unplanned, because the conditions weren’t ideal). For maintenance there is planned and unplanned, small changes that occur on the fly that result in productivity loss, and maybe also reduce availability in the long run. Small, unplanned changes can occasionally shift into the availability loss category if a simple, quick repair winds up being complex and time-consuming. A good reason tree can differentiate easily between short and longer stops in order to respond to each in a deliberate way.   To start off in the process of architecting your reason tree, try writing the three categories on a board in a common room in an average factory (or several as a survey). Ask operators to stop in over the course of a few days and write various machine codes that they see often and find useful under one of these categories, or more than one if the machine code pops up under different circumstances and can mean different things. Have them write a 10 word justification, if the association isn’t obvious. Gather all of the “leaves” in this way, and then begin to associate them with the “trunk”, forming the “branches”.   An example tree can be seen in figure 3 here, with leaves like “Changeover” and “Maintenance” being semi-ambiguous; they could just as easily be seen as unplanned stops. Therefore, there may be multiple reason codes mapping up to the top of the tree in more than one branch, and these can have different categories, which controls how the business logic responds to the different codes. The Help Center has more details about how the events are mapped to types, and each type contains multiple categories, as configured by you when you set-up the DPM model. Fg 3: Different types of changeovers may have different codes, and can map up as either planned or unplanned, but all planned and unplanned stops (long stops) are under the Availability category of the trunk. Similarly, small stops can involve idling, like if there are not enough materials, reduced speed if the conditions are not ideal, or other small stops, usually caused by human error or unforeseeable circumstances. Quality loss then refers to the products which fail quality checks, either because the machine still has the wrong paint in the applicator and needs a few rounds to be ready for the next production item, or because the conditions are again, not ideal, and items wind up scrapped.   Example Reason Tree Fg 5 example tree with more specific tags (there may be dozens or hundreds in a full reason tree, though the fewer are needed to capture the events we care about, the better).   Theory of Constraints Fg 6 theory of constraint wheel: an industry process for gradual OEE improvement in factories that has been adapted into the PTC methodology as well. While architecting your reason tree, always remember the key purpose: gathering only as much data as necessary to analyze the efficiency of a factory and to identify the bottleneck, or the most limiting factor. The important point is to identify not just the bottleneck that seems the most troublesome, but the one that actually results in the greatest impact to OEE across the entire factory.   Without software like DPM, and a properly designed reason code tree, the process of improving a factory can be very challenging, involving a lot of guesswork, and sometimes solving one problem at the cost of another. The issue is that these machines produce a LOT of raw data, and humans are not the best tool available to gather and aggregate this data in a consumable way. A good reason tree ensures a smart application that can quickly prioritize the machine (bottleneck) that most impacts production, and not just the machine that functions in the least optimal way.   So, the theory of constraints is really a process for identifying small, incremental changes, which together can make a big difference, and fast, in factory OEE. The rate at which this cycle can be completed varies, however. The slower the process of identifying constraints and the less information that is gathered, the slower and less precise the first two steps of this process. Alternatively, in a traditional constraint identification process, too much information can be a problem as well, due to human limitation, as discussed above. So, DPM is a great benefit in this regard, because it aggregates the data into a consumable, comparable way every 5 minutes, freeing up your human analytics for problem solving and prioritization, and not data gathering and sorting.   Other Key Tips Also remember that a good tree treats the trunk like a whole unit, with each category occupying a percentage of the overall OEE. Afterall, look back up at the 3 dimensions of OEE in the equation above. For example, the more you see issues with availability, the less you will see issues with scrap, for the machine simply doesn’t have as much time to produce scrap if it is constantly down. The more you see issues with quality loss, the less you should see of productivity loss, because these are simply inversely proportional modes; to say it differently, if a machine is running quickly and seeing few minor maintenance stops, then it is likely to produce more scrap (as well as more good product as well).   Another thing to remember is that even DPM is limited in its capacity to interpret raw data. Even while many magnitudes more efficient than any human gathering and analysis could ever be, there is an upper limit to how much raw data DPM can ingest and analyze before the system gets very expensive. For this reason, you want to ensure your reason trees use only as many reason codes as are required to capture the OEE of a factory site. This will mean using different codes for different types of things, most likely, which is easy to do maintainably across many sites using thing shapes. Keeping things tightly defined and organized is the easiest way to ensure a clean, efficient system for gathering and storing data.   Also remember that data will not need to persist very long once DPM is fully operational and adopted by your factories. DPM ensures that the changes made to the production line to improve efficiency are the highest impact, and the least difficult to implement, meaning that there will be a very rapid return on investment, and a process to ensure future issues are identified and resolved quickly. Data from past issues in the factory won’t be as relevant, and historical data stores can be kept smaller than one might think. It is the power of ingesting data directly into the processing and aggregation process, the automatic reduction of data down into presentable, consumable webpages, that makes DPM and ThingWorx such a great factory solution for optimizing OEE.
View full tip
Video Author:                     Christophe Morfin Original Post Date:            October 10, 2016 Applicable Releases:        ThingWorx Analytics 52.x and 7.4   Description: In this video we review the prerequisites needed prior to installing ThingWorx Analytics Server.  
View full tip
When an Expression Rule of type File calls a Groovy script, the script is provided with the implicit object compressedFile.  This example shows how the compressedFile object can be used. This Expression Rule uses the Groovy script 'LastLine' to return the last line of the file, and sets the dataItem 'lastLine' to the returned value: Type:  File IF:      some condition e.g. File.hint=="hint" THEN:  SetDataItem("lastline", str(ExecuteCustomObject("LastLine"))) The LastLine script uses the implicit object 'compressedFile': import com.axeda.drm.sdk.scm.CompressedFile if (compressedFile != null) {     File file = compressedFile.getFiles()[0].extractFile()     def result =  file.eachLine { line ->         return line     } }
View full tip
  ThingWorx 9.2 is here! Deploy an entire solution and all its dependencies in one click with Solution Central’s one-click deploy, garner deeper analytic insight with our new waterfall charts, and manage and authenticate users more seamlessly with an Azure Active Directory integration. Discover these features and more in my 9.2 preview post here!   Review our release notes here and be sure to upgrade to 9.2!   Stay connected, Kaya
View full tip
   Who’s ready for exciting new functionality like smoother integration with Azure, rapid deployment capabilities, flexible KPIs and so much more?   Good news! Yesterday, we released ThingWorx 8.5—equipped with features like a new Azure connector for ThingWorx Flow, new software content management (SCM) capabilities with the Azure IoT Hub Connector, streamlined deployments with Solution Central, flexible KPI calculations with our PTC manufacturing and service apps—just to name a few. Check out the 8.5 release notes to discover all the highlights and goodness of our latest release and hear our CTO of IoT, Joe Biron (who you may recognize from previous Ask Kaya posts) and one of our product experience specialists, Sebastian Bergner, highlight new functionality and share demos in this exciting webcast (please note that we've had a little snafu with the link and the recording should be available later this week).   Play around with our new features by downloading ThingWorx 8.5, and let the good times roll.   Let us know what you think in the comments below and be on the lookout for future Ask Kaya posts highlighting new 8.5 functionality.   Stay connected, Kaya
View full tip
This video walks you through the use of Analysis Replay to execute analysis events on historic data. This video applies to ThingWorx Analytics 7.4 to 8.1   Updated Link for access to this video:  Analytics Manager : Using Analysis Replay
View full tip
The ThingWorx Android SDK was designed to load without modification into Android Studio but due to recent changes in Android Studio, the Thingworx Always On Android SDK 1.0 needs to have minor modifications made to its build files before it will load or build. This changes will be made in the 1.1 release in July, 2016 but until then they will have to be updated after the user downloads the SDK. Android Studio changed the minimum required Android build tools for gradle. This also forces a new version of gradle to be required. The following changes must be made to each set of SDK project build files. The tw-android-sdk/gradle/wrapper/gradle-wrapper.properties file ( there is only one present in the entire sdk) must have this line changed from: distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip to: distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip In all build.gradle files change from: buildToolsVersion "19.1.0" to: buildToolsVersion “21.0.0” also in all build.gradle files change from: dependencies { classpath 'com.android.tools.build:gradle:1.3.0' } to: dependencies { classpath 'com.android.tools.build:gradle:2.1.0' } Now you should be able to import and build all examples again.
View full tip
In this post I show how to use Federation in ThingWorx to execute services on a different ThingWorx platform instance. In the use case below I set up one ThingWorx instance in the Factory and another instance in the Cloud, whereby the latter is executing a service which is actually running on the former.   Please find the document in attachment.   HTH, Alessio Marchetti  
View full tip
While it is not a requirement, it is a best practice to install KEPServerEX (v6.2 or higher) before installing ThingWorx (v8.0.1 or higher). If ThingWorx is already installed, close the application and complete the install of KEPServerEX by following these install instructions: How do I download and install KEPServerEX? Now, when you attempt to launch ThingWorx, if you are presented with a "null pointer exception" error, follow this workaround: 1. Navigate to the 'PostgreSQL\installer' directory, within the directory where the Manufacturing Apps are installed. By default this will be: <ThingWorx install path>\ThingWorxManufacturingApps\PostgreSQL\installer 2. Run the 'vcredist.exe' located there. This application should re-install the conflicting redistributables, and you should be able to launch ThingWorx again normally.
View full tip
Announcements