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

Community Tip - Have a PTC product question you need answered fast? Chances are someone has asked it before. Learn about the community search. X

IoT Tips

Sort by:
Hello everyone,   Following a recent  experience, I felt it was important to share my insights with you. The core of this article is to demonstrate how you can format a Flux request in ThingWorx and post it to InfluxDB, with the aim of reporting the need for performance in calculations to InfluxDB. The following context is renewable energy. This article is not about Kepware neither about connecting to InfluxDB. As a prerequisite, you may like to read this article: Using Influx to store Value Stream properties from... - PTC Community     Introduction   The following InfluxDB usage has been developed for an electricity energy provider.   Technical Context Kepware is used as a source of data. A simulation for Wind assets based on excel file is configured, delivering data in realtime. SQL Database also gather the same data than the simulation in Kepware. It is used to load historical data into InfluxDB, addressing cases of temporary data loss. Once back online, SQL help to records the lost data in InfluxDB and computes the KPIs. InfluxDB is used to store data overtime as well as calculated KPIs. Invoicing third party system is simulated to get electricity price according time of the day.   Orchestration of InfluxDB operations with ThingWorx ThingWorx v9.4.4 Set the numeric property to log Maintain control over execution logic Format Flux request with dynamic inputs to send to Influx DB  InfluxDB Cloud v2 Store logged property Enable quick data read Execute calculation Note: Free InfluxDB version is slower in write and read, and only 30 days data retention max.     ThingWorx model and services   ThingWorx context Due to the fact relevant numeric properties are logged overtime, new KPIs are calculated based on the logged data. In the following example, each Wind asset triggered each minute a calculation to get the monetary gain based on current power produced and current electricity price. The request is formated in ThingWorx, pushed and executed in InfluxDB. Thus, ThingWorx server memory is not used for this calculation.   Services breakdown CalculateMonetaryKPIs Entry point service to calculate monetary KPIs. Use the two following services: Trigger the FormatFlux service then inject it in Post service. Inputs: No input Output: NOTHING FormatFlux _CalculateMonetaryKPI Format the request in Flux format for monetary KPI calculation. Respect the Flux synthax used by InfluxDB. Inputs: bucketName (STRING) thingName (STRING) Output: TEXT PostTextToInflux Generic service to post the request to InfluxDB, whatever the request is Inputs: FluxQuery (TEXT) influxToken (STRING) influxUrl (STRING) influxOrgName (STRING) influxBucket (STRING) thingName (STRING) Output: INFOTABLE   Highlights - CalculateMonetaryKPIs Find in attachments the full script in "CalculateMonetaryKPIs script.docx". Url, token, organization and bucket are configured in the Persitence Provider used by the ValueStream. We dynamically get it from the ValueStream attached to this thing. From here, we can reuse it to set the inputs of two other services using “MyConfig”.   Highlights - FormatFlux_CalculateMonetaryKPI Find in attachments the full script in "FormatFlux_CalculateMonetaryKPI script.docx". The major part of this script is a text, in Flux synthax, where we inject dynamic values. The service get the last values of ElectricityPrice, Power and Capacity to calculate ImmediateMonetaryGain, PotentialMaxMonetaryGain and PotentialMonetaryLoss.   Flux logic might not be easy for beginners, so let's break down the intermediate variables created on the fly in the Flux request. Let’s take the example of the existing data in the bucket (with only two minutes of values): _time _measurement _field _value 2024-07-03T14:00:00Z WindAsset1 ElectricityPrice 0.12 2024-07-03T14:00:00Z WindAsset1 Power 100 2024-07-03T14:00:00Z WindAsset1 Capacity 150 2024-07-03T15:00:00Z WindAsset1 ElectricityPrice 0.15 2024-07-03T15:00:00Z WindAsset1 Power 120 2024-07-03T15:00:00Z WindAsset1 Capacity 160   The request articulates with the following steps: Get source value Get last price, store it in priceData _time ElectricityPrice 2024-07-03T15:00:00Z 0,15 Get last power, store it in powerData _time Power 2024-07-03T15:00:00Z 120 Get last capacity, store it in capacityData _time Capacity 2024-07-03T15:00:00Z 160 Join the three tables *Data on the same time. Last values of price, power and capacity maybe not set at the same time, so final joinedData may be empty. _time ElectricityPrice Power Capacity 2024-07-03T14:00:00Z 0,15 120 160 Perform calculations gainData store the result: ElectricityPrice * Power _time _measurement _field _value 2024-07-03T15:00:00Z WindAsset1 ImmediateMonetaryGain 18 maxGainData store the result: ElectricityPrice * Capacity lossData store the result: ElectricityPrice * (Capacity – Power) Add the result to original bucket   Highlights - PostTextToInflux Find in attachments the full script in "PostTextToInflux script.docx". Pretty straightforward script, the idea is to have a generic script to post a request. The header is quite original with the vnd.flux content type Url needs to be formatted according InfluxDB API     Well done!   Thanks to these steps, calculated values are stored in InfluxDB. Other services can be created to retrieve relevant InfluxDB data and visualize it in a mashup.     Last comment It was the first time I was in touch with Flux script, so I wasn't comfortable, and I am still far to be proficient. After spending more than a week browsing through InfluxDB documentation and running multiple tests, I achieved limited success but nothing substantial for a final outcome. As a last resort, I turned to ChatGPT. Through a few interactions, I quickly obtained convincing results. Within a day, I had a satisfactory outcome, which I fine-tuned for relevant use.   Here is two examples of two consecutive ChatGPT prompts and answers. It might need to be fine-tuned after first answer.   Right after, I asked to convert it to a ThingWorx script format:   In this last picture, the script won’t work. The fluxQuery is not well formatted for TWX. Please, refer to the provided script "FormatFlux_CalculateMonetaryKPI script.docx" to see how to format the Flux query and insert variables inside. Despite mistakes, ChatGPT still mainly provides relevant code structure for beginners in Flux and is an undeniable boost for writing code.  
View full tip
    Step 4: Write Data to External Database You’ve connected to the database, you’re able to query the database. Now let’s handle inserting new data into the database. The update statements and data shown below are based on the table scripts provided in the download. Examples of how the ThingWorx entity should look can be seen in the SQLServerDatabaseController and OracleDatabaseController entities. Running an Insert Follow the steps below to set up a helper service to perform queries for the database. While other services might generate the query to be used, this helper service will be your shared execution service. In the DatabaseController entity, go to the Services tab.   Create a new service of type SQL (Command) called RunDatabaseCommand. Keep the Output as Integer. Add the following parameter:  Name           Base Type       Required command String True 5. Add the following code to your new service: <<command>> 6. Click Save and Continue. Your service signature should look like the below example. You now have a service that can run commands to the database. Run your service with a simple insert. There are two ways to go from here. You can either query the database using services that call this service, or you can create more SQL Command services that query the database directly. Let’s go over each method next, starting with a service to call the helper. In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service JavaScriptInsert_PersonsTable. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following code to your new service: try { var command = "INSERT INTO Persons (person_key, person_name_first, person_name_last, person_email, person_company_name, " + "person_company_position, person_addr1_line1, person_addr1_line2, person_addr1_line3, person_addr1_city, person_addr1_state, " + "person_addr1_postal_code, person_addr1_country_code, person_addr1_phone_number, person_addr1_fax_number, person_created_by, " + "person_updated_by, person_created_date, person_updated_date) VALUES ('" + key + "', '" + name_first + "', '" + name_last + "', '" + email + "', '" + company_name + "', '" + company_position + "', '" + addr1_line1 + "', '" + addr1_line2 + "', '" + addr1_line3 + "', '" + addr1_city + "', '" + addr1_state + "', '" + addr1_postal_code + "', '" + addr1_country_code + "', '" + addr1_phone_number + "', '" + addr1_fax_number + "', '" + created_by + "', '" + updated_by + "', '" + created_date + "', '" + updated_date + "')"; logger.debug("DatabaseController.JavaScriptInsert_PersonsTable(): Query - " + command); var result = me.RunDatabaseCommand({command: command}); } catch(error) { logger.error("DatabaseController.JavaScriptInsert_PersonsTable(): Error - " + error.message); } 5. Add the following parameter:  Name                                   Base Type           Required key String True name_first String True name_last String True company_name String True company_position String True addr1_line1 String True addr1_line2 String True addr1_line3 String True addr1_city String True addr1_state String True addr1_postal_code String True addr1_country_code String True addr1_phone_number String True addr1_fax_number String True created_by String True updated_by String True created_date String True updated_date String True 6. Click Save and Continue. Any parameter, especially those that were entered by users, that is being passed into a SQL Statement using the Database Connectors should be fully validated and sanitized before executing the statement! Failure to do so could result in the service becoming an SQL Injection vector. Now, let’s utilize a second method to create a query directly to the database. You can use open and close brackets for parameters for the insert. You can also use <> as a method to mark a value that will need to be replaced. As you build your insert statement, use [[Parameter Name]] for parameters/variables substitution and <<string replacement >> for string substitution. In the Services tab of the DatabaseController entity, create a new service of type SQL (Command).   Name the service SQLInsert_PersonsTable. Add the following code to your new service: INSERT INTO Persons (person_key ,person_name_first ,person_name_last ,person_email ,person_company_name ,person_company_position ,person_addr1_line1 ,person_addr1_line2 ,person_addr1_line3 ,person_addr1_city ,person_addr1_state ,person_addr1_postal_code ,person_addr1_country_code ,person_addr1_phone_number ,person_addr1_fax_number ,person_created_by ,person_updated_by ,person_created_date ,person_updated_date) VALUES ([[key]] ,[[name_first]] ,[[name_last]] ,[[email]] ,[[company_name]] ,[[company_position]] ,[[addr1_line1]] ,[[addr1_line2]] ,[[addr1_line3]] ,[[addr1_city]]]] ,[[addr1_state]] ,[[addr1_postal_code]] ,[[addr1_country_code]] ,[[addr1_phone_number]] ,[[addr1_fax_number]] ,[[created_by]] ,[[updated_by]] ,[[created_date]] ,[[updated_date]]); 4. Add the following parameter:  Name                                  Base Type       Required key String True name_first String True name_last String True company_name String True company_position String True addr1_line1 String True addr1_line2 String True addr1_line3 String True addr1_city String True addr1_state String True addr1_postal_code String True addr1_country_code String True addr1_phone_number String True addr1_fax_number String True created_by String True updated_by String True created_date String True updated_date String True 5. Click Save and Continue. Examples of insert services can be seen in the provided downloads.   Step 5: Executing Stored Procedures There will be times when a singular query will not be enough to get the job done. This is when you'll need to incorporate stored procedures into your database design. ThingWorx is able to use the same SQL Command when executing a stored procedure with no data return and a SQL query when executing a stored procedure with an expected result set. Before executing these services or stored procedures, ensure they exist in your database. They can be found in the example file provided. Execute Stored Procedure Now, let's create the service to handle calling/executing a stored procedure. If you are expecting data from this stored procedure, use EXEC to execute the stored procedure. If you only need to execute the stored procedure and do not expect a result set, then using the EXECUTE statement is good enough. You're also able to use the string substitution similar to what we've shown you in the earlier steps. In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Command) called RunAssignStudentStoredProcedure. Add the following parameter:  Name                      Base Type        Required student_key String True course_key String True 4. Add the following code to your new service: EXECUTE AddStudentsToCourse @person_key = N'<<person_key>>', @course_key = N'<<course_key>>';   You can also perform this execute in a service based on JavaScript using the following code: try { var command = "EXECUTE AddStudentsToCourse " + " @student_key = N'" + student_key + "', " + " @course_key = N'" + course_key + "'"; logger.debug("DatabaseController.RunAssignStudentStoredProcedure(): Command - " + command); var result = me.RunDatabaseCommand({command:command}); } catch(error) { logger.error("DatabaseController.RunAssignStudentStoredProcedure(): Error - " + error.message); } 5. Click Save and Continue. Execute Stored Procedure for Data Let's create the entity you will use for both methods. This can be seen in the example below:   In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Query) called GetStudentCoursesStoredProcedure. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following parameter:  Name                    Base Type        Required course_key String True 5. Add the following code to your new service: EXEC GetStudentsInCourse @course_key = N'<<course_key>>'   You can also perform this execute in a service based on JavaScript using the following code: try { var query = "EXEC GetStudentsInCourse " + " @course_key = N'" + course_key + "'"; logger.debug("DatabaseController.GetStudentCoursesStoredProcedure(): Query - " + query); var result = me.RunDatabaseQuery({query:query}); } catch(error) { logger.error("DatabaseController.GetStudentCoursesStoredProcedure(): Error - " + error.message); } 6. Click Save and Continue. You've now created your first set of services used to call stored procedures for data. Of course, these stored procedures will need to be in the database before they can successfully run. Step 6: Next Steps Congratulations! You've successfully completed the guide for External Database, and learned how to use the ThingWorx Platform to connect to database, query for data, and write new data. Learn More We recommend the following resources to continue your learning experience:  Capability       Guide Build Design Your Data Model Build Configure Permissions Additional Resources If you have questions, issues, or need additional information, refer to:  Resource           Link Community Developer Community Forum
