Skip to content

Instantly share code, notes, and snippets.

@Tschuck
Last active April 22, 2020 08:20
Show Gist options
  • Save Tschuck/0d4913c70a17bf775592e1ebe24a99f2 to your computer and use it in GitHub Desktop.
Save Tschuck/0d4913c70a17bf775592e1ebe24a99f2 to your computer and use it in GitHub Desktop.
Digital Twin - Step by Step
module.exports = {
accounts: [
{
// mnemonic: 'load eagle joke blame flock unhappy infant post lobster prevent stuff cause',
// password: 'SWini6i23zXm',
accountId: '0x3c6b68c59DA231a9a9331789db839A74e315EbC7',
identity: '0x4b87f95C47C91a812e9D59AacfA6622569adB6e8',
// get infos at https://dashboard.test.evan.network/#/dashboard.vue.evan/settings.evan/account
privateKey: '2f0606104c3f4d6f3a71637644c9ec304b19f84d04fd3c74d6ca5c1d3e44faf6',
encryptionKey: '76f180f00bf6da91df9f4022f95733aa164e3be96d5c555229fd33c7ea8a33a9',
},
{
// mnemonic: 'purity script uncover shoulder group puppy dutch corn advance affair dynamic achieve',
// password: 'iL6U3Na9mWQh',
accountId: '0xeEEe6ACc1F52a65c3ABed8C9666798d52D905a25',
identity: '0x89E97c52adDcF1604372d8764F11CDDEDB61650E',
// get infos at https://dashboard.test.evan.network/#/dashboard.vue.evan/settings.evan/account
privateKey: 'ce1fc6633de72c1e9e74fd9be3c281771a3f856de7b2b81ab1b52b21a49e4b74',
encryptionKey: '90a45d358534f550908a654a55d96454950593ecd542cd8713ba98d6c73ad679',
},
],
runtimeConfig: {
ipfsConfig: {
host: 'ipfs.test.evan.network', // 'ipfs.evan.network'
port: '443',
protocol: 'https',
},
web3Provider: 'wss://testcore.evan.network/ws', // 'wss://core.evan.network/ws',
},
}
const { DigitalTwin, Container, } = require('@evan.network/api-blockchain-core')
const utils = require('./utils')
const { accounts, runtimeConfig } = require('./config')
/**
* Documentation
*
* - https://api-blockchain-core.readthedocs.io/en/latest/
* - https://evannetwork.github.io/
*/
// test connection
async function testRuntime(accountConfig = accounts[0]) {
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
const accountDetails = await runtime.profile.getProfileProperty('accountDetails')
console.dir(accountDetails)
}
// test twin creation
async function testCreate(accountConfig = accounts[0]) {
// Get the current templates for baxxler here: https://github.com/evannetwork/heavy-machine-examples
const { description, plugins } = require('./template-aerial-platform.json')
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
// create a new twin
const twin = await DigitalTwin.create(
runtime,
{
accountId: runtime.activeIdentity,
description: {
...description,
name: 'test twin',
description: 'new twin sample',
},
plugins,
}
)
// load twin data
const twinAddress = await twin.getContractAddress()
const container = (await twin.getEntry('Metadata')).value
console.dir({
twinAddress,
metadataContainer: {
owner: await container.getOwner(),
identity: await container.getEntry('identity'),
identity: await container.getEntry('dimensions'),
containerDescription: await container.getDescription(),
},
})
}
// get the twin data
async function testLoad(twinAddress, accountConfig = accounts[0]) {
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
const twin = new DigitalTwin(runtime, { accountId: runtime.activeIdentity, address: twinAddress })
// load twin data
const containers = await twin.getEntries()
const containerNames = Object.keys(containers)
const completeData = { }
await Promise.all(containerNames.map(async (name) => {
const container = containers[name].value
const dataSchema = (await container.getDescription()).dataSchema
// load container entry data
completeData[name] = { }
await Promise.all(Object.keys(dataSchema).map(async (entryName) => {
try {
const value = await container.getEntry(entryName)
completeData[name][entryName] = value
} catch (ex) {
completeData[name][entryName] = 'not permitted'
}
}))
}))
console.log(`Data for twin and identity:`)
console.log(` - twin address: ${twinAddress}`)
console.log(` - identity: ${runtime.activeIdentity}`)
console.log(JSON.stringify(completeData, null, 2))
}
async function testUpdate(twinAddress, accountConfig = accounts[0]) {
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
const twin = new DigitalTwin(runtime, { accountId: runtime.activeIdentity, address: twinAddress })
const container = (await twin.getEntry('Metadata')).value
await container.setEntry('identity', {
chassisNumber: 'XYZ',
machineCategory: 'aerial-platform',
machineClass: 'test',
machineId: '12345',
manufacturer: 'manufacturer',
manufacturerModelDesignation: 'ABC',
yom: 12345,
})
console.log(`\n\nUpdated "${twinAddress}" and entry "${runtime.activeIdentity}"`)
}
// share a twin with another identity
async function testSharing(twinAddress, accountConfig = accounts[0], shareToConfig = accounts[1]) {
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
const twin = new DigitalTwin(runtime, { accountId: runtime.activeIdentity, address: twinAddress })
const container = (await twin.getEntry('Metadata')).value
// remove works with unshareProperties
await container.shareProperties([{
accountId: shareToConfig.identity,
read: [
'identity',
'owner',
// 'characteristics',
// 'documents',
'dimensions',
'performance',
// 'drive',
// 'weights',
// 'wheels',
// 'others',
// 'locationData'
]
}])
await testLoad(twinAddress, shareToConfig)
}
// share a twin with another identity
async function testBmail(twinAddress, accountConfig = accounts[0], sendToConfig = accounts[1]) {
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
const twin = new DigitalTwin(runtime, { accountId: runtime.activeIdentity, address: twinAddress })
await runtime.mailbox.sendMail(
{
content: {
from: runtime.activeIdentity,
title: `Invitation to twin - ${new Date()}`,
body: `Hi, i shared the twin ${twinAddress} with you. You can now have a look at the data.`,
attachments: [
{
fullPath: `/dashboard.vue.evan/detail.digital-twin.evan/${twinAddress}/data`,
type: 'url',
},
],
},
},
runtime.activeIdentity,
sendToConfig.identity,
)
const runtime2 = await utils.getRuntime(runtimeConfig, sendToConfig)
console.log(`Mailbox for identity ${sendToConfig.identity}`)
const mailResult = await runtime2.mailbox.getReceivedMails(1, 0);
console.log(JSON.stringify(mailResult, null, 2))
}
// delete a twin
async function testDelete(twinAddress, accountConfig = accounts[0]) {
const runtime = await utils.getRuntime(runtimeConfig, accountConfig)
const twin = new DigitalTwin(runtime, { accountId: runtime.activeIdentity, address: twinAddress })
await twin.deactivate()
console.log('\n\ntwin deleted')
}
testRuntime()
// testCreate()
// const twinAddress = '0xa83A4680bcE5565cbfAb10aCd7B41C65517890d4'
// testLoad(twinAddress, accounts[0])
// testUpdate(twinAddress, accounts[0])
// testLoad(twinAddress, accounts[1])
// testUpdate(twinAddress, accounts[1])
// testSharing(twinAddress, accounts[0], accounts[1])
// testBmail(twinAddress, accounts[0], accounts[1])
// testDelete(twinAddress, accounts[0])
{
"author": "evan GmbH",
"dependencies": {
"@evan.network/api-blockchain-core": "https://github.com/evannetwork/api-blockchain-core.git#develop",
"request": "^2.88.2",
"web3": "2.0.0-alpha"
},
"description": "test evan.network twins",
"main": "index.js",
"name": "twin-tests",
"version": "2.18.0",
"scripts": {
"postinstall": "cd ./node_modules/@evan.network/api-blockchain-core; yarn build"
}
}
{
"description": {
"author": "Evan GmbH",
"dbcpVersion": 2,
"description": "",
"i18n": {
"de": {
"description": "",
"name": "Lindig Arbeitsbühne"
},
"en": {
"description": "",
"name": "Lindig Aerial Platform"
}
},
"name": "lindig_aerial_platform",
"version": "0.1.0"
},
"plugins": {
"rentalCalendar": {
"description": {
"author": "Lindig",
"dbcpVersion": 2,
"description": "",
"i18n": {
"de": {
"calendar": {
"name": "Mietkalender"
},
"description": "",
"name": "Mietkalender"
},
"en": {
"calendar": {
"name": "Rental calendar"
},
"description": "",
"name": "Rental calendar"
}
},
"name": "calendar",
"version": "1.0.0"
},
"template": {
"properties": {
"calendar": {
"dataSchema": {
"items": {
"properties": {
"details": {
"additionalProperties": true,
"type": "object"
},
"from": {
"default": "",
"type": "number"
},
"orderDetails": {
"additionalProperties": true,
"type": "object"
},
"orderHistory": {
"additionalProperties": true,
"type": "object"
},
"to": {
"default": "",
"type": "number"
},
"type": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"type": "array"
},
"permissions": {
"0": [
"set",
"remove"
]
},
"type": "list"
}
},
"type": "metadata"
}
},
"Metadata": {
"description": {
"author": "Lindig",
"dbcpVersion": 2,
"description": "",
"i18n": {
"de": {
"description": "",
"name": "Produktdaten"
},
"en": {
"description": "",
"name": "Product data"
}
},
"name": "metadata",
"version": "1.0.0"
},
"template": {
"properties": {
"identity": {
"dataSchema": {
"$id": "identity_schema",
"properties": {
"chassisNumber": {
"default": "",
"type": "string"
},
"machineCategory": {
"default": "",
"minLength": 1,
"type": "string"
},
"machineClass": {
"minLength": 1,
"type": "string"
},
"machineId": {
"default": "",
"minLength": 1,
"type": "string"
},
"manufacturer": {
"default": "",
"minLength": 1,
"type": "string"
},
"manufacturerModelDesignation": {
"default": "",
"minLength": 1,
"type": "string"
},
"yom": {
"default": "",
"type": "number"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"machineClass": "Arbeitsbühne"
}
},
"owner": {
"dataSchema": {
"$id": "owner_schema",
"properties": {
"internalAssetDesignation": {
"default": "",
"type": "string"
},
"internalModelDesignation": {
"default": "",
"type": "string"
},
"internalSystemDesignation": {
"default": "",
"type": "string"
},
"licensePlate": {
"default": "",
"type": "string"
},
"owner": {
"default": "",
"minLength": 1,
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {}
},
"characteristics": {
"dataSchema": {
"$id": "characteristics_schema",
"properties": {
"certificateOfQualification": {
"default": "",
"type": "string"
},
"color": {
"default": "",
"type": "string"
},
"licenseClass": {
"default": "",
"type": "string"
},
"profilePicture": {
"$comment": "{\"isEncryptedFile\": true}",
"maxItems": 1,
"properties": {
"additionalProperties": false,
"files": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"files"
],
"type": "object"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"profilePicture": {
"files": []
}
}
},
"documents": {
"dataSchema": {
"$id": "documents_schema",
"properties": {
"machinePictures": {
"$comment": "{\"isEncryptedFile\": true}",
"maxItems": 10,
"properties": {
"additionalProperties": false,
"files": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"files"
],
"type": "object"
},
"operaterFilm": {
"$comment": "{\"isEncryptedFile\": true}",
"maxItems": 3,
"properties": {
"additionalProperties": false,
"files": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"files"
],
"type": "object"
},
"operationManual": {
"$comment": "{\"isEncryptedFile\": true}",
"maxItems": 5,
"properties": {
"additionalProperties": false,
"files": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"files"
],
"type": "object"
},
"workingChart": {
"$comment": "{\"isEncryptedFile\": true}",
"maxItems": 3,
"properties": {
"additionalProperties": false,
"files": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"files"
],
"type": "object"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"machinePictures": {
"files": []
},
"operaterFilm": {
"files": []
},
"operationManual": {
"files": []
},
"workingChart": {
"files": []
}
}
},
"dimensions": {
"dataSchema": {
"$id": "dimensions_schema",
"properties": {
"groundClearanceCentre": {
"default": "",
"type": "number"
},
"groundClearanceCentreUnit": {
"type": "string"
},
"height": {
"default": "",
"type": "number"
},
"heightStowed": {
"default": "",
"type": "number"
},
"heightStowedUnit": {
"type": "string"
},
"heightUnit": {
"minLength": 1,
"type": "string"
},
"length": {
"default": "",
"type": "number"
},
"lengthStowed": {
"default": "",
"type": "number"
},
"lengthStowedUnit": {
"type": "string"
},
"lengthUnit": {
"minLength": 1,
"type": "string"
},
"outrigger": {
"default": "",
"type": "string"
},
"platformLength": {
"default": "",
"type": "number"
},
"platformLengthUnit": {
"type": "string"
},
"platformWidth": {
"default": "",
"type": "number"
},
"platformWidthUnit": {
"type": "string"
},
"wheelbase": {
"default": "",
"type": "number"
},
"wheelbaseUnit": {
"type": "string"
},
"width": {
"default": "",
"type": "number"
},
"widthStowed": {
"default": "",
"type": "number"
},
"widthStowedUnit": {
"type": "string"
},
"widthUnit": {
"minLength": 1,
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"groundClearanceCentreUnit": "mm",
"heightStowedUnit": "mm",
"heightUnit": "mm",
"lengthStowedUnit": "mm",
"lengthUnit": "mm",
"platformLengthUnit": "mm",
"platformWidthUnit": "mm",
"wheelbaseUnit": "mm",
"widthStowedUnit": "mm",
"widthUnit": "mm"
}
},
"performance": {
"dataSchema": {
"$id": "performance_schema",
"properties": {
"gradeability": {
"default": "",
"type": "number"
},
"gradeabilityUnit": {
"type": "string"
},
"jib": {
"default": "",
"type": "string"
},
"maximumLoadCapacity": {
"default": "",
"type": "number"
},
"maximumLoadCapacityUnit": {
"minLength": 1,
"type": "string"
},
"maximumPersonsAllowed": {
"default": "",
"type": "number"
},
"maximumReach": {
"default": "",
"type": "number"
},
"maximumReachUnit": {
"type": "string"
},
"maximumWorkingHeight": {
"default": "",
"type": "number"
},
"maximumWorkingHeightUnit": {
"minLength": 1,
"type": "string"
},
"maximumStandingPlatformHeight": {
"default": "",
"type": "number"
},
"maximumStandingPlatformHeightUnit": {
"minLength": 1,
"type": "string"
},
"movability": {
"default": "",
"type": "string"
},
"oscillatingAxle": {
"default": "",
"type": "string"
},
"platformExtension": {
"default": "",
"type": "string"
},
"rotationType": {
"default": "",
"type": "string"
},
"rotationUnit": {
"type": "string"
},
"turntableRotation": {
"default": "",
"type": "number"
},
"upAndOverHeight": {
"default": "",
"type": "number"
},
"upAndOverHeightUnit": {
"minLength": 1,
"type": "string"
},
"usability": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"gradeabilityUnit": "° (Grad), % (Prozent)",
"maximumLoadCapacityUnit": "kg",
"maximumReachUnit": "m",
"maximumWorkingHeightUnit": "m",
"maximumStandingPlatformHeightUnit": "m",
"rotationUnit": "° (Grad)",
"upAndOverHeightUnit": "m"
}
},
"drive": {
"dataSchema": {
"$id": "drive_schema",
"properties": {
"awd": {
"default": "",
"type": "string"
},
"batteryCapacity": {
"default": "",
"type": "number"
},
"batteryType": {
"default": "",
"type": "string"
},
"batteryVoltage": {
"default": "",
"type": "number"
},
"capacityUnit": {
"type": "string"
},
"driveType": {
"default": "",
"minLength": 1,
"type": "string"
},
"powerCobustionEngine": {
"default": "",
"type": "number"
},
"powerUnit": {
"type": "string"
},
"tankCapacity": {
"default": "",
"type": "number"
},
"tankCapacityUnit": {
"type": "string"
},
"voltageUnit": {
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"capacityUnit": "Ah",
"powerUnit": "kW",
"tankCapacityUnit": "l",
"voltageUnit": "V"
}
},
"weights": {
"dataSchema": {
"$id": "weights_schema",
"properties": {
"batteryWeight": {
"default": "",
"type": "number"
},
"batteryWeightUnit": {
"type": "string"
},
"groundPressure": {
"default": "",
"type": "number"
},
"groundPressureUnit": {
"type": "string"
},
"serviceWeight": {
"default": "",
"type": "number"
},
"serviceWeightUnit": {
"minLength": 1,
"type": "string"
},
"trailerLoad": {
"default": "",
"type": "number"
},
"trailerLoadUnit": {
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"batteryWeightUnit": "kg",
"groundPressureUnit": "psi / kg",
"serviceWeightUnit": "kg",
"trailerLoadUnit": "kg"
}
},
"wheels": {
"dataSchema": {
"$id": "wheels_schema",
"properties": {
"markingNonMarking": {
"default": "",
"type": "string"
},
"tireType": {
"default": "",
"minLength": 1,
"type": "string"
},
"wheelNumberFront": {
"default": "",
"type": "number"
},
"wheelNumberRear": {
"default": "",
"type": "number"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {}
},
"others": {
"dataSchema": {
"$id": "others_schema",
"properties": {
"soundLevelAtOperatorsEar": {
"default": "",
"type": "number"
},
"soundLevelUnit": {
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {
"soundLevelUnit": "dbA"
}
},
"locationData": {
"dataSchema": {
"$id": "locationData_schema",
"properties": {
"actualLocation": {
"default": "",
"type": "string"
},
"assignedLocation": {
"default": "",
"type": "string"
},
"city": {
"default": "",
"type": "string"
},
"country": {
"default": "",
"type": "string"
},
"houseNumber": {
"default": "",
"type": "string"
},
"latitude": {
"default": "",
"type": "string"
},
"longitude": {
"default": "",
"type": "string"
},
"street": {
"default": "",
"type": "string"
},
"zipCode": {
"default": "",
"type": "string"
}
},
"type": "object"
},
"permissions": {
"0": [
"set"
]
},
"type": "entry",
"value": {}
}
},
"type": "metadata"
}
}
}
}
const Web3 = require('web3')
const request = require('request')
const { createDefaultRuntime, Ipfs, } = require('@evan.network/api-blockchain-core')
/**
* Create the evan.network runtime.
*/
async function getRuntime({ web3Provider, ipfsConfig, }, { privateKey, encryptionKey, accountId }) {
const provider = new Web3.providers.WebsocketProvider(
web3Provider,
{ clientConfig: { keepalive: true, keepaliveInterval: 5000 }
})
const web3 = new Web3(provider, { transactionConfirmationBlocks: 1 })
const dfs = new Ipfs({ dfsConfig: ipfsConfig, })
const sha3Account = web3.utils.soliditySha3(accountId)
const sha9Account = web3.utils.soliditySha3(sha3Account, sha3Account)
// create runtime
return createDefaultRuntime(
web3,
dfs,
{
accountMap: {
[ accountId ]: privateKey,
},
keyConfig: {
[ sha3Account ]: encryptionKey,
[ sha9Account ]: encryptionKey,
},
useIdentity: true,
},
)
}
module.exports = {
getRuntime,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment