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:
To setup the Single-Sign On with Windchill, we can just follow steps in Windchill extension guide. However, there is a huge problem to use "Websocket" for EMS or Edge SDKs from devices since Apache for Windchill blocks to pass "ws" or "wss" protocol. It's like a problem of a proxy server. There might be a couple of ways to avoid this issue, but I suggest to change filter-mappings for the SSO filter. When you look at the Windchill extension guide, it says that users set filters for all incoming URLs of ThingWorx by using "/*" filter mappings. Please use below settings for "web.xml" of ThingWorx server to avoid the problem that I stated above. It looks quite long and complicated, but basically the filter mappings from settings for "AuthenticationFilter" which are already defined by default except "Websocket" related urls. <!-- Windchill Extension SSO Start--> <filter> <filter-name>IdentityProviderAuthenticationFilter</filter-name> <filter-class>com.ptc.connected.plm.thingworx.wc.idp.client.filter.IdentityProviderAuthenticationFilter</filter-class> <init-param> <param-name>idpLoginUrl</param-name> <param-value>http(s)://<SERVERHOSTURL>/Windchill/wtcore/jsp/genIdKey.jsp</param-value> </init-param> </filter> <filter-mapping>   <filter-name>IdentityProviderAuthenticationFilter</filter-name>   <url-pattern>/extensions/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/action-authenticate/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/action-login/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/action-confirm-creds/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/action-change-password/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ThingworxMain.html</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ThingworxMain.html/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Server/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ApplicationKeys/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Networks/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Dashboards/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/DirectoryServices/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Authenticators/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/PersistenceProviderPackages/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/tunnel/wsadapter.jsp</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/tunnel/adapter.jsp</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Logs/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Resources/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Subsystems/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Users/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Home/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/StateDefinitions/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/StyleDefinitions/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ScriptFunctionLibraries/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/AtomFeedService/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/DataShapes/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Importer/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ImageEncoder/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Exporter/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ExportDatabase/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ExportTheme/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ExportDefaultEntities/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ImportDatabase/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/DataExporter/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/DataImporter/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Widgets/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Groups/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ThingPackages/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Things/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ThingTemplates/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ThingShapes/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/DataTags/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ModelTags/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Composer/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Squeal/index.html</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Runtime/index.html</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Mashups/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Menus/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/MediaEntities/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/loaders/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/demos/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ExtensionPackageUploader/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/ExtensionPackages/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/FileRepositoryUploader/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/FileRepositoryDownloader/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/FileRepositories/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/xmpp/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/LocalizationTables/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/Organizations/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/RemoteTunnel/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderAuthenticationFilter</filter-name>     <url-pattern>/PersistenceProviders/*</url-pattern>   </filter-mapping> <filter> <filter-name>IdentityProviderKeyValidationFilter</filter-name> <filter-class>com.ptc.connected.plm.thingworx.wc.idp.client.filter.IdentityProviderKeyValidationFilter</filter-class> <init-param> <param-name>keyValidationUrl</param-name> <param-value>http(s)://<SERVERHOSTURL>/Windchill/login/validateIdKey.jsp</param-value> </init-param> </filter> <filter-mapping>   <filter-name>IdentityProviderKeyValidationFilter</filter-name>   <url-pattern>/extensions/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/action-authenticate/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/action-login/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/action-confirm-creds/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/action-change-password/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ThingworxMain.html</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ThingworxMain.html/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Server/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ApplicationKeys/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Networks/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Dashboards/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/DirectoryServices/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Authenticators/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/PersistenceProviderPackages/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/tunnel/wsadapter.jsp</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/tunnel/adapter.jsp</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Logs/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Resources/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Subsystems/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Users/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Home/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/StateDefinitions/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/StyleDefinitions/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ScriptFunctionLibraries/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/AtomFeedService/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/DataShapes/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Importer/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ImageEncoder/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Exporter/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ExportDatabase/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ExportTheme/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ExportDefaultEntities/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ImportDatabase/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/DataExporter/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/DataImporter/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Widgets/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Groups/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ThingPackages/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Things/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ThingTemplates/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ThingShapes/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/DataTags/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ModelTags/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Composer/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Squeal/index.html</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Runtime/index.html</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Mashups/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Menus/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/MediaEntities/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/loaders/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/demos/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ExtensionPackageUploader/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/ExtensionPackages/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/FileRepositoryUploader/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/FileRepositoryDownloader/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/FileRepositories/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/xmpp/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/LocalizationTables/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/Organizations/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/RemoteTunnel/*</url-pattern>   </filter-mapping>   <filter-mapping>     <filter-name>IdentityProviderKeyValidationFilter</filter-name>     <url-pattern>/PersistenceProviders/*</url-pattern>   </filter-mapping> <!-- Windchill Extension SSO End-->
View full tip
The App URI in the ThingWorx Remote Thing Tunnel configuration specifies the endpoint of the specified tunnel. The default value (/Thingworx/tunnel/vnc.jsp) will point to the built in ThingWorx VNC client that can be downloaded through the Remote Access Widget in a Mashup to provide VNC remote desktop access. Leaving the App URI blank will result in the Tunnel being connected to the listen port on the users machine as specified in the Remote Access Widget​. In this case the user must supply the application client (e.g. an ssh client) in order to connect to the tunnel endpoint.
View full tip
  Part I – Securing connection from remote device to Thingworx platform The goal of this first part is to setup a certificate authority (CA) and sign the certificates to authenticate MQTT clients. At the end of this first part the MQTT broker will only accept clients with a valid certificate. A note on terminology: TLS (Transport Layer Security) is the new name for SSL (Secure Sockets Layer).  Requirements The certificates will be generated with openssl (check if already installed by your distribution). Demonstrations will be done with the open source MQTT broker, mosquitto. To install, use the apt-get command: $ sudo apt-get install mosquitto $ sudo apt-get install mosquitto-clients Procedure NOTE: This procedure assumes all the steps will be performed on the same system. 1. Setup a protected workspace Warning: the keys for the certificates are not protected with a password. Create and use a directory that does not grant access to other users. $ mkdir myCA $ chmod 700 myCA $ cd myCA 2. Setup a CA and generate the server certificates Download and run the generate-CA.sh script to create the certificate authority (CA) files, generate server certificates and use the CA to sign the certificates. NOTE: Open the script to customize it at your convenience. $ wget https://github.com/owntracks/tools/raw/master/TLS/generate-CA.sh . $ bash ./generate-CA.sh The script produces six files: ca.crt, ca.key, ca.srl, myhost.crt,  myhost.csr,  and myhost.key. There are: certificates (.crt), keys (.key), a request (.csr a serial number record file (.slr) used in the signing process. Note that the myhost files will have different names on your system (ubuntu in my case) Three of them get copied to the /etc/mosquitto/ directories: $ sudo cp ca.crt /etc/mosquitto/ca_certificates/ $ sudo cp myhost.crt myhost.key /etc/mosquitto/certs/ They are referenced in the /etc/mosquitto/mosquitto.conf file like this: After copying the files and modifying the mosquitto.conf file, restart the server: $ sudo service mosquitto restart 3. Checkpoint To validate the setup at this point, use mosquitto_sub client: If not already installed please install it: Change folder to ca_certificates and run the command : The topics are updated every 10 seconds. If debugging is needed you can add the -d flag to mosquitto_sub and/or look at /var/logs/mosquitto/mosquitto.log. 4. Generate client certificates The following openssl commands would create the certificates: $ openssl genrsa -out client.key 2048 $ openssl req -new -out client.csr  -key client.key -subj "/CN=client/O=example.com" $ openssl x509 -req -in client.csr -CA ca.crt  -CAkey ca.key -CAserial ./ca.srl -out client.crt  -days 3650 -addtrust clientAuth The argument -addtrust clientAuth makes the resulting signed certificate suitable for use with a client. 5. Reconfigure Change the mosquitto configuration file To add the require_certificate line to the end of the /etc/mosquitto/mosquitto.conf file so that it looks like this: Restart the server: $ sudo service mosquitto restart 6. Test The mosquitto_sub command we used above now fails: Adding the --cert and --key arguments satisfies the server: $ mosquitto_sub -t \$SYS/broker/bytes/\# -v --cafile ca.crt --cert client.crt --key client.key To be able to obtain the corresponding certificates and key for my server (named ubuntu), use the following syntax: And run the following command: Conclusion This first part permit to establish a secure connection from a remote thing to the MQTT broker. In the next part we will restrict this connection to TLS 1.2 clients only and allow the websocket connection.
