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:
Connecting Existing Things to ThingWorx Industrial Gateway for Anomaly Detection   In this Video you will learn how to :   - To bind a property of an existing entity to the KEPSserverEX Data Feed - To create an Alert on that property and monitor it's behavior   Updated Link for access to this video:  Connecting Existing Things to ThingWorx Industrial Gateway for Anomaly Detection
View full tip
  Hi, everyone!   In previous tech tips, we’ve introduced 9.0’s biggest feature, active-active clustering, and covered some of the main architectural components. Today, I’ll cover some other architectural configurations and the flexibility that active-active clustering provides to meet your IoT deployment needs.   Deployment Flexibility With Active-Active Clustering, ThingWorx allows you to achieve the highest availability of your IIoT system while still retaining the high degree of deployment flexibility that ThingWorx is known for.   It’s important to emphasize flexibility not only in where you deploy ThingWorx, but also in how  you deploy it. Flexibility is embedded in the ThingWorx architecture to suit your deployment needs. Let’s look at two interesting options.   Cost-Efficient Deployment The first example is deploying ThingWorx in a cost-efficient architecture for smaller or cost-sensitive deployments. Instead of each component on its own separate VM or box, ThingWorx Connection Server, ThingWorx Foundation Server, ZooKeeper, and Ignite are all installed on the same box.   With three boxes in parallel, the system still achieves high availability while reducing deployment costs by minimizing the number of servers utilized. A minimum of three servers is needed to achieve an odd number of instances required by ZooKeeper while still providing redundancy.   In order to optimize for cost while still providing high availability, there are a few factors to consider with this deployment. In this configuration, Ignite is run within the same JVM as ThingWorx Foundation, rather than on a different server. While this does reduce the overall footprint, Ignite will consume additional memory, sharing the resources with the ThingWorx Foundation platform. Since ThingWorx Connection Server is run on the same VM as ThingWorx Foundation Server, this introduces socket limitations, which can restrict the maximum number of connected devices.     In short, the example above illustrates how, while being in an active-active clustered environment, you still retain the deployment flexibility to optimize for your deployment needs. In this scenario, the architecture is optimized for a leaner, more cost-effective deployment at the expense of numbers of connections and memory.   Now, let’s walk through some common use cases where ThingWorx is deployed on premise on VMs or baremetal to support use cases that require a balance of availability and scalability at an affordable cost. A few of these examples include: On-premise deployment of ThingWorx Foundation to support a dedicated factory production line on a plant floor to improve its connected manufacturing operations. VM based on-site deployment of ThingWorx Foundation to support IoT applications for a Smart Building scenario. Smart Ship deployments managing key ship operations where ThingWorx is deployed on a ship and sends data intermittently to private data centers running ThingWorx on shore through a satellite network leveraging ThingWorx federation technology. A failover-proof redundant setup required to capture key service metrics for medical equipment for predictive failures and maintenance where ThingWorx is deployed in hospital premises. OEM Deployment with Common Components The second example covers how active-active clustering architectural components can be shared across multiple clusters to reduce the cost and complexity of deployment. This can include scenarios where a large deployment spans multiple sites, geographies or end customers.   In this deployment, there are two ThingWorx clusters that share a common ZooKeeper cluster and database layer. Within each cluster, both the Connection Server and ThingWorx Foundation with Ignite running as embedded are deployed on a VM.   For the shared components, proper separation measures must be taken to ensure security. For ZooKeeper, separate namespaces and authentication from the clients are required. For the shared database layer, each cluster must have a unique schema, a separate shared file system and separate user credentials with database-level isolation. Please note that with a large shared database across tenants, rather than a dedicated database for each tenant of HA cluster, there is a risk of impacting performance and availability of other tenants due to issues caused by one of the shared ones.     This architecture is optimized for a larger deployment comprised of multiple ThingWorx clusters requiring separation between the clusters, while still allowing the provider to share a common infrastructure for cost reduction.   Again, let’s walk through another few common use cases, including: A ThingWorx OEM hosting multiple ThingWorx Foundation instances in their managed data center or public cloud to offer applications with further customization abilities to their end users. In this case, an OEM vendor can offer multiple ThingWorx clusters in active-active cluster mode with shared pieces of infrastructure across multiple tenants. A ThingWorx enterprise customer looking to build and host different ThingWorx-based applications in their IT data center where each application is powered by an individual active-active cluster satisfying specific digital transformation use cases across the enterprise value chain, including those related to engineering, product, sales, marketing, supply chain, partners, service and support. A ThingWorx factory customer looking to host multiple ThingWorx applications from their main regional factory IT data center to cater to the IoT needs of different factories located in surrounding geographic regions. In this case, a customer could dedicate one HA cluster to each factory to enable that factory/site to power multiple IoT applications efficiently.   These two configurations are some of the lesser known—yet equally powerful—deployments of this new architecture. Again, flexibility of our deployment architecture is one of the key superpowers of the ThingWorx platform. And, the active-active fun doesn’t stop there! Be on the lookout for an upcoming LiveWorx session titled Active-Active Clustering with ThingWorx 9.0  (Session ID: IP1117B), future tech tips like this one, and, of course, the GA release of ThingWorx 9.0 (targeted for June 2020) where you can take advantage of this new functionality!   Let us know what you think in the comments!   Stay connected, Kaya      
