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

Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X

IoT Tips

Sort by:
    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
    Step 4: Create Extension Project   In this tutorial, you will create a ThingWorx extension that retrieves weather information using OpenWeatherMap API. Create Account In this part of the lesson, you will create a free account in OpenWeatherMap that creates an AppKey so you can access their REST API. Sign-up for a free account. Log in to your account. Create a new API Key   NOTE: We will use this generated API key as a parameter in the REST calls.   Create New Extension Project   NOTE: Make sure that you are in the ThingWorx Extension Perspective. To verify, you should see a plus icon:   in the menu bar. If you don’t see this, you are probably in the wrong perspective. Go back to the previous step to learn how to set the perspective to ThingWorx Extension in Eclipse.   Go to File->New->Project. Click ThingWorx->ThingWorx Extension Project.  Click Next. NOTE: A New ThingWorx Extension window will appear. Enter the Project Name (for example, MyThingworxWeatherExtension). Select Gradle or Ant as your build framework. Enter the SDK location by browsing to the directory where the Extension SDK is storeed.   NOTE: The Eclipse Plugin accepts the Extension SDK version 6.6 or higher. Enter the Vendor information (for example, ThingWorx Labs). Change the default package version from 1.0.0 to support extension dependency. NOTE: The information from ThingWorx Extension Properties is used to populate the metadata.xml file in your project. The metadata.xml file contains information about the extension and details for the various artifacts within the extension. The information in this file is used in the import process in ThingWorx to create and initialize the entities. Select the JRE version to 1.8. Click Next then click Finish. Your newly created project is added to the Package Explorer tab.   Create New Entity   Select your project and click Add to create a new entity. NOTE: You can also access this from the ThingWorx menu on the menu bar. Create a Thing Template for your MyThingWorxWeatherExtension Project.   NOTE: In this guide, we are using a Template, but in a real-world scenario, you may consider using a Thing Shape to encapsulate extension functionality. By using Thing Shapes you give users of your extension the ability to easily add new functionality to existing Things. It is simple to add a new Thing Shape to an existing Thing Template, while using the properties or services defined by a Thing Template would require recreating all existing assets using the new Template. Since subscriptions cannot be created on Thing Shapes, you might choose to create Thing Templates that implement one or more subscriptions for convenience. In the pop-up window, browse to add the source folder of your project in Source Folder. NOTE: It should default to the src directory of your project. In our case it will be MyThingworxWeatherExtension/src. Browse to add the package where you want to create this new class, or simply give it a name (such as com.thingworx.weather). Enter a name and description to your Thing Template (WeatherThingTemplate).  NOTE: By default, the Base Thing Template is set to GenericThing. Select Next. NOTE: If you want to give other users of this entity permission to edit it in ThingWorx Composer, select the entity as an editable entity. Only non-editable entities can be upgraded in place; editable entities must be deleted and recreated when your extension is updated. If you need to make it possible to customize the extension, consider using a configuration table to save user customizations. Select Finish.   Verify that you have a WeatherThingTemplate class created that extends the Thing class. @ThingworxBaseTemplateDefinition(name = "GenericThing") public class WeatherThingTemplate extends Thing { public WeatherThingTemplate() { // TODO Auto-generated constructor stub } } NOTE: You might see a warning to add a serial version. You can add a default or generated serial value.   Step 5: Add Properties    In this section, you are going to add CurrentCity, Temperature and WeatherDescription properties to the WeatherThingTemplate. These properties are associated with the Thing Template and add the @ThingworxPropertyDefinitions annotation before the class definition in the code.   Right click inside the WeatherThingTemplate class or right click on the WeatherThingTemplate class from the Package Explorer. Select ThingWorx Source-> Add Property. In the popup window, create a property to store the city name. Name = CurrentCity, Base Type = STRING, Description = ‘’ Select the Has Default Value checkbox and enter a city name (eg. Boston). This will be the default value unless a specific value is passed. Select the “Persistent” checkbox. This will maintain the property value if a system restart occurs. NOTE: If you select the Logged checkbox, the property value is logged to a data store. If you select the Read Only checkbox, the data will be static. Select VALUE from the Data Change Type drop down menu       NOTE: This allows any Thing in the system to subscribe to a data change event for this property. Choose to use one of the following Data Change Types:   Data Change Type Description Always Fires the event to subscribers for any property value change Never Does not fire a change event On For most values, any change will trigger this. Off Fires the event if the new value is false Value For numbers, if the new value has changed by more than the threshold value, fire the change event. For non-numbers, this setting behaves the same as Always. Select Finish. Create another property called Temperature with a base type of NUMBER. You can keep the default values for the other parameters. Create another property called WeatherDescription with a base type of STRING. Keep the default values for the other parameters.   Step 6: Create Configuration Table   In this part of the lesson, we will create a configuration table to store the API Id that you generated from the openMapsWeather. Configuration tables are used for Thing Templates to store values similar to properties that do not change often.   Right-click inside the WeatherThingTemplate class and select ThingWorx Source->Add Configuration Table. Create a new configuration table with name OpenWeatherMapConfigurationTable. Click Add in the Data Shape Field Definitions frame. NOTE: Configuration tables require fields (columns) with a defined table structure (DataShape). Enter appid as the name with a base type STRING. Select the Required checkbox. Click OK, then Finish to add the Configuration Table To use the appid in the REST calls, you need to obtain the value from the configuration table and assign it to a field variable in the Java code. We will use the initializeThing method to obtain the appid value at runtime. NOTE: The initializeThing() method acts as an initialization hook for the Thing. Every time a Thing is created or modified, this method is executed and the value of appid is obtained from the configuration table and stored in a global field variable of the class. initializeThing() must call super.initializeThing() to ensure it performs initialization of the Thing. Create the initializeThing() method and field variable _appid with base type STRING anywhere in the WeatherThingTemplate class. private static Logger _logger = LogUtilities.getInstance().getApplicationLogger(WeatherThingTemplate.class); private String _appid; @Override public void initializeThing() throws Exception { super.initializeThing(); _appid = (String) this.getConfigurationSetting("OpenWeatherMapConfigurationTable", "appid"); } NOTE: In the code above we used ThingWorx LogUtilities to get a reference to the ThingWorx logging system, then assigned the reference to the variable _logger. In the steps below we will use this variable to log information. There are multiple kinds of loggers and log levels used in the ThingWorx Platform, but we recommend that you use the application or script loggers for logging anything from inside extension services. If prompted to import the logger, use slf4j.     Click here to view Part 3 of this guide.
View full tip
    Step 9: Create Event and Subscription   In this section, you will create a mechanism to notify the user when inclement weather occurs. For example, whenever the weather indicates storm/snow/rain, an Event should be triggered. This event is then handled by a service called a Subscription.   For this tutorial, while updating weather information inside the service UpdateWeatherInfo,we need to fire an Event: BadWeather when the weather description indicates either storm/snow/rain. This Event is handled by a Subscription: HandleWeather, which is a service that gets called whenever the BadWeather Event is fired. The subscription service HandleWeather updates a property called AlertNotification.   Create Event   In this part of the lesson, we will create an Event: BadWeather that updates weather information inside the service UpdateWeatherInfo when the weather description indicates either storm/snow/rain.   Create a property AlertNotification with a baseType STRING using the Add Property feature of the plugin we discussed before. Right click inside your java file->ThingWorx Source->Add Event.   Set the name to BadWeather and set a name for the Data Shape to Weather. NOTE: This custom Data Shape has to be created in Composer. Importing Datashapes and other custom entities created in Composer into your extension will be discussed later in the tutorial. Our DataShape Weather includes one field called WeatherDescription with a STRING base type.  Click Finish. NOTE: This will create annotation for your EventDefinition.    Create Subscription   In this part of the lesson, we will create a Subscription: HandleWeather, which is a service that gets called whenever the BadWeather Event is fired. The subscription service HandleWeather updates a property called AlertNotification. Right click inside your java file ->ThingWorx Source->Add Subscription   Set the Event Name to BadWeather and Handler Service to HandleWeather. NOTE: This means that whenever the BadWeather event is fired, the HandleWeather service will be executed. Source is left blank if the event belongs to the same template. Click Finish. This creates annotation for subscription service and also creates a new service called HandleWeather.   Modify Service   In this part of the lesson, you'll ensure that when the properties are updated, BadWeather event is triggered if the description indicates rain/snow/thunderstorm. To do this, we will modify the UpdateWeatherInfo service.   After we have called the setPropertyValue method for the properties WeatherDescription and Temperature, we can check if the weather description contains snow/rain/thunderstorm. We will create an InfoTable from the Weather Datashape. InfoTables represent data sets that take the structure of the Datashape. Each row of an InfoTable can be passed as a ValueCollection to hold data within the table. When an event is fired, we need to send data along with it. This data will be passed as an InfoTable and it is then handled by the Subscription handling the Event.We use a ValueCollection to add the weatherDescription to the InfoTable. Then, this InfoTable is set as the Event Data.   Add the code snippet to UpdateWeatherInfo section at the end of the service after setting the properties- Temperature and WeatherDescription. /* fire event BadWeather */ if (description.contains("snow") || description.contains("rain") || description.contains("thunderstorm")) { ValueCollection v = new ValueCollection(); v.put("weatherDescription", new StringPrimitive(description)); InfoTable data = InfoTableInstanceFactory.createInfoTableFromDataShape("Weather"); data.addRow(v); _logger.info("Firing event"); ThingworxEvent event = new ThingworxEvent(); event.setEventName("BadWeather"); event.setEventData(data); this.dispatchEvent(event); } Inside the HandleWeather service, set the property AlertNotification. Ensure that you have created the property AlertNotification using the eclipse plugin. Add the following code snippet to the HandleWeather service. @ThingworxServiceDefinition(name = "HandleWeather", description = "Subscription handler", category = "", isAllowOverride = false, aspects = {"isAsync:false"}) public void HandleWeather( @ThingworxServiceParameter(name = "eventData", description = "", baseType = "INFOTABLE") InfoTable eventData, @ThingworxServiceParameter(name = "eventName", description = "", baseType = "STRING") String eventName, @ThingworxServiceParameter(name = "eventTime", description = "", baseType = "DATETIME") DateTime eventTime, @ThingworxServiceParameter(name = "source", description = "", baseType = "STRING") String source, @ThingworxServiceParameter(name = "sourceProperty", description = "", baseType = "STRING") String sourceProperty) throws Exception { _logger.trace("Entering Service: HandleWeather with: Source: \"\", Event: \"BadWeather\", Property: \"\""); this.setPropertyValue("AlertNotification", new StringPrimitive("Alert:"+eventData.getFirstRow().getStringValue("weatherDescription"))); _logger.trace("Exiting Service: HandleWeather"); } Now we have an event BadWeather fired every time weather description indicates storm/snow/rain and it is handled by HandleWeather service that sets the AlertNotification property to the InfoTable data passed by the event.     Step 10: Add Composer Entities In previous parts of this tutorial, we assumed we had a datashape Weather available with field weatherDescription as the Datashape of our event: BadWeather. In this part of the lesson, we'll create a DataShape. Go to ThingWorx Composer. Click the + button. In the dropdown, select Data Shape. Enter a name, for example: Weather. Add a Field Definition weatherDescription with baseType STRING. Click check mark in the top left, then Save.   Click the More drop-down, then click Export. Export the DataShape entity from Composer, it will download in your system as an xml file. Go back to Eclipse, right-click on your project ->Import..->ThingWorx->Entities. Click Next. Browse to the directory where the xml file was downloaded. Select the xml file and Click Finish.   NOTE: This adds the xml file to the Entities folder in your project. Following the same procedure, import other entities required for this Extension stored in the Entities folder of the download we provided for this training.   NOTE: You can uncheck the box for importing DataShapes_Weather.xml, if you already loaded your Datashape in the previous steps.     Click here to view Part 5 of this guide.
View full tip
  Step 7: Add JAR Resources   You can add external JARs for use by your extension. Every third-party JAR that is not already included in either the ThingWorx Extension SDK or ThingWorx Core needs to be added to your extension project as a JAR Resource. These JAR resources are added to your metadata.xml as a tag and are used to reference the Java classes in the third-party JAR on which the extension depends. You can either use the Add button   or the ThingWorx Menu from the menu bar to add a new JAR resource. By doing so, the JAR is automatically updated in the metadata file and added to the build path. Although ThingWorx allows developers to include jar files for third-party libraries in their code, it is recommended that you avoid adding jar files for common libraries and instead use the jar files that are included with the SDK. Adding jar files to an extension could cause conflicts with jar files already used by the ThingWorx server, either when uploading an extension, or when an extension executes. Even if your extension works today, future updates to ThingWorx may require updates to your extensions. Similarly, packaging a verison of a commonly used library may mean that a customer will not be able to use your extension together with someone else’s extension.   Select the project to which you want to add the jar file to and select New Jar Resource.       Open the directory in which you have stored the training files for this tutorial. Browse to the Jars directory. Select the json-simple-1.1.1.jar file. Add a description and click Finish. NOTE: This will automatically add json-simple-1.1.1.jar to the lib folder and to your project’s build path. Add httpclient-4.5.6.jar, httpcore-4.4.10.jar and commons-logging-1.2.jar directly into the twx-lib folder in the Project folder. NOTE: These JARs are included in the group of JARs used by ThingWorx by default. In order to build your extension locally, without bundling the jars into your extension that are available on the ThingWorx server, add the above JARs to your project's build path by right-clicking on your project in the Package Explorer, right-click Your_Extension_Project (ie, MyThingWorxWeatherExtension) and select Build Path -> Configure Build Path. Verify the jars we added are in the build path. Otherwise, click Add JARs, then browse to the directory containing these JARs (lib) and add them. NOTE: twx-lib folder is a hidden folder and does not appear in the Eclipse package explorer. The twx-lib folder can be found in the WeatherExtension project inside the Eclipse workspace directory.   Step 8: Create Services   Now that you have created properties, configuration tables and added the required jars, you can begin to add services to your WeatherThingTemplate.   In this part of the lesson, we’ll add a service, UpdateWeatherInfo that will take a City parameter and update the properties of this template using the values obtained from the openWeatherMap API.   Right click inside the WeatherThingTemplate and select ThingWorx Source->Add Service. Create a new service with name UpdateWeatherInfo. Click Add in the Input Parameters frame to add City parameter with a base type STRING.   Set the name and base type of the Output Parameter based on the value that you want the service to return. For simplification, assume this service returns nothing. Set the Base Type to NOTHING. Click Finish to create the service. Copy and Paste the code for UpdateWeatherInfo as specified below. @ThingworxServiceDefinition(name = "UpdateWeatherInfo", description = "updates weather description and temperature properties", category = "", isAllowOverride = false, aspects = { "isAsync:false" }) @ThingworxServiceResult(name = "Result", description = "", baseType = "NOTHING") public void UpdateWeatherInfo( @ThingworxServiceParameter(name = "City", description = "city name", baseType = "STRING") String City) throws Exception { _logger.trace("Entering Service: UpdateWeatherInfo"); String cityProp = this.getPropertyValue("CurrentCity").getStringValue(); if (City == null){ City = cityProp; } else { this.setPropertyValue("CurrentCity", new StringPrimitive(City)); } String url = "http://api.openweathermap.org/data/2.5/weather?q=" +URLEncoder.encode(City,"UTF-8") + "&appid="+ _appid+"&units=imperial"; // create a http client HttpClient client = new DefaultHttpClient(); // create a get request with the URL HttpGet getRequest = new HttpGet(url); // add Accept header to accept json format response getRequest.addHeader("Accept", "application/json"); // send the get request and obtain a response HttpResponse response = client.execute(getRequest); // if response is successful the status code will be 200. if (response.getStatusLine().getStatusCode() == 200) { BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuilder sb = new StringBuilder(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } JSONParser parser = new JSONParser(); JSONObject json = (JSONObject) parser.parse(sb.toString()); JSONArray weather = (JSONArray) json.get("weather"); Iterator<JSONObject> it = weather.iterator(); String description = (String) it.next().get("description"); this.setPropertyValue("WeatherDescription", new StringPrimitive(description)); double temp = (Double) ((JSONObject) json.get("main")).get("temp"); this.setPropertyValue("Temperature", new NumberPrimitive(temp)); /* fire event BadWeather */ _logger.trace("Exiting Service: UpdateWeatherInfo"); } }   Troubleshooting Issue Solution The iterator() is undefined in JSONArray Import only org.json.simple.*. Importing other JSON libraries can give this error. HttpClient/HttpGet could not be resolved to a type. Make sure you have imported the jars: httpclient-4.5.2.jar, httpcore-4.4.5.jar and commons-logging-1.2.jar, json-simple-1.1.1.jar as indicated in the previous chapter. Make sure you have imported the following packages in your template by Eclipse   Your code should be similar to the following:   package com.thingworx.weather; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URLEncoder; import java.util.Iterator; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.slf4j.Logger; import com.thingworx.logging.LogUtilities; import com.thingworx.metadata.annotations.ThingworxBaseTemplateDefinition; import com.thingworx.metadata.annotations.ThingworxConfigurationTableDefinition; import com.thingworx.metadata.annotations.ThingworxConfigurationTableDefinitions; import com.thingworx.metadata.annotations.ThingworxDataShapeDefinition; import com.thingworx.metadata.annotations.ThingworxFieldDefinition; import com.thingworx.metadata.annotations.ThingworxPropertyDefinition; import com.thingworx.metadata.annotations.ThingworxPropertyDefinitions; import com.thingworx.metadata.annotations.ThingworxServiceDefinition; import com.thingworx.metadata.annotations.ThingworxServiceParameter; import com.thingworx.metadata.annotations.ThingworxServiceResult; import com.thingworx.things.Thing; import com.thingworx.types.primitives.NumberPrimitive; import com.thingworx.types.primitives.StringPrimitive; @ThingworxBaseTemplateDefinition(name = "GenericThing") @ThingworxPropertyDefinitions(properties = { @ThingworxPropertyDefinition(name = "CurrentCity", description = "", category = "", baseType = "STRING", isLocalOnly = false, aspects = { "defaultValue:Boston", "isPersistent:true", "isLogged:true", "dataChangeType:VALUE" }), @ThingworxPropertyDefinition(name = "Temperature", description = "", category = "", baseType = "NUMBER", isLocalOnly = false, aspects = { "defaultValue:0", "isPersistent:true", "isLogged:true", "dataChangeType:VALUE" }), @ThingworxPropertyDefinition(name = "WeatherDescription", description = "", category = "", baseType = "STRING", isLocalOnly = false, aspects = { "dataChangeType:VALUE" }) }) @ThingworxConfigurationTableDefinitions(tables = { @ThingworxConfigurationTableDefinition(name = "OpenWeatherMapConfigurationTable", description = "", isMultiRow = false, ordinal = 0, dataShape = @ThingworxDataShapeDefinition(fields = { @ThingworxFieldDefinition(name = "appid", description = "", baseType = "STRING", ordinal = 0, aspects = { "isRequired:true" }) })) }) public class WeatherThingTemplate extends Thing { private static final long serialVersionUID = -5294151832877452442L; public WeatherThingTemplate() {} private static Logger _logger = LogUtilities.getInstance().getApplicationLogger(WeatherThingTemplate.class); private String _appid; @Override public void initializeThing() throws Exception {     super.initializeThing();     _appid = (String) this.getConfigurationSetting("OpenWeatherMapConfigurationTable", "appid"); } @ThingworxServiceDefinition(name = "UpdateWeatherInfo", description = "updates weather description and temperature properties", category = "", isAllowOverride = false, aspects = {     "isAsync:false" }) @ThingworxServiceResult(name = "Result", description = "", baseType = "NOTHING") public void UpdateWeatherInfo(     @ThingworxServiceParameter(name = "City", description = "city name", baseType = "STRING") String City) throws Exception {     _logger.trace("Entering Service: UpdateWeatherInfo");     String cityProp = this.getPropertyValue("CurrentCity").getStringValue();     if (City == null){         City = cityProp;     } else {         this.setPropertyValue("CurrentCity", new StringPrimitive(City));     }     String url = "http://api.openweathermap.org/data/2.5/weather?q=" +URLEncoder.encode(City,"UTF-8") + "&appid="+ _appid+"&units=imperial";     // create a http client     HttpClient client = HttpClientBuilder.create().build();     // create a get request with the URL     HttpGet request = new HttpGet(url);     // add Accept header to accept json format response     request.addHeader("Accept", "application/json");     // send the get request and obtain a response     HttpResponse response = client.execute(request);     // if response is successful the status code will be 200.     if (response.getStatusLine().getStatusCode() == 200) {         BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));         StringBuilder sb = new StringBuilder();         String line = "";         while ((line = br.readLine()) != null) {             sb.append(line);         }         JSONParser parser = new JSONParser();         JSONObject json = (JSONObject) parser.parse(sb.toString());         JSONArray weather = (JSONArray) json.get("weather");         Iterator<JSONObject> it = weather.iterator();         String description = (String) it.next().get("description");         this.setPropertyValue("WeatherDescription", new StringPrimitive(description));         Double temp = (Double) ((JSONObject) json.get("main")).get("temp");         Number number = (Number) temp;         this.setPropertyValue("Temperature", new NumberPrimitive(number));         _logger.trace("Exiting Service: UpdateWeatherInfo");     } } }     Click here to view Part 4 of this guide.
View full tip
    Build extensions quickly and extend your application functionality with the Eclipse Plugin.   GUIDE CONCEPT   Extensions enable you to quickly and easily add new functionality to an IoT solution. Extensions can be service (function/method) libraries, connector templates, functional widgets, and more.   The Eclipse Plugin for ThingWorx Extension Development (Eclipse Plugin) is designed to streamline and enhance the creation of extensions for the ThingWorx Platform. The plugin makes it easier to develop and build extensions by automatically generating source files, annotations, and methods as well as updating the metadata file to ensure the extension can be imported.   These features allow you to focus on developing functionality in your extension, rather than worrying about getting the syntax and format of annotations and the metadata file correct.   YOU'LL LEARN 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   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete all parts of this guide is 60 minutes.   Step 1: Completed Example    Download the attached file needed for this tutorial: ExtensionSampleFiles.zip.   The ExtensionSampleFiles.zip file provided to you contains a completed example of the scenario you will be walk through in the following steps. Utilize this file if you would like to see a finished example as a reference or if you become stuck during this guide and need some extra help.     Step 2: Download Plugin and SDK    The ThingWorx Extension SDK provides supported classes and APIs to build Java-based extensions. The APIs included in this SDK allow manipulation of ThingWorx platform objects to create Java based extensions that can extend the capability of the existing ThingWorx platform.   The Eclipse Plugin assists in working with the Extension SDK to create projects, entities, and samples. Download the Eclipse Plugin. Download the Extension SDK.. Make a note of the directory where the plugin and the extension SDK are stored. The path of the directory will be required in upcoming steps. Do not extract the zip files.     Step 3: Install and Configure   Before you install the plugin, ensure that software requirements are met for proper installation of the plugin. Open Eclipse and choose a suitable directory as a workspace. Go to the menu bar of the Eclipse window and select Help->Install New Software… After the Install window opens, click Add to add the Eclipse Plugin repository. Click Archive… and browse to the directory where the Eclipse Plugin zip file is stored and click Open. Enter a name (for example, Eclipse Plugin).     Click OK. NOTE: Do not extract this zip file. Ensure that the Group items by category checkbox is not selected. Select ThingWorx Extension Builder in the items list of the Install window. Click Next and the items to be installed are listed Click Next and review the license agreement. Accept the license agreement and click Finish to complete the installation process.   NOTE: If a warning for unsigned content is displayed, click OK to complete the installation process. Restart Eclipse. When Eclipse starts again, ensure that you are in the ThingWorx Extension perspective. If not, select Window->Perspective->Open Perspective->Other->ThingWorx Extension, then click OK.      NOTE: Opening any item from File->New->Other…->ThingWorx will also change the perspective to ThingWorx Extension.     You are ready to start a ThingWorx Extension Project!     Click here to view Part 2 of this guide.  
View full tip
In this post we will take a look at using an existing JavaScript Library. The library will we will use is agGrid  which provides a very extensive Grid UI component. The objectives are To see how to add the library Use an external source to populate the grid Provide a click action when a user selects a row (Part 2) (see attachments - import AAGridExtensionExample as an extension and import as File PTC-ExternalSources-Entities ) Previous Posts for reference Widget Extensions Introduction Widget Extensions Click Event Widget Extensions Date Picker Widget Extensions Google Bounce We will not worry about CSS - I'm working on a post for that using Thingworx 8.2 CustomClass (CSS) feature. Also I will assume you have worked through the Widget Extensions Introduction The image below image below shows the resulting UI after grid population and a user clicked a row The following provides the high level areas of interest Steps 1. Create a Working Folder for example  AGGrid as in previous posts setup your ui folder and metadata file 2. Think of a name for the Extension - we will use aggrid and add a folder with this name under ui folder 3. create the required files as per previous posts - Note the jslibrary folder is where aagrid resides     Below shows the jslibrary folder the main file we care about is the ag-grid (we could use the min file but initially have the full makes debugging easier) 4. Setup the metadata file 5. Understand some of the agGrid requirements To create a grid we need to use the function agGrid which comes from the ag-grid.js       myGrid = new agGrid.Grid(gridContainer, gridOptions ); The gridContainer is where the grid will be placed in the DOM and the gridOptions is a definition object that holds all the settings for the grid before it is created. Using a init function inside the runtime.js (see previous posts for runtime)  we can get the gridContainer  by using a snippet like this document.getElementById(gridElementId); The gridOptions takes the form of a json object - note there are many options please refer to the agGrid documentation for more info. Our focus will be  columnDefs , rowData to start with. These 2 define the layout and the contents of the grid The columnsDefs takes the form of an Array of JSON basically headerName: and field The image below shows a hard-coded approach I took initially To make this more generic I created a Thingworx datashape and used a service script GetColumndefs to populate and output the columnDefs service script example uses a PTC-ExternalSourcesHelper thing below is the GetColumnsDefs service The next point of focus will be the gridOptions and the rowData (JSON  array of data ) based on the same definition as the columnDefs Both the columnDefs and the GridDataAsJSON (which turns into rowData)  shown below are setup in the ide.js file (see previous posts for ide) Returning back to the services we need to get some Grid data from an external source. For that we will create a GetRSSFeed and use that inside GetRSSAsJSON The GetRSSFeed  looks like this and uses the url input More Top Stories - Google News The GetRSSAsJSON looks like this looking back at the code maybe I should changed to result.rows when returning the GridData  but for now it works. The last thing is getting the data from the services and we use the updateProperty ( previous posts for ide ). Here we check for the property and set and pass the RawData to the drawaggrid function The drawaggrid takes in the rowData and uses the columnDefs to understand the format. Also the last thing the drawaggrid  function is create the actual grid. (Finally!) 5. lat but not least - Wire it all up in a Mashup! The first set is to zip up the Extension and Import  (see previous posts) The next is to create a Mashup and add the PTC-ExternalSourcesHelper entity and wire up the GetColumsDefs and the GetRSSAsJSON to the agGrid widget and then preview and hopefully it all works - I will upload the Extension and Entities shortly See you in Part 2 not yet created! (see attachments - import AAGridExtensionExample as an extension and import as File PTC-ExternalSources-Entities )
View full tip
There are now three new places where you can get and/or share ThingWorx code examples in the ThingWorx Community: ThingWorx Platform Services ThingWorx Extensions and Widgets ThingWorx Edge and Edge SDKs We encourage you to share your own relevant code examples in the appropriate space. Be sure to read the how-to and guidelines for posting to the Code Examples Libraries before you create your document. Any official code from ThingWorx Support Services will be marked with an official designation at the top of the document, which looks like this: Keep an eye out for more code examples as we ramp up these libraries and don’t forget to share your own examples!
View full tip
Attached (as PDF) are some steps to quickly get started with the Thingworx MQTT Extension so that you can subscribe / publish topics.
View full tip
Key Functional Highlights Add connectivity to National Instruments TestStand Make it easier to edit the apps Easier to find mashups and things in Composer Support for Asset sub-types Open up the tag picker to allow adding any connection types through Composer General App Improvements Enhance tag picker to improve speed of configuration Make it easier to add additional properties to assets Make app configuration more intuitive by centralizing the configuration Controls Advisor Merge the Server and Connection status fields Asset Advisor Performance improvement when displaying pages Add support for CFS/ServiceMax integration Added trial support for Service     Compatibility ThingWorx 8.2.x KEPServerEX 6.2 and later KEPServerEX V6.1 and older as well as different OPC Servers (with Kepware OPC aggregator) National Instruments TestStand 2016 SP1 and later Support upgrade from 8.0.1 and later     Documentation What’s New in ThingWorx Manufacturing Apps ThingWorx Manufacturing Apps Setup and Configuration Guide What’s New in ThingWorx Service Apps ThingWorx Service Apps Setup and Configuration Guide ThingWorx Manufacturing and Service Apps Customization Guide     Download ThingWorx Manufacturing Apps Freemium portal ThingWorx Manufacturing and Service Apps Extensions
View full tip
Video Author:                     Asia Garrouj Original Post Date:            March 31, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: This video is the second part of a two part video series walking thru the configuration of Analysis Event which is applied for Real-Time Scoring.  This second video will walk you thru the configuration of Analysis Event for Real Time Scoring and validating that a predictions job has been executed based on new input data.    
View full tip
Video Author:                     Christophe Morfin Original Post Date:            October 6, 2017 Applicable Releases:        ThingWorx Analytics 8.1   Description: This video covers the new features of ThingWorx Analytics Builder 8.1      
View full tip
Video Author:                     Christophe Morfin Original Post Date:            June 2, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: In this video we show a simple mashup and services in order to display the ThingPredictor's real time scoring results.  
View full tip
Video Author:                     Christophe Morfin Original Post Date:            March 31, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: This video walks you through the use of Analysis Replay to execute analysis events on historical data.    
View full tip
Video Author:                     Asia Garrouj Original Post Date:            March 31, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: This video is the first of a two part video series walking thru the configuration of Analysis Event which is applied for Real-Time Scoring.  This 1st video demonstrates how to create a Template and Thing which allows for the prediction model to score in real-time.   Note: This video is intended for demo purposes.  Customers who already have ThingWorx should already have their properties set-up.  In this case, you will need to configure the Analysis Event, which is demonstrated in the second part of this video series.    
View full tip
Video Author:                     Asia Garrouj Original Post Date:            March 31, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: This video will walk you through the first steps on how to set-up Analytics Manager for Real-Time Scoring and demonstrate how to share your predictive model from Analytics Builder into Analytics Manager, as well as to test the shared model.    
View full tip
Video Author:                     Asia Garrouj Original Post Date:            March 31, 2017 Applicable Releases:        ThingWorx Analytics 7.4 to 8.1   Description: This video will walk you through the first steps on how to set-up Analytics Manager for Real-Time Scoring and demonstrate how to create an Analysis Provider and start the ThingPredictor Agent.     Please Note: In this video, the startup command for the Agent has changed in Release 8.1.  Please refer to the PTC Help center  
View full tip
Video Author:                     Asia Garrouj Original Post Date:            December 9, 2016 Applicable Releases:        ThingWorx Analytics 52.0 to 8.1   Description: This video walks you through how to upload data and shows the configuration settings.   Please Note: In this video, the shown configuration settings page is different for ThingWorx Analytics 8.1.  
View full tip
Video Author:                     Asia Garrouj Original Post Date:            November 29, 2016 Applicable Releases:        ThingWorx Analytics 52.0 to 8.1   Description: Signals indicate the predictive strength or weakness of specific features on the goal variable. Use Signals to explore which features are important to predicting outcomes, and which are not.   Please Note:  In this video, it states that a model needs to be created prior to running Signals.  As of ThingWorx Analytics 8.1, this is no longer the case.    
View full tip
Video Author:                    Christophe Morfin Original Post Date:            September 13, 2016 Applicable Releases:        ThingWorx Analytics 52.1 to 8.1 Description: In this video we cover the different configuration steps required for ThingWorx Analytics Builder extension.   Please Note: This video uses Classic Composer.  The same operations can be done using the New Composer starting with version 8.0 as illustrated in the Help Center For release 8.1, the Settings menu differs from previous versions, see What's New in ThingWorx Analytics Builder 8.1 between times 00:12 sec to 00:40 sec for an up to date menu selection.  
View full tip
Video Author:                     Christophe Morfin Original Post Date:            September 13, 2016 Applicable Releases:        ThingWorx Analytics 52.1 to 8.1 ​ Description: A short introduction to ThingWorx Analytics Builder The import of the ThingWorx Analytics Builder Extension  
View full tip
Initial Objective statements This post is about getting D3 connected as an extension to Thingworx. There are a number of existing extensions using D3 but I wanted to explore a simple use case to make it easier to get into and bring out 2 additional points Using an infotable as data input Resize The output looks like the image below and the data was generated by a Timer based random value generator that set the values on a Thing every minute. The data into the Widget is from a core service QueryHistory (a wrapped service that uses QueryProperyHistory) In this example I will use temp as the variable in focus If you have never created an extension take a look at Widget Extensions Introduction which provides a start to understanding the steps defined below, which are the core points to keep it relatively short. The extension will be called d3timeseries and will use the standard design pattern Create a folder called d3timeseries and create a subfolder ui and a add a metadata.xml file to the d3timeseries From there create the files and folder structure define the metadata.xml using CDN url for D3 url url="https://d3js.org/d3.v4.js" legend url = "https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.3/d3-legend.js" Also check out https://d3js.org/ which provides documentation and examples for D3 For the initial set of Properties that control the D3 will use DataAsINFOTABLE (Data coming into d3) Title XLegendTitle YLegendTitle TopMargin BottomMargin LeftMargin RightMargin Note: we are not using Width and Height as in previous articles but setting 'supportsAutoResize': true, Below shows the general structure will use for the d3timeseries.ide.js properties After deploying the extension  (take look at Widget Extensions Introduction to understand the how) we can see its now possible to provide Data input and some layout controls as parameters From there we can work in the d3timeseries.runtime.js file to define how to consume and pass data to D3. There a 4 basic function that need to be defined this.renderHtml this.afterRender this.updateProperty this.resize renderHtml afterRender updateProperty resize The actual D3 worker is drawChart which I will break down the highlights I use an init function to setup where the SVG element will be placed The init is called inside drawChart Next inside drawChart the rowData incoming parameter is checked for any content we can consume the expected rows object Next the x and y ranges need to be defined and notice that I have hardcoded for d.timestamp and d.temp these 2 are returned in the infotable rows The last variable inputs are the layout properties Now we have the general inputs defined the last piece is to use D3 to draw the visualization (and note we have chosen a simple visualization timeseries chart) Define a svg variable and use D3 to select the div element defined in the init function. Also remove any existing elements this helps in the resize call. Get the current width and height as before Now do some D3 magic (You will have to read in more detail the D3 documentation to get the complete understanding) Below sets up the x and y axis and labels Next define x and y scale so the visualization fits in the area available and actually add the axis's and ticks, plus the definition for the actual line const line = d3.line() Now we are ready for the row data which gets defined as data and passed to the xScale and yScale using in the const line = d3.line() After zipping up and deploying and using in a mashup you should get a D3 timeseries chart. Code for the QueryHistory logger.debug("Calling "+ me.name + ":QueryHistory"); // result: INFOTABLE var result = me.QueryPropertyHistory({ maxItems: undefined /* NUMBER */, startDate: undefined /* DATETIME */, endDate: undefined /* DATETIME */, oldestFirst: undefined /* BOOLEAN */, query: undefined /* QUERY */ }); Thing properties example Random generator code me.hum = Math.random() * 100; me.temp = Math.random() * 100; message = message + "Hum=" + me.hum+ " "; message = message + "Temp=" +me.temp+ " "; logger.debug(me.name + "  RandomGenerator values= " + message ); result = message; Previous Posts Title Widget Extensions Using AAGRID a JS library in Developer Community Widget Extensions Google Bounce in Developer Community Widget Extensions Date Picker in Developer Community Widget Extensions Click Event in Developer Community Widget Extensions Introduction in Developer Community
View full tip