├── .DS_Store ├── Blockchain ├── .DS_Store ├── IoT-Perishable-Network │ ├── README.md │ ├── lib │ │ └── logic.js │ ├── logic.js │ ├── models │ │ └── perishable.cto │ ├── package.json │ ├── perishable.cto │ └── permissions.acl ├── README-ja.md ├── README.md ├── iot-asset-tracker-network.bna └── screenshots │ ├── .DS_Store │ ├── API.png │ ├── Authorize.png │ ├── AuthorizeCloud.png │ ├── Breadcrumbs.png │ ├── ConnectNow.png │ ├── Create.png │ ├── DeliveryPipeline.png │ ├── DeployMarbles.png │ ├── DeploymentProgress.png │ ├── DevOps.png │ ├── Guided.png │ ├── MarblesToolchain.png │ ├── MarblesUI.png │ ├── Passed.png │ ├── Perishable-Network-BNA-ConnectNow.png │ ├── Perishable-Network-BNA-Model-update-annotated.png │ ├── Perishable-Network-BNA-annotated.png │ ├── Perishable-Network-BNA-creds-annotated.png │ ├── Perishable-Network-REST-API-swagger.png │ ├── RepoName.png │ ├── SeeApp.png │ ├── SelectGitHub.png │ ├── SetupDemo.png │ ├── SubmitTransaction.png │ ├── Success.png │ ├── Test.png │ ├── ToolChainName.png │ ├── TrySamples.png │ ├── Update.png │ ├── ViewLogs.png │ ├── VisitAppURL.png │ ├── clonegithub.png │ ├── completetoolchain.png │ ├── composer-rest-server.png │ ├── deploynew.png │ ├── deploypassed.png │ ├── developcode.png │ ├── example.png │ ├── export.png │ ├── gitcommit.png │ ├── gotogithub.png │ ├── launchnow.png │ ├── menubar.png │ ├── movecontents.png │ ├── npmsample.png │ ├── repositorycreate.png │ ├── restserverdetails.png │ ├── savebna.png │ ├── starterkittoolchain.png │ ├── toolchainlog.png │ ├── webplayground.png │ └── yo.png ├── LICENSE ├── Node-RED ├── README-ja.md ├── README.md ├── flows │ └── IoTAssetTracker-AllFlows.json └── screenshots │ ├── IBMCloud-Catalog-newstarter-annotated.png │ ├── IBMCloud-NodeRED-CFappcreate.png │ ├── IBMCloud-NodeRED-import.png │ ├── IBMCloud-NodeRED-launch.png │ ├── IBMCloud-NodeRED-nodeinstall.png │ ├── IBMCloud-NodeRED-palette.png │ ├── IBMCloud-NodeRED-pastefromclipboard.png │ ├── Node-RED-dashboard-AssetTracker-NJ.png │ ├── Node-RED-dashboard-AssetTracker-PR.png │ ├── Node-RED-dashboard-ControlParticleDevice.png │ ├── Node-RED-flow-AssetTrackerDashboardControls.png │ ├── Node-RED-flow-AssetTrackerMap.png │ ├── Node-RED-flow-ControlParticleDevice.png │ ├── Node-RED-flow-InitPerishableBlockchain.png │ ├── Node-RED-flow-LoadBlockchainTransactionHistory.png │ ├── Node-RED-flow-ReceiveParticleEvents.png │ └── Node-RED-flow-WriteParticleEvents2Blockchain.png ├── ParticleElectron ├── README-ja.md ├── README.md ├── WatsonIoTAssetTracker.ino ├── project.properties └── screenshots │ ├── ParticleConsoleDeviceEvents.png │ ├── ParticleElectronAssetTracker-IoT.jpg │ ├── ParticleElectronAssetTracker-Kit.jpg │ └── ParticleElectronAssetTracker-in-Case.jpg ├── README-ja.md ├── README.md └── Workshop ├── README-ja.md └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/.DS_Store -------------------------------------------------------------------------------- /Blockchain/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/.DS_Store -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/README.md: -------------------------------------------------------------------------------- 1 | # IoT Asset Tracking Perishable Goods Network 2 | 3 | > Example business network that shows growers, shippers and importers defining contracts for the price of perishable goods, based on temperature readings from IoT sensors in the shipping containers. 4 | 5 | The business network defines a contract between growers and importers. The contract stipulates that: On receipt of the shipment the importer pays the grower the unit price x the number of units in the shipment. Shipments that arrive late are free. Shipments that have breached the low temperate threshold have a penalty applied proportional to the magnitude of the breach x a penalty factor. Shipments that have breached the high temperate threshold have a penalty applied proportional to the magnitude of the breach x a penalty factor. 6 | 7 | This business network defines: 8 | 9 | **Participants** 10 | `Grower` `Importer` `Shipper` 11 | 12 | **Assets** 13 | `Contract` `Shipment` 14 | 15 | **Transactions** 16 | `TemperatureReading``AccelReading` `GpsReading` `ShipmentReceived` `SetupDemo` 17 | 18 | **Events** 19 | `TemperatureThresholdEvent` `AccelerationThresholdEvent` `ShipmentInPortEvent` 20 | 21 | To test this Business Network Definition in the **Test** tab: 22 | 23 | Submit a `SetupDemo` transaction: 24 | 25 | ``` 26 | { 27 | "$class": "org.acme.shipping.perishable.SetupDemo" 28 | } 29 | ``` 30 | 31 | This transaction populates the Participant Registries with a `Grower`, an `Importer` and a `Shipper`. The Asset Registries will have a `Contract` asset and a `Shipment` asset. 32 | 33 | Submit a `TemperatureReading` transaction: 34 | 35 | ``` 36 | { 37 | "$class": "org.acme.shipping.perishable.TemperatureReading", 38 | "celsius": 8, 39 | "latitude": "40.6840", 40 | "longitude":"74.0062", 41 | "readingTime": "2018-03-22T17:31:36.229Z", 42 | "shipment": "resource:org.acme.shipping.perishable.Shipment#SHIP_001" 43 | } 44 | ``` 45 | 46 | If the temperature reading falls outside the min/max range of the contract, the price received by the grower will be reduced, and a `TemperatureThresholdEvent` is emitted. You may submit several readings if you wish. Each reading will be aggregated within `SHIP_001` Shipment Asset Registry. 47 | 48 | Submit a `AccelReading` transaction: 49 | 50 | ``` 51 | { 52 | "$class": "org.acme.shipping.perishable.AccelReading", 53 | "accel_x": -96, 54 | "accel_y": 18368, 55 | "accel_z": -12032, 56 | "latitude": "40.6840", 57 | "longitude":"74.0062", 58 | "readingTime": "2018-03-22T17:31:36.229Z", 59 | "shipment": "resource:org.acme.shipping.perishable.Shipment#SHIP_001" 60 | } 61 | ``` 62 | 63 | If the acceleration reading falls outside the min/max range of the contract, the price received by the grower will be reduced, and a `AccelerationThresholdEvent` is emitted. You may submit several readings if you wish. Each reading will be aggregated within `SHIP_001` Shipment Asset Registry. 64 | 65 | Submit a `ShipmentReceived` transaction for `SHIP_001` to trigger the payout to the grower, based on the parameters of the `CON_001` contract: 66 | 67 | ``` 68 | { 69 | "$class": "org.acme.shipping.perishable.ShipmentReceived", 70 | "shipment": "resource:org.acme.shipping.perishable.Shipment#SHIP_001" 71 | } 72 | ``` 73 | 74 | If the date-time of the `ShipmentReceived` transaction is after the `arrivalDateTime` on `CON_001` then the grower will no receive any payment for the shipment. 75 | 76 | Submit a `GpsReading` transaction: 77 | 78 | ``` 79 | { 80 | "$class": "org.acme.shipping.perishable.GpsReading", 81 | "readingTime": "120000", 82 | "readingDate": "20171024", 83 | "latitude":"40.6840", 84 | "latitudeDir":"N", 85 | "longitude":"74.0062", 86 | "laongitudeDir":"W", 87 | } 88 | ``` 89 | 90 | If the GPS reading indicates the ship's location is the Port of New Jersey/New York (40.6840,-74.0062) then a `ShipmentInPortEvent` is emitted. 91 | 92 | Enjoy! 93 | -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/lib/logic.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /** 16 | * A shipment has been received by an importer 17 | * @param {org.acme.shipping.perishable.ShipmentReceived} shipmentReceived - the ShipmentReceived transaction 18 | * @transaction 19 | */ 20 | function payOut(shipmentReceived) { 21 | 22 | var contract = shipmentReceived.shipment.contract; 23 | var shipment = shipmentReceived.shipment; 24 | var payOut = contract.unitPrice * shipment.unitCount; 25 | 26 | //console.log('Received at: ' + shipmentReceived.timestamp); 27 | //console.log('Contract arrivalDateTime: ' + contract.arrivalDateTime); 28 | 29 | // set the status of the shipment 30 | shipment.status = 'ARRIVED'; 31 | 32 | // if the shipment did not arrive on time the payout is zero 33 | if (shipmentReceived.timestamp > contract.arrivalDateTime) { 34 | payOut = 0; 35 | //console.log('Late shipment'); 36 | } else { 37 | // find the lowest temperature reading 38 | if (shipment.temperatureReadings) { 39 | // sort the temperatureReadings by celsius 40 | shipment.temperatureReadings.sort(function (a, b) { 41 | return (a.celsius - b.celsius); 42 | }); 43 | var lowestReading = shipment.temperatureReadings[0]; 44 | var highestReading = shipment.temperatureReadings[shipment.temperatureReadings.length - 1]; 45 | var penalty = 0; 46 | //console.log('Lowest temp reading: ' + lowestReading.celsius); 47 | //console.log('Highest temp reading: ' + highestReading.celsius); 48 | 49 | // does the lowest temperature violate the contract? 50 | if (lowestReading.celsius < contract.minTemperature) { 51 | penalty += (contract.minTemperature - lowestReading.celsius) * contract.minPenaltyFactor; 52 | //console.log('Min temp penalty: ' + penalty); 53 | } 54 | 55 | // does the highest temperature violate the contract? 56 | if (highestReading.celsius > contract.maxTemperature) { 57 | penalty += (highestReading.celsius - contract.maxTemperature) * contract.maxPenaltyFactor; 58 | //console.log('Max temp penalty: ' + penalty); 59 | } 60 | 61 | // apply any penalities 62 | payOut -= (penalty * shipment.unitCount); 63 | 64 | if (payOut < 0) { 65 | payOut = 0; 66 | } 67 | } 68 | } 69 | 70 | //console.log('Payout: ' + payOut); 71 | contract.grower.accountBalance += payOut; 72 | contract.importer.accountBalance -= payOut; 73 | 74 | //console.log('Grower: ' + contract.grower.$identifier + ' new balance: ' + contract.grower.accountBalance); 75 | //console.log('Importer: ' + contract.importer.$identifier + ' new balance: ' + contract.importer.accountBalance); 76 | 77 | return getParticipantRegistry('org.acme.shipping.perishable.Grower') 78 | .then(function (growerRegistry) { 79 | // update the grower's balance 80 | return growerRegistry.update(contract.grower); 81 | }) 82 | .then(function () { 83 | return getParticipantRegistry('org.acme.shipping.perishable.Importer'); 84 | }) 85 | .then(function (importerRegistry) { 86 | // update the importer's balance 87 | return importerRegistry.update(contract.importer); 88 | }) 89 | .then(function () { 90 | return getAssetRegistry('org.acme.shipping.perishable.Shipment'); 91 | }) 92 | .then(function (shipmentRegistry) { 93 | // update the state of the shipment 94 | return shipmentRegistry.update(shipment); 95 | }); 96 | } 97 | 98 | /** 99 | * A temperature reading has been received for a shipment 100 | * @param {org.acme.shipping.perishable.TemperatureReading} temperatureReading - the TemperatureReading transaction 101 | * @transaction 102 | */ 103 | function temperatureReading(temperatureReading) { 104 | 105 | var shipment = temperatureReading.shipment; 106 | var NS = 'org.acme.shipping.perishable'; 107 | var contract = shipment.contract; 108 | var factory = getFactory(); 109 | 110 | //console.log('Adding temperature ' + temperatureReading.celsius + ' to shipment ' + shipment.$identifier); 111 | 112 | if (shipment.temperatureReadings) { 113 | shipment.temperatureReadings.push(temperatureReading); 114 | } else { 115 | shipment.temperatureReadings = [temperatureReading]; 116 | } 117 | 118 | if (temperatureReading.celsius < contract.minTemperature || 119 | temperatureReading.celsius > contract.maxTemperature) { 120 | var temperatureEvent = factory.newEvent(NS, 'TemperatureThresholdEvent'); 121 | temperatureEvent.shipment = shipment; 122 | temperatureEvent.temperature = temperatureReading.celsius; 123 | temperatureEvent.latitude = temperatureReading.latitude; 124 | temperatureEvent.longitude = temperatureReading.longitude; 125 | temperatureEvent.readingTime = temperatureReading.readingTime; 126 | temperatureEvent.message = 'Temperature threshold violated! Emitting TemperatureEvent for shipment: ' + shipment.$identifier; 127 | emit(temperatureEvent); 128 | } 129 | 130 | return getAssetRegistry(NS + '.Shipment') 131 | .then(function (shipmentRegistry) { 132 | // add the temp reading to the shipment 133 | return shipmentRegistry.update(shipment); 134 | }); 135 | } 136 | 137 | /** 138 | * An Acceleration reading has been received for a shipment 139 | * @param {org.acme.shipping.perishable.AccelReading} AccelReading - the AccelReading transaction 140 | * @transaction 141 | */ 142 | function AccelReading(AccelReading) { 143 | var shipment = AccelReading.shipment; 144 | var NS = 'org.acme.shipping.perishable'; 145 | var contract = shipment.contract; 146 | var factory = getFactory(); 147 | 148 | //console.log('Adding acceleration ' + AccelReading.accel_x + ' to shipment ' + shipment.$identifier); 149 | 150 | if (shipment.AccelReadings) { 151 | shipment.AccelReadings.push(AccelReading); 152 | } else { 153 | shipment.AccelReadings = [AccelReading]; 154 | } 155 | 156 | // Also test for accel_y / accel_z 157 | if (AccelReading.accel_x < contract.maxAccel ) { 158 | var AccelerationEvent = factory.newEvent(NS, 'AccelerationThresholdEvent'); 159 | AccelerationEvent.shipment = shipment; 160 | AccelerationEvent.accel_x = AccelReading.accel_x; 161 | AccelerationEvent.accel_y = AccelReading.accel_y; 162 | AccelerationEvent.accel_z = AccelReading.accel_z; 163 | AccelerationEvent.latitude = AccelReading.latitude; 164 | AccelerationEvent.longitude = AccelReading.longitude; 165 | AccelerationEvent.readingTime = AccelReading.readingTime; 166 | AccelerationEvent.message = 'Acceleration threshold violated! Emitting AccelerationEvent for shipment: ' + shipment.$identifier; 167 | emit(AccelerationEvent); 168 | } 169 | 170 | return getAssetRegistry(NS + '.Shipment') 171 | .then(function (shipmentRegistry) { 172 | // add the temp reading to the shipment 173 | return shipmentRegistry.update(shipment); 174 | }); 175 | } 176 | 177 | /** 178 | * A GPS reading has been received for a shipment 179 | * @param {org.acme.shipping.perishable.GpsReading} gpsReading - the GpsReading transaction 180 | * @transaction 181 | */ 182 | function gpsReading(gpsReading) { 183 | 184 | var factory = getFactory(); 185 | var NS = "org.acme.shipping.perishable"; 186 | var shipment = gpsReading.shipment; 187 | var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W'; 188 | 189 | if (shipment.gpsReadings) { 190 | shipment.gpsReadings.push(gpsReading); 191 | } else { 192 | shipment.gpsReadings = [gpsReading]; 193 | } 194 | 195 | var latLong = '/LAT:' + gpsReading.latitude + gpsReading.latitudeDir + '/LONG:' + 196 | gpsReading.longitude + gpsReading.longitudeDir; 197 | 198 | if (latLong == PORT_OF_NEW_YORK) { 199 | var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent'); 200 | shipmentInPortEvent.shipment = shipment; 201 | var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK; 202 | shipmentInPortEvent.message = message; 203 | emit(shipmentInPortEvent); 204 | } 205 | 206 | return getAssetRegistry(NS + '.Shipment') 207 | .then(function (shipmentRegistry) { 208 | // add the temp reading to the shipment 209 | return shipmentRegistry.update(shipment); 210 | }); 211 | } 212 | 213 | /** 214 | * Initialize some test assets and participants useful for running a demo. 215 | * @param {org.acme.shipping.perishable.SetupDemo} setupDemo - the SetupDemo transaction 216 | * @transaction 217 | */ 218 | function setupDemo(setupDemo) { 219 | 220 | var factory = getFactory(); 221 | var NS = 'org.acme.shipping.perishable'; 222 | 223 | // create the grower 224 | var grower = factory.newResource(NS, 'Grower', 'farmer@email.com'); 225 | var growerAddress = factory.newConcept(NS, 'Address'); 226 | growerAddress.country = 'USA'; 227 | grower.address = growerAddress; 228 | grower.accountBalance = 0; 229 | 230 | // create the importer 231 | var importer = factory.newResource(NS, 'Importer', 'supermarket@email.com'); 232 | var importerAddress = factory.newConcept(NS, 'Address'); 233 | importerAddress.country = 'UK'; 234 | importer.address = importerAddress; 235 | importer.accountBalance = 0; 236 | 237 | // create the shipper 238 | var shipper = factory.newResource(NS, 'Shipper', 'shipper@email.com'); 239 | var shipperAddress = factory.newConcept(NS, 'Address'); 240 | shipperAddress.country = 'Panama'; 241 | shipper.address = shipperAddress; 242 | shipper.accountBalance = 0; 243 | 244 | // create the contract 245 | var contract = factory.newResource(NS, 'Contract', 'CON_002'); 246 | contract.grower = factory.newRelationship(NS, 'Grower', 'farmer@email.com'); 247 | contract.importer = factory.newRelationship(NS, 'Importer', 'supermarket@email.com'); 248 | contract.shipper = factory.newRelationship(NS, 'Shipper', 'shipper@email.com'); 249 | var tomorrow = setupDemo.timestamp; 250 | tomorrow.setDate(tomorrow.getDate() + 1); 251 | contract.arrivalDateTime = tomorrow; // the shipment has to arrive tomorrow 252 | contract.unitPrice = 0.5; // pay 50 cents per unit 253 | contract.minTemperature = 2; // min temperature for the cargo 254 | contract.maxTemperature = 10; // max temperature for the cargo 255 | contract.maxAccel = 15000; // max acceleration for the cargo 256 | contract.minPenaltyFactor = 0.2; // we reduce the price by 20 cents for every degree below the min temp 257 | contract.maxPenaltyFactor = 0.1; // we reduce the price by 10 cents for every degree above the max temp 258 | 259 | // create the shipment 260 | var shipment = factory.newResource(NS, 'Shipment', '320022000251363131363432'); 261 | shipment.type = 'MEDICINE'; 262 | shipment.status = 'IN_TRANSIT'; 263 | shipment.unitCount = 5000; 264 | shipment.contract = factory.newRelationship(NS, 'Contract', 'CON_002'); 265 | return getParticipantRegistry(NS + '.Grower') 266 | .then(function (growerRegistry) { 267 | // add the growers 268 | return growerRegistry.addAll([grower]); 269 | }) 270 | .then(function() { 271 | return getParticipantRegistry(NS + '.Importer'); 272 | }) 273 | .then(function(importerRegistry) { 274 | // add the importers 275 | return importerRegistry.addAll([importer]); 276 | }) 277 | .then(function() { 278 | return getParticipantRegistry(NS + '.Shipper'); 279 | }) 280 | .then(function(shipperRegistry) { 281 | // add the shippers 282 | return shipperRegistry.addAll([shipper]); 283 | }) 284 | .then(function() { 285 | return getAssetRegistry(NS + '.Contract'); 286 | }) 287 | .then(function(contractRegistry) { 288 | // add the contracts 289 | return contractRegistry.addAll([contract]); 290 | }) 291 | .then(function() { 292 | return getAssetRegistry(NS + '.Shipment'); 293 | }) 294 | .then(function(shipmentRegistry) { 295 | // add the shipments 296 | return shipmentRegistry.addAll([shipment]); 297 | }); 298 | } -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/logic.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /** 16 | * A shipment has been received by an importer 17 | * @param {org.acme.shipping.perishable.ShipmentReceived} shipmentReceived - the ShipmentReceived transaction 18 | * @transaction 19 | */ 20 | function payOut(shipmentReceived) { 21 | 22 | var contract = shipmentReceived.shipment.contract; 23 | var shipment = shipmentReceived.shipment; 24 | var payOut = contract.unitPrice * shipment.unitCount; 25 | 26 | //console.log('Received at: ' + shipmentReceived.timestamp); 27 | //console.log('Contract arrivalDateTime: ' + contract.arrivalDateTime); 28 | 29 | // set the status of the shipment 30 | shipment.status = 'ARRIVED'; 31 | 32 | // if the shipment did not arrive on time the payout is zero 33 | if (shipmentReceived.timestamp > contract.arrivalDateTime) { 34 | payOut = 0; 35 | //console.log('Late shipment'); 36 | } else { 37 | // find the lowest temperature reading 38 | if (shipment.temperatureReadings) { 39 | // sort the temperatureReadings by celsius 40 | shipment.temperatureReadings.sort(function (a, b) { 41 | return (a.celsius - b.celsius); 42 | }); 43 | var lowestReading = shipment.temperatureReadings[0]; 44 | var highestReading = shipment.temperatureReadings[shipment.temperatureReadings.length - 1]; 45 | var penalty = 0; 46 | //console.log('Lowest temp reading: ' + lowestReading.celsius); 47 | //console.log('Highest temp reading: ' + highestReading.celsius); 48 | 49 | // does the lowest temperature violate the contract? 50 | if (lowestReading.celsius < contract.minTemperature) { 51 | penalty += (contract.minTemperature - lowestReading.celsius) * contract.minPenaltyFactor; 52 | //console.log('Min temp penalty: ' + penalty); 53 | } 54 | 55 | // does the highest temperature violate the contract? 56 | if (highestReading.celsius > contract.maxTemperature) { 57 | penalty += (highestReading.celsius - contract.maxTemperature) * contract.maxPenaltyFactor; 58 | //console.log('Max temp penalty: ' + penalty); 59 | } 60 | 61 | // apply any penalities 62 | payOut -= (penalty * shipment.unitCount); 63 | 64 | if (payOut < 0) { 65 | payOut = 0; 66 | } 67 | } 68 | } 69 | 70 | //console.log('Payout: ' + payOut); 71 | contract.grower.accountBalance += payOut; 72 | contract.importer.accountBalance -= payOut; 73 | 74 | //console.log('Grower: ' + contract.grower.$identifier + ' new balance: ' + contract.grower.accountBalance); 75 | //console.log('Importer: ' + contract.importer.$identifier + ' new balance: ' + contract.importer.accountBalance); 76 | 77 | return getParticipantRegistry('org.acme.shipping.perishable.Grower') 78 | .then(function (growerRegistry) { 79 | // update the grower's balance 80 | return growerRegistry.update(contract.grower); 81 | }) 82 | .then(function () { 83 | return getParticipantRegistry('org.acme.shipping.perishable.Importer'); 84 | }) 85 | .then(function (importerRegistry) { 86 | // update the importer's balance 87 | return importerRegistry.update(contract.importer); 88 | }) 89 | .then(function () { 90 | return getAssetRegistry('org.acme.shipping.perishable.Shipment'); 91 | }) 92 | .then(function (shipmentRegistry) { 93 | // update the state of the shipment 94 | return shipmentRegistry.update(shipment); 95 | }); 96 | } 97 | 98 | /** 99 | * A temperature reading has been received for a shipment 100 | * @param {org.acme.shipping.perishable.TemperatureReading} temperatureReading - the TemperatureReading transaction 101 | * @transaction 102 | */ 103 | function temperatureReading(temperatureReading) { 104 | 105 | var shipment = temperatureReading.shipment; 106 | var NS = 'org.acme.shipping.perishable'; 107 | var contract = shipment.contract; 108 | var factory = getFactory(); 109 | 110 | //console.log('Adding temperature ' + temperatureReading.celsius + ' to shipment ' + shipment.$identifier); 111 | 112 | if (shipment.temperatureReadings) { 113 | shipment.temperatureReadings.push(temperatureReading); 114 | } else { 115 | shipment.temperatureReadings = [temperatureReading]; 116 | } 117 | 118 | if (temperatureReading.celsius < contract.minTemperature || 119 | temperatureReading.celsius > contract.maxTemperature) { 120 | var temperatureEvent = factory.newEvent(NS, 'TemperatureThresholdEvent'); 121 | temperatureEvent.shipment = shipment; 122 | temperatureEvent.temperature = temperatureReading.celsius; 123 | temperatureEvent.latitude = temperatureReading.latitude; 124 | temperatureEvent.longitude = temperatureReading.longitude; 125 | temperatureEvent.readingTime = temperatureReading.readingTime; 126 | temperatureEvent.message = 'Temperature threshold violated! Emitting TemperatureEvent for shipment: ' + shipment.$identifier; 127 | emit(temperatureEvent); 128 | } 129 | 130 | return getAssetRegistry(NS + '.Shipment') 131 | .then(function (shipmentRegistry) { 132 | // add the temp reading to the shipment 133 | return shipmentRegistry.update(shipment); 134 | }); 135 | } 136 | 137 | /** 138 | * An Acceleration reading has been received for a shipment 139 | * @param {org.acme.shipping.perishable.AccelReading} AccelReading - the AccelReading transaction 140 | * @transaction 141 | */ 142 | function AccelReading(AccelReading) { 143 | var shipment = AccelReading.shipment; 144 | var NS = 'org.acme.shipping.perishable'; 145 | var contract = shipment.contract; 146 | var factory = getFactory(); 147 | 148 | //console.log('Adding acceleration ' + AccelReading.accel_x + ' to shipment ' + shipment.$identifier); 149 | 150 | if (shipment.AccelReadings) { 151 | shipment.AccelReadings.push(AccelReading); 152 | } else { 153 | shipment.AccelReadings = [AccelReading]; 154 | } 155 | 156 | // Also test for accel_y / accel_z 157 | if (AccelReading.accel_x < contract.maxAccel ) { 158 | var AccelerationEvent = factory.newEvent(NS, 'AccelerationThresholdEvent'); 159 | AccelerationEvent.shipment = shipment; 160 | AccelerationEvent.accel_x = AccelReading.accel_x; 161 | AccelerationEvent.accel_y = AccelReading.accel_y; 162 | AccelerationEvent.accel_z = AccelReading.accel_z; 163 | AccelerationEvent.latitude = AccelReading.latitude; 164 | AccelerationEvent.longitude = AccelReading.longitude; 165 | AccelerationEvent.readingTime = AccelReading.readingTime; 166 | AccelerationEvent.message = 'Acceleration threshold violated! Emitting AccelerationEvent for shipment: ' + shipment.$identifier; 167 | emit(AccelerationEvent); 168 | } 169 | 170 | return getAssetRegistry(NS + '.Shipment') 171 | .then(function (shipmentRegistry) { 172 | // add the temp reading to the shipment 173 | return shipmentRegistry.update(shipment); 174 | }); 175 | } 176 | 177 | /** 178 | * A GPS reading has been received for a shipment 179 | * @param {org.acme.shipping.perishable.GpsReading} gpsReading - the GpsReading transaction 180 | * @transaction 181 | */ 182 | function gpsReading(gpsReading) { 183 | 184 | var factory = getFactory(); 185 | var NS = "org.acme.shipping.perishable"; 186 | var shipment = gpsReading.shipment; 187 | var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W'; 188 | 189 | if (shipment.gpsReadings) { 190 | shipment.gpsReadings.push(gpsReading); 191 | } else { 192 | shipment.gpsReadings = [gpsReading]; 193 | } 194 | 195 | var latLong = '/LAT:' + gpsReading.latitude + gpsReading.latitudeDir + '/LONG:' + 196 | gpsReading.longitude + gpsReading.longitudeDir; 197 | 198 | if (latLong == PORT_OF_NEW_YORK) { 199 | var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent'); 200 | shipmentInPortEvent.shipment = shipment; 201 | var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK; 202 | shipmentInPortEvent.message = message; 203 | emit(shipmentInPortEvent); 204 | } 205 | 206 | return getAssetRegistry(NS + '.Shipment') 207 | .then(function (shipmentRegistry) { 208 | // add the temp reading to the shipment 209 | return shipmentRegistry.update(shipment); 210 | }); 211 | } 212 | 213 | /** 214 | * Initialize some test assets and participants useful for running a demo. 215 | * @param {org.acme.shipping.perishable.SetupDemo} setupDemo - the SetupDemo transaction 216 | * @transaction 217 | */ 218 | function setupDemo(setupDemo) { 219 | 220 | var factory = getFactory(); 221 | var NS = 'org.acme.shipping.perishable'; 222 | 223 | // create the grower 224 | var grower = factory.newResource(NS, 'Grower', 'farmer@email.com'); 225 | var growerAddress = factory.newConcept(NS, 'Address'); 226 | growerAddress.country = 'USA'; 227 | grower.address = growerAddress; 228 | grower.accountBalance = 0; 229 | 230 | // create the importer 231 | var importer = factory.newResource(NS, 'Importer', 'supermarket@email.com'); 232 | var importerAddress = factory.newConcept(NS, 'Address'); 233 | importerAddress.country = 'UK'; 234 | importer.address = importerAddress; 235 | importer.accountBalance = 0; 236 | 237 | // create the shipper 238 | var shipper = factory.newResource(NS, 'Shipper', 'shipper@email.com'); 239 | var shipperAddress = factory.newConcept(NS, 'Address'); 240 | shipperAddress.country = 'Panama'; 241 | shipper.address = shipperAddress; 242 | shipper.accountBalance = 0; 243 | 244 | // create the contract 245 | var contract = factory.newResource(NS, 'Contract', 'CON_002'); 246 | contract.grower = factory.newRelationship(NS, 'Grower', 'farmer@email.com'); 247 | contract.importer = factory.newRelationship(NS, 'Importer', 'supermarket@email.com'); 248 | contract.shipper = factory.newRelationship(NS, 'Shipper', 'shipper@email.com'); 249 | var tomorrow = setupDemo.timestamp; 250 | tomorrow.setDate(tomorrow.getDate() + 1); 251 | contract.arrivalDateTime = tomorrow; // the shipment has to arrive tomorrow 252 | contract.unitPrice = 0.5; // pay 50 cents per unit 253 | contract.minTemperature = 2; // min temperature for the cargo 254 | contract.maxTemperature = 10; // max temperature for the cargo 255 | contract.maxAccel = 15000; // max acceleration for the cargo 256 | contract.minPenaltyFactor = 0.2; // we reduce the price by 20 cents for every degree below the min temp 257 | contract.maxPenaltyFactor = 0.1; // we reduce the price by 10 cents for every degree above the max temp 258 | 259 | // create the shipment 260 | var shipment = factory.newResource(NS, 'Shipment', '320022000251363131363432'); 261 | shipment.type = 'MEDICINE'; 262 | shipment.status = 'IN_TRANSIT'; 263 | shipment.unitCount = 5000; 264 | shipment.contract = factory.newRelationship(NS, 'Contract', 'CON_002'); 265 | return getParticipantRegistry(NS + '.Grower') 266 | .then(function (growerRegistry) { 267 | // add the growers 268 | return growerRegistry.addAll([grower]); 269 | }) 270 | .then(function() { 271 | return getParticipantRegistry(NS + '.Importer'); 272 | }) 273 | .then(function(importerRegistry) { 274 | // add the importers 275 | return importerRegistry.addAll([importer]); 276 | }) 277 | .then(function() { 278 | return getParticipantRegistry(NS + '.Shipper'); 279 | }) 280 | .then(function(shipperRegistry) { 281 | // add the shippers 282 | return shipperRegistry.addAll([shipper]); 283 | }) 284 | .then(function() { 285 | return getAssetRegistry(NS + '.Contract'); 286 | }) 287 | .then(function(contractRegistry) { 288 | // add the contracts 289 | return contractRegistry.addAll([contract]); 290 | }) 291 | .then(function() { 292 | return getAssetRegistry(NS + '.Shipment'); 293 | }) 294 | .then(function(shipmentRegistry) { 295 | // add the shipments 296 | return shipmentRegistry.addAll([shipment]); 297 | }); 298 | } 299 | -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/models/perishable.cto: -------------------------------------------------------------------------------- 1 | /** 2 | * A business network for shipping perishable goods 3 | * The cargo is temperature controlled and contracts 4 | * can be negociated based on the temperature 5 | * readings received for the cargo 6 | */ 7 | 8 | namespace org.acme.shipping.perishable 9 | 10 | /** 11 | * The type of perishable product being shipped 12 | */ 13 | enum ProductType { 14 | o BANANAS 15 | o APPLES 16 | o PEARS 17 | o PEACHES 18 | o COFFEE 19 | o MEDICINE 20 | } 21 | 22 | /** 23 | * The status of a shipment 24 | */ 25 | enum ShipmentStatus { 26 | o CREATED 27 | o IN_TRANSIT 28 | o ARRIVED 29 | } 30 | 31 | /** 32 | * Directions of the compass 33 | */ 34 | enum CompassDirection { 35 | 36 | } 37 | 38 | /** 39 | * An abstract transaction that is related to a Shipment 40 | */ 41 | abstract transaction ShipmentTransaction { 42 | --> Shipment shipment 43 | } 44 | 45 | /** 46 | * An Accelerometer reading for a shipment. E.g. received from a 47 | * device within an accelerometer controlled shipping container 48 | * 49 | * The combination of the accelerometer environment reading, 50 | * PLUS the GPS location, PLUS the timestamp is what is interesting 51 | * Just knowing temperature without knowing where or when is 52 | * not sufficient. 53 | */ 54 | transaction AccelReading extends ShipmentTransaction { 55 | 56 | } 57 | 58 | /** 59 | * An temperature reading for a shipment. E.g. received from a 60 | * device within a temperature controlled shipping container 61 | * 62 | * The combination of the temperature environment reading, 63 | * PLUS the GPS location, PLUS the timestamp is what is interesting 64 | * Just knowing temperature without knowing where or when is 65 | * not sufficient. 66 | */ 67 | transaction TemperatureReading extends ShipmentTransaction { 68 | 69 | } 70 | 71 | /** 72 | * A GPS reading for a shipment. E.g. received from a device 73 | * within a shipping container 74 | */ 75 | transaction GpsReading extends ShipmentTransaction { 76 | 77 | } 78 | 79 | /** 80 | * A notification that a shipment has been received by the 81 | * importer and that funds should be transferred from the importer 82 | * to the grower to pay for the shipment. 83 | */ 84 | transaction ShipmentReceived extends ShipmentTransaction { 85 | 86 | } 87 | 88 | /** 89 | * A shipment being tracked as an asset on the ledger 90 | */ 91 | asset Shipment identified by shipmentId { 92 | o String shipmentId 93 | o ProductType type 94 | o ShipmentStatus status 95 | o Long unitCount 96 | --> Contract contract 97 | 98 | } 99 | 100 | /** 101 | * Defines a contract between a Grower and an Importer to ship using 102 | * a Shipper, paying a set unit price. The unit price is multiplied by 103 | * a penality factor proportional to the deviation from the min and max 104 | * negociated temperatures for the shipment. 105 | */ 106 | asset Contract identified by contractId { 107 | o String contractId 108 | --> Grower grower 109 | --> Shipper shipper 110 | --> Importer importer 111 | o DateTime arrivalDateTime 112 | o Double unitPrice 113 | o Double minTemperature 114 | o Double maxTemperature 115 | o Double minPenaltyFactor 116 | o Double maxPenaltyFactor 117 | } 118 | 119 | /** 120 | * A concept for a simple street address 121 | */ 122 | concept Address { 123 | o String city optional 124 | o String country 125 | o String street optional 126 | o String zip optional 127 | } 128 | 129 | /** 130 | * An abstract participant type in this business network 131 | */ 132 | abstract participant Business identified by email { 133 | o String email 134 | o Address address 135 | o Double accountBalance 136 | } 137 | 138 | /** 139 | * A Grower is a type of participant in the network 140 | */ 141 | participant Grower extends Business { 142 | } 143 | 144 | /** 145 | * A Shipper is a type of participant in the network 146 | */ 147 | participant Shipper extends Business { 148 | } 149 | 150 | /** 151 | * An Importer is a type of participant in the network 152 | */ 153 | participant Importer extends Business { 154 | } 155 | 156 | /** 157 | * JUST FOR INITIALIZING A DEMO 158 | */ 159 | transaction SetupDemo { 160 | } 161 | 162 | /** 163 | * An event - when the temperature goes outside the agreed-upon boundaries 164 | */ 165 | event TemperatureThresholdEvent { 166 | 167 | } 168 | 169 | /** 170 | * An event - when the acceleration event has been detected 171 | */ 172 | event AccelerationThresholdEvent { 173 | 174 | } 175 | 176 | /** 177 | * An event - when the ship arrives at the port 178 | */ 179 | event ShipmentInPortEvent { 180 | 181 | } -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "composer": "^0.15.0" 4 | }, 5 | "name": "iot-asset-tracker-network", 6 | "version": "0.1.0", 7 | "description": "IoT Asset Tracker Perishable Goods Business Network", 8 | "scripts": { 9 | "clean": "rm -Rf ./node_modules ./dist ./composer-logs ./out", 10 | "prepublish": "mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/iot-asset-tracker-network.bna", 11 | "pretest": "npm run lint", 12 | "lint": "eslint .", 13 | "postlint": "npm run licchk", 14 | "licchk": "license-check", 15 | "postlicchk": "npm run doc", 16 | "doc": "jsdoc --pedantic --recurse -c jsdoc.json", 17 | "test": "mocha -t 0 --recursive && cucumber-js", 18 | "deploy": "./scripts/deploy.sh" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain.git" 23 | }, 24 | "keywords": [ 25 | "shipping", 26 | "goods", 27 | "perishable", 28 | "asset-tracking", 29 | "asset-tracker", 30 | "composer", 31 | "composer-network", 32 | "iot" 33 | ], 34 | "author": "Hyperledger Composer", 35 | "license": "Apache-2.0", 36 | "devDependencies": { 37 | "browserfs": "^1.2.0", 38 | "chai": "latest", 39 | "chai-as-promised": "latest", 40 | "composer-admin": "^0.19.1", 41 | "composer-cli": "^0.19.1", 42 | "composer-client": "^0.19.1", 43 | "composer-common": "^0.19.1", 44 | "composer-connector-embedded": "^0.19.1", 45 | "composer-cucumber-steps": "^0.19.1", 46 | "cucumber": "^2.2.0", 47 | "eslint": "latest", 48 | "istanbul": "^0.4.5", 49 | "jsdoc": "^3.5.5", 50 | "license-check": "^1.1.5", 51 | "mkdirp": "latest", 52 | "mocha": "latest", 53 | "moment": "^2.17.1", 54 | "nyc": "latest" 55 | }, 56 | "license-check-config": { 57 | "src": [ 58 | "**/*.js", 59 | "!./coverage/**/*", 60 | "!./node_modules/**/*", 61 | "!./out/**/*", 62 | "!./scripts/**/*" 63 | ], 64 | "path": "header.txt", 65 | "blocking": true, 66 | "logInfo": false, 67 | "logError": true 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/perishable.cto: -------------------------------------------------------------------------------- 1 | /** 2 | * A business network for shipping perishable goods 3 | * The cargo is temperature controlled and contracts 4 | * can be negociated based on the temperature 5 | * readings received for the cargo 6 | */ 7 | 8 | namespace org.acme.shipping.perishable 9 | 10 | /** 11 | * The type of perishable product being shipped 12 | */ 13 | enum ProductType { 14 | o BANANAS 15 | o APPLES 16 | o PEARS 17 | o PEACHES 18 | o COFFEE 19 | o MEDICINE 20 | } 21 | 22 | /** 23 | * The status of a shipment 24 | */ 25 | enum ShipmentStatus { 26 | o CREATED 27 | o IN_TRANSIT 28 | o ARRIVED 29 | } 30 | 31 | /** 32 | * Directions of the compass 33 | */ 34 | enum CompassDirection { 35 | o N 36 | o S 37 | o E 38 | o W 39 | } 40 | 41 | /** 42 | * An abstract transaction that is related to a Shipment 43 | */ 44 | abstract transaction ShipmentTransaction { 45 | --> Shipment shipment 46 | } 47 | 48 | /** 49 | * An Accelerometer reading for a shipment. E.g. received from a 50 | * device within an accelerometer controlled shipping container 51 | * 52 | * The combination of the accelerometer environment reading, 53 | * PLUS the GPS location, PLUS the timestamp is what is interesting 54 | * Just knowing temperature without knowing where or when is 55 | * not sufficient. 56 | */ 57 | transaction AccelReading extends ShipmentTransaction { 58 | o Double accel_x 59 | o Double accel_y 60 | o Double accel_z 61 | o String latitude 62 | o String longitude 63 | o String readingTime 64 | } 65 | 66 | /** 67 | * An temperature reading for a shipment. E.g. received from a 68 | * device within a temperature controlled shipping container 69 | * 70 | * The combination of the temperature environment reading, 71 | * PLUS the GPS location, PLUS the timestamp is what is interesting 72 | * Just knowing temperature without knowing where or when is 73 | * not sufficient. 74 | */ 75 | transaction TemperatureReading extends ShipmentTransaction { 76 | o Double celsius 77 | o String latitude 78 | o String longitude 79 | o String readingTime 80 | } 81 | 82 | /** 83 | * A GPS reading for a shipment. E.g. received from a device 84 | * within a shipping container 85 | */ 86 | transaction GpsReading extends ShipmentTransaction { 87 | o String readingTime 88 | o String readingDate 89 | o String latitude 90 | o CompassDirection latitudeDir 91 | o String longitude 92 | o CompassDirection longitudeDir 93 | } 94 | 95 | /** 96 | * A notification that a shipment has been received by the 97 | * importer and that funds should be transferred from the importer 98 | * to the grower to pay for the shipment. 99 | */ 100 | transaction ShipmentReceived extends ShipmentTransaction { 101 | } 102 | 103 | /** 104 | * A shipment being tracked as an asset on the ledger 105 | */ 106 | asset Shipment identified by shipmentId { 107 | o String shipmentId 108 | o ProductType type 109 | o ShipmentStatus status 110 | o Long unitCount 111 | --> Contract contract 112 | o TemperatureReading[] temperatureReadings optional 113 | o AccelReading[] AccelReadings optional 114 | o GpsReading[] gpsReadings optional 115 | } 116 | 117 | /** 118 | * Defines a contract between a Grower and an Importer to ship using 119 | * a Shipper, paying a set unit price. The unit price is multiplied by 120 | * a penality factor proportional to the deviation from the min and max 121 | * negociated temperatures for the shipment. 122 | */ 123 | asset Contract identified by contractId { 124 | o String contractId 125 | --> Grower grower 126 | --> Shipper shipper 127 | --> Importer importer 128 | o DateTime arrivalDateTime 129 | o Double unitPrice 130 | o Double minTemperature 131 | o Double maxTemperature 132 | o Double minPenaltyFactor 133 | o Double maxPenaltyFactor 134 | o Double maxAccel 135 | } 136 | 137 | /** 138 | * A concept for a simple street address 139 | */ 140 | concept Address { 141 | o String city optional 142 | o String country 143 | o String street optional 144 | o String zip optional 145 | } 146 | 147 | /** 148 | * An abstract participant type in this business network 149 | */ 150 | abstract participant Business identified by email { 151 | o String email 152 | o Address address 153 | o Double accountBalance 154 | } 155 | 156 | /** 157 | * A Grower is a type of participant in the network 158 | */ 159 | participant Grower extends Business { 160 | } 161 | 162 | /** 163 | * A Shipper is a type of participant in the network 164 | */ 165 | participant Shipper extends Business { 166 | } 167 | 168 | /** 169 | * An Importer is a type of participant in the network 170 | */ 171 | participant Importer extends Business { 172 | } 173 | 174 | /** 175 | * JUST FOR INITIALIZING A DEMO 176 | */ 177 | transaction SetupDemo { 178 | } 179 | 180 | /** 181 | * An event - when the temperature goes outside the agreed-upon boundaries 182 | */ 183 | event TemperatureThresholdEvent { 184 | o String message 185 | o Double temperature 186 | o String latitude 187 | o String longitude 188 | o String readingTime 189 | --> Shipment shipment 190 | } 191 | 192 | /** 193 | * An event - when the acceleration event has been detected 194 | */ 195 | event AccelerationThresholdEvent { 196 | o String message 197 | o Double accel_x 198 | o Double accel_y 199 | o Double accel_z 200 | o String latitude 201 | o String longitude 202 | o String readingTime 203 | --> Shipment shipment 204 | } 205 | 206 | /** 207 | * An event - when the ship arrives at the port 208 | */ 209 | event ShipmentInPortEvent { 210 | o String message 211 | --> Shipment shipment 212 | } 213 | -------------------------------------------------------------------------------- /Blockchain/IoT-Perishable-Network/permissions.acl: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample access control list. 3 | */ 4 | rule Default { 5 | description: "Allow all participants access to all resources" 6 | participant: "ANY" 7 | operation: ALL 8 | resource: "org.acme.shipping.perishable.*" 9 | action: ALLOW 10 | } 11 | 12 | rule SystemACL { 13 | description: "System ACL to permit all access" 14 | participant: "org.hyperledger.composer.system.Participant" 15 | operation: ALL 16 | resource: "org.hyperledger.composer.system.**" 17 | action: ALLOW 18 | } 19 | 20 | rule NetworkAdminUser { 21 | description: "Grant business network administrators full access to user resources" 22 | participant: "org.hyperledger.composer.system.NetworkAdmin" 23 | operation: ALL 24 | resource: "**" 25 | action: ALLOW 26 | } 27 | 28 | rule NetworkAdminSystem { 29 | description: "Grant business network administrators full access to system resources" 30 | participant: "org.hyperledger.composer.system.NetworkAdmin" 31 | operation: ALL 32 | resource: "org.hyperledger.composer.system.**" 33 | action: ALLOW 34 | } -------------------------------------------------------------------------------- /Blockchain/README-ja.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [English](README.md).* 2 | 3 | # Hyperledger ブロックチェーン上の IoT 資産トラッカー 4 | 5 | IoT 資産追跡ワークショップのこのセクションは、実際には2つの部分に分かれています。 6 | 最初の部分は **ブロックチェーン Aパート** と呼ばれ、IBM Cloud 上の [IBM Blockchain Starter Plan](https://www.ibm.com/blockchain/getting-started.html) に [Hyperledger](https://www.hyperledger.org/) Fabric と Hyperledger Composer をデプロイするチュートリアルに従います。 7 | 8 | 優れた IBM Blockchain チュートリアルが幾つか存在しますが、ここではこれを繰り返すつもりはありません。 9 | 私たちは道に沿って、それらを組み合わせて使用します。 10 | **ブロックチェーン Aパート** では、生鮮品のブロックチェーンビジネスネットワークを構築します。 11 | 12 | **ブロックチェーン Bパート** では、それを IBM Blockchain Starter プランにデプロイするためにスマートコントラクトに変換します。 13 | DevOps という IBM Cloud の一部を使用して、コードを作成し、IBM Blockchain Starter プランのインスタンスにデプロイします。 14 | 構築プロセスでは、Cloudly Foundry サービスとして動作する Hyperledger Composer Rest Server も IBM Cloud に導入します。 15 | Hyperledger Composer REST API は、Node-RED によってブロックチェーンの生鮮品のネットワークと通信するために使用されます。 16 | 最後に、Node-RED を操作して対話し、資産のトラッキングを視覚的に表示します。 17 | 18 | ## ブロックチェーン Aパート: 生鮮品ネットワークを構築 19 | 20 | 私たちは生鮮品ネットワークを構築するために Hyperledger Composer Playground を使用します。 21 | 作業が完了したら、Bパートで使用するコードをローカルシステムにエクスポートします。 22 | 23 | ### 生鮮品ネットワークのサンプルを Hyperledger Composer Playground にインポート 24 | 25 | 1. [IBM Hyperledger Composer Playground](https://blockchaindevelop.mybluemix.net/test) にアクセスします。 26 | 2. `Deploy a new business network` をクリックします。 27 | ![Select Deploy a new business network.](screenshots/deploynew.png) 28 | 3. 下にスクロールして、npm のサンプルから `perishable-network` を選択します。 29 | ![Select perishable-network from the *Samples on npm*.](screenshots/npmsample.png) 30 | 4. 上にスクロールすると、ビジネスネットワークの名前は `perishable-network` になります。 31 | 5. `Give the network admin card` に名前 **admin@perishable-network** を指定します。 32 | ![Perishable Network BNA screenshot](screenshots/Perishable-Network-BNA-annotated.png "Hyperledger Composer") 33 | 6. 右側のサイドバーで、**Deploy** をクリックします。 34 | 7. **Connect now ->** をクリックします。 35 | 36 | ![Select Connect now](screenshots/ConnectNow.png) 37 | 38 | ### IoT トラッキングのための生鮮品ネットワークをカスタマイズする 39 | 40 | 導入した生鮮品ネットワークを見直してみましょう。 41 | これは温度を追跡しますが、地理情報は追跡しません。 42 | developerWorksには、生鮮品ネットワークを紹介する優れた3つの Hyperledger シリーズの記事があります。 43 | 44 | * [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) 45 | * [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) 46 | * [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) 47 | 48 | Part 2 記事は手順を含んでいます 49 | 50 | > 次に、パート1で作業した生鮮品ネットワークのサンプルを変更します。具体的には、船積みアセットに GPS 読み取り値を追加して IoT GPS センサーを出荷コンテナにモデル化し、スマートコントラクト (チェーンコード) が発送先ポートに到着したときにアラートを送信します。 51 | 52 | ええ、これはまさに **私たちがしたいこと** です。 53 | 素晴らしい! 54 | Steve Perry の [perishable-network git repository]( 55 | https://github.com/makotogo/developerWorks) には、彼が dW の記事で詳しく述べた内容のバリエーションを含んでいます。 56 | 57 | もちろん、これら紹介したサンプルは私にとって完全なものではありません。 58 | なぜなら、Particle Electron 資産トラッカーから加速度計データもクラウドに送信したいからです。 59 | 60 | Hyperledger Blockchain モデリング言語の CTO ファイルとチェーンコードについて少し学ぶ必要があります。 61 | dW シリーズのパート1(上のリンク)は良い教材です。 62 | 63 | 次のステップでは、モデルファイルを変更して、加速度計データ、環境データ、地理位置データ、タイムスタンプを追加します。 64 | IoT データに追加するには、追加のトランザクションも必要です。 65 | モデルファイル更新後の時間を節約したい場合は、クローンしたリポジトリからトランザクションをインポートしてください。 66 | 67 | 1. モデルファイルで、**enum CompassDirection** を見つけるまでスクロールします。 次の値を入力して、4つの基本的な方向 (東西南北) を列挙します。 68 | ``` 69 | /** 70 | * Directions of the compass 71 | */ 72 | enum CompassDirection { 73 | o N 74 | o S 75 | o E 76 | o W 77 | } 78 | ``` 79 | 2. 現在、センサーからデータを取得するためには、いくつかのトランザクションモデルが必要です。 空の **ShipmentTransaction を継承 (拡張) した AccelReading トランザクション** を完成するため、次の情報を入力します: 80 | ``` 81 | transaction AccelReading extends ShipmentTransaction { 82 | o Double accel_x 83 | o Double accel_y 84 | o Double accel_z 85 | o String latitude 86 | o String longitude 87 | o String readingTime 88 | } 89 | ``` 90 | 3. **ShipmentTransaction を継承した TemperatureReading トランザクション** に対しては、以下の変数に一致するように変更します: 91 | ``` 92 | transaction TemperatureReading extends ShipmentTransaction { 93 | o Double celsius 94 | o String latitude 95 | o String longitude 96 | o String readingTime 97 | } 98 | ``` 99 | 4. **ShipmentTransaction を継承した GpsReading トランザクション** を設定するときです: 100 | ``` 101 | transaction GpsReading extends ShipmentTransaction { 102 | o String readingTime 103 | o String readingDate 104 | o String latitude 105 | o CompassDirection latitudeDir 106 | o String longitude 107 | o CompassDirection longitudeDir 108 | } 109 | ``` 110 | 111 | 5. IoTデータを資産、出荷に関連付けるには、IoT関連の変数を出荷するための資産モデルに追加する必要があります。出荷モデルに以下の追加を行います。 112 | * AccelReading[] AccelReadings optional 113 | * GpsReading[] gpsReadings optional 114 | 115 | ``` 116 | asset Shipment identified by shipmentId { 117 | o String shipmentId 118 | o ProductType type 119 | o ShipmentStatus status 120 | o Long unitCount 121 | --> Contract contract 122 | o TemperatureReading[] temperatureReadings optional 123 | o AccelReading[] AccelReadings optional 124 | o GpsReading[] gpsReadings optional 125 | } 126 | ``` 127 | 128 | 6. 我々の契約は、現在、加速度計によって捕捉された事故なしに到着する出荷を前提としたものです。 129 | 加速度計値のフィールドを契約 (Contract) 資産モデルに追加する必要があります。 130 | これにより、logic.js ファイルの加速度計データに基づいて、衝突、ひどい揺れ、その他のインシデントの条件を指定することができます。 131 | * Contract 資産モデルに **Double maxAccel** を追加する。 132 | 133 | ``` 134 | asset Contract identified by contractId { 135 | o String contractId 136 | --> Grower grower 137 | --> Shipper shipper 138 | --> Importer importer 139 | o DateTime arrivalDateTime 140 | o Double unitPrice 141 | o Double minTemperature 142 | o Double maxTemperature 143 | o Double minPenaltyFactor 144 | o Double maxPenaltyFactor 145 | o Double maxAccel 146 | } 147 | ``` 148 | 7. ここで、いくつかのイベントを作成して、合意されたしきい値を超えた場合に、適切な参加者に警告する必要があります。下にスクロールして、**TemperatureThresholdEvent** に次の情報を入力します。 149 | ``` 150 | event TemperatureThresholdEvent { 151 | o String message 152 | o Double temperature 153 | o String latitude 154 | o String longitude 155 | o String readingTime 156 | --> Shipment shipment 157 | } 158 | ``` 159 | 160 | 8. **AccelerationThresholdEvent** に変数を作成します: 161 | ``` 162 | event AccelerationThresholdEvent { 163 | o String message 164 | o Double accel_x 165 | o Double accel_y 166 | o Double accel_z 167 | o String latitude 168 | o String longitude 169 | o String readingTime 170 | --> Shipment shipment 171 | } 172 | ``` 173 | 9. **ShipmentInPort** イベントのモデルを作成するための情報を記入します: 174 | ``` 175 | event ShipmentInPortEvent { 176 | o String message 177 | --> Shipment shipment 178 | } 179 | ``` 180 | 181 | 10. モデルファイルが完成しました。`Update` をクリックすると、Hyperledger Composer Playground に変更が保存されます。 182 | ![Click Update.](screenshots/Update.png) 183 | 184 | 11. 私たちの新しい logic.js ファイルの内容を私たちの [リポジトリ](IoT-Perishable-Network/lib/logic.js) から **コピー** (CTRL+C) します。 185 | 186 | 12. Hyperledger Composer Playground に戻り: 187 | * logic.js ファイルの内容を **全て選択** (CTRL+A) して削除します 188 | * さきほどリポジトリの logic.js ファイルからコピーした内容を **ペースト** (CTRL+V) します 189 | * `Update` をクリックして変更を保存します 190 | 191 | ![Perishable Network BNA model update screenshot](screenshots/Perishable-Network-BNA-Model-update-annotated.png "Hyperledger Composer Model") 192 | 193 | 13. さあ、私たちの仕事をテストしましょう!ページの上部にある `Test` タブをクリックします。 194 | ![Click Test.](screenshots/Test.png) 195 | 196 | 14. まず、`Submit Transaction` を選択することで、*setupDemo* トランザクションを実行してデフォルト値を与えることができます。 197 | 198 | ![Select Submit Transaction.](screenshots/SubmitTransaction.png) 199 | 200 | 15. ドロップダウンから `SetupDemo` を選択して `Submit` します。 201 | ![Run setupDemo.](screenshots/SetupDemo.png) 202 | 203 | 16. あなたの3つの参加者と2つの資産を見てください。栽培業者(Grower)、輸入業者(Importer)、荷送人(Shipper)、貨物(Shipment)および契約(Contract)が定義されているはずです。 204 | 205 | 17. 他の取引と一緒に実行して、資産を更新するようにします。以下の例のように、貨物に追加された項目が詳細に表示されます。任意のデータを入力できます。架空のものでかまいません。 206 | ![Test your transactions and verify it updates the asset.](screenshots/example.png) 207 | 208 | 18. デプロイメントの実行中に使用するため、コードをローカルシステムに `Export` します。 209 | ![Click Export.](screenshots/export.png) 210 | 211 | 19. ビジネスネットワークアーカイブ、**perishable-network.bna** ファイルをどこか簡単に見つけられる場所に保存します。 212 | ![Save your business network archive locally.](screenshots/savebna.png) 213 | 214 | ## ブロックチェーン Bパート: 生鮮品ネットワークの実装 215 | 216 | さあ楽しい時間が始まります!これを2つのセクションに分けて説明します: 217 | 218 | * [ブロックチェーン・ネットワークを IBM Blockchain Starter プランにデプロイする](#deploy-your-network) 219 | * [Hyperledger Composer Rest Server を使用して、デプロイしたブロックチェーン・ネットワーク用の API を生成する](#working-with-the-rest-api) 220 | 221 | 222 | ### 自身のネットワークをデプロイする 223 | 224 | 自身のブロックチェーン・アプリケーションを作成したので、今度は IBM Blockchain Starter プランで実行させましょう。 225 | そのために、IBM Cloud の DevOps サービスを使用してコードをデプロイし、REST サーバーを開始します。 226 | 別の機会に同様のことをする場合、この全プロセスは [こちら](https://github.com/sstone1/blockchain-starter-kit/blob/master/README.md) に文書化されていますので参照してください。 227 | このプロセスにより、IBM Blockchain Starter プランが作成されます。 228 | 229 | **ノート:** IBM Blockchain Starter プランを使用するには、IBM Cloud アカウントを pay-as-you-go アカウントにアップグレードする必要があります。最大30日間無料です。料金の請求を避けるために使用量を監視するのを忘れないでください。 230 | 231 | これは以下の手順に分かれています: 232 | * [DevOps ツールチェーンを作成する](#create-a-devops-toolchain) 233 | * [Hyperledger Composer をローカル環境にインストールする](#install-hyperledger-composer-locally) 234 | * [デプロイのためのコードを準備する](#prepare-your-code-for-deployment) 235 | * [デプロイメントの検証](#verify-deployment) 236 | 237 | 238 | #### DevOps ツールチェーンを作成する 239 | 1. [こちら](https://console.bluemix.net/devops/setup/deploy/?repository=https%3A//github.com/sstone1/blockchain-starter-kit&branch=master&env_id=ibm%3Ayp%3Aus-south) で DevOps ツールチェーン作成を開始する。 240 | 241 | 2. あなたのツールチェーンの名前を入力してください。ユニークなものにしましょう! 242 | 243 | **ノート:** 以前に IBM Cloud で GitHub 認証を実施していない場合は、Blockchain Starter Kit を作成する前に実施する必要があります。この画面をスクロールして認証ボタンを選択してください。 244 | 245 | ![Enter a name for your toolchain.](screenshots/starterkittoolchain.png) 246 | 247 | 3. 下にスクロールしてユニークなリポジトリ名 **XXX-blockchain-toolkit** を作成します。XXXはあなたの頭文字です。 248 | 249 | 4. `Create` をクリック。 250 | ![Create a uniquire repository name and select Create.](screenshots/repositorycreate.png) 251 | 252 | 5. おめでとうございます!コードをデプロイするために使用できる完全なツールチェーンが用意されました。 253 | ![Complete blockchain-starter-kit toolchain.](screenshots/completetoolchain.png) 254 | 255 | 途中の `GitHub` ボタンを押すと、新しく作成した GitHub リポジトリに移動します。この GitHub リポジトリをローカル開発環境にクローンすることで、ブロックチェーンアプリケーションを操作できます。 256 | 257 | 右側の `Delivery Pipeline` ボタンをクリックすると、DevOps ツールチェーンのデリバリーパイプラインに移動します。ここからは、ブロックチェーンアプリケーションの最新の自動ビルドとデプロイメントの結果を調べることができます。 258 | 259 | 260 | #### Hyperledger Composer をローカル環境にインストールする 261 | コードを展開するには、システム上の Hyperledger Composer コマンドのいくつかを使用する必要があります。 262 | 263 | 1. 前提条件のインストールと Hyperledger Composerの インストールについては、[指示](https://hyperledger.github.io/composer/latest/installing/installing-index) に従ってください。 264 | * この演習で Hyperledger Composer をインストールする場合は、手順1と手順2のみを完了してください。 265 | 266 | 267 | #### デプロイのためのコードを準備する 268 | 269 | 1. あなたのツールチェインで、`GitHub` アイコンを選択して、新しく作成したリポジトリを開きます。 270 | ![Select GitHub.](screenshots/gotogithub.png) 271 | 272 | 2. GitHubで、`Clone or download` をクリックし、`copy` アイコンをクリックして、リポジトリをローカルシステムにクローンするためのURLを取得します。 273 | ![Select Clone and then copy.](screenshots/clonegithub.png) 274 | 275 | 3. あなたのローカルシステム上の端末で、 `git clone ` と入力します。`` は前の手順でコピーした値です。 276 | ``` 277 | $ git clone https://github.com/SweetJenn23/XXX-blockchain-starter-kit.git 278 | Cloning into 'XXX-blockchain-starter-kit'... 279 | remote: Counting objects: 40, done. 280 | remote: Compressing objects: 100% (35/35), done. 281 | remote: Total 40 (delta 2), reused 40 (delta 2), pack-reused 0 282 | Unpacking objects: 100% (40/40), done. 283 | ``` 284 | 285 | 4. `cd XXX-blockchain-starter-kit/contracts` でcontract 契約ディレクトリに移動します。XXXはあなたの頭文字です。 286 | 287 | 5. 私たちはブロックチェーンネットワーク(.bna)からスマートコントラクトを作成する必要があります。これを行うには、Yeoman と呼ばれる Hyperledger Composer と共にインストールされたツールの1つを使用します。これにより、Hyperledger Fabricに 展開できるスマートスマートコントラクトの雛形 (スケルトン) が作成されます。私たちはこの雛形に私たちの仕事をコピーしなければなりません。 288 | 289 | 雛形を作成するには、ローカルシステムの端末に `yo` と入力し、**XXX-perishable-network** という名のビジネスネットワークを作成します。XXXはあなたの頭文字です。プロンプトで残りの情報を入力します。 290 | 291 | ![Enter the information for Yeoman to create a skeleton smart contract.](screenshots/yo.png) 292 | 293 | 6. コードをスケルトンにコピーするには、ビジネスネットワークアーカイブを展開する必要があります。 294 | * ローカルシステムの端末で、**perishable-network.bna** を保存したディレクトリに移動します。 295 | * ファイルの拡張子を変更します: `mv perishable-network.bna perishable-network.zip` 296 | * ファイルを解凍します: `unzip perishable-network.zip` 297 | ``` 298 | > unzip perishable-network.zip 299 | Archive: perishable-network.zip 300 | extracting: package.json 301 | extracting: README.md 302 | extracting: permissions.acl 303 | creating: models/ 304 | extracting: models/perishable.cto 305 | creating: lib/ 306 | extracting: lib/logic.js 307 | ``` 308 | 7. */XXX-blockchain-starter-kit/contracts/xxx-perishable-network* に、抽出したファイルをコピーします。*xxx-perishable-network* ディレクトリにあるファイルを同じ名前のファイルで置き換えます。次のすべてのファイルに対してこれを行います: 309 | * `/xxx-blockchain-starter-kit/contracts/xxx-perisable-network/lib/org.acme.biznet.perishable.cto` を削除 310 | * `perishable-network/README.md` を `XXX-blockchain-starter-kit/contracts/xxx-perishable-network` にコピー 311 | * `perishable-network/permissions.acl` を `XXX-blockchain-starter-kit/contracts/xxx-perishable-network` にコピー 312 | * `perishable-network/models/perishable.cto` を `XXX-blockchain-starter-kit/contracts/xxx-perishable-network/models/` にコピー 313 | * `perishable-network/lib/logic.js` を `XXX-blockchain-starter-kit/contracts/xxx-perishable-network/lib/` にコピー 314 | 315 | ![Move the contents of your perishable-network.bna into the generated skeleton.](screenshots/movecontents.png) 316 | 317 | 8. リポジトリの中のファイル **~/XXX-blockchain-starter-kit/.bluemix/pipeline_BUILD.sh** を編集します。 318 | 319 | * **function test_composer_contract** を探す 320 | 321 | * function 定義のなかで `#npm test` の行のコメントを外して **npm test** とする: 322 | ``` 323 | function test_composer_contract { 324 | CONTRACT=$1 325 | echo testing composer contract ${CONTRACT} 326 | pushd contracts/${CONTRACT} 327 | npm install 328 | #npm test 329 | rm -rf node_modules 330 | popd 331 | } 332 | ``` 333 | 334 | 9. ツールチェインの GitHub のリポジトリにコードをコミットするには、端末で **XXX-blockchain-starter-kit** ディレクトリ内で次のコマンドを実行する必要があります: 335 | * `git add -A` 336 | * `git commit -m "Update files"` 337 | * `git push` 338 | 339 | ![Run these git commands.](screenshots/gitcommit.png) 340 | 341 | 342 | 343 | #### デプロイメントの検証 344 | 345 | GitHub にコードをコミットすると、DevOps ツールチェインが自動的に変更を取得します。ツールチェインはすぐに変更のデプロイを開始します。 346 | 347 | 1. DevOps ツールチェーンページに移動し、`Delivery Pipeline` ボタンをクリックします。以下のページが表示され、デリバリーパイプラインの現在の状態の概要がわかります: 348 | ![Successful deployment.](screenshots/deploypassed.png) 349 | 350 | 2. デリバリーパイプラインには "BUILD" と "DEPLOY" の2つのフェーズがあります。 351 | 352 | デリバリーパイプラインの **BUILD** フェーズは、GitHubリポジトリをクローンし、依存関係をインストールし、すべてのスマートコントラクトの自動化ユニットテストをすべて実行します。ユニットテストが失敗した場合、デリバリーパイプラインは失敗し、変更はデプロイ(DEPLOY)されません。 353 | 354 | デリバリーパイプラインの **DEPLOY** フェーズは、スマート・コントラクトを IBM Cloud にデプロイします。 355 | IBM Blockchain Platform: Starter プラン (ブロックチェーンネットワーク) のインスタンス、Cloudant (ブロックチェーン資格情報の保存場所)のインスタンス、スマートコントラクトのデプロイ、デプロイ各スマートコントラクト用の RESTful API サーバーのプロビジョニングと構成を担当します。 356 | 357 | `View logs and history` をクリックすると、ビルドの最新ログが表示されます: 358 | ![View your logs.](screenshots/toolchainlog.png) 359 | 360 | BUILD と DELIVERY 両方のフェーズが緑色ならば、エラーが発生していないことを示します。そうでない場合は、ログを使用してエラーの原因を調査する必要があります。 361 | 362 | 363 | ### REST API を使用してビジネスネットワークを公開する 364 | 365 | Node-RED からブロックチェーンを操作するために、Hyperledger Composer REST API を使用して perishable-network ビジネスネットワークを公開します。現在、このスターターキットでは、Hyperledger Fabric を使用して開発されたスマートコントラクト用の RESTful API サーバーはデプロイされていません。Hyperledger Composer を使用しているので、DevOps ツールチェーンは、配備された各スマートコントラクトに対して RESTful AP Iサーバーを自動的にデプロイしました。これらの RESTful API を使用して、スマートコントラクトと対話するエンドユーザー・アプリケーションを構築できます。 366 | 367 | 1. デプロイされた RESTful API サーバーのURLは、"DELIVERY" フェーズのログで確認できますが、[IBM Cloud Dashboard](https://console.bluemix.net/dashboard/apps) でも見つけることができます。RESTful API サーバーは "composer-rest-server-" という名前とスマートコントラクトの名前で、アプリケーションとしてデプロイされます。 私たちは **composer-rest-server-xxx-perishable-network** という名前を使用します。 368 | ![Find your composer-rest-server in the IBM Cloud Dashboard.](screenshots/composer-rest-server.png) 369 | 370 | 2. rest サーバーをクリックして、アプリケーションの詳細ページに移動します。 371 | ![View the rest server application details.](screenshots/restserverdetails.png) 372 | 373 | 3. `Visit App URL` であなたの API を確認できます。 374 | ![Select Visit App URL.](screenshots/VisitAppURL.png) 375 | 376 | 4. これらのAPIは、Node-RED がブロックチェーンと通信する方法を提供しています。 377 | ![View your APIs.](screenshots/API.png) 378 | 379 | おめでとう! あなたはワークショップの Blockchain セクションを完了しました。 380 | [Node-RED セクション](../Node-RED/README-ja.md) に進み、 381 | IoT 資産環境センサーのデータをトランザクション履歴に書き込み/読み取り/可視化できるようにした REST API を活用してください。 382 | -------------------------------------------------------------------------------- /Blockchain/README.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [日本語](README-ja.md).* 2 | 3 | # IoT Asset Tracking on a Hyperledger Blockchain 4 | 5 | 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. 6 | 7 | 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. 8 | 9 | ## Blockchain Part A - Build your perishable network 10 | 11 | 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. 12 | 13 | ### Import the sample perishable network into Hyperledger Composer Playground 14 | 1. Access the [IBM Hyperledger Composer Playground](https://blockchaindevelop.mybluemix.net/test). 15 | 2. Click on **Deploy a new business network** 16 | ![Select Deploy a new business network.](screenshots/deploynew.png) 17 | 3. Scroll down and choose **perishable-network** from the samples on npm. 18 | ![Select perishable-network from the *Samples on npm*.](screenshots/npmsample.png) 19 | 4. Scrolling back to the top, you should now have a business network name of **perishable-network**. 20 | 5. Give the network admin card that will be created a name **admin@perishable-network**. 21 | ![Perishable Network BNA screenshot](screenshots/Perishable-Network-BNA-annotated.png "Hyperledger Composer") 22 | 6. On the right sidebar, click on **Deploy**. 23 | 7. Press **Connect now ->** 24 | 25 | ![Select Connect now](screenshots/ConnectNow.png) 26 | 27 | ### Customize the perishable network for IoT tracking 28 | 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. 29 | * [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) 30 | * [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) 31 | * [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) 32 | 33 | Part 2 includes instructions 34 | 35 | > Then you'll make changes to the sample Perishable Goods network that you worked with in Part 1. Specifically, you'll model an IoT GPS sensor in the shipping container by adding GPS readings to the Shipment asset, and modify the smart contract (chaincode) to send an alert when the Shipment reaches its destination port. 36 | 37 | Well, duh. THAT'S WHAT WE WANT TO DO.... With full step by step instructions. Triple word score. Following all the links finds Steve Perry's [perishable-network git repository]( 38 | https://github.com/makotogo/developerWorks) that contains the variants he details in the dW articles. 39 | 40 | Of course, those samples only got me so far because I also want to send accelerometer data from the Particle Electron Asset Tracker to the cloud. 41 | 42 | 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. 43 | 44 | 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. 45 | 46 | 1. In your model file, scroll until you find **enum CompassDirection**. Enter the following values to enumerate the four cardinal directions: 47 | ``` 48 | /** 49 | * Directions of the compass 50 | */ 51 | enum CompassDirection { 52 | o N 53 | o S 54 | o E 55 | o W 56 | } 57 | ``` 58 | 2. Now we need some transaction models to be able to get data from our sensors. In the empty **transaction AccelReading extends ShipmentTransaction** complete the following information: 59 | ``` 60 | transaction AccelReading extends ShipmentTransaction { 61 | o Double accel_x 62 | o Double accel_y 63 | o Double accel_z 64 | o String latitude 65 | o String longitude 66 | o String readingTime 67 | } 68 | ``` 69 | 3. For **transaction TemperatureReading extends ShipmentTransaction** modify the transaction to match the following variables: 70 | ``` 71 | transaction TemperatureReading extends ShipmentTransaction { 72 | o Double celsius 73 | o String latitude 74 | o String longitude 75 | o String readingTime 76 | } 77 | ``` 78 | 4. It's time to setup the **transaction GpsReading extends ShipmentTransaction**: 79 | ``` 80 | transaction GpsReading extends ShipmentTransaction { 81 | o String readingTime 82 | o String readingDate 83 | o String latitude 84 | o CompassDirection latitudeDir 85 | o String longitude 86 | o CompassDirection longitudeDir 87 | } 88 | ``` 89 | 90 | 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 the shipment model. 91 | * AccelReading[] AccelReadings optional 92 | * GpsReading[] gpsReadings optional 93 | ``` 94 | asset Shipment identified by shipmentId { 95 | o String shipmentId 96 | o ProductType type 97 | o ShipmentStatus status 98 | o Long unitCount 99 | --> Contract contract 100 | o TemperatureReading[] temperatureReadings optional 101 | o AccelReading[] AccelReadings optional 102 | o GpsReading[] gpsReadings optional 103 | } 104 | ``` 105 | 106 | 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. 107 | * Add **Double maxAccel** to the Contract asset model. 108 | ``` 109 | asset Contract identified by contractId { 110 | o String contractId 111 | --> Grower grower 112 | --> Shipper shipper 113 | --> Importer importer 114 | o DateTime arrivalDateTime 115 | o Double unitPrice 116 | o Double minTemperature 117 | o Double maxTemperature 118 | o Double minPenaltyFactor 119 | o Double maxPenaltyFactor 120 | o Double maxAccel 121 | } 122 | ``` 123 | 7. Now we need to create some events so we can alert the appropriate participants when agreed upon thresholds are exceeded. Scroll down and fill in the following information for the **TemperatureThresholdEvent**. 124 | ``` 125 | event TemperatureThresholdEvent { 126 | o String message 127 | o Double temperature 128 | o String latitude 129 | o String longitude 130 | o String readingTime 131 | --> Shipment shipment 132 | } 133 | ``` 134 | 135 | 8. Create the variables for the **AccelerationThresholdEvent**. 136 | ``` 137 | event AccelerationThresholdEvent { 138 | o String message 139 | o Double accel_x 140 | o Double accel_y 141 | o Double accel_z 142 | o String latitude 143 | o String longitude 144 | o String readingTime 145 | --> Shipment shipment 146 | } 147 | ``` 148 | 9. Complete the information to create the model for the event **ShipmentInPort**. 149 | ``` 150 | event ShipmentInPortEvent { 151 | o String message 152 | --> Shipment shipment 153 | } 154 | ``` 155 | 156 | 10. Our model file is now complete. Select **Update** to save the changes in the Hyperledger Composer Playground. 157 | ![Click Update.](screenshots/Update.png) 158 | 159 | 11. Now it is time to **copy** (CTRL+C) our new logic.js file from our [repository](IoT-Perishable-Network/lib/logic.js). 160 | 161 | 12. Back in the Hyperledger Composer Playground: 162 | * **Remove all of the content** (CTRL+A) in the logic.js file 163 | * **Paste** (CTRL+V) in the content copied from the logic.js file in our repository. 164 | * Select **Update** to save the changes. 165 | ![Perishable Network BNA model update screenshot](screenshots/Perishable-Network-BNA-Model-update-annotated.png "Hyperledger Composer Model") 166 | 167 | 13. Now let's test our work! Click on the **Test** tab at the top of the page. 168 | ![Click Test.](screenshots/Test.png) 169 | 170 | 14. First, select **Submit Transaction** so we can run our *setupDemo* transaction to give us some default values. 171 | ![Select Submit Transaction.](screenshots/SubmitTransaction.png) 172 | 173 | 15. From the *drop down*, select **SetupDemo** and then **Submit**. 174 | ![Run setupDemo.](screenshots/SetupDemo.png) 175 | 176 | 16. Look through your three partipants and two assets. You should now have a defined Grower, Importer, Shipper, Shipment and Contract. 177 | 178 | 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. 179 | ![Test your transactions and verify it updates the asset.](screenshots/example.png) 180 | 181 | 18. **Export** the code to your local system. We will use it during the deployment process. 182 | ![Click Export.](screenshots/export.png) 183 | 184 | 19. Save the business network archive, **perishable-network.bna**, somewhere you can easily find it. 185 | ![Save your business network archive locally.](screenshots/savebna.png) 186 | 187 | ## Blockchain Part B - Implement a Perishable Business Network 188 | Now it's time for the fun to begin! We are going to break this down into two sections: 189 | 190 | * [Deploying your blockchain network to your IBM Blockchain Starter Plan](#deploy-your-network) 191 | * [Generating your API for your deployed blockchain network with Hyperledger Composer Rest Server](#working-with-the-rest-api) 192 | 193 | 194 | ### Deploy your network 195 | 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. 196 | 197 | **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. 198 | 199 | This breaks down into the following steps: 200 | * [Create a DevOps toolchain](#create-a-devops-toolchain) 201 | * [Installing Hyperledger Composer locally](#install-hyperledger-composer-locally) 202 | * [Moving your code into your repository](#prepare-your-code-for-deployment) 203 | * [Verifying deployment of code](#verify-deployment) 204 | 205 | #### Create a DevOps toolchain 206 | 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. 207 | 208 | 2. Enter a name for your toolchain. Make it unique! 209 | 210 | **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. 211 | 212 | ![Enter a name for your toolchain.](screenshots/starterkittoolchain.png) 213 | 214 | 3. Scroll down and create a unique repository name, **XXX-blockchain-toolkit** where XXX are your initials. 215 | 216 | 4. Click **Create**. 217 | ![Create a uniquire repository name and select Create.](screenshots/repositorycreate.png) 218 | 219 | 5. Congratulations! You have a complete toolchain that can be used to deploy your code. 220 | ![Complete blockchain-starter-kit toolchain.](screenshots/completetoolchain.png) 221 | 222 | 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. 223 | 224 | 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. 225 | 226 | #### Install Hyperledger Composer locally 227 | To deploy our code, we'll need to work with some of the Hyperledger Composer commands on our system. 228 | 229 | 1. Follow the [directions](https://hyperledger.github.io/composer/latest/installing/installing-index) for installing the prerequisites and installing Hyperledger Composer. 230 | * Only complete Step 1 and Step 2 of installing Hyperledger Composer for this exercise. 231 | 232 | #### Prepare your code for deployment 233 | 1. In your toolchain, select the **GitHub** icon to open your newly created repository. 234 | ![Select GitHub.](screenshots/gotogithub.png) 235 | 236 | 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. 237 | ![Select Clone and then copy.](screenshots/clonegithub.png) 238 | 239 | 3. In a terminal on your local system, enter `git clone ` where \ is the value you copied in the previous step. 240 | ``` 241 | $ git clone https://github.com/SweetJenn23/XXX-blockchain-starter-kit.git 242 | Cloning into 'XXX-blockchain-starter-kit'... 243 | remote: Counting objects: 40, done. 244 | remote: Compressing objects: 100% (35/35), done. 245 | remote: Total 40 (delta 2), reused 40 (delta 2), pack-reused 0 246 | Unpacking objects: 100% (40/40), done. 247 | ``` 248 | 249 | 4. Move into the contracts directory, `cd XXX-blockchain-starter-kit/contracts` where XXX are your initials. 250 | 251 | 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. 252 | 253 | 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. 254 | ![Enter the information for Yeoman to create a skeleton smart contract.](screenshots/yo.png) 255 | 256 | 6. To copy our code into the skeleton you'll need to expand the business network archive. 257 | * In your terminal, change directory to where your **perishable-network.bna** is saved. 258 | * Change the extension on the file. `mv perishable-network.bna perishable-network.zip` 259 | * Unzip the file. `unzip perishable-network.zip` 260 | ``` 261 | > unzip perishable-network.zip 262 | Archive: perishable-network.zip 263 | extracting: package.json 264 | extracting: README.md 265 | extracting: permissions.acl 266 | creating: models/ 267 | extracting: models/perishable.cto 268 | creating: lib/ 269 | extracting: lib/logic.js 270 | ``` 271 | 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: 272 | * remove `/xxx-blockchain-starter-kit/contracts/xxx-perisable-network/lib/org.acme.biznet.perishable.cto` 273 | * copy `perishable-network/README.md` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network` 274 | * copy `perishable-network/permissions.acl` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network` 275 | * copy `perishable-network/models/perishable.cto` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network/models/` 276 | * copy `perishable-network/lib/logic.js` to `XXX-blockchain-starter-kit/contracts/xxx-perishable-network/lib/` 277 | ![Move the contents of your perishable-network.bna into the generated skeleton.](screenshots/movecontents.png) 278 | 279 | 8. In your repository edit the file, **~/XXX-blockchain-starter-kit/.bluemix/pipeline_BUILD.sh** 280 | 281 | * Find **function test_composer_contract** 282 | 283 | * In the function comment out the line **npm test**, `#npm test` 284 | ``` 285 | function test_composer_contract { 286 | CONTRACT=$1 287 | echo testing composer contract ${CONTRACT} 288 | pushd contracts/${CONTRACT} 289 | npm install 290 | #npm test 291 | rm -rf node_modules 292 | popd 293 | } 294 | ``` 295 | 296 | 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: 297 | * `git add -A` 298 | * `git commit -m "Update files"` 299 | * `git push` 300 | ![Run these git commands.](screenshots/gitcommit.png) 301 | 302 | 303 | #### Verify deployment 304 | When you committed your code to GitHub, the DevOps toolchain automatically picked up the changes. The toolchain will immediately begin deploying those changes. 305 | 306 | 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: 307 | ![Successful deployment.](screenshots/deploypassed.png) 308 | 309 | 2. The delivery pipeline is made up of two phases, "BUILD" and "DEPLOY". 310 | 311 | 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. 312 | 313 | 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. 314 | 315 | If you click "View logs and history", you can see the latest logs for your build: 316 | ![View your logs.](screenshots/toolchainlog.png) 317 | 318 | 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. 319 | 320 | ### Working with the REST API 321 | 322 | 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. 323 | 324 | 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**. 325 | ![Find your composer-rest-server in the IBM Cloud Dashboard.](screenshots/composer-rest-server.png) 326 | 327 | 2. Click on the rest server to navigate to the application details page. 328 | ![View the rest server application details.](screenshots/restserverdetails.png) 329 | 330 | 3. Select the **Visit App URL** to view your API. 331 | ![Select Visit App URL.](screenshots/VisitAppURL.png) 332 | 333 | 4. These APIs are how Node-RED will communicate with blockchain. 334 | ![View your APIs.](screenshots/API.png) 335 | 336 | 337 | 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. 338 | -------------------------------------------------------------------------------- /Blockchain/iot-asset-tracker-network.bna: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/iot-asset-tracker-network.bna -------------------------------------------------------------------------------- /Blockchain/screenshots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/.DS_Store -------------------------------------------------------------------------------- /Blockchain/screenshots/API.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/API.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Authorize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Authorize.png -------------------------------------------------------------------------------- /Blockchain/screenshots/AuthorizeCloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/AuthorizeCloud.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Breadcrumbs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Breadcrumbs.png -------------------------------------------------------------------------------- /Blockchain/screenshots/ConnectNow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/ConnectNow.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Create.png -------------------------------------------------------------------------------- /Blockchain/screenshots/DeliveryPipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/DeliveryPipeline.png -------------------------------------------------------------------------------- /Blockchain/screenshots/DeployMarbles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/DeployMarbles.png -------------------------------------------------------------------------------- /Blockchain/screenshots/DeploymentProgress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/DeploymentProgress.png -------------------------------------------------------------------------------- /Blockchain/screenshots/DevOps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/DevOps.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Guided.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Guided.png -------------------------------------------------------------------------------- /Blockchain/screenshots/MarblesToolchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/MarblesToolchain.png -------------------------------------------------------------------------------- /Blockchain/screenshots/MarblesUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/MarblesUI.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Passed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Passed.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Perishable-Network-BNA-ConnectNow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Perishable-Network-BNA-ConnectNow.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Perishable-Network-BNA-Model-update-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Perishable-Network-BNA-Model-update-annotated.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Perishable-Network-BNA-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Perishable-Network-BNA-annotated.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Perishable-Network-BNA-creds-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Perishable-Network-BNA-creds-annotated.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Perishable-Network-REST-API-swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Perishable-Network-REST-API-swagger.png -------------------------------------------------------------------------------- /Blockchain/screenshots/RepoName.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/RepoName.png -------------------------------------------------------------------------------- /Blockchain/screenshots/SeeApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/SeeApp.png -------------------------------------------------------------------------------- /Blockchain/screenshots/SelectGitHub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/SelectGitHub.png -------------------------------------------------------------------------------- /Blockchain/screenshots/SetupDemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/SetupDemo.png -------------------------------------------------------------------------------- /Blockchain/screenshots/SubmitTransaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/SubmitTransaction.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Success.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Test.png -------------------------------------------------------------------------------- /Blockchain/screenshots/ToolChainName.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/ToolChainName.png -------------------------------------------------------------------------------- /Blockchain/screenshots/TrySamples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/TrySamples.png -------------------------------------------------------------------------------- /Blockchain/screenshots/Update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/Update.png -------------------------------------------------------------------------------- /Blockchain/screenshots/ViewLogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/ViewLogs.png -------------------------------------------------------------------------------- /Blockchain/screenshots/VisitAppURL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/VisitAppURL.png -------------------------------------------------------------------------------- /Blockchain/screenshots/clonegithub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/clonegithub.png -------------------------------------------------------------------------------- /Blockchain/screenshots/completetoolchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/completetoolchain.png -------------------------------------------------------------------------------- /Blockchain/screenshots/composer-rest-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/composer-rest-server.png -------------------------------------------------------------------------------- /Blockchain/screenshots/deploynew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/deploynew.png -------------------------------------------------------------------------------- /Blockchain/screenshots/deploypassed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/deploypassed.png -------------------------------------------------------------------------------- /Blockchain/screenshots/developcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/developcode.png -------------------------------------------------------------------------------- /Blockchain/screenshots/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/example.png -------------------------------------------------------------------------------- /Blockchain/screenshots/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/export.png -------------------------------------------------------------------------------- /Blockchain/screenshots/gitcommit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/gitcommit.png -------------------------------------------------------------------------------- /Blockchain/screenshots/gotogithub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/gotogithub.png -------------------------------------------------------------------------------- /Blockchain/screenshots/launchnow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/launchnow.png -------------------------------------------------------------------------------- /Blockchain/screenshots/menubar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/menubar.png -------------------------------------------------------------------------------- /Blockchain/screenshots/movecontents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/movecontents.png -------------------------------------------------------------------------------- /Blockchain/screenshots/npmsample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/npmsample.png -------------------------------------------------------------------------------- /Blockchain/screenshots/repositorycreate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/repositorycreate.png -------------------------------------------------------------------------------- /Blockchain/screenshots/restserverdetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/restserverdetails.png -------------------------------------------------------------------------------- /Blockchain/screenshots/savebna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/savebna.png -------------------------------------------------------------------------------- /Blockchain/screenshots/starterkittoolchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/starterkittoolchain.png -------------------------------------------------------------------------------- /Blockchain/screenshots/toolchainlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/toolchainlog.png -------------------------------------------------------------------------------- /Blockchain/screenshots/webplayground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/webplayground.png -------------------------------------------------------------------------------- /Blockchain/screenshots/yo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Blockchain/screenshots/yo.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Node-RED/README-ja.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [English](README.md).* 2 | 3 | # Node-RED - IoT 資産トラッカー 4 | ## Node-RED - IoT 資産トラッカー 前書き 5 | 6 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-dashboard-AssetTracker-PR.png) 7 | 8 | 今回の Node-RED プログラムフローは、IoT資産トラッカーを実装し、Particle Electron からジオロケーションと環境センサーデータを受け取り、その情報を Hyperledger Fabric ブロックチェーンに格納し、マップ/ダッシュボード上の IoT デバイスのルートを視覚化します。 9 | 環境データが閾値を超えた場合に警告をトリガーします。 10 | 11 | このワークショップでは、GitHub からフローをコピーし、IBM Cloud 上で動作する Watson IoT / Node-RED Starter アプリケーションにデプロイします。 12 | 13 | 7つのフローは、次の機能を実行します: 14 | 15 | * **ブロックチェーンと Node-RED 変数を初期化** - すべてのフローを駆動するグローバル変数を設定します。 16 | * **Particle Electron の制御** - Particle Electron を有効/無効にする Node-RED Dashboard。 17 | * **Particle Electron イベントの受信** - Particle Electron イベントハンドラを購読する。 18 | * Hyperledger Fabric ブロックチェーンへの **Particle Electron データの書き込み** 19 | * **ブロックチェーンのトランザクション履歴をロード** し、IoTデバイスのルートをプロットする。 20 | * **Build a Dashboard を作成** し、デバイスの視覚化を制御する。 21 | * **記録された履歴に沿って IoT アセットを移動** することで、地図上にルートを視覚化する。 22 | 23 | ダッシュボードは、エンドユーザーにとって魅力的なユーザーエクスペリエンスではありません。これらのダッシュボードは、IoT 資産トラッカーで何か実装可能であるかを示すための、開発者向けのデモンストレーションです。エンドユーザーは、ジオロケーション座標には関心がないでしょう。 24 | 25 | ## IBM Cloud 上で Node-RED を使い始める 26 | 27 | IoT 資産トラッカーのダッシュボードを導入する前に、IBM Cloud 上で IoT Starter アプリケーションを作成する必要があります。このセクションでは、これらの手順について説明します。 28 | 29 | ### Internet of Things Starter アプリの作成 30 | 31 | * [IBM Cloud](http://bluemix.net) のアカウントを作成しログインする。 32 | * **(1)** のカタログをクリックし、 **(2)** 'internet of things' を検索する。 33 | * Internet of Things Platform Starter **(3)** ボイラープレートは、あらかじめ組み立てられたサービスが一緒に働くパターンです。 Internet of Things Platform Starter には、Node-RED Node.js Webサーバー、フローを格納する Cloudant データベース、IoT プラットフォームサービスが含まれているため、デバイスを接続できます。 34 | ![IBM Cloud Node-RED IoT Starter screenshot](screenshots/IBMCloud-Catalog-newstarter-annotated.png) 35 | * アプリケーションに何かユニークな名前を決めましょう。もし *myapp* という名前をつけたのなら、あなたのアプリケーションは http://myapp.mybluemix.net のURLアドレスに配置されるでしょう。*myapp* アプリケーションとそのURLは、IBM Cloud 内で1つしか登録できません。 36 | * 決めたユニークなアプリケーション名を **(4)** に入力します - 例えば *IoTAssetTracker-yourname* のように。 37 | * **(5)** Create ボタンをクリック。 38 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-CFappcreate.png) 39 | * IBM Cloud は、ボイラープレート内で定義されたサービスに基づいてアカウント内にアプリケーションを作成します。これはアプリケーションのステージングと呼ばれます。このプロセスが完了するまでに数分かかることがあります。待っている間は、`Logs` タブをクリックして、プラットフォームと Node.js ランタイムからのアクティビティログを見ることができます。 40 | 41 | ### IoT Starter アプリケーションの起動 42 | 43 | 緑の `Running` アイコン**(6)** が表示されたら、`Visit App URL` リンクをクリックします 44 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-launch.png) 45 | 46 | ### Node-RED ビジュアル プログラミング エディタを開く 47 | 48 | 新しいブラウザタブが開き、Node-RED の開始ページが表示されます。 49 | Node-RED は、オープンソースの Node.js アプリケーションで、ビジュアルプログラミングエディタを備えており、フローを簡単に配線できます。 50 | Node-REDエディタにアクセスするには、ユーザ名とパスワードを選択します。 51 | あなたのユーザー名とパスワードを忘れないでください。 52 | 赤いボタンをクリックします。 53 | Node-RED フローエディタを選び、エディタを起動します。 54 | 55 | * Node-RED Visual Programming Editorがデフォルトのフローで開きます。 56 | * 左側には、フローにドラッグできるノードのパレットがあります。 57 | * ノードを結んでプログラムを作成することができます。 58 | * サンプル IoT スターターフローはこのワークショップでは使用しませんので、削除してかまいません。 59 | * 上で説明したフローをこれからインポートします。 60 | 61 | ### 追加の Node-RED ノードをインストールする 62 | 63 | IBM Cloud に導入された IoT スターター・アプリケーションには、Node-RED ノードのわずかなサブセットしか含まれていません。Node-RED パレットは、さまざまなデバイスや機能に合わせて1000個以上のノードを追加することで拡張できます。これらのNPMノードは http://flows.nodered.org で閲覧できます 64 | 65 | このステップでは、Node-RED Dashboard ノードを Internet of Things Starter アプリケーションに追加します。 66 | 67 | * 右上のNode-RED Menu **(1)** をクリックし、Manage palette **(2)** をクリックします。 68 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-palette.png) 69 | * Install tab **(3)** を選択し、"node-red-dashboard" **(4)** と入力し、Install **(5)** ボタンをクリック。 70 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-nodeinstall.png) 71 | * 次に表示されたダイアログでも Install ボタンをクリック。 72 | * 同様に **node-red-contrib-particle** と **node-red-contrib-web-worldmap** もインストールする。 73 | 74 | ### GitHub から事前に作成されたフローをインポートする 75 | 76 | Node-RED ノードを設定してそれらをまとめて配線するためには、スクリーンショットで文書化するための多くのステップが必要です。事前に作成されたフローを IoT スターターアプリケーションにインポートすることで、フローを簡単に作成できます。 77 | 78 | * 以降のセクションのいくつかには **コードを取得** のリンクがあります。 79 | 80 | * 指示があったら、**コードを取得** する GitHub URLを開き、マークを付けるか Ctrl-A を押してすべてのテキストを選択し、フローのテキストをクリップボードにコピーします。 81 | 82 | * Node-RED Menu **(6)** をクリックし、Import **(7)** をクリックし、Clipboard **(8)** をクリック。 83 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-import.png) 84 | 85 | * フローのテキストを **Import nodes** ダイアログにペーストし、赤い **Import** ボタンをクリック。 86 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-pastefromclipboard.png) 87 | 88 | * 新しいフローは、Node-RED Editor の **新しいタブ** にインポートされます。 89 | 90 | ## 生鮮品のブロックチェーンと Node-RED フローを初期化する 91 | 92 | ### 前書き 93 | 94 | このフローは、他のすべてのフローを駆動するいくつかのグローバル変数を設定します。 Hyperledger Fabric IP アドレス、Particle Electron デバイスID、アクセストークンなどを変更するために他のフローを検索する代わりに、このフローではグローバル値として事前にプルしておき、残りのフローでは単にそれを利用します。 95 | 96 | * 自身の [Hyperledger Fabric](../Blockchain/README.md) を設定している場合は、**Set HyperLedgerFabricIP** Changeノードを編集し、パブリックIPアドレスを挿入します。 97 | * Particle Electron を購入した場合は、Particle デバイスIDとアクセストークンを知り、その詳細を **Particle Electron to Monitor** Changeノードに挿入する必要があります。 98 | * あなたがワークショップに参加している場合、インストラクターは Particle デバイスIDとアクセストークンを別のスライド (GitHubには含まれません) で共有します。 99 | 100 | 初期化フローでは、デモとワークショップを実行するために、以下で説明するほとんどすべてのフローに対してリンクノードを使用します。 101 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-InitPerishableBlockchain.png) 102 | 103 | 最初のステップとして、コードを GitHub からクリップボードにコピーし、Node-RED エディタにインポートしてみましょう。 104 | 105 | **コードを取得** [IoT Asset Tracker Node-RED flows](flows/IoTAssetTracker-AllFlows.json) 106 | 107 | ## Particle Electron イベントの制御 108 | 109 | ### 前書き 110 | 111 | このフローは、Particle Electron デバイスの構成を制御します。 112 | このフローは、デバイスの地理ロケーションレポートを有効または無効にするコマンドを送信できます。 113 | レポートの間隔を変更することができ、デフォルトは60秒です。 114 | また、Particle の2つの照会機能、GetRecentXYZ() と GetCurrTemp()も実行します。 115 | 加速度のしきい値は、SetXYZThresh() の呼び出しによってリモートで設定することもできます。 116 | 117 | Particle.io URL関数呼び出しは、アクセストークンを使用して特定のデバイスを制御します。 118 | 最初のタブの InitPerishableBlockchain フローにアクセストークンが設定されています。 119 | 講師はワークショップの後にこのアクセストークンをリセットします。 120 | 121 | このダッシュボードのインスピレーションは Hovig Ohannessian のものでした。 122 | 彼は、[Particle Core Bluemix article](https://www.ibm.com/blogs/bluemix/2015/05/led-hello-world-with-spark-core-android-bluemix/) を書きました。 123 | これはパラメーターを設定し、**httpリクエストノード** を使用して Particle 関数コマンドをポストするものです。 124 | 125 | 私は Node-RED Particle Function ノードも試しましたが、このユースケースでは柔軟性がありませんでした。 126 | フロー がParticle デバイスIDまたはアクセストークンを動的に設定できませんでした。 127 | ドロップダウンから選択可能な複数の Particle デバイスがある場合、Node-RED Particle Function ノードは特定のデバイスにハードコードされます。 128 | IoT 資産トラッカーのプロトタイプ作成には Particle Electron が1個しかないかもしれませんが、デプロイを開始するときには数十〜数百個になる可能性があります。 129 | 本番用のデプロイでは MQTT に切り替えることをお勧めします。 130 | 131 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-dashboard-ControlParticleDevice.png) 132 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-ControlParticleDevice.png) 133 | 134 | ## Particle Electron イベントの受信 135 | 136 | ### 前書き 137 | 138 | Particle Receiver フローでは、**node-red-contrib-particle** ノードを使用します。ParticleSSE ノードを使用すると、永続的な接続を介して Particle クラウド上の着信サーバー受信イベント (SSE: Server-Sent Events) を購読できます。 139 | 140 | このフローには 4つの ParticleSSE() ノードがあります。 141 | それぞれは、InitPerishableBlockchain フローによって設定されたデバイスIDとアクセストークンを必要としています。 142 | 143 | * 最初の ParticleSSE() ノードは、Google Maps ジオロケーションイベントが有効になっていることを確認し、 Particular Electron の deviceLocator イベントにサブスクライブします。フローはこの情報で何もしません。これは単なる健全性のチェックです。 144 | 145 | * 一番下の ParticleSSE()ノードは、ジオロケーションイベント メッセージを解析して試します。 フローはこの情報で何もしません。 146 | 147 | * 間にある ParticlesSSE() ノードは、Particle Electron の AssetTrackerAccelerationEvent関数 と AssetTrackerTemperatureEvent 関数を購読しています - これらに関しては [WatsonIoTAssetTracker program のドキュメント](../ParticleElectron/README-ja.md) を見直してください。 148 | この情報は文字列から JSON オブジェクトに変換され、解析され、ブロックチェーン イベントに必要な msg.payload に再フォーマットされます。デバイスの GPS 座標が移動していない場合は、Exception ノードによる報告でイベントが破棄されます。この決定は単に、私が動作している装置のみの環境センサーの状態を気にしていたからです (そして、席に座って作業している間、テスト目的には、全てを扱うとデータ量が多すぎたので)。 実際の実装では、デバイスが流通センターの駐車場またはポートに置かれている間に温度と加速度のイベントが気になることがあります。 多くの場合、AssetTrackerAccelerationEvent 関数と AssetTrackerTemperatureEvent 関数は、deviceLocator コールバックによってほぼ同時にトリガーされます。 フローは、ブロックチェインがずらして少しずつ書き込むことで、Hyperledger Fabric に (書き込み障害を引き起こす可能性があるような) 大きな負荷をかけることが防ぎます。 149 | 150 | 151 | まとめると、このフローは到着するデータを取り込み、再フォーマットし、次のフローを呼び出して、Particle イベントを Hyperledger 生鮮品のネットワーク ブロックチェーンのトランザクション履歴に書き込みます。 152 | 153 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-ReceiveParticleEvents.png) 154 | 155 | ## Particle イベントを Hyperledger 生鮮品のネットワーク ブロックチェーンに書き込む 156 | 157 | ### 前書き 158 | 159 | このフローは、Hyperledger Perishable Network REST API を呼び出すための http パラメータを設定します。 160 | このワークショップの [Blockchain README](../Blockchain/README-ja.md) セクションで Hyperledger 生鮮品のネットワークモデルについて学んでください。 161 | このフローには6つの REST API の例があります。 162 | 163 | * 最初の REST API が SetupDemo API を呼び出します。これは一度だけ呼び出す必要があります。ブロックチェーンモデル [chaincode logic.js](../Blockchain/IoT-Perishable-Network/logic.js) の中に埋め込まれている場合、出荷IDとして Particle デバイスIDを挿入する必要がある setupDemo() 関数があります。 164 | * 2番目のセクションでは、トランザクションとして温度イベントをブロックチェーンに書き込むために必要な POST コマンドを設定します。 165 | * 3番目のセクションでは、ブロックチェーン上のすべての温度トランザクションを照会するために必要な GET コマンドを設定します。 166 | * 4番目のセクションでは、Acceleration イベントをトランザクションとしてブロックチェーンに書き込むために必要な POST コマンドを設定します。 167 | * 5番目のセクションでは、ブロックチェーン上のすべてのアクセラレーショントランザクションを照会するために必要な GET コマンドを設定します。 168 | * 6番目のセクションでは、トランザクションとしてジオロケーション イベントをブロックチェーンに書き込むために必要な POST コマンドを設定します。温度および加速度イベントには、関連付けられたジオロケーション座標があるため、このトランザクション履歴は使用されません。 169 | 170 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-WriteParticleEvents2Blockchain.png) 171 | 172 | ## 生鮮品のネットワーク ブロックチェーンのトランザクション履歴をロードする 173 | 174 | ### 前書き 175 | 176 | 生鮮品のネットワーク ブロックチェーンのトランザクション履歴をロードするフローは、このプログラムとワークショップの資産トラッカー ダッシュボード実装に固有のものになりそうです。温度ブロックチェーンのトランザクション履歴を照会し、加速度ブロックチェーンのトランザクション履歴を **配列** にマージし、マップを駆動します。 177 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-LoadBlockchainTransactionHistory.png) 178 | 179 | 180 | ## 資産トラッカーダッシュボードを開発する 181 | 182 | ### 前書き 183 | 184 | このフローは、IoT 環境センサーの読み取り値を収集しながら、デバイスの輸送 (トラック、車、船舶経由) が行ったルートの移動を選択および制御するためのさまざまな Node-RED Dashboard UI要素を構築します。Particle Electron 資産トラッカーデバイスは、異なる日に旅行をする可能性があるため、地図パスを絞り込む日付選択ツールがあります。マップ上にピンとジオフェンスを表示するための一連のフロー ロジックがあります。 185 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-AssetTrackerDashboardControls.png) 186 | 187 | 188 | ## 追跡されたデバイスをマップ上で移動する 189 | 190 | ### 前書き 191 | 192 | この最後のフローは、選択された Particle Electron IoT 資産トラッカーデバイスの移動中にその動きを駆動します。1秒に1回、マップ上のデバイスを進めます。これは、選択されたデバイスと時間枠で配列をフィルタリングします。これらの配列を管理するより良い方法があるかもしれません。数十のルートの後で、おそらく縮尺は変わっていないでしょう。それは素晴らしいデモとワークショップになります。 常に企業スケールでの規模の改善の余地があります。楽しみましょう! 193 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-AssetTrackerMap.png) 194 | 195 | ## おめでとうございます! これでこの IBM コードパターンのワークショップは完了です 196 | 197 | あなたは、Hyperledger Blockchain にデータを格納する環境センサーを備えた IoT 資産トラッカーを構築しました。 198 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-dashboard-AssetTracker-NJ.png) 199 | -------------------------------------------------------------------------------- /Node-RED/README.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [日本語](README-ja.md).* 2 | 3 | # Node-RED - IoT Asset Tracker 4 | ## Node-RED - IoT Asset Tracker Introduction 5 | 6 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-dashboard-AssetTracker-PR.png) 7 | 8 | These Node-RED program flows implement an IoT Asset Tracker that receives geolocation and environmental sensor data from a Particle Electron, stores that information in a Hyperledger Fabric blockchain and visualizes the routes of the IoT devices on a map / dashboard. It triggers alerts when environmental thresholds are exceeded. 9 | 10 | During this workshop you will copy the flow from github and deploy it into your to Watson IoT / Node-RED Starter application running on IBM Cloud. 11 | 12 | These seven flows perform the following functions: 13 | 14 | * **Initialize Blockchain and Node-RED variables** - Set some globals that drive all of the flows. 15 | * **Control a Particle Electron** - A Node-RED Dashboard which enables / disables / configures a Particle Electron. 16 | * **Receive Particle Electron events** - subscribe to Particle Electron event handlers. 17 | * **Write Particle Electron data** to a Hyperledger Fabric Blockchain. 18 | * **Load Blockchain Transaction History** so the IoT device routes can be plotted 19 | * **Build a Dashboard** that controls the visualization of devices. 20 | * **Move a IoT asset along its recorded history** by visualizing the route on a map. 21 | 22 | The dashboards are not intended to be a fancy user experience for end users. These dashboards are demonstrations for a developer of what an IoT Asset Tracker might be capable of. End users are not likely to be interested in geolocation coordinates. 23 | 24 | ## Getting started with Node-RED in the IBM Cloud 25 | Before you can deploy the IoT Asset Tracker dashboard, you need to create an IoT Starter application in the IBM Cloud. This section walks you through those steps. 26 | ### Create an Internet of Things Starter App 27 | * Create an account and log into [IBM Cloud](http://bluemix.net) 28 | * Click on the Catalog **(1)** and search for 'internet of things' **(2)** 29 | * The Internet of Things Platform Starter **(3)** boilerplate is a pattern with pre-assembled services that work together. The Internet of Things Platform Starter includes a Node-RED Node.js web server, Cloudant database to store the flow, and the IoT platform service so you can connect devices. 30 | ![IBM Cloud Node-RED IoT Starter screenshot](screenshots/IBMCloud-Catalog-newstarter-annotated.png) 31 | * Name your application something unique. If you choose myapp, your application will be located at http://myapp.mybluemix.net There can only be one “myapp” application and URL registered in IBM Cloud. 32 | * Give the application a unique name **(4)** - eg. IoTAssetTracker-yourname 33 | * Press the Create button **(5)**. 34 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-CFappcreate.png) 35 | * IBM Cloud will create an application in your account based on the services in the boilerplate. This is called staging an application. It can take a few minutes for this process to complete. While you wait, you can click on the Logs tab and see activity logs from the platform and Node.js runtime. 36 | 37 | ### Launch the IoT Starter Application 38 | Once the Green “Running” icon appears, Click the Visit App URL link **(6)** 39 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-launch.png) 40 | 41 | ### Open the Node-RED visual programming editor 42 | A new browser tab will open to the Node-RED start page. Node-RED is an open-source Node.js application that provides a visual programming editor that makes it easy to wire together flows. Select a username / password to access the Node-RED editor. Remember your username / password. Click the red button. Go to your Node-RED flow editor to launch the editor. 43 | * The Node-RED Visual Programming Editor will open with a default flow. 44 | * On the left side is a palette of nodes that you can drag onto the flow. 45 | * You can wire nodes together to create a program. 46 | * The sample IoT Starter flow is not applicable to this workshop and can be deleted. 47 | * We will import the flows discussed above. 48 | 49 | ### Install Additional Node-RED nodes 50 | The IoT Starter Application deployed into IBM Cloud includes just a small subset of Node-RED nodes. The Node-RED palette can be extended with over one thousand additional nodes for different devices and functionality. These NPM nodes can be browsed at http://flows.nodered.org 51 | 52 | In this Step, you will add the Node-RED Dashboard nodes to your Internet of Things Starter Application. 53 | * Click on the Node-RED Menu **(1)** in the upper right corner, then Manage palette **(2)** 54 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-palette.png) 55 | * Turn to the Install tab **(3)**, type node-red-dashboard **(4)** and press the Install button **(5)**. 56 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-nodeinstall.png) 57 | * Press the Install button in the next dialog. 58 | * Repeat **(4)** to install **node-red-contrib-particle** and **node-red-contrib-web-worldmap** nodes. 59 | 60 | ### Import a prebuilt flow from GitHub 61 | Since configuring Node-RED nodes and wiring them together requires many steps to document in screenshots, there is an easier way to build a flow by importing a prebuilt flow into your IoT Starter Application. 62 | 63 | * Some of the sections below will have a **Get the Code** link. 64 | 65 | * When instructed, open the **Get the Code** github URL, mark or Ctrl-A to select all of the text, and copy the text for the flow to your Clipboard. 66 | * Click on the Node-RED Menu **(6)**, then Import **(7)**, then Clipboard **(8)**. 67 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-import.png) 68 | * Paste the text of the flow into the **Import nodes** dialog and press the red **Import** button. 69 | ![IBM Cloud Node-RED Starter screenshot](screenshots/IBMCloud-NodeRED-pastefromclipboard.png) 70 | * The new flow will be imported into **new tabs** in the Node-RED Editor. 71 | 72 | ## Initialize the Perishable Blockchain / Node-RED flow 73 | ### Introduction 74 | This flow sets several global variables that drive all of the other flows. Instead of hunting through the other flows to modify the Hyperledger Fabric IP address or your Particle Electron Device ID and access token, this flow simply pulls the globals forward and initializes the remaining flows. 75 | 76 | * If you have set up your [Hyperledger Fabric](../Blockchain/README.md), edit the **Set HyperLedgerFabricIP** change node and insert the public IP address. 77 | * If you purchased your own Particle Electron, you will need to know the Particle Device ID and Access Token and insert those details into the **Particle Electron to Monitor** change node. 78 | * If you are participating in a workshop, the instructor will share the Particle Device ID and Access Token in a separate slide (not part of GitHub) 79 | 80 | The Initialization flow then uses Link nodes to most all of the other flows described below to drive the demo and workshop. 81 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-InitPerishableBlockchain.png) 82 | 83 | As a first step, copy the code from GitHub to your Clipboard and import it into your Node-RED editor. 84 | 85 | Get the Code [IoT Asset Tracker Node-RED flows](flows/IoTAssetTracker-AllFlows.json) 86 | 87 | ## Control Particle Electron events 88 | ### Introduction 89 | This flow controls the Particle Electron device configuration. This flow can send a command to enable / disable the device geolocation reporting. It can change the interval of the report. The default is 60 seconds. It also exercises the two query Particle Functions - GetRecentXYZ() and GetCurrTemp(). The acceleration threshold can also be remotely configured through a call to SetXYZThresh(). 90 | 91 | The Particle.io URL function calls use a AccessToken to control a particular device. The AccessToken is set in the InitPerishableBlockchain flow (on the first tab) The instructor will reset this access token after the workshop. 92 | 93 | The inspiration for this dashboard came from Hovig Ohannessian. He wrote a [Particle Core Bluemix article](https://www.ibm.com/blogs/bluemix/2015/05/led-hello-world-with-spark-core-android-bluemix/) 94 | that sets up the params and uses a **http request node** to post the Particle function command. 95 | 96 | I also experimented with the Node-RED Particle Function nodes but I found them inflexible in this use case. The flow could not dynamically set the Particle Device ID or AccessToken. When there are multiple Particle devices selectable from the drop down, the Node-RED Particle Function nodes are hard coded to specific devices. While you might only have one Particle Electron for prototyping an IoT Asset Tracker, when you start a deployment, you might have dozens / hundreds. I would recommend switching to MQTT for production deployments. 97 | 98 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-dashboard-ControlParticleDevice.png) 99 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-ControlParticleDevice.png) 100 | 101 | ## Receive Particle Electron events 102 | ## Introduction 103 | The Particle Receiver flow uses the **node-red-contrib-particle** nodes. The ParticleSSE node lets you subscribe to incoming server-sent events (SSE) on a Particle cloud via a persistent connection. 104 | 105 | There are four ParticleSSE() nodes on this flow. Each needs to be configured with a Device ID and an AccessToken - set by the InitPerishableBlockchain flow. 106 | * The first ParticleSSE() node just confirms that there is a Google Maps geolocation Event enabled and subscribes to the deviceLocator event on a particular Electron. The flow doesn't do anything with this information. It's just a sanity check. 107 | * The bottom ParticleSSE() node experiments with parsing the geolocation event message. The flow doesn't do anything with this information. 108 | * The middle ParticleSSE() nodes subscribe to the AssetTrackerAccelerationEvent and AssetTrackerTemperatureEvent functions of our Particle Electron - review the [WatsonIoTAssetTracker program here](../ParticleElectron/README.md). This information is converted from a string to a JSON object, parsed and reformatted into a msg.payload that is expected for a Blockchain event. If the device GPS coordinates have not moved, discard the event by using a Report By Exception node. This decision was simply because I only care about the environmental sensor conditions of the device in motion (and it was filling my blockchain while sitting on my desk). A real implementation might care about temperature and acceleration events while the device sits in a distribution center parking lot or port. Often the AssetTrackerAccelerationEvent and AssetTrackerTemperatureEvent functions are triggered nearly simultaneously by the deviceLocator callback. The flow staggers the blockchain writes a little to avoid overwhelming the Hyperledger Fabric (which could cause a write failure). 109 | 110 | In summary, this flow takes the arriving data, reformats it and calls the next flow to write the Particle Events to the Hyperledger Perishable Network blockchain transaction history. 111 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-ReceiveParticleEvents.png) 112 | 113 | ## Write Particle Events to Hyperledger Perishable Network Blockchain 114 | ### Introduction 115 | This flow sets up the http parameters to call the Hyperledger Perishable Network REST APIs. Learn about the Hyperledger Perishable Network model in the [Blockchain README](../Blockchain/README.md) section of this workshop / IBM Code pattern. There are six REST API examples in this flow. 116 | * The first REST API calls the SetupDemo API. This only needs to be called once. Buried deep in the Blockchain Model [chaincode logic.js](../Blockchain/IoT-Perishable-Network/logic.js), there is a setupDemo() function where you will need to insert your Particle Device ID as the Shipment ID 117 | * The second section sets up the POST command required to write a Temperature event into the blockchain as a transaction. 118 | * The third section sets up the GET command required to query all of the Temperature transactions on the blockchain. 119 | * The fourth section sets up the POST command required to write an Acceleration event into the blockchain as a transaction. 120 | * The fifth section sets up the GET command required to query all of the Acceleration transactions on the blockchain. 121 | * The sixth section sets up the POST command required to write a geolocation event into the blockchain as a transaction. The flow does not use this transaction history because the Temperature and Acceleration events have geolocation coordinates associated with them. 122 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-WriteParticleEvents2Blockchain.png) 123 | 124 | ## Load Perishable Network Blockchain Transaction History 125 | ### Introduction 126 | The Load Perishable Network Blockchain Transaction History flow starts to become specific to the Asset Tracker dashboard implementation of this program and workshop. It queries the Temperature blockchain transaction history and then merges the Acceleration blockchain transaction history into an **array** that will drive the map. 127 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-LoadBlockchainTransactionHistory.png) 128 | 129 | 130 | ## Build an Asset Tracking Dashboard 131 | ### Introduction 132 | This flow constructs a variety of Node-RED Dashboard UI elements to select and control the movement of the routes that the device shipment (via trucks, cars, ships) took while collecting IoT environmental sensor readings. A Particle Electron asset tracking device might take trips on different days so there is a date picker to narrow the map paths. There is a bunch of flow logic to display pins and geo fences on the map. 133 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-AssetTrackerDashboardControls.png) 134 | 135 | 136 | ## Move the Tracked Device on a Map 137 | ### Introduction 138 | This final flow drives the movement of a selected Particle Electron IoT AssetTracker device during its journey. Every fraction of a second, it advances the device on a map. It filters the array down to the selected device and time frame. There might be better ways to manage these arrays. After a few dozen routes, it probably doesn't scale. It makes for a great demo and workshop. There's always room for enterprise scale improvements. Enjoy! 139 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-flow-AssetTrackerMap.png) 140 | 141 | ## Congratulations! You have completed the Workshop / IBM Code Pattern 142 | You've built an IoT Asset Tracker with environmental sensors that store data in a Hyperledger Blockchain. 143 | ![IoT Asset Tracker Node-RED flow screenshot](screenshots/Node-RED-dashboard-AssetTracker-NJ.png) 144 | -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-Catalog-newstarter-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-Catalog-newstarter-annotated.png -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-NodeRED-CFappcreate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-NodeRED-CFappcreate.png -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-NodeRED-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-NodeRED-import.png -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-NodeRED-launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-NodeRED-launch.png -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-NodeRED-nodeinstall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-NodeRED-nodeinstall.png -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-NodeRED-palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-NodeRED-palette.png -------------------------------------------------------------------------------- /Node-RED/screenshots/IBMCloud-NodeRED-pastefromclipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/IBMCloud-NodeRED-pastefromclipboard.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-dashboard-AssetTracker-NJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-dashboard-AssetTracker-NJ.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-dashboard-AssetTracker-PR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-dashboard-AssetTracker-PR.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-dashboard-ControlParticleDevice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-dashboard-ControlParticleDevice.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-AssetTrackerDashboardControls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-AssetTrackerDashboardControls.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-AssetTrackerMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-AssetTrackerMap.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-ControlParticleDevice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-ControlParticleDevice.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-InitPerishableBlockchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-InitPerishableBlockchain.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-LoadBlockchainTransactionHistory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-LoadBlockchainTransactionHistory.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-ReceiveParticleEvents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-ReceiveParticleEvents.png -------------------------------------------------------------------------------- /Node-RED/screenshots/Node-RED-flow-WriteParticleEvents2Blockchain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/Node-RED/screenshots/Node-RED-flow-WriteParticleEvents2Blockchain.png -------------------------------------------------------------------------------- /ParticleElectron/README-ja.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [English](README.md).* 2 | 3 | # Particle Electron 資産トラッカー 4 | 5 | Particle Electron 資産トラッカーを使用すると、環境センサーデータを収集し、GPSまたはセルラー三角測量を使用してその位置を計算し、両方のデータイベントを Particle Functions を使用して Particle.io コンソールに送信することができます。 6 | 物理的なものが過酷な環境条件にさらされた時、**Where、What、When** の情報を知ることにより、多くのビジネスプロセスを改善することができます。 7 | 8 | このセクションでは以下を確認します: 9 | * Particle Electron 資産トラッカーのハードウェア構成 10 | * Particle ソフトウェア ツールチェーン 11 | * Watson IoT Asset Tracker プログラムは、温度と加速度計のデータを問い合わせ、クラウドに報告します 12 | 13 | ## Particle Electron Asset Tracker v2 14 | ![Electron Asset Tracker](https://docs.particle.io/assets/images/shields/asset-tracker-shield-v2/asset.png "Particle Electron picture") 15 | 16 | [Particle Electron Asset Tracker v2](https://store.particle.io/products/asset-tracker) ボードでは、uBlox M8 GNSS GPS レシーバーと Adafruit LIS3DH Triple Axis 加速度計を Particle Electron に接続することができます。 17 | Grove センサーを接続することもできます。 18 | 19 | ## Particle Electron ソフトウェア ツールチェーン 20 | 1. http://login.particle.io/ サイトで自身の Particle.io アカウントを設定する。 21 | 2. 自身の Particle Electron を起動し名前をつける。 22 | * 私の Electron は `blockchain-iot-asset-tracker1` です。 23 | 3. SIM を起動する。 24 | 4. 自身の Particle Electron を登録すると、[Particle Devices Console](https://console.particle.io/devices) に表示される。 25 | 5. Particle.io の提供する [Particle Build WebIDE](https://docs.particle.io/guide/getting-started/build/core/) か CLI コマンドライン toolchain を使用する。 26 | 6. 私は [WebIDE](https://build.particle.io/) に関して以下のサンプルを使用して少し学びました: 27 | * LEDをブレッドボードに配線し、blink-led プログラムで点滅させてみた 28 | * ウェブ接続の LED サンプルアプリケーションを試してみた 29 | * Cloud2LED.bin を変更して Particle クラウドから LED の On/Off を Electron に送信してみた。 30 | 私はそれを大文字と小文字を区別しないよう、"on/off" と "ON/OFF" を共に認識するよう簡単な改造をしてみました! 31 | 32 | 7. [Particle Functions](https://docs.particle.io/reference/firmware/core/#particle-function-) を読むと、イベントを公開して購読できるようになります。 33 | 8. 私は Web IDE よりコマンドラインインターフェースを好むので、ガイドに従って、[Particle CLI]( https://docs.particle.io/guide/tools-and-features/cli/electron/) をインストールしました。 34 | ``` 35 | $ particle login 36 | $ particle upgrade 37 | ``` 38 | [ファームウェアのアップグレード](https://docs.particle.io/guide/tools-and-features/firmware-manager/electron/) は、Google Map ジオロケーションデバイスのロケータを機能させるために重要でした。私の Particle Electron は v0.4.9 が工場出荷時にインストールされていましたが、v0.6.4にアップグレードすると Google Maps 機能が機能するようになりました。 39 | 40 | 9. 次のステップとして [particle compile]( https://docs.particle.io/reference/cli/#particle-compile) コマンドを学びます。 41 | ``` 42 | $ particle compile 43 | ``` 44 | 私の場合は: 45 | ``` 46 | $ particle compile electron WatsonIoTAssetTracker --saveTo WatsonIoTAssetTracker.bin 47 | ``` 48 | 10. あなたの Particle プロジェクトで利用できる多くの Arduino 用の [Particle ライブラリ](https://docs.particle.io/guide/tools-and-features/libraries/) があります。 49 | ``` 50 | $ particle library list 51 | $ particle library view AssetTracker 52 | $ particle library view OneWire 53 | ``` 54 | 11. あなたの Particle Electron を書き換えるためには、 [dfu-util](https://docs.particle.io/faq/particle-tools/installing-dfu-util/core/) をインストールする必要があります。私は Fedora 25 リポジトリにある *dfu-util-0.9-1.fc25.x86_64.rpm* を使用しました。 55 | 12. Electron のリセットボタンとモードボタンを押したままにして 56 | * リセットボタンをはなす 57 | * LEDが黄色になるのを待つ 58 | * モードボタンをはなす 59 | 13. 最後に、次のコマンドを使用してプログラムをボードに書き込みます: 60 | ``` 61 | $ particle flash --usb firmware.bin 62 | ``` 63 | 私の場合は: 64 | ``` 65 | $ particle flash --usb WatsonIoTAssetTracker.bin 66 | ``` 67 | 14. プログラムが何をしているかを見るには、[Particle serial](https://docs.particle.io/reference/firmware/photon/#serial) 出力を監視するようにUSBケーブルを設定します。rickkas7 が素晴らしい [Particle serial チュートリアル](https://github.com/rickkas7/serial_tutorial) を書きました。 68 | ``` 69 | $ particle serial monitor 70 | ``` 71 | 72 | ## Watson IoT Asset Tracker プログラム 73 | 74 | このリポジトリにある Watson IoT Asset Tracker プログラムの実装を見てみましょう。温度と加速度計のデータを要求し、その位置とともにクラウドに報告します。 75 | 76 | このリポジトリで [WatsonIoTAssetTracker.ino](WatsonIoTAssetTracker.ino) コードを取得し、以下のレビューに従ってください。 77 | これは [Particle Simple project](https://docs.particle.io/guide/tools-and-features/libraries/#project-file-structure) ですので、[project.properties](project.properties) ファイルもリポジトリからダウンロードする必要があります。これには、プログラムをコンパイルするために必要なライブラリのリストが含まれています。 78 | 79 | > 訳注: INO ファイルは Arduino Sketch File 形式で、Arduino ベースの IoT 機器上で動作するプログラムです。 80 | 81 | ### ```void setup()``` 82 | 83 | この Arduino プログラムのもっとも興味深いのは ``setup()`` で、温度と加速度センサーのデータを送信して問い合わせる4つの Particle 関数を宣言しています。 84 | 85 | ``` C 86 | // Declare a Particle.function so that we can adjust the Asset Tracking on and off reporting interval from the cloud. 87 | Particle.function("SetInterval",AssetTrackerSetReportInterval); 88 | 89 | // Declare a Particle.function so that we can query the current temperature from the cloud. 90 | Particle.function("GetCurrTemp",AssetTrackerGetCurrentTemp); 91 | 92 | // Declare a Particle.function so that we can adjust the accelerometer threshold from the cloud. 93 | Particle.function("SetXYZThresh",AssetTrackerSetAccelThresh); 94 | 95 | // Declare a Particle.function so that we can query recent accelerometer data from the cloud. 96 | Particle.function("GetRecentXYZ",AssetTrackerGetRecentAccel); 97 | ``` 98 | 99 | このプログラムの次の興味深い点は、[Google Maps Locator API](https://docs.particle.io/tutorials/integrations/google-maps/) を使用して、Cellular タワーの信号強度に基づいて地理的位置を三角測量することです。 100 | Google は、Cellular タワーの位置 (ヒント: タワーは移動せず、地面に固定されています) を把握しており、タワーからあなたのデバイスまでの信号の RSSI 強度から、そのおおよその位置を計算することができます。 101 | 都合の良いことに、Particle Electron にはSIMカードがあり、携帯電話網を介して通信することができます。 102 | 103 | Asset Trackerボードで GPS を使用するのは素晴らしいことですが、遮られることもなく、GPS衛星と常に直線的な通信ができる状態を常に保つことは困難でしょう。 104 | また GPS チップセットはかなりのバッテリー電力を消費するので、トラッカーの稼働時間を短くしてしまうでしょう。 105 | 実際、Cellular による三角測量はGPSほど正確ではありません。 106 | しかし、高速道路を走行する際に「どこにいるの?」という質問に答えるほとんどのケースでは、数百メートルの半径で十分なことがほとんどです。 107 | 私は個人的に [Google Maps API Key](https://developers.google.com/maps/documentation/geolocation/get-api-key) を持っています。 108 | これは CellularHelper ライブラリを使用しています。 109 | 110 | ``` 111 | $ particle library view CellularHelper 112 | $ particle library view google-maps-device-locator 113 | ``` 114 | 115 | ### 機能 116 | 117 | プログラムは4つの Particle Function コールバックとヘルパー関数を実装して、加速度センサーと温度センサーを照会します。 118 | 119 | 注目すべきは、もっと洗練された実装でしたが、私は [Grove 温度センサー](http://wiki.seeed.cc/Grove-Temperature_Sensor_V1.2/) を AssetTracker ボードの Grove コネクタと連携させることができませんでした。 120 | 私はいくつかの古き良き Dallas DS18B20 温度センサーを注文しました。 121 | 私は、これらの [チュートリアルの指示](https://docs.particle.io/tutorials/projects/maker-kit/#tutorial-4-temperature-logger) に従って、それらの1つ (と1つの抵抗器) を私の Particle Electron に配線しました。 122 | これは OneWire ライブラリを使用します。 123 | 124 | ### プログラム ロジック 125 | 126 | プログラムは、その場所に応じて設定した間隔で定期的に起動します。 127 | これにより、DeviceLocator イベントがトリガーされます。 128 | Cellular タワーの信号強度を照会し、RSSI データを Google Maps API に送信した後、地理的位置の緯度/経度/確度など座標情報をボードに返信します。 129 | プログラムが座標情報を取得すると、温度を読み取り、加速度計がモーション閾値を超えているかどうかをチェックします。 130 | その後、Particleコールバック関数 *AssetTrackerLocationCallback()* によって3つのデータポイント(**WHERE、WHAT、WHEN**)をクラウドに送信します。 131 | この情報の組み合わせは **IoT 資産トラッカー** の基礎です。 132 | 133 | それをまとめてみると、このように見えます。 134 | ![WatsonIoTAssetTracker board](screenshots/ParticleElectronAssetTracker-IoT.jpg) 135 | 136 | また、提供された Particle 資産トラッカーのケースにうまく収まります: 137 | ![WatsonIoTAssetTracker case](screenshots/ParticleElectronAssetTracker-in-Case.jpg) 138 | 139 | ### クラウドプログラムを有効化して Particle Function コールバックを受け取る 140 | 141 | 最初にデータが Particle コンソールに届くと、あなたはとても喜ぶでしょう。 142 | ここに、[Particle.io](https://console.particle.io/devices) クラウドに到着する温度データ、加速度計データ、および地理位置データのスクリーンショットがあります。 143 | 144 | ![ParticleConsoleDeviceEvents screenshot](screenshots/ParticleConsoleDeviceEvents.png "Particle Console Device Event screenshot") 145 | 146 | あなたが本当にやりたいことは、そのデータをどこか別の場所に送ることです。 147 | 私の場合、IoT データを IBM Cloud および Node-RED にルーティングして、Hyperledger Fabricブロックチェーンに格納する必要があります。 148 | [次のセクション](../Blockchain/README-ja.md) もしくは [Node-REDのセクション](../Node-RED/README-ja.md) にジャンプします。 149 | 150 | 151 | 152 | 移動する前に、Node-RED プログラムがこれらのセンサーイベントを監視/購読することを許可する Particle トークンが必要です。 153 | 154 | ``` 155 | $ particle token list 156 | $ particle token new 157 | ``` 158 | ターミナルから以下のコマンドでデータを参照することができます: 159 | ``` 160 | $ curl https://api.particle.io/v1/devices/events?access_token= 161 | ``` 162 | -------------------------------------------------------------------------------- /ParticleElectron/README.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [日本語](README-ja.md).* 2 | 3 | # Particle Electron Asset Tracker 4 | The Particle Electron Asset Tracker can be used to collect environmental sensor data, calculate its location using GPS or Cellular triangulation and send both data events to the Particle.io console using Particle Functions. The power of knowing **Where, What and When** physical things were subjected to harsh environmental conditions can improve many business processes. 5 | 6 | In this section we will review : 7 | * Particle Electron Asset Tracker hardware configuration 8 | * Particle software toolchain 9 | * A Watson IoT Asset Tracker program to query and report temperature and accelerometer data to the cloud. 10 | 11 | ## Particle Electron Asset Tracker v2 12 | ![Electron Asset Tracker](https://docs.particle.io/assets/images/shields/asset-tracker-shield-v2/asset.png "Particle Electron picture") 13 | 14 | The [Particle Electron Asset Tracker v2](https://store.particle.io/products/asset-tracker) board allows you to connect a Particle Electron with its uBlox M8 GNSS GPS receiver and Adafruit LIS3DH Triple Axis Accelerometer. You can connect Grove Sensors to it as well. 15 | 16 | ## Particle Electron software toolchain 17 | 1. Set up your Particle.io Account at http://login.particle.io/ 18 | 2. Activate your Particle Electron and give it a name. I called my Electron - blockchain-iot-asset-tracker1 19 | 3. Activate the SIM 20 | 4. After I registered my Particle Electron, it appeared in the [Particle Devices Console](https://console.particle.io/devices) 21 | 5. Particle.io provides a [Particle Build WebIDE](https://docs.particle.io/guide/getting-started/build/core/) or a CLI command line toolchain. 22 | 6. I spent some time learning the [WebIDE](https://build.particle.io/) by playing with the samples: 23 | * Wire a LED to the breadboard using the blink-led program 24 | * Web Connected LED sample app 25 | * I modified the Cloud2LED.bin to send LED on/off from Particle cloud down to Electron. I modified it to support case insensitive "on/off" and "ON/OFF" - baby steps! 26 | 7. It's worth reading about [Particle Functions](https://docs.particle.io/reference/firmware/core/#particle-function-) so that you can publish and subscribe to events. 27 | 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. 28 | ``` 29 | $ particle login 30 | $ particle upgrade 31 | ``` 32 | 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. 33 | 34 | 9. The next step was to learn about the [$ particle compile]( https://docs.particle.io/reference/cli/#particle-compile) command 35 | ``` 36 | $ particle compile 37 | ``` 38 | In my case: 39 | ``` 40 | $ particle compile electron WatsonIoTAssetTracker --saveTo WatsonIoTAssetTracker.bin 41 | ``` 42 | 10. There are lots of Arduino / [Particle libraries](https://docs.particle.io/guide/tools-and-features/libraries/) which you can include in your Particle projects. 43 | ``` 44 | $ particle library list 45 | $ particle library view AssetTracker 46 | $ particle library view OneWire 47 | ``` 48 | 11. To flash your Particle Electron, you need to install [dfu-util](https://docs.particle.io/faq/particle-tools/installing-dfu-util/core/). 49 | I grabbed a copy of *dfu-util-0.9-1.fc25.x86_64.rpm* from the Fedora 25 repo. 50 | 12. Hold down both the Reset and Mode buttons on the Electron 51 | * Release the Reset button 52 | * Wait for the LED to turn Yellow 53 | * Release the Mode button 54 | 13. Finally flash your program to the board using the next command 55 | ``` 56 | $ particle flash --usb firmware.bin 57 | ``` 58 | In my case: 59 | ``` 60 | $ particle flash --usb WatsonIoTAssetTracker.bin 61 | ``` 62 | 14. To watch what the program is doing, you can set up the USB cable to monitor the [Particle serial](https://docs.particle.io/reference/firmware/photon/#serial) output. I found that rickkas7 wrote a great [Particle serial tutorial](https://github.com/rickkas7/serial_tutorial) 63 | ``` 64 | $ particle serial monitor 65 | ``` 66 | 67 | ## Watson IoT Asset Tracker program 68 | Let's review the Watson IoT Asset Tracker program implementation found in this repository. It queries and reports temperature and accelerometer data to the cloud along with its location. 69 | 70 | Grab the [WatsonIoTAssetTracker.ino](WatsonIoTAssetTracker.ino) code in this repo to follow along in the review. This is a [Particle Simple project](https://docs.particle.io/guide/tools-and-features/libraries/#project-file-structure) so you will also need to download the [project.properties](project.properties) file from the repo. It includes a list of libraries necessary for the program to compile. 71 | 72 | ### ```void setup()``` 73 | 74 | The most interesting aspect of this Arduino program is that in ```setup()``` I declare four Particle functions to send and query temperature and accelerometer sensor data. 75 | ``` C 76 | // Declare a Particle.function so that we can adjust the Asset Tracking on and off reporting interval from the cloud. 77 | Particle.function("SetInterval",AssetTrackerSetReportInterval); 78 | 79 | // Declare a Particle.function so that we can query the current temperature from the cloud. 80 | Particle.function("GetCurrTemp",AssetTrackerGetCurrentTemp); 81 | 82 | // Declare a Particle.function so that we can adjust the accelerometer threshold from the cloud. 83 | Particle.function("SetXYZThresh",AssetTrackerSetAccelThresh); 84 | 85 | // Declare a Particle.function so that we can query recent accelerometer data from the cloud. 86 | Particle.function("GetRecentXYZ",AssetTrackerGetRecentAccel); 87 | ``` 88 | 89 | The next most interesting thing about the program is that it uses the [Google Maps Locator API](https://docs.particle.io/tutorials/integrations/google-maps/) to triangulate its geo location based on Cellular tower signal strength. Google knows where the cell towers are (hint - they don't move and are cemented to the ground) and the RSSI strength of the signals from the towers to your thing, its a math calculation to approximate your things' location. Nice that the Particle Electron has a SIM card and communicates over the cellular network. While it's great to use the GPS on the Asset Tracker board, often the thing you want to track is deep in a truck or a car or ship without clear line of sight to the Global Navigation Satellite System - rendering GPS useless. The GPS chipset also draws substantial battery power that would be better used to increase the tracker's time between charges. In truth, cellular triangulation is not as accurate as GPS. For most cases of answering "where's the thing" as it drives down the highway, a few hundred meter radius is plenty good enough. I got myself a [Google Maps API Key](https://developers.google.com/maps/documentation/geolocation/get-api-key) It uses the CellularHelper library. 90 | ``` 91 | $ particle library view CellularHelper 92 | $ particle library view google-maps-device-locator 93 | ``` 94 | ### Functions 95 | The program proceeds to implement the four Particle Function callbacks and the helper functions to query the accelerometer and temperature sensors. 96 | 97 | Of note, while it would have been a much cleaner implementation, I could not get the [Grove Temperature sensor](http://wiki.seeed.cc/Grove-Temperature_Sensor_V1.2/) to work with the Grove connectors on the AssetTracker board. I ordered some good old Dallas DS18B20 temperature sensors. I wired one of them (and a resistor) to my Particle Electron following these [tutorial instructions](https://docs.particle.io/tutorials/projects/maker-kit/#tutorial-4-temperature-logger). It uses the OneWire library. 98 | 99 | ### Program Logic 100 | The program wakes up periodically on an interval you set to determine its location. That triggers a DeviceLocator event. After querying cellular tower signal strengths and sending the RSSI data to the Google Maps API, it responds back to the board with geolocation latitude / longitude / uncertainty coordinates. When the program gets the geolocation, it reads the temperature and checks if the accelerometer has exceeded a motion threshold. It then sends three datapoints - **WHERE, WHAT and WHEN** - to the cloud via the Particle callback function *AssetTrackerLocationCallback()* The combination of that information is the basis of an **IoT Asset Tracker**. 101 | 102 | Put it all together and it looks like this. 103 | ![WatsonIoTAssetTracker board](screenshots/ParticleElectronAssetTracker-IoT.jpg) 104 | 105 | It also fits nicely into the provided Particle Asset Tracker case: 106 | ![WatsonIoTAssetTracker case](screenshots/ParticleElectronAssetTracker-in-Case.jpg) 107 | 108 | 109 | ### Enabling your Cloud Programs to intercept your Particle Function callbacks 110 | You'll be all giddy the first time data arrives in the Particle Console. Here's a screenshot of temperature data, accelerometer data and geolocation data arriving in the [Particle.io](https://console.particle.io/devices) cloud. 111 | ![ParticleConsoleDeviceEvents screenshot](screenshots/ParticleConsoleDeviceEvents.png "Particle Console Device Event screenshot") 112 | 113 | What you really want to do is send that data somewhere else. In my case, I want to route the IoT data to the IBM Cloud and Node-RED for storage in a Hyperledger Fabric blockchain. Jump to the next [section](../Node-RED/README.md). 114 | 115 | Before you go, you'll need a Particle token to authorize your Node-RED program to observe / subscribe to these sensor events. 116 | ``` 117 | $ particle token list 118 | $ particle token new 119 | ``` 120 | You can see the data in your terminal 121 | ``` 122 | $ curl https://api.particle.io/v1/devices/events?access_token= 123 | ``` 124 | -------------------------------------------------------------------------------- /ParticleElectron/WatsonIoTAssetTracker.ino: -------------------------------------------------------------------------------- 1 | // Library dependencies to be added to the Particle Simple project.properties 2 | // dependencies.Adafruit_LIS3DH=1.0.3 3 | // dependencies.Adafruit_GPS=1.0.3 4 | // dependencies.AssetTracker=0.0.10 5 | // dependencies.CellularHelper=0.0.4 6 | // dependencies.OneWire=2.0.1 7 | // dependencies.Adafruit_Sensor=1.0.2 8 | // dependencies.google-maps-device-locator=0.0.4 9 | #include 10 | #include 11 | #include 12 | 13 | // Dallas DS18B20 initialization 14 | OneWire ds = OneWire(D4); // 1-wire signal on pin D4 15 | float lastTemp; 16 | 17 | // Adafruit LIS3DH Triple Axis Accelerometer on the Particle Asset Tracker v2 PCB 18 | // Accelerometer Threshold to trigger a publish 19 | // 9000 is very sensitive, 12000 will detect small bumps 20 | int AccelThreshold = 12000; 21 | String MaxAccelJSON; 22 | int MaxAccelThisInterval = 0; 23 | 24 | // Creating an AssetTracker named 't' 25 | GoogleMapsDeviceLocator locator; 26 | AssetTracker t = AssetTracker(); 27 | int ledonboard = D7; // Light the onboard Particle LED when in Tracking mode 28 | 29 | void setup() { 30 | // Sets up all the necessary AssetTracker bits 31 | t.begin(); 32 | 33 | Serial.begin(9600); 34 | 35 | // Declare a Particle.function so that we can adjust the Asset Tracking on and off reporting interval from the cloud. 36 | Particle.function("SetInterval",AssetTrackerSetReportInterval); 37 | 38 | // Declare a Particle.function so that we can query the current temperature from the cloud. 39 | Particle.function("GetCurrTemp",AssetTrackerGetCurrentTemp); 40 | 41 | // Declare a Particle.function so that we can adjust the accelerometer threshold from the cloud. 42 | Particle.function("SetXYZThresh",AssetTrackerSetAccelThresh); 43 | 44 | // Declare a Particle.function so that we can query recent accelerometer data from the cloud. 45 | Particle.function("GetRecentXYZ",AssetTrackerGetRecentAccel); 46 | 47 | 48 | // Set the returned location handler function by the locationCallback() method 49 | // Initialize the Asset Tracker to check in once a Day 60*60*24 50 | locator.withSubscribe(AssetTrackerLocationCallback).withLocatePeriodic(86400); 51 | 52 | // Give this Electron a name so we can identify it 53 | // locator.withEventName("blockchain-iot-asset-tracker1"); 54 | // locator.withLocatePeriodic(60); 55 | 56 | // LED pin configuration 57 | pinMode(ledonboard, OUTPUT); 58 | 59 | // Turn off LED on the Particle board when the application starts 60 | digitalWrite(ledonboard, LOW); 61 | } 62 | 63 | 64 | // Remotely change the accelerometer trigger threshold 65 | int AssetTrackerSetAccelThresh( String command ) { 66 | // Try to convert Srting to an integer 67 | int NewAccelThreshold = command.toInt(); 68 | // Disgard any non-integer command strings sent from the cloud 69 | if ( NewAccelThreshold > 0) { 70 | AccelThreshold = NewAccelThreshold; 71 | Serial.print("Accelerometer Threshold now set to : "); 72 | Serial.println(command); 73 | return 1; 74 | } 75 | // Keep the predefined Threshold if function received garbage 76 | return 0; 77 | } 78 | 79 | 80 | int AssetTrackerSetReportInterval( String command ) { 81 | /* Particle.functions always take a string as an argument and return an integer. 82 | Since we can pass a string, it means that we can give the program commands on how the function should be used. 83 | In this case, telling the function a string that contains a Number will set the AssetTracker delay 84 | and telling it "off", 0 or some bogus command will turn the AssetTracker off. 85 | Then, the function returns a value to us to let us know what happened. 86 | In this case, it will return : 87 | New Delay value - when the Cellular Asset Tracker is turning on 88 | 0 when the Cellular Asset Tracker is turning off, 89 | */ 90 | int Delay = command.toInt(); 91 | if( Delay > 0 ) { 92 | locator.withSubscribe(AssetTrackerLocationCallback).withLocatePeriodic(Delay); 93 | digitalWrite(ledonboard,HIGH); 94 | Serial.print("Enabling Asset Location reporting interval:"); 95 | Serial.println(command); 96 | return Delay; 97 | } else { 98 | // Any invalid string that doesn't convert to a number or 0 should be considered "Off" 99 | // "once a day" to be sufficiently large to be OFF 100 | locator.withSubscribe(AssetTrackerLocationCallback).withLocatePeriodic(86400); 101 | digitalWrite(ledonboard,LOW); 102 | Serial.println("Disabling Asset Location reporting"); 103 | return 0; 104 | } 105 | 106 | } 107 | 108 | 109 | int AssetTrackerGetCurrentTemp(String Coordinates ) { 110 | byte i; 111 | byte present = 0; 112 | byte type_s; 113 | byte data[12]; 114 | byte addr[8]; 115 | float celsius, fahrenheit; 116 | int init = 0; 117 | 118 | // wait to initialize / find the chip 119 | while( init < 10 ) { 120 | if ( !ds.search(addr)) { 121 | Serial.println("Searching for Temperature Sensor..."); 122 | ds.reset_search(); 123 | delay(250); 124 | init++; 125 | } else { 126 | init = 10; // found 127 | } 128 | } 129 | 130 | // The order is changed a bit in this example 131 | // first the returned address is printed 132 | Serial.print("ROM ="); 133 | for( i = 0; i < 8; i++) { 134 | Serial.write(' '); 135 | Serial.print(addr[i], HEX); 136 | } 137 | 138 | // second the CRC is checked, on fail, 139 | // print error and just return to try again 140 | if (OneWire::crc8(addr, 7) != addr[7]) { 141 | Serial.println("CRC is not valid!"); 142 | return 0; 143 | } 144 | Serial.println(); 145 | 146 | // we have a good address at this point 147 | // what kind of chip do we have? 148 | // we will set a type_s value for known types or just return 149 | 150 | // the first ROM byte indicates which chip 151 | switch (addr[0]) { 152 | case 0x10: 153 | Serial.println(" Chip = DS1820/DS18S20"); 154 | type_s = 1; 155 | break; 156 | case 0x28: 157 | Serial.println(" Chip = DS18B20"); 158 | type_s = 0; 159 | break; 160 | case 0x22: 161 | Serial.println(" Chip = DS1822"); 162 | type_s = 0; 163 | break; 164 | case 0x26: 165 | Serial.println(" Chip = DS2438"); 166 | type_s = 2; 167 | break; 168 | default: 169 | Serial.println("Unknown device type."); 170 | return 0; 171 | } 172 | 173 | // this device has temp so let's read it 174 | ds.reset(); // first clear the 1-wire bus 175 | ds.select(addr); // now select the device we just found 176 | // ds.write(0x44, 1); // tell it to start a conversion, with parasite power on at the end 177 | ds.write(0x44, 0); // or start conversion in powered mode (bus finishes low) 178 | 179 | // just wait a second while the conversion takes place 180 | // different chips have different conversion times, check the specs, 1 sec is worse case + 250ms 181 | // you could also communicate with other devices if you like but you would need 182 | // to already know their address to select them. 183 | delay(1000); // maybe 750ms is enough, maybe not, wait 1 sec for conversion 184 | 185 | // we might do a ds.depower() (parasite) here, but the reset will take care of it. 186 | 187 | // first make sure current values are in the scratch pad 188 | present = ds.reset(); 189 | ds.select(addr); 190 | ds.write(0xB8,0); // Recall Memory 0 191 | ds.write(0x00,0); // Recall Memory 0 192 | 193 | // now read the scratch pad 194 | present = ds.reset(); 195 | ds.select(addr); 196 | ds.write(0xBE,0); // Read Scratchpad 197 | if (type_s == 2) { 198 | ds.write(0x00,0); // The DS2438 needs a page# to read 199 | } 200 | 201 | // transfer and print the values 202 | Serial.print(" Data = "); 203 | Serial.print(present, HEX); 204 | Serial.print(" "); 205 | for ( i = 0; i < 9; i++) { // we need 9 bytes 206 | data[i] = ds.read(); 207 | Serial.print(data[i], HEX); 208 | Serial.print(" "); 209 | } 210 | Serial.print(" CRC="); 211 | Serial.print(OneWire::crc8(data, 8), HEX); 212 | Serial.println(); 213 | 214 | // Convert the data to actual temperature 215 | // because the result is a 16 bit signed integer, it should 216 | // be stored to an "int16_t" type, which is always 16 bits 217 | // even when compiled on a 32 bit processor. 218 | int16_t raw = (data[1] << 8) | data[0]; 219 | if (type_s == 2) raw = (data[2] << 8) | data[1]; 220 | byte cfg = (data[4] & 0x60); 221 | 222 | switch (type_s) { 223 | case 1: 224 | raw = raw << 3; // 9 bit resolution default 225 | if (data[7] == 0x10) { 226 | // "count remain" gives full 12 bit resolution 227 | raw = (raw & 0xFFF0) + 12 - data[6]; 228 | } 229 | celsius = (float)raw * 0.0625; 230 | break; 231 | case 0: 232 | // at lower res, the low bits are undefined, so let's zero them 233 | if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms 234 | if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms 235 | if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms 236 | // default is 12 bit resolution, 750 ms conversion time 237 | celsius = (float)raw * 0.0625; 238 | break; 239 | 240 | case 2: 241 | data[1] = (data[1] >> 3) & 0x1f; 242 | if (data[2] > 127) { 243 | celsius = (float)data[2] - ((float)data[1] * .03125); 244 | } else { 245 | celsius = (float)data[2] + ((float)data[1] * .03125); 246 | } 247 | } 248 | 249 | // remove random errors 250 | if((((celsius <= 0 && celsius > -1) && lastTemp > 5)) || celsius > 125) { 251 | celsius = lastTemp; 252 | } 253 | 254 | fahrenheit = celsius * 1.8 + 32.0; 255 | lastTemp = celsius; 256 | 257 | // now that we have the readings, we can publish them to the cloud 258 | // store celsius and fahrenheit temp readings in "temperature" stringified JSON 259 | String temperature = String::format("{\"Celsius\":%f,\"Fahrenheit\":%f}", celsius, fahrenheit ); 260 | String TempPlusLocation; 261 | if( Coordinates.length() != 0) { 262 | TempPlusLocation = String("{\"Temp\":"+temperature+",\"gps\":"+Coordinates+"}"); 263 | } else { 264 | TempPlusLocation = String("{\"Temp\":"+temperature+"}"); // This was a web query, location unknown 265 | } 266 | Particle.publish("AssetTrackerTemperatureEvent", TempPlusLocation, PRIVATE); // publish to cloud 267 | Serial.print( "Sending AssetTrackerTemperatureEvent : " ); 268 | Serial.println( TempPlusLocation ); 269 | return (int)fahrenheit ; 270 | } 271 | 272 | 273 | int AssetTrackerGetRecentAccel( String Coordinates ) { 274 | // Check if there's been a big acceleration 275 | // Report the largest acceleration detected during the prior time interval 276 | if ( MaxAccelThisInterval ) { 277 | String AccelPlusLocation; 278 | if( Coordinates.length() != 0) { 279 | AccelPlusLocation = String("{\"Accel\":"+MaxAccelJSON+",\"gps\":"+Coordinates+"}"); 280 | } else { 281 | AccelPlusLocation = String("{\"Accel\":"+MaxAccelJSON+"}"); // This was a web query, location unknown 282 | } 283 | Particle.publish("AssetTrackerAccelerationEvent", AccelPlusLocation, 60, PRIVATE); 284 | Serial.print( "Sending AssetTrackerAccelerationEvent : " ); 285 | Serial.println( AccelPlusLocation ); 286 | } 287 | 288 | // Report the Max Acceleration back to Particle Function return code 289 | // Reset the Max Acceleration for the next time interval to zero 290 | int reportMaxAccel = MaxAccelThisInterval; 291 | MaxAccelThisInterval = 0; 292 | return reportMaxAccel; 293 | } 294 | 295 | 296 | void AssetTrackerLocationCallback(float lat, float lon, float accuracy) { 297 | // Handle the returned location data for the device. This method is passed three arguments: 298 | // - Latitude 299 | // - Longitude 300 | // - Accuracy of estimated location (in meters) 301 | String Coordinates; 302 | Coordinates = String::format("{\"lat\":%f,\"lon\":%f,\"accuracy\":%d}", lat, lon, accuracy); 303 | 304 | // Check here if the Particle Asset Tracker v2 built-in GPS can get a more accurate geolocation 305 | // than the Cellular Tower Triangulation. Consumes more power but improves accuracy. 306 | 307 | // Report the temperture at this location. 308 | AssetTrackerGetCurrentTemp( Coordinates ); 309 | 310 | // Determine if there has been a big acceleration event in the past interval 311 | AssetTrackerGetRecentAccel( Coordinates ); 312 | } 313 | 314 | 315 | void loop() { 316 | locator.loop(); 317 | 318 | // Check if there's been a big acceleration 319 | // Save only the largest acceleration detected during the prior time period 320 | int CurrentAccelmagnitude = t.readXYZmagnitude(); 321 | if (CurrentAccelmagnitude > AccelThreshold && CurrentAccelmagnitude > MaxAccelThisInterval) { 322 | // Format a JSON Object to be parsed in the cloud {x:X,y:Y,z:Z} 323 | // Save a stringified JSON object 324 | MaxAccelJSON = String::format("{\"x\":%d,\"y\":%d,\"z\":%d}", t.readX(), t.readY(), t.readZ()); 325 | Serial.print( "AccelerationEvent triggered: " ); 326 | Serial.println( MaxAccelJSON ); 327 | MaxAccelThisInterval = CurrentAccelmagnitude; 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /ParticleElectron/project.properties: -------------------------------------------------------------------------------- 1 | dependencies.Adafruit_LIS3DH=1.0.3 2 | dependencies.Adafruit_GPS=1.0.3 3 | dependencies.AssetTracker=0.0.10 4 | dependencies.CellularHelper=0.0.4 5 | dependencies.OneWire=2.0.1 6 | dependencies.Adafruit_Sensor=1.0.2 7 | dependencies.google-maps-device-locator=0.0.4 8 | -------------------------------------------------------------------------------- /ParticleElectron/screenshots/ParticleConsoleDeviceEvents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/ParticleElectron/screenshots/ParticleConsoleDeviceEvents.png -------------------------------------------------------------------------------- /ParticleElectron/screenshots/ParticleElectronAssetTracker-IoT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/ParticleElectron/screenshots/ParticleElectronAssetTracker-IoT.jpg -------------------------------------------------------------------------------- /ParticleElectron/screenshots/ParticleElectronAssetTracker-Kit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/ParticleElectron/screenshots/ParticleElectronAssetTracker-Kit.jpg -------------------------------------------------------------------------------- /ParticleElectron/screenshots/ParticleElectronAssetTracker-in-Case.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/IoT-AssetTracking-Perishable-Network-Blockchain/75e46e90c43311b69f29def7243f6eef015f601d/ParticleElectron/screenshots/ParticleElectronAssetTracker-in-Case.jpg -------------------------------------------------------------------------------- /README-ja.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [English](README.md).* 2 | 3 | # Hyperledger ブロックチェーンを使用した IoT 資産追跡アプリの開発 4 | 5 | ## イントロダクション 6 | 7 | このリポジトリには **IoT資産追跡デバイス**、**Hyperledger ブロックチェーン**、**Node-RED ダッシュボード** を組み立てる3つのセクションがあり、生鮮品のネットワークサプライチェーンを実装します。 8 | 9 | 温度、湿度、振動、または時間に影響されやすい生鮮品 (食品サプライ・チェーン、冷却保管された医薬品、園芸植物など) の配送に関連する環境条件を追跡するには、このコード・パターンを使用できます。貨物を安全な環境パラメーターの範囲内で安全な時間内に配送しなければならないとしたら、環境センサーを結合した IoT 資産追跡デバイスを使用して、GPS、三角測量、またはビーコンによって現在位置を計算して、その位置をセルラー、5G、Sub1GHz、SigFox、または WiFi のネットワークを介して報告することには極めて大きな価値があります。安全な配送と貨物の決済に、農場、製造業者、処理工場、トラック、港湾、船、流通センター、消費者向け小売店などの複数の参加者が関与する場合、Hyperledger ブロックチェーンを使用すれば、IoT 資産追跡デバイスから報告される配送の進捗を、不変のトランザクションとして記録することができます。 10 | 11 | ## ワークショップ 12 | 13 | 私はこのgitリポジトリに関して **[IBM コードパターン](https://developer.ibm.com/jp/)** の [ワークショップ・チュートリアル](Workshop/README-ja.md) にまとめました。 14 | この手順に従って、自分でビルドする方法を学んでください! 15 | 16 | ## セクションの概要 17 | 18 | [最初のセクション](ParticleElectron/README-ja.md) は、**Particle Electron Asset Tracker v2** をセットアップして環境センサーのデータと場所をクラウドに送信する方法を詳しく説明しています。 19 | この実装では、[Particle Electron](https://docs.particle.io/datasheets/kits-and-accessories/particle-shields/#electron-asset-tracker-v2) を使用しますが、他の多くの IoT 資産追跡デバイスでも、場所とデータを送信できるものであれば、同様の結果を得ることができます。 20 | このワークショップチュートリアルのその後の改訂では、他の IoT 資産追跡ボードが追加される予定ですので、今後もチェックしてください。 21 | 22 | [2番目のセクション](Blockchain/README-ja.md) は、[Hyperledger](https://www.hyperledger.org/) Fabric、Hyperledger Composer、Hyperledger Composer REST APIを使用して、IBM Cloud 上の [Kubernetes cluster](https://console.bluemix.net/docs/tutorials/scalable-webapp-kubernetes.html#deploy-a-scalable-web-application-on-kubernetes) で管理された [IBM Cloud Container Service](https://www.ibm.com/cloud/container-service) 上で、**生鮮品のビジネスネットワーク** を実装しています。 23 | 24 | [3番目のセクション](Node-RED/README-ja.md) では、**Where、What、When** のパワーが、ジオロケーションパスや環境センサーデータをプロットするダッシュボードで最もよく視覚化され、トリガーとアラートを制御できることを示します。 25 | IBM Cloud でホストされた Cloud Foundry アプリケーションで稼働する **[Node-RED](https://nodered.org/)** と Node.js サーバーを使用し、IoT 資産追跡データを受信して、Hyperledger Composer REST API 経由で Hyperledgerファブリックに書き込みます。 26 | また、**Node-RED ダッシュボード** を使用して地図上に貨物をプロットします。 27 | 28 | 楽しくやりましょう! 29 | このチュートリアルを改善する提案がある場合は、私にフィードバックしてください。 30 | 31 | # ライセンス 32 | 33 | [Apache 2.0](LICENSE) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [日本語](README-ja.md).* 2 | 3 | # IoT Asset Tracking using a Hyperledger Blockchain 4 | 5 | # WARNING: This repository is no longer maintained :warning: 6 | 7 | > This repository, which contains assets to run a Hyperledger Composer application, 8 | is not being actively maintained due to a shift to focus on Hyperledger Fabric. 9 | This repository will not be updated. The repository will be kept available 10 | in read-only mode. Refer to https://github.com/IBM/assetTracking 11 | for a similar example. 12 | 13 | ## Introduction 14 | This repository contains three sections which assemble an **IoT Asset Tracking device**, **Hyperledger Blockchain** and a **Node-RED Dashboard** to implement a perishable network supply chain. This example can be used to track environmental conditions for a food safety supply chain, refrigerated medical supplies, garden plant shipments or any perishable shipment that are temperature / humidity / vibration / time sensitive. If a cargo needs to be delivered within safe environmental parameters and time, the use of an IoT Asset Tracking device that combines environmental sensors, calculates its location via GPS, triangulation or beacons, and then reports its location via Cellular, 5G, Sub1GHz, SigFox, WiFi networks is extremely valuable. When multiple participants - farms, manufacturers, processing plants, trucks, ports, ships, distribution centers, consumer retail outlets - are involved in the safe shipment and payment of the cargo, a Hyperledger Blockchain can be used to record immutable transactions as the cargo shipment progresses through its delivery journey. 15 | 16 | ## Workshop 17 | I've arranged this git repository to be read as an **[IBM Code Pattern](https://developer.ibm.com/code/)** [workshop tutorial](Workshop/README.md). Follow the steps in the [Workshop directory](Workshop/README.md) to learn how to build one yourself! 18 | 19 | ## Section Overviews 20 | The first [section](ParticleElectron/README.md) details how to set up a **Particle Electron Asset Tracker v2** to send environmental sensor data and location to the cloud. This implementation uses a [Particle Electron](https://docs.particle.io/datasheets/kits-and-accessories/particle-shields/#electron-asset-tracker-v2) but many other IoT Asset Tracking devices that can transmit location and data can be substituted with similar results. Subsequent revisions of this workshop tutorial will add other IoT Asset Tracking boards so check back in the future. 21 | 22 | The second [section](Blockchain/README.md) implements a **Perishable Business Network** using [Hyperledger](https://www.hyperledger.org/) Fabric, Hyperledger Composer, Hyperledger Composer REST APIs 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. 23 | 24 | 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. 25 | 26 | Enjoy! Give me feedback if you have suggestions on how to improve this tutorial. 27 | 28 | ## License 29 | 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). 30 | 31 | [Apache Software License (ASL) FAQ](http://www.apache.org/foundation/license-faq.html#WhatDoesItMEAN) 32 | -------------------------------------------------------------------------------- /Workshop/README-ja.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [English](README.md).* 2 | 3 | # IoT 資産トラッカー Perishable Network ブロックチェーン ワークショップ 4 | 著者: [@johnwalicki](https://twitter.com/johnwalicki) 5 | 6 | # 元となるワークショップは: **https://github.com/johnwalicki/IoT-AssetTracking-Perishable-Network-Blockchain** 7 | 8 | 私はこのgitリポジトリを **[IBM コードパターン](https://developer.ibm.com/code/)** の [ワークショップ・チュートリアル](README-ja.md) として読むように調整しました。 9 | 10 | ## セクションの概要 11 | 12 | [最初のセクション](../ParticleElectron/README-ja.md) は、**Particle Electron Asset Tracker v2** をセットアップして環境センサーのデータと場所をクラウドに送信する方法を詳しく説明しています。 13 | 我々は多数の Particle Electrons を持たないので、私はその代表として所持するものをデモします。ワークショップの最後に、このトラッカーから環境データを読んでいきます。 14 | 15 | [2番目のセクション](../Blockchain/README-ja.md) は、[Hyperledger](https://www.hyperledger.org/) Fabric、Hyperledger Composer、Hyperledger Composer REST APIを使用して、IBM Cloud 上の [Kubernetes cluster](https://console.bluemix.net/docs/tutorials/scalable-webapp-kubernetes.html#deploy-a-scalable-web-application-on-kubernetes) で管理された [IBM Cloud Container Service](https://www.ibm.com/cloud/container-service) 上で、**生鮮品のビジネスネットワーク** を実装しています。 16 | 17 | [3番目のセクション](../Node-RED/README-ja.md) では、**Where、What、When** のパワーが、ジオロケーションパスや環境センサーデータをプロットするダッシュボードで最もよく視覚化され、トリガーとアラートを制御できることを示します。 18 | IBM Cloud でホストされた Cloud Foundry アプリケーションで稼働する **[Node-RED](https://nodered.org/)** と Node.js サーバーを使用し、IoT 資産追跡データを受信して、Hyperledger Composer REST API 経由で Hyperledgerファブリックに書き込みます。 19 | また、**Node-RED ダッシュボード** を使用して地図上に貨物をプロットします。 20 | 21 | * 独自の Particle Electron を購入した場合は、Particle のデバイスIDとアクセストークンを知り、それを Node-RED 初期化フローに設定する必要があります。 22 | * あなたがワークショップに参加している場合、インストラクターは Particle のデバイスIDとアクセストークンを別のスライド (GitHubには含まれません) で共有します。 23 | 24 | ワークショップの最後には、食品安全サプライチェーンが導入された Hyperledger ブロックチェーンと、Particle のルートを追跡する Node-RED Map ダッシュボードが用意されています。 25 | -------------------------------------------------------------------------------- /Workshop/README.md: -------------------------------------------------------------------------------- 1 | *Read this in other languages: [日本語](README-ja.md).* 2 | 3 | # IoT Asset Tracking Perishable Network Blockchain Workshop 4 | Author: [@johnwalicki](https://twitter.com/johnwalicki) 5 | 6 | # Follow this workshop at **https://github.com/johnwalicki/IoT-AssetTracking-Perishable-Network-Blockchain** 7 | 8 | I've arranged this git repository to be read as an **[IBM Code Pattern](https://developer.ibm.com/code/)** [workshop tutorial](README.md). 9 | 10 | ## Section Overviews 11 | The first [section](../ParticleElectron/README.md) details how to set up a **Particle Electron Asset Tracker v2** to send environmental sensor data and location to the cloud. This implementation uses a [Particle Electron](https://docs.particle.io/datasheets/kits-and-accessories/particle-shields/#electron-asset-tracker-v2). Since we don't have dozens of Particle Electrons, I will demo mine from the podium. By the end of the workshop you will be reading environmental data off this tracker. 12 | 13 | The second [section](../Blockchain/README.md) implements a **Perishable Business Network** using [Hyperledger](https://www.hyperledger.org/) Fabric, Hyperledger Composer, Hyperledger Composer REST APIs 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. 14 | 15 | 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/)** running in the IBM Cloud 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. 16 | 17 | * If you purchased your own Particle Electron, you will need to know the Particle Device ID and Access Token and insert it into Node-RED initialization flow. 18 | * If your participating in a workshop, the instructor will share the Particle Device ID and Access Token in a separate slide (not part of GitHub) 19 | 20 | At the end of the workshop, you will have a complete Hyperledger Blockchain with a food safety supply chain implemented and a Node-RED Map Dashboard that tracks the routes of my Particle. 21 | --------------------------------------------------------------------------------