diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..c382d19 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/Blockchain/.DS_Store b/Blockchain/.DS_Store new file mode 100644 index 0000000..bfdd813 Binary files /dev/null and b/Blockchain/.DS_Store differ diff --git a/Blockchain/IoT-Perishable-Network/lib/logic.js b/Blockchain/IoT-Perishable-Network/lib/logic.js index a459b41..2af5d20 100644 --- a/Blockchain/IoT-Perishable-Network/lib/logic.js +++ b/Blockchain/IoT-Perishable-Network/lib/logic.js @@ -12,6 +12,7 @@ * limitations under the License. */ +'use strict'; /** * A shipment has been received by an importer * @param {org.acme.shipping.perishable.ShipmentReceived} shipmentReceived - the ShipmentReceived transaction @@ -160,7 +161,7 @@ function AccelReading(AccelReading) { AccelerationEvent.accel_x = AccelReading.accel_x; AccelerationEvent.accel_y = AccelReading.accel_y; AccelerationEvent.accel_z = AccelReading.accel_z; - AccelerationEvent.latitude = AccelReading.latitude; + AccelerationEvent.latitude = AccelReading.latitude; AccelerationEvent.longitude = AccelReading.longitude; AccelerationEvent.readingTime = AccelReading.readingTime; AccelerationEvent.message = 'Acceleration threshold violated! Emitting AccelerationEvent for shipment: ' + shipment.$identifier; @@ -171,7 +172,7 @@ function AccelReading(AccelReading) { .then(function (shipmentRegistry) { // add the temp reading to the shipment return shipmentRegistry.update(shipment); - }); + }); } /** @@ -182,10 +183,10 @@ function AccelReading(AccelReading) { function gpsReading(gpsReading) { var factory = getFactory(); - var NS = "org.acme.shipping.perishable"; + var NS = 'org.acme.shipping.perishable'; var shipment = gpsReading.shipment; var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W'; - + if (shipment.gpsReadings) { shipment.gpsReadings.push(gpsReading); } else { @@ -195,7 +196,7 @@ function gpsReading(gpsReading) { var latLong = '/LAT:' + gpsReading.latitude + gpsReading.latitudeDir + '/LONG:' + gpsReading.longitude + gpsReading.longitudeDir; - if (latLong == PORT_OF_NEW_YORK) { + if (latLong === PORT_OF_NEW_YORK) { var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent'); shipmentInPortEvent.shipment = shipment; var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK; @@ -204,10 +205,10 @@ function gpsReading(gpsReading) { } return getAssetRegistry(NS + '.Shipment') - .then(function (shipmentRegistry) { + .then(function (shipmentRegistry) { // add the temp reading to the shipment - return shipmentRegistry.update(shipment); - }); + return shipmentRegistry.update(shipment); + }); } /** @@ -295,4 +296,4 @@ function setupDemo(setupDemo) { // add the shipments return shipmentRegistry.addAll([shipment]); }); -} +} \ No newline at end of file diff --git a/Blockchain/IoT-Perishable-Network/logic.js b/Blockchain/IoT-Perishable-Network/logic.js index a459b41..2af5d20 100644 --- a/Blockchain/IoT-Perishable-Network/logic.js +++ b/Blockchain/IoT-Perishable-Network/logic.js @@ -12,6 +12,7 @@ * limitations under the License. */ +'use strict'; /** * A shipment has been received by an importer * @param {org.acme.shipping.perishable.ShipmentReceived} shipmentReceived - the ShipmentReceived transaction @@ -160,7 +161,7 @@ function AccelReading(AccelReading) { AccelerationEvent.accel_x = AccelReading.accel_x; AccelerationEvent.accel_y = AccelReading.accel_y; AccelerationEvent.accel_z = AccelReading.accel_z; - AccelerationEvent.latitude = AccelReading.latitude; + AccelerationEvent.latitude = AccelReading.latitude; AccelerationEvent.longitude = AccelReading.longitude; AccelerationEvent.readingTime = AccelReading.readingTime; AccelerationEvent.message = 'Acceleration threshold violated! Emitting AccelerationEvent for shipment: ' + shipment.$identifier; @@ -171,7 +172,7 @@ function AccelReading(AccelReading) { .then(function (shipmentRegistry) { // add the temp reading to the shipment return shipmentRegistry.update(shipment); - }); + }); } /** @@ -182,10 +183,10 @@ function AccelReading(AccelReading) { function gpsReading(gpsReading) { var factory = getFactory(); - var NS = "org.acme.shipping.perishable"; + var NS = 'org.acme.shipping.perishable'; var shipment = gpsReading.shipment; var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W'; - + if (shipment.gpsReadings) { shipment.gpsReadings.push(gpsReading); } else { @@ -195,7 +196,7 @@ function gpsReading(gpsReading) { var latLong = '/LAT:' + gpsReading.latitude + gpsReading.latitudeDir + '/LONG:' + gpsReading.longitude + gpsReading.longitudeDir; - if (latLong == PORT_OF_NEW_YORK) { + if (latLong === PORT_OF_NEW_YORK) { var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent'); shipmentInPortEvent.shipment = shipment; var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK; @@ -204,10 +205,10 @@ function gpsReading(gpsReading) { } return getAssetRegistry(NS + '.Shipment') - .then(function (shipmentRegistry) { + .then(function (shipmentRegistry) { // add the temp reading to the shipment - return shipmentRegistry.update(shipment); - }); + return shipmentRegistry.update(shipment); + }); } /** @@ -295,4 +296,4 @@ function setupDemo(setupDemo) { // add the shipments return shipmentRegistry.addAll([shipment]); }); -} +} \ No newline at end of file diff --git a/Blockchain/IoT-Perishable-Network/package.json b/Blockchain/IoT-Perishable-Network/package.json index 55f2601..54e42b2 100644 --- a/Blockchain/IoT-Perishable-Network/package.json +++ b/Blockchain/IoT-Perishable-Network/package.json @@ -7,7 +7,7 @@ "description": "IoT Asset Tracker Perishable Goods Business Network", "scripts": { "clean": "rm -Rf ./node_modules ./dist ./composer-logs ./out", - "prepublish": "mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/iot-perishable-network.bna", + "prepublish": "mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/iot-asset-tracker-network.bna", "pretest": "npm run lint", "lint": "eslint .", "postlint": "npm run licchk", @@ -25,8 +25,8 @@ "shipping", "goods", "perishable", - "asset-tracking" - "asset-tracker" + "asset-tracking", + "asset-tracker", "composer", "composer-network", "iot" @@ -35,22 +35,23 @@ "license": "Apache-2.0", "devDependencies": { "browserfs": "^1.2.0", - "chai": "^3.5.0", - "chai-as-promised": "^6.0.0", - "composer-admin": "^0.14.0-0", - "composer-cli": "^0.14.0-0", - "composer-client": "^0.14.0-0", - "composer-connector-embedded": "^0.14.0-0", - "composer-cucumber-steps": "^0.14.0-0", + "chai": "latest", + "chai-as-promised": "latest", + "composer-admin": "^0.19.1", + "composer-cli": "^0.19.1", + "composer-client": "^0.19.1", + "composer-common": "^0.19.1", + "composer-connector-embedded": "^0.19.1", + "composer-cucumber-steps": "^0.19.1", "cucumber": "^2.2.0", - "eslint": "^3.6.1", + "eslint": "latest", "istanbul": "^0.4.5", "jsdoc": "^3.5.5", "license-check": "^1.1.5", - "mkdirp": "^0.5.1", - "mocha": "^3.2.0", + "mkdirp": "latest", + "mocha": "latest", "moment": "^2.17.1", - "nyc": "^11.0.2" + "nyc": "latest" }, "license-check-config": { "src": [ diff --git a/Blockchain/README.md b/Blockchain/README.md index 90fcff7..a8a0a2c 100644 --- a/Blockchain/README.md +++ b/Blockchain/README.md @@ -1,46 +1,35 @@ # IoT Asset Tracking on a Hyperledger Blockchain -This section of the IoT Asset tracking workshop is really split into two parts. The first part, which we will call **Blockchain Part A**, follows the tutorial to deploy a [Hyperledger](https://www.hyperledger.org/) Fabric and Hyperledger Composer running in the [IBM Cloud Container Service](https://www.ibm.com/cloud/container-service) managed by a [Kubernetes cluster](https://console.bluemix.net/docs/tutorials/scalable-webapp-kubernetes.html#deploy-a-scalable-web-application-on-kubernetes) in the IBM Cloud. +This section of the IoT Asset tracking workshop is really split into two parts. The first part, which we will call **Blockchain Part A**, follows the tutorial to deploy a [Hyperledger](https://www.hyperledger.org/) Fabric and Hyperledger Composer running in the [IBM Blockchain Starter Plan](https://www.ibm.com/blockchain/getting-started.html) in the IBM Cloud. -The IBM Blockchain tutorial is excellent and I won't try to repeat it here. Part A takes a while to provision so you'll want to start it and then get a head start on the [Node-RED section](../Node-RED/README.md) of the workshop while you wait. The out-of-order execution is detailed below. Finally, the **Blockchain Part B** will detail how to implement a **Perishable Business Network** and Hyperledger Composer REST APIs. +**Note:** User could incur charges! -## Blockchain Part A - Build a basic IBM Blockchain Hyperledger network -The IBM Container Service free plan includes everything you need to deploy a Hyperledger Fabric (Blockchain runtime) and a Hyperledger Composer (UI for creating and deploying Business Networks to Fabric). The [guide](https://ibm-blockchain.github.io/) makes it relatively simple. Get started however, because provisioning a kubernetes cluster can take 30 minutes. +* The IBM Blockchain Starter Plan is free for only 30 days through IBM Cloud credits and could change at any time. You may need to enter your credit card information to be able to deploy the Blockchain Starter Plan. There will be notes at the end of the code pattern to remove the instances to help eliminate the potential risk of charges. -Follow the **Free Cluster** [Prepare & Setup](https://ibm-blockchain.github.io/setup/) instructions. Once you execute the cluster-create command, you'll be waiting.... Return here. +There are quite a few IBM Blockchain tutorials that are excellent and we won't try to repeat them here. We will be using a couple of them along the way. In **Blockchain Part A** we are going to create our blockchain business network of perishable goods. In **Blockchain Part B** we will convert it into smart contracts to deploy to the IBM Blockchain Starter Plan. We will use part of the IBM Cloud called DevOps to build our code and deploy it to an instance of the IBM Blockchain Starter Plan. The build process will also deploy a Hyperledger Composer Rest Server running as a Cloud Foundry service in the IBM Cloud. The Hyperledger Composer REST APIs will be used by Node-RED to talk to the blockchain perishable network. Finally, you'll get to work with Node-RED to interact and visually see the tracking of the asset. -Glad, you're back. Your free cluster is provisioning. You've got about 25-30 minutes to get a jump on the [Node-RED section](../Node-RED/README.md) of the workshop. Every few minutes, keep an eye on the status of your cluster. -``` -$ bx cs clusters -``` -Once the IBM Cloud Container Service returns from the cluster provisioning, finish that section of the Prepare & Setup instructions and then proceed to the Hyperledger Composer setup in the [Simple Install](https://ibm-blockchain.github.io/simple/) instructions. +## Blockchain Part A - Build your perishable network -## Blockchain Part B - Implement a Perishable Business Network -Follow Step #1 and #2 of [Interacting with your Blockchain](https://ibm-blockchain.github.io/interacting/) instructions. -At this point you should have opened a browser tab to -``` -http://YOUR_PUBLIC_IP_HERE:31080/login -``` -1. Press the **Launch Now** button +We will be using Hyperledger Composer Playground to build our perishable network. When we are done, we will export the code to our local system to use in Part B. + +### Import the sample perishable network into Hyperledger Composer Playground +1. Access the [IBM Hyperledger Composer Playground](http://composer-playground.mybluemix.net/). 2. Click on **Deploy a new business network** -3. For our use case, you should substitute the **Perishable Network** sample instead of the basic Business Network. Don't pick the first / prefilled basic-sample-network! Scroll down to the 'Samples on npm'. The **perishable-network** is in the list of Model Network Starter Templates. -4. Scroll down and choose **perishable-network** from the samples. -5. Give your new Business Network a name (1) **perishable-network** -6. Give the network admin card that will be created a name (2) **admin@perishable-network** -![Perishable Network BNA screenshot](screenshots/Perishable-Network-BNA-annotated.png "Hyperledger Composer") -7. Scroll to the bottom, Click on (3) **ID and Secret** -8. Enter (4) **admin** as the Enrollment ID -9. Enter (5) **adminpw** as the Enrollment Secret -![Perishable Network BNA creds screenshot](screenshots/Perishable-Network-BNA-creds-annotated.png "Hyperledger Composer") -10. Scroll to the top of the page. -11. On the right sidebar, click on **Deploy** -12. Press **Connect now ->** -![Perishable Network BNA creds screenshot](screenshots/Perishable-Network-BNA-ConnectNow.png "Hyperledger Composer") - -## Perishable Network Discussion + ![Select Deploy a new business network.](screenshots/deploynew.png) +3. Scroll down and choose **perishable-network** from the samples on npm. + ![Select perishable-network from the *Samples on npm*.](screenshots/npmsample.png) +4. Scrolling back to the top, you should now have a business network name of **xxx-perishable-network**, where xxx is a unique identifer. + * Note: The unique identifier becomes very important later on in this code pattern because this business network name is used to create a rest server on the IBM Cloud. If the name is not unique then it will fail during the build process. +5. Give the network admin card that will be created a name **admin@xxx-perishable-network**. + ![Perishable Network BNA screenshot](screenshots/Perishable-Network-BNA-annotated.png "Hyperledger Composer") +6. On the right sidebar, click on **Deploy**. +7. Press **Connect now ->** + +![Select Connect now](screenshots/ConnectNow.png) + +### Customize the perishable network for IoT tracking Let's pause for a moment to review the perishable-network you just deployed. It tracks temperature but not geolocation information. There is an excellent three part Hyperledger series of articles in developerWorks that introduce the perishable-network. -* [Hyperledger Composer basics, Part 1 - -Model and test your blockchain network](https://www.ibm.com/developerworks/cloud/library/cl-refine-deploy-your-blockchain-network-with-hyperledger-composer-playground/index.html) +* [Hyperledger Composer basics, Part 1 - Model and test your blockchain network](https://www.ibm.com/developerworks/cloud/library/cl-refine-deploy-your-blockchain-network-with-hyperledger-composer-playground/index.html) * [Hyperledger Composer basics, Part 2 - Refine and deploy your blockchain network](https://www.ibm.com/developerworks/cloud/library/cl-refine-deploy-your-blockchain-network-with-hyperledger-composer-playground/index.html) * [Hyperledger Composer basics, Part 3 - Deploy locally, interact with, and extend your blockchain network](https://www.ibm.com/developerworks/cloud/library/cl-deploy-interact-extend-local-blockchain-network-with-hyperledger-composer/index.html) @@ -55,40 +44,364 @@ Of course, those samples only got me so far because I also want to send accelero We're going to need to learn a little bit about the Hyperledger Blockchain modeling language CTO files and chaincode. Part 1 of the dW Series (link above) is a good primer. -That brings me to my **forked implementation of the perishable-network**. It adds accelerometer data transactions and chaincode. It also changes the transactions to include environmental data, geolocation and a timestamp in one record. My blockchain model implementation is necessary for this IoT Asset Tracking Perishable Network to function correctly. +In the following steps, we will make changes to the model file to add in accelerometer data, environmental data, geolocation and a timestamp. Adding in the IoT data will also require additional transactions. To save time after we complete the model file updates, we will import the transactions from a cloned repository. + +1. In the **enum ProductType**, add a variable to the enum for **medicine**. +``` + enum ProductType{ + + o BANANAS + + o APPLES + + o PEARS -This repository contains the forked [perishable.cto](IoT-Perishable-Network/perishable.cto) and the perishable [chaincode](IoT-Perishable-Network/logic.js) + o PEACHES -## Replace the default perishable-network model and chaincode -The following instructions replace the default perishable-network model and chaincode with my implementation. -1. Recall that you've pressed the **Connect now ->** button. -2. Click on the **Model File** (1) in the Files sidebar -3. Place your cursor in the Model File editor, Ctrl-A to select all the text. Ctrl-D to delete the text. -4. Visit [perishable.cto](IoT-Perishable-Network/perishable.cto) and copy that file to your clipboard. -5. Paste in my modified Model from github into the model. -6. Scroll down in the Files sidebar -7. Click on **Script File** (2) in the Files sidebar -8. Place your cursor in the Script File editor, Ctrl-A to select all the text. Ctrl-D to delete the text. -9. Visit [chaincode](IoT-Perishable-Network/logic.js) and copy that file to your clipboard. -10. Paste in my modified chaincode from github into the Script file. -11. Press the Update button + o COFFEE + o MEDICINE + + } +``` + +2. In your model file, create **enum CompassDirection**. Enter the following values to enumerate the four cardinal directions: +``` +/** + * Directions of the compass + */ +enum CompassDirection { + o N + o S + o E + o W +} +``` +2. Now we need some transaction models to be able to get data from our sensors. Add the following **transaction AccelReading extends ShipmentTransaction**: +``` +/** + * An Accelerometer reading for a shipment. E.g. received from a + * device within an accelerometer controlled shipping container + * + * The combination of the accelerometer environment reading, + * PLUS the GPS location, PLUS the timestamp is what is interesting + * Just knowing temperature without knowing where or when is + * not sufficient. + */ +transaction AccelReading extends ShipmentTransaction { + o Double accel_x + o Double accel_y + o Double accel_z + o String latitude + o String longitude + o String readingTime +} +``` +3. For **transaction TemperatureReading extends ShipmentTransaction** modify the transaction to match the following variables: +``` +transaction TemperatureReading extends ShipmentTransaction { + o Double celsius + o String latitude + o String longitude + o String readingTime +} +``` +4. It's time to setup the **transaction GpsReading extends ShipmentTransaction**. Add the following: +``` +/** + * A GPS reading for a shipment. E.g. received from a device + * within a shipping container + */ +transaction GpsReading extends ShipmentTransaction { + o String readingTime + o String readingDate + o String latitude + o CompassDirection latitudeDir + o String longitude + o CompassDirection longitudeDir +} +``` + +5. For the IoT data to be associated with the asset, shipment, we will need to add some IoT related variables to the asset model for shipment. Make the following additions to **asset Shipment identified by shipmentId**. +* AccelReading[] AccelReadings optional +* GpsReading[] gpsReadings optional +``` +asset Shipment identified by shipmentId { + o String shipmentId + o ProductType type + o ShipmentStatus status + o Long unitCount + --> Contract contract + o TemperatureReading[] temperatureReadings optional + o AccelReading[] AccelReadings optional + o GpsReading[] gpsReadings optional +} +``` + +6. Our contract will also now be dependent on the shipment arriving without any incidents captured by the accelerometer. We will need to add a field for the accelerometer value to the contract asset model. This will allow us to specify conditions for a crash, a hard jolt or other incidents based on the accelerometer data in the logic.js file. +* Add **Double maxAccel** to the Contract asset model. +``` +asset Contract identified by contractId { + o String contractId + --> Grower grower + --> Shipper shipper + --> Importer importer + o DateTime arrivalDateTime + o Double unitPrice + o Double minTemperature + o Double maxTemperature + o Double minPenaltyFactor + o Double maxPenaltyFactor + o Double maxAccel +} +``` +7. Now we need to create some events so we can alert the appropriate participants when agreed upon thresholds are exceeded. Scroll down to the bottom of the model and add in the following information for the **TemperatureThresholdEvent**. +``` +/** + * An event - when the temperature goes outside the agreed-upon boundaries + */ +event TemperatureThresholdEvent { + o String message + o Double temperature + o String latitude + o String longitude + o String readingTime + --> Shipment shipment +} +``` + +8. Create an event for the **AccelerationThresholdEvent**. +``` +/** + * An event - when the acceleration event has been detected + */ +event AccelerationThresholdEvent { + o String message + o Double accel_x + o Double accel_y + o Double accel_z + o String latitude + o String longitude + o String readingTime + --> Shipment shipment +} +``` +9. Add in the event **ShipmentInPort**. +``` +/** + * An event - when the ship arrives at the port + */ +event ShipmentInPortEvent { + o String message + --> Shipment shipment +} +``` + +10. Our model file is now complete. Select **Deploy changes** to save the changes in the Hyperledger Composer Playground. +![Click Update.](screenshots/Update.png) + +11. Now it is time to **copy** (CTRL+C) our new logic.js file from our [repository](IoT-Perishable-Network/lib/logic.js). + +12. Back in the Hyperledger Composer Playground: +* **Remove all of the content** (CTRL+A) in the logic.js file +* **Paste** (CTRL+V) in the content copied from the logic.js file in our repository. +* Select **Deploy Changes** to save the changes. ![Perishable Network BNA model update screenshot](screenshots/Perishable-Network-BNA-Model-update-annotated.png "Hyperledger Composer Model") +13. Now let's test our work! Click on the **Test** tab at the top of the page. +![Click Test.](screenshots/Test.png) + +14. First, select **Submit Transaction** so we can run our *setupDemo* transaction to give us some default values. +![Select Submit Transaction.](screenshots/SubmitTransaction.png) + +15. From the *drop down*, select **SetupDemo** and then **Submit**. +![Run setupDemo.](screenshots/SetupDemo.png) + +16. Look through your three partipants and two assets. You should now have a defined Grower, Importer, Shipper, Shipment and Contract. + +17. Play with the other transactions to make sure that they update your assets. You should see fields added to your shipment in particular like the example below. You can enter any data. It doesn't need to be realistic. +![Test your transactions and verify it updates the asset.](screenshots/example.png) + +18. Click on the **Define** tab to**Export** the code to your local system. We will use it during the deployment process. +![Click Export.](screenshots/export.png) + +19. Save the business network archive, **perishable-network.bna**, somewhere you can easily find it. +![Save your business network archive locally.](screenshots/savebna.png) + +## Blockchain Part B - Implement a Perishable Business Network +Now it's time for the fun to begin! We are going to break this down into two sections: + +* [Deploying your blockchain network to your IBM Blockchain Starter Plan](#deploy-your-network) +* [Generating your API for your deployed blockchain network with Hyperledger Composer Rest Server](#working-with-the-rest-api) + + +### Deploy your network +Now that you've created your blockchain application, it's time to make it run on the IBM Blockchain Starter Plan. To do that, we are going to use the DevOps service in the IBM Cloud to deploy our code and start a REST server. This entire process is documented [here](https://github.com/sstone1/blockchain-starter-kit/blob/master/README.md) if you are interested in doing something similar outside of this exercise. This process will create the IBM Blockchain Starter Plan for you. -## Expose the Perishable Business Network as a REST API +**NOTE:** You may have to upgrade your IBM Cloud account to a pay-as-you-go account to use the IBM Blockchain Starter Plan. It is free for up to 30 days. It is your responsibility to monitor usage to avoid fees. -To manipulate the blockchain from Node-RED, we will expose the perishable-network business network using the Hyperledger Composer REST API. -1. Return to the [Hyperledger tutorial](https://ibm-blockchain.github.io/interacting/) and complete the instructions in Step 4. Essentially you will want to run +This breaks down into the following steps: +* [Create a DevOps toolchain](#create-a-devops-toolchain) +* [Installing Hyperledger Composer locally](#install-hyperledger-composer-locally) +* [Moving your code into your repository](#prepare-your-code-for-deployment) +* [Verifying deployment of code](#verify-deployment) + +#### Create a DevOps toolchain +1. Start [here](https://console.bluemix.net/devops/setup/deploy/?repository=https%3A//github.com/sstone1/blockchain-starter-kit&branch=master&env_id=ibm%3Ayp%3Aus-south) to create your DevOps toolchain. + +2. Enter a name for your toolchain. Make it unique! + + **Note:** If you haven't authenticated with GitHub in IBM Cloud before, you will need to do this before you will be able to create the Blockchain Starter Kit. You can do this now by scrolling down on this screen and selecting the authenticate button. + + ![Enter a name for your toolchain.](screenshots/starterkittoolchain.png) + +3. Scroll down and create a unique repository name where your artifacts will be stored on GitHub, **XXX-blockchain-toolkit** where XXX are your initials. + +4. Click **Create**. + ![Create a uniquire repository name and select Create.](screenshots/repositorycreate.png) + +5. If you've used the Delivery Pipeline before, then skip this step. Otherwise, complete the required fields to setup your delivery pipeline. + + * Click on **Create +** to generate an IBM Cloud API Key + + * Enter a unique name for your blockchain service, e.g. xxx-iot-asset-blockchain-service. + + * Click **Create** to begin working with your toolchain. + + ![Create your IBM Cloud API Key.](screenshots/createkey.png) + +6. Congratulations! You have a complete toolchain that can be used to deploy your code. + ![Complete blockchain-starter-kit toolchain.](screenshots/completetoolchain.png) + +The "GitHub" button in the middle will take you to your newly created GitHub repository. You will clone this GitHub repository into your local development environment, so you can work on your blockchain application. + +The "Delivery Pipeline" button on the right will take you to the delivery pipeline for your DevOps toolchain. From here, you can inspect the output from the latest automated build and deployment of your blockchain application. + +#### Install Hyperledger Composer locally +To deploy our code, we'll need to work with some of the Hyperledger Composer commands on our system. + +1. Follow the [directions](https://hyperledger.github.io/composer/latest/installing/installing-index) for installing the prerequisites and installing Hyperledger Composer. +* Only complete Step 1 and Step 2 of installing Hyperledger Composer for this exercise. +* If you've previously had Hyperledger Composer installed, follow these directions for [updating Hyperledger Composer](https://hyperledger.github.io/composer/v0.16/managing/updating-composer). Complete both steps. + +#### Prepare your code for deployment +1. In your toolchain, select the **GitHub** icon to open your newly created repository. +![Select GitHub.](screenshots/gotogithub.png) + +2. In GitHub, click **Clone or download** and then the **copy** button to get the URL to use to clone your repository to your local system. +![Select Clone and then copy.](screenshots/clonegithub.png) + +3. In a terminal on your local system, enter `git clone ` where \ is the value you copied in the previous step. ``` -$ cd cs-offerings/scripts/ -$ ./create/create_composer-rest-server.sh --business-network-card admin@perishable-network +$ git clone https://github.com/SweetJenn23/XXX-blockchain-starter-kit.git +Cloning into 'XXX-blockchain-starter-kit'... +remote: Counting objects: 40, done. +remote: Compressing objects: 100% (35/35), done. +remote: Total 40 (delta 2), reused 40 (delta 2), pack-reused 0 +Unpacking objects: 100% (40/40), done. ``` -2. Visit the Swagger documentation for your blockchain REST API. + +4. Move into the contracts directory, `cd XXX-blockchain-starter-kit/contracts` where XXX are your initials. + +5. We need to make a smart contract from our blockchain network (.bna). To do this we will use one of the tools installed with Hyperledger Composer called Yeoman. This will create a smart contract skeleton we can deploy to Hyperledger Fabric. We will have to copy our work into this skeleton. + +To make the skeleton, type `yo` into a terminal on your local system and create a business network named **XXX-perishable-network** where XXX are your initials. Complete the rest of the information in the prompts. +![Enter the information for Yeoman to create a skeleton smart contract.](screenshots/yo.png) + +6. To copy our code into the skeleton you'll need to expand the business network archive. +* In your terminal, change directory to where your **perishable-network.bna** is saved. +* Change the extension on the file. `mv perishable-network.bna perishable-network.zip` +* Unzip the file. `unzip perishable-network.zip` ``` -http://YOUR_PUBLIC_IP_HERE:31090/explorer +> unzip perishable-network.zip +Archive: perishable-network.zip + extracting: package.json + extracting: README.md + extracting: permissions.acl + creating: models/ + extracting: models/perishable.cto + creating: lib/ + extracting: lib/logic.js ``` +7. Copy the extracted files into your cloned GitHub directory, */XXX-blockchain-starter-kit/contracts/xxx-perishable-network*. Replace the files already in the *xxx-perishable-network* directory with the same name. Do this for all of the following files: +* remove `/xxx-blockchain-starter-kit/contracts/xxx-perisable-network/models/org.acme.biznet.perishable.cto` +* copy `perishable-network/README.md` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network` +* copy `perishable-network/permissions.acl` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network` +* copy `perishable-network/models/perishable.cto` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network/models/` +* copy `perishable-network/lib/logic.js` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network/lib/` +![Move the contents of your perishable-network.bna into the generated skeleton.](screenshots/movecontents.png) -![Perishable Network REST API swagger screenshot](screenshots/Perishable-Network-REST-API-swagger.png "Hyperledger Composer REST API") +8. In your repository edit the file, **~/XXX-blockchain-starter-kit/.bluemix/pipeline-BUILD.sh** + + * Find **function test_composer_contract** + + * In the function comment out the line **npm test**, `#npm test` +``` + function test_composer_contract { + CONTRACT=$1 + echo testing composer contract ${CONTRACT} + pushd contracts/${CONTRACT} + npm install + #npm test + rm -rf node_modules + popd + } +``` + +9. To commit the code to your repository on GitHub for the toolchain you'll need to use the following in a terminal in your **XXX-blockchain-starter-kit** directory: +* `git add -A` +* `git commit -m "Update files"` +* `git push` +![Run these git commands.](screenshots/gitcommit.png) + + +#### Verify deployment +When you committed your code to GitHub, the DevOps toolchain automatically picked up the changes. The toolchain will immediately begin deploying those changes. + +1. Navigate to the DevOps toolchain page, and click on the "**Delivery Pipeline**" button. You should see the following page, giving you an overview of the current status of your delivery pipeline: +![Successful deployment.](screenshots/deploypassed.png) + +2. The delivery pipeline is made up of two phases, "BUILD" and "DEPLOY". + +The "BUILD" phase of the delivery pipeline clones your GitHub repository, installs any dependencies, and runs all of the automated unit tests for all of your smart contracts. If any unit tests fail, then the delivery pipeline will fail and your changes will not be deployed. + +The "DEPLOY" phase of the delivery pipeline deploys your smart contracts into the IBM Cloud. It is reponsible for provisioning and configuring an instance of the IBM Blockchain Platform: Starter Plan (the blockchain network), an instance of Cloudant (the wallet for blockchain credentials), deploying the smart contracts, and deploying RESTful API servers for each deployed smart contract. + +If you click "View logs and history", you can see the latest logs for your build: +![View your logs.](screenshots/toolchainlog.png) + +Both "BUILD" and "DELIVERY" phases should be green and showing that no errors have occurred. If this is not the case, you must use the logs to investigate the cause of the errors. + +### Working with the REST API + +To manipulate the blockchain from Node-RED, we will expose the perishable-network business network using the Hyperledger Composer REST API. Currently, this starter kit does not deploy a RESTful API server for smart contracts developed using Hyperledger Fabric. Since we used Hyperledger Composer, the DevOps toolchain has automatically deployed a RESTful API server for each deployed smart contract. You can use these RESTful APIs to build end user applications that interact with a smart contract. + +1. The URLs for the deployed RESTful API servers are available in the logs for the "DELIVERY" phase, but you can also find them in the [IBM Cloud Dashboard](https://console.bluemix.net/dashboard/apps). The RESTful API server is deployed as an application, with a name made up of "composer-rest-server-" and the name of the smart contract. Ours are called **composer-rest-server-xxx-perishable-network**. +![Find your composer-rest-server in the IBM Cloud Dashboard.](screenshots/composer-rest-server.png) + +2. Click on the rest server to navigate to the application details page. +![View the rest server application details.](screenshots/restserverdetails.png) + +3. Select the **Visit App URL** to view your API. +![Select Visit App URL.](screenshots/VisitAppURL.png) + +4. These APIs are how Node-RED will communicate with blockchain. +![View your APIs.](screenshots/API.png) Congratulations! You have completed the Blockchain section of the workshop. Proceed to the [Node-RED section](../Node-RED/README.md) which will leverage the REST API you just enabled to write / read / visualize IoT Asset environmental sensor data to the transaction history. + + + +### Removing instances from IBM Cloud + +1. From the [IBM Cloud Dashboard](https://console.bluemix.net/dashboard/apps) **stop** and **delete** the following services. + + * Under Cloud Foundry Applications: **composer-rest-server-xxx-perishable-network** + + ![Stop your app and then delete your app.](screenshots/stopanddeleteapp.png) + + * Under Cloud Foundry Services: + + * Your toolchain: **iot-asset-blockchain-starter-kit** (you were told to give this a unique name, so your name may differ.) + * Your blockchain starter plan: **xxx-iot-asset-blockchain-service** + diff --git a/Blockchain/iot-asset-tracker-network.bna b/Blockchain/iot-asset-tracker-network.bna index d62ca6a..f00c980 100644 Binary files a/Blockchain/iot-asset-tracker-network.bna and b/Blockchain/iot-asset-tracker-network.bna differ diff --git a/Blockchain/screenshots/.DS_Store b/Blockchain/screenshots/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Blockchain/screenshots/.DS_Store differ diff --git a/Blockchain/screenshots/API.png b/Blockchain/screenshots/API.png new file mode 100644 index 0000000..5317cee Binary files /dev/null and b/Blockchain/screenshots/API.png differ diff --git a/Blockchain/screenshots/Authorize.png b/Blockchain/screenshots/Authorize.png new file mode 100644 index 0000000..e69eaaf Binary files /dev/null and b/Blockchain/screenshots/Authorize.png differ diff --git a/Blockchain/screenshots/AuthorizeCloud.png b/Blockchain/screenshots/AuthorizeCloud.png new file mode 100644 index 0000000..a0a873f Binary files /dev/null and b/Blockchain/screenshots/AuthorizeCloud.png differ diff --git a/Blockchain/screenshots/Breadcrumbs.png b/Blockchain/screenshots/Breadcrumbs.png new file mode 100644 index 0000000..38de8eb Binary files /dev/null and b/Blockchain/screenshots/Breadcrumbs.png differ diff --git a/Blockchain/screenshots/ConnectNow.png b/Blockchain/screenshots/ConnectNow.png new file mode 100644 index 0000000..db9376f Binary files /dev/null and b/Blockchain/screenshots/ConnectNow.png differ diff --git a/Blockchain/screenshots/Create.png b/Blockchain/screenshots/Create.png new file mode 100644 index 0000000..aef6a9a Binary files /dev/null and b/Blockchain/screenshots/Create.png differ diff --git a/Blockchain/screenshots/DeliveryPipeline.png b/Blockchain/screenshots/DeliveryPipeline.png new file mode 100644 index 0000000..69b9655 Binary files /dev/null and b/Blockchain/screenshots/DeliveryPipeline.png differ diff --git a/Blockchain/screenshots/DeployMarbles.png b/Blockchain/screenshots/DeployMarbles.png new file mode 100644 index 0000000..88519d8 Binary files /dev/null and b/Blockchain/screenshots/DeployMarbles.png differ diff --git a/Blockchain/screenshots/DeploymentProgress.png b/Blockchain/screenshots/DeploymentProgress.png new file mode 100644 index 0000000..2ae0971 Binary files /dev/null and b/Blockchain/screenshots/DeploymentProgress.png differ diff --git a/Blockchain/screenshots/DevOps.png b/Blockchain/screenshots/DevOps.png new file mode 100644 index 0000000..9bd2c3f Binary files /dev/null and b/Blockchain/screenshots/DevOps.png differ diff --git a/Blockchain/screenshots/Guided.png b/Blockchain/screenshots/Guided.png new file mode 100644 index 0000000..deb002d Binary files /dev/null and b/Blockchain/screenshots/Guided.png differ diff --git a/Blockchain/screenshots/MarblesToolchain.png b/Blockchain/screenshots/MarblesToolchain.png new file mode 100644 index 0000000..f240df3 Binary files /dev/null and b/Blockchain/screenshots/MarblesToolchain.png differ diff --git a/Blockchain/screenshots/MarblesUI.png b/Blockchain/screenshots/MarblesUI.png new file mode 100644 index 0000000..f05f15d Binary files /dev/null and b/Blockchain/screenshots/MarblesUI.png differ diff --git a/Blockchain/screenshots/Passed.png b/Blockchain/screenshots/Passed.png new file mode 100644 index 0000000..9d89f68 Binary files /dev/null and b/Blockchain/screenshots/Passed.png differ diff --git a/Blockchain/screenshots/Perishable-Network-BNA-Model-update-annotated.png b/Blockchain/screenshots/Perishable-Network-BNA-Model-update-annotated.png index 4f5437b..ad867e1 100644 Binary files a/Blockchain/screenshots/Perishable-Network-BNA-Model-update-annotated.png and b/Blockchain/screenshots/Perishable-Network-BNA-Model-update-annotated.png differ diff --git a/Blockchain/screenshots/Perishable-Network-BNA-annotated.png b/Blockchain/screenshots/Perishable-Network-BNA-annotated.png index 5d9282c..7ef219d 100644 Binary files a/Blockchain/screenshots/Perishable-Network-BNA-annotated.png and b/Blockchain/screenshots/Perishable-Network-BNA-annotated.png differ diff --git a/Blockchain/screenshots/RepoName.png b/Blockchain/screenshots/RepoName.png new file mode 100644 index 0000000..1f2f5f7 Binary files /dev/null and b/Blockchain/screenshots/RepoName.png differ diff --git a/Blockchain/screenshots/SeeApp.png b/Blockchain/screenshots/SeeApp.png new file mode 100644 index 0000000..f13685f Binary files /dev/null and b/Blockchain/screenshots/SeeApp.png differ diff --git a/Blockchain/screenshots/SelectGitHub.png b/Blockchain/screenshots/SelectGitHub.png new file mode 100644 index 0000000..58cf146 Binary files /dev/null and b/Blockchain/screenshots/SelectGitHub.png differ diff --git a/Blockchain/screenshots/SetupDemo.png b/Blockchain/screenshots/SetupDemo.png new file mode 100644 index 0000000..8f57cc6 Binary files /dev/null and b/Blockchain/screenshots/SetupDemo.png differ diff --git a/Blockchain/screenshots/SubmitTransaction.png b/Blockchain/screenshots/SubmitTransaction.png new file mode 100644 index 0000000..2a01e2a Binary files /dev/null and b/Blockchain/screenshots/SubmitTransaction.png differ diff --git a/Blockchain/screenshots/Success.png b/Blockchain/screenshots/Success.png new file mode 100644 index 0000000..0612753 Binary files /dev/null and b/Blockchain/screenshots/Success.png differ diff --git a/Blockchain/screenshots/Test.png b/Blockchain/screenshots/Test.png new file mode 100644 index 0000000..89b90df Binary files /dev/null and b/Blockchain/screenshots/Test.png differ diff --git a/Blockchain/screenshots/ToolChainName.png b/Blockchain/screenshots/ToolChainName.png new file mode 100644 index 0000000..0cd494c Binary files /dev/null and b/Blockchain/screenshots/ToolChainName.png differ diff --git a/Blockchain/screenshots/TrySamples.png b/Blockchain/screenshots/TrySamples.png new file mode 100644 index 0000000..6cb212e Binary files /dev/null and b/Blockchain/screenshots/TrySamples.png differ diff --git a/Blockchain/screenshots/Update.png b/Blockchain/screenshots/Update.png new file mode 100644 index 0000000..11bd0cb Binary files /dev/null and b/Blockchain/screenshots/Update.png differ diff --git a/Blockchain/screenshots/ViewLogs.png b/Blockchain/screenshots/ViewLogs.png new file mode 100644 index 0000000..3cbf39a Binary files /dev/null and b/Blockchain/screenshots/ViewLogs.png differ diff --git a/Blockchain/screenshots/VisitAppURL.png b/Blockchain/screenshots/VisitAppURL.png new file mode 100644 index 0000000..d407858 Binary files /dev/null and b/Blockchain/screenshots/VisitAppURL.png differ diff --git a/Blockchain/screenshots/clonegithub.png b/Blockchain/screenshots/clonegithub.png new file mode 100644 index 0000000..f8a29e7 Binary files /dev/null and b/Blockchain/screenshots/clonegithub.png differ diff --git a/Blockchain/screenshots/completetoolchain.png b/Blockchain/screenshots/completetoolchain.png new file mode 100644 index 0000000..6ac9163 Binary files /dev/null and b/Blockchain/screenshots/completetoolchain.png differ diff --git a/Blockchain/screenshots/composer-rest-server.png b/Blockchain/screenshots/composer-rest-server.png new file mode 100644 index 0000000..8ee6f9e Binary files /dev/null and b/Blockchain/screenshots/composer-rest-server.png differ diff --git a/Blockchain/screenshots/createkey.png b/Blockchain/screenshots/createkey.png new file mode 100644 index 0000000..864be97 Binary files /dev/null and b/Blockchain/screenshots/createkey.png differ diff --git a/Blockchain/screenshots/deploynew.png b/Blockchain/screenshots/deploynew.png new file mode 100644 index 0000000..ebbd0e1 Binary files /dev/null and b/Blockchain/screenshots/deploynew.png differ diff --git a/Blockchain/screenshots/deploypassed.png b/Blockchain/screenshots/deploypassed.png new file mode 100644 index 0000000..ae9357b Binary files /dev/null and b/Blockchain/screenshots/deploypassed.png differ diff --git a/Blockchain/screenshots/developcode.png b/Blockchain/screenshots/developcode.png new file mode 100644 index 0000000..b88e109 Binary files /dev/null and b/Blockchain/screenshots/developcode.png differ diff --git a/Blockchain/screenshots/example.png b/Blockchain/screenshots/example.png new file mode 100644 index 0000000..2df7ed8 Binary files /dev/null and b/Blockchain/screenshots/example.png differ diff --git a/Blockchain/screenshots/export.png b/Blockchain/screenshots/export.png new file mode 100644 index 0000000..e82e233 Binary files /dev/null and b/Blockchain/screenshots/export.png differ diff --git a/Blockchain/screenshots/gitcommit.png b/Blockchain/screenshots/gitcommit.png new file mode 100644 index 0000000..b8719cb Binary files /dev/null and b/Blockchain/screenshots/gitcommit.png differ diff --git a/Blockchain/screenshots/gotogithub.png b/Blockchain/screenshots/gotogithub.png new file mode 100644 index 0000000..1d1e121 Binary files /dev/null and b/Blockchain/screenshots/gotogithub.png differ diff --git a/Blockchain/screenshots/launchnow.png b/Blockchain/screenshots/launchnow.png new file mode 100644 index 0000000..4830928 Binary files /dev/null and b/Blockchain/screenshots/launchnow.png differ diff --git a/Blockchain/screenshots/menubar.png b/Blockchain/screenshots/menubar.png new file mode 100644 index 0000000..27bee6c Binary files /dev/null and b/Blockchain/screenshots/menubar.png differ diff --git a/Blockchain/screenshots/movecontents.png b/Blockchain/screenshots/movecontents.png new file mode 100644 index 0000000..bb24207 Binary files /dev/null and b/Blockchain/screenshots/movecontents.png differ diff --git a/Blockchain/screenshots/npmsample.png b/Blockchain/screenshots/npmsample.png new file mode 100644 index 0000000..d8c1610 Binary files /dev/null and b/Blockchain/screenshots/npmsample.png differ diff --git a/Blockchain/screenshots/repositorycreate.png b/Blockchain/screenshots/repositorycreate.png new file mode 100644 index 0000000..d7e12c2 Binary files /dev/null and b/Blockchain/screenshots/repositorycreate.png differ diff --git a/Blockchain/screenshots/restserverdetails.png b/Blockchain/screenshots/restserverdetails.png new file mode 100644 index 0000000..b08f655 Binary files /dev/null and b/Blockchain/screenshots/restserverdetails.png differ diff --git a/Blockchain/screenshots/savebna.png b/Blockchain/screenshots/savebna.png new file mode 100644 index 0000000..a71a9d3 Binary files /dev/null and b/Blockchain/screenshots/savebna.png differ diff --git a/Blockchain/screenshots/starterkittoolchain.png b/Blockchain/screenshots/starterkittoolchain.png new file mode 100644 index 0000000..db63d1f Binary files /dev/null and b/Blockchain/screenshots/starterkittoolchain.png differ diff --git a/Blockchain/screenshots/stopanddeleteapp.png b/Blockchain/screenshots/stopanddeleteapp.png new file mode 100644 index 0000000..64bfc4c Binary files /dev/null and b/Blockchain/screenshots/stopanddeleteapp.png differ diff --git a/Blockchain/screenshots/toolchainlog.png b/Blockchain/screenshots/toolchainlog.png new file mode 100644 index 0000000..108f94a Binary files /dev/null and b/Blockchain/screenshots/toolchainlog.png differ diff --git a/Blockchain/screenshots/webplayground.png b/Blockchain/screenshots/webplayground.png new file mode 100644 index 0000000..c5d6086 Binary files /dev/null and b/Blockchain/screenshots/webplayground.png differ diff --git a/Blockchain/screenshots/yo.png b/Blockchain/screenshots/yo.png new file mode 100644 index 0000000..6262b8c Binary files /dev/null and b/Blockchain/screenshots/yo.png differ diff --git a/Node-RED/SIMULATOR.md b/Node-RED/SIMULATOR.md new file mode 100644 index 0000000..ee70cf9 --- /dev/null +++ b/Node-RED/SIMULATOR.md @@ -0,0 +1,71 @@ +# Route Simulator for the Blockchain IoT Asset Tracker + +## Introduction + +If you have not purchased a Particle Electron but are interested in completing +the [IoT Asset Tracking using Hyperledger Blockchain IBM Code Pattern](https://developer.ibm.com/code/patterns/develop-an-iot-asset-tracking-app-using-blockchain/), you can +use the instructions on this page to create a simulated route and generate +some temperature transactions that will be written to the +IoT Asset Tracker Blockchain history. + +This Node-RED flow replaces the physical Particle Electron. You can +optionally use the technique described below to create your own route and +temperature event thresholds. + +## Use Case - Simulated Bicycle Ride through New York City Central Park +In the below Node-RED flow, the simulator plots a course around Central Park +New York City. The story might be that you want to use the IoT Asset Tracker +to track a bicycle ride through the park on a nice day. The rough outline is to generate the GPS coordinates, fake timestamps, fake temperature, fake vibration data then play it all into your Blockchain transaction history. + +You can create your own use case stories with simulated routes / simulated data and then play that data into the Blockchain. + +The next section describes the general technique of how you can build your own unique route. If you want to skip creating your own route, jump straight to the subsequent section to import the Bicycle ride through New York Central Park simulated route. + +### General Technique - Build your own unique route +- Visit the [OnTheGoMap website](https://onthegomap.com/#/create) that allows you to plot a route on a world map. +- Create your route **(1)** using [OnTheGoMap](https://onthegomap.com/#/create) +- Click on the **Menu** in the upper right corner **(2)** +- Select **Export as GPX (3)** +- **Save** the file to your local system. +![OnTheGoMap Route](screenshots/onthegomap-route.png) +- **Inspect** this xml file. Depending on the length of your route, it will likely contain thousands of geocode waypoints. +- That is way too much accuracy, you don't really want to load thousands of geolocation transactions into the Blockchain. You probably only need a few hundred for demo purposes. +- The Node-RED dashboard that you will build in the final section of the workshop advances the little icon at one geolocation transaction per second. No one wants to watch your demo truck icon creep along a route for dozens of minutes to complete. Slice the data down to maybe 2-3 minutes per route. Determine the appropriate modulo to prune the data. Unix is awesome for this and there are several command line tools that can help you slice the data: +``` +$ awk '0 == NR % 14'  onthegomap-6.4-mi-route-route.gps +$ sed -n '0-14p'   onthegomap-6.4-mi-route-route.gps +``` +- Now, we can load those abbreviated geolocation coordinates into the blockchain. + +## Node-RED Simulated Route flow + +- Copy the code from the GitHub link below into your Clipboard and import it into your Node-RED editor. + +Get the Code [Simulated Route Node-RED flow for IoT Asset Tracker](flows/IoTAssetTracker-SimulatedRoute.json) + +![Simulated Route flow](screenshots/Node-RED-flow-SimulateRoute.png) + +- Wire the **Link** node **(3)** on this flow to the Blockchain REST API flow **New Tempeature Reading** link node +- Deploy the flow +- Press the **One Time Setup to create the Blockchain Bicycle Shipment** inject (true) node. **(1)** +- The one time setup is required to create the shipment asset +- Either accept the default NYC Central Park route or insert your custom route into the **Paste GPX file into this Template Node** **(2)** +- Last, press the **Inject** true button **(4)**. +- The simulated route geolocation / temperature readings will start to play into your Blockchain transaction history. The rate limit node will slow it down so that transactions are successfully written to the blockchain. + +## Node-RED Dashboard Asset Tracking +- Turn to the **IoT Asset Dashboard** flow +- Double click on the **Asset IDs to be Tracked** function node **(1)** +- Add the following **(2)** to the msg.options array +``` +{"Bicycle #1":"34304"}, +``` +- Deploy the flow + +![Node-RED flow AssetTrackerDashboardControls fixup](screenshots/Node-RED-flow-AssetTrackerDashboardControls-fixup.png) + +## Node-RED Dashboard +- Launch the Node-RED dashboard +- Select **Bicycle #1** from the **Select Truck Route** dropdown. +- Turn on the **Track Truck Route** switch +![Node-RED Dashboard Central Park Route](screenshots/Node-RED-dashboard-AssetTracker-NYC.png) diff --git a/Node-RED/flows/IoTAssetTracker-SimulatedRoute.json b/Node-RED/flows/IoTAssetTracker-SimulatedRoute.json new file mode 100644 index 0000000..ffe1caa --- /dev/null +++ b/Node-RED/flows/IoTAssetTracker-SimulatedRoute.json @@ -0,0 +1,290 @@ +[ + { + "id": "24aab329.a0d324", + "type": "tab", + "label": "Simulated Route", + "disabled": false, + "info": "" + }, + { + "id": "40d7609d.85a22", + "type": "inject", + "z": "24aab329.a0d324", + "name": "", + "topic": "", + "payload": "true", + "payloadType": "bool", + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "x": 130, + "y": 400, + "wires": [ + [ + "7c8d6acb.b9d81c" + ] + ] + }, + { + "id": "7c8d6acb.b9d81c", + "type": "template", + "z": "24aab329.a0d324", + "name": "Paste GPX file into this Template node", + "field": "payload", + "fieldType": "msg", + "format": "handlebars", + "syntax": "plain", + "template": "\n\n \n 6.43 mi route\n On The Go Map\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", + "output": "str", + "x": 370, + "y": 400, + "wires": [ + [ + "39b8d718.876a7" + ] + ] + }, + { + "id": "eac5bef1.7dfc9", + "type": "debug", + "z": "24aab329.a0d324", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "x": 630, + "y": 540, + "wires": [] + }, + { + "id": "8b794514.171258", + "type": "comment", + "z": "24aab329.a0d324", + "name": "#1 - Visit https://onthegomap.com to map a simulated course", + "info": "", + "x": 440, + "y": 240, + "wires": [] + }, + { + "id": "b663982e.2d6258", + "type": "comment", + "z": "24aab329.a0d324", + "name": "#2 - Export route to a GPX file", + "info": "After plotting an interesting route,\nclick on the menu in the upper right corner \nof the https://onthegomap.com/#/create\nSelect \"Export as GPX\"\nSave as a text file\n\nYou might want to open the txt file and inspect\nthe lat / lon geocoordinates.\n\nIf your route is many thousands of waypoint entries,\nyou will fill a very big blockchain transaction\nhistory. Keep the route to < 500 waypoints", + "x": 340, + "y": 280, + "wires": [] + }, + { + "id": "f5ef19a5.8ae7b", + "type": "comment", + "z": "24aab329.a0d324", + "name": "#3 - Paste the entire GPX text file into the Template node below", + "info": "", + "x": 450, + "y": 320, + "wires": [] + }, + { + "id": "39b8d718.876a7", + "type": "function", + "z": "24aab329.a0d324", + "name": "Extract Route", + "func": "var waypoints = msg.payload.split(/\\r?\\n/) ;\n// the GPX file will contain many\n// \"\n\ngeocoordinates = waypoints.filter(path => path.match(/rtept/));\nvar route = \"\";\n\n//var lat, lon;\n//var geo = [];\n\nfor( x=0; x< geocoordinates.length; x++ ) {\n fields = geocoordinates[x].split('\"');\n// lat = parseFloat(fields[1]);\n// lon = parseFloat(fields[3]);\n// geo.push({lat,lon});\n route = route + fields[1] + \",\"+ fields[3] + \"\\n\";\n}\n//msg.payload = geo; // Array of geocoords\n\n// Send a big string to the CSV node so that\n// the CSV node splits each geocoord into an individual msg\nmsg.payload = route;\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "x": 660, + "y": 400, + "wires": [ + [ + "5b1d8ecb.804d" + ] + ] + }, + { + "id": "5b1d8ecb.804d", + "type": "csv", + "z": "24aab329.a0d324", + "name": "Split Route", + "sep": ",", + "hdrin": "", + "hdrout": "", + "multi": "one", + "ret": "\\n", + "temp": "lat,lon", + "skip": "0", + "x": 170, + "y": 500, + "wires": [ + [ + "a822eff2.4412c8" + ] + ] + }, + { + "id": "d89e55f8.3b9768", + "type": "function", + "z": "24aab329.a0d324", + "name": "Simulate a Blockchain Temperature Transaction", + "func": "var now = Date.now();\nvar d = new Date(now);\nvar ts = d.getFullYear() + \"-\" + ('0' + (d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2)+ \"T\" + d.getHours() + \":\" + d.getMinutes() + \":\" + d.getSeconds()+\"Z\";\n\n\nmsg.payload = { \"AssetID\":\"34304\",\n \"timestamp\": ts ,\n \"Temperature\": {\"Celsius\":Math.floor(Math.round(Math.random()*11)+1) },\n \"gps\": {\"lat\":msg.payload.lat.toString(),\"lon\":msg.payload.lon.toString()}};\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "x": 280, + "y": 580, + "wires": [ + [ + "eac5bef1.7dfc9", + "e44c8973.1492e8" + ] + ] + }, + { + "id": "a822eff2.4412c8", + "type": "delay", + "z": "24aab329.a0d324", + "name": "", + "pauseType": "rate", + "timeout": "1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "5", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "x": 380, + "y": 500, + "wires": [ + [ + "d89e55f8.3b9768" + ] + ] + }, + { + "id": "307fb704.7e2078", + "type": "comment", + "z": "24aab329.a0d324", + "name": "This example is a bike route through New York City Central Park", + "info": "", + "x": 450, + "y": 360, + "wires": [] + }, + { + "id": "22ea9728.739a6", + "type": "comment", + "z": "24aab329.a0d324", + "name": "Configure this link node to the \"Blockchain REST API\" flow tab and \"Build a TemperatureReading Transaction\" link node", + "info": "", + "x": 520, + "y": 620, + "wires": [] + }, + { + "id": "e44c8973.1492e8", + "type": "link out", + "z": "24aab329.a0d324", + "name": "", + "links": [ + "ae534d7a.bba95" + ], + "x": 580, + "y": 580, + "wires": [] + }, + { + "id": "3f2b2e52.781ba2", + "type": "debug", + "z": "24aab329.a0d324", + "name": "Blockchain Asset response", + "active": true, + "console": "false", + "complete": "true", + "x": 940, + "y": 160, + "wires": [] + }, + { + "id": "e05835b2.d9e828", + "type": "debug", + "z": "24aab329.a0d324", + "name": "Add Bicycle Asset", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "x": 590, + "y": 120, + "wires": [] + }, + { + "id": "b97ba68b.6aa838", + "type": "http request", + "z": "24aab329.a0d324", + "name": "hyperledger - Create Bicycle Asset", + "method": "POST", + "ret": "obj", + "url": "", + "tls": "", + "x": 640, + "y": 160, + "wires": [ + [ + "3f2b2e52.781ba2" + ] + ] + }, + { + "id": "8201843c.bd7f9", + "type": "comment", + "z": "24aab329.a0d324", + "name": "One Time Setup to create the Blockchain Bicycle Shipment", + "info": "Remember to edit the Blockchain Model chaincode (logic.js) \nIn the setupDemo() function, insert your Particle Device ID\nas the Shipment ID", + "x": 270, + "y": 100, + "wires": [] + }, + { + "id": "92dccf1.dbc19b", + "type": "inject", + "z": "24aab329.a0d324", + "name": "", + "topic": "", + "payload": "true", + "payloadType": "bool", + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "x": 130, + "y": 160, + "wires": [ + [ + "c06feddc.e111" + ] + ] + }, + { + "id": "c06feddc.e111", + "type": "function", + "z": "24aab329.a0d324", + "name": "Create Bicycle Shipment Asset", + "func": "// A Shipment Blockchain transaction looks like this:\n// {\n// \"$class\": \"org.acme.shipping.perishable.Shipment\",\n// \"shipmentId\": \"34304\",\n// \"type\": \"MEDICINE\",\n// \"status\": \"IN_TRANSIT\",\n// \"unitCount\": 100,\n// \"contract\": \"resource:org.acme.shipping.perishable.Contract#CON_002\"\n// }\n\nvar FabricIP=global.get(\"HyperLedgerFabricIP\");\n\nmsg.payload = {\n \"$class\": \"org.acme.shipping.perishable.Shipment\",\n \"shipmentId\": \"34304\",\n \"type\": \"MEDICINE\",\n \"status\": \"IN_TRANSIT\",\n \"unitCount\": 100,\n \"contract\": \"resource:org.acme.shipping.perishable.Contract#CON_002\"\n};\nShipmentMsg = JSON.stringify(msg.payload);\n\nmsg.url = \"http://\"+FabricIP+\"/api/Shipment?data=\"+ShipmentMsg;\nmsg.headers = {\n \"Content-Type\":\"application/json\",\n \"Accept\":\"application/json\"\n};\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "x": 330, + "y": 160, + "wires": [ + [ + "b97ba68b.6aa838", + "e05835b2.d9e828" + ] + ] + } +] diff --git a/Node-RED/screenshots/Node-RED-dashboard-AssetTracker-NYC.png b/Node-RED/screenshots/Node-RED-dashboard-AssetTracker-NYC.png new file mode 100644 index 0000000..db5429d Binary files /dev/null and b/Node-RED/screenshots/Node-RED-dashboard-AssetTracker-NYC.png differ diff --git a/Node-RED/screenshots/Node-RED-flow-AssetTrackerDashboardControls-fixup.png b/Node-RED/screenshots/Node-RED-flow-AssetTrackerDashboardControls-fixup.png new file mode 100644 index 0000000..f9aed89 Binary files /dev/null and b/Node-RED/screenshots/Node-RED-flow-AssetTrackerDashboardControls-fixup.png differ diff --git a/Node-RED/screenshots/Node-RED-flow-SimulateRoute.png b/Node-RED/screenshots/Node-RED-flow-SimulateRoute.png new file mode 100644 index 0000000..59cec42 Binary files /dev/null and b/Node-RED/screenshots/Node-RED-flow-SimulateRoute.png differ diff --git a/Node-RED/screenshots/onthegomap-route.png b/Node-RED/screenshots/onthegomap-route.png new file mode 100644 index 0000000..4ebb7f6 Binary files /dev/null and b/Node-RED/screenshots/onthegomap-route.png differ diff --git a/ParticleElectron/README.md b/ParticleElectron/README.md index 578fbe4..6d55a48 100644 --- a/ParticleElectron/README.md +++ b/ParticleElectron/README.md @@ -25,9 +25,9 @@ The [Particle Electron Asset Tracker v2](https://store.particle.io/products/asse 8. Since I prefer a command line interface over a Web IDE, I installed the [Particle CLI]( https://docs.particle.io/guide/tools-and-features/cli/electron/) by following the guide. ``` $ particle login - $ particle upgrade + $ particle update ``` - The [firmware upgrade](https://docs.particle.io/guide/tools-and-features/firmware-manager/electron/) was important to get the Google Maps geolocation device locator working. My Particle Electron was factory installed with v0.4.9, once I upgraded to v0.6.4, the Google Maps function finally worked. + The [firmware update](https://docs.particle.io/guide/tools-and-features/firmware-manager/electron/) was important to get the Google Maps geolocation device locator working. My Particle Electron was factory installed with v0.4.9, once I upgraded to v0.6.4, the Google Maps function finally worked. 9. The next step was to learn about the [$ particle compile]( https://docs.particle.io/reference/cli/#particle-compile) command ``` @@ -113,7 +113,7 @@ What you really want to do is send that data somewhere else. In my case, I want Before you go, you'll need a Particle token to authorize your Node-RED program to observe / subscribe to these sensor events. ``` $ particle token list -$ particle token new +$ particle token create ``` You can see the data in your terminal ``` diff --git a/README.md b/README.md index 5f0318c..d5f6f9f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +*Read this in other languages: [日本語](README-ja.md).* + # IoT Asset Tracking using a Hyperledger Blockchain ## Introduction @@ -14,3 +16,8 @@ The second [section](Blockchain/README.md) implements a **Perishable Business Ne In the third [section](Node-RED/README.md), the power of **Where, What and When** is best visualized in a dashboard that plots the geo location path, the environmental sensor data and can control triggers and alerts. I use **[Node-RED](https://nodered.org/)** and a Node.js server running in an IBM Cloud hosted Cloud Foundry application to receive the IoT Asset Tracking data and write it to the Hyperledger Fabric using Hyperledger Composer REST APIs. I also use a **Node-RED Dashboard** to plot the shipment on a map. Enjoy! Give me feedback if you have suggestions on how to improve this tutorial. + +## License +This code pattern is licensed under the Apache Software License, Version 2. Separate third party code objects invoked within this code pattern are licensed by their respective providers pursuant to their own separate licenses. Contributions are subject to the Developer [Certificate of Origin, Version 1.1 (“DCO”)] (https://developercertificate.org/) and the [Apache Software License, Version 2]( (http://www.apache.org/licenses/LICENSE-2.0.txt). + +ASL FAQ link: http://www.apache.org/foundation/license-faq.html#WhatDoesItMEAN