View full tip
  Step 5: Bind Industrial Tag   Now that you've established a connection, you can use ThingWorx Foundation to inspect all available information on ThingWorx Kepware Server.   ThingWorx Kepware Server includes some information by default to assist you with verifying a valid connection with ThingWorx Foundation.   Create New Thing   In ThingWorx Foundation, click Browse > Modeling > Industrial Connections.   Click IndConn_Server. At the top, click Discover. The Discover option is exclusive to Things inheriting the IndustrialGateway Thing Template and displays information coming from ThingWorx Kepware Server.   Expand Channel1. Click Device1. On the right, you’ll see Tag1 and Tag2, which are pre-defined Tags to assist with connectivity testing.   Click the checkbox next to Tag1. Click Bind to New Entity.   In the Choose Template pop-up, select RemoteThing and click OK.   Finalize New RemoteThing   You’ll now be in an interface to create a new Thing with a predefined Property based on ThingWorx Kepware Server Tag1.   Type IndConn_Tag1 in the Name field. In the Description field, enter an appropriate description, such as Thing with a property fed from an Kepware Server Tag. The Base Thing Template has been automatically set to RemoteThing. The Implemented Shapes has been automatically set to IndustrialThingShape.   If Project is not already set, search for and select PTCDefaultProject.   Click Save.   Test Connection   The IndConn_Tag1 Thing you created now has a Property with a value that will change with each update from ThingWorx Kepware Server.   The Tag1 we utilized is a 'ramp' and therefore, the value will increase at regular intervals.   At the top, click Properties and Alerts. Under Inherited Properties, you will see entries for both RemoteThing and IndustrialThingShape. The Property isConnected is checked, indicating a connection from Foundation to ThingWorx Kepware Server. The Property IndustrialThing has been automatically set to IndConn_Server. Notice the predefined Property named Channel1_Device1_Tag1.   Click Refresh repeatedly. You’ll see the value increase with each Refresh. This represents data being simulated in ThingWorx Kepware Server.   Step 6: Log to Value Stream   Now that you have explored the Properties of IndConn_Tag1, you’ve seen how ThingWorx Kepware Server feeds information to ThingWorx Foundation.   To get an even better indication of changes and confirm continued connectivity, we will log the changes to a Value Stream in order to record the values with a TimeStamp.   Create Value Stream   In ThingWorx Foundation, click Browse > Data Storage > Value Streams.   Click + New.   In the Choose Template pop-up, select ValueStream. Click OK. Type IndConn_ValueStream in the Name field. In the Description field, enter an appropriate description, such as Value Stream to record changes from ThingWorx Kepware Server. If Project is not already set, search for and select PTCDefaultProject. Click Save.   Bind Value Stream   Return to the IndConn_Tag1 Thing. At the top, select General Information. In the Value Stream field, search for and select IndConn_ValueStream.   At the top, select Properties and Alerts.   Click Channel1_Device1_Tag1. A new set of options will expand from the right.   Check the box for Persistent. Check the box for Logged.   In the top-right, click the Check button to close the expanded options. Click Save.   All changes to the Tag1 Property fed from ThingWorx Kepware Server are now stored and TimeStamped to the IndConn_ValueStream.     Step 7: Visualize the Data   We'll now create a Mashup to visualize the record of information from ThingWorx Kepware Server.   In ThingWorx Foundation, click Browse > Visualization > Mashups.   Click +New.   In the New Mashup pop-up, leave the default selections and click OK.   In the Name field, type IndConn_Mashup. If Project is not already set, search for and select PTCDefaultProject.  At the top, click Save.   At the top, click Design.   At the top-left, ensure the Widgets tab is selected.   In the Filter Widgets field at the top-left, type line. Drag-and-drop a Line Chart onto the central canvas area.     Add Data   At the top-right, ensure the Data tab is active.   Click the + button.   In the Entity Filter field, search for and select IndConn_Tag1. In the Services Filter field, type queryprop. Click the right-arrow button beside QueryPropertyHistory. The QueryPropertyHistory Service of the IndConn_Tag1 Thing will appear on the right in the Selected Services field. Check the box under Execute on Load in the Selected Services field.   Click Done. Note that the QueryPropertyHistory Service now appears on the right side Data tab. On the top-right Data tab, expand Things_IndConn_Tag1 > QueryPropertyHistory > Returned Data.   Drag-and-drop All Data from the QueryPropertyHistory Service from the right onto the Line Chart in the center.   In the Select Binding Target pop-up, select Data.   Configure Chart Properties   Click the Line Chart to select it. In the bottom-left Properties, type xaxisfield in the filter. Expand the drop-down for XAxisField.   Select timestamp. At the top, click Save. Click View Mashup. (You may have to enable pop-ups in your browser.)   The IndConn_Mashup will show you the recorded history of Property changes that came from ThingWorx Kepware Server.   Because the Tag1 Example is a ramp, you’ll notice a slowly-increasing value in the Line Chart.   Reload the Mashup's browser-tab to see the value increase even further.   NOTE: If the Mashup visualization is blank, confirm your connection to ThingWorx Kepware Server. Return to the Test Connection section of the "Bind Industrial Tag" step.     Step 8: Next Steps   Congratulations! You've successfully completed the Connect Industrial Devices and Systems guide.   You've learned how to:   Connect ThingWorx Kepware Server to ThingWorx Foundation Secure the connection with an Application Key Create an IndustrialGateway Thing Map ThingWorx Kepware Server Tags to ThingWorx Foundation Thing Properties Visualize Data from connected digital assets   Learn More   Capability Resource Connect Connect to an Allen-Bradley PLC   Additional Resources   For additional information on ThingWorx Kepware Server:   Resource Link Documentation Kepware documentation Support Kepware Support site
View full tip
  Connect an ESP8266 WiFi module using the Arduino programming environment and the ThingWorx REST API.   This information was created for a previous version of ThingWorx and may not be fully accurate. Report any issues with this article here.   Guide Concept   This project will introduce the utilities ThingWorx provides for connections to an Adafruit Feather.   Following the steps in this guide, you will have a fully configured setup between your Adafruit Feather and the ThingWorx platform to begin your IoT development.   We will teach you how to utilize the ThingWorx REST API and the Arduino programming language to connect your Adafruit Feather for IoT application development.   You'll learn how to   Connect an ESP8266 WiFi module to a ThingWorx server Use the Arduino programming environment with the ThingWorx REST API   NOTE:  The estimated time to complete this guide is 30 minutes.      Step 1: Install Software   Arduino   There are three pieces of software to install before getting started with the ThingWorx-specfic code: Install FTDI USB driver. If you have connected development boards to your PC in the past you probably already have this installed. The latest Arduino IDE full install will also install the driver. NOTE: SparkFun has an excellent FTDI Driver Installation guide.   3. Arduino IDE - version 1.6.4 or later recommended. 4. Install ESP8266 addon into Arduino IDE. 5. The SparkFun Setting Up the Arduino IDE Tutorial is a great guide to getting started with their board. 6. Adafruit also has a great with their board Testing a Wifi Connection Tutorial.   When everything is set-up correctly and you are able to upload and see the Blink demo flashing the LED on the board you are ready to move to the next step.   ThingWorx Foundation Server   Start, and Launch your ThingWorx Foundation server. Log into Composer.  You will need a ThingWorx appKey to authorize the board.  Follow these instructions in Create an Application Key to create an appKey that you will copy into the source code in the next step.       Step 2: Set up Arduino IDE, Developer Board, and ThingWorx Server   Once you are able to run the blink test sketch, your IDE and board are set-up correctly. To learn how to run the blink test, read the SparkFun Board Instructions and the Adafruit board instructions.   Arduino IDE   Before you will be able to run the code below that connects a developement board to a ThingWorx Foundation server, you will need to modify the code with four pieces of information specific to your environment. You will need:   A WiFi access point SSID The correct password for the WiFi access point The IP address or URL of a ThingWorx Foundation Server A valid appKey created by your ThingWorx Foundation Server. To create an appKey, follow these instructions to Create An Application Key   Create a new sketch in the Arduino IDE then copy and paste the code below into the IDE.   Modify the WiFi Definitions and the ThingWorx server definitions shown in the code with your specficic information then save the sketch with a new name. The next step will describe what you should see when you upload and run the code on your developer board.   /** * * ESP8266_ThingWorx_REST_Demo.ino * * * (c) PTC, Inc. 2016-2020 * */ #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClientSecureBearSSL.h> ////////////////////// // WiFi Definitions // ////////////////////// const char WiFiSSID[] = "Liberty454"; // WiFi access point SSID const char WiFiPSK[] = "Flutie22"; // WiFi password - empty string for open access points ////////////////////////////////////////////// // ThingWorx server definitions // // modify for a specific platform instance // ////////////////////////////////////////////// const char TWPlatformBaseURL[] = "https://pp-2007011431nt.devportal.ptc.io"; const char appKey[] = "2d4e9440-3e51-452f-a057-b55d45289264"; //////////////////////////////////////////////////////// // Pin Definitions - board specific for Adafruit board// //////////////////////////////////////////////////////// const int RED_LED = 0; // Thing's onboard, red LED - const int BLUE_LED = 2; // Thing's onboard, blue LED const int ANALOG_PIN = A0; // The only analog pin on the Thing const int OFF = HIGH; const int ON = LOW; // this will set as the Accept header for all the HTTP requests to the ThingWorx server // valid values are: application/json, text/xml, text/csv, text/html (default) #define ACCEPT_TYPE "text/csv" ///////////////////// //Attempt to make a WiFi connection. Checks if connection has been made once per second until timeout is reached //returns TRUE if successful or FALSE if timed out ///////////////////// boolean connectToWiFi(int timeout){ Serial.println("Connecting to: " + String(WiFiSSID)); WiFi.begin(WiFiSSID, WiFiPSK); // loop while WiFi is not connected waiting one second between checks uint8_t tries = 0; // counter for how many times we have checked while ((WiFi.status() != WL_CONNECTED) && (tries < timeout) ){ // stop checking if connection has been made OR we have timed out tries++; Serial.printf(".");// print . for progress bar Serial.println(WiFi.status()); delay(2000); } Serial.println("*"); //visual indication that board is connected or timeout if (WiFi.status() == WL_CONNECTED){ //check that WiFi is connected, print status and device IP address before returning Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); return true; } else { //if WiFi is not connected we must have exceeded WiFi connection timeout return false; } } ////////////////////////// //create a name for the board that is probably unique by appending last two bytes of MAC address //return name as a String /////////////////////////////// String getUniqueDeviceName(){ String uniqueName; uint8_t mac[WL_MAC_ADDR_LENGTH]; WiFi.macAddress(mac); // WiFi does NOT need to be connected for this call String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) + String(mac[WL_MAC_ADDR_LENGTH - 1], HEX); macID.toUpperCase(); uniqueName = "ESP8266Board-" + macID; Serial.println("DeviceID>" + uniqueName); return uniqueName; } /////////////////////////////// // make HTTP GET to a specific Thing and Propertry on a ThingWorx server // thingName - Name of Thing on server to make GET from // property - Property of thingName to make GET from // returns HTTP response code from server and prints full response /////////////////////////////// int httpGetPropertry(String thingName, String property){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[httpsGetPropertry] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Things/"+ thingName +"/Properties/"+ property +"?appKey=" + String(appKey); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); Serial.println("GET URL>" + fullRequestURL +"<"); // start connection and send HTTP header httpCode = https.GET(); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[httpGetPropertry] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[httpGetPropertry] failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } /////////////////////////////// // makes HTTP POST to platform to CreateThing service using input string as the new Things's name. // Returns server response code /////////////////////////////// int createThing(String nameOfThing){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[createThing] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Resources/EntityServices/Services/CreateThing?appKey=" + String(appKey); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); https.addHeader("Content-Type","application/json",false,false); Serial.println("POST URL>" + fullRequestURL + "<"); // start connection and send HTTP header httpCode = https.POST("{\"name\": \""+ nameOfThing +"\",\"thingTemplateName\": \"GenericThing\"}"); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[createThing] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[createThing] POST... failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } /////////////////////////////// // make HTTP POST to ThingWorx server Thing service // nameOfThing - Name of Thing to POST to // endPoint - Services URL to invoke // postBody - Body of POST to send to ThingWorx platform // returns HTTP response code from server /////////////////////////////// int postToThing(String nameOfThing, String endPoint, String postBody){ std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure); client->setInsecure(); HTTPClient https; int httpCode = -1; String response = ""; Serial.print("[postToThing] begin..."); String fullRequestURL = String(TWPlatformBaseURL) + "/Thingworx/Things/"+ nameOfThing +"/Services/"+ endPoint +"?appKey=" + String(appKey); Serial.println("URL>" + fullRequestURL + "<"); https.begin(*client,fullRequestURL); https.addHeader("Accept",ACCEPT_TYPE,false,false); https.addHeader("Content-Type","application/json",false,false); Serial.println("[postToThing] POST body>" + postBody + "<"); // start connection and send HTTP header httpCode = https.POST(postBody); // httpCode will be negative on error if(httpCode > 0) { response = https.getString(); Serial.printf("[postToThing] response code:%d body>",httpCode); Serial.println(response + "<\n"); } else { Serial.printf("[postToThing] POST... failed, error: %s\n\n", https.errorToString(httpCode).c_str()); } https.end(); return httpCode; } void setup() { pinMode(RED_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); Serial.begin(115200); Serial.setDebugOutput(true); Serial.println(); Serial.println(); Serial.println(); Serial.printf("Starting...\n"); for(uint8_t t = 4; t > 0; t--) { Serial.printf(" WAIT %d...\n", t); Serial.flush(); delay(1000); } connectToWiFi(10); } void loop() { String thingName = getUniqueDeviceName(); //unique name for this Thing so many work on one ThingWorx server while (WiFi.status() == WL_CONNECTED) { //confirm WiFi is connected before looping as long as WiFi is connected int getResponseCode = httpGetPropertry(thingName, "SomeNumber"); if (getResponseCode == 404){ // a 404 means connected, but either no Thing or no property // first we will try to create a new Thing on the platform int postResp = createThing(thingName); // saving the response code for retry logic in the future // the newly crated Thing has to be enabled postResp = postToThing(thingName,"EnableThing",""); //POST to EnableThing endpoint with no body // after the new Thing is enabled it must be restarted postResp = postToThing(thingName,"RestartThing",""); //POST to RestartThing endpoint with no body // add a property to the Thing 3rd parameter is ugly because required quotes are escaped with backslashes postResp = postToThing(thingName,"AddPropertyDefinition", "{\"name\":\"SomeNumber\",\"type\":\"NUMBER\"}"); //POST body contains JSON object with property name and property type // after changes to a Thing's structure it must be restarted postResp = postToThing(thingName,"RestartThing",""); //POST to RestartThing endpoint with no body } delay(2000); }// end WiFi connected while loop Serial.printf("****Wifi connection dropped****\n"); WiFi.disconnect(true); delay(10000); connectToWiFi(10); }     Step 3: Run Arduino Demo   Click on the right arrow in the Arduino IDE toolbar to upload and start the sketch. Note:The compile and upload process will take almost a minute and will show [ 100% ] when it is completed successfully. 2. After the upload is complete, click on Tools > Serial Monitor and select 115200 baud from the drop down in the lower right.            Check Connection on ThingWorx Server   Open the Composer window of your ThingWorx Foundation server and click on the browse folder icon, then Things.   You will see a Thing named "ESP8266Board-XXXX" with XXXX replaced by the last 4 digits of your boards WiFi MAC address. Click on the Thing then click the Properties and Alerts tab in the left column. Click the pencil "Set value" icon in the value column and enter a number in the text box. Click the "Check" button to set the value.   Open the Arduino Serial monitor window, and you will see the value you just entered on the platform shown in the serial output.   Step 4: Next Steps   Congratulations! You've successfully completed the Connect an Arduino Developer Board Quickstart.   This guide has given you the basic tools to:   Set up Arduino IDE Run Arduino demo Check connection on ThingWorx Server   Learn More   We recommend the following resources to continue your learning experience:    Capability Guide Connect Use REST API to Access ThingWorx Build Data Model Introduction   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource Link Community Developer Community Forum Support REST API Help Center