View full tip
In this post we will take a look at using an existing JavaScript Library. The library will we will use is agGrid  which provides a very extensive Grid UI component. The objectives are To see how to add the library Use an external source to populate the grid Provide a click action when a user selects a row (Part 2) (see attachments - import AAGridExtensionExample as an extension and import as File PTC-ExternalSources-Entities ) Previous Posts for reference Widget Extensions Introduction Widget Extensions Click Event Widget Extensions Date Picker Widget Extensions Google Bounce We will not worry about CSS - I'm working on a post for that using Thingworx 8.2 CustomClass (CSS) feature. Also I will assume you have worked through the Widget Extensions Introduction The image below image below shows the resulting UI after grid population and a user clicked a row The following provides the high level areas of interest Steps 1. Create a Working Folder for example  AGGrid as in previous posts setup your ui folder and metadata file 2. Think of a name for the Extension - we will use aggrid and add a folder with this name under ui folder 3. create the required files as per previous posts - Note the jslibrary folder is where aagrid resides     Below shows the jslibrary folder the main file we care about is the ag-grid (we could use the min file but initially have the full makes debugging easier) 4. Setup the metadata file 5. Understand some of the agGrid requirements To create a grid we need to use the function agGrid which comes from the ag-grid.js       myGrid = new agGrid.Grid(gridContainer, gridOptions ); The gridContainer is where the grid will be placed in the DOM and the gridOptions is a definition object that holds all the settings for the grid before it is created. Using a init function inside the runtime.js (see previous posts for runtime)  we can get the gridContainer  by using a snippet like this document.getElementById(gridElementId); The gridOptions takes the form of a json object - note there are many options please refer to the agGrid documentation for more info. Our focus will be  columnDefs , rowData to start with. These 2 define the layout and the contents of the grid The columnsDefs takes the form of an Array of JSON basically headerName: and field The image below shows a hard-coded approach I took initially To make this more generic I created a Thingworx datashape and used a service script GetColumndefs to populate and output the columnDefs service script example uses a PTC-ExternalSourcesHelper thing below is the GetColumnsDefs service The next point of focus will be the gridOptions and the rowData (JSON  array of data ) based on the same definition as the columnDefs Both the columnDefs and the GridDataAsJSON (which turns into rowData)  shown below are setup in the ide.js file (see previous posts for ide) Returning back to the services we need to get some Grid data from an external source. For that we will create a GetRSSFeed and use that inside GetRSSAsJSON The GetRSSFeed  looks like this and uses the url input More Top Stories - Google News The GetRSSAsJSON looks like this looking back at the code maybe I should changed to result.rows when returning the GridData  but for now it works. The last thing is getting the data from the services and we use the updateProperty ( previous posts for ide ). Here we check for the property and set and pass the RawData to the drawaggrid function The drawaggrid takes in the rowData and uses the columnDefs to understand the format. Also the last thing the drawaggrid  function is create the actual grid. (Finally!) 5. lat but not least - Wire it all up in a Mashup! The first set is to zip up the Extension and Import  (see previous posts) The next is to create a Mashup and add the PTC-ExternalSourcesHelper entity and wire up the GetColumsDefs and the GetRSSAsJSON to the agGrid widget and then preview and hopefully it all works - I will upload the Extension and Entities shortly See you in Part 2 not yet created! (see attachments - import AAGridExtensionExample as an extension and import as File PTC-ExternalSources-Entities )
View full tip
Twilio extends the ThingWorx functionality to send SMS and voice messages in variety of languages. Starting from scratch I'll cover the steps required to setup the Twilio extension and the basic account registration (trial version) and setup at Twilio.com Twilio allows registering with the trial account, which comes with $15 as initial account balance, something which is quite useful for testing the initial setup and testing of Twilio extension in conjunction to ThingWorx. Prerequisite 1. Sign up, if not already done, with Twilio.com for free trail account 2. Configure the account to setup a verified phone number to receive text and voice messages, free trial account allows setting up 1 verified phone number that can receive text and voice messages Note: See What's the difference between a verified phone number and a Twilio phone number? 3. Choose and configure a Twilio phone number capable of sending text and voice messages, free trial account allows setting up of 1 Twilio number which will be used in the Extension configuration in ThingWorx for sending the messages 4. Download Twilio Extension from ThingWorx Marketplace Note that Twilio phone number should be enabled with the send SMS or send voice message capability, depending on what your use case is. Failing to do so will lead to error while testing the sendSMS or sendVOICE service (two default services provided with the Twilio Extension when imported in ThingWorx) Signing up and setting up Twilio account 1. Sign up on Twilio.com with your details and emailID. When registering for the first time you'll be prompted for your personal phone number as part of the security requirement. Also with free trial account this will be the only phone number where you'll be able to send SMS or Voice message via Twilio Extension in ThingWorx 2. Next would be to setup the Twilio number with voice and text messaging, navigate to https://www.twilio.com/console/phone-numbers/getting-started 3. Do ensure that you setup the voice or text capabilities for the new Twilio number, failing to do so will lead to error in sending message via Twilio Extension in ThingWorx 4. Different Twilio Number have different capabilities, it's quite possible that you don't find the number with required capabilities i.e. Voice, SMS - in that scenario simply search for different number, one that has the capabilities you are looking for 5. With trial account only 1 Twilio number is avilable for setup 6. While setting up the Twilio number you will be required to provide a valid local address of your country The cost of setting up the number and further sending the SMS will only be deducted from the $15 made available when you signed up for the first time. Navigate to your account details on Twilio.com to make note of the following information which will be used when configuring the Twilio Extension in ThingWorx: a. Account SID b. Authentication ID c. Your Verified Phone Number (will be used for receiving the messages) d. Twilio Phone number created with required capabilities, e.g. that number is capable of sending text message Here's how it shows up once you are successfully registered and logged on to the twilio.com/console To check your Twilio Phone Number and the Verified Phone Number navigate to twilio.com/phone-numbers As it can be seen in the above screenshot, the number I have bought from Twilio is capable of sending Voice and SMS. With this all's set  and ready to configure the Twilio Extension in ThingWorx, which is pretty straight forward. Setup Twilio Extension in ThingWorx 1. Let's setup the extension by navigating to the ThingWorx Composer > Import/Export > Extensions > Import > browse to the location where you saved the Twilio Extension from ThingWorx Marketplace and click Import 2. Once imported successfully refresh the composer and navigate to Modeling > Things , to create a new Thing implementing the Twilio Template (imported with the extension) like so, in screenshot below Thing is named DemoTwilioThing 3. Navigate to the the Configuration section of that Thing, to provide the information we noted above from Twilio account Note: this demo thing is setup to send the text SMS to my verified phone number only, therefore the CallerID in the configuration above is the Twilio number I created after signing up on Twilio with text message capability. 4. Save the created the Thing 5. Finally, we can test with the 1 of the 2 default services provided with the Twilio Template i.e. SendSMSMessage service 6. While testing the SendSMSMessage service use your verified phone number in To for receiving the message Troubleshooting some setup related issues I'll try to cover some of the generic errors that came up while doing this whole setup with Twilio Extension Error making outgoing SMS: 404 / TwilioResponse 20404 Reason If the Twilio number is not enabled with SMS sending capabilities you may run into such an error when testing the service. Here's the full error stack Unable to Invoke Service SendSMSMessage on DemoTwilioThing : Error making outgoing SMS: 404 <?xml version='1.0' encoding='UTF-8'?><TwilioResponse><RestException><Code>20404</Code><Message>The requested resource /2010-04-01/Accounts/<AccountSID>/SMS/Messages was not found</Message><MoreInfo>https://www.twilio.com/docs/errors/20404</MoreInfo><Status>404</Status></RestException></TwilioResponse> Resolution Navigate back to the Phone Number section on Twilio's website and as highlight in screenshot above check if the Twilio number is enabled with SMS capabilities. Error making outgoing SMS:400 / TwilioResponse 21608 Reason You may encounter following error when attempting to send SMS/Voice message, here's the full error detail Wrapped java.lang.Exception: Error making outgoing SMS: 400 <?xml version='1.0' encoding='UTF-8'?><TwilioResponse><RestException><Code>21608</Code><Message>The number <somePhoneNumber>is unverified. Trial accounts cannot send messages to unverified numbers; verify <somePhoneNumber>at twilio.com/user/account/phone-numbers/verified, or purchase a Twilio number to send messages to unverified numbers.</Message><MoreInfo>https://www.twilio.com/docs/errors/21608</MoreInfo><Status>400</Status></RestException></TwilioResponse> Cause: Error making outgoing SMS: 400 <?xml version='1.0' encoding='UTF-8'?><TwilioResponse><RestException><Code>21608</Code><Message>The number <somePhoneNUmber>is unverified. Trial accounts cannot send messages to unverified numbers; verify <somePhoneNumber> at twilio.com/user/account/phone-numbers/verified, or purchase a Twilio number to send messages to unverified numbers.</Message><MoreInfo>https://www.twilio.com/docs/errors/21608</MoreInfo><Status>400</Status></RestException></TwilioResponse> Resolution As the error points out clearly the number used in To section while testing the SendSMSMessage service didn't have verified number. With free trial account you can only use the registered verified phone number where SMS/Voice message can be sent. If you want to use different number an account upgrade is required. Error making outgoing SMS:400 / TwilioResponse 21606 Reason Following error is thrown while testing SendSMSMessage service with different Twilio number which is either not the same as the number you bought when setting up the trial account or it doesn have SMS sending capabiltiy. Here's the full error stack Wrapped java.lang.Exception: Error making outgoing SMS: 400 <?xml version='1.0' encoding='UTF-8'?><TwilioResponse><RestException><Code>21606</Code><Message>The From phone number <TwilioNumber>is not a valid, SMS-capable inbound phone number or short code for your account.</Message><MoreInfo>https://www.twilio.com/docs/errors/21606</MoreInfo><Status>400</Status></RestException></TwilioResponse> Cause: Error making outgoing SMS: 400 <?xml version='1.0' encoding='UTF-8'?><TwilioResponse><RestException><Code>21606</Code><Message>The From phone number <TwilioNumber> is not a valid, SMS-capable inbound phone number or short code for your account.</Message><MoreInfo>https://www.twilio.com/docs/errors/21606</MoreInfo><Status>400</Status></RestException></TwilioResponse> Resolution Check the configuration in the ThingWorx Composer for the Thing created out of Twilio Template whether or not the callerID is configured with correct Twilio account number
View full tip
This document is a general reference/help with configuring and troubleshooting google email account with the ThingWorx mail extension. To start with the configuration: SMTP: smtp.gmail.com 587, TLS checked.  If SSL is being used, the port should be 465. POP3: pop.gmail.com 995 To test, go to "Services" and click on "test" for the SendMessage service. Successful request will show an empty screen with green "result" at the top. Possible errors: Could not connect to SMTP host: smtp.gmail.com, port: 587 with nothing else in the logs. Check your Internet connection to ensure it's not being blocked. <hostname:port>/Thingworx/Common/locales/en-US/translation-login.json 404 (Not Found) Check your gmail folders for incoming messages regarding a sign-in from unknown device. The subject will be "Someone has your password", and the email  content will include the device, location, and timestamp of when the incident occurred. Ensure to check the "this was me" option to prevent from further blocking. This may or may not be sufficient, sometimes this leads to another error - "Please log in via your web browser and 534-5.7.14 then try again. 534-5.7.14 Learn more at 534 5.7.14..." The error can be resolved by: Turning off “less secure”  feature in your Gmail settings. You have to be logged in to your gmail account to follow the link: https://www.google.com/settings/security/lesssecureapps​ Changing your gmail password afterwards. I don't have a valid explanation as to why, but this is a required step, and the error doesn't clear without changing the password.
View full tip
    Step 4: Create Extension Project   In this tutorial, you will create a ThingWorx extension that retrieves weather information using OpenWeatherMap API. Create Account In this part of the lesson, you will create a free account in OpenWeatherMap that creates an AppKey so you can access their REST API. Sign-up for a free account. Log in to your account. Create a new API Key   NOTE: We will use this generated API key as a parameter in the REST calls.   Create New Extension Project   NOTE: Make sure that you are in the ThingWorx Extension Perspective. To verify, you should see a plus icon:   in the menu bar. If you don’t see this, you are probably in the wrong perspective. Go back to the previous step to learn how to set the perspective to ThingWorx Extension in Eclipse.   Go to File->New->Project. Click ThingWorx->ThingWorx Extension Project.  Click Next. NOTE: A New ThingWorx Extension window will appear. Enter the Project Name (for example, MyThingworxWeatherExtension). Select Gradle or Ant as your build framework. Enter the SDK location by browsing to the directory where the Extension SDK is storeed.   NOTE: The Eclipse Plugin accepts the Extension SDK version 6.6 or higher. Enter the Vendor information (for example, ThingWorx Labs). Change the default package version from 1.0.0 to support extension dependency. NOTE: The information from ThingWorx Extension Properties is used to populate the metadata.xml file in your project. The metadata.xml file contains information about the extension and details for the various artifacts within the extension. The information in this file is used in the import process in ThingWorx to create and initialize the entities. Select the JRE version to 1.8. Click Next then click Finish. Your newly created project is added to the Package Explorer tab.   Create New Entity   Select your project and click Add to create a new entity. NOTE: You can also access this from the ThingWorx menu on the menu bar. Create a Thing Template for your MyThingWorxWeatherExtension Project.   NOTE: In this guide, we are using a Template, but in a real-world scenario, you may consider using a Thing Shape to encapsulate extension functionality. By using Thing Shapes you give users of your extension the ability to easily add new functionality to existing Things. It is simple to add a new Thing Shape to an existing Thing Template, while using the properties or services defined by a Thing Template would require recreating all existing assets using the new Template. Since subscriptions cannot be created on Thing Shapes, you might choose to create Thing Templates that implement one or more subscriptions for convenience. In the pop-up window, browse to add the source folder of your project in Source Folder. NOTE: It should default to the src directory of your project. In our case it will be MyThingworxWeatherExtension/src. Browse to add the package where you want to create this new class, or simply give it a name (such as com.thingworx.weather). Enter a name and description to your Thing Template (WeatherThingTemplate).  NOTE: By default, the Base Thing Template is set to GenericThing. Select Next. NOTE: If you want to give other users of this entity permission to edit it in ThingWorx Composer, select the entity as an editable entity. Only non-editable entities can be upgraded in place; editable entities must be deleted and recreated when your extension is updated. If you need to make it possible to customize the extension, consider using a configuration table to save user customizations. Select Finish.   Verify that you have a WeatherThingTemplate class created that extends the Thing class. @ThingworxBaseTemplateDefinition(name = "GenericThing") public class WeatherThingTemplate extends Thing { public WeatherThingTemplate() { // TODO Auto-generated constructor stub } } NOTE: You might see a warning to add a serial version. You can add a default or generated serial value.   Step 5: Add Properties    In this section, you are going to add CurrentCity, Temperature and WeatherDescription properties to the WeatherThingTemplate. These properties are associated with the Thing Template and add the @ThingworxPropertyDefinitions annotation before the class definition in the code.   Right click inside the WeatherThingTemplate class or right click on the WeatherThingTemplate class from the Package Explorer. Select ThingWorx Source-> Add Property. In the popup window, create a property to store the city name. Name = CurrentCity, Base Type = STRING, Description = ‘’ Select the Has Default Value checkbox and enter a city name (eg. Boston). This will be the default value unless a specific value is passed. Select the “Persistent” checkbox. This will maintain the property value if a system restart occurs. NOTE: If you select the Logged checkbox, the property value is logged to a data store. If you select the Read Only checkbox, the data will be static. Select VALUE from the Data Change Type drop down menu       NOTE: This allows any Thing in the system to subscribe to a data change event for this property. Choose to use one of the following Data Change Types:   Data Change Type Description Always Fires the event to subscribers for any property value change Never Does not fire a change event On For most values, any change will trigger this. Off Fires the event if the new value is false Value For numbers, if the new value has changed by more than the threshold value, fire the change event. For non-numbers, this setting behaves the same as Always. Select Finish. Create another property called Temperature with a base type of NUMBER. You can keep the default values for the other parameters. Create another property called WeatherDescription with a base type of STRING. Keep the default values for the other parameters.   Step 6: Create Configuration Table   In this part of the lesson, we will create a configuration table to store the API Id that you generated from the openMapsWeather. Configuration tables are used for Thing Templates to store values similar to properties that do not change often.   Right-click inside the WeatherThingTemplate class and select ThingWorx Source->Add Configuration Table. Create a new configuration table with name OpenWeatherMapConfigurationTable. Click Add in the Data Shape Field Definitions frame. NOTE: Configuration tables require fields (columns) with a defined table structure (DataShape). Enter appid as the name with a base type STRING. Select the Required checkbox. Click OK, then Finish to add the Configuration Table To use the appid in the REST calls, you need to obtain the value from the configuration table and assign it to a field variable in the Java code. We will use the initializeThing method to obtain the appid value at runtime. NOTE: The initializeThing() method acts as an initialization hook for the Thing. Every time a Thing is created or modified, this method is executed and the value of appid is obtained from the configuration table and stored in a global field variable of the class. initializeThing() must call super.initializeThing() to ensure it performs initialization of the Thing. Create the initializeThing() method and field variable _appid with base type STRING anywhere in the WeatherThingTemplate class. private static Logger _logger = LogUtilities.getInstance().getApplicationLogger(WeatherThingTemplate.class); private String _appid; @Override public void initializeThing() throws Exception { super.initializeThing(); _appid = (String) this.getConfigurationSetting("OpenWeatherMapConfigurationTable", "appid"); } NOTE: In the code above we used ThingWorx LogUtilities to get a reference to the ThingWorx logging system, then assigned the reference to the variable _logger. In the steps below we will use this variable to log information. There are multiple kinds of loggers and log levels used in the ThingWorx Platform, but we recommend that you use the application or script loggers for logging anything from inside extension services. If prompted to import the logger, use slf4j.     Click here to view Part 3 of this guide.
View full tip
How to input Database User Credentials at RunTime. This Blog considers that you have already imported the Database Extension and Configured the Thing Template. If you have not done this already please see Steps to connecting to your Relational Database first. Steps: Create a Database Thing template with correct configuration. Example configuration for MySql Database: jDBCDriverClass: com.mysql.jdbc.Driver jDBCConnectionURL: jdbc:mysql://127.0.0.1:3306/<DatabaseNameHere>?allowMultiQueries=true connectionValidationString: SELECT NOW() maxConnections: 100 userName: <DataBaseUserNameHere> password: <DataBasePasswordHere> Create any Generic Thing and add a service to create thing based on the Thing template created in Step 1. Example: // NewDataBaseThingName is the String input for name the database thing to be created. // MySqlServerUpdatedConfiguration is the Thing template with correct configuration var params = {      name: NewDataBaseThingName /* STRING */,      description: NewDataBaseThingName /* STRING */,     thingTemplateName: "MySqlServerUpdatedConfiguration" /* THINGTEMPLATENAME */,     tags: undefined /* TAGS */ }; // no return Resources["EntityServices"].CreateThing(params); Add code to enable and then restart the above thing using EnableThing() and RestartThing() service. Example Things[NewDataBaseThingName].EnableThing(); Things[NewDataBaseThingName].RestartThing(); Test and confirm that the Database Thing services runs as expected. Now Create a DataShape with following Fields: jDBCDriverClass: STRING jDBCConnectionURL: STRING connectionValidationString: STRING maxConnections: NUMBER userName: STRING password: PASSWORD Now in the Generic Thing created in Step 1 add code to update the configuration settings of DataBase Thing. Make sure JDBC Driver Class Name should never be changed. If different database connection is required use different Thing Template. Also, add code to restart the DataBase Thing using RestartThing() service. Example: var datashapeParams = {     infoTableName : "InfoTable",     dataShapeName : "DatabaseConfigurationDS" }; // CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(DatabaseConfigurationDS) var config = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(datashapeParams); var passwordParams = {         data: "DataBasePasswordHere" /* STRING */ }; // DatabaseConfigurationDS entry object var newEntry = new Object(); newEntry.jDBCDriverClass= "com.mysql.jdbc.Driver"; // STRING newEntry.jDBCConnectionURL = "jdbc:mysql://127.0.0.1:3306/<DatabaseNameHere>?allowMultiQueries=true"; // STRING newEntry.connectionValidationString = "SELECT NOW()"; // STRING newEntry.maxConnections = 100; // NUMBER newEntry.userName = "DataBaseUserNameHere"; // STRING newEntry.password = Resources["EncryptionServices"].EncryptPropertyValue(passwordParams); // PASSWORD config.AddRow(newEntry); var configurationTableParams = { configurationTable: config /* INFOTABLE */, persistent: true /* BOOLEAN */, tableName: "ConnectionInfo" /* STRING */ }; // ThingNameForConfigurationUpdate is the input string for Thing Name whose configuration needs to be updated. // no return Things[ThingNameForConfigurationUpdate].SetConfigurationTable(configurationTableParams); Things[ThingNameForConfigurationUpdate].RestartThing(); Test and confirm that the Database Thing services runs as expected.
View full tip
<p>We live in a connected world where we can (want!) to receive instant updates and notifications. ThingWorx leverages the power of Web 2.0 and its Always-On technology to deliver that, but our friendly SMS providers have also provided an easy and powerful way that can be used to deliver SMS notifications right to your phone. Email to Text!</p><div>Set up a 'notification' Thing using our MailServer Template, set up your outgoing e-mail server and you are now ready to invoke the 'SendMessage' service on a given event. All you need now is the email address of your SMS number, which you can find by following this link: <a href="http://sms411.net/how-to-send-email-to-a-phone/" target="_blank"><span style="font-size:8.5pt;line-height:115%;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;">List of e-Mail to SMS  addresses</span></a></div><p class="MsoNormal"><o:p></o:p></p><div><p class="MsoNormal"><o:p></o:p></p></div><p></p>
View full tip
This video go through the steps required to use the Creo Insight extension: - Download and install the required extension - Set required config.pro options - Create provider in Analytics Manager - Publish sensor from Creo - Create analysis Event in Analysis Manager - Retrieve sensor values from ThingWorx in Creo     See also: - https://www.ptc.com/en/support/article?n=CS277514  for a  written version of those steps. - Creo Help Center  
View full tip
This project is developed out of curiosity of how ThingWorx communicates with sensors and vice versa. Immediately a Smart Parking system idea struck to our mind and I started working on it. While heading from home to office I always worry about car parking space in office especially in rainy season. This project will help user in getting parking space. This project has 4 sections as follows, 1) Smart Parking system: A system application developed in ThingWorx guides user to find empty car parking space. Sensors placed at each car parking slot senses the presence of car. A program running on Raspberry Pi board collects sensor information and sends that information to the Smart Car Parking System application in ThingWorx. The data received through sensor is displayed on ThingWorx dashboard/mashup. 2) Live Traffic: This inherits a Google Map and shows the traffic around user's current location. 3) Traffic Blog: If user is visiting a place and have questions regarding parking, traffic condition etc., then user can post their questions here and people around that area can answer it. Questions are not restricted for parking related questions but like best places to visit in areas, restaurant, shops etc. 4) Automobile Wiki: This page provides an documented help regarding anything related to automobile e.g. how to change car tyres?, how to change car wipers? etc.
View full tip
Here is a demo that uses repeater widget and smart grid widget to display a nested table. Note: This demo is for testing use. Create a datashape for  the nested datatable named DataTableStructure Create DataShape named InfoStructure for Obj Create the nested datatable named DataTableTest as below Create a service named AddObjInput as below in this datatable Crate a Mashup named RepeaterMsh Add widgets like textbox, label, button and smart grid on the mashup There are some parameters we added before, please bind them to the widgets that we just added to the mashup Add DataTableTest service AddOrUpdateDataTableEntry to the mashup. Bind textbox and smart grid edited table to AddOrUpdateDataTableEntry parameter. Bind button click event to trigger the service AddOrUpdateDataTableEntry The smart grid widget need a special attribute named TableDefinition This demo sample is{"columns":[{"name":"PrimarySchool","type":"text","display":"PrimarySchool"},{"name":"SecondarySchool","type":"text","display":"SecondarySchool"},{"name":"HighSchool","type":"text","display":"HighSchool"}]} Create mashup which has repeater widgets The mashup over view is like below The first part is aimed to add a new record, the second part (repeater widget)is aimed to display table data, and also update data. In the first part, there are textboxs, labels, smart grid and button widget. They are banded to the service named AddDataTableEntry, aimed to add a new record in the table. (Smart grid is used to add the nested table data) There is a button named AddRecords, bind it’s clicked event to AddDataTableEntry service. And bind the AddDataTableEntry service’s event ServiceInvokeCompleteted to GetDataTableEntries The smart grid widget in here is an empty grid, but it should have a structure at beginning. That’s why to create a service named AddObjInput in step2. It returns an empty table but with the datashape. The second part is a repeater widget. Repeater widget has an attribute named Mashup, bind the mashup Repeatermsh. Bind GetDataTableEntries all data to the repeater widget. There should be some parameters that need to bind like gender, InfoTable, Sname… Testing the demo Note: Smart Grid widget is not a ThingWorx OOTB functionality The smart grid widget can be edited flexible. Please download with is Link https://marketplace.thingworx.com/Items/Smart%20Grid%20Widget There is a thread teach how to use smart grid: https://community.thingworx.com/message/53379#53379
View full tip
Remember that when you are calling an external URL to fetch data via an API call to another system that you must encode special characters specifically. For example the URL that you may type into a browser to test may look like this: https://someserver.somwhere.com:443/apicall?parameter1=test string&parameter2=test^number but when scripting that into a string variable you'll need to replace the space and the carrot with the proper encoded values (%20 and %5E) var params = { username : "me", password : "password", url : "https://someserver.somwhere.com:443/apicall?parameter1=test%20string&parameter2=test%5Enumber", ignoreSSLErrors : false, timeout : 60, headers : headers }; var result = Resources['ContentLoaderFunctions'].LoadXML(params); also note that in this instance we're making a secure connection therefore port 443 (typically the default) was explicitly specified...
View full tip
In this video we cover: a short introduction of Thingworx Analytics Builder The import of the Thingworx Analytics Builder extension   This video applies to ThingWorx Analytics 52.1 till 8.1   Updated Link for access to this video:  Installing Thingworx Analytics Builder:  Part 1 of 3
View full tip
  Step 7: Add JAR Resources   You can add external JARs for use by your extension. Every third-party JAR that is not already included in either the ThingWorx Extension SDK or ThingWorx Core needs to be added to your extension project as a JAR Resource. These JAR resources are added to your metadata.xml as a tag and are used to reference the Java classes in the third-party JAR on which the extension depends. You can either use the Add button   or the ThingWorx Menu from the menu bar to add a new JAR resource. By doing so, the JAR is automatically updated in the metadata file and added to the build path. Although ThingWorx allows developers to include jar files for third-party libraries in their code, it is recommended that you avoid adding jar files for common libraries and instead use the jar files that are included with the SDK. Adding jar files to an extension could cause conflicts with jar files already used by the ThingWorx server, either when uploading an extension, or when an extension executes. Even if your extension works today, future updates to ThingWorx may require updates to your extensions. Similarly, packaging a verison of a commonly used library may mean that a customer will not be able to use your extension together with someone else’s extension.   Select the project to which you want to add the jar file to and select New Jar Resource.       Open the directory in which you have stored the training files for this tutorial. Browse to the Jars directory. Select the json-simple-1.1.1.jar file. Add a description and click Finish. NOTE: This will automatically add json-simple-1.1.1.jar to the lib folder and to your project’s build path. Add httpclient-4.5.6.jar, httpcore-4.4.10.jar and commons-logging-1.2.jar directly into the twx-lib folder in the Project folder. NOTE: These JARs are included in the group of JARs used by ThingWorx by default. In order to build your extension locally, without bundling the jars into your extension that are available on the ThingWorx server, add the above JARs to your project's build path by right-clicking on your project in the Package Explorer, right-click Your_Extension_Project (ie, MyThingWorxWeatherExtension) and select Build Path -> Configure Build Path. Verify the jars we added are in the build path. Otherwise, click Add JARs, then browse to the directory containing these JARs (lib) and add them. NOTE: twx-lib folder is a hidden folder and does not appear in the Eclipse package explorer. The twx-lib folder can be found in the WeatherExtension project inside the Eclipse workspace directory.   Step 8: Create Services   Now that you have created properties, configuration tables and added the required jars, you can begin to add services to your WeatherThingTemplate.   In this part of the lesson, we’ll add a service, UpdateWeatherInfo that will take a City parameter and update the properties of this template using the values obtained from the openWeatherMap API.   Right click inside the WeatherThingTemplate and select ThingWorx Source->Add Service. Create a new service with name UpdateWeatherInfo. Click Add in the Input Parameters frame to add City parameter with a base type STRING.   Set the name and base type of the Output Parameter based on the value that you want the service to return. For simplification, assume this service returns nothing. Set the Base Type to NOTHING. Click Finish to create the service. Copy and Paste the code for UpdateWeatherInfo as specified below. @ThingworxServiceDefinition(name = "UpdateWeatherInfo", description = "updates weather description and temperature properties", category = "", isAllowOverride = false, aspects = { "isAsync:false" }) @ThingworxServiceResult(name = "Result", description = "", baseType = "NOTHING") public void UpdateWeatherInfo( @ThingworxServiceParameter(name = "City", description = "city name", baseType = "STRING") String City) throws Exception { _logger.trace("Entering Service: UpdateWeatherInfo"); String cityProp = this.getPropertyValue("CurrentCity").getStringValue(); if (City == null){ City = cityProp; } else { this.setPropertyValue("CurrentCity", new StringPrimitive(City)); } String url = "http://api.openweathermap.org/data/2.5/weather?q=" +URLEncoder.encode(City,"UTF-8") + "&appid="+ _appid+"&units=imperial"; // create a http client HttpClient client = new DefaultHttpClient(); // create a get request with the URL HttpGet getRequest = new HttpGet(url); // add Accept header to accept json format response getRequest.addHeader("Accept", "application/json"); // send the get request and obtain a response HttpResponse response = client.execute(getRequest); // if response is successful the status code will be 200. if (response.getStatusLine().getStatusCode() == 200) { BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuilder sb = new StringBuilder(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } JSONParser parser = new JSONParser(); JSONObject json = (JSONObject) parser.parse(sb.toString()); JSONArray weather = (JSONArray) json.get("weather"); Iterator<JSONObject> it = weather.iterator(); String description = (String) it.next().get("description"); this.setPropertyValue("WeatherDescription", new StringPrimitive(description)); double temp = (Double) ((JSONObject) json.get("main")).get("temp"); this.setPropertyValue("Temperature", new NumberPrimitive(temp)); /* fire event BadWeather */ _logger.trace("Exiting Service: UpdateWeatherInfo"); } }   Troubleshooting Issue Solution The iterator() is undefined in JSONArray Import only org.json.simple.*. Importing other JSON libraries can give this error. HttpClient/HttpGet could not be resolved to a type. Make sure you have imported the jars: httpclient-4.5.2.jar, httpcore-4.4.5.jar and commons-logging-1.2.jar, json-simple-1.1.1.jar as indicated in the previous chapter. Make sure you have imported the following packages in your template by Eclipse   Your code should be similar to the following:   package com.thingworx.weather; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URLEncoder; import java.util.Iterator; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.slf4j.Logger; import com.thingworx.logging.LogUtilities; import com.thingworx.metadata.annotations.ThingworxBaseTemplateDefinition; import com.thingworx.metadata.annotations.ThingworxConfigurationTableDefinition; import com.thingworx.metadata.annotations.ThingworxConfigurationTableDefinitions; import com.thingworx.metadata.annotations.ThingworxDataShapeDefinition; import com.thingworx.metadata.annotations.ThingworxFieldDefinition; import com.thingworx.metadata.annotations.ThingworxPropertyDefinition; import com.thingworx.metadata.annotations.ThingworxPropertyDefinitions; import com.thingworx.metadata.annotations.ThingworxServiceDefinition; import com.thingworx.metadata.annotations.ThingworxServiceParameter; import com.thingworx.metadata.annotations.ThingworxServiceResult; import com.thingworx.things.Thing; import com.thingworx.types.primitives.NumberPrimitive; import com.thingworx.types.primitives.StringPrimitive; @ThingworxBaseTemplateDefinition(name = "GenericThing") @ThingworxPropertyDefinitions(properties = { @ThingworxPropertyDefinition(name = "CurrentCity", description = "", category = "", baseType = "STRING", isLocalOnly = false, aspects = { "defaultValue:Boston", "isPersistent:true", "isLogged:true", "dataChangeType:VALUE" }), @ThingworxPropertyDefinition(name = "Temperature", description = "", category = "", baseType = "NUMBER", isLocalOnly = false, aspects = { "defaultValue:0", "isPersistent:true", "isLogged:true", "dataChangeType:VALUE" }), @ThingworxPropertyDefinition(name = "WeatherDescription", description = "", category = "", baseType = "STRING", isLocalOnly = false, aspects = { "dataChangeType:VALUE" }) }) @ThingworxConfigurationTableDefinitions(tables = { @ThingworxConfigurationTableDefinition(name = "OpenWeatherMapConfigurationTable", description = "", isMultiRow = false, ordinal = 0, dataShape = @ThingworxDataShapeDefinition(fields = { @ThingworxFieldDefinition(name = "appid", description = "", baseType = "STRING", ordinal = 0, aspects = { "isRequired:true" }) })) }) public class WeatherThingTemplate extends Thing { private static final long serialVersionUID = -5294151832877452442L; public WeatherThingTemplate() {} private static Logger _logger = LogUtilities.getInstance().getApplicationLogger(WeatherThingTemplate.class); private String _appid; @Override public void initializeThing() throws Exception {     super.initializeThing();     _appid = (String) this.getConfigurationSetting("OpenWeatherMapConfigurationTable", "appid"); } @ThingworxServiceDefinition(name = "UpdateWeatherInfo", description = "updates weather description and temperature properties", category = "", isAllowOverride = false, aspects = {     "isAsync:false" }) @ThingworxServiceResult(name = "Result", description = "", baseType = "NOTHING") public void UpdateWeatherInfo(     @ThingworxServiceParameter(name = "City", description = "city name", baseType = "STRING") String City) throws Exception {     _logger.trace("Entering Service: UpdateWeatherInfo");     String cityProp = this.getPropertyValue("CurrentCity").getStringValue();     if (City == null){         City = cityProp;     } else {         this.setPropertyValue("CurrentCity", new StringPrimitive(City));     }     String url = "http://api.openweathermap.org/data/2.5/weather?q=" +URLEncoder.encode(City,"UTF-8") + "&appid="+ _appid+"&units=imperial";     // create a http client     HttpClient client = HttpClientBuilder.create().build();     // create a get request with the URL     HttpGet request = new HttpGet(url);     // add Accept header to accept json format response     request.addHeader("Accept", "application/json");     // send the get request and obtain a response     HttpResponse response = client.execute(request);     // if response is successful the status code will be 200.     if (response.getStatusLine().getStatusCode() == 200) {         BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));         StringBuilder sb = new StringBuilder();         String line = "";         while ((line = br.readLine()) != null) {             sb.append(line);         }         JSONParser parser = new JSONParser();         JSONObject json = (JSONObject) parser.parse(sb.toString());         JSONArray weather = (JSONArray) json.get("weather");         Iterator<JSONObject> it = weather.iterator();         String description = (String) it.next().get("description");         this.setPropertyValue("WeatherDescription", new StringPrimitive(description));         Double temp = (Double) ((JSONObject) json.get("main")).get("temp");         Number number = (Number) temp;         this.setPropertyValue("Temperature", new NumberPrimitive(number));         _logger.trace("Exiting Service: UpdateWeatherInfo");     } } }     Click here to view Part 4 of this guide.
View full tip
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
Signals indicate the predictive strength or weakness of specific features on the goal variable. Use Signals to explore which features are important to predicting outcomes, and which are not. Note: Please be aware that the video states that a model has to be created before Signals can run, but this is no longer the case for version 8.1.   Updated Link for access to this video:  Create Signals In ThingWorx Analytics Builder
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
Introduction to the platform extensibility structures and options. Includes overview of setting up the eclipse plugin and build process, as well as install considerations and best practices.     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
Video Author:                     Asia Garrouj Original Post Date:            March 31, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: This video is the second part of a two part video series walking thru the configuration of Analysis Event which is applied for Real-Time Scoring.  This second video will walk you thru the configuration of Analysis Event for Real Time Scoring and validating that a predictions job has been executed based on new input data.    
View full tip
Video Author:                     Asia Garrouj Original Post Date:            December 9, 2016 Applicable Releases:        ThingWorx Analytics 52.0 to 8.1   Description: This video walks you through how to upload data and shows the configuration settings.   Please Note: In this video, the shown configuration settings page is different for ThingWorx Analytics 8.1.  
View full tip
Announcements