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:
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
Video Author:                      Asia Garrouj Original Post Date:            June 13, 2017 Applicable Releases:        ThingWorx Analytics 8.0   Description: This video is the first of a 3 part series walking you through how to setup ThingWatcher for Anomaly Detection. In this first video you will learn the basics of how to establish connectivity between KEPServer and the ThingWorx Platform.    
View full tip
Introduction to the base EMS connections and settings, what and how the websocket connections work, security, data transfer and bandwidth.     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 is an example for setting up remote desktop and file transfer for an asset in Thingworx Utilities using the Java Edge SDK. Step 1.   EMS Configuration ClientConfigurator config = new ClientConfigurator(); // application key RemoteAccessThingKey String appKey = "s2ad46d04-5907-4182-88c2-0aad284f902c"; config.setAppKey(appKey); // Thingworx server Uri config.setUri("wss://10.128.49.63:8445//Thingworx/WS"); config.ignoreSSLErrors(true); config.setReconnectInterval(15); SecurityClaims claims = SecurityClaims.fromAppKey(appKey); config.setSecurityClaims(claims);      // enable tunnels for the EMS config.tunnelsEnabled(true); // initialize a virtual thing with identifier PTCDemoRemoteAccessThing VirtualThing myThing = new VirtualThing(ThingName, "PTCDemoRemoteAccessThing", "PTCDemoRemoteAccessThing", client); **// for the file transfer functionality FileTransferVirtualThing myThing = new FileTransferVirtualThing(ThingName, "PTCDemoRemoteAccessThing", "PTCDemoRemoteAccessThing", client); myThing.addVirtualDirectory("AssetRepo",  "E:/AssetRepo"); Step 2.   Install TightVNC on the asset ( http://www.tightvnc.com/download.php ) Step 3.   Go to Thingworx Composer, search for thing PTCDemoRemoteAccessThing                 a.   pair  PTCDemoRemoteAccessThing with identifier PTCDemoRemoteAccessThing                 b.   go to PTCDemoRemoteAccessThing Configuration  and add a tunnel name: vnc host: asset IP port: 5900 (this is the default port for VNC servers; it can be changed)                 c.   go to PTCDemoRemoteAccessThing Properties and set the vncPassword Troubleshooting                 If the VNC server is on the same machine with the Thingworx server, check “Allow loopback connections” from Access Control tab in TightVNC Server Configuration.
View full tip
  Step 11: Users   Access to functions and information on the ThingWorx Foundation server is controlled by Users. The REST API can be used to create, list, and delete Users.   Get Usernames of all Users   The REST API exposes the ability to retrieve collections of Entities so that a UI can be dynamically updated with current data.   Required Parameters   AppKey created by your Foundation server Request   Construct the URL. Include the hostname and authentication credentials for your specific ThingWorx server as described below. The Usernames of all Users can be returned by making a GET request to this endpoint: 〈Server IP:port〉/Thingworx/Users Authenticate Request. All API requests to the ThingWorx server must be authenticated either with a username and password or with an appKey. For this example we will authenticate by passing the appKey as a URL query string parameter. The parameter appKey is recognized by the ThingWorx server as an authentication credential in requests, it can be passed either as a URL query string parameter .../CreateThing?appKey=64b87... , or as request header appKey: 64b87... Send request parameters. Other than authentication, no other parameters are used in this GET request. Response   It is possible for the content to be returned in four different formats by sending an Accept header with the request.   Desired Response Type  Accept Header Values JSON application/json XML text/xml HTML text/html (or omit Accept Header) CSV text/csv   HTTPie example:   http -v -j http://52.201.57.6/Thingworx/Users appKey==64b879ae-2455-4d8d-b840-5f5541a799ae Accept:text/csv       Step 12: Troubleshooting   You should expect to get back the status code of 200 - OK either with or without content. In the case of an error, you will receive an error message. You can use the following table to diagnose the issue.   Response Code Definition  401 - Unauthorized appKey is incorrect or missing 403 - Forbidden Content-Type request header is not set to application/json Sometimes returned instead of a 404 A Property with that name already exists on the platform 404 - Not Found Incorrect URL or API endpoint Thing or Property has not been created Incorrect ThingTemplate name Required parameter missing from request 405 - Invalid Request Incorrect request verb; for example a GET was used instead of PUT or POST 406 - Not Acceptable Invalid JSON in PUT or POST request Thing [ Thing name ] already exists: A Thing with that name already exists on the platform 500 - Internal Server Error Content-Type request header is not set for a service execution POST, required even without a POST body Content-Type request header is not set for DELETE request, required despite the fact that DELETE does not send any content 503 - Service Unavailable Thing [] is not running RestartThing endpoint must be called Thing [] is not enabled EnableThing endpoint must be called       Step 13: Authentication Tags   There are different ways to authorize requests.   AppKey in HTTP Request Header   We recommend you place the appKey in the HTTP request header rather than passing the appKey as a URL parameter. This prevents the appKey from being written into server log files that may be seen by someone who is not authorized to modify the ThingWorx server.   HTTPie example:   http -v -j http://iotboston.com:8887/Thingworx/Things/aTestThing/Properties/CurrentTemp appKey:d0a68eff-2cb4-4327-81ea-7e71e26 Full request headers:   GET /Thingworx/Things/AllenTestThingFour/Properties/CurrentTemp HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Type: application/json Host: iotboston.com:8887 appKey: d0a68eff-2cb4-4327-81ea-7e71e26bb   AppKey In URL as Parameter   To send an appkey in a URL request string parameter, check the Allow Application Key as URL Parameter checkbox in the PlatformSubsystem Configuration. If the ThingWorx server is using HTTPS, the parameter will be encrypted in transit, however the appKey may be comprised because full request URLs are often written to server log files.   HTTPie example:   http -v -j http://iotboston.com:8887/Thingworx/Things/AllenTestThingFour/Properties/CurrentTemp appKey==d0a68eff-2cb4-4327-81ea-7e71e26bb645 Full request headers:   GET /Thingworx/Things/aTestThing/Properties/CurrentTemp?appKey=d0a68eff-2cb4-4327-81ea-7e71e26 HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Connection: keep-alive Content-Type: application/json Host: iotboston.com:8887   HTTP Basic Auth   We do not recommend Basic Auth, because the username and password used are NOT encrypted and could be used to log into the ThingWorx platform. To demonstrate that username and password are not encrypted, copy the string in the Authorization line after Basic to Base64 Decode then click DECODE.   HTTPie example:   http -v -j http://iotboston.com:8887/Thingworx/Things/aTestThing/Properties/CurrentTemp -a Administrator:password1 Full request headers:   GET /Thingworx/Things/AllenTestThingFour/Properties/CurrentTemp HTTP/1.1 Accept: application/json, */* Accept-Encoding: gzip, deflate Authorization: Basic QWRtaW5pc3RyYXRvcjpwYXNzd29yZDE= Connection: keep-alive Content-Type: application/json Host: iotboston.com:8887     Step 14: Next Steps   Congratulations! You've successfully completed the Use REST API to Access ThingWorx guide. You learned how to use the REST API to:   Create new Things on a ThingWorx Foundation Server Add Properties to Things Access Property values Execute custom Services   The next guide in the Connect and Configure Industrial Devices and Systems learning path is Java SDK Tutorial.   Learn More   We recommend the following resources to continue your learning experience:      Capability Guide Build Data Model Introduction   Additional Resources   If you have questions, issues, or need additional information, refer to:   Resource    Link Community Developer Community Forum Support REST API Help Center    