View full tip
  Step 8: Call Custom Service   In order to execute a Service of a specific Thing with the REST API, you can use the POST verb.   Required Parameters:   AppKey created by your ThingWorx server Name of the Thing that implements a custom Service Name of the custom Service Names of inputs, if any, required by the Service Request   Construct the URL. To call a custom Service of an existing Thing, make an HTTP POST to this endpoint: <server_ip:port>/Thingworx/Things/<name of Thing>/Services/<name of Service> Substitute <name of Thing> with the actual name of a Thing that exists on the ThingWorx server, and <name of Service> with an existing Service. Send request parameters The names of the inputs along with their values are sent in the body of the POST as a JSON object. For example, the JSON object below will send a parameter named 'firstNumber' with a value of 35 and a parameter named secondNumber with a value of 711. { "firstNumber": "35", "secondNumber": "711" } NOTE: The full request must include a header with the appKey for your specific ThingWorx server.   Response   A successful call to a Service will return a JSON object in the body of the response containing both a DataShape object and an array named rows. Inside the array, an object named result will have the value returned by the custom Service. Here is an example response:   { "dataShape": { "fieldDefinitions": { "result": { "aspects": {}, "baseType": "NUMBER", "description": "", "name": "result", "ordinal": 0 } } }, "rows": [ { "result": 746.0 } ] } 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 Service endpoint has a JSON body so the header must be set to match the format of the request body.   Step 9: Import and Export Entities   Collections of Entities that perform a function can be grouped then shared by exporting from a server. These entity collections are called Extensions and can be uploaded using the REST API. You can create custom Extensions or download Extensions created by other developers. You can use the REST API to automate the process of uploading an Extension to a ThingWorx server.   Required Parameters   AppKey created by your Foundation server Path to properly formatted zip file containing extension Entities Request   Construct the URL. Upload an Extension by making an HTTP POST to the endpoint: <Server IP:port〉Thingworx/ExtensionPackageUploader Send request parameters. The zip file that contains the extension entities is uploaded as a multi-part POST. The name of the file parameter is upload. Use a library to properly format the multi-part POST request You must also send this header: X-XSRF-TOKEN:TWX-XSRF-TOKEN-VALUE 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...   Response   A successful call to upload an Extension will return a description of the Entities that were successfully uploaded in the body of the response.   HTTPie example: http -f POST iotboston.com:8887/Thingworx/ExtensionPackageUploader upload@/home/ec2-user/extension.zip X-XSRF-TOKEN:TWX-XSRF-TOKEN-VALUE appKey:d0a68eff-2cb4-4327-81ea-7e71e26bb645 cURL example: curl -v --header X-XSRF-TOKEN:TWX-XSRF-TOKEN-VALUE --header appKey:d0a68eff-2cb4-4327-81ea-7e71e26bb645 -F upload=@extension.zip iotboston.com:8887/Thingworx/ExtensionPackageUploader?purpose=import&validate=false     Download Things By Name   The REST API can be used to export a file representation of Things on a ThingWorx Foundation server. The downloaded file can be imported to another ThingWorx server making the Thing available for use.   Required Parameters   AppKey created by your Foundation server Name of the Thing Request   Construct the URL. Retrieve the components of a Thing by making an HTTP GET to the endpoint. Substitute <name of Thing> with the actual name of a Thing that exists on the ThingWorx server that wil be downloaded. <Server IP:port>/Thingworx/Exporter/Things/<name of Thing> Send request parameters. No parameters are sent. 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...   Response   It is possible for the content to be returned in two different formats by sending an Accept header with the request.   Desired Response Type  Accept Header Values JSON application/json XML text/xml HTML text/html (or omit Accept Header) CSV text/csv   A successful call to download a Thing will return a file in the body of the response suitable for importing into a ThingWorx Foundation server.   HTTPie example:   http -v GET iotboston.com:8081/Thingworx/Exporter/Things/PiThing appKey==d0a68eff-2cb4-4327-81ea-7e71e26bb645 Accept:text/xml     Download Things By Tag   The REST API can be used to export a file representation of Things on a ThingWorx Foundation server. This file can be imported to another ThingWorx server making the Thing available for use.   Required Parameters   AppKey created by your Foundation server Name of the Tag Request   Construct the URL. Retrieve the components of a Thing by making an HTTP GET to the endpoint <Server IP:port〉/Thingworx/Exporter/Things Send request parameters. The Tag name is sent as a request parameter named: searchTags 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...   Response   It is possible for the content to be returned in two different formats by sending an Accept header with the request.   Desired Response Type  Accept Header Values JSON application/json XML text/xml HTML text/html (or omit Accept Header) CSV text/csv   A successful call to download a Thing will return a file in the body of the response suitable for importing into a ThingWorx Foundation server   HTTPie example:   http -v GET iotboston.com:8081/Thingworx/Exporter/Things searchTags==Applications:Raspberry_light appKey==d0a68eff-2cb4-4327-81ea-7e71e26bb645 Accept:text/xml     Step 10: Authentication Tags   A Tag is composed of two parts: a Vocabulary, and a specific vocabulary term. A Tag is shown as Vocabulary:VocabularyTerm. Almost every ThingWorx entity can be tagged. Tags can be used to create a relationship between many different ThingWorx Entities.   Create New Tag   You can use the REST API to create a new dynamic Tag vocabulary.   Required Parameters   AppKey created by your Foundation server Name of Tag Vocabulary   Request   Construct the URL. Create a new Tag Vocabulary by making an HTTP PUT to this endpoint: 〈Server IP:port〉/Thingworx/ModelTags Send Request Parameters. The name of the new DataShape and the name of the base DataShape that the new DataShape extends are sent in the body of the POST as a JSON object. For example, the JSON object below will create a new DataShape named SomeTestDataShape using the system template GenericThing. { "name": "SecondTest", "isDynamic": "true" } Authenticate Request. All API requests to the ThingWorx server must be authenticated either with a username and password or with an appKey. For this example we will authenticate by passing the appKey as a URL query string parameter. The parameter appKey is recognized by the ThingWorx server as an authentication credential in requests, it can be passed either as a URL query string parameter .../CreateThing?appKey=64b87... , or as request header appKey: 64b87...   Response   A successful call to the ModelTag Service does not return any content in the body of the response, only an HTTP 200 is returned.   HTTPie example:   http -v -j PUT http://52.201.57.6/Thingworx/ModelTags name=SecondTest isDynamic=true appKey==64b879ae-2455-4d8d-b840-5f5541a799ae     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 PUT request to the ModelTags endpoint has a JSON body so the header must be set to match the format of the request body. 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. Below is an example cURL call that explicitly sets the Content-Type header to application/json.   curl -v -H "Content-Type: application/json" -X PUT -d '{"name": "SecondTest", "isDynamic":"true"}' http://52.201.57.6/Thingworx/ModelTags?appKey=d0a68eff-2cb4-4327-81ea-7e71e26bb645   Add Tag to Thing   You can use the REST API to add a Tag to a Thing. There must be a Thing and a Dynamic Tag Vocabulary already created on your Foundation Server before you can add a Tag.   Required Parameters   AppKey created by your Foundation server Name of the Thing to be tagged Name of Dynamic Tag Vocabulary Name of for Tag to be assigned to Thing Request   Construct the URL. Substitute 〈name of Thing〉 with the actual name of a Thing that exists on the ThingWorx server that will have the Tag added. Add a new Tag to an existing Thing by making an HTTP POST to this endpoint: 〈Server IP:port〉/Thingworx/Things/〈name of Thing〉/Services/AddTags Send request parameters. The name of the new field to be added and type of the field are sent in the body of the POST as a JSON object. For example, the JSON object below will create a new field named SomeNumber using the ThingWorx base type NUMBER. Some other commonly used types are STRING, INTEGER, and BOOLEAN. Include a header in the full request with the appKey for your specific ThingWorx server. { "tags" : "SecondlightTest:RaspberryTest", }   Response   A successful call to the AddTags Service does not return any content in the body of the response. Only an HTTP 200 is returned.   HTTPie example:   http -v -j http://52.201.57.6/Thingworx/Things/SomeTestThing/Services/AddTags appKey==64b879ae-2455-4d8d-b840-5f5541a799ae tags=SecondTest:RaspberryTest curl -v -H "Content-Type: application/json" -X POST -d '{"tags": "SecondlightTest:RaspberryTest"}' http://52.201.57.6/Thingworx/Things/PiThing/Services/AddTags?appKey=d0a68eff-2cb4-4327-81ea-7e71e26bb645 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 AddPropertyDefinition endpoint has a JSON body so the header must be set to match the format of the request body. 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. Below is an example cURL call that explicitly sets the Content-Type header to application/json.   curl -v -H "Content-Type: application/json" -X POST -d '{"tags": "SecondlightTest:RaspberryTest"}' http://52.201.57.6/Thingworx/Things/PiThing/Services/AddTags?appKey=d0a68eff-2cb4-4327-81ea-7e71e26bb645      Click here to view Part 4 of this guide.  
View full tip
Hi,   I have just been playing around with the Edge MicroServer on a couple of Raspberry Pi's.  I obviously want them connected to ThingWorx, however they stop when the SSH session closes which isn't ideal.  I thought about doing something really quick and dirty using 'nohup', but this could have lead to many running processes, and wouldn't still not have started automatically when the Pi booted.  So, I did it right instead using init.d daemon configurations.   There are two files; one for the EMS and one for the Lua Script Resource.  You need to put these in /etc/init.d, then make sure they are owned by root.   sudo chown root /etc/init.d/thingworx* sudo chgrp root /etc/init.d/thingworx*   You'll need to modify the paths in the first lines of these files to match where you have your microserver folder.  Then you need to update the init.d daemon configs and enable the services.   sudo update-rc.d thingworx-ems defaults sudo update-rc.d thingworx-ems enable sudo update-rc.d thingworx-lsr defaults sudo update-rc.d thingworx-lsr enable   You can then start (stop, etc.) like this:   sudo service thingworx-ems start sudo service thingworx-lsr start   They should both also start automatically after a reboot.   Regards,   Greg
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
I've had a lot of questions over the years working with Azure IoT, Kepware, and ThingWorx that I really struggled getting answers to. I was always grateful when someone took the time to help me understand, and now it is time to repay the favour.   People ask me many things about Azure (in a ThingWorx context), and one of the common ones has been about MQTT communications from Kepware to ThingWorx using IoT Hub. Recently the topic has come up again as more and more of the ThingWorx expert community start to work with Azure IoT. Today, I took the time to build, test, validate, and share an approach and utilities to do this in cases where the Azure Industrial IoT OPC UA integration is overkill or simply a step later in the project plan. Enjoy!   End to end Integration of Kepware to ThingWorx using MQTT over Azure IoT (YoutTube 45 minute deep-dive)   ThingWorx entities for import (ThingWorx 9.0)   This approach can be quite good for a simple demo if you have a Kepware Integrator or Kepware Enterprise license, but the use of IoT Gateway for many servers and tags can be quite costly.   Those looking to leverage Azure IoT Hub for MQTT integration to ThingWorx would likely also find this recorded session and shared utilities quite helpful.   Cheers, Greg
View full tip
This document provides API information for all 51.0 releases of ThingWorx Machine Learning.
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
  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
  Send voice and text messages with Twilio.   GUIDE CONCEPT   This project will demonstrate how you can create applications that provide information to users, even when they are away from their computer. Users who are on the go can benefit from your application by receiving text and voice messages.   Following the steps in this guide, you will learn how to configure and use the Twilio Widget and explore it’s ability to send messages.   We will teach you how data can be used to send pertinent information to any cell phone.   YOU'LL LEARN HOW TO   Download and import the Twilio Widget extension Create a Thing using the Twilio Thing Template Configure the Twilio Thing to use your Twilio account Send text messages using a Service   NOTE:  The estimated time to complete this guide is 30 minutes.     Step 1: Install Twilio Extension   Download the Twilio Extension from IQNOX.com. Note:  IQNOX is a PTC Partner and will be maintaining and supporting specific extensions going forward.  It will be necessary to create an account on the IQNOX website, but the ThingWorx extensions are free. In the lower-left side of Composer, click Import/Export, then Import.   In the Import From File pop-up, under Import Option select Extension from the drop-down, then click Browse. Navigate to the .zip file you downloaded.   Click Import in the Import From File pop-up, then click Close after file is successfully imported.     Step 2: Create Twilio Thing   In this step, you will create a Thing that represents a connection with the Twilio service.   Start on the Browse, folder icon tab on the far left of ThingWorx Composer.  Under the Modeling tab, hover over Things then click the + button. Type twilio-connector in the Name field.   NOTE: This name, with matching capitalization, is required for the example code which will be entered in a later step. If Project is not already set, click the + in the Project text box and select the PTCDefaultProject. In the Base Thing Template text box, click the + and select Twilio.     Click Save.     Step 3: Configure Twilio Thing   Now that we have created a Thing to represent the Twilio connection, we will configure it with your Twilio account credentials.   When the Twilio Extension is installed, it does not include the Twilio account credentials required to send messages.   You will need Twilio account credentials to complete this step. If you do not already have a Twilio account, you can click on this link to create a Twilio account.   Open the twilio-connection Thing if it is not already open. Click on the Configuration tab. Click the pencil icon next to the authToken field.   Copy your AUTH TOKEN from your Twilio account dashboard.   Paste your AUTH TOKEN into the New Password and Confirm Password fields under authToken.   Click the pencil icon next to the accountSID field. Copy your ACCOUNT SID from your Twilio account dashboard, and paste it into the New Password and Confirm Password fields under accountSID. Follow the steps in your Twilio account dashboard to get a trial phone number.   Copy your PHONE NUMBER from your Twilio account dashboard, and paste it into the callerID field.   Click Save.     Step 4: Test Twilio Thing   Now that we have created a Thing to represent the Twilio connection and configured it with Twilio account credentials, we will confirm that everything is working.   Click the Services tab at the top of the twilio-connector Thing.     Click the link to the SendSMSMessage Service in the Services Name column. Enter a phone number in the to field. Enter a test message in the text field.   Click the Execute button to send the SMS message. The service should execute without any errors within a couple of seconds and the phone number will receive your message. Click Close to end testing the service.     Step 5: Sample Alerting App   At this point, you have created and tested a Thing that can send text messages. This step will demonstrate sending a message when a Property Value is out of the desired range.   Import Simulated Freezer Thing   Download and unzip the attached sample Things_freezer.zip. In Composer, click the Import/Export icon at the lower-left of the page.   Click Import. Leave all default values and click Browse to select the Things_freezer.twx file that you just downloaded. Click Open, then Import. When you see the success message, click Close.   Explore Imported Entities   Navigate to the freezer Thing by using the search bar at the top of the screen. Click the Subscriptions tab.   Click reportFreezer under Name. Open the Subscription Info tab. Select the Enabled checkbox.   Click Done then Save to save any changes.   Verify Data Simulation   Open the freezer Thing and click Properties and Alerts tab. Click the Set value in the alertedPhone Property row, in the Value column.   Enter a phone number to receive the SMS alert, then click the Check icon above where you entered the phone number. Click the pencil icon in the temp Property row, in the Value column. Enter a value for the temp property that is greater than 30, and click the Check icon. In a couple seconds, the phone number you entered will receive an alert that includes the value you entered.      Step 6: Next Steps   Congratulations!   In this guide, you learned how to:   Create a Thing using the Twilio Thing Template Configure the Twilio Thing to use your Twilio account Send text messages using a Service   Additional Resources   If you have questions, issues, or need additional information, refer to:   Resource Link Community Developer Community Forum Support Twilio Extension Help Center
View full tip
  Connect Devices and Equipment Using Industry-Standard Protocol Drivers in ThingWorx   GUIDE CONCEPT   This guide has step-by-step instructions for connecting ThingWorx Kepware Server to ThingWorx Foundation.   This guide will demonstrate the ease of connecting edge industrial equipment to ThingWorx Foundation without installing any software on production equipment.   We will also show how connecting different systems and devices improves operations through the creation of business intelligence.     YOU'LL LEARN HOW TO   Connect ThingWorx Kepware Server to ThingWorx Foundation Secure the connection with an Application Key Create an IndustrialGateway Thing Map ThingWorx Kepware Server Tags to ThingWorx Foundation Thing Properties Visualize Data from connected digital assets   Note: The estimated time to complete this guide is 30 minutes     Step 1: Installation   Download the ThingWorx Kepware Server executable application from MyKepware. If you desire installation instructions, you may find them in the attached guide: install-thingworx-kepware-server.zip . Navigate to START -> PTC. Click ThingWorx Kepware Server 6 Configuration.                           For additional information on ThingWorx Kepware Server, click Help -> Server Help on the Menu Bar.         Step 2: Create Gateway   To make a connection between ThingWorx Kepware Server and Foundation Server, you must first create a Thing.   WARNING: To avoid a timeout error, create a Thing in ThingWorx Foundation BEFORE attempting to make the connection in ThingWorx Kepware Server.   In ThingWorx Foundation Composer, click Browse > Modeling -> Things.   Click + NEW. In the Name field, type IndConn_Server, including matching capitalization. In the Description field, enter an appropriate description, such as Industrial Gateway Thing to connect to ThingWorx Kepware Server. If the Project field is not already set, search for and select PTCDefaultProject. In the Base Thing Template field, search for and select IndustrialGateway.   Click Save.     Step 3: Create an AppKey   To secure the connection between ThingWorx Foundation and ThingWorx Kepware Server, you need to utilize an Application Key.   In ThingWorx Foundation, click Browse > Security -> Applications Keys.   Click + New. In the Name field, type IndConn_AppKey. If Project is not already set, search for and select PTCDefaultProject. Set User Name Reference to the Administrator User. Click Yes on the warning pop-up.   Assign an Expiration Date that is far enough in the future to not interfere with your trial.   Click Save.   Under Key ID, click the page icon to the right of the Application Key string to copy it.     Step 4: Connect to Foundation   Now that you’ve created an IndustrialGateway Thing and an Application Key, you can configure ThingWorx Kepware Server to connect to ThingWorx Foundation.   Return to the ThingWorx Kepware Server Windows application. Right-click Project. Select Properties….   In the Property Editor pop-up, click ThingWorx. In the Enable field, select Yes from the drop-down. In the Host field, enter the IP address or URL of your ThingWorx Foundation server. Enter the Port number. If you are using the "hosted" Developer Portal trial, enter 443.     In the Application Key field, copy and paste the Application Key you just created. In the Trust self-signed certificates field, select Yes from the drop-down. In the Trust all certificates field, select Yes from the drop-down. In the Disable encryption field, select No from the drop-down if you are using a secure port. Select Yes if you are using an http port. Type IndConn_Server in the Thing name field, including matching capitalization. If you are connecting with a remote instance of ThingWorx Foundation and you expect any breaks or latency in your connection, enable Store and Forward. Click Apply in the pop-up. Click Ok.   In the ThingWorx Kepware Server Event window at the bottom, you should see a message indicating Connected to ThingWorx.     NOTE: If you do not see the "Connected" message, repeat the steps above, ensuring that all information is correct. In particular, check the Host, Port, and Thing name fields for errors.     Click here to view Part 2 of this guide.
View full tip
  Step 6: Building the Data Model   You can build your data model using different methods. You can build your data model where the Data Shapes match with your tables, but what you'll realize over time is that you will often need custom Data Shapes. When you query for data, you will often need data from differing tables to be in one result set. Because of this, I suggest against making your data model based on the tables. You can start the basis for your model with the tables in mind, but know that this won't be the basis for long.   Create Data Shapes   Let's start by setting up two queries and the Data Shapes to match. The first query will be to find the list of classes a student is assigned to and query will be completed here. The second query will be to find all student in an active class and we'll ask you to create it based on how we did the first one.   1. In the ThingWorx Composer, click the + New button in the top left.    2. In the dropdown list, click Data Shapes.   3. Name the Data Shape DataShape.StudentCourses   4. Add the set of fields below. You may notice, we included information from the Person table that we might already have. This is perfectly fine based on how much data you expect to come back. This will allow you to reuse this database for other purposes later where the person information might change. This can be very beneficial when you're calling a service with this Data Shape (or InfoTable based on this Data Shape). Allowing you to keep the input simple.    Name Base Type  Additional Info   id  STRING Primary Key   person_key  STRING  N/A  person_name_first  STRING  N/A  person_name_last  STRING  N/A  course_key  STRING  N/A  course_name  STRING  N/A  course_professor  STRING  N/A   Let's add in our database query and use our new Data Shape.    1. Open the DatabaseController.Facilities entity and go to the Services tab. If you have not done so as yet, add the configuration information to allow your queries to connect to a database. 2. Create a new service of type SQL (Query) called GetStudentEnrollment. 3. Click Save and Continue to save your changes.   4. Add a parameter to the service title email. It will have a String base type and be required. 5. Add the following query to the canvas.         SELECT person_key, person_name_first, person_name_last, course_key, course_name, course_professor FROM Person person INNER JOIN PersonCourses pc ON person.person_key = pc.person_key INNER JOIN Courses courses ON courses.course_key = pc.course_key WHERE person.person_email = [[email]]​           6. For the output of the service, InfoTable should be there by default. If not, switch the output to be an InfoTable. For the Data Shape, set it to the Data Shape we just created, DataShape.StudentCourses.   You now have a database where you can run your queries and use the responses to bind to Widgets in Mashups.    We have our database connection and a data model setup to handle our current queries. This might be where you begin to question if you would like to add Data Tables. This is more of a design choice. You might want to keep datasets in a Data Table for quick access or separation. Nevertheless, if you already have you database, you won't need many (if any) Data Tables.     Step 7: Next Steps   Congratulations! You've successfully completed the guide for Connecting to an External Database, and learned how to use the ThingWorx Platform to connect to database, query for data, and write new data.   The next guide in the Utilizing ThingWorx to Secure Your Aerospace and Defense Systems learning path is Low Level Device Connection.   Learn More   We recommend the following resources to continue your learning experience:   Capability Guide Build Design Your Data Model Build Configure Permissions   Additional Resources   If you have questions, issues, or need additional information, refer to:   Resource Link Community Developer Community Forum
View full tip
  Step 4: Write Data to External Database   You’ve connected to the database, you’re able to query the database. Now let’s handle inserting new data into the database. The update statements and data shown below are based on the table scripts provided in the download. Examples of how the ThingWorx entity should look can be seen in the SQLServerDatabaseController and OracleDatabaseController entities that you've downloaded   Running an Insert   Follow the steps below to set up a helper service to perform queries for the database. While other services might generate the query to be used, this helper service will be your shared execution service. In the DatabaseController entity, go to the Services tab.     2. Create a new service of type SQL (Command) called RunDatabaseCommand. 3. Keep the Output as Integer. 4. Add the following parameter:   Name Base Type Required command String True         5. Add the following code to your new service:   <<command>>       6. Click Save and Continue. Your service signature should look like the below example.     You now have a service that can run commands to the database. Run your service with a simple insert.   There are two ways to go from here. You can either query the database using services that call this service, or you can create more SQL Command services that query the database directly. Let’s go over each method next, starting with a service to call the helper.   In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service JavaScriptInsert_PersonsTable. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following code to your new service: try { var command = "INSERT INTO Persons (person_key, person_name_first, person_name_last, person_email, person_company_name, " + "person_company_position, person_addr1_line1, person_addr1_line2, person_addr1_line3, person_addr1_city, person_addr1_state, " + "person_addr1_postal_code, person_addr1_country_code, person_addr1_phone_number, person_addr1_fax_number, person_created_by, " + "person_updated_by, person_created_date, person_updated_date) VALUES ('" + key + "', '" + name_first + "', '" + name_last + "', '" + email + "', '" + company_name + "', '" + company_position + "', '" + addr1_line1 + "', '" + addr1_line2 + "', '" + addr1_line3 + "', '" + addr1_city + "', '" + addr1_state + "', '" + addr1_postal_code + "', '" + addr1_country_code + "', '" + addr1_phone_number + "', '" + addr1_fax_number + "', '" + created_by + "', '" + updated_by + "', '" + created_date + "', '" + updated_date + "')"; logger.debug("DatabaseController.JavaScriptInsert_PersonsTable(): Query - " + command); var result = me.RunDatabaseCommand({command: command}); } catch(error) { logger.error("DatabaseController.JavaScriptInsert_PersonsTable(): Error - " + error.message); }         5. Add the following parameter:   Name Base Type Required key String True name_first String True name_last String True company_name String True company_position String True addr1_line1 String True addr1_line2 String True addr1_line3 String True addr1_city String True addr1_state String True addr1_postal_code String True addr1_country_code String True addr1_phone_number String True addr1_fax_number String True created_by String True updated_by String True created_date String True updated_date String True         6. Click Save and Continue.   Any parameter, especially those that were entered by users, that is being passed into a SQL Statement using the Database Connectors should be fully validated and sanitized before executing the statement! Failure to do so could result in the service becoming an SQL Injection vector.   Now, let’s utilize a second method to create a query directly to the database. You can use open and close brackets for parameters for the insert. You can also use <> as a method to mark a value that will need to be replaced. As you build your insert statement, use [[Parameter Name]] for parameters/variables substitution and <<string replacement >> for string substitution.   1. In the Services tab of the DatabaseController entity, create a new service of type SQL (Command).   2. Name the service SQLInsert_PersonsTable. 3. Add the following code to your new service: INSERT INTO Persons (person_key ,person_name_first ,person_name_last ,person_email ,person_company_name ,person_company_position ,person_addr1_line1 ,person_addr1_line2 ,person_addr1_line3 ,person_addr1_city ,person_addr1_state ,person_addr1_postal_code ,person_addr1_country_code ,person_addr1_phone_number ,person_addr1_fax_number ,person_created_by ,person_updated_by ,person_created_date ,person_updated_date) VALUES ([[key]] ,[[name_first]] ,[[name_last]] ,[[email]] ,[[company_name]] ,[[company_position]] ,[[addr1_line1]] ,[[addr1_line2]] ,[[addr1_line3]] ,[[addr1_city]]]] ,[[addr1_state]] ,[[addr1_postal_code]] ,[[addr1_country_code]] ,[[addr1_phone_number]] ,[[addr1_fax_number]] ,[[created_by]] ,[[updated_by]] ,[[created_date]] ,[[updated_date]]);       4. Add the following parameter:   Name Base Type Required key String True name_first String True name_last String True company_name String True company_position String True addr1_line1 String True addr1_line2 String True addr1_line3 String True addr1_city String True addr1_state String True addr1_postal_code String True addr1_country_code String True addr1_phone_number String True addr1_fax_number String True created_by String True updated_by String True created_date String True updated_date String True         5. Click Save and Continue.   Examples of insert services can be seen in the provided downloads.     Step 5: Executing Stored Procedures   There will be times when a singluar query will not be enough to get the job done. This is when you'll need to incorporate stored procedures into your database design.   ThingWorx is able to use the same SQL Command when executing a stored procedure with no data return and a SQL query when executing a stored procedure with an expected result set. Before executing these services or stored procedures, ensure they exist in your database. They can be found in the example file provided.   Execute Stored Procedure   Now, let's create the service to handle calling/executing a stored procedure.   If you are expecting data from this stored procedure, use EXEC to execute the stored procedure. If you only need to execute the stored procedure and do not expect a result set, then using the EXECUTE statement is good enough. You're also able to use the string substitution similar to what we've shown you in the earlier steps.   In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Command) called RunAssignStudentStoredProcedure. Add the following parameter:   Name Base Type Required student_key String True course_key String True         4. Add the following code to your new service:   EXECUTE AddStudentsToCourse @person_key = N'<<person_key>>', @course_key = N'<<course_key>>'; You can also perform this execute in a service based on JavaScript using the following code: try { var command = "EXECUTE AddStudentsToCourse " + " @student_key = N'" + student_key + "', " + " @course_key = N'" + course_key + "'"; logger.debug("DatabaseController.RunAssignStudentStoredProcedure(): Command - " + command); var result = me.RunDatabaseCommand({command:command}); } catch(error) { logger.error("DatabaseController.RunAssignStudentStoredProcedure(): Error - " + error.message); }         5. Click Save and Continue.   Execute Stored Procedure for Data   Let's create the entity you will use for both methods. This can be seen in the example below:     In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Query) called GetStudentCoursesStoredProcedure. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following parameter:   Name Base Type Required course_key String True         5. Add the following code to your new service:   EXEC GetStudentsInCourse @course_key = N'<<course_key>>'   You can also perform this execute in a service based on JavaScript using the following code:   try { var query = "EXEC GetStudentsInCourse " + " @course_key = N'" + course_key + "'"; logger.debug("DatabaseController.GetStudentCoursesStoredProcedure(): Query - " + query); var result = me.RunDatabaseQuery({query:query}); } catch(error) { logger.error("DatabaseController.GetStudentCoursesStoredProcedure(): Error - " + error.message); }       6. Click Save and Continue.   You've now created your first set of services used to call stored procedures for data. Of course, these stored procedures will need to be in the database before they can successfully run.     Click here to view Part 3 of this guide.
View full tip
  Step 7: Set-up and Run Demo   The ThingWorx Azure IoT Connector download includes a Java application that simulates a device connecting to your Azure IoT Hub. A ThingTemplate is also included and can be imported into ThingWorx.   Import Demo Templates   In ThingWorx Composer, click Import/Export menu, then click From File and browse to ../demo/edgedevice- demo/platform/entities/CPUDemo_AllEntities.xml   Click Import then click Close when the import successful message is displayed. Create a new Thing using the imported template azureDemo1, enter a name for your Thing and click Save. NOTE: You will enter this name in the demo config file in the next step. Configure Demo Application   In the ../demo/edge-device-demo/conf subdirectory, open the edge-device.conf file with a text editor. Edit the deviceId to be the name of the Thing you created in step 3. Edit the iotHubHostName to use the name of your hub plus the domain: azure-devices.net. For example, sample-iot-hub.azuredevices.net. Edit the registryPolicyKey property to use the Primary Key for the registryReadWrite policy in the Azure IoT Hub. Below is an example configuration: azure-edge-device { deviceId = "alstestedgething" iotHubHostname = "alsiot.azure-devices.net" registryPolicyName = "registryReadWrite" registryPolicyKey = "pzXAi2nonYWsr3R7KVX9WuzV/1234567NZVTuScl/Kg=" }   Run Demo Script   Open a shell or Command Prompt, set the EDGE_DEVICE_DEMO_OPTS environment variable to refer to the file you just edited: Linux - export EDGE_DEVICE_DEMO_OPTS="-Dconfig.file=../conf/edge-device.conf" Windows - set EDGE_DEVICE_DEMO_OPTS="-Dconfig.file=../conf/edge-device.conf" Launch the demo from the ../demo/edge-device-demo/bin subdirectory, using the edge-device-demo command. Return to the ThingWorx Composer and open the Properties page of the Azure Thing that you created previously. Click the refresh button to see the properties change every five seconds. Open the azure-iot-demo Mashup and view the Load Average and CPU gauges, and the increases in the values of the Cycle and Uptime fields. NOTE: If the edgedevice-demo is running on Windows, the Load Average does not register.   Step 8: Next Steps   Congratulations! You've successfully completed the Connect Azure IoT Hub to ThingWorx Quickstart. By following the steps in this lesson, you imported a device created in Azure into ThingWorx and saw how data from an Azure device could be used in a ThingWorx Mashup.   Learn More   We recommend the following resources to continue your learning experience:   If you're following the Azure MXChip Development Kit learning path, the next guide is Create a Thing Shape.    Capability     Guide Connect Choose a Connectivity Method Build Design Your Data Model Experience Create Your Application UI   Additional Resources   If you have questions, issues, or need additional information, refer to:  Resource       Link Community Developer Community Forum Support Getting Started with ThingWorx        