View full tip
This Javascript snippet creates a random value between those limits:   var dbl_Value = Math.floor(Math.random()*(max-min+1)+min);
View full tip
Video Author:                     Asia Garrouj Original Post Date:            June 13, 2017 Applicable Releases:        ThingWorx Analytics 8.0   Description: This video is the second of a 3 part series walking you through how to setup ThingWatcher for Anomaly Detection. In this second video you will learn how to use the "Discover UI" from the NextGen Composer to bind simulated data coming thru KEPServer for Anomaly Detection.    
View full tip
In this particular scenario, the server is experiencing a severe performance drop.The first step to check first is the overall state of the server -- CPU consumption, memory, disk I/O. Not seeing anything unusual there, the second step is to check the Thingworx condition through the status tool available with the Tomcat manager. Per the observation: Despite 12 GB of memory being allocated, only 1 GB is in use. Large number of threads currently running on the server is experiencing long run times (up to 35 minutes) Checking Tomcat configuration didn't show any errors or potential causes of the problem, thus moving onto the second bullet, the threads need to be analyzed. That thread has been running 200,936 milliseconds -- more than 3 minutes for an operation that should take less than a second. Also, it's noted that there were 93 busy threads running concurrently. Causes: Concurrency on writing session variable values to the server. The threads are kept alive and blocking the system. Tracing the issue back to the piece of code in the service recently included in the application, the problem has been solved by adding an IF condition in order to perform Session variable values update only when needed. In result, the update only happens once a shift. Conclusion: Using Tomcat to view mashup generated threads helped identify the service involved in the root cause. Modification required to resolve was a small code change to reduce the frequency of the session variable update.
View full tip
Developing with Axeda Artisan (for Axeda Platform, v6.8 and later) Axeda Artisan is a development tool based on the Apache Maven build system. Artisan includes authoring, management, and deployment mechanisms that define and manage the development of Axeda Platform extension points, allowing you to flexibly install, update, and uninstall many types of objects on the Axeda Platform. The Components of Artisan The Artisan framework is comprised of several components: The Axeda Platform Each instance of the Axeda Platform contains libraries and sample Artisan Projects (archetypes) that are downloaded by developers to author and deploy their own Artisan Projects. The Artisan Project An Artisan Project is a collection of content and configuration files that are used to define a set of objects that will be installed on the Axeda Platform. The Artisan Installer The Artisan Installer is a flexible, configurable application that uses the Apache Maven build life-cycle to upload the contents of an Artisan Project to the Axeda Platform. Axeda Platform APIs The Artisan Installer interacts with the Axeda Platform and uses Axeda APIs to install, upgrade, or uninstall ArtisanProjects. How You Work With Artisan The goal of using Artisan is to develop an Artisan Project that will become an object or application that runs on the Axeda Platform. There are several phases involved in creating an Artisan Project: Preparing Your Development Environment – When first working with Artisan, you need to prepare your development environment by installing or configuring Java, Apache Maven, and any other required development tools. Creating an Artisan Project – Artisan uses archetypes as the basis for Artisan Projects. Archetypes are used to generate an Artisan Project that contains the correct type of development framework, which you then modify to create your own Artisan Project: The Hello World archetype provides a sample project you can use to create common objects on the Axeda Platform. The Machine Streams archetype provides a sample project you can use to configure machine streams for your Axeda Platform. Installing an Artisan Project on the Axeda Platform – The Artisan Installer packages the contents of the Artisan Project, and deploys them on the Axeda Platform. Testing the Artisan Project – Once installed, you can test your Artisan Project to verify its functionality and identify any issues that need to be addressed. It is common for an Artisan Project to be installed on the Axeda Platform several times as issues are identified and corrected during development. Creating a Stand-alone Installer – Once ready for deployment to production, the Artisan Installer is used to create a stand-alone installer for distributing the project contents to other instances of the Axeda Platform. Where to Go from Here To begin working with the Artisan framework to create your own projects, refer to the following: Artisan Landing Page – A page hosted on the Axeda Platform that introduces Artisan and serves as a starting point for creating an Artisan Project. The Artisan Landing Page can be found at the following location: http://instance_name:port/artisan                     Where instance_name:port/ is the ip address and port of an instance of the Axeda Platform. Axeda® Artisan Developer’s Guide – A reference that introduces Artisan, describes how to prepare your development environment, and provides detailed technical information concerning creating an Artisan Project and configuring the Artisan Installer. The Axeda® Artisan Developer’s Guide is available with all Axeda product documentation from the PTC Support site, http://support.ptc.com/
View full tip
Warning This post is quite long, has various chapters and you might get bored reading it. If you just want a summary read the "Use case" and "Conclusion" chapter - and maybe the "Required Logic" chapter, because I made a cool graph for it. The rest is all about implementation... Introduction I recently had the opportunity to deliver a ThingWorx training for Saint Gobain. One of the use cases for their ThingWorx application is monitoring machine errors and outages on the production line. If an outage or error status is triggered, the machine operator will see a popup on the monitoring screen where he is forced to select a root cause. This root cause will then be persisted in ThingWorx for more data transformation, analytics and reporting - like cost analysis or optimization opportunities. During the training we were also discussing on how such a forced root cause monitoring can be implemented via Mashups and the usage of modal popups. I've compiled the details into this post as it might also interest other developers. The ThingWorx Entities I'm using in this example can be downloaded from here Note: I'm using the word "Alert" here - but not in the context of a ThingWorx Property Alert... just beware to not be confused due to the wording. Use Case One of the requirements for Saint Gobain's IoT Solution was an interactive alert monitoring directly in the factory on the production machines. Let's say the machine has stopped, the root cause should be recorded. For this an interactive popup will be displayed on the machine's monitoring display and an employee has to choose the root cause from a pre-defined list. This could be planned outages, e.g. for maintenance or unplanned outages, e.g. material jam. The root cause will then be recorded and a history of outage causes can be stored in a ThingWorx value stream. This can then be later analyzed with e.g. ThingWorx Analytics capabilities to understand and optimize the machine's production capabilities and efficiency. As the root cause must be entered, the popup will be forced to be displayed when a certain condition / criteria is met - and it will only disappar when a root cause is chosen. The user should not be able to interact with any other elements of the Mashup and not be able to just close the popup. The popup will close itself and reset the initial condition once the root cause has been identified and chosen. Requirements Required Entities Required Logic Note: Just to make it easier to manage and export Entities, I will add all of the created elements in a new Project called RootCausePopups. All of the elements will have a "rcp_" added in front of their name - just to make it easier for me to find and identify them. Implementation Before we start - set a Project Context Create Entities Create a Popup Mashup Create the Main Mashup Testing the Mashups Conclusion Certain conditions (like the state of a checkbox) can be used to trigger modal popups. A modal popup forces a user interaction and the interaction will not offer any other option until a choice is made. With these parameters it's easy to have mandatory reaction from users when it's important to capture data which rely on the analysis of an engineer or a user - e.g. reasons for machine outages. Using this technique there's not much training required for staff, other than pushing a button with an option of their choice - this saves quite some time in capturing data in any other way (e.g. updating Excel files or manual pen-and-paper techniques). As this data is now part of the ThingWorx instance it can be used for further transformation, analysis or just for monitoring purposes There's of course more possibilities when it comes to states and formatting which would exhaust the context of this post - but feel free to explore... In the example we wouldn't need the textbox, but it's there to demonstrate if the correct values are persisted or not In the example we could of course also set the visibility of the checkbox to false, so that we would only see the popup and the Grid holding historic information We could also create different StateDefinitions to color-format / text-format the input differently from the output in the Grid If you found this interesting (and actually made it to the end of this post) - feel free to play with this concept a bit more... The dependencies might seem a bit difficult, but it should be easy to implement and to adjust to your own ideas and requirements.
View full tip
Procedure on how to configure Single Sign On (SSO) with Thingworx and Windchill, where users will be able to access Thingworx/Navigate with their  Windchill credentials. This video consist of demo and architecture of how SSO works.     For full-sized viewing, click on the YouTube link in the player controls.   Visit the Online Success Guide to access our Expert Session videos at any time as well as additional information about ThingWorx training and services.
View full tip
This Guide contains all the Linux commands that you may have to use for ThingWorx Analytics Installation or day to day use. Command/Category Description Network/port ip a List the ips of all of the network interfaces ssh How to jump from one machine to another ping Send packets to a remote machine.  useful for testing connectivity netstat –anp Check active port cat < /dev/tcp/localhost/8080 Test connection to a port Replace localhost with desired hostname or ip, replace 8080 with desired port number (/dev/tcp/host/port) exit Exit my current sign in.  this lets one disconnect from remove ssh sessions or if one has changed one's user e.g. switched to root scp Retrieve something via ssh Resource Usage free -m Check memory -m is for output in Mb Mpstat -P ALL CPU usage top Process usage jvmtop Collect cpu usage of jvm and its thread https://github.com/patric-r/jvmtop (requires jdk to be installed) File Interaction cp / mv Copy and move respectively. mv just deletes the source file.  Usage: cp /source/location/file /output/location/file cat Mostly used to just print the contents of a file to the command line.  can also print multiple files at once:  cat /var/log/gridworker/warning.log /var/log/gridworker/error.log vim / vi A command line text editor. Not the most user friendly (none of them are) but really useful. Here's a cheat sheet for the commands https://www.fprintf.net/vimCheatSheet.html rm Remove files chmod Change the access permissions of files chown Change the user or group ownership of files grep A text based filtering.  Useful for making a larger list smaller and more targeted.  Almost always used after a pipe (see pipe below) less Generally used to view the contents of a file with more friendly scrolling locate Find a file by name Directory ls What’s in the directory.  Will do the current directory but you can also pass the directory e.g. ls /var/log/tomcat. Black writing is files Blue writing is directories Red writing is compressed file pwd Tell me which directory I'm currently in cd Change directory.  provide the directory to change to or just use cd to return to the user's home directory clear Clears the screen Terminal clears all provided commands mkdir Creates Directories Running Processes ps Query what services are running. usually use ps -aux to get a full, sorted list.  using grep with this is helpful systemctl The correct way to interact with services that are running Package installation yum install <packageName> Install a package. More useful commands: https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s1-yum-useful-commands.html yum list installed List installed packages yum list <package> List available packages yum --showduplicates list java-1.7.0-openjdk-devel Use --showduplicates to see all versions Can use * for package name: *openjdk* rpm -ql <packagename> Find where package are installed Note: works if package installed with yum Yumdownloader --urls <packageName> Find URL where a package is downloaded from. Note: need to install yum-utils package Repoquery --requires <packageName> Find dependencies of a package Note: need to install yum-utils package repoquery --qf=%{name} -g --list --grouppkgs=all [groups] | xargs repotrack -a x86_64 -p /repos/Packages Download a package with all its dependencies. Need to install yum-utils package From  <http://unix.stackexchange.com/questions/50642/download-all-dependencies-with-yumdownloader-even-if-already-installed> Other Commands curl http://localhost:8080/1.0/about/versioninfo Send REST call via command line Use -X POST (default GET) for a POST (see man page - https://curl.haxx.se/docs/manual.html for example) See also http://www.codingpedia.org/ama/how-to-test-a-rest-api-from-command-line-with-curl/ Find / -type f -exec grep -I mystring {} \; Search string in files Sudo -u user command Execute a command as different user The below helpers are not commands themselves, but can be used in conjunction with the above commands. Helper Description 'pipe' The | character.  lets one chain commands.  e.g. ps -aux | grep java ./ The shorthand way to refer to this directory explicitly ../ The shorthand way to refer to the parent directory 'tab completion' Pressing tab will let linux guess what command/option best fits what's currently written.  very useful for navigating directories and long-named files (NOTE: not necessarily tab based upon one's keyboard layout/language) 'ctrl-r' Look up the mostly likely command that matches what one typing.  so if one earlier used ps -aux | grep java | less and the hit ctrl-r and typed -aux it would likely pull that command or at least the most recent one that matches
View full tip
All of the entities and data in storage entities(Stream, ValueStream, DataTable, Wiki, Blog) are kept in Persistence Provider, to enhance the storage volume of Thingworx, it is advised to use bigger Persistence Provider (PostgreSQL or Cassandra rather than Neo4j and H2), move and keep certain part of data in external database or set up a second Persistence Provider Data Storage entities (Stream, ValueStream, DataTable) and Collaboration entities (Wiki, Blog) can be assigned to the new Persistence Provider to keep the Business Data The original Persistence Provider (upon installation) will be freed from large data input and respond faster, and only holds the Model Data (entity information) Small Persistence Provider like H2 or Neo4j, which does not require extra steps to setup in the Thingworx installation process, cannot set up a second Persistence Provider (they don't have .bat files to configure the database) Here is an example for setting up a second PostgreSQL (may also applicable for Cassandra) Install a new PostgreSQL in the server Should give different folder names for the files, or two PostgreSQL will affect each other PostgreSQL 9.5 could work with Thingworx 7.2.x, but cannot be used with 7.3 and above. Version 9.5 is not officially supported or advised by now, and the user should take their own risk if doing so. The new PostgreSQL will have a new port number (e.g. first port is 5432, the new port is 5433) Open PostgreSQL using pgAdmin 3 Create a new user role: a. Right click PostgreSQL9.4 (localhost:5433). b. Select NewObject>New Login Role. On the Properties tab, in the Role name field, enter the user role name. c. On the Definition tab, in the Password field, enter a unique password (you will be prompted to enter it twice). Add the new <postgres-installation>/bin folder to system path variable Edit the thingworxPostgresDBSetup.bat and thingworxPostgresSchemaSetup.bat from the Thingworx software download package, and change the port property to 5433 Execute the two scripts, and new database and tablesapce will be created platform-settings.json file does not need extra configuration Restart the Tomcat server, a new folder will be created under ThingworxPostgresqlStorage folder Go to Thingworx composer, create a new Persistence Provider in the Home list Give it a new name, and select Persistence Provider Package(only one choice) After selection, a Configuration field will show up in the ENTITY INFORMATION field ( such field will not appear in Neo4j based Thingworx) Open Configuration and change the JDBC URL to jdbc:postgresql://localhost:5433/thingworx, update Password, click Save The new Persistence Provider can be used in data storage entities now The new Persistence Provider can also be set as default provider
View full tip
Hello Developer Community, We are pleased to announce pre-release availability of the ThingWorx Edge SDK for Android! The Android SDK beta is built off the Java SDK code base, but replaces the Netty websocket client with Autobahn for compatibility with Android OS.  Those familiar with the Java SDK API will feel very much at home in the Android SDK.  We recommend beginning with the included sample application.  Please watch this thread for upcoming beta releases.  b4 adds file transfers between the ThingWorx platform and Android devices and an example application. We welcome your questions and comments in the thread below!  Happy coding! Regards, ThingWorx Edge Products Team
View full tip
  Step 3: Create a Base Mashup   Now that you have some data, you need to create and configure a Mashup to display the data.   Using Mashup Parameters, the Collection Widget will replicate the base Mashup multiple times, correlating to each row of data in the Info Table Property.   On the ThingWorx Composer Browse tab, click Visualization > Mashups, + New                2. Keep the default ofResponsive(without selecting any Templates), and click OK          3. In the Name field, enter cwht_base_mashup.      4. If Project is not already set, search for and select PTCDefaultProject.      5. Click Save.     Add Widgets to Design   At the top, click Design. TIP: You can click the left arrow on the divider between the Browse left-navigation and the Mashup Builder to minimize the navigation and provide more room for the Mashup Builder itself.                  2.  On the Layout tab at the top-left, select Positioning > Static. You generally want the base Mashup to be "Static" so that you know the size of the cells which  the Collection Widget will replicate.                3. From the top-left Widgets tab, drag-and-drop a Gauge Widget onto the central Canvas area.             4. Drag-and-drop an LED Display Widget onto the central Canvas area.               5. Drag-and-drop a Text Field Widget onto the central Canvas area       Reduce the Mashup Size   At the top-left on the Explorer tab, select the Container.                2. In the central Canvas area, click-and-drag the far-right side of the container to reduce its horizontal size               3. Click-and-drag the bottom of the container to reduce its vertical size     Create Mashup Parameters   On the top-left Explorer tab, select the Mashup itself. A drop-down menu indicator will appear in the top-left of the Mashup.                 2. Click the top-left drop-down menu to reveal the Mashup options               3. Select Configure Mashup Parameters to open the Configure Mashup pop-up menu                4. Click Add Parameter three times              5. For the Name fields, enter first_number, second_number, and third_number.         6. Change the Base Type to NUMBER for all three Parameters           7. Click Done to close the Configure Mashup pop-up menu   Bind Mashup Parameters to Widgets   Click the Mashup's drop-down menu in the top-left to expose the options again. There are now additional options for first_number, second_number, and third_number.              2. Drag-and-drop first_number onto the Gauge Widget               3. Select Data on the Select Binding Target pop-up menu of the Gauge Widget.         4. Drag-and-drop second_number onto the LED Display Widget. You may have to first reselect the Mashup itself to reveal the Mashup's drop-down menu to access the second_number Mashup Parameter. Remember that you can easily select the Mashup itself through the Explorer tab.                                    5. Select Data on the Select Binding Target pop-up menu of the LED Display Widget.         6. Drag-and-drop third_number onto the Text Field Widget.         7. Select Text on the Select Binding Target pop-up menu of the Text Field Widget.         8. At the top, click Save. You can expand the Connections window at the bottom and select the Mashup itself to confirm that all three Mashup Parameters have been correctly bound to each Widget.          9. Click the Right Arrow on the far-left of the Mashup Builder to re-expand the Browse navigation menu.         Click here to view Part 3 of this Guide.
View full tip
Merging InfoTables can seem to be an overwhelming task in ThingWorx. What even IS an InfoTable?? The short answer is that an InfoTable is a specifically structured JSON object. Merging InfoTables is therefore as easy as incrementing through each, adding the columns of each to another table, and then populating the new table with data. For InfoTables with the same DataShapes, the built in "Union" service can be used. Find this snippet under the InfoTableResources section. There is also a snippet for incrementing through DataShape fields if the DataShape is known. For InfoTables which don't have the same DataShapes or for which the DataShape is not known, things get a bit trickier. Thankfully, some new KCS documentation provides example code to step you through merging any number of tables together. I hope this documentation is helpful!
View full tip
  Use the C SDK to build an app that connects to ThingWorx with persistent bi-directional communication   Guide Concept This project will introduce more complex aspects of the ThingWorx C SDK and help you to get started with development.  Following the steps in this this guide, you will be ready to develop your own IoT application with the ThingWorx C SDK.  We will teach you how to use the C programming language to connect and build IoT applications to be used with the ThingWorx Platform.   You'll learn how to Establish and manage a secure connection with a ThingWorx server, including SSL negotiation and connection maintenance Enable easy programmatic interaction with the Properties, Services, and Events that are exposed by Entities running on a ThingWorx server Create applications that can be directly used with your device running the C programming language Basic concepts of the C Edge SDK How to use the C Edge API to build a real-world application How to utilize resources provided in the Edge SDK to help create your own application NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL 3 parts of this guide is 60 minutes.   Step 1: Completed Examples Download the completed files for this tutorial: ThingWorx C Edge SDK Sample Files.zip.  This tutorial will guide you through working with the C SDK on differing levels. Utilize this file to see a finished example and return to it as a reference if you become stuck creating your own fully fleshed out application.  Keep in mind, this download uses the exact names for Entities used in this tutorial. If you would like to import this example and also create Entities on your own, change the names of the Entities you create.   Step 2: Environment Setup In order to compile C code, you need a C compiler and the ThingWorx C Edge SDK available in the PTC Support download site.  It will be helpful to have CMake installed on your system. CMake is a build tool that will generate make or project files for many different platforms and IDEs.   Operating System      Notes Windows You will need a 3rd party compiler such as MinGW GCC, Cygwin GCC or you can follow these Microsoft instructions to download and use the Microsoft Visual C++ Build Tool. Mac Download the Apple Developer Tools. Linux/Ubuntu A compiler is included by default.   NOTE: You can use CMake, version 2.6.1 or later to build projects or make files, which then are used to build the applications that you develop with the C SDK.     Before you can begin developing with the ThingWorx C SDK, you need to generate an Application Key and modify the source code file. You can use the Create an Application Key guide as a reference.   Modify Source File Extract the files from the C SDK samples zip file. At the top level of the extracted files, you will see a folder called examples. This directory provides examples of how to utilize the C SDK. Open a terminal, go to your workspace, and create a new directory. You can also just switch to the unzipped directory in your system. After you've created this directory in your workspace, copy the downloaded files and folders into your new directory. You can start creating your connection code or open the main.c source file in the examples\SteamSensor\src directory for an example. Operating System      Code Linux/Ubuntu gedit main.c OR vi main.c Mac open –e main.c Windows start main.c Modify the Server Details section at the top with the IP address for your ThingWorx platform instance and the Application Key you would like to use. Change the TW_HOST definition accordingly. Change the TW_PORT definition accordingly. Change the TW_APP_KEY definition to the keyId value saved from the last step.         /* Server Details */ #define TW_HOST "https://pp-XXXXXXXXX.devportal.ptc.i" #define TW_PORT 80 #define TW_APP_KEY "e1d78abf-cfd2-47a6-92b7-37ddc6dd34618"​         NOTE: Using the Application Key for the default Administrator is not recommended. If administrative access is absolutely necessary, create a User and place the user as a member of Admins.   Compile and Run Code To test your connection, you will only need to update the main.c in the SteamSensor example folder. CMake can generate Visual Studio projects, make build files or even target IDEs such as Eclipse, or XCode. CMake generates a general description into a build for your specific toolchain or IDE.   Inside the specific example folder you would like to run, ie SteamSensor. Create a directory to build in, for this example call it bin. mkdir bin  cd bin Run the CMake command listed below. This assumes CMake is already on your PATH.         cmake ..​           CMake has now produced a set of project files which should be compatible with your development environment. Operating System        Command                                            Notes Unix make A set of make files Windows msbuild tw-c-sdk.sln /t:build A visual studio solution   NOTE: CMake does its best to determine what version of Visual Studio you have but you may wish to specify which version to use if you have more than one installed on your computer. Below is an example of forcing CMake to use a specific version of Visual Studio: cmake -G "Visual Studio 15 2017" .. If your version of Visual Studio or other IDE is unknown, use cmake -G to see a list of supported IDEs.   You also have the alternative of opening the tw-c-sdk.sln from within Visual Studio and building in this IDE.   NOTE: By default, CMake will generate a build for the creation of a release binary. If you want to generate a debug build, use the command:           cmake -DBUILD_DEBUG=ON ..           Once your build completes you will find the build products in the CMake directory (see example below). From here, open the project in your IDE of choice.   NOTE: You should receive messages confirming successful binding, authentication, and connection after the main.c file edits have been made.   Operating System Files Description Unix ./bin/src/libtwCSdk_static.a  Static Library Unix ./bin/src/libtwCSdk.so  Shared Library Unix ./bin/examples/SteamSensor/SteamSensor   Sample Application Windows .\bin\src\<Debug/Release>\twCSdk_static.lib  Static Library Windows .\bin\src\<Debug/Release>\twCSdk.dll  Shared Library Windows .\bin\examples\<Debug/Release>\SteamSensor\SteamSensor.exe  Sample Application   Click here to view Part 2 of this guide.  
View full tip
Why we need improve ThingWorx Query Performance? ThingWorx is good at injesting data from systems and devices and persisting data in Value Stream. When users build mashups/services which pull anything more than small amounts of data back, or have many users making queries at the same time, they encounter slow performance and/or server failure. Let's take a typical example which may happen among many of our end users: User A is currently gathering data from their edge devices and placing them in a Value Stream. About 80 properties are sharing the same Value Stream and they are estimating roughly 10 million rows a month of data into the platform. Their application requires querying large sections of this data and displaying aggregate info to certain mashups. A ton of work has been done to optimize these queries to make them as efficient as possible. However, querying with results larger than a few thousand rows causes RAM usage to spike so high, that the JVM runs out of heap space and brings down the server. What we have done to improve Query Performance in ThingWorx 8.2? 1. Improvements to the implementation of QueryPropertyHistory and QueryNamedPropertyHistory services:      1) These two query services are optimized by:          (1) Before ThingWorx 8.2, we query property history from database for each properties(imagine 80 properties in our example in the beginning), and then combine the            dataset(80 datasets in our example!) and display them in one table.          (2) In ThingWorx 8.2, we have replaced the "query for each property" with "single query for all properties"      2) Moved most of the query work to database level which is formally done post processing after grabing all the dataset from database including:          (1) Moved Combiner logic to database          (2) Moved Filter functionality in database Note: This improvement is only implemented on MS SQL and PostgreSQL, other persistence providers are not considered in this version, and this may be the plan for future release. 2. Improved string handling for the Query<Basetype>PropertyHistory services Memory reduction for these services are implemented by storing only one copy of each distinct string How much memory reduction could the Query Service Improvement bring QueryPropertyHistory and QueryNamedPropertyHistory Services From our internal test scenario we have seen approximately a 20% reduction in Thingworx platform memory utilization for these services with no Filter applied. Filtering may reduce memory an additional amount. Besides, a approximately 10% execution time saved as a result of this new improvement! Query<Basetype>PropertyHistory services Memory reduction is highly dependent on the stored data. From our internal test scenario, this improvement is providing up to 10% memory reduction on the platform. Note: This improvement is only implemented on MS SQL and PostgreSQL, so the memory reduction is not applied to other persistence providers. Best practice to call Query Services to improve Performance Although there are some Query service improvements in 8.2, still by following some rules or choosing a suitable service would bring extra performance improvement according to different use scenarios. From this point of view, this secion applies to all ThingWorx versions not specially for 8.2. 1. Limit the number of calls to the Query services from a given mashup/app       By repeatedly calling QueryPropertyHistory to display data may cause severe performance problems. Try to clean up unnecessary service calls in mashup and there should be a significant       improvement to the system.       Note: That was without any of the above improvements. 2. Use Query<BASETYPE>PropertyHistory service as much as possible     Unless customer needs to create a normalized dataset for multiple properties, try using QueryIntegerPropertyHistory, QueryStringPropertyHistory, etc. as they return smaller datasets and do not     use the combiner to normalize the data across a large number of properties. 3. Use QueryNamedPropertyHistory as much as possible     Similarly, QueryNamedPropertyHistory can provide a smaller dataset if you don’t need the values from all the properties on the Thing. So for example if a Thing has 10 logged properties but     you only need 3 returned; using QueryNamedPropertyHistory and identifying the three properties specifically needed will return a significantly reduced data set. 4. Use a Query to narrow down the dataset Where/when it makes sense, use a Query to narrow down the dataset; similarly to option 3, the returned dataset will be smaller. Note: this will have limited use scenario though. What needs to be done for end user when upgrading or utilize the service in ThingWorx 8.2 All the changes are transparent to the user! We improved the underlying implementation of the existing services so users won’t need to do anything after upgrade to see the improvements. There are no changes to the databases or schema.  
View full tip
Do you trust me? if (true) { why } else      { !why } Communication between client and server can be encrypted or not. Communication between client and server can be between trusted parties or not. Both statements are independant of each other. There's no need to trust a server - but still traffic can be encrypted. There's no need to encrypt traffic - but still a server can be trusted. For secure and safe communication in an IoT environment encryption as well as trust should be an integral part of exchanging data. ​ Trust Certificates and Chains of Trust Trust establishes the identity of the parties involved, e.g. is server I'm contacting really the server it pretends to be? This can be ensured with server certificates. On the other hand, client certificates ensure that the client is actual the client it pretends to be. This can be used as an authentication approach and if the identity of the server as well as the client is confirmed, this is also known as mutual authentication. Trust is usually invoked through certificates. Certificates have a subject, usually the servername that the certificate belongs to. This can also be a wildcard subject like *.myserver.com which will be valid for all subdomains of myserver.com. A certificate can be digitally signed to ensure its identity. Usually a Certificate Authority (CA) signs the certificate. This CA can in turn be signed by another CA and so an, creating a whole chain of CAs. This chain is commonly known as the Chain of Trust or the certification path. If a certificate is not signed by a CA it's called a "self-signed certificate". These are mostly used for test scenarios, but should never be used in real production environments. Certificates can also expire by using dates like "Valid From" and "Valid To" to determine if a certificate is valid or not. In case a certificate or CA is expired, all following certificates in the Chain of Trust will no longer be considered as valid. For "commercial" certificates, certificates that are signed by an official CA like Google, Let's Encrypt or VeriSign, a Certificate Signing Request (CSR) is used. For this a key-pair is generated and the CSR is signed with the private key. The CSR contains the public key and is sent to and finally signed by the CA itself, returning the public certificate e.g. signed by VeriSign. This mechanism allows to generate certificates by preparing the main information and just having the CA sign it as a trusted authority. Key-pair All certificates consist of a key-pair - a private key and a public key. The private key is indeed very private to the server and MUST NOT be shared with anyone else. The public key is indeed very public and can be shared with anyone. The key-pair consists of mainly two very large prime numbers and some mathematical magic allows for a mathematical one-way function ​with a trap door. This function allows to en-crypt any message with the public key and to de-crypt this message with the private key. So by giving out the public key to anyone, anyone can en-crypt a message to the server but only the server alone can de-crypt it with its private key. Therefore it's important that the private key is not shared with anyone, otherwise messages can be de-crypted by anyone possessing the private key and secure communication can be compromised. This method is called public-key encryption, or asymmetric encryption (as the key for en- and de-crypting are different). For more information, check out https://en.wikipedia.org/wiki/Public-key_cryptography This key-pair is not related to any encryption while sending data between client and server. Encryption on a transport level is accomplished by using different, random keys. It's just used to generate a unique certificate with a unique fingerprint as a public certificate. The private key part is amongst other things used for signing other certificates in the Chain of Trust. Tomcat needs access to the private key of the server specific certificate, to actually verify that the certificate is authentic. However, certificates can also be used for e.g. emails where the private key is in fact used to en- or decrypt the mail on a content level! ThingWorx ThingWorx is mainly configured for server side trust. In this case all connecting clients can ensure that the identity of the ThingWorx server is a trusted one - and not a fake server or an untrusted source. Certificates and trust are usually triggered when a secure connection is established, via TLS / SSL - e.g. by calling https://<myserver.com>:443/Thingworx The default port for a HTTPS (HTTP Secure / over TLS) connection is 443. For "normal" HTTP configuration, certificates are not required. Keystore To establish trust, any client needs to know the public certificate of the ThingWorx server. This is usually stored in a keystore. In ThingWorx, Tomcat needs to be configured with the location and the password of the keystore containing the certificate. For each web-request Tomcat will then present the server certificate to the client. The client can then verify through its own keystore if the certificate is trusted or not. When operating in browsers, this is done via e.g. the Windows-Keystore. For devices a custom, e.g. a Java-Keystore is required. The keystore must contain the whole Chain of Trust as well as the server specific certificate and its key. If the Chain of Trust is not stored completely in the keystore, or the key is missing / not accessible, the certificate validation process will already fail on server side. Certificates in Windows The default Windows-Keystore is actually pre-filled with lots of Root-Certificates, which start the Chain of Trust - such as Google, VeriSign or Microsoft. Trust needs to start somewhere… If the browser can trace the CAs of certificate back to a trusted Root CA, it's indicated by a green lock and the server will be trusted. If the Root CA cannot be found, it's indicated by a red lock (not a purse) - meaning that the server is not trusted. The server can still be contacted anyway, by manually acknowleding the risks (like identity theft or credit card scams). As an example, here's the certificate for Wikipedia and its Chain of Trust, starting with the GlobalSign Root CA: Trustworthy? In the end, certificates only clarify the identity of a server. If it is trusted or not, is completely up to the user / device. This trustful relationship all comes down to the client keystore / truststore. While the presenting server holds its certificate in the keystore, the verifying client holds the trusted certificates in the truststore. Any certificate in the truststore will ensure the correct server identity. Any unknown certificate will trigger a "Are you sure?" question in the browser. And as devices usually cannot respond to such a question, communication with an untrusted server can be forbidden by default. There are also products, like PTC Navigate which will require a client certificate to not only ensure server identity, but also ensure that also specific clients are able to connect to the server. Encryption No matter if a server is trusted or not, as soon as HTTPS is used as a protocol, communication will be encrypted. The certificate plays a role, but no matter if it's in the client's truststore, TSL forces encryption. Client Hello Usually the client contacts the server and sends a Client Hello. With this it also sends a list of available cipher suites, the intended receiver (server name) and a list of available Signature Hash Algorithms to be used. Cipher suites are used to determine which algorithms are used to establish a connection. The Signature Hash Algorithms define the Hash function, like SHA256 and the key / signature, like RSA. In my environment usually the Elliptic Curve Diffie-Hellman key exchange is used to transfer public keys between server and client. During the Client Hello information about the elliptic curves are also transferred. For more information on these topics, see https://en.wikipedia.org/wiki/SHA-2 https://en.wikipedia.org/wiki/RSA_(cryptosystem) https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange https://www.youtube.com/watch?v=YEBfamv-_do (Diffie-Hellman explained) https://en.wikipedia.org/wiki/Elliptic_curve_cryptography Server Hello After receiving the Client Hello, the server sends back the Server Hello. This consists of multiple handshakes. In this phase, the server sends the preferred cipher suite (intersection of client and server suites) including the Signature Hash Algorithm to be used. In the same step the server is sending off the certificate to the client for identity validation. For establishing trust and validating the certificate, the server needs to know the private key for the server specific certificate. The server also announces in the server key exchange what public key it's using for encryption to the client. This key is not related to the certificate, but a random number from a newly generated key-pair. Keys are exchanged between server and client and vice versa via the Diffie-Hellman key exchange. Client Response The client now sends in the client key exchange what public key it's using for encryption to the server. This is also a random key transmitted via the Diffie-Hellman key exchange. Initiating Communication After announcing the public keys, both server and client will now communicate encrypted by using their custom key-pairs for asymmetric encryption of the payloads. This can also include an additional change of the cipher specification. As the public keys have been exchanged via the Diffie-Hellman key exchange, server and client are now bi-directionally communicating using each other's public key to en-crypt a message and each's own private key to de-crypt the message again. For more information, also see https://tools.ietf.org/html/rfc5246 Trust & Encryption - Hands On Do you trust me now? if (true) { why } else      { !why } To see how this all works in a ThingWorx enviroment, and how easy it actually set up what has been discussed above, see also Trust &amp; Encryption - Hands On
View full tip
Hello, Since there have been discussions regarding SNMP capabilities when using the ThingWorx platform, I have made a guide on how you can manage SNMP content with the help of an EMS. Library used: SNMP4J - http://www.snmp4j.org/ Purpose: trapping SNMP events from an edge network, through a JAVA SDK EdgeMicroServer implementation then forwarding the trap information to the ThingWorx server. Background: There are devices, like network elements (routers, switches) that raise SNMP traps in external networks. Usually there are third party systems that collect this information, and then you can query them, but if you want to catch directly the trap, you can use this starter-kit implementation. Attached to this blog post you can find an archive containing the source code files and the entities that you will need for running the example, and a document with information on how to setup and run and the thought process behind the project. Regards, Andrei Valeanu
View full tip
I always find it difficult to remember which version of software is supported with which version of ThingWorx, so I created a table for my reference. I hope this is also helpful to other people.     Oracle JDK Tomcat Database Options Memo PostgreSQL Neo4J H2 Microsoft SQLServer SAP HANA DetaStax Enterprise Edition ThingWorx 6.5 1.8.0(64-bit) 8.0.23(64-bit) 9.4.4 embedded N/A N/A N/A N/A IE 10 ThingWorx 6.6 1.8.0(64-bit) 8.0.23(64-bit) 9.4.4 embedded N/A N/A N/A N/A   ThingWorx 7.0 1.8.0(64-bit) 8.0.23(64-bit) 9.4.? embedded N/A N/A N/A N/A   ThingWorx 7.1 1.8.0_92-b14(64-bit) 8.0.33(64-bit) 9.4.5 embedded N/A N/A N/A 4.6.3   ThingWorx 7.2 1.8.0_92-b14(64-bit) 8.0.33(64-bit) 9.4.5 embedded embedded N/A N/A 4.6.3 IE 11 and later ThingWorx 7.3 1.8.0_92-b14(64-bit) 8.0.38(64-bit) 9.4.5 embedded embedded N/A SPS 11, 12 4.6.3, 5   ThingWorx 7.4 1.8.0_92-b14(64-bit) 8.0.38(64-bit) 9.4.5 embedded embedded 2014 and later SPS 11, 12 4.6.3, 5   ThingWorx 8.0 1.8.0_92-b14(64-bit) 8.0.44(64-bit), 8.5.13(64-bit) 9.4.5 embedded embedded 2014 and later SPS 11, 12 4.6.3, 5   ThingWorx 8.1 1.8.0_92-b14(64-bit) 8.0.44(64-bit), 8.5.13(64-bit) 9.4.5 embedded embedded 2014 and later SPS 11, 12 4.6.3, 5   ThingWorx 8.2 1.8.0_92-b14(64-bit) 8.0.47(64-bit), 8.5.23(64-bit) 9.4.5 embedded embedded 2014 and later SPS 11, 12 4.6.3, 5   ThingWorx 8.3                  
View full tip
  Step 5: Launch the EMS   1. Navigate to the microserver directory. cd .. 2. Ensure that you have ownership to the executable wsems and executable privileges. To check ownership. Ls -la -rwxrwxr-x 1 pi pi 769058 Jun 9 17:46 wsems NOTE: The account that owns the wsems executable should be used to log into the Raspberry Pi.   3. Confirm that you have executable privileges by run the following command: sudo chmod 775 wsems 4. Run the EMS. sudo ./wsems 5. Validate that your EMS successfully connected.   Depending on your logger level, your wsems execution should indicate Websocket connected in the log and the following INFO message: [INFO ] 2016-10-11 14:22:54,770 Main: Succesfully connected. Saving .booted config file   Troubleshoot Connectivity Issues   If the websocket does not connect successfully, check the following:    Issue                                               Solution WEBSOCKET CLOSED - Warning seen immediately after Websocket gets connected. Ensure that the host IP address, port and appKey of the ThingWorx composer instance are accurately set. If in the config.json you have selected the option to validate certification, then make sure the path to the certificate file is correctly set. twWs_Connect - Error trying to connect. Ensure that the host IP address, port running the ThingWorx Composer is accurately set. Check if the certification parameter is set or not. By default the WS EMS validates certificates. To ensure that the validation is performed correctly without errors, ensure that the certificates configuration parameters are set accurately with the correct path to the certificate file. If you do not wish to validate the certificate, you may explicitly set the validate parameter in certificates parameter set to false. twTlsClient_Connect - Error intializing TLS connection. Invalid certificate. Check if the ws_encryption parameter is present in your config.json file. By default, WS EMS enables TLS connection to ThingWorx platform. Ensure that the certificate file mentioned in the config.json is valid and stored in the path specified in the config.json. For debugging purposes, you can set the ssl parameter to none in ws_encryption configuration parameter. [WARN ] ... Main - Unable to connect to server. Trying .booted config file. Ensure that the host is up and running at the IP address and port number mentioned in the config.json file. Ensure that ThingWorx is running on the host address at the correct port number. Ensure that all appropriate networking ports are open and available.     Step 6: Configure Lua Script Resource (LSR)   The Lua Script Resource (LSR) is used to implement Things on the Edge device. Using the Lua Script Resource, you can define for your Raspberry Pi: Data Shapes Properties Services Tasks NOTE: The steps in this guide install the LSR on the same server (Raspberry Pi) as the EMS but it could also be installed on another server.   Launch a new terminal session that will be used to configure and launch the LSR. Navigate to etc folder. cd microserver/etc Create the config.lua file. sudo nano config.lua Set the logger level. scripts.log_level = "INFO" Turn off encryption for connection to EMS. This should only be used for testing. scripts.script_resource_ssl = false scripts.script_resource_authenticate = false Create the Edge RemoteThing. scripts.PiThing = { file = "thing.lua", template = "PiTemplate", scanRate = 1000, taskRate = 30000 }   NOTE: This configuration tells the Lua Script Resource to create a Thing called PiThing whose template definition is in PiTemplate.lua file in the path etc/customs/templates/PiTemplate.lua. You will create the template file PiTemplate.lua in the next section.   Property    Description scanRate Controls how frequently (milliseconds) properties are evaluated and pushed to the server. In our example, the Pi will check every 1 second if the values have changed. If so, the values will be pushed to the server. taskRate Controls how frequently the tasks specified in the Thing's template should be executed. In our example, the task will run every 30 seconds.   7.  Set the IP and port address of the LSR host server. scripts.rap_host = "127.0.0.1" scripts.rap_port = 8080   Sample config.lua File   Here is an example of a complete config.lua that can be used to configure the Lua Script Resource.   scripts.log_level = "INFO" scripts.script_resource_ssl = false scripts.script_resource_authenticate = false scripts.PiThing = { file = "thing.lua", template = "PiTemplate", scanRate = 1000, taskRate = 30000 } scripts.rap_host = "127.0.0.1" scripts.rap_port = 8080     Step 7: Configure Template File (Properties)   The template file is located in the microserver/etc/custom/templates directory. The template file provides a base configuration for defining Properties, Services, tasks, etc. This section will focus on defining the template file and adding Properties.   Navigate from the installation directory to the templates folder at microserver/etc/custom/templates . cd microserver/etc/custom/templates Create the file PiTemplate.lua. sudo nano PiTemplate.lua NOTE: This is the same template filename used in config.lua in the previous section. 3. Define the template. The module statement is used to define the template containing the configuration for the software component of the edge device. module ("templates.PiTemplate", thingworx.template.extend)   Parameter                                   Description templates.PiTemplate refers to the name of the template file: PiTemplate.lua thingworx.template.extend identifies the file as a template and provides base Thingworx template implementation   4. Define the Properties. For this guide, we are going to use the Raspberry Pi’s system properties like CPU temperature, clock frequency and internal voltage as sensor readings for the Remote Thing. Add the properties for these in your PiTemplate.lua file. properties.cpu_temperature={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_freq={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_volt={baseType="NUMBER", pushType="ALWAYS", value=0} NOTE: This code defines the properties cpu_temperature, cpu_freq and cpu_volt with a baseType of NUMBER. Additionally, it sets each default value to null as well as sets the pushType to ALWAYS which means that the property is always pushed to the Thingworx Server from the Raspberry Pi. The pushType can be set to ALWAYS, ON, OFF, NEVER or VALUE.   Sample PiTemplate.lua File   Here is an example of a complete PiTemplate.lua that can be used to configure the Lua Script Resource. module ("templates.PiTemplate", thingworx.template.extend) properties.cpu_temperature={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_freq={baseType="NUMBER", pushType="ALWAYS", value=0} properties.cpu_volt={baseType="NUMBER", pushType="ALWAYS", value=0}     Click here to view Part 3 of this guide. 
View full tip
ThingWorx's JDBC extensions - Relational Database Management System and the JDBC Extensions allow ThingWorx to connect to variety of different databases. With that comes a natural question how and what sort of SQL statements could be executed via these extensions? Note: ​​Importing the JDBC extensions i.e. the RDBMS and JDBC Extensions, creates a Database Template for that particular database. If you are working with RDBMS extension then Template of corresponding Database will be created with similar name e.g. importing the RDBMS Extension for Oracle 12 will create Template named OracleDBServer12. While importing the JDBC driver using the JDBC extension will create Template name based on the JDBC driver used or a custom name could be given. Following examples and SQL statements are adhering to Oracle's SQL*Plus standard, however these can be easily adapted to the type of RDBMS you intend to work with. Topics How to create SQL Service in ThingWorx entity Types of SQL Statements Examples on SQL Service usage and some extended use cases / examples How to create SQL Service in ThingWorx Navigate to the Thing implementing the Database Template, e.g. OracleDBServer12         2. Click on the Services section under the Entity Information and click on Add My Service         3. A new service creation section will come up, change the Service type of JavaScript (this is default selection) to either SQL (Query) or SQL (Command) depending on the type of SQL you are to create under this particular service                       4. Here's quick example on creating SQL (Query) service which takes name as input for a select *  sql … Statement, i.e. it returns complete set of rows and columns from any given table on which the user has the access to perform Select                   Note: BaseType defaults to Infotable when creating SQL (Query) service and the returned number of rows are restricted to 500. Therefore, if table contains rows more than 500, ensure to change the Max Rows parameters         5. Example on creating SQL (Command) service that delete all the rows from the database table               Note: The Base Type defaults to Number when using SQL (Command)     Additional information:     When creating a SQL service, apart from providing changing the Service Info and  Inputs /Outputs, 3rd section Tables/Columns allows users to explore the Tables and their respective columns as part of that particular user's schema - meaning the objects on which the user has select rights in his schema in the database.     Types of SQLs This is not an exhaustive list, rather contains most commonly used types of SQL statements     1. Data Definition Language (DDL)           a. Create, Alter and drop schema objects           b. Grant and Revoke privileges and roles     2. Data Manipulation Language (DML)           a. Insert           b. Delete           c. Select Examples for SQL Service usage and some extended use cases / examples     1. Data Definition Language (DDL)           a. Create statement                       b. Alter statements                         c. Drop statement                         d. Flashback statements (Oracle specific)                         e. Grant statement                     f. Rename statement                 2. Data Manipulation Language (DML)           a. Insert statement                     b. Delete statement                     c. Select statements           Use cases - Case 1 : Backing up DataTable DataTable objects in ThingWorx are for quick lookup of data and they are most performant till ~100K rows. Exceeding rows over 100K in a DataTable makes it highly susceptible to performance issues in terms of querying or writing to it. Unless, there's sharding​ on the persistence provider or multiple persistence providers used - JDBC connectivity to external data stores like RDBMS systems could help in keeping up with growing number of rows in DataTables. RDBMS tables are more than capable of storing very large amount of rows without being taxed over the performance. JDBC extension could be used to do just that in a use case requiring backing up DataTable or any Data Storage objects from ThingWorx for that matter. Here's one quick example using one of the Insert SQL service shown above to back up the entire DataTable to the Oracle's DB table. Following ThingWorx JavaScript service wraps the InsertIntoBULKDATAINSERTDT SQL service: // result: INTEGER // getting total row count in the DataTable var totalCount = Things["BulkInsertDT"].GetDataTableEntryCount(); var params = { maxItems: totalCount /* NUMBER */ }; // result: INFOTABLE // DataTable service to fetch all the rows from it var allData = Things["BulkInsertDT"].GetDataTableEntries(params); // looping over the result fetched above to get all the rows for insertion     for (var i = 0; i<totalCount; i++) {         var result = allData.getRow(i); // mapping the data for insert     var params = {         LongCol3: result.LongCol3 /* LONG */,         numcol1: result.NumCol1 /* NUMBER */,         StringCol2: result.StringCol2 /* STRING */,         IntCol4: result.IntCol4 /* INTEGER */     }; try { // result: NUMBER // calling the SQL Service InsertIntoBULKDATAINSERTDT created under a DB Thing called OracleDBThingNew     var result = Things["OracleDBThingNew"].InsertIntoBULKDATAINSERTDT(params); } catch (err) {      Logger.info ("Failed to insert the values" + err) }     }
View full tip
A student in the Axeda Groovy course had some good questions. Instead of answering via email, I thought I'd answer here, so we could share the knowledge. Domain Objects - How can I customize or extend Axeda provided domain objects? (Eg., I need to store whether a user is external or internal user) How can I achieve this? This is a perfect use case for the Axeda Extended Data API. Documentation on the API can be found in the Axeda Platform v1 API Developer's Reference Guide. A good, "Getting Started," topic is available on Axeda Mentor - Getting Started With the Axeda Extended Data API. To customize/extend/decorate Axeda-provided domain objects, use Extended Objects. Extended Objects can be thought of in the abstract as a collection of custom database table rows. The analogy isn't perfect, but it helps with understanding. The use case in the question is very common. Extended Objects can stand on their own, or they can be associated with an Axeda domain object with the setInternalID() method. In the following sample code, we "decorate" an Axeda User object with two new fields, isExternalUser and companyID: private void updateAdditionalFieldsForUser(User user, boolean isExternalUser, String companyID) {   // GET OBJECT TYPE - This example assumes the ExtendedObjectType has already been created   ExtendedObjectType extObjectType = extendedObjectService.findExtendedObjectTypeByClassname("com.axeda.drm.sdk.user.User")   // GET PROPERTY TYPES   PropertyType isExternalUserPropertyType = findOrCreatePropertyType(extObjectType, "IS_EXTERNAL_USER")   PropertyType companyIdPropertyType = findOrCreatePropertyType(extObjectType, "COMPANY_ID")      /* GET THE EXTENDED OBJECT   * Note - the example provides a findExtendedObject() method that searches by INTERNAL ID. This linkage via the internal ID   * associates a domain object to an ExtendedObject, allowing us to "decorate" it with custom attributes   */   ExtendedObject extObject = findExtendedObject(extObjectType, user.id.value)   if (extObject == null)   {     extObject = new ExtendedObject()     extObject.setExtendedObjectType(extObjectType)     extObject.setInternalObjectId(user.id.value)     extObject.addProperty(createExtendedProperty(isExternalUserPropertyType, isExternalUser.toString()))     extObject.addProperty(createExtendedProperty(companyIdPropertyType, companyID))     extendedObjectService.createExtendedObject(extObject)   }   else   {     addOrUpdateExtendedProperty(extObject, isExternalUserPropertyType, "IS_EXTERNAL_USER", isExternalUser.toString())     addOrUpdateExtendedProperty(extObject, companyIdPropertyType, "COMPANY_ID", companyID)     extendedObjectService.updateExtendedObject(extObject)   } }  /**  * Adds or Updates an extended property.  *  * @param extendedObject the extended object to associate with the property  * @param propertyType the type of the property  * @param propertyName the name of the property  * @param propertyValue the value of the property  */ private void addOrUpdateExtendedProperty(ExtendedObject extendedObject, PropertyType propertyType, String propertyName, String propertyValue) {   Property extendedProperty = extendedObject.getPropertyByName(propertyName)   if (extendedProperty == null)   {   extendedProperty = createExtendedProperty(propertyType, propertyValue)   extendedObject.addProperty(extendedProperty)   }   else   {   extendedProperty.setValue(propertyValue)   } }  /**  * Retrieves and returns the extended object with the given type and internal id.  *  * @param extObjectType the type of the desired external object  * @param internalObjectId the internal id of the desired extended object  * @return the extended object matching the given details or <code>null</code> in case there's no match  */ private ExtendedObject findExtendedObject(ExtendedObjectType extObjectType, Long internalObjectId) {   ExtendedObjectSearchCriteria searchCriteria = new ExtendedObjectSearchCriteria()   searchCriteria.setExtendedObjectTypeId(extObjectType.getId())   searchCriteria.setInternalObjectId(internalObjectId)    List<ExtendedObject> extObjects = extendedObjectService.findExtendedObjects(searchCriteria, -1, 0, "name")    if (!extObjects?.isEmpty())   {    return extObjects[0]   }   return null }  /**  * Gets a property type given its name and the associated extended object type.  * If it cannot find the property type it will create it.  *  * @param extendedObjectType the associated extended object type for the property type  * @param propertyTypeName the property type name  * @return the property type  */  private PropertyType findOrCreatePropertyType(ExtendedObjectType extendedObjectType, String propertyTypeName)  {     PropertyType propertyType = extendedObjectType.getPropertyTypeByName(propertyTypeName)     if (propertyType == null)     {       propertyType = new PropertyType()       propertyType.setDataType(PropertyDataType.String)       propertyType.setName(propertyTypeName)       propertyType.setExtendedObjectType(extendedObjectType)       extendedObjectService.createPropertyType(propertyType)       extendedObjectType.addPropertyType(propertyType)     }     return propertyType  } By using Extended Objects, and associating them with Axeda domain objects via an internal ID, we can decorate/extend/customize those domain objects with use-case-specific attributes.
View full tip
Announcements