View full tip
The purpose of this document is to see how you can setup an MXChip IoT DevKit and also how send the readings of this microprocessor to ThingWorx through an Azure cloud server. You will also learn how to view the values that are being sent.
View full tip
In case we would like to create an external application and we aren't sure what's the best solution to use, below are some useful tips. Scenario: Let's say we use a gateway in order to access the external application we want to create. We would like to implement this gateway translating the ThingWorx standard protocol to the SCADA protocol. The system administrator, who manages the grid, has the own secure system, with a standard for communication inside the SCADA system, and we want to be able to get data from our system to the system they have. Let's also consider that the data is connected on the electrical field. Tips: It is recommended to develop a 3rd party that on one side talks to ThingWorx, and on the other side, talks to the SCADA system. This external ThingWorx application that we want to implement would have a series-edge-interface allowing to enter in our customer's Ethernet network, in order for both systems to communicate. JDBC is not recommended - it's mostly for connecting to the data base, which in our case is not the main purpose. Each REST API call to the platform uses a security accreditation (appkey or user/password); depending of the permissions contained in that token, the access can be allowed to certain parts of the platform. Reasons for using REST API: REST API is simple and not dependent on any format that the data comes from ThingWorx. It can be used offline, online, synchronously, asynchronously, and is easy to manage from a formatting point of view. ThingWorx can give a lot of options: like exporting information via xml to a plain xml file, to parse it to whatever protocol we have on the other hand: Either our application would have to handle xml inputs from ThingWorx and process it towards SCADA compatible output. Or our application will have to handle xml input from ThingWorx and process it towards SCADA compatible output. Or we can talk directly via REST API and read on a per-thing basis (using the web services). The interface application just has to know how to read xmls or REST API calls (which are provided with an xml formatted response). SDK has already library written in C, C# and Java. SDK C, C# and Java use the AlwaysOn protocol (web socket)  and are more firewall friendly. It's mostly like for speed and automated processing, so when known exactly what happens and we trust the other side and we know there are little chances for errors.​ If we go with REST API or SDK , the application that is developed will have complete access inside ThingWorx, like change/edit the things. If we want to have access in both ways, not only in reading data, but also in update/delete information, etc, SDK and REST API ​can be used, because we have the whole range of commands, like set property values, call on services, etc. We can limit access, if we want, for security reasons. SDK offers access to the same services as REST API, but in a different way. Otherwise, it's better to go with xml decoupled files. Conclusion: for this particular scenario, better use SDK.
View full tip
If the ThingWorx 7.4 installation with MSSQL db doesn't start with a license error on the splash screen, despite taking the necessary steps for specifying the license path, the error might be misleading and the problem is actually lying in the database connection. Going to THingworxStorage/logs and opening ApplicationLog.log might reveal the following (or similar ) errors: 2017-04-13 10:26:17.993-0400 [L: INFO] [O: c.t.s.ThingWorxServer] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] Sending Post Start Notifications... 2017-04-13 10:26:17.999-0400 [L: ERROR] [O: c.t.p.m.MssqlModelExceptionTranslator] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] [message: Could not create a transaction for ThingworxPersistenceProvider] 2017-04-13 10:26:18.001-0400 [L: ERROR] [O: E.c.t.p.d.FileTransferDocumentModelProvider] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] [context: Could not create a transaction for ThingworxPersistenceProvider][message: Could not create a transaction for ThingworxPersistenceProvider] 2017-04-13 10:26:18.004-0400 [L: ERROR] [O: c.t.p.m.MssqlModelExceptionTranslator] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] [message: Could not create a transaction for ThingworxPersistenceProvider] 2017-04-13 10:26:18.005-0400 [L: ERROR] [O: c.t.s.s.f.FileTransferSubsystem] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] Error loading queued transfer jobs from persistence provider 2017-04-13 10:26:18.006-0400 [L: ERROR] [O: c.t.p.m.MssqlModelExceptionTranslator] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] [message: Could not create a transaction for ThingworxPersistenceProvider] 2017-04-13 10:26:18.006-0400 [L: ERROR] [O: E.c.t.p.d.FileTransferDocumentModelProvider] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] [context: Could not create a transaction for ThingworxPersistenceProvider][message: Could not create a transaction for ThingworxPersistenceProvider] 2017-04-13 10:26:18.007-0400 [L: ERROR] [O: c.t.p.m.MssqlModelExceptionTranslator] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] [message: Could not create a transaction for ThingworxPersistenceProvider] 2017-04-13 10:26:18.008-0400 [L: ERROR] [O: c.t.s.s.f.FileTransferSubsystem] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] Error loading queued transfer jobs from persistence provider 2017-04-13 10:26:18.008-0400 [L: INFO] [O: c.t.s.ThingWorxServer] [I: ] [U: SuperUser] [S: ] [T: localhost-startStop-1] Thingworx Server Application...ON A few things to check here. First, how the database was set up. The standard expected port if 1433, however, if you choose a different port - ensure that the port is available. If it isn't - update the port setting in SQL configuration manager. Another possible root cause -- the database scripts did not run properly upon the setup. Currently, there is an active Jira PSPT-3587 for resolving the script issue (NOTE, this thread to be updated once the Jira is fixed). There are two options here, either to run the sql files manually (found in the "install" folder of the downloadable), or edit the bat scripts manually. It's recommended to edit the script files instead because running the sql commands allows more room for a mistake. The following line in the bat scripts needs to be edited to have the ".\" removed: sqlcmd.exe -S %server%\%serverinstance%,%port% -U %adminusername% -v loginname=%loginname% -v database=%database% -v thingworxusername=%thingworxusername% -v schema=%schema%  -i .\thingworx-database-setup.sql Note, that the scripts need to be run from the same directory ("/install")
View full tip
Attached to this article is my slide deck from Liveworx 2016 titled "Getting Mobile with ThingWorx and Android". It is an overview of the ThingWorx android SDK which had its 1.0 release this past April. Also attached is the Light Blue Bean bluetooth integration example I demoed at the show.
View full tip
Objective Learn how the Scripto Web Service helps you to present platform information in your HTML with JavaScript and dynamic page updating.  After this tutorial, you will know how to create Axeda Custom Objects that return formatted results to JavaScript using XmlHttpResponse, and how a very simple page can incorporate platform data into your browser-based user interface. Part 1 - Simple Scripto In Using Scripto, you learned how Scripto can be called from very simple clients, even the most basic HTTP tools. This tutorial builds on the examples in that tutorial. The following HelloWorld script accepts a parameter named "foo". This means that the caller of the script may supply a value for this parameter, and the script simple returns a message that includes the value supplied. import static com.axeda.sdk.v2.dsl.Bridges.* import com.axeda.services.v2.* import com.axeda.sdk.v2.exception.* return "Hello world, ${parameters.foo}" In the first part of this tutorial, we'll be creating an HTML page with some JavaScript that simply calls the HelloWorld script and puts the result on the page. Create an HTML File Open up your favorite text editor and create a blank document. Paste in this simple scaffold, which includes a very simple FORM with fields for your developer platform email and password, and the "foo" parameter. <html> <head> <title>Axeda Developer Connection Simple Ajax HelloWorld Example</title> </head> <body> <form name="f1">         Platform email (login): <input name="username" type="text"><br/>         Password: <input name="password" type="password"><br/>         foo: <input name="foo" type="text"><br/> <input value="Go" type="button" onclick='JavaScript: callScripto()'/></p> <div id="result"></div> </form> </body> </html> Pretty basic HTML that you've seen lots of times. Notice the form onclick refers to a JavaScript function. We'll be adding that next. Add the JavaScript Directly under the <title> tag, add the following <script language="Javascript"> var scriptoURL ="http://dev6.axeda.com/services/v1/rest/Scripto/execute/"; var scriptName ="HelloWorld2"; </script> This defines our JavaScript block, and a couple of constants to tell our script where the server's Scripto REST endpoint is, and the name of the script we will be running. Let's add in our callScripto() function. Paste the following directly under the scriptName variable declaration: function callScripto(){ try{                 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); }catch(e){ // must be IE }    var xmlHttpReq =false;    var self =this;    // Mozilla/Safari    if(window.XMLHttpRequest){                 self.xmlHttpReq =new XMLHttpRequest();    }// IE elseif(window.ActiveXObject){                 self.xmlHttpReq =new ActiveXObject("Microsoft.XMLHTTP"); }    var form = document.forms['f1'];    var username = form.username.value;    var password = form.password.value;    var url = scriptoURL + scriptName +"?username="+ username +"&password="+ password;             self.xmlHttpReq.open('POST', url,true);             self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');             self.xmlHttpReq.onreadystatechange =function() {       if(self.xmlHttpReq.readyState ==4){                     updatepage(self.xmlHttpReq.responseText);       }    }    var foo = form.foo.value;    var qstr ='foo='+escape(foo);    self.xmlHttpReq.send(qstr); } That was a lot to process in one chunk, so let's examine each piece. This piece just tells the browser that we'll be wanting to make some Ajax calls to a remote server. We'll be running the example right off a local file system (at first), so this is necessary to ask for permission. try{                 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); }catch(e){ // must be IE } This part creates an XmlHttpRequest object, which is a standard object available in browsers via JavaScript. Because of slight browser differences, this code creates the correct object based on the browser type. var xmlHttpReq =false; var self =this; // Mozilla/Safari if(window.XMLHttpRequest){                 self.xmlHttpReq =new XMLHttpRequest(); } // IE elseif(window.ActiveXObject){                 self.xmlHttpReq =new ActiveXObject("Microsoft.XMLHTTP"); } Next we create the URL that will be used to make the HTTP call. This simply combines our scriptoURL, scriptName, and platform credentials. var form = document.forms['f1']; var username = form.username.value; var password = form.password.value; var url = scriptoURL + scriptName +"?username="+ username +"&password="+ password; Now let's tell the xmlHttpReq object what we want from it. we'll also reference the name of another JavaScript function which will be invoked when the operation completes. self.xmlHttpReq.open('POST', url,true);     self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');     self.xmlHttpReq.onreadystatechange =function(){ if(self.xmlHttpReq.readyState ==4){             updatepage(self.xmlHttpReq.responseText); } } Finally, for this function, we'll grab the "foo" parameter from the form and tell the prepped xmlHttpReq object to post it. var qstr ='foo='+escape(foo);     self.xmlHttpReq.send(qstr); almost done. We just need to supply the updatepage function that we referenced above. Add this code directly before the </script> close tag: function updatepage(str){             document.getElementById("result").innerHTML = str; } Try it out Save your file as helloworld.html and open it in a browser by starting your browser and choosing "Open File". You can also download a zip with the file prepared for you at the end of this page. If you are using Internet Explorer, IE will pop a bar asking you if it is OK for the script inside this page to execute a script. Choose "Allow Blocked Content". Type in your platform email address (the address you registered for the developer connection with) and your password. Enter any text that you like for "foo". When you click "Go", the area below the button will display the result of the Scripto call. Note that if you are using Mozilla Firefox, you will be warned about the script wanting to access a remote server. Click "Allow". Congratulations! You have learned how to call a Custom Object-backed Scripto service to display dynamic platform content inside a very simple HTML page. Next Steps Be sure to check out the tutorial on Hosting Custom Applications to learn how you can make this page get directly served from your platform account, with its very own URL. Also explore code samples that show more sophisticated HTML+AJAX examples using Google Charts and other presentation tools.
View full tip
This Expert Session is designed to help beginners get up and running with ThingWorx Analytics. It covers basic concepts like: What are APIs, how to configure the metadata file, and a live Demo that shows you how to interact and use ThingWorx Analytics in real time. This Expert Session would also be useful for experienced users who need a refresher course.   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
Every edge component that connects to the ThingWorx platform requires an Application Key.  This 'AppKey' provides both authentication and authorization control.  When an edge component connects it steps through a connection process.  The second step of that process is to send the AppKey to the platform.  The platform will inspect the key and ensure that it is valid.  It also creates a session for that edge connection and associates the AppKey with the session.  Any future requests that are sent over that AlwaysOn connection will execute under the security context configured for the user associated with the AppKey. In order for edge applications to interact with the platform they require a certain set of permissions.  It is a best practice to not associate the Administrator user with an Application Key.  Doing this would allow an edge application to invoke any and all services on the platform, and to modify the property values of any thing.  The permissions applied to an edge component's AppKey should be the minimum set required for your application to function. The AppKey associated with an edge component is typically associated with a single Thing, or a collection of Things, usually of the same ThingTemplate.  Identify the Thing(s) or ThingTemplate(s) that your application will interact with.  There are four types of interactions for edge components: property reads, property writes, service invocations, and event executions (edge components do not subscribe to events).  These four types of interactions match the runtime permissions that can be configured on a Thing, or the 'run time instance' permissions for a ThingTemplate. If an edge application will be reading or writing all properties of a particular Thing, then applying the 'read property' and 'write property' permissions is appropriate.  If only a select set of a Thing's properties will be read or written, then read and/or write permission should be disabled, and only the select properties should be enabled using overrides. Since every Thing has a number of generic services, the 'service execute' permission should be disabled, and overrides should be configured for the selected services that the edge needs access to.  In addition, overrides should be configured for the 'UpdateSubscribeProeprtyValues' service and for the 'ProcessRemoteEvents' service.  Edge components often use these service to update a collection of properties or to fire a set of events. Finally, if your edge application triggers events on a Thing, overrides should be used to provide execute permission for those events. In summary, the safest path to configuring edge permissions is to create a new user and AppKey with no permissions applied, and to then selectively apply permissions for that user only on the Thing or Things that your edge components will interact with.
View full tip
GOBOT Framework GOBOT is a framework written in Go programming language. Useful for connecting robotic components, variety of hardware & IoT devices.   Framework consists of Robots -> Virtual entity representing rover, drones, sensors etc. Adaptors -> Allows connectivity to the hardware e.g. connection to Arduino is done using Firmata Adaptor, defining how to talk to it Drivers -> Defines specific functionality to support on specific hardware devices e.g. buttons, sensors, etc. API -> Provides RESTful API to query Robot status There are additional core features of the framework that I recommend having a look esp. Events, Commands allowing Subscribing / Publishing events to the device for more refer to the doc There's already a long list of Platforms for which the drivers and adaptors are available. For this blog I will be working with Arduino + Garmin LidarLite v3. There are cheaper versions available for distance measurement, however if you are looking for high performance, high precision optical distance measurement sensor, then this is it. Pre-requisite Install Go see doc Install Gort Install Gobot Wire-up LidarLite Sensor with Arduino How to connect For our current setup I have Arduino connected to Ubuntu 16 over serial port, see here if you are looking for a different platform.   For ubuntu you just need following 3 commands to connect and upload the firmata as our Adaptor to prepare Arduino for connectivity   // Look for the connected serial devices $ gort scan serial // install avrdude to upload firmata to the Arduino $ gort arduino install // uploading the firmata to the serial port found via first scan command, mine was found at /dev/ttyACM0 $ gort arduino upload firmata /dev/ttyACM0 Reading Sensor data Since there is a available driver for the LidarLite, I will be using it in the following Go code below in a file called main.go which connects and reads the sensor data.   For connecting and reading the sensor data we need the driver, connection object & the task / work that the robot is supposed to perform. Adaptor firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") // this the port on which for me Arduino is connecting Driver As previously mentioned that Gobot provides several drivers on of the them is LidarLite we will be using this like so   d := i2c.NewLIDARLiteDriver(firmataAdaptor) Work Now that we have the adaptor & the driver setup lets assign the work this robot needs to do, which is to read the distance work := func() { gobot.Every(1*time.Second, func() { dist, err := d.Distance() if err != nil { log.Fatalln("failed to get dist") } fmt.Println("Fetching the dist", dist, "cms") }) } Notice the Every function provided by gobot to define that we want to perform certain action as the time lapses, here we are gathering the distance.   Note: The distance returned by the lidarLite sensor is in CMs & the max range for the sensor is 40m Robot Now we create the robot representing our entity which in this case is simple, its just the sensor itself   lidarRobot := gobot.NewRobot("lidarBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{d}, work)   This defines the vitual representation of the entity and the driver + the work this robot needs to do. Here's the complete code. Before running this pacakge make sure to build it as you likely will have to execute the runnable with sudo. To build simply navigate to the folder in the shell where the main.go exists and execute   $ go build   This will create runnable file with the package name execute the same with sudo if needed like so   $ sudo ./GarminLidarLite   And if everything done as required following ouput will appear with sensor readings printed out every second 2018/08/05 22:46:54 Initializing connections... 2018/08/05 22:46:54 Initializing connection Firmata-634725A2E59CBD50 ... 2018/08/05 22:46:54 Initializing devices... 2018/08/05 22:46:54 Initializing device LIDARLite-5D4F0034ECE4D0EB ... 2018/08/05 22:46:54 Robot lidarBot initialized. 2018/08/05 22:46:54 Starting Robot lidarBot ... 2018/08/05 22:46:54 Starting connections... 2018/08/05 22:46:54 Starting connection Firmata-634725A2E59CBD50 on port /dev/ttyACM0... 2018/08/05 22:46:58 Starting devices... 2018/08/05 22:46:58 Starting device LIDARLite-5D4F0034ECE4D0EB... 2018/08/05 22:46:58 Starting work... Fetching the dist 166 cms Fetching the dist 165 cms Fetching the dist 165 cms Here's complete code for reference   package main import ( "fmt" "log" "time" "gobot.io/x/gobot" "gobot.io/x/gobot/drivers/i2c" "gobot.io/x/gobot/platforms/firmata" ) func main() { lidarLibTest() } // reading Garmin LidarLite data func lidarLibTest() { firmataAdaptor := firmata.NewAdaptor("/dev/ttyACM0") d := i2c.NewLIDARLiteDriver(firmataAdaptor) work := func() { gobot.Every(1*time.Second, func() { dist, err := d.Distance() if err != nil { log.Fatalln("failed to get dist") } fmt.Println("Fetching the dist", dist, "cms") }) } lidarRobot := gobot.NewRobot("lidarBot", []gobot.Connection{firmataAdaptor}, []gobot.Device{d}, work) lidarRobot.Start() }
View full tip
Does WSEMS use SSL pinning? Yes, it does. To explain the process a bit more, the ssl pinning is the act of verifying a server certificate by comparing it to the exact certificate that is expected. We “install” a certificate on the EMS (copying the cert to the ems device, and specifying the cert in config.json), EMS will then check all incoming certs against the cert in config.json, looking for an exact match and verifying the certificate chain. Should it be expected that the client, WSEMS.exe, installs the client certificate in order to validate the server certificate using SSL pinning? This does not happen automatically, the cert must be downloaded and manually added to the device. The config must also be manually updated. If so, how we issue the client cert for WSEMS.exe? Does it need to be issued the same way as the server certificate? If talking about pinning, one could use either the server cert directly, or the root cert (recommended). The root cert is the public cert of the signing authority, e.g. if the server uses a verisign issued cert, one can verify the authenticity of the signer by having the verisign public cert. If talking about client certs (2 way auth, client verifies server, server verifies client) then the process is a little different. What happens when the client certificate expires? Do all the devices go offline when the client certificate expires? The device won’t connect with a failure to authorize. Once the server cert expires, the server cert needs to be updated everywhere. This is the advantage to using something like the verisign public cert (root cert) as the installed cert on the client. The root certs usually last longer than the issued certs, but they will have to replaced eventually when they expire. When using Entrust certificates, obtained at https://www.entrust.com/get-support/ssl-certificate-support/root-certificate-downloads/ , how do we know that the certifactes are fed to the WSEMS configuration incorrectly? With the wrong configuration, WSEMS would error out rejecting the Entrust certificate: Non-fips Error code 20: Invalid certificate Fips: Error code 19:  self signed certificate in certificate chain How to properly install Entrust certificate to be accessed by EMS? Public certificate needs to be downloaded and put in a directory that is accessible to the EMS. The path to be added to the cert chain field of the configuration. Even if its trusted it will always need to be installed on the EMS. If a certificate is self-signed, meaning it's non-trusted by default, OpenSSL would throw errors and compain. To solve this, it needs to be installed as a trusted server. If it's signed by a non-trusted CA, that CA's certificate needs to be installed as well. Once the certificates are obtained this if the block of the configuration we are interested in: "certificates":    {                   "validate":          true, //Not validated model is not recommended                       "allow_self_signed":  false, //Self signed model is not recommended, yet theoretically better than non-validated                       "cert_chain":      " " } //recommended, trusted - also the only way to work with a FIPS enabled EMS May use the SSL test tool (for example,https://www.ssllabs.com )to find all chains. For Entrust, both Entrust L1k and G2 need to be downloaded: Because cert_chain is an array type of field, the format to install the certificates paths, would be: "cert_chain": ["path1"], ["path2"] "cert_chain": ["C:\\ThingworxLocation\\MicroServerLocation\\locationofcertificates\\entrust_l1k.pem","C:\\ThingworxLocation\\MicroServerLocation\\locationofcertificates\\entrust_g2_ca.pem"]
View full tip
  Build authentications extensions quickly and add to the security of your application.   GUIDE CONCEPT   Extensions enable you to quickly and easily add new functionality to an IoT solution. Extensions can be service (function/method) libraries, connector templates, functional widgets, and more.   These pointers and steps will enable you to maintain focus on development of your own application and still utilize the power of ThingWorx for other purposes at the same time.   When to Utilize:   You have your own login from outside of ThingWorx but you want to leverage ThingWorx user management You are using an identity provider other than ThingWorx You need to support passing of credentials in headers/query string parameters which ThingWorx doesn’t support out-of-the-box   Concept   Whether you would like ThingWorx to handle the security for your application, have an application you want ThingWorx to pump data into, or would just like to utilize ThingWorx features in your own application, external authentication can be a great way to integrate your application with ThingWorx. This guide will focus in on how to create an authentication middle man between a system you have already developed (or are in the middle of creating) and connect it to the ThingWorx Platform. In a provided demo website, you will login (with the provided credentials) and validate your user profile and password with ThingWorx. This setup shows the simple integration between ThingWorx and an application you would like to connect to the ThingWorx Platform.   YOU'LL LEARN HOW TO   Install the Eclipse plugin and extension SDK Create authentication application Build and import an extension   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 60 minutes.        Step 1: Completed Example   Download the completed files for this tutorial: AuthenticationExtension.zip   This tutorial will guide you through security concepts within ThingWorx. Utilize this file to see a finished example and return to it as a reference if you become stuck creating your own fully flushed out application.   Keep in mind, this download uses the exact names for entities used in this tutorial. If you would like to import this example and also create entities on your own, change the names of the entities you create. The download contains three directories (Source, CompletedExtension, and Demo). See below for the information about each directory.     Directory Description Source The completed project and source code to be utilized as a comparison or ready to go pre-built extension. CompletedExtension A completed and built extension that is based on the steps utilized in the latter steps. The zip file in this directory can be imported directly. Demo A demo web page that shows easy integration of an external application and ThingWorx authentication.       Step 2: Understanding Authenticators   Authentication between ThingWorx and custom outside applications begins with Authenticators.  Authenticators are the component integration point that allows for custom authentication schemes to be added into the ThingWorx platform. Authenticators can be used to retrieve content, parameters, headers, etc from HTTP requests.   The retrieved data can be verified by the authenticator using its implemented/configured verification  algorithm(s). If that data is of a username/password credential type the authenticator can choose to pass validation of that data to the configured list of Directory Services. For example, the internal ThingWorx username/password store, or delegate to an external Active Directory set of username/passwords.   ThingWorx tries to authenticate in increasing order of priority. In example, starting with  ThingworxBasicAuthenticator, unless a custom authenticator is given higher priority than that, ThingWorx will continue trying enabled authenticators by priority until one succeeds.   If an authenticator has priority 1, it will be consulted first in the chain of authenticators. If the authenticator has a priority of 101, it will be consulted after the ThingworxBasicAuthenticator (with priority of 100) fails to authenticate the HTTP request. There are several built-in authenticators   Authenticator Priority Editable ThingworxBasicAuthenticator 100 No ThingworxMobileTokenAuthenticator 150 Yes ThingworxApplicationKeyAuthenticator 200 No ThingworxSSOAuthenticator 250 Yes ThingworxFormAuthenticator 300 No ThingworxMobileAuthorizationAuthenticator 350 Yes ThingworxHttpBasicAuthenticator 400 No   When all configured and enabled authenticators fail to validate the data provided by an HTTP request, an authentication failure response is sent back to the requesting client. Custom Authenticators can be given priority such that they fit into any part of this process.   For setting the priority follow the instructions below:   Navigate to and select Security > Authenticators.   Select the Authenticator you would like to edit (ie, ThingworxSSOAuthenticator). If you do not see a specific Authenticator you would like to VIEW ONLY, check the Show System Objects checkbox in your search filter.   Update the Priority field with a new value. Click Save.       Step 3: Download Plugin and SDK   The ThingWorx Extension SDK provides supported classes and APIs to build Java-based extensions. The APIs included in this SDK allow manipulation of ThingWorx platform objects to create Java based extensions that can extend the capability of the existing ThingWorx platform.   The Eclipse Plugin assists in working with the Extension SDK to create projects, entities, and samples.   Download the Eclipse Plugin. Download Extensions SDK. Make a note of the directory where the plugin and the extension SDK are stored. The path of the directory will be required in upcoming steps. Do not extract the zip files.     Click here to view Part 2 of this guide.