View full tip
  Use the ThingWorx Azure IoT Hub Connector with simulated appliances.   Guide Concept   This project will introduce how to integrate ThingWorx with Azure IoT Hub. The combination of these two platforms extends the ThingWorx utilities to Azure IoT Hub edge devices and allows integration with Azure Blob Storage accounts.   Following the steps in this guide, you will install the ThingWorx Azure IoT Hub Connector and run a simulated Azure device.   We will teach you how to build powerful and scalable IoT applications by integrating ThingWorx and Azure IoT Hub.   You'll learn how to   Install, configure, and run the ThingWorx Azure IoT Hub Connector Import devices that exist in Azure into ThingWorx Connect a simulated Azure device to ThingWorx Foundation server   NOTE: This guide's content aligns with ThingWorx 9.3. The estimated time to complete this guide is 60 minutes       Step 1: Overview Diagram   The ThingWorx Azure IoT Hub Connector maintains a network connection to both an Azure IoT and a ThingWorx Foundation instance:        The ThingWorx Azure IoT Hub Connector enables remote devices that connect to the Azure IoT Hub, to connect to the ThingWorx Foundation server. The Azure IoT Connector handles message routing for the devices that communicate through the Azure IoT system. It also handles message routing from the ThingWorx Foundation server to devices via the Azure IoT Hub.   The ThingWorx Azure IoT Connector is a separate, stand-alone application that must be run on a server that can connect to both the ThingWorx server and the Azure IoT service.     Step 2: Configure Azure IoT Hub   In order to use the ThingWorx Azure IoT Connector, you must first configure an IoT Hub and a storage account in Microsoft Azure. You can provision a free tier account for these resources. In this step, we will create the Azure resources and gather the configuration information that enable you to connect to ThingWorx with the required credentials.   Log into Azure Portal   If you do not already have an Azure account you can create a free account that will work with this guide.   Create Azure IoT Hub   Follow the Microsoft documentation to create an Azure IoT Hub, accepting any defaults.   TIP: The name your IoT Hub must be globally unique and include only lowercase letters and numbers.   1. Create message routes to direct DeviceLifecycleEvents and TwinChangeEvents events to the built-in events endpoint. For a tutorial, refer to Tutorial: Use the Azure CLI and Azure portal to configure IoT Hub message routing 2. Register at least one Azure IoT Device or Azure IoT Edge Device to your Azure IoT Hub. For a tutorial, refer to Register an IoT Edge device in IoT Hub     Create Storage Account   Follow the Microsoft documentation to create an Azure Storage account.   NOTE: Select Blob storage as the account type and the Hot Access Tier.       Step 3: Import Extensions   The ThingWorx Azure IoT Hub Connector distribution bundle comes packaged with all the software you will need to connect ThingWorx and Azure. Download the Azure IoT Hub Connector from PTC Support Extract the application bundle to a directory on the system where it will run. (where v.v.v represents the release number) On Linux, this guide uses the base directory, /opt. The subdirectories and files should reside in the directory, /opt/ThingWorx-Azure-IoTHub-Connector-4.2.0. On Windows, extract the bundle so that the subdirectories and files reside in C:\ThingWorx-Azure-IoT-Hub-Connector-4.2.0 In the lower-left side of Composer, click Import/Export, then Import.  In the Import From File pop-up, under Import Option select Extension from the drop-down, then click Browse. Navigate to the /extensions directory and click on ConnectionServicesExtension-2.2.4.zip file.   Click Import in the Import From File pop-up, then click Close after file is successfully imported. Repeat the above steps for the azure-iot-hub-adapter-extension-4.2.0.4.zip file. Follow the steps to Create an Application Key and note the value, it will be used in the the next step.     Step 4: Install Azure Connector   Configure Connection Server   The Connection Server component of ThingWorx Azure IoT Connector must be configured with information specific to both your Azure IoT Hub and your ThingWorx Foundation server.   Copy the file azure-iot-sample.conf in the connector > conf directory and save the file with the name azure-iot.conf Edit the configuration file to replace the ten placeholder values for the parameters listed below with values copied from your Azure control panel. consumerPolicyName - Whether you have a new or existing hub, you need to provide the name of the consumer policy and its related Primary or Secondary key. The policy to select is typically the built-in, pre-defined policy called service. Navigate to All Resources > your hub > Settings > Shared access policies > service. If you added a custom service policy to your hub with the permission service connect select that policy.   consumerPolicyKey - Once you find the policy name, stay in the Shared access policies screen, and click the name. Copy the content of the Primary key. This key supplies the credentials to access services that are specified in the related policy. registryPolicyName - Specify a policy name that is related to the registryPolicyKey. This policy is typically a built in, predefined policy called registryReadWrite, but it is possible to use a custom policy if you add it to your hub. The shared access policy requires the registry read and registry write permissions. registryPolicyKey - The key that supplies credentials to access services in the policy specified in registryPolicyName. hubName - A name that defines the Azure IoT Hub related to this ThingWorx Connector. This Azure IoT Hub manages your things and their related messages. Hubs can be scaled via hub units at different price tiers per unit. Hubs are related to a resource group, which is related to a subscription Id and a cloud Location. TIP: To find the name associated with your Azure IoT Hub that the ThingWorx Connector will use to communicate with it, navigate to All Resources > your hub > Settings > Properties > NAME eventHubName - The Event Hub-compatible name that is used by SDKs and integrations that expect to read from Event Hubs. An Event Hub is an internal component of an Azure IoT Hub that handles device-to-cloud events for related things. In many cases, the IoT Hub name and Event Hubcompatible name are the same, so this property defaults to the Azure IoT Hub name (hubName). Navigate to All Resources > your hub > Settings > Built-in endpoints > Events > Event Hub-compatible name to find this name.   eventHubNamespace - To find the endpoint that is used by SDKs and integrations that expect to read from Event Hubs, navigate to All resources > your hub > Settings > Built-in endpoints > Events > Event Hub-compatible endpoint, and copy the host name, without the rest of the address (".servicebus.windows.net"). The ThingWorx Azure IoT Connector uses this endpoint to read messages from your hub. consumerGroup - To find a consumer group name to enable the Connector to pull data from the Azure IoT Hub, navigate to All Resources > your hub > Messaging > Endpoints > Built-in endpoints > Events > Consumer groups. To use the $Default consumer group, set this property to null. hubHostname - To find the host name for your hub, navigate to All Resources > your hub > Overview > Hostname. The host name is defined by the hubName plus a domain name that is chosen by Azure, typically azuredevices.net.   blob-storage.account-name - The blob-storage section specifies the settings for an Azure blob storage account. The storage provides containers that are used for device export of an Azure IoT Hub to ThingWorx via the Connector and can also be created by the Connector if you create AzureStorageContainerFileRepository things in ThingWorx. If you do not have one, create a Storage Account in the Azure portal. To find the name of an existing account, navigate to Settings > Access Keys > Storage account name.   blob-storage.account-key - The key to associate with the name of the blob storage account. To find the key for an existing account, navigate to Settings > Access Keys > Primary or secondary key Enter your ThingWorx Foundation server host, port, and appKey  in the transport.websockets section. transport.websockets { app-key = "6d70dfca-fe88-4d8c-83aa-686449b52cb2" platforms = "ws://45.23.12.112:80/Thingworx/WS" }   NOTE: If you are using an SSL connection to your ThingWorx Foundation server use wss in place of ws in the platform parameter. If the URL for the ThingWorx Foundation server does not include a port, use 80 for http connections and 443 for https.       Step 5: Launch IoT Hub Connector   Open a shell or a command prompt window. On a Windows machine, open the command prompt as Administrator. The AZURE_IOT_OPTS environment variable must be set before starting the Azure IoT Hub Connector. Below are sample commands using the default installation directory. On Windows: set AZURE_IOT_OPTS=-Dconfig.file=C:\ThingWorx-Azure-IoT-Connector-<version>\azure-iot-<version>-application\conf\azure-iot.conf -Dlogback.configurationFile=C:\ThingWorx-Azure-IoT-Connector-<version>\azure-iot-<version>-application\conf\logback.xml On Linux: export AZURE_IOT_OPTS="-Dconfig.file=/var/opt/ThingWorx-Azure-IoT-Connector-<version>/azure-iot-<version>-application/conf/azure-iot.conf -Dlogback.configurationFile=/var/opt/ThingWorx-Azure-IoT-Connector-<version>/azure-iot-<version>-application/conf/logback.xml" NOTE: You must run the export command each time you open a shell or command prompt window. Change directories to the bin subdirectory of the Azure IoT Hub Connector installation. Start the Azure IoT Hub Connector with the appropriate command for your operating system. On Windows: azure-iot.bat On Linux: /azureiot NOTE: On Windows you may have to shorten the installation directory name or move the bin directory closer to the root directory of your system to prevent exceeding the Windows limit on the classpath length.   The Connection Server should start with no errors or stack traces displayed. If the program ends, check the following: Java version is 1.8.0, update 92 or greater and is Java(TM) not OpenJDK. Open azure-iot.conf and confirm ThingWorx Foundation is set to the correct URL and port. Confirm the platform scheme is ws if http is used to access ThingWorx. Confirm all Azure credentials are correct for your Azure account. In ThingWorx Foundation click the Monitoring tab then click Connection Servers. You should see a server named azure-iot-cxserver-{server-uuid}, where {server-uuid} is a unique identifier that is assigned automatically to the server.       Step 6: Import Device from Azure   With the ThingWorx Azure IoT Connector, you can import into ThingWorx any existing devices that are currently provisioned to the Azure IoT Hub.   Add Device Azure IoT Hub   If you have not provisioned any devices to your Azure IoT Hub you can learn more about Azure IoT Hub device identity before following the steps below to create a test device.   In your Azure Portal, click All Resources, then select the name of your IoT Hub. Under Explorers click IoT devices, then click + Add. Enter a name for your device, then click Save. When the device name appears in the list it is ready to use.   Import Device into ThingWorx   We will manually execute a service in ThingWorx that will import Azure IoT Hub devices into ThingWorx.   In ThingWorx Composer, navigate to the ConnectionServicesHub Thing. Click Services tab and scroll to the ImportAzureIotDevices service and click the execute Arrow. NOTE: The * in the pattern field will act as a wildcard and import all devices, you can enter a string to match that will only import a subset of all available devices. Click Execute to import the devices then click Done. Click Things in the left column to see the Things that were created.   Click here to view Part 2 of this guide.
