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

Community Tip - Help us improve the PTC Community by taking this short Community Survey! X

IoT Tips

Sort by:
The AddStreamEntries​ snippet does not offer too much information, except that it needs an InfoTable as input. It is however based on the InfoTable for the AddStreamEntity service.     To use the AddStreamEntries table, an InfoTable based on sourceType, values, location, source, timestamp​ and ​tags​ must be used.   In this example, I started with a new Thing based on a ​Stream​ template and the following DataShape:     This DataShape must be converted into an InfoTable with is used as the ​values​ parameter. It's important that the ​timestamp​ parameter has distinct values! Otherwise values matching the same timestamp will be overwritten!   We don't really need the sourceType​ as ThingWorx will automatically determine the type by knowing the source and which kind of Entity Type it is.   I created a new ​MyStreamThing​ with a new service, filling the InfoTable and the Stream. The result is the following code which will add 5 rows to the Stream:     // *** SET UP META DATA FOR INFO TABLE ***   // create a new InfoTable based on AddStreamEntries parameters (timestamp, location, source, sourceType, tags, values)   var myInfoTable = { dataShape: { fieldDefinitions : {} }, rows: [] };   myInfoTable.dataShape.fieldDefinitions['timestamp']  = { name: 'timestamp', baseType: 'DATETIME' }; myInfoTable.dataShape.fieldDefinitions['location']  = { name: 'location', baseType: 'LOCATION' }; myInfoTable.dataShape.fieldDefinitions['source']    = { name: 'source', baseType: 'STRING' }; myInfoTable.dataShape.fieldDefinitions['sourceType'] = { name: 'sourceType', baseType: 'STRING' }; myInfoTable.dataShape.fieldDefinitions['tags']      = { name: 'tags', baseType: 'TAGS' }; myInfoTable.dataShape.fieldDefinitions['values']    = { name: 'values', baseType: 'INFOTABLE' };   // *** SET UP ACTUAL VALUES FOR INFO TABLE ***   // create new meta data   var tags = new Array(); var timestamp = new Date(); var location = new Object(); location.latitude = 0; location.longitude = 0; location.elevation = 0; location.units = "WGS84";   // add rows to InfoTable (~5 times)   for (i=0; i<5; i++) {       // create new values based on Stream DataShape       var params = {           infoTableName : "InfoTable",           dataShapeName : "Cxx-DS"     };       var values = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);       // add something to the values to make them unique       // create and add new row based on Stream DataShape     // only a single line allowed!       var newValues = new Object();     newValues.a = "aaa" + i; // STRING - isPrimaryKey = true     newValues.b = "bbb" + i; // STRING     newValues.c = "ccc" + i; // STRING       values.AddRow(newValues);       // create new InfoTable row based on meta data & values     // add 10 ms to each object, to make it's timestamp unique     // otherwise entries with the same timestamp will be overwritten       var newEntry = new Object();     newEntry.timestamp = new Date(Date.now() + (i * 10));     newEntry.location = location;     newEntry.source = me.name;     newEntry.tags = tags;     newEntry.values = values;       // add new Info Table row to Info Table           myInfoTable.rows = newEntry;       }       // *** ADD myInfoTable (HOLDING MULITPLE STREAM ENTRIES) TO STREAM       // add stream entries in the InfoTable       var params = {           values: myInfoTable /* INFOTABLE */     };       // no return       Things["MyStreamThing"].AddStreamEntries(params);   To verify the values have been added correctly, call the ​GetStreamEntriesWithData​ service on the ​MyStreamThing​
View full tip
Sometimes you need the values from different ThingTemplate members in ONE grid. Therefore it would be great, if you can join 2 "GetImplementedThingsWithData" results into a common one. Here a script that works generally as long as you don't mess with datatypes on same column names. I'm very interested, if someone can find a much easier solution. The Union function was the only one I found suited for the task, but this needs preparation of the infotables upfront. Input: Table1 :Infotable Table2: Infotable Output: Infotable Here the "Snippet": // Define params for an Infotable to hold column names var params = {   infoTableName: "field" /* STRING */ }; // Define column 1 var newField = new Object(); newField.name = "field"; newField.baseType = 'STRING'; // Two 1 columns Infotables to store the field definition; var field1 = Resources["InfoTableFunctions"].CreateInfoTable(params); field1.AddField(newField); var field2 = Resources["InfoTableFunctions"].CreateInfoTable(params); field2.AddField(newField); // Define the cell to add to Infotable var myField = new Object(); myField.field = ""; myField.baseType = "STRING"; // Loop through Table1 var dataShapeFields = Table1.dataShape.fields; for (var fieldName in dataShapeFields) {   logger.debug('field1 name is ' + dataShapeFields[fieldName].name);     myField.field = dataShapeFields[fieldName].name;    field1.AddRow(myField); } // Loop through Table2 var dataShapeFields = Table2.dataShape.fields; for (var fieldName in dataShapeFields) {   logger.debug('field2 name is ' + dataShapeFields[fieldName].name);    myField.field = dataShapeFields[fieldName].name;    field2.AddRow(myField); } // Using inner join functionality to filter only the values that exist in both var params = {   columns2: "field" /* STRING */,   columns1: "field" /* STRING */, joinType: "INNER" /* STRING */,   t1: field1 /* INFOTABLE */, t2: field2 /* INFOTABLE */,   joinColumns1: "field" /* STRING */,   joinColumns2: "field" /* STRING */ }; var commonFields = Resources["InfoTableFunctions"].Intersect(params); // Loop over the result to build a search string var commonColumns = ""; var tableLength = commonFields.rows.length; for (var x = 0; x < tableLength; x++) {   var row = commonFields.rows ;   commonColumns = commonColumns + row.field + ","; } // Reduce Table1 to match only common columns var params = { t: Table1 /* INFOTABLE */, columns: commonColumns /* STRING */ }; var result1 = Resources["InfoTableFunctions"].Distinct(params); // Reduce Table2 to match only common columns var params = {   t: Table2 /* INFOTABLE */,   columns: commonColumns /* STRING */ }; var result2 = Resources["InfoTableFunctions"].Distinct(params); // At the END JOIN the tables together (does not work if colums are different) var params = {   t1: result1 /* INFOTABLE */,   t2: result2 /* INFOTABLE */ }; var result = Resources["InfoTableFunctions"].Union(params);
View full tip
In this post, I show how you can downsample time-series data on server side using the LTTB algorithm. The export comes with a service to setup sample data and a mashup which shows the data with weak to strong downsampling.   Motivation: Users displaying time series data on mashups and dashboards (usually by a service using a QueryPropertyHistory-flavor in the background) might request large amounts of data by selecting large date ranges to be visualized, or data being recorded in high resolution. The newer chart widgets in Thingworx can work much better with a higher number of data points to display. Some also provide their own downsampling so only the „necessary“ points are drawn (e.g. no need to paint beyond the screen‘s resolution). See discussion here. However, as this is done in the widgets, this means the data reduction happens on client site, so data is sent over the network only to be discarded. It would be beneficial to reduce the number of points delivered to the client beforehand. This would also improve the behavior of older widgets which don’t have support for downsampling. Many methods for downsampling are available. One option is partitioning the data and averaging out each partition, as described here. A disadvantage is that this creates and displays points which are not in the original data. This approach here uses Largest-Triangle-Three-Buckets (LTTB) for two reasons: resulting data points exist in the original data set and the algorithm preserves the shape of the original curve very well, i.e. outliers are displayed and not averaged out. It also seems computationally not too hard on the server. Setting it up: Import Entities from LTTB_Entities.xml Navigate to thing LTTB.TestThing in project LTTB, run service downsampleSetup to setup some sample data Open mashup LTTB.Sampling_MU: Initially, there are 8000 rows sent back. The chart widget decides how many of them are displayed. You can see the rowcount in the debug info. Using the button bar, you determine to how many points the result will be downsampled and sent to the client. Notice how the curve get rougher, but the shape is preserved. How it works: The potentially large result of QueryPropertyHistory is downsampled by running it through LTTB. The resulting Infotable is sent to the widget (see service LTTB.TestThing.getData). LTTB implementation itself is in service downsampleTimeseries     Debug mode allows you to see how much data is sent over the network, and how much the number decreases proportionally with the downsampling.   LTTB.TestThing.getData;   The export and the widget is done with TWX  9 but it's only the widget that really needs TWX 9. I guess the code would need some more error-checking for robustness, but it's a good starting point.  
View full tip
Modbus is a commonly used communications protocol that allows data transfer between computers and PLCs. This is intended to be a simple guide on setting up and using a Modbus PLC Simulator with ThingWorx. ThingWorx provides Modbus packages for Windows, Linux and Linux ARM. The Modbus Package contains libraries and lua files intended to be used along with the Edge Microserver. Note: The Modbus package is not intended as an out of the box solution Requirements: ThingWorx Platform Edge Microserver Modbus Package Modbus PLC Simulator In this guide, a free Modbus PLC Simulator​ is used. Here is the direct download link for their v8.20 binary release. Configuring the EMS: The first step is to configure the EMS as a gateway. This is done via adding an auto_bind section in the config.json: "auto_bind": [ {     "name": "ModbusGateway",     "gateway": true }] This creates an ephemeral Thing that only exists when the EMS is running. The next step is to modify the config.lua to include the Modbus configuration. Copy over the contents of the etc folder of the Modbus Package over to the etc folder of the EMS. A sample config_modbus.lua is provided in the Modbus Package as a reference. The following code defines a Thing called MyPLC (which is a Remote Thing created on the Platform): scripts.MyPLC = {     file = "thing.lua",     template = "modbusExample",     identifier = "plc",     updateRate = 2000 } scripts.Thingworx = {     file = "thingworx.lua" } scripts.modbus_handler = {     file = "modbus_handler.lua",     name = "modbus_handler",     host = "localhost" } Adding 'modbusExample' to the above script enables the usage of the same located at /etc/custom/templates/. 'modbusExample' is a reference point for creating a script to add the registers of the PLC. The given template has examples for different basetypes. The different types of available registers are noted and referenced in the modbus.lua file available under /etc/thingworx/lua/. Setting up the PLC Simulator: Extract the mod_RSsim to a folder and run the executable. Since we are 'simulating' a PLC connection, set the protocol to Modbus TCP/IP. Change the I/O to Holding Registers (or any other relevant option), with the Address set to Dec. In the Simulation menu, select 'No animation' if you want to enter values manually or use 'Increment BYTES' to automatically generate values. This PLC Simulator will run at port 502. The Connection: With the EMS & luaScriptResource running, the PLC Simulator should have a connection to the platform with activity on the received/sent section. Now if you open the Remote Thing 'MyPLC' in the platform, the isConnected property (under the Properties section) should be true. (If not, go back to General Information, click on Browse in the Identifier section and select 'plc'). Go back to the Properties section, and click on Manage Bindings. Click on the Remote tab and the list of defined properties should appear. For example, the following code from the modbusExample.lua: properties.Int16HoldRegExample = {key="holding_register/1/40001?format=Int16", handler="modbus_handler", basetype="NUMBER"} denotes a property named Int16HoldRegExample at register 40001. The value at the address 40001 in the PLC Simulator should correspond with the value at the platform once this property is added and the Thing saved. If you are running into any errors when connecting with a Raspberry Pi, please take a look atDuan Gauche's follow up document/ guide - Using your Raspberry Pi with the Edge Microserver and Modbus
View full tip
Hello! I have just written a tutorial on how to set up Lua to be run from the command line. As many already know, there is no good way to debug Lua scripts as they are used in package deployment in Software Content Manager, and building such a debugger is a vast and difficult undertaking. As an alternative, running small portions of code in the command line to ensure they will work as expected is one way to verify the validity of the Lua syntax prior to attempting a deployment. Here are the steps to set up Lua as a command line tool:   Grab the GCC compiler called TDM-GCC Run the exe file and follow the install instructions Remember the install directory for this, as the attached install script will need to be configured in a later step Default location in the install file is "C:\Program Files\TDM-GCC\" Note: leaving the "Add to PATH" selected will allow you to compile C code on the command line as well by typing "gcc" (this is not required for this set-up) Download the Lua source code ​This comes as a ".tar.gz" file, which can be tricky to extract in Windows Download 7zip for freeware which can unzip this type of archive Extract the Lua source code and navigate to the top level directory which should just contain one folder named like "lua-x.x.x" where the x's refer to the version Download and extract the attached zip file containing the build file Copy the "build.cmd" file from this to the top level directory of the Lua source code Modify the configuration as needed: Version number default is 5.3.4 (parameter is called lua_version) GCC install path default is "C:\Program Files\TDM-GCC\bin" (parameter is called lua_build_dir) Double click the "build.cmd" file A console window will appear with installation details If you see the following, then it worked successfully: The "lua\" directory will be created in the same folder as the "build.cmd" file Copy the "lua\" directory to "C:\Program Files\" Open "Computer" > "System Properties" > "Advanced system settings" Click "Environment Variables" > "New..." Call the variable "LUA" and make the value "C:\Program Files\lua\bin" Find the "Path" variable and click "Edit..." At the end of what is already there (do NOT delete anything that is already there), add "%LUA%" (make sure there is a ";" between the previous path and this entry) Click "Ok" Open a new command prompt (has to be new to load the new path) and type "lua" to see if it works Example syntax test from Lua command line:   I hope this is helpful to people! Let me know if you have any questions!
View full tip
Hi everyone,   Maybe you got my email, I just wanted to post this also here.   I built a CSS generator for a few widgets, 8 at the moment. This is on a cloud instance accessible by anyone.   Advantages:      - don't have to style buttons and apply style definitions over and over again      - greater flexibility in styling the widget      - you don't have to write any CSS code   The way this works: you use the configurator to style the widget as you want. Use also a class to define what that widget is, or how it's styled. For example "primary-btn", "secondary-btn", etc. Copy the generated CSS code into the CustomCSS tab in ThingWorx and on the widget, put the CustomClass specified in the configurator.   As a best practice, I'd recommend placing all your CSS code into the Master mashup. And then all your mashups that use that master will also get the CustomCSS. So the only thing you have to do to your widgets in the mashups, is fill the CustomClass property with the desired generated style. Also, comment your differently styled widgets by separating them with /* My red button */ for example.   The mashups for this won't be released, this will only be offered as a service. As you'll see in the configurator, they are not that pretty, the main goal was functionality.   Here is the link to the configurator: https://pp-18121912279c.portal.ptc.io/Thingworx/Runtime/index.html#master=CSSMaster&mashup=ButtonVariables User: guest Password: guest123123   Give it a go and have fun! 🙂   NOTE: I will add more widgets to this in the future and will not take any requests in making it for a specific widget, I make these based on usage and styling capabilities.    
View full tip
Alerts are a special type of event.  Alerts allow you to define rules for firing events.  Like events, you must define a subscription to handle a change in state.  All properties in a Thing Shape, Thing Template, or Thing can have one or more alert conditions defined.   You can even define several of the same type of alert.  When an alert condition is met, ThingWorx throws an event. You can subscribe to the event and define the response to the alert using JavaScript.  Events also fire when a property alert is acknowledged and when it goes out of alert condition.   Alert Types Alerts have conditions which describe when the alert is triggered.  The types of conditions available depend upon the property type.  For example, string alerts may be triggered when the string matches pre-set text.  A number alert may be set to trigger when the value of the number is within a range.   EqualTo: Alert is triggered when the defined Value is reached. Applies to Boolean, DateTime, Infotable (in regard to number of rows), Integer, Long, Location, Number, and String base types. NotEqualTo: Alert is triggered when the defined Value is not reached. Applies to Boolean, DateTime, Infotable (in regard to number of rows), Integer, Long, Location, Number, and String base types. Above: Alert is triggered when the defined Limit is exceeded or met (if the Limit is included).  By default, the Limit is included.  Applies to DateTime, Infotable, Integer, Long, and Number base types. Below: Alert is triggered when the alert value is below the defined Limit or meets it (if the Limit is included).  By default, the Limit is included.  Applies to DateTime, Infotable, Integer, Long, and Number base types. InRange: Alert is triggered when a value is between a defined range.  By default, the minimum value is included, but the maximum can be included as well.  Applies to DateTime, Integer, Long, and Number base types. OutofRange: Alert is triggered when a value is outside a defined range.  By default, the minimum value is included, but the maximum can be included as well.  Applies to DateTime, Integer, Long, and Number base types. DeviationAbove: Alert is triggered when the property value minus the alert Value is greater than the alert Limit ((property value - alert value) > alert Limit).  If the Limit is included, the alert is triggered when the property value minus the alert Value is greater than or equal to the alert Limit ((property value - alert value) >= alert Limit).   By default, the Limit is included.  Applies to DateTime, Integer, Long, Location, and Number base types. DeviationBelow: Alert is triggered when the property value minus the alert Value is less than the alert Limit ((property value - alert value) < alert Limit).  If the Limit is included, the alert is triggered when the property value minus the alert Value is less than or equal to the alert Limit ((property value - alert value) <= alert Limit). By default, the Limit is included.  Applies to DateTime, Integer, Long, Location, and Number base types. Anomaly: Alert is triggered when the property value falls outside of an expected pattern as defined by a predictive model.  Applies to Integer, Long, and Number base types.   Alert types are specific to the data type of the property.  Properties configured as the following base types can be used for alerts:   Boolean Datetime Infotable Integer Location Number String   Creating an Alert When creating an alert:   You can set it to be enabled or disabled Alerts must have a ThingWorx-compatible name and can optionally contain a description You must set the limit(s) to determine when the event fires If an Include Limit is included, the event fires when the Limit Condition is met Not including the Limit causes the event to fire when the Limit Condition is surpassed The priority is a metadata field that enables the addition of a priority. It does not impact the Event/Subscription handling or sequence because the system fires events off asynchronously.   Steps to create or modify an Alert:   Select an existing Property or create a new Property for a Thing, Thing Shape, or Thing Template for which to create/update the Alert Click Manage Alerts Click the New Alert drop-down and select the appropriate Alert Type Note:  The available fields will be vary depending on data type of the Property   Deselect Enabled if you do not wish to make the Alert enabled at the present time (Alert is enabled by default) Provide a Name and optional Description for the Alert Enter a Limit (numeric properties) Select Include Limit? if the value entered in the Limit field should trigger the Alert   Select the appropriate Priority. (The Priority is a metadata field for searching and categorization only.  It does not affect the order of processing, CPU or memory usage.) After defining an Alert, you can click New Alert to add additional alerts of either the same or different condition. You can also click Add New to add additional alerts of the same condition. When all Alerts have been created, click Update Click Done Once all Properties have been updated as needed, click Save   Once Alerts are defined, they appear on the Properties page (while in Edit mode).       After an Alert is defined, a Subscription to that Alert can be configured to launch the appropriate business logic, such as notifying a user of an Event through email or text message.     Monitoring Alerts   When an Alert condition is met, ThingWorx fires off an Alert. You can create a Subscription to the Alert so that you are automatically notified when an Alert is triggered.  Alerts are written to the alert history file and can be viewed through the Alert Summary and Alert History Mashups. The system tracks acknowledged and unacknowledged alerts. Alerts do not fire redundant events. For example, if a numeric property has a rule defined that generates an alert when the value is greater than 50, and a value = 51, an alert is generated and an alert event will fire. If another value comes in at 53 before the original alert is acknowledged, another event will not be fired because the current state is still greater than 50.   The Alert History and Alert Summary streams provide functionality to monitor alerts in the system.  Alert History is a comprehensive log that records all information recorded into the alert stream, where the data is stored until manually removed.   The Alert Summary provides the ability to filter by all alerts, unacknowledged alerts, or acknowledged alerts. You can also acknowledge alerts on a selected property or all alerts from a particular source (thing).   This information can be retrieved using Scripts as well, so you can create your own Alert Summary and History mashups.   From the ThingWorx header, choose Monitoring > Alert History. All Alerts are listed here. Click the Alert Summary Click the Unacknowledged tab to view alerts that have not been acknowledged. Choose to acknowledge an alert on a property or on the source. Type a message in the corresponding field. Click Acknowledge.   For each alert, the following displays: Property name. Source thing – lists the thing that contains this property with the alert. Timestamp – indicates when the alert was triggered. Name and type of alert. Duration – details how long the alert has been active. AckBy – indicates if the alert has been acknowledged and, if so, by whom and when. Message – defaults to the condition but is overwritten with the acknowledge message if one exists. Alert description.    The Alert History screen displays all Alerts that were once in an alert condition, but have moved out of that alert condition.  A Data Filter is provided at the top of the mashup to more easily find a particular Source, Property, or Alert.   The Alert History report is a Thingworx Mashup created using standard Thingworx functionality.  This means that any developer has the ability to re-create this report or a modification of this report.       Acknowledging Alerts   An acknowledgement (ack) is an indication that someone has seen the alert and is dealing with it (for example, low helium in an MRI machine and someone is filling it).  Alert History shows when alerts were acknowledged and any comments.   You can acknowledge an alert on a property or on the source. A source acknowledgment acknowledges all alerts on the source Thing for the selected alert in Monitoring > Alert Summary. A property acknowledgment (ack) only acknowledges the alerts on the property for the selected alert in Alert Summary.   For example, you create a Thing with two properties that have alerts set up. You put both properties in their alert states. View Alert Summary and select the Unacknowledged tab. You should see two alerts. Select one, and do a property acknowledgement. The alert you selected moves to the Acknowledged tab and is removed from the Unacknowledged tab. Put both properties in their alert states again, select one of the alerts on the Unacknowledged tab, and this time do a source acknowledgement. In this case, both alerts move to the Acknowledged tab, even though you only selected one of them.    For more information about Alerts, click here. To view a tutorial video on alerts, click here. Refer to this article for best practices affecting alerts.
View full tip
  Connect a Raspberry Pi to ThingWorx using the Edge Micro Server (EMS).   Guide Concept   This project will introduce you to the Edge MicroServer (EMS) and how to connect your ThingWorx server to a Raspberry Pi device.   Following the steps in this guide, you will be able to connect to the ThingWorx platform with your Raspberry Pi. The coding will be simple and the steps will be very straight forward.   We will teach you how to utilize the EMS for your Edge device needs. The EMS comes with the Lua Script Resource, which serves as an optional process manager, enabling you to create Properties, Services, Events, and Subscriptions for a remote device on the ThingWorx platform.   You'll learn how to   Set up Raspberry Pi Install, configure and launch the EMS Connect a remote device to ThingWorx   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete ALL parts of this guide is 30 minutes.    Step 1: Setup Raspberry Pi   Follow the setup instructions to get your Raspberry Pi up and running with the Raspberry Pi OS operating system. Ensure that your Pi has a valid Ethernet or Wifi connection. If your Pi is connected to a monitor/keyboard, run ifconfig from the Command Line Interface (CLI) to determine the IP address. If you are connecting remotely, probe your local network to find your Pi using one of these methods to determine the IP address. Log into your Raspberry Pi using the userid/password combination pi/raspberry.   Step 2: Install the EMS Download the MED-61060-CD-054_SP10_Microserver-Linux-arm-hwfpu-openssl-5-4-10-1509.zip attached here directly to the Raspberry Pi, or transfer it using a SFTP application such as WinSCP. After downloading the EMS zip file, unzip the archive in a suitable location on the Pi using the command below. Use the Tab key to automatically complete file names. unzip /MED-61060-CD-054_SP9_Microserver-Linux-arm-hwfpu-openssl-5-4-10-1509.zip After unzipping the distribution, a sub-directory named /microserver will be created inside the parent directory. Verify that microserver directory was created with the command ls -l   Switch into the microserver directory with the command cd microserver The microserver directory includes the following files.        File Name                    Description wsems An executable file that runs the Edge MicroServer luaScriptResource The Lua utility that is used to run Lua scripts, configure remote things, and integrate with the host system     Step 3: Create Application Key   In this step, you will be using the ThingWorx Composer to generate an Application Key. The Application Key will be used to identify the Edge Agent. The Application Key is tied to a user and has the same entitlements on the server.   Using the Application Key for the default User (Administrator) is not recommended. If administrative access is absolutely necessary, create a User and place the user as a member of the SecurityAdministrators and Administrators User Groups.   Create the User the Application Key will be assigned to.   On the Home screen of Composer click + New.   In the dropdown list, click Applications Key.   Give your Application Key a name (ie, MyAppKey). Set the User Name Reference to a User you created.   Update the Expiration Date field, otherwise it will default to 1 day. Click Save.   Step 4: Configure the EMS   The EMS consists of two distinct components that do slightly different things and communicate with each other. The first is the EMS which creates an AlwaysOn™ connection to the ThingWorx server. It binds things to the platform and automatically provides features like file transfer and tunneling.   The second is the Lua Script Resource (LSR). It is used as a scripting language so that you can add properties, services, and events to the things that you create in the EMS. The LSR communicates with your sensors or devices. The LSR can be installed on the same device as the EMS or on a separate device. For example, one LSR can be a gateway and send data from several different things to a single EMS.     Open a terminal emulator for the Raspberry Pi. Change directory to microserver/etc. cd microserver/etc Create a config.json file. EMS comes with two sample config files that can be used as a reference for creating your config.json file. The config.json.minimal file provides minimum and basic options for getting started. The config.json.complete provides all of the configuration options.   Create the config.json file in the etc folder. sudo nano config.json Edit the config.json file ws_servers - host and port address of the server hosting the ThingWorx Platform. If you are using a Developer Portal hosted server, your server hostname is listed on the dashboard. {"host":"<TwX Server IP>", "port":443} http_server - host and port address of the machine running the LSR. In this case it will be your localhost running on the raspberry pi. {"host":"127.0.0.1","port":8080, "use_default_certificate": true,"ssl": false, "authenticate": false} appKey - the application key generated from the ThingWorx server. Use the keyId generated in the previous step "Create Application Key". "appKey":"<insert keyId>" logger - sets the logging level for debugging purposes. Set to log at a DEBUG level. ("level":"INFO"} certificates - for establishing a secure websocket connection between the ThingWorx server and the EMS. A valid certificate should be used in a production environment but for debugging purposes you can turn off validation and allow self signed certificates. {"validate":false, "disable_hostname_validation": true} NOTE: To ensure a secure connection, use valid certificates, encryption and HTTPS (port : 443) protocol for establishing a websocket connection between the EMS and the ThingWorx Platform. 5. Exit and Save. ctrl x   Sample config.json File   Replace host and appKey with values from your hosted server.   { "ws_servers": [{ "host": "pp-2007011431nt.devportal.ptc.io", "port": 443 }], "appkey": "2d4e9440-3e51-452f-a057-b55d45289264", "http_server": { "host": "127.0.0.1", "port": 8080, "use_default_certificate": true, "ssl": false, "authenticate": false }, "logger": { "level": "INFO" }, "certificates": { "validate": false, "disable_hostname_validation": true } }     Click here to view Part 2 of this guide. 