View full tip
This is a follow-up post on my initial document about Edge Microserver (EMS) and Lua Script Resource (LSR) security. While the first part deals with fundamentals on secure configurations, this second part will give some more practical tips and tricks on how to implement these security measurements.   For more information it's also recommended to read through the Setting Up Secure Communications for WS EMS and LSR chapter in the ThingWorx Help Center. See also Trust & Encryption Theory and Hands On for more information and examples - especially around the concept of the Chain of Trust, which will be an important factor for this post as well.   In this post I will only reference the High Security options for both, the EMS and the LSR. Note that all commands and directories are Linux based - Windows equivalents might slightly differ.   Note - some of the configuration options are color coded for easy recognition: LSR resources / EMS resources   Password Encryption   It's recommended to encrypt all passwords and keys, so that they are not stored as cleartext in the config.lua / config.json files.   And of course it's also recommended, to use a more meaningful password than what I use as an example - which also means: do not use any password I mentioned here for your systems, they might too easy to guess now 🙂   The luaScriptResource script can be used for encryption:   ./luaScriptResource -encrypt "pword123" ############ Encrypted String AES:A26fBYKHJq+eMu0Fm2FlDw== ############   The wsems script can be used for encryption:   ./wsems -encrypt "pword123" ############ Encrypted String AES:A26fBYKHJq+eMu0Fm2FlDw== ############   Note that the encryption for both scripts will result in the same encrypted string. This means, either the wsems or luaScriptResource scripts can be used to retrieve the same results.   The string to encrypt can be provided with or without quotation marks. It is however recommended to quote the string, especially when the string contains blanks or spaces. Otherwise unexpected results might occur as blanks will be considered as delimiter symbols.   LSR Configuration   In the config.lua there are two sections to be configured:   scripts.script_resource which deals with the configuration of the LSR itself scripts.rap which deals with the connection to the EMS   HTTP Server Authentication   HTTP Server Authentication will require a username and password for accessing the LSR REST API.     scripts.script_resource_authenticate = true scripts.script_resource_userid = "luauser" scripts.script_resource_password = "pword123"     The password should be encrypted (see above) and the configuration should then be updated to   scripts.script_resource_password = "AES:A26fBYKHJq+eMu0Fm2FlDw=="   HTTP Server TLS Configuration   Configuration   HTTP Server TLS configuration will enable TLS and https for secure and encrypted communication channels from and to the LSR. To enable TLS and https, the following configuration is required:     scripts.script_resource_ssl = true scripts.script_resource_certificate_chain = "/pathToLSR/lsrcertificate.pem" scripts.script_resource_private_key = "/pathToLSR/key.pem" scripts.script_resource_passphrase = "keyForLSR"     It's also encouraged to not use the default certificate, but custom certificates instead. To explicitly set this, the following configuration can be added:     scripts.script_resource_use_default_certificate = false     Certificates, keys and encryption   The passphrase for the private key should be encrypted (see above) and the configuration should then be updated to     scripts.script_resource_passphrase = "AES:A+Uv/xvRWENWUzourErTZQ=="     The private_key should be available as .pem file and starts and ends with the following lines:     -----BEGIN ENCRYPTED PRIVATE KEY----- -----END ENCRYPTED PRIVATE KEY-----     As it's highly recommended to encrypt the private_key, the LSR needs to know the password for how to encrypt and use the key. This is done via the passphrase configuration. Naturally the passphrase should be encrypted in the config.lua to not allow spoofing the actual cleartext passphrase.   The certificate_chain holds the Chain of Trust of the LSR Server Certificate in a .pem file. It holds multiple entries for the the Root, Intermediate and Server Specific certificate starting and ending with the following line for each individual certificate and Certificate Authority (CA):     -----BEGIN CERTIFICATE----- -----END CERTIFICATE-----     After configuring TLS and https, the LSR REST API has to be called via https://lsrserver:8001 (instead of http).   Connection to the EMS   Authentication   To secure the connection to the EMS, the LSR must know the certificates and authentication details for the EMS:     scripts.rap_server_authenticate = true scripts.rap_userid = "emsuser" scripts.rap_password = "AES:A26fBYKHJq+eMu0Fm2FlDw=="     Supply the authentication credentials as defined in the EMS's config.json - as for any other configuration the password can be used in cleartext or encrypted. It's recommended to encrypt it here as well.   HTTPS and TLS   Use the following configuration establish the https connection and using certificates     scripts.rap_ssl = true scripts.rap_cert_file = "/pathToLSR/emscertificate.pem" scripts.rap_deny_selfsigned = true scripts.rap_validate = true     This forces the certificate to be validated and also denies selfsigned certificates. In case selfsigned certificates are used, you might want to adjust above values.   The cert_file is the full Chain of Trust as configured in the EMS' config.json http_server.certificate options. It needs to match exactly, so that the LSR can actually verify and trust the connections from and to the EMS.   EMS Configuration   In the config.lua there are two sections to be configured:   http_server which enables the HTTP Server capabilities for the EMS certificates which holds all certificates that the EMS must verify in order to communicate with other servers (ThingWorx Platform, LSR)   HTTP Server Authentication and TLS Configuration   HTTP Server Authentication will require a username and password for accessing the EMS REST API. HTTP Server TLS configuration will enable TLS and https for secure and encrypted communication channels from and to the EMS.   To enable both the following configuration can be used:   "http_server": { "host": "<emsHostName>", "port": 8000, "ssl": true, "certificate": "/pathToEMS/emscertificate.pem", "private_key": "/pathToEMS/key.pem", "passphrase": "keyForEMS", "authenticate": true, "user": "emsuser", "password": "pword123" }   The passphrase as well as the password should be encrypted (see above) and the configuration should then be updated to   "passphrase": "AES:D6sgxAEwWWdD5ZCcDwq4eg==", "password": "AES:A26fBYKHJq+eMu0Fm2FlDw=="   See LSR configuration for comments on the certificate and the private_key. The same principals apply here. Note that the certificate must hold the full Chain of Trust in a .pem file for the server hosting the EMS.   After configuring TLS and https, the EMS REST API has to be called via https://emsserver:8000 (instead of http).   Certificates Configuration   The certificates configuration hold all certificates that the EMS will need to validate. If ThingWorx is configured for HTTPS and the ws_connection.encryption is set to "ssl" the Chain of Trust for the ThingWorx Platform Server Certificate must be present in the .pem file. If the LSR is configured for HTTPS the Chain of Trust for the LSR Server Certificate must be present in the .pem file.   "certificates": { "validate": true, "allow_self_signed": false, "cert_chain" : "/pathToEMS/listOfCertificates.pem" } The listOfCertificates.pem is basicially a copy of the lsrcertificate.pem with the added ThingWorx certificates and CAs.   Note that all certificates to be validated as well as their full Chain of Trust must be present in this one .pem file. Multiple files cannot be configured.   Binding to the LSR   When binding to the LSR via the auto_bind configuration, the following settings must be configured:   "auto_bind": [{ "name": "<ThingName>", "host": "<lsrHostName>", "port": 8001, "protocol": "https", "user": "luauser", "password": "AES:A26fBYKHJq+eMu0Fm2FlDw==" }]   This will ensure that the EMS connects to the LSR via https and proper authentication.   Tips   Do not use quotation marks (") as part of the strings to be encrypted. This could result in unexpected behavior when running the encryption script. Do not use a semicolon (:) as part of any username. Authentication tokens are passed from browsers as "username:password" and a semicolon in a username could result in unexpected authentication behavior leading to failed authentication requests. In the Server Specific certificates, the CN must match the actual server name and also must match the name of the http_server.host (EMS) or script_resource_host (LSR) In the .pem files first store Server Specific certificates, then all required Intermediate CAs and finally all required Root CAs - any other order could affect the consistency of the files and the certificate might not be fully readable by the scripts and processes. If the EMS is configured with certifcates, the LSR must connect via a secure channel as well and needs to be configured to do so. If the LSR is configured with certifcates, the EMS must connect via a secure channel as well and needs to be configured to do so. For testing REST API calls with resources that require encryptions and authentcation, see also How to run REST API calls with Postman on the Edge Microserver (EMS) and Lua Script Resource (LSR)   Export PEM data from KeyStore Explorer   To generate a .pem file I usually use the KeyStore Explorer for Windows - in which I have created my certificates and manage my keystores. In the keystore, select a certificate and view its details Each certificate and CA in the chain can be viewed: Root, Intermediate and Server Specific Select each certificate and CA and use the "PEM" button on the bottom of the interface to view the actual PEM content Copy to clipboard and paste into .pem file To generate a .pem file for the private key, Right-click the certificate > Export > Export Private Key Choose "PKCS #8" Check "Encrypted" and use the default algorithm; define an "Encryption Password"; check the "PEM" checkbox and export it as .pkcs8 file The .pkcs8 file can then be renamed and used as .pem file The password set during the export process will be the scripts.script_resource_passphrase (LSR) or the http_server.passphrase (EMS) After generating the .pem files I copy them over to my Linux systems where they will need 644 permissions (-rw-r--r--)
View full tip
Key Functional Highlights ThingWorx Manufacturing Apps enhancements Support for NI InsightCM connected to KEPServerEX as an aggregator Controls Advisor usability improvement to retrieve App Key for a specific KEPServerEX connection Asset Advisor usability improvement for displaying alerts Compatibility ThingWorx 8.1.0 KEPServerEX 6.2, 6.3 KEPServerEX V6.1 and older as well as different OPC Servers (with Kepware OPC aggregator) Documentation ThingWorx Manufacturing Apps Setup and Configuration Guide ThingWorx Manufacturing Apps Customization Guide What’s New in ThingWorx Manufacturing Apps 8.1.0 Download Extensions for ThingWorx Manufacturing Apps and Asset Remoting Note: this release announcement applies to the ThingWorx Manufacturing Apps Extensions 8.1.0. For the ThingWorx Manufacturing Apps Freemium (Express) 8.1.0 release notes, see this page: ThingWorx Manufacturing Apps 8.1 Freemium is Available for Download!
View full tip
Objective Use Influx as a database to store data coming from Kepware ThingWorx Industrial Connectivity server   Prerequisite Configure ThingWorx connection to Kepware’s KEPServerEX  and bind tags that exist in KEPServerEX to things in the ThingWorx model as referenced in Industrial Connections Example   Configuration Steps 1. Create database in Influx for ThingWorx: Connect:    influx -precision rfc3339 > SHOW DATABASES > CREATE DATABASE thingworx   2. Create Influx Persistence Provider     and configure   3. In the Industrial Thing where the Remote Properties are bounded define Value Stream     and make sure to have Persistence Provider set to Influx and is set to Active     4. In the Value Stream Properties and Alerts define the mappings using Manage Bindings to specify what properties are to be stored in this value stream     5. Save it and test it to make sure properties are stored in Influx: > use thingworx > show measurements   name   ----   Channel1.Device1 > show field keys on thingworx from "Channel1.Device1" > select Channel1_Device1_Tag2 from "Channel1.Device1"   name: Channel1.Device1   fieldKey fieldType   -------- ---------   Channel1_Device1_Tag10 integer   Channel1_Device1_Tag11 integer   Channel1_Device1_Tag12 integer   Channel1_Device1_Tag13 integer   Channel1_Device1_Tag14 integer   Channel1_Device1_Tag15 integer   Channel1_Device1_Tag16 integer   Channel1_Device1_Tag17 integer   Channel1_Device1_Tag18 integer   Channel1_Device1_Tag19 integer   Channel1_Device1_Tag2 integer   Channel1_Device1_Tag20 integer   Channel1_Device1_Tag21 integer   Channel1_Device1_Tag3 integer   Channel1_Device1_Tag4 integer   Channel1_Device1_Tag5 integer   Channel1_Device1_Tag6 integer   Channel1_Device1_Tag7 integer   Channel1_Device1_Tag8 integer   Channel1_Device1_Tag9 integer   shows data stored in Channel1_Device1_Tag2: >select Channel1_Device1_Tag2 from "Channel1.Device1"   2019-02-20T16:26:13.699Z 8043   2019-02-20T16:26:14.715Z 8044   2019-02-20T16:26:15.728Z 8045   2019-02-20T16:26:16.728Z 8046   2019-02-20T16:26:17.727Z 8047   2019-02-20T16:26:18.725Z 8048   2019-02-20T16:26:19.724Z 8049   2019-02-20T16:26:20.722Z 8050   2019-02-20T16:26:21.723Z 8051   2019-02-20T16:26:22.722Z 8052
View full tip
  Connect an ESP8266 WiFi module using the Arduino programming environment and the ThingWorx REST API.   This information was created for a previous version of ThingWorx and may not be fully accurate. Report any issues with this article here.   Guide Concept   This project will introduce the utilities ThingWorx provides for connections to an Adafruit Feather.   Following the steps in this guide, you will have a fully configured setup between your Adafruit Feather and the ThingWorx platform to begin your IoT development.   We will teach you how to utilize the ThingWorx REST API and the Arduino programming language to connect your Adafruit Feather for IoT application development.   You'll learn how to   Connect an ESP8266 WiFi module to a ThingWorx server Use the Arduino programming environment with the ThingWorx REST API   NOTE:  The estimated time to complete this guide is 30 minutes.      Step 1: Install Software   Arduino   There are three pieces of software to install before getting started with the ThingWorx-specfic code: Install FTDI USB driver. If you have connected development boards to your PC in the past you probably already have this installed. The latest Arduino IDE full install will also install the driver. NOTE: SparkFun has an excellent FTDI Driver Installation guide.   3. Arduino IDE - version 1.6.4 or later recommended. 4. Install ESP8266 addon into Arduino IDE. 5. The SparkFun Setting Up the Arduino IDE Tutorial is a great guide to getting started with their board. 6. Adafruit also has a great with their board Testing a Wifi Connection Tutorial.   When everything is set-up correctly and you are able to upload and see the Blink demo flashing the LED on the board you are ready to move to the next step.   ThingWorx Foundation Server   Start, and Launch your ThingWorx Foundation server. Log into Composer.  You will need a ThingWorx appKey to authorize the board.  Follow these instructions in Create an Application Key to create an appKey that you will copy into the source code in the next step.       Step 2: Set up Arduino IDE, Developer Board, and ThingWorx Server   Once you are able to run the blink test sketch, your IDE and board are set-up correctly. To learn how to run the blink test, read the SparkFun Board Instructions and the Adafruit board instructions.   Arduino IDE   Before you will be able to run the code below that connects a developement board to a ThingWorx Foundation server, you will need to modify the code with four pieces of information specific to your environment. You will need:   A WiFi access point SSID The correct password for the WiFi access point The IP address or URL of a ThingWorx Foundation Server A valid appKey created by your ThingWorx Foundation Server. To create an appKey, follow these instructions to Create An Application Key   Create a new sketch in the Arduino IDE then copy and paste the code below into the IDE.   Modify the WiFi Definitions and the ThingWorx server definitions shown in the code with your specficic information then save the sketch with a new name. The next step will describe what you should see when you upload and run the code on your developer board.   /** * * ESP8266_ThingWorx_REST_Demo.ino * * * (c) PTC, Inc. 2016-2020 * */ #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClientSecureBearSSL.h> ////////////////////// // WiFi Definitions // ////////////////////// const char WiFiSSID[] = "Liberty454"; // WiFi access point SSID const char WiFiPSK[] = "Flutie22"; // WiFi password - empty string for open access points ////////////////////////////////////////////// // ThingWorx server definitions // // modify for a specific platform instance // ////////////////////////////////////////////// const char TWPlatformBaseURL[] = "https://pp-2007011431nt.devportal.ptc.io"; const char appKey[] = "2d4e9440-3e51-452f-a057-b55d45289264"; //////////////////////////////////////////////////////// // Pin Definitions - board specific for Adafruit board// //////////////////////////////////////////////////////// const int RED_LED = 0; // Thing's onboard, red LED - const int BLUE_LED = 2; // Thing's onboard, blue LED const int ANALOG_PIN = A0; // The only analog pin on the Thing const int OFF = HIGH; const int ON = LOW; // this will set as the Accept header for all the HTTP requests to the ThingWorx server // valid values are: application/json, text/xml, text/csv, text/html (default) #define ACCEPT_TYPE "text/csv" ///////////////////// //Attempt to make a WiFi connection. Checks if connection has been made once per second until timeout is reached //returns TRUE if successful or FALSE if timed out ///////////////////// boolean connectToWiFi(int timeout){ Serial.println("Connecting to: " + String(WiFiSSID)); WiFi.begin(WiFiSSID, WiFiPSK); // loop while WiFi is not connected waiting one second between checks uint8_t tries = 0; // counter for how many times we have checked while ((WiFi.status() != WL_CONNECTED) && (tries < timeout) ){ // stop checking if connection has been made OR we have timed out tries++; Serial.printf(".");// print . for progress bar Serial.println(WiFi.status()); delay(2000); } Serial.println("*"); //visual indication that board is connected or timeout if (WiFi.status() == WL_CONNECTED){ //check that WiFi is connected, print status and device IP address before returning Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); return true; } else { //if WiFi is not connected we must have exceeded WiFi connection timeout return false; } } ////////////////////////// //create a name for the board that is probably unique by appending last two bytes of MAC address //return name as a String /////////////////////////////// String getUniqueDeviceName(){ String uniqueName; uint8_t mac[WL_MAC_ADDR_LENGTH]; WiFi.macAddress(mac); // WiFi does NOT need to be connected for this call String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX); macID.toUpperCase(); uniqueName = "ESP8266Board-" + macID; Serial.println("DeviceID>" + uniqueName); return uniqueName; } /////////////////////////////// // make HTTP GET to a specific Thing and Propertry on a ThingWorx server // thingName - Name of Thing on server to make GET from // property - Property of thingName to make GET from // returns HTTP response code from server and prints full response /////////////////////////////// int httpGetPropertry(String thingName, String property){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[httpsGetPropertry] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Things/"+ thingName +"/Properties/"+ property +"?appKey=" + String(appKey); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); Serial.println("GET URL>" + fullRequestURL +"<"); // start connection and send HTTP header httpCode = https.GET(); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[httpGetPropertry] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[httpGetPropertry] failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } /////////////////////////////// // makes HTTP POST to platform to CreateThing service using input string as the new Things's name. // Returns server response code /////////////////////////////// int createThing(String nameOfThing){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[createThing] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Resources/EntityServices/Services/CreateThing?appKey=" + String(appKey); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); https.addHeader("Content-Type","application/json",false,false); Serial.println("POST URL>" + fullRequestURL + "<"); // start connection and send HTTP header httpCode = https.POST("{\"name\": \""+ nameOfThing +"\",\"thingTemplateName\": \"GenericThing\"}"); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[createThing] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[createThing] POST... failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } /////////////////////////////// // make HTTP POST to ThingWorx server Thing service // nameOfThing - Name of Thing to POST to // endPoint - Services URL to invoke // postBody - Body of POST to send to ThingWorx platform // returns HTTP response code from server /////////////////////////////// int postToThing(String nameOfThing, String endPoint, String postBody){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[postToThing] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Things/"+ nameOfThing +"/Services/"+ endPoint +"?appKey=" + String(appKey); Serial.println("URL>" + fullRequestURL + "<"); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); https.addHeader("Content-Type","application/json",false,false); Serial.println("[postToThing] POST body>" + postBody + "<"); // start connection and send HTTP header httpCode = https.POST(postBody); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[postToThing] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[postToThing] POST... failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } void setup() { pinMode(RED_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); Serial.begin(115200); Serial.setDebugOutput(true); Serial.println(); Serial.println(); Serial.println(); Serial.printf("Starting...\n"); for(uint8_t t = 4; t > 0; t--) { Serial.printf(" WAIT %d...\n", t); Serial.flush(); delay(1000); } connectToWiFi(10); } void loop() { String thingName = getUniqueDeviceName(); //unique name for this Thing so many work on one ThingWorx server while (WiFi.status() == WL_CONNECTED) { //confirm WiFi is connected before looping as long as WiFi is connected int getResponseCode = httpGetPropertry(thingName, "SomeNumber"); if (getResponseCode == 404){ // a 404 means connected, but either no Thing or no property // first we will try to create a new Thing on the platform int postResp = createThing(thingName); // saving the response code for retry logic in the future // the newly crated Thing has to be enabled postResp = postToThing(thingName,"EnableThing",""); //POST to EnableThing endpoint with no body // after the new Thing is enabled it must be restarted postResp = postToThing(thingName,"RestartThing",""); //POST to RestartThing endpoint with no body // add a property to the Thing 3rd parameter is ugly because required quotes are escaped with backslashes postResp = postToThing(thingName,"AddPropertyDefinition", "{\"name\":\"SomeNumber\",\"type\":\"NUMBER\"}"); //POST body contains JSON object with property name and property type // after changes to a Thing's structure it must be restarted postResp = postToThing(thingName,"RestartThing",""); //POST to RestartThing endpoint with no body } delay(2000); }// end WiFi connected while loop Serial.printf("****Wifi connection dropped****\n"); WiFi.disconnect(true); delay(10000); connectToWiFi(10); }     Step 3: Run Arduino Demo   Click on the right arrow in the Arduino IDE toolbar to upload and start the sketch. Note:The compile and upload process will take almost a minute and will show [ 100% ] when it is completed successfully. 2. After the upload is complete, click on Tools > Serial Monitor and select 115200 baud from the drop down in the lower right.            Check Connection on ThingWorx Server   Open the Composer window of your ThingWorx Foundation server and click on the browse folder icon, then Things.   You will see a Thing named "ESP8266Board-XXXX" with XXXX replaced by the last 4 digits of your boards WiFi MAC address. Click on the Thing then click the Properties and Alerts tab in the left column. Click the pencil "Set value" icon in the value column and enter a number in the text box. Click the "Check" button to set the value.   Open the Arduino Serial monitor window, and you will see the value you just entered on the platform shown in the serial output.   Step 4: Next Steps   Congratulations! You've successfully completed the Connect an Arduino Developer Board Quickstart.   This guide has given you the basic tools to:   Set up Arduino IDE Run Arduino demo Check connection on ThingWorx Server   Learn More   We recommend the following resources to continue your learning experience:    Capability Guide Connect Use REST API to Access ThingWorx Build Data Model Introduction   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource Link Community Developer Community Forum Support REST API Help Center