View full tip
  Connect to an existing database and design a connected data model.   GUIDE CONCEPT   There are times you already have your database designed and only need to integrate the ThingWorx environment.   These concepts and steps will allow you to focus on development of your application while still allowing the ability to utilize the power of ThingWorx!   We will teach you how to create a data model around your database design and connect to that database.     YOU'LL LEARN HOW TO   How to connect an external database and created services to be used with it How to design and implement a new data model based on an external resource Using data models with database services   Note: The estimated time to complete this guide is 30 minutes.      Step 1: Examples and Strategy   If you’d like to skip ahead, download and unzip the completed example of the Aerospace and Defense learning path attached to this guide:  AerospaceEntitiesGuide1.zip.   By now, you likely know how to create a data model from scratch. You have likely already created services that work with Info Tables. What you might not have completed, is combining both a new data model, handling data in services, and connecting it all to an external database.   Our organization, PTC Defense Department, has existed for years and has an existing database setup. Developers in our organization refuse to remodel the database, so we must model the ThingWorx data model to our database schema. With ThingWorx, this is not a difficult task, but there are numerous decisions and options that we will explore in this guide.     Step 2: Database Connections   ThingWorx is based on the Java programming language and can make connections to any database that supports a Java-based connection. Dropping the JAR file for the database JDBC driver to the lib folder of Tomcat is all that is needed for connection to the ThingWorx Platform. Follow the below steps to get started creating the connection.   To establish the connection and begin working with an external database, you will need to create a Database Thing and configure the connection string and credentials. Let us start with our database connection. If you have not done so already, download the Aerospace and Defense database scripts: DatabaseApplication.zip. Use the README.txt file to create the database schema. It is based on Microsoft SQL Server, but you can configure the scripts to your database preferences.   NOTE: You will not need to connect to a database to utilize this guide as a learning utility. For your services to work, you will need to connect to a database.   1. In ThingWorx Composer, click the + New at the top-left of the screen.     2. Select Thing in the dropdown.     3. Name the Thing `DatabaseController.Facilities` and select Database as the Base Thing Template.     4.Click Save and go to the Configurations tab.   In this tab, you will enter the class name of your driver, the connection string for that database connection, and the credentials to access the database.   Keep in mind, the JDBC Driver Class Name, JDBC Connection String, and the connection Validation String values are all database type specific. For example, to connect to a SQL Server database, the below configuration can be used.   Title Description  Example   JDBC Driver Class Name  The specific class name of the driver being used for the connection.  net.sourceforge.jtds.jdbc.Driver (SQL Server) or oracle.jdbc.driver.OracleDriver (Oracle)  JDBC Connection String  The connection string to locate the database by host/port/database name.  jdbc:jtds:sqlserver://server:port/databaseName (SQL Server) or jdbc:oracle:thin:@hostname:port:databaseName (Oracle)  connectionValidationString  A simple query that should always work in a database.  SELECT GetDate() (SQL Server) or SELECT SYSDATE FROM DUAL (Oracle)   5. After entering credentials, click Save.     6. Go the Properties and Alerts tab.   The connected Property should be checked. This property informs us of the current connection to the database. The lastConnection Datetime Property should show a current timestamp. This property informs us of the last time there was a valid connection to the database. This is an easy way to confirm the connection to the database.   If you do not have a connection, work on your configurations in the Configurations tab and validate the credentials being used. If you are still having troubles, see the examples section below or use the next section for help to try a query of the database.   Help and Troubleshooting   For help finding the correct configuration for you, check out these JDBC Configuration Examples or try out this Connection String Reference for help with your connection string.   You have just established your first database connection! Now jump to the next section and let us begin to build a data model to match the database schema.   Step 3: Query Data from External Database   Now that you're connected to the database, you can begin querying the database for information and the flow of data. The queries and data shown below are based on the table scripts provided in the download.   Examples of how the ThingWorx entity should look can be seen in the SQLServerDatabaseController and OracleDatabaseController entities.   Running a Query   As you may have noticed by working in ThingWorx and developing applications, an InfoTable is often used to work with large sets of data. An InfoTable is also how data is returned from a database query. If you're expecting only 1 value in the result set, the data will be held in the first index of the InfoTable. If you're expecting rows of data coming back, expect there to be rows of information inside of the InfoTable.   Follow the steps below to set up a helper service to perform queries for the database. While other services might generate the query to be used, this helper service will be a shared execution service.   In the DatabaseController entity, go to the Services tab. Create a new service of type SQL (Query) called RunDatabaseQuery.           3. Set the Output as InfoTable, but do not set the DataShape for the InfoTable.       4. Add the following parameter: Name Base Type Required query String True       5. Add the following code to the new service:   <<query>>       6. Click Save and Continue. Your service signature should look like the below example.       You now have a service that can run queries to the database. This is also a simple method to test/troubleshoot the database connection or a quick query.   Run your service with a simple query. You might notice that no matter the fields in the result set, the InfoTable will match it based on field type and field name.   There are two ways you can go from here. You can either query the database using services that call this service, or you can create more SQL command services that query the database directly. Let's go over each method next, starting with a service to call our helper.   In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service JavaScriptQuery_PersonsTable. Set the Output as InfoTable, but do not set the DataShape for the InfoTable. Add the following code to your new service: try { var query = "SELECT * FROM Persons"; logger.debug("DatabaseController.JavaScriptQuery_PersonsTable(): Query - " + query); var result = me.RunDatabaseQuery({query:query}); } catch(error) { logger.error("DatabaseController.JavaScriptQuery_PersonsTable(): Error - " + error.message); }       5. Click Save and Continue.   Any parameter, especially those that were entered by users, that is being passed into an SQL Statement using the Database Connectors should be fully validated and sanitized before executing the statement! Failure to do so could result in the service becoming an SQL Injection vector.   This is a simple way to query the database since much of your development inside of ThingWorx was already based in JavaScript.   Now, let's utilize the second method to create a query directly to the database. You can use open and close brackets to create parameters for your query. You can also use <> as a method to mark a value that will need to be replaced. As you build your query, use [[Parameter Name]] for parameters/variables substitution and <> for string substitution.   In the Services tab of the DatabaseController entity, create a new service of type JavaScript. Name the service SQLQuery_GetPersonByEmail. Ensure the Output is InfoTable. Add the following code to your new service: SELECT * FROM Persons WHERE person_email = [[email]];       5. Add the following parameter:   Name Base Type Required email String True         6. Click Save and Continue.   An example of using the string replacement is as follows: DELETE FROM <> WHERE (FieldName = '[[MatchName]]'); DELETE FROM << TableName >> WHERE ( FieldName = [[MatchNumber]]);       Click here to view Part 2 of this guide.
View full tip
    Step 8: Tasks   If you are using the built-in Tasker to drive data collection or other types of repetitive or periodic activities, create a function for the task. Task functions are registered with the Tasker and then called at the rate specified after they are registered. The Tasker is a very simple, cooperative multitasker, so these functions should not take long to return and most certainly must not go into an infinite loop.   The signature for a task function is found in [C SDK HOME DIR]/src/utils/twTasker.h. The function is passed a DATETIME value with the current time and a void pointer that is passed into the Tasker when the task is registered. After creating this function, it will need to be registered using the twApi_CreateTask function after the connection is created. Below shows an example of creating this function, registering this function, and how this function can be used.   #define DATA_COLLECTION_RATE_MSEC 2000 void dataCollectionTask(DATETIME now, void * params) { /* TW_LOG(TW_TRACE,"dataCollectionTask: Executing"); */ properties.TotalFlow = rand()/(RAND_MAX/10.0); properties.Pressure = 18 + rand()/(RAND_MAX/5.0); properties.Location.latitude = properties.Location.latitude + ((double)(rand() - RAND_MAX))/RAND_MAX/5; properties.Location.longitude = properties.Location.longitude + ((double)(rand() - RAND_MAX))/RAND_MAX/5; properties.Temperature = 400 + rand()/(RAND_MAX/40); /* Check for a fault. Only do something if we haven't already */ if (properties.Temperature > properties.TemperatureLimit && properties.FaultStatus == FALSE) { twInfoTable * faultData = 0; char msg[140]; properties.FaultStatus = TRUE; properties.InletValve = TRUE; sprintf(msg,"%s Temperature %2f exceeds threshold of %2f", thingName, properties.Temperature, properties.TemperatureLimit); faultData = twInfoTable_CreateFromString("message", msg, TRUE); twApi_FireEvent(TW_THING, thingName, "SteamSensorFault", faultData, -1, TRUE); twInfoTable_Delete(faultData); } /* Update the properties on the server */ sendPropertyUpdate(); } … twApi_CreateTask(DATA_COLLECTION_RATE_MSEC, dataCollectionTask); … while(1) { char in = 0; #ifndef ENABLE_TASKER DATETIME now = twGetSystemTime(TRUE); twApi_TaskerFunction(now, NULL); twMessageHandler_msgHandlerTask(now, NULL); if (twTimeGreaterThan(now, nextDataCollectionTime)) { dataCollectionTask(now, NULL); nextDataCollectionTime = twAddMilliseconds(now, DATA_COLLECTION_RATE_MSEC); } #else in = getch(); if (in == 'q') break; else printf("\n"); #endif twSleepMsec(5); }      Step 9: File Transfer Example    To handle file transfers, a virtual directory is created in the SteamSensor1 entity and in the [C SDK HOME DIR]/examples/FileTransferExample application directory. The source code used for this example is found in [C SDK HOME DIR]/examples/FileTransferExample/src/main.c.   Inside of the [C SDK HOME DIR]/examples/FileTransferExample folder, create the folder structure shown below: /transfer/ /transfer/incoming/ /transfer/outgoing/ Inside of the /transfer/outgoing/ directory, create and open a file with the name outgoing.txt. Once the outgoing.txt document is open, add the following text, save, and close the file: Hello. This is a file coming from the client application. Navigate to the [C SDK HOME DIR]/examples/FileTransferExample/src/main.c code and update the lines below with the appropriate information for your IP, port, and the “admin_key” Application Key’s keyId value in the ThingWorx Composer: /* Server Details */ #define TW_HOST "127.0.0.1" #define TW_PORT 80 #define TW_APP_KEY "ce22e9e4-2834-419c-9656-ef9f844c784c" To support file transfers in your client application, you must use the twFileManager_AddVirtualDir function in order to create the virtual directories in the entity with such a capability. It will also define the directories available for file operations. A virtual directory maps a unique name to an absolute path of a directory in the file system. All subdirectories of the specified directory are exposed to the server. You can define multiple virtual directories. The directories do not need to be contiguous.   Staging Directory   As an optional, but recommended step, you should set the directory that the application should use for staging when performing file transfers. This can be seen in the line below and should be done before initializing the FileManager. The default directory of the FileManager is most likely owned by root and will require a change to either the location of the staging directory and the ownership of the staging directory, or running the application as a User with the correct permissions.   twcfg.file_xfer_staging_dir = "staging"; The example provided uses the TW_SHARE_DIRECTORY macro to create two virtual directories that will act as the root directories in the virtual file system of this application are added. The client is then started as follows with the necessary TW_ADD_FILE_TRANSFER_SHAPE function being called: TW_ADD_FILE_TRANSFER_SHAPE(); TW_SHARE_DIRECTORY("in", "/transfer/incoming/"); TW_SHARE_DIRECTORY("out", "/transfer/outgoing/"); The creations of the payloads used to create the remote directories on the platform have been moved to a helper function below to make the design cleaner: int setupSystemRepo(const char * remoteInPath, const char * remoteOutPath, const char * remoteFile); After our remote directories and files have been setup, it is time to perform the file transfers. Normally, this would mean invoking the Copy service for a Subsystem, but two functions have been created to make this process easier: int twFileManager_GetFile(const char * sourceRepo, const char * sourcePath, const char * sourceFile, const char * targetRepo, const char * targetPath, const char * targetFile, uint32_t timeout, char asynch, char ** tid) int twFileManager_SendFile(const char * sourceRepo, const char * sourcePath, const char * sourceFile, const char * targetRepo, const char * targetPath, const char * targetFile, uint32_t timeout, char asynch, char ** tid) The table below displays an example of the first set of parameters:    Parameter     Example                             Description sourceRepo SystemRepository The name of FileRepository or RemoteThing to transfer the file FROM. sourcePath outgoing The path specifying the location of the source file. sourceFile The name of the source file.   targetRepo SteamSensor1 The name of FileRepository or RemoteThing to transfer the file TO. targetPath incoming The path specifying the destination location of the file. targetFile incoming.txt The name of the file at the target. This name can differ from the sourceName. timeout 15,000 The amount of time (in seconds) to wait for a synchronous transfer to complete before cancelling the transfer. async false If false, the service call will block for timeout seconds or until the transfer completes. tid incoming0123 The unique TID associated with the file.   The C SDK also provides the ability to create a FileCallback function that the FileManager will call that function when any file transfer events occur. You can provide a wildcard filter so that only file transfer Events of files that match the filter call the callback function. In addition, callbacks can be set up as “one-shots” such that the callback is unregistered automatically after it is invoked the first time.   NOTE: An optional file transfer callback is registered in the code and provided. You will see the output from the function as files are sent and received.   After running this application, you will notice a new file in the transfer/incoming folder after refreshing. This is the file that we created in the ThingWorx Composer file system for the SystemRepository Entity and was able to copy from that location to our local project. We have also sent a file to the server’s SystemRepository. The BrowseFileSystem and GetFileListing services can be used to check for the folders and files created.   twFileManager_RegisterFileCallback(fileCallbackFunc, NULL, FALSE, NULL);     Step 10: Support Other Platforms   All Websocket errors indicate some general issue communicating with the ThingWorx platform. If you experience an issue connecting, refer to the table below for a list of websocket errors, their corresponding codes, and an explanation of the issue.    Code     Message                                                                      Troubleshooting 200 TW_UNKNOWN_WEBSOCKET_ERROR An unknown error occurred on the websocket. 201 TW_ERROR_INITIALIZING_WEBSOCKET An error occurred while initializing the websocket. Check your websocket configuration parameters for validity. 202 TW_TIMEOUT_INITIALIZING_WEBSOCKET A timeout occurred while initializing the websocket. Check the status of the connection to ThingWorx. 203 TW_WEBSOCKET_NOT_CONNECTED The websocket is not connected to ThingWorx. The requested operation cannot be performed. 204 TW_ERROR_PARSING_WEBSOCKET_DATA An error occurred while parsing websocket data. The parser could not break down the data from the websocket. 205 TW_ERROR_READING_FROM_WEBSOCKET An error occurred while reading data from the websocket. Retry the read operation. If necessary, resend the data. 206 TW_WEBSOCKET_FRAME_TOO_LARGE The SDK is attempting to send a websocket frame that is too large. The Maximum Frame Size is set when calling twAPI_Initialize and should always be set to the Message Chunk Size (twcfg.message_chunk_size). 207 TW_INVALID_WEBSOCKET_FRAME_TYPE The type of the frame coming in over the websocket is invalid. 208 TW_WEBSOCKET_MSG_TOO_LARGE The application is attempting to send a message that has been broken up in to chunks that are too large to fit in a frame. You should not see this error. 209 TW_ERROR_WRITING_TO_WEBSOCKET An error occurred while writing to the Web socket. 210 TW_INVALID_ACCEPT_KEY The Accept key sent earlier from ThingWorx is not valid.     Step 11: Next Steps   Congratulations! You've successfully completed the Low Level Device Connect Guide, and learned how to utilize the resources provided in the Edge SDK to create your own application.   The next guide in the Utilizing ThingWorx to Secure Your Aerospace and Defense Systems learning path is Tracking Activities and Statistics.    Learn More   We recommend the following resources to continue your learning experience:    Capability      Guide Build Design Your Data Model Build Implement Services, Events, and Subscriptions   Additional Resources   If you have questions, issues, or need additional information, refer to:    Resource       Link Community Developer Community Forum Support C Edge SDK Help Center      
View full tip
  Step 6: Create OPC UA Tag in ThingWorx   We will now create a Device in Kepware with a Tag whose value will be shown in ThingWorx.   Right-click on Channel1 that was just created, then click Next to accept the default name Device1       Click Next six times to accept the default settings, Then click the Select import items button.     Expand the remote OPC UA server URL, then expand OpcPlc and Telemetry.     Click SlowUint1 to select it, then click Add items >>. Click OK, Next, Finish. Return to ThingWorx Composer. Under Browse > Modeling > Industrial Connections, open IndConn_Server. Expand Channel1 > Device1 > OpcPlc, then click Telemetry.     Click the check-box next to SlowUint1. Click Bind to New Entity.     Select RemoteThing, then click OK. Enter azure-opcua-plc in the Name field, then click Save.     Click Properties and Alerts, then Click Refresh to see the property value changing every 10 seconds.     Step 7: Next Steps   Congratulations! You've successfully completed the Connect to an Azure OPC UA Server guide, and learned how to:   Create an OPC UA Server in Azure Configure Kepware as on OPC UA Client Connect Kepware to ThingWorx Foundation Monitor OPC UA data in ThingWorx Composer   Learn More   We recommend the following resources to continue your learning experience: Capability Guide Experience Create Your Application UI   Additional Resources   If you have questions, issues, or need additional information, refer to:   Resource Link Community Developer Community Forum Support Getting Started with ThingWorx Documentation Kepware documentation Support Kepware Support site
View full tip
  Utilize the C SDK to build an app that creates a secure connection to ThingWorx with low level device access.   Guide Concept   This project will cover using the ThingWorx C SDK to develop applications for the purpose of secure and low level development.   Following the steps in this this guide, you will be ready to develop your own IoT application with the ThingWorx C SDK.   We will teach you how to use the C programming language to connect and build IoT applications to be used with the ThingWorx Platform.       You'll learn how to   Establish and manage a secure connection with a ThingWorx server, including SSL negotiation and connection maintenance. Enable easy programmatic interaction with the Properties, Services, and Events that are exposed by Entities running on a ThingWorx server. Basic concepts of the C Edge SDK How to create an application that can communicate with other devices   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 Examples   Download the completed files attached to this tutorial: C_SDK.zip.   This tutorial will guide you through working with the C SDK on differing levels. Utilize this file to see a finished example and return to it as a reference if you become stuck creating your own fully flushed out application. With the C SDK, you can connect to whatever device you have at a level most programming languages wouldn't be able to. Now think of your secure system, your fighter jet, or even you communication devices. All these systems and levels need to have a way to secure transfer data and the C SDK is how we do it.   Keep in mind, this download uses the exact names for entities used in this tutorial. If you would like to import this example and also create entities on your own, change the names of the entities you create.     Step 2: Environment Setup   In order to compile C code, download the attached C compiler: C-SDK-2-2-12-1052.zip.    Operating System          Notes Windows You will need a 3rd party compiler such as MinGW GCC, Cygwin GCC or you can follow these Microsoft instructions to download and use the Microsoft Visual C++ Build Tool. Mac Download the Apple Developer Tools. Linux/Ubuntu A compiler is included by default.   NOTE: You can use CMake, version 2.6.1 or later to build projects or make files, which then are used to build the applications that you develop with the C SDK. Before you can begin developing with the ThingWorx C SDK, you need to generate an Application Key and modify the source code file. You can use the Create an Application Key as a reference.   Modify Source File   Extract the files from the C SDK samples zip file. At the top level of the extracted files, you will see a folder called examples, which provides examples of how to utilize the C SDK. Open a terminal, go to your workspace, and create a new project. After you've created this project in your workspace, import the entire C SDK downloaded from the PTC Support site for ease of use (mainly the src folder and the CMakeList.txt file). You can start creating your connection code or open the main.c source file in the examples\SteamSensor\src directory for an example.    Operating System        Code Linux/Ubuntu gedit main.c OR vi main.c Mac open –e main.c Windows start main.c   5. Modify the Server Details section at the top with the IP address for your ThingWorx Platform instance and the application key you would like to use. Change the TW_HOST definition accordingly. Change the TW_PORT definition accordingly. Change the TW_APP_KEY definition to the keyId value saved from the last step. /* Server Details */ #define TW_HOST "https://pp-XXXXXXXXX.devportal.ptc.i" #define TW_PORT 80 #define TW_APP_KEY "e1d78abf-cfd2-47a6-92b7-37dc6dd34618" NOTE: Using the Application Key for the default Administrator is not recommended. If administrative access is absolutely necessary, create a user and place the user as a member of Admins.   Compile and Run Code   To test your connection, you will only need to update the main.c in the SteamSensor example folder.   CMake can generate visual studio projects, make build files or even target IDEs such as Eclipse, or XCode. CMake generates a general description into a build for your specific toolchain or IDE.   If you have not downloaded and installed CMake, do it now at the CMake website. NOTE: CMake comes as a command line and a GUI application. The steps in this guide use the command line version only. Inside the specific example folder you would like to run, ie SteamSensor. Create a directory to build in, for this example call it cmake. mkdir cmake cd cmake 4. Run the CMake command listed below. This assumes CMake is already on your PATH. cmake -G "Visual Studio 15 2012" .. 5. CMake has now produced a set of project files which should be compatible with your development environment.  Operating System    Command                                        Notes Unix command-> make A set of make files Windows **msbuild tw-c-sdk.sln /t:build** A visual studio solution NOTE: CMake does its best to determine what version of Visual Studio you have but you may wish to specify which version to use if you have more than one installed on your computer. Below is an example of forcing CMake to use a specific version of Visual Studio: cmake -G "Visual Studio 15 2017" .. If your version of Visual Studio or other IDE is unknown, use cmake -G to see a list of supported IDEs.   You also have the alternative of opening the tw-c-sdk.sln from within Visual Studio and building in this IDE.   NOTE: By default, CMake will generate a build for the creation of a release binary. If you want to generate a debug build, use the command-> cmake -DBUILD_DEBUG=ON.   6. Once your build completes you will find the build products in the cmake directory. From here, open the project in your IDE of choice. NOTE: You should receive messages confirming successful binding, authentication, and connection after the main.c file edits have been made.       Step 3: Run Sample Code   The C code in the sample download is configured to run and connect to the Entities provided in the ThingWorxEntitiesExport.xml file. Make note of the IP address of your ThingWorx Composer instance. The top level of the exported zip file will be referred to as [C SDK HOME DIR]. Navigate to the [C SDK HOME DIR]/examples/ExampleClient/src directory. Open the main.c source file.  Operating System      Command Linux/Ubuntu gedit main.c OR vi main.c Mac open –e main.c Windows start main.c   3. Modify the Server Details section at the top with the IP address for your ThingWorx Platform instance and the Application Key you would like to use. Change the TW_HOST definition accordingly. NOTE: By default, TW_APP_KEY has been set to the Application Key from the admin_key in the import step completed earlier. Using the Application Key for the default Administrator is not recommended. If administrative access is absolutely necessary, create a user and place the user as a member of the Admins security group. /* Server Details */ #define TW_HOST "127.0.0.1" #define TW_APP_KEY "ce22e9e4-2834-419c-9656-e98f9f844c784c"   4. If you are working on a port other than 80, you will need to update the conditional statement within the main.c source file. Search for and edit the first line within the main function. Based on your settings, set the int16_t port to the ThingWorx platform port. 5. Click Save and close the file. 6. Create a directory to build in, for this example call it bin.  Operating System            Command Linux/Ubuntu mkdir bin Mac mkdir bin Windows mkdir bin   7. Change to the newly created bin directory.  Operating System              Command Linux/Ubuntu cd bin Mac cd bin Windows cd bin   8. Run the CMake command using your specific IDE of choice. NOTE: Include the two periods at the end of the code as shown below. Use cmake -G to see a list of supported IDEs. cmake ..   9. Once your build completes, you will find the build products in the bin directory, and you can open the project in your IDE of choice. NOTE: You should receive messages confirming successful binding, authentication, and connection after building and running the application. 10. You should be able to see a Thing in your ThingWorx Composer called SimpleThing_1 with updated lastConnection and isConnected properties. SimpleThing_1 is bound for the duration of the application run time.   The below instructions will help to verify the connection.   Click Monitoring. Click Remote Things from the list to see the connection status. You will now be able to see and select the Entity within the list.       Step 4: ExampleClient Connection   The C code provided in the main.c source file is preconfigured to initialize the ThingWorx C Edge SDK API with a connection to the ThingWorx platform and register handlers. In order to set up the connection, a number of parameters must be defined. This can be seen in the code below.   #define TW_HOST "127.0.0.1" #define TW_APP_KEY "ce22e9e4-2834-419c-9656-ef9f844c784c #if defined NO_TLS #define TW_PORT = 80; #else #define TW_PORT = 443; #endif   The first step of connecting to the platform: Establish Physical Websocket, we call the twApi_Initialize function with the information needed to point to the websocket of the ThingWorx Composer. This function:   Registers messaging handlers Allocates space for the API structures Creates a secure websocket err = twApi_Initialize(hostname, port, TW_URI, appKey, NULL, MESSAGE_CHUNK_SIZE, MESSAGE_CHUNK_SIZE, TRUE); if (TW_OK != err) { TW_LOG(TW_ERROR, "Error initializing the API"); exit(err); }   If you are not using SSL/TLS, use the following line to test against a server with a self-signed certificate: twApi_SetSelfSignedOk();   In order to disable HTTPS support and use HTTP only, call the twApi_DisableEncryption function. This is needed when using ports such as 80 or 8080. A call can be seen below:   twApi_DisableEncryption();   The following event handlers are all optional. The twApi_RegisterBindEventCallback function registers a function that will be called on the event of a Thing being bound or unbound to the ThingWorx platform. The twApi_RegisterOnAuthenticatedCallback function registered a function that will be called on the event the SDK has been authenticated by the ThingWorx Platform. The twApi_RegisterSynchronizeStateEventCallback function registers a function that will be called after binding and used to notify your application about fields that have been bound to the Thingworx Platform.   twApi_RegisterOnAuthenticatedCallback(authEventHandler, TW_NO_USER_DATA); twApi_RegisterBindEventCallback(NULL, bindEventHandler, TW_NO_USER_DATA); twApi_RegisterSynchronizeStateEventCallback(NULL, synchronizeStateHandler, TW_NO_USER_DATA);   NOTE: Binding a Thing within the ThingWorx platform is not mandatory, but there are a number of advantages, including updating Properties while offline.    You can then start the client, which will establish the AlwaysOn protocol with the ThingWorx Composer. This protocol provides bi-directional communication between the ThingWorx Composer and the running client application. To start this connection, use the line below:   err = twApi_Connect(CONNECT_TIMEOUT, RETRY_COUNT); if(TW_OK != err){ exit(-1); }   Click here to view Part 2 of this guide.      
View full tip
Announcements