View full tip
  Leverage the REST API to create Things, modify Properties, execute Services and more.   GUIDE CONCEPT   This project will introduce you to the REST API utilized by the ThingWorx platform.   Following the steps in this guide, you will be able to connect to the ThingWorx platform and make REST calls to call Services, update Properties, and perform a number of actions for your IoT applications.   We will teach you how to use the ThingWorx REST API to create a more robust application. With the REST API you can leverage the full power of the ThingWorx Foundation server with simple HTTP requests. The REST API can easily be explored using a command line tool such as curl, a browser plugin like Postman, or any preferred programming language.   YOU'LL LEARN HOW TO   Create new Things on a ThingWorx Foundation Server Add Properties to Things Access Property values Execute custom Services   NOTE: The estimated time to complete ALL 4  parts of this guide is 30 minutes.      Step 1: REST API Design   Almost every Entity and Service of ThingWorx can be accessed through the REST API. This step will review some points that are common to all ThingWorx REST API calls.   REST API Syntax   The endpoint URLs used by the REST API follow the consistent pattern shown in the diagram below.   The following table describes the individual pieces of the URL for the REST API calls.   Term Description Optional/Required? http method GET, PUT, DELETE, POST required scheme http, https required host server IP address where ThingWorx is running required port port on which the Web Server is listening for requests (default is 80) optional entity collection One of the built-in entity collection types proprietary to ThingWorx required entity name that identifies a specific characteristic required characteristic collection Names such as Property Definition, Properties VTQ, ThingName, and Service Definition optional characteristic name of the Service or Property on which to execute optional accept header format of HTTP content being requested; must be application/json or text/xml or text/html optional content type header format of HTTP content being provided; must be application/json, text/csv or text/html required content   optional query parameters   optional   Requests   The ThingWorx REST API uses HTTP request verbs in ways common to many REST APIs:   GET to retrieve information POST for both creating a new entity and executing a service DELETE to remove a Thing or Property PUT to change the value of an existing entity When a REST API request requires parameters to be sent, the Content-Type header must be set to match the format of the request body.   Discovering and using Services requires using a dedicated URL. To list available Services and see their definitions, issue a GET to   ``` <server_ip:port>/Thingworx/Things/<name of thing>/ServiceDefinitions ``` In order to execute a listed Service issue a POST to   ``` <server_ip:port>/Thingworx/Things/<name of thing>/Services/<service name> ```   NOTE: The Content-Type header of a POST that executes a Service must always be set to application/json or text/xmleven if the service does not take any parameters and no content is being sent.   Responses   The following tables describe the valid Accept and Content-Type header values when making a REST API calls.   Accept Headers   If the request sends either an invalid Accept header, or no Accept header is supplied, the default response will be in text/html format.   Value Syntax JSON application/json XML text/xml HTML text/html (or omit Accept header) CSV text/csv   Content Type Headers   A Content-Type header indicating the format of data sent to ThingWorx, is required. Some POST requests require a content type header even when no data is being sent.   Value Syntax JSON application/json XML text/xml     Step 2: REST Client   In order to make calls to any REST API you need a client software. A web browser can be used to make some GET calls, but you must install extensions to modify headers or to make POST or PUT calls.   Client software options include:   cURL is a venerable command line tool and library that is a Swiss Army Knife of dealing with web requests. And like an old Swiss Army Knife you can make it work but you might wind up hurting yourself.   Httpie is a modern command line tool with easy to use, intuitive options. Server responses are shown in color with easy to read formatting. The examples will be given as HTTPie commands.   NOTE: The following steps in this guide use Httpie as the client software.     Step 3: Create Application Key   In this Quickstart, you will use ThingWorx Composer to generate an Application Key. A device must be authenticated to send data to, or recieve data from ThingWorx. One of the most common authentication methods used with ThingWorx is by using a security token called an Application Key or appKey. These tokens are associated with a particular user and have the same permissions as that user.   Create an Application Key   On the Home screen of Composer click + New. In the dropdown list, click Applications Key.   Give your Application Key a name (ie, MyAppKey). Set the User Name Reference to a User you created. Update the Expiration Date field, otherwise it will default to 1 day. Click Save.   A Key ID has been generated and can be used to make secure connections.   BEST PRACTICE: We recommend you create separate keys for every connected device, User or system. This allows better security in case of situations where you may need to revoke access from one of them.     Step 4: Create New Thing   A Thing is a basic building block used to model applications in the ThingWorx Foundation Server. All Things are based on a Thing Template, either a built-in system template or a custom Template that was previously created. With the REST API, you can create, modify, list, and delete Things. After a Thing has been created by using an API call, it must be enabled and restarted with additional API calls before it can be used.   Required Parameters   AppKey created by your ThingWorx server A name for the new Thing The name of a valid ThingTemplate that will be used to create the new Thing Request   An HTTP POST request to ThingWorx is assembled from 3 components: a URL A POST body Authentication credentials A request to ThingWorx can be made only after these 3 components are properly configured.         1.  Construct the URL.   Create a new Thing by making an HTTP POST to the endpoint.   <server_ip:port>/Thingworx/Resources/EntityServices/Services/CreateThing NOTE: The server_ip is the ip address of your ThingWorx Core server.        2. Required POST body parameters.   Send the name of the Thing and the name of the ThingTemplate that will define the new thing in the body of the POST as a JSON object. For example, the JSON object below will create a new Thing named SomeTestThing using the system template GenericThing. { "name": "SomeTestThing", "thingTemplateName": "GenericThing" }   TIP: When creating Things that will be used with the REST API, use the GenericThing ThingTemplate or a ThingTemplate based GenericThing. A RemoteThing should only be used with devices that make an AlwaysOn™ connection to a ThingWorx server using the Edge MicroServer or one of the AlwaysOn™ SDKs.        3. Authenticate the 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... Refer to Step 13: Authentication Tags for an overview of different authentication methods. Response   A successful call to the CreateThing service does not return any content in the body of the response, only an HTTP 200 is returned.   Examples HTTPie example:   http -v http://52.201.57.6/Thingworx/Resources/EntityServices/Services/CreateThing appKey==64b879ae-2455-4d8d-b840-5f5541a799ae name=SomeTestThing thingTemplateName=GenericThing   The Content-Type header does not appear in the sample HTTPie call because HTTPie sets the Accept and Content-type request headers to application/json by default.   WARNING for other HTTP clients: Most HTTP clients do not set a Content-Type header by default, without this header set the server will return an error message. The POST request to the CreateThing endpoint has a JSON body so the header must be set to match the format of the request body.   cURL example   curl -v -H "Content-Type: application/json" -X POST -d '{"name": "SomeTestThing","thingTemplateName": "GenericThing"}' http://52.201.57.6/Thingworx/Resources/EntityServices/Services/CreateThing?appKey=d0a68eff-2cb4-4327-81ea-7e71e26bb645 Note: cURL explicitly sets the Content-Type header to application/json.     Validate   The Thing you just created is now available in the ThingWorx Composer, however before anything else can be done with your new Thing through the REST API it must be enabled and started. Follow these steps to validate that the new Thing has been created and enabled.   From the home page of Composer, click Things, select the name of the Thing you just created, then click General Information.   NOTE: You will see the Active checkbox is not checked indicating this Thing is not Enabled.       2. Execute EnableThing Service.   To enable your newly created Thing, make an HTTP POST to the endpoint below. Substitute <name of Thing> with the actual name of the Thing you created. No body is required in the POST, however, the Content-Type header of a POST that executes a Service must always be set to application/json or text/xml even if the service does not take any parameters and no content is being sent. No body is returned upon success, only an HTTP 200 response code. <server_ip:port>/Thingworx/Things/<name of Thing>/Services/EnableThing HTTPie example   http -v -j POST http://52.201.57.6/Thingworx/Things/SomeTestThing/Services/EnableThing appKey==64b879ae-2455-4d8d-b840-5f5541a799ae         3.  Confirm new Thing is Enabled.   To update the General Information section of your new Thing and confirm the Active checkbox is now checked, refresh the page with the browser or close and re-open your Thing.         4. Restart your Thing.   After a Thing is created and whenever any changes are made to its structure, the Thing has to be restarted. Start you new Thing by making a HTTP POST to the endpoint below. Substitute <name of Thing> with the actual name of the Thing you created. No body is required in the POST, however, the Content-Type header of a POST that executes a Service must always be set to application/json or text/xml even if the service does not take any parameters and no content is being sent. No body is returned upon success, only an HTTP 200 response code. <server_ip:port>/Thingworx/Things/<name of Thing>/Services/RestartThing HTTPie example:   http -v -j POST http://52.201.57.6/Thingworx/Things/SomeTestThing/Services/RestartThing appKey==64b879ae-2455-4d8d-b840-5f5541a799ae     Click here to view Part 2 of this guide
View full tip
Learning Paths combine guides into one experience to teach related skills efficiently from start to finish. Begin your learning journey to reduce time to proficiency to get up and running with ThingWorx quickly.   Featured Learning   Utilizing ThingWorx to Secure Your Aerospace and Defense Systems Connect and Monitor Industrial Plant Equipment Vehicle Predictive Pre-Failure Detection with ThingWorx Platform   Industry Solutions   Complex and Automatic Food and Beverage Systems Connect and Configure Industrial Devices and Systems Medical Device Service Monitor Factory Supplies and Consumables Using an Allen-Bradley PLC with ThingWorx   Learn ThingWorx   Getting Started on the ThingWorx Platform Design and Implement Data Models to Enable Predictive Analytics Customize UI and Display Options to Deploy Applications Azure MXChip Development Kit    
View full tip
Predicting time to failure (TTF) or remaining useful life (RUL) is a common need in IIOT world. We are looking here at some  ways to implement it. We are going to use one of the Nasa dataset publicly available that simulates the Turbofan engine degradation (https://c3.nasa.gov/dashlink/resources/139/) . The original dataset has got 26 features as below Column 1 – asset id Column 2 – cycle/time of sensor data collection Column 3- 5 – operational setting Column 6-26 – sensor measurement In the training dataset the sensor measurement ends when the failure occurs.     Data Collection Since the prediction model is based on historic data, the data collection is a critical point. In some cases the data would have been already collected form the past and you need to make the best out of it. See the Data preparation chapter below. In situation where you are collecting data, a few points are good to keep in mind, some may or may not apply depending on the type of data to be collected. More frequent (higher frequency) collection is usually better, especially for electronic measure. In situation where one or more specific sensor values are known to impact the TTF, it is good to take measure at different values of this sensor until the failure without artificially modifying the values. For example, for a light bulb with normal working voltage of 1.5V, it is good to take some measure at let’s say 1V, 1.5V , 2V , 3V and 4V. But each time run till the failure. Do not start at 1.5V and switch to 4V after 1h. This would compromise what the model can learn. More variation is better as it helps the prediction model to generalize. In the same example of voltage it is best to collect data for 1V, 1.5V , 2V , 3V and 4V rather than just 1.5V which would be the normal running condition. This also depends on the use case, for example if we know for sure that voltage will always be between 1.45V and 1.55V, then we could focus only on data collection in this range. Once the failure is reached, stop collecting data. We are indeed not interested in what happens after the failure. Collecting data after the failure will also lead to lower prediction model accuracy. Each failure run should be a separate cycle in the dataset. In other word from a metadata stand point, each failure run should be represented by a different ENTITY_ID. TTF business need Before going into data preparation and model creation we need to understand what information is important in term of TTF prediction for our business need. There are several ways to conceive the TTF, for example: Exact time value when failure might occur This is probably going to be the most challenging to predict However one should consider if it is really necessary. Indeed do we need to know that a failure might occur in 12 min as opposed to 14 min ? Very often knowing that the time to failures is less than X min, is what is important, not the exact time. So the following options are often more appropriate. Threshold For some application knowing that a critical threshold is reached is all that is needed. In this case a Boolean goal, for example lessThan30min or healthy with yes/no values, can be used This is usually much easier than the exact value above. Range For other applications we may need to have a bit more insight and try to predict some ranges, for example: lessThan30min, 30to60min, 60to90min and moreThan90min In this case we will define an ordinal goal The caveat here is that currently ThingWorx Analytics Builder does not support ordinal goal, though ThingWorx Analytics Server does support it. So it only means that the model creation needs to be done through the API. This is the option we will take with the NASA dataset. The picture below shows the 3 different types of TTF listed above   Data Preparation   General Feature engineering Data Preparation is always a very important step for any machine learning work. It is important to present the data in the best suitable way for the algorithms to give the best results. There are a lot of practices that can be used but beyond the scope of this post. The Feature Engineering  post gives some starting point on this. There are also a lot of resources available on the Internet to get started, though the use of a data scientist may be necessary. As an example, in the original NASA dataset we can see that a few features have a constant value therefore there are unlikely to impact the prediction and will be removed. This will allow to free computational resources and prevent confusion in the model. Sensor data resampling The data sampling across the different sensor should be uniform. In a real case scenario we may though have sensors data collected at different time interval. Data transformation/extrapolation should  be done so that all sensor values are at the same frequency in the uploaded dataset. TTF feature Since we want to predict the time to failure, we do need a column in the dataset that represent this values for the data we have. In a real case scenario we obviously cannot measure the time to failure, but we usually have sensor data up to the point of failure, which we can use to derived the TTF values. This is what happens in the NASA dataset, the last cycle corresponds to the time when the failure occurred. We can therefore derive a new feature TTF in this dataset. This will start at 0 for the last cycle when failure occurred, and will be incremented by 1 up to the very first measurement, as shown below:   Once this TTF column is defined, we may need to transform it further depending on the path we choose for TTF prediction, as described in the TTF business need chapter. In the case of the NASA dataset we are choosing a range TTF with values of more100, 50to100, 10to50 and less10 to represent the number of remaining cycles till the predicted failure. This is the information we need to predict in order to plan a suitable maintenance action. Our transformed TTF column look as below:     Once the data in csv is ready, we need to create the json file to represent the metadata. In the case of range TTF this will be defined as an ordinal goal as below (see attachment for the full matadata json file) {         "fieldName": "TTF",         "values": ["less10",                   "10to50",                   "50to100",                   "more100"],         "range": null,         "dataType": "STRING",         "opType": "ORDINAL",         "timeSamplingInterval": null,         "isStatic": false   }   Model creation Once the data is ready it can be uploaded into ThingWorx Analytics and work on the prediction model can start. ThingWorx Analytics is designed to make machine learning easy and accessible to non data scientists, so this steps will be easier than when using other solutions. However some trial and error are needed to refine the model which may also involve reworking the dataset. Important considerations: When dealing with Time to failure prediction, it is usually needed to unset the Use Goal History in the Advanced parameters of the model creation wizard. If using API, the equivalent is to set the virtualSensor parameter to true. Tests with Redundancy Filter enabled should be done as this has shown to give better results. In a first attempt it is a good idea to keep lookback Size to 0. This indicates to ThingWorx Analytics to find the best lookback size between 2, 4, 8 and 16. If you need a different value or know that a different value is better suited, you can change this value accordingly. However bear in mind the following: Larger lookback size will lead to less data being available to train, since more data are needed to predict one goal. Larger lookback do lead to significant memory increase – See https://www.ptc.com/en/support/article?n=CS294545     In the case of the NASA dataset, since we are using an ordinal goal, we need to execute it through API. This can be done through mashup and services (see How to work with ordinal and categorical data in ThingWorx Analytics ? for an example) for a more productive way. As a test the TrainingThing.CreateJob service can be called from the Composer directly, as shown below:       Once the model is created we can check some performance statistics in ThingWorx Analytics Builder or, in the case of ordinal goal, via the ValidationThing.RetrieveResults service. The parameter most relevant in the case of ordinal goal will be the confusion matrix. Here is the confusion matrix I get   Another validation is to compute some PVA (Predicted Vs Actual) results for some validation data. ThingWorx Analytics does validation automatically when using ThingWorx Analytics Builder and present some useful performance metrics and graph. In the case of ordinal goal, we can still get this automatic validation run (hence the above confusion matrix), but no PVA graph or data is available. This can be done manually if some data are kept aside and not passed to the training microservice. Once the model is completed, we can then score (using PredictionThing.RealTimeScore or BatchScore for ordinal goal, or Builder UI for other goal) this validation dataset and compare the prediction result with the actual value. here is one example:     Depending on the business case this model can be deemed acceptable or may need rework, such as change the range values, change learners’ parameters, modify dataset … There is certainly a fair amount of experimentation before creating the optimal model but hopefully this post does give some good starting points.   Resources:   Original Dataset attached as train_FD001-original.csv Transformed dataset attached as train_FD001-TTF-transformed.csv json metadata file for transformed dataset attached as train_FD001-ttford.json                    
View full tip
Since the advent of 6.1.6 we've been able to access the body of a post in a Groovy script.  This frees us from the tyranny of those pesky predefined parameters and opens up all sorts of Javascript object-passing possibilities. To keep this example as simple as possible, there are only two files: postbody.html TestPostBody.groovy postbody.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"             "http://www.w3.org/TR/html4/loose.dtd"> <html> <head>     <title>Scripto Post Body Demo</title>     <meta http-equiv="content-type" content="text/html; charset=utf-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>     <meta name="apple-mobile-web-app-capable" content="yes"/>     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">     <meta http-equiv="refresh" content="3600"> </head> <body> <div id="wrapper"> <div id="header"> <h1>Scripto Post Body Demo</h1> </div> <p> Username:<input type="text" id="username" /><br /> Password:<input type="password" id="password"  /><br /><br /> Enter some valid JSON (validate it <a href="http://jsonlint.com/" alt="jsonlint">here</a> if you're not sure): <br /><textarea id="jsoninput" rows=10 cols=20></textarea><br /> Enter arbitrary Text: <br /><textarea id="textinput" rows=10 cols=20></textarea> <input type="submit" value="Go" id="submitbtn"  onclick="poststuff();"/> </p> <div id="response"></div> </div>         <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>         <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>   <script type="text/javascript">         var poststuff= function(){             var data = {}             var temp             if ($("#jsoninput").val() != ""){                 try {                     temp = $.parseJSON($("#jsoninput").val())                 }                 catch (e){                     temp = ""                 }                 if (temp && temp != ""){                     data = JSON.stringify(temp)                 }             }             else if ($("#textinput").val() != ""){                 data.text = $("#textinput").val()                 data = JSON.stringify(data)             }             else data = {"testing":"hello"}             if ($("#username").val() != "" && $("#password").val() != ""){                 // you need contentType in order for the POST to succeed                 var promise = $.ajax({                     type:"POST",                     url: "http://dev6.axeda.com/services/v1/rest/Scripto/execute/TestPostBody?username=" + $("#username").val() + "&password=" + $("#password").val(),                     data: data,                     contentType:"application/json; charset=utf-8",                     dataType:"text"                 })                 $.when(promise).then(function(json){                     $("#response").html("<p>" + JSON.stringify(json) + "</p><br />Check your console for the object.<br />")                     console.log($.parseJSON(json))                     $("#jsoninput").val("")                     $("#textinput").val("")                 })             }         } </script> </body> </html> TestPostBody.groovy import net.sf.json.JSONObject import groovy.json.JsonSlurper import static com.axeda.drm.sdk.scripto.Request.*; try {     // just get the string body content     response = [body: body]     response.element = []     // parse the text into a JSON Object or JSONArray suitable for traversing in Groovy     // this assumes the body is stringified JSON     def slurper = new JsonSlurper()     def result = slurper.parseText(body)     result.each{ response.element << it } } catch (Exception e) {     response = [                 faultcode: 'Groovy Exception',                 faultstring: e.message             ]; } return ["Content-Type": "application/json","Content":JSONObject.fromObject(response).toString(2)] The "body" variable is passed in as a standalone implicit object of type String.  The key here is that to process the string as a Json object in Groovy, we send stringed JSON from the Javascript, rather than the straight JSON object. FYI: If you happen to be using Scripto Editor, you might like to know that importing the Request class disables the sidebar input of parameters.  You can enter the parameters in the sidebar, but if this import is included the parameters will not be visible to the script. To access the POST body through the Request Object, you can also refer to: Using Axeda Scripto
View full tip
Please note that the below configuration is intended for testing purposes only.  Make sure that your final deployment is within your business security policies. The installation guide can be found at: http://support.ptc.com/WCMS/files/173161/en/ThingWorxDockerInstaller.pdf Postgres: Reference the Installation Guide above for a supported version of Postgres Once deployed, configure it to support remote connections: Navigate to: <PostgresInstallPoint>\data Open the following with a text editor: pg_hba.conf Find the line with IPv4 local connections Change 127.0.0.1/32 to 0.0.0.0/0 Restart PostgreSQL server NOTE: This could open up security vulnerabilities to the database, so make sure you take appropriate security measures if the data will be sensitive Docker: Find the appropriate Docker platform for your OS Docker Community Edition For Windows Server 2016, there is a download for the Edge (Windows Server 2016) under the above link -> Docker CE for Windows -> And then scroll down a little bit Docker Toolbox If you try to deploy the Docker Community Edition on a system that doesn't support, it will direct you to this installation instead At some point during or after the installation, it will prompt you to enable Hyper-V If this is a physical server, these settings will be in your Bios For VMWare, while the VM is powered down, go to VM-> Virtual Machine Properties -> Hardware -> Processors -> Enable 'Virtualize Intel VT-x/EPT or AMD-V/RVI' Restart, and make sure Docker is running (whale icon in your system tray for the Windows Server 2016 edge version) With Docker running, open a command prompt and look at your IP settings For windows Server 2016, right click the start menu -> Command Prompt (admin) and run IPCONFIG Write down the IP assigned to DockerNAT, as this is will be your Postgres HOST later Share your main drive with Docker In Windows Server 2016, right click the docker icon in the system tray -> Settings -> Shared Drives -> C: Thingworx Installation: At this point you should have Docker installed and Postgres remotely configured with only the admin user (postgres) The installer will create the image/container inside of Docker, Install Tomcat, and configure your database Below is a capture of the settings used in the above screenshots.  Anything not listed (like specifying the container name, which is twxfoundation by default) was left as the default values:       Installation Directory: C:\Program Files (x86)\twxEnterpriseFoundationPostgresDocker       ThingWorx License Directory: C:\Users\Administrator\Desktop\license.bin       Local ThingWorx Foundation Port: 8080       Java Initial Heap setting for TWX Foundation: 1024       Java Max Heap setting for TWX Foundation: 2048       RDS Instance: 1     PostgreSQL Host: 10.0.75.1       PostgreSQL Port: 5432       PostgreSQL Admin Schema: postgres       PostgreSQL Admin Username: postgres       PostgreSQL Admin Password: <see note>       PostgreSQL ThingWorx Foundation Schema: thingworx       PostgreSQL ThingWorx Foundation Username: thingworx       PostgreSQL ThingWorx Foundation Password: <see note>       PostgreSQL ThingWorx Tablespace Location: /                     ​NOTE:​ It is highly recommended to use a complex password (Letters of all cases, numbers, and symbols) as we have opened up our database to remote connections RDS was set to Yes (Default is no) PostgreSQL Host is the IP taken from the earlier steps In this example, the Tablespace location is defined inside of Docker, not Windows Post Install: Confirm that Thingworx is running properly by opening a broswer and attempting to log in For our example, the URL is http://10.0.75.1:8080/Thingworx Troubleshooting: If the installation fails, refer to the end of the Installation Guide on where to look for logs, and items that need to be cleaned up before attempting to install again If the install was successful, but connecting fails, run the following in the command prompt to look at the Docker Server's startup logs for hints: Docker logs -f twxfoundation *Note that twxfoundation is the default during installation.  If this was changed in your installation, use that instead
View full tip
Introduction The Edge MicroServer (EMS) and Lua Script Resource (LSR) are Edge software that can be used to connect remote devices to the ThingWorx platform. Using a Gateway is beneficial because, this will allow you to run one instance of the EMS on a server and then many instances of the LSR on different devices all over the world. All communication to the platform will be handled by this one EMS Gateway server. The EMS Gateway can be set up in two different types of scenarios: Self-Identifying Remote Things and Explicitly defined Remote Things​. The scenario I'm going to discuss below will involve explicitly defined Remote Things, a ThingWorx server, an EMS, and a LSR. We will need at least 1 server to run the ThingWorx platform and EMS, but these can always be on separate servers as well. We will also need some other machine or device that will run the LSR. Visit the support downloads page to find the latest EMS releases. The LSR is contained within the EMS download. You can also navigate to the Edge Support site to read more about the EMS and LSR oif this is the first time you have ever configured one. The "ThingWorx WebSocket-based Edge MicroServer Developer's Guide" is also provided inside of the zip file that contains the EMS for further information. Setting up the EMS Once we have obtained the EMS download from the support site (see the section above for links) we can begin creating our config.json file. The image below is a working config.json file for using the EMS as a Gateway. The settings in here are particular to my personal IP addresses and Application Key, but the concept remains the same, and I will go into further detail on the necessary sections, below the image. ws_servers The host and port parameters are always set to the IP address and port that the ThingWorx platform is being hosted on When the EMS and ThingWorx platform are on the same server, "localhost" can be used instead of an IP address appKey The appKey section is the value of an Application Key in the ThingWorx platform that should be used for the authentication of the EMS to the platform An Application Key will need to be created and assigned a user with proper priveledges prior to authenticating certificates The certificates section should be validating and pointing to proper certificates, but in the example above I am not validating any certificates for the sake of simplicity More can be read about the certificates sections here logger The logging section is out of scope of this article, but further reading on ​logger​ configurations can be found here The section in the example above will work for basic logging needs http_server The http_server section configuration parameters will tell the EMS what host and port to spin up a server on and if there is authentication necessary by any LSRs trying to connect The LSR has settings that will explicitly call out whatever value is set to the host and port in this section, so make sure to set these to an open port that is not in use or blocked behind a firewall Further reading on the http_server section can be found here auto_bind You can see above that there are two objects defined in the auto_bind section. One of these is binding the EMS to an EMSGateway Thing in the platform called "EdgeGateway" and the other is defined in the config.lua file for the LSR The gateway parameter is set to true only in the object, "EdgeGateway", that is being used for the EMS to bind to The host and port defined for the "OtherEdgeThing" should point to the port and IP address that the LSR is running on in the other device By default, the LSR runs on port 8001, but you can always double check the listening port by finding the Process Identification (PID) number of the luaScriptResource.exe and then matching the PID to the corresponding line item in the output of netstat -ao command in a console window The protocol can be set to "http" in an example application, but make sure to use "https" when security is of concern All further reading on the sections of the config.json file can be found in the config.json.complete file included with the EMS download and on the Edge Help Center under the "Creating a Configuration File" section and the "Viewing All Options" section. Setting up the LSR In this example, the LSR is going to run on a separate server and point to the EMS server. Below is a screenshot of two very important additions (rap_host and rap_port) to the default config.lua file: rap_host The rap_host field should be set to the IP address where the EMS is hosted rap_port The rap_port field should be set to the port parameter defined in the config.json http_server section script_resource_host The ​script_resource_host​ field must be set to ensure that the EMS will know what IP address to communicate with the LSR at scripts.OtherEdgeThing This line is necessary to identify what the name of the LSR is that will register with the EMS to bind to the platform "OtherEdgeThing" can be changed to anything, but make sure that the auto_bind section in the config.json aligns with what you've defined in the config.lua file at this line Running the EMS and LSR Now that we have configured the LSR and EMS to point to each other and the platform we can try running both of these applications to make sure we are successful. Make sure the ThingWorx platform is running Create a RemoteThing with the name given in the auto_bind section for the LSR we are connecting Create an EMSGateway with the name given in the auto_bind section for the EMS as a Gateway to bind to Start the EMS This can be done by double clicking the wsems.exe when in Windows, running it as a service, or running it directly from the command line Start the LSR This can be done by double clicking the luaScriptResource.exe when in Windows, running it as a service, or running it directly from the command line Navigate to the ThingWorx platform and make sure that the Things you have created are connected Do this by navigating to the Properties menu option and refreshing the isConnected property You should be able to browse remote properties and services for each bound RemoteThing, and this means you have successfully setup the EMS as a Gateway device to external LSR applications running on remote devices Any further questions about browsing remote properties or other configuration settings in the .config files is most likely addressed in the Edge Help Center under the EMS section​, and if not, feel free to comment directly on this document.
View full tip
    Step 11: Build Extension   You can use either Gradle or Ant to build your ThingWorx Extension Project. Ant is the preferred method.   Build Extension with Gradle   Right click on your project ->Gradle (STS)->Tasks Quick Launcher.     NOTE: This opens up a new window.   Set Project from the drop-down menu to your project name and type Tasks as build. Press Enter   NOTE: This will build the project and any error will be indicated in the console window. Your console window will display BUILD SUCCESSFUL. This means that your extension is created and stored as a zip file in your_project->build->distributions folder.   Build Extension with Ant   Go to the Package explorer -> your_project->. Right click on build-extension.xml->Run As->Ant Build   Your console output will indicate BUILD SUCCESSFUL.   NOTE: This will build your project and create the extension zip in the your_project->build->distributions folder of your project.     Step 12: Import Extension    If you have valuable data on your ThingWorx server, save the current state before importing an untested extension by duplicating and renaming the ThingworxStorage directory. This will save all current entities and a new, empty ThingworxStorage directory will be generated when Tomcat is restarted. To restore your saved state, rename the duplicate directory back to ThingworxStorage. Alternatively, If you do not back up your storage, make sure that any entities you want to save are exported into xml format. This way you will be able to restore your ThingWorx server to its initial state by deleting the storage directory before importing the saved entities.   Import Extension In the lower left corner, click Import/Export, then select Import. NOTE: The build produces a zip file in ProjectName->build->distributions folder. This zip file will be required for importing the extension. For the Import Option option, select Extension. Click Browse and choose the zip file in the distributions folder (located in the Exclipse Project's build directory). Click Import.   Create a Thing   Create a Thing using the ThingWorx Composer with the Thing Template set to the WeatherThingTemplate.     Open the ConfigurationTable tab and add the appid from the OpenWeatherMap.org site.   Open the WeatherAppMashup Mashup by searching for WeatherAppMashup in the Search bar.   Click View Mashup in the WeatherAppMashup Mashup window. Type the name of a city (eg. Boston) and click go.   NOTE: You can now see the current temperature reading and weather description of your city in the Mashup.   Troubleshooting   If your import did not get through with the two green checks, you may want to modify your metadata.xml or java code to fix it depending on the error shown in the logs.   Issue Solution JAR Conflict arises between two similar jars JAR conflicts arise when a similar jar is already present in the Composer database. Try to remove the respective jar resources from the metadata.xml. Add these jars explicitly in twx-lib folder in the project folder inside the workspace directory. Now, build the project and import the extension in ThingWorx Composer once again. JAR is missing Add the respective jar resource in metadata.xml using the ThingWorx->New Jar Resource. Now, build the project and import the extension in ThingWorx Composer once again. Minimum Thingworx Version [ 7.2.1] requirements are not met because current version is: 7.1.3 The version of SDK you have used to build your extension is higher than the version of the ThingWorx Composer you are testing against. You can manually edit the configfiles->metadata.xml file to change the Minimum ThingWorx version to your ThingWorx Composer version.   Step 13: Next Steps    Congratulations! You've successfully completed the Create an Extension tutorial, and learned how to:   Install the Eclipse Plugin and Extension SDK Create and configure an Extension project Create Services, Events and Subscriptions Add Composer entities Build and import an Extension   Learn More We recommend the following resources to continue your learning experience:" Capability Guide Build Application Development Tips & Tricks Additional Resources If you have questions, issues, or need additional information, refer to: Resource Link Community Developer Community Forum Support Extension Development Guide
View full tip
There are some scenarios where you don't necessarily want to connect to your corporate mail server, or a public mail server like gmail - e.g. when testing a new function that possibly spams the official mail servers - or the mail server is not yet available. In such a scenario it might be a good idea to use a custom, private mail server to be able to send and receive emails locally on a test- or development-environment.   In this post I will show how to use the hMailServer and setup the ThingWorx mail extension to send emails. This post will concentrate on installing and deploying within a Windows environment. More specifically on a Windows 2012 R2 server virtual machine.   Installing hMailServer   Download and install the ​.NET Framework 3.5 (includes .NET 2.0 and 3.0)​. In Windows Server 2012 R2 open the Server Manager and in the Configuration add roles and features.​ Click through the "Role-based or feature-based installation" steps and install the ".NET Framework 3.5 Features" in case they are not already installed.   Download ​hMailServer​ via https://www.hmailserver.com/download As always: the latest version is more stable while the beta versions might provide more functionality and additional bug fixes. This post is based on version 5.6.6-B2383. Functionality and how-to-clicks might change in other versions.   Note: The Microsoft .NET Framework is required for this installation. In case the .NET installation fails by installing it with the hMailServer framework, it's best to cancel the installation and install the required .NET Framework manually instead of the automatic download and installation offered by hMailServer. In case of such a failure it's best to play it safe and uninstall the mail server again, install the .NET framework manually and then re-install hMailServer. (Any left-over directories should be deleted before re-installing)   For the installation, choose your path and a ​full​ installation. Use the built-in database engine​, set a password for the administrative user and install.   Configuring hMailServer   The hMailServer Administrator opens automatically after the installation - if not you will find it in the Start menu. Connect to the default instance on the localhost. The password is the one set up during the installation process.   ​Add a domain​ (e.g. mycompany.com) and ​save​ it. The domain will specify the domain of the mail-addresses e.g. user@domain (me@mycompany.com).   In the domain add an account​. Specify the address (e.g. noreply) and set a password (e.g. ts). ​Save​ the new account.   The default port used for SMTP is 25​. For POP3 it's ​110​. This is configured under Settings > Advanced > TCP/IP ports​ Ensure the ports for SMPT and POP3 are not blocked by a firewall in case you run into issues later on.   This setup should *usually* work. However there might be hostname specific SMTP issues. In case something happens / or to avoid errors in the first place, go to Settings > Protocols > SMTP > Delivery of e-mail​ and specific the ​Local host name​. This should be the fully qualified hostname of the server (e.g. myserver.this.company.com).   Test hMailServer via telnet   Note: telnet needs to be installed for this test - in case it's not installed, Google can help.​​​   Open a command line window and execute: telnet <yourhostname> 25 This will open a connection to the SMTP port of the hMailServer. Manual commands can be send to test if the basic send functions are working. The following structure can be used for testing - it holds manual input and responses.   Username and password need to be Base64 encoded. See https://www.base64encode.org/ for Base64 conversions. (Tip: only text, don't add additional spaces or line breaks - otherwise the hash will be quite different!)   Command / Response Description 220 <HOSTNAME> ESMTP Connected to host HELO mycompany.com Connect with domain as defined in hMailServer 250 Hello. Connected AUTH LOGIN Login as authenticated user 334 VXNlcm5hbWU6 Base64 for "Username:" bm9yZXBseUBteWNvbXBhbnkuY29t Base64 for "noreply@mycompany.com" 334 UGFzc3dvcmQ6 Base64 for "Password:" dHM= Base64 for "ts" 235 authenticated. Authentication successful MAIL FROM: noreply@mycompany.com Sender address 250 OK   RCPT TO: <your real mail address> To address 250 OK   DATA ​Body​ 354 OK, send.   Subject: sending mail via telnet ​Subject ​line   Blank line to indicate end of subject just a simple test! ​Content​ . . indicates the end of mail 250 Queued (10.969 seconds) Mail queued and sent with duration QUIT Log off telnet 221 goodbye   Connection to host lost. Log off confirmed     Configuring ThingWorx   Download and configure the mail extension   Download the MAIL EXTENSION from the ThingWorx Marketplace https://marketplace.thingworx.com/Items/mail-extension   In ThingWorx, click Import / Export > Extensions > Import​, choose the downloaded .zip file and import it. The Composer should be refreshed to reflect the changes introduced by the extension.   The Extension created a new Thing Template: MailServer​   Create a new ​Thing​ based on the MailServer Template​. In its configuration adjust the servername and port to match the hMailServer configuration, e.g. localhost and port 25. Change the Mail User Account and Password to the authentication user (e.g. noreply@mycompany.com / ts). ​Save​ the configuration to persist the changes.   In any Thing, create a new Service to send mails and notifications. Insert a snippet based on Entities > <yourMailThing> > Send Message​ Call the service manually for an initial functional test. It should look similar to this... but parameters need to be adjusted to your environment:   var params = {   cc: undefined /* STRING */,   bcc: undefined /* STRING */,   subject: "sending email via ThingWorx" /* STRING */,   from: "noreply@mycompany.com" /* STRING */,   to: "<your real mail address>" /* STRING */,   body: "just a simple test!" /* HTML */ };   // no return Things["<yourMailThing>"].SendMessage(params);   Check your mailbox for incoming messages!   What next?   The mail server can also be used to receive emails. So instead of sending mails to your regular mail address and risking a ton of spam (depending on your services and frequency of sending automated emails), you could also configure a local Outlook / Thunderbird / etc. installation and send mails directly to the noreply@mycompany.com address. Those mails can then be downloaded from hMailServer via POP3.   With this the whole send AND receive mechanism is contained within a single (virtual) machine.
View full tip
Hello, There have been some inquires about how can one use AngularJS for developing custom parts that can run in the ThingWorx environment. To address these inquires I have created a document that describes the process of integrating AngularJS with ThingWorx. The document attached comes with the source code for the examples presented throughout the document and an extension for AngularJS 1.5.8 and angular-material components. Feedback is appreciated. Thank you.
View full tip
In this post, I will use an instance of InfluxDB and Chronograf. See this post for installing both using Docker. InfluxDB - Time Series Databases   InfluxDB is a time series database. It allows users to work with and organize time series data. The advantage of such a database system is that it comes with built-in functionality to easily aggregate and operate on data based on time intervals. Other types of databases can do this as well - but time series databases are heavily optimized for this kind of data structures which will show in storage space and performance.   Data is stored in the database with its timestamp, its value and one or more tags.   Time Temperature Humidity Location 2019-01-24T00:00:00 23 42 Home 2019-01-24T00:01:00 22 43 Home 2019-01-24T00:02:00 21 44 Home 2019-01-24T00:03:00 23 45 Home 2019-01-24T00:04:00 24 42 Home 2019-01-24T00:05:00 25 43 Home 2019-01-24T00:06:00 23 44 Home   Values can be aggregated by intervalls, i.e. "give me the temperatur values within the last hour and take the average for 5 minutes". This would result in (60 / 5) = 12 results with a value that represents the average temperature within this 5 minute interval.   Example: Temperature Data averaged by 4 minutes   Time Temperature 2019-01-24T00:00:00 (23 + 22 + 21+ 23) / 4 = 22,25 2019-01-24T00:04:00 (24 + 25 + 23) / 3 = 24   To find out more about InfluxDB see also https://www.influxdata.com/time-series-database/ and https://www.influxdata.com/time-series-platform/   InfluxDB in ThingWorx   The new ThingWorx 8.4 release comes with an option to setup InfluxDB as additional Persistence Provider. Meta Data like Entity Definitons will still be stored in PostgreSQL. Streams, Value Streams and Data Tables however can be stored in InfluxDB.   The InfluxDB Persistence Provider setup is delivered with the PostgreSQL installation package for ThingWorx. Currently ThingWorx does not allow any aggregation of data with its built-in InfluxDB capabilities.   Prepare InfluxDB   InfluxDB will need a user and a database. Connect via Chronograf - the graphical UI to administer InfluxDB and create a new user via   InfluxDB Admin > Users Default username = twadmin Default password = password Permissions = ALL   Create a new database via   InfluxDB Admin > Databases Default database name = thingworx   Configure ThingWorx   Create a new Persistence Provider for InfluxDB in ThingWorx - but don't mark it as active yet!     Switch to the Configuration and change the username / password, database and hostname to match your installation.     Save the configuration, switch back to the General tab and mark the InfluxDB Persistence Provider as Active.   Save again and a "successful" message will be shown. If the save action failed, the connection settings are not correct - check for the correct ports and for any typos.   Creating Entities & Testing   Streams, Value Streams and Data Tables can now be created using the new InfluxDB Persistence Provider.   To test with a Value Stream   Create a new Thing with some NUMBER properties, e.g. 'a', 'b' and 'c' as properties - ensure they are marked as logged as well Name = InfluxValueStreamThing Create a new ValueStream based and change its Persistance Provider to the InfluxDB created above Name = InfluxValueStream Save both Entities Setting values for the properties will now automatically create the entries in InfluxDB - including the Entity name "InfluxValueStreamThing" Running the QueryPropertyHistory service on the Thing will return the results as an InfoTable In Chronograf this will display like this:   ThingWorx 8.4 will be released end of January 2019. Be sure to check out and test the new Persistence Provider features!
View full tip
Greetings, Community Members! PTC has launched ThingWorx 9.6.0 as of June, and it's now ready for your upgrade! Let's explore the key enhancements in this latest version of ThingWorx.   What are the top three areas of updates in ThingWorx 9.6?   Performance, Scalability, Reliability, and Security: There's a significant boost in file transfer performance between connected devices and the ThingWorx platform. A notable enhancement in server startup performance, with some instances showing an 84% reduction in startup time. Numerous logging improvements, including limitations on log verbosity, log filtration, and configurable log storage capabilities, contribute to the stabilization of the ThingWorx system. Additionally, ThingWorx now supports log extraction to third-party software like Sumologic, Datadog, Splunk, Grafana, etc., utilizing the industry-standard OpenTelemetry framework starting from TWX 9.6. Content Security Policy has been implemented, fortifying ThingWorx against script and data injection attacks, man-in-the-middle (MITM) attacks, and clickjacking. Several tech stack updates in 9.6; support now available for Azure B2C and TLS 1.3 (limited)   Developer Productivity: Introducing a new Collection widget with improved performance, enabling a transition away from the legacy Collection and Repeater widgets. Several other new widgets such as KPI dial widget, Tree selector widget, Progress Tracker widget and other critical enhancements for ThingWorx WebComponents are now available Support for viewing mashup configurations such as layouts, bindings, and widget properties in a read-only mode, helping improve user experience by allowing multiple users to review mashup designs simultaneously without making edits.   Solutions updates: Streamlined continuous improvement with the ability to View and Create Actions in One-Click from performance analysis screens for the Digital Performance Management (DPM) solution. Enhanced performance for the Asset Monitoring & Utilization (AMU) solution, with alarm events creation now handled asynchronously. Several fixes and improvements for Connected Work Cell (CWC), Real-Time Production Performance Monitoring (RTPPM), and DPM such as limits evaluation, messages not displayed, incorrectly calculated KPIs and issues with Running Time on the operator display and more, helping customers achieve continuous improvements in their manufacturing operations   View release notes here and be sure to upgrade to 9.6!   Dilanur Bayraktar ThingWorx Product Management
View full tip
There are a lot of new and exciting changes included in ​ThingWorx 8.0.0, which is due out today, and no doubt, you'll want to get a test environment set up to try them out.  But there are a few changes that could impact your ability to get up and running with a new server that I wanted to share with everyone. IMPORTANT – Changes to Licensing in ThingWorx 8.0.0 In ThingWorx 7.4.0, a new Licensing Subsystem was introduced, and the license file required was provided as part of the ThingWorx 7.4.0 platform download.  As of ThingWorx 8.0.0, the license.bin file will no longer be provided with the platform download, but will instead need to be downloaded from the PTC Licensing Tool on the PTC eSupport Portal. As part of the operating system specific Installing ThingWorx (OS) sections in the Installing ThingWorx 8.0 guide, additional steps have been added that outline how to use the PTC Licensing Tool to download and install the ThingWorx license file for your organization. The license file downloaded from the ThingWorx Licensing Tool must be renamed to license.bin and copied to the /ThingworxPlatform directory prior to starting ThingWorx for the first time.  The server will fail to start if it cannot find this license file. For more information:      KCS Article 264374 - ThingWorx 8.0.0 Licensing IMPORTANT – Default Administrator Password for ThingWorx Composer is Changing in 8.0.0 In order to help encourage the use of secure passwords for the Administrator account on ThingWorx servers, the default Administrator account password will be changing in version 8.0 and above.  The new Administrator password is a complex password containing mixed case and special characters. This will encourage administrators to change their default, fully-privileged account password to one that is more secure and conforms to their organizational security standards. Information about the new default password can be found in each of the operating system specific Installing ThingWorx (OS) sections of the Installing ThingWorx 8.0 guide. PTC strongly advises against the use of any default password on any product, and encourages administrators to immediately change any default password to a proper, complex password. For more information: KCS Article 264270​ - ​Unable to log into ThingWorx 8.0 Composer using the default Administrator login Application Key Usage is Changing in 8.0.0 As part of an effort to better secure the ThingWorx Platform, the use of Application Keys as URL parameters (through the ‘appkey’ parameter) is being deprecated in ThingWorx 8.0.0. For example, the following URL uses the now deprecated ‘appkey’ parameter to pass in an application key:               https://thingworx.server.com/ThingWorx/Things/MyThing/Services/MyService?appkey=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx When included in the URL, the ‘appkey’ parameter becomes a browser-cacheable, clear-text rendition of a usable application key.  A knowledgeable user could retrieve this application key from their browser history and use it to perform unauthorized actions against a ThingWorx server. For full security, GET and POST requests that are run against a ThingWorx server should be performed over an HTTPS connection and should include the required application key in the request’s headers.  Query string parameters are visible in both HTTP and HTTPS contexts, and by moving the application key into the request headers, the application key itself is encrypted as part of the HTTPS request. (Note that the application key in a header is still visible for plaintext HTTP connections though!) By default, new installations of ThingWorx 8.0.0 will have the Allow Application Key as URL Parameter option disabled.  Upgrades from previous versions of ThingWorx will retain the ability to use the ‘appkey’ query string parameter, but PTC strongly encourages customers to promptly update any solutions that are dependent on sending the appkey using a URL parameter to move to request headers instead.  Please note that a future release of ThingWorx may completely disable the use of application keys as URL parameters. The Allow Application Key as URL Parameter option can be enabled or disabled on the ThingWorx PlatformSubsystem’s configuration page, accessible at System > Subsystems > PlatformSubsystem > Configuration. For more information: KCS Article 264349 - ThingWorx Appkey URL Parameter is Deprecated as of ThingWorx 8.0.0 Changes to Default Visibility (Organizations) in ThingWorx 8.0.0 Starting in ThingWorx 8.0.0, the Everyone organization will no longer be granted default visibility across all entity collections.  Only users who are a member of the Administrator group will be able to see ThingWorx entities on a newly installed server; any additional visibility permissions will need to be explicitly granted by the Administrator. This is a change in behavior from the previous ThingWorx releases where the Everyone organization (of which the all-encompassing Users group was a member) was granted visibility access by default to all entity collections. Visibility permissions had to explicitly be removed by the Administrator during solution development, which could be overlooked. For more information: KCS Article 264351 - Changes to Default Visibility (Organizations) in ThingWorx 8.0.0
View full tip
Thingworx provides a library of InfoTable functions, one of the most powerful ones being DeriveFields (besides that I use Aggregate and Query a lot and ... getRowCount) DeriveFields can generate additional columns to your InfoTable and fill that with values that can be derived from ... nearly anything! Hard coded, based on a Service you call, based on a Property Value, based on other values within the InfoTable you are adding the column to. Just remember for this Service (as well as Aggregate), no spaces between different column definitions and use a , (comma) as separator. Here are some two powerful examples: //Calling another function using DeriveFields //Note that the value thingTemplate is the actual value in the row of column thingTemplate! var params = {   types: "STRING" /* STRING */,   t: AllItems /* INFOTABLE */,   columns: "BaseTemplate" /* STRING */,     expressions: "Things['PTC.RemoteMonitoring.GeneralServices'].RetrieveBaseTemplate({ThingTemplateName:thingTemplate})" /* STRING */ }; // result: INFOTABLE var AllItemsWithBase = Resources["InfoTableFunctions"].DeriveFields(params); //Getting values from other Properties //to in this case is the value of the row in the column to //Note the use of , and no spaces //NOTE: You can make this even more generic with something like Things[to][propName] var params = {     types: "NUMBER,STRING,STRING,LOCATION" /* STRING */,     t: AllAssets /* INFOTABLE */,     columns: "Status,StatusLabel,Description,AssetLocation" /* STRING */,     expressions: "Things[to].Status,Things[to].StatusLabel,Things[to].description,Things[to].AssetLocation" /* STRING */ }; // result: INFOTABLE var AllAssetsWithStatus = Resources["InfoTableFunctions"].DeriveFields(params);
View full tip
Announcements