View full tip
Key Functional Highlights Add connectivity to National Instruments TestStand Make it easier to edit the apps Easier to find mashups and things in Composer Support for Asset sub-types Open up the tag picker to allow adding any connection types through Composer General App Improvements Enhance tag picker to improve speed of configuration Make it easier to add additional properties to assets Make app configuration more intuitive by centralizing the configuration Controls Advisor Merge the Server and Connection status fields Asset Advisor Performance improvement when displaying pages Add support for CFS/ServiceMax integration Added trial support for Service     Compatibility ThingWorx 8.2.x KEPServerEX 6.2 and later KEPServerEX V6.1 and older as well as different OPC Servers (with Kepware OPC aggregator) National Instruments TestStand 2016 SP1 and later Support upgrade from 8.0.1 and later     Documentation What’s New in ThingWorx Manufacturing Apps ThingWorx Manufacturing Apps Setup and Configuration Guide What’s New in ThingWorx Service Apps ThingWorx Service Apps Setup and Configuration Guide ThingWorx Manufacturing and Service Apps Customization Guide     Download ThingWorx Manufacturing Apps Freemium portal ThingWorx Manufacturing and Service Apps Extensions
View full tip
  Meet Anthony. Anthony came to PTC from a large industrial company as a user of Axeda, a leading device connectivity company that PTC acquired in 2014. With a background in aerospace engineering and experience in a variety of industries including life safety, healthcare, nuclear power, and oil and gas, Anthony has been working to create new value around innovation for customers transitioning to ThingWorx. When he’s not working on IIoT, he’s playing music on Cape Cod, photographing Hawaiian landscapes or bringing awesome inflatable chairs into the office.    You may recall from last week's post that Thing Presence is one of the top three features in 8.4 that you might not know about. This week, I spoke with Anthony for a deeper dive on Thing Presence. Check out how it went.   Kaya: What was the challenge users were facing that led us to create Thing Presence? Anthony: Axeda customers transitioning to ThingWorx were struggling with the connectivity use case and kept asking, ‘why is my asset always offline?’ When we evaluated it, we discovered that it was tied to the difference between AlwaysOn and Axeda eMessage protocol architectures. IsConnected will always report false for polling and duty cycle devices.   The use case of Thing Presence is to know that the asset is reporting into the network and is ready to provide information (push) or be accessed to retrieve information or do a remote desktop support (pull). This use case is relevant for any asset in ThingWorx that uses duty cycle.   In ThingWorx 8.4 (coming in early 2019), the new IsReporting state will inform the user when a polling device is communicating on a regular basis. If it is, then IsReporting will be true. The IsReporting state resolves the discrepancy wherein devices that are on duty cycle appear disconnected due to the IsConnected state reporting false.  New "IsReporting" state improves visibility of an asset's communication state Kaya: How exactly does Thing Presence work? Anthony: You can think of it in terms of having teenagers. You tell them they need to check in with you on a regular basis through text message. If a text is missed, all of a sudden you take action.   Now, imagine the teenager is a device. If a device was supposed to check in every five minutes and it misses one poll, I want to flag that as a problem. The challenge with that from a service perspective is that sometimes your service personnel will go out and work on a device and may need to take it offline for a bit of time; we need to factor that in. We certainly don’t want to deploy someone or try to fix something when a service technician is already there.   You might decide, ‘my average service visit is an hour, so, if I miss a couple of pings, I’m okay; but, if I’m offline for more than an hour, then I’d like to know about it because I’d like to take action.’ Thing Presence allows you to define that window.   Kaya: You’ve mentioned ‘duty cycle’ and ‘polling cycle.’ Can you explain these terms? Anthony: Duty cycle and polling cycle are the same thing. It means that a device has a time for which it is expected to check in, and, provided that it checks in within that timeframe, all is good with the connection.   Connected services rely on a connection. As soon as the connection is broken, I no longer have the ability to service the asset.   Kaya: Given everything we’ve discussed, where do you see Thing Presence headed? Anthony: The next piece of the equation for us is to provide information on the health of the connection. When you look at servicing a remote asset, you need to a) know that it is communicating, and b) know that the connection is healthy before you try anything. I wouldn’t want to try a software update if I am losing connection with my asset on a regular basis.   What do we mean by health? We mean: is the device checking in when it should be? If it’s not, is there a pattern to that connection, and are those patterns tied to applications? For example, is it only on during working hours? Does it turn off during holidays? If the device is in a school, does it turn off during summer maintenance work? This allows us to garner insights on how and when the equipment is being used, not just operating status. At the end of the day, does this mean I can apply analytics and AI tools to it? Absolutely. Is it the first place I would apply it? Probably not.   Kaya: In your mind, what is the next big thing coming in ThingWorx that you’re particularly excited about? Anthony: Mashup 2.0 and Asset Advisor 8.4. (Double mic drop.)   Kaya: That’s awesome. My last question is related to you. Can you tell me what your favorite aspect is about working at PTC? Anthony: The chaos. Very often it’s chaos that breeds innovation. What I mean by that is that, if you try to create something because you sit down and you say, ‘I am going to innovate,’ very often that is a failure because the majority of the time it’s the influence of a deadline, a customer need or an application at hand that makes the environment trying and sometimes hectic. But, it is in these challenging environments where you can be the most creative and innovative as an engineer.
View full tip
Announcements