├── .github
└── workflows
│ └── action.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dashboard_getting_started
├── Resources
│ ├── IMPORT_Dashboard.json
│ └── IMPORT_DataGenerator.json
├── Setup
│ ├── DataGenerator.json
│ └── readme.md
├── doc
│ ├── Data_Generator_Flow.png
│ ├── asset_complete.png
│ ├── asset_switch.mp4
│ ├── asset_type.png
│ ├── button_node.png
│ ├── change_node.png
│ ├── change_tab.png
│ ├── check_nodes.png
│ ├── dashboard_menu.png
│ ├── dashpic_1.png
│ ├── event_node.png
│ ├── event_table.png
│ ├── flowpic_1.png
│ ├── flowpic_2.png
│ ├── flowpic_3.png
│ ├── flowpic_4.png
│ ├── flowpic_5.png
│ ├── flowpic_6.png
│ ├── flowpic_7.png
│ ├── function_node.png
│ ├── generate_node.png
│ ├── group_edit.png
│ ├── group_structure.png
│ ├── groups_content.png
│ ├── hide_show.png
│ ├── import.png
│ ├── led_node.png
│ ├── logical_grouping.png
│ ├── map.png
│ ├── map_text.png
│ ├── notification_node.png
│ ├── open_dashboard.png
│ ├── overview.png
│ ├── read_location.png
│ ├── readme.md
│ ├── selector.png
│ ├── store_ctx_node.png
│ ├── switch_node.png
│ ├── tab_structure.png
│ ├── tabs_groups.png
│ ├── text_node.png
│ ├── text_node_2.png
│ ├── text_node_3.png
│ └── write_timeseries.png
└── readme.md
├── DataLake_provideAccessToken
├── doc
│ ├── example.png
│ └── result_IDL_AccessToken.png
├── readme.md
└── template.json
├── DataLake_scheduledImport
├── doc
│ ├── example.png
│ └── result_IDL_Explorer.png
├── readme.md
└── template.json
├── LICENSE.md
├── README.md
├── UserActivityTracker
├── UserInsights_AspectDefinition.csv
├── doc
│ ├── AM-Setup_Aspect.png
│ ├── AM-Setup_Asset.png
│ ├── AM-Setup_AssetType.png
│ ├── UserActivityTracker.png
│ └── UserActivityTracker_results.png
├── readme.md
└── template.json
├── WriteLocationToAsset
├── IMPORT_WriteLocationToAsset.json
└── readme.md
├── commandMqttDevice_MindConnect
├── IMPORT_commandMqttDevice_MindConnect.json
├── doc
│ ├── VFC_setup_MindConnect.png
│ ├── commandMqttDevice_MC.png
│ └── receive_command_MC.png
└── readme.md
├── createCustomAPI_endpoint
├── IMPORT_createCustomEndpoint.json
├── doc
│ ├── createCustomEndpoint.png
│ ├── result.png
│ ├── setup_KeyGeneration.png
│ └── setup_selectAssetToRead.png
└── readme.md
├── createRuleForAssetType
├── createRuleForAssetType.json
├── doc
│ └── createRuleForAssetType.png
└── readme.md
├── data_simulation_24h
├── doc
│ ├── 24h-replay-for_data-simulation.png
│ ├── FileUpload_AssetManager.png
│ ├── FileUpload_Monitor.png
│ └── explain-of-logic.png
├── flow_template.json
└── readme.md
├── docs
├── How_To_Import.gif
├── Launchpad_VFC.png
└── VFC_roles.png
├── generateSampleData
├── doc
│ └── generateSampleData.png
├── generateSampleData.json
└── readme.md
├── integrateExternalApi
├── doc
│ ├── API_KEY_details.png
│ └── external_API_image.png
├── externalApi.json
└── readme.md
├── sendSmsNotifications
├── doc
│ ├── SMS_result.gif
│ ├── example.png
│ └── sendSmsNotifications.png
├── readme.md
├── sendSmsNotifications.json
└── template.json
├── templateFlow.zip
├── virtualMachineSimulator
├── IMPORT_virtualMachineSimulator.json
├── doc
│ ├── Asset_Manager_AssetInstance.png
│ ├── Asset_Manager_AssetType_virtualMachine.png
│ ├── Asset_Manager_Import_Aspect.png
│ ├── FleetManager_Results.png
│ ├── VFC_setup_Asset-Aspect.png
│ └── virtualMachineSimulator.png
├── readme.md
└── src
│ ├── Aspect_machine-states.csv
│ └── Aspect_product_counter.csv
└── x_templateFlow
├── doc
└── example.png
├── readme.md
└── template.json
/.github/workflows/action.yml:
--------------------------------------------------------------------------------
1 | name: Check Markdown links
2 |
3 | on: push
4 |
5 | jobs:
6 | markdown-link-check:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@master
10 | - uses: gaurav-nelson/github-action-markdown-link-check@v1
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependency directories
2 | setFlowVariablesViaDashboard
3 |
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # Diagnostic reports (https://nodejs.org/api/report.html)
14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
15 |
16 | # Runtime data
17 | pids
18 | *.pid
19 | *.seed
20 | *.pid.lock
21 |
22 | # Directory for instrumented libs generated by jscoverage/JSCover
23 | lib-cov
24 |
25 | # Coverage directory used by tools like istanbul
26 | coverage
27 | *.lcov
28 |
29 | # nyc test coverage
30 | .nyc_output
31 |
32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
33 | .grunt
34 |
35 | # Bower dependency directory (https://bower.io/)
36 | bower_components
37 |
38 | # node-waf configuration
39 | .lock-wscript
40 |
41 | # Compiled binary addons (https://nodejs.org/api/addons.html)
42 | build/Release
43 |
44 | # Dependency directories
45 | node_modules/
46 | jspm_packages/
47 |
48 | # TypeScript v1 declaration files
49 | typings/
50 |
51 | # TypeScript cache
52 | *.tsbuildinfo
53 |
54 | # Optional npm cache directory
55 | .npm
56 |
57 | # Optional eslint cache
58 | .eslintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variables file
76 | .env
77 | .env.test
78 |
79 | # parcel-bundler cache (https://parceljs.org/)
80 | .cache
81 |
82 | # Next.js build output
83 | .next
84 |
85 | # Nuxt.js build / generate output
86 | .nuxt
87 | dist
88 |
89 | # Gatsby files
90 | .cache/
91 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
92 | # https://nextjs.org/blog/next-9-1#public-directory-support
93 | # public
94 |
95 | # vuepress build output
96 | .vuepress/dist
97 |
98 | # Serverless directories
99 | .serverless/
100 |
101 | # FuseBox cache
102 | .fusebox/
103 |
104 | # DynamoDB Local files
105 | .dynamodb/
106 |
107 | # TernJS port file
108 | .tern-port
109 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog - VFC Examples
2 |
3 | ## VFC Examples 1.0.0
4 |
5 | - Initial Version
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at [support.oss@siemens.com](mailto:support.oss@siemens.com).
59 |
60 | All complaints will be reviewed and investigated and will result in a response
61 | that is deemed necessary and appropriate to the circumstances. The project team
62 | is obligated to maintain confidentiality with regard to the reporter of an
63 | incident. Further details of specific enforcement policies may be posted
64 | separately.
65 |
66 | Project maintainers who do not follow or enforce the Code of Conduct in good
67 | faith may face temporary or permanent repercussions as determined by other
68 | members of the project's leadership.
69 |
70 | ## Attribution
71 |
72 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
73 | available at [http://contributor-covenant.org/version/1/4][version]
74 |
75 | [homepage]: http://contributor-covenant.org
76 | [version]: http://contributor-covenant.org/version/1/4/
77 |
--------------------------------------------------------------------------------
/Dashboard_getting_started/Resources/IMPORT_DataGenerator.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "92f8b622.df2838",
4 | "type": "comment",
5 | "z": "42c6ce94.a9202",
6 | "name": "Get Random Functions",
7 | "info": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n",
8 | "sticky": 1,
9 | "x": 300,
10 | "y": 680,
11 | "wires": []
12 | },
13 | {
14 | "id": "56f3fb32.1321b4",
15 | "type": "comment",
16 | "z": "42c6ce94.a9202",
17 | "name": "Basic Machine",
18 | "info": "",
19 | "sticky": 0,
20 | "x": 410,
21 | "y": 80,
22 | "wires": []
23 | },
24 | {
25 | "id": "cd612bbe.c1cd68",
26 | "type": "comment",
27 | "z": "42c6ce94.a9202",
28 | "name": "Performance Machine",
29 | "info": "",
30 | "sticky": 0,
31 | "x": 440,
32 | "y": 240,
33 | "wires": []
34 | },
35 | {
36 | "id": "5216b1db.909bc",
37 | "type": "comment",
38 | "z": "42c6ce94.a9202",
39 | "name": "Eco Machine",
40 | "info": "",
41 | "sticky": 0,
42 | "x": 410,
43 | "y": 400,
44 | "wires": []
45 | },
46 | {
47 | "id": "cc846ce2.eef4a",
48 | "type": "function",
49 | "z": "42c6ce94.a9202",
50 | "name": "Basic Machine Status",
51 | "func": "function getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n\nlet programList = [\"EDS TTU 553 V8\",\"PA12 - KKT Vorheizen\",\"TC 3D AKF PA11\",\"detax v30\",\"Tool changing position\",\"EDS PT 3404 Balanced\",\"Postprocessing\", \"PT Black TL l-R\", \"PT White FT\", \"Preprocessing\", \"Cleaning\", \"PT M FT L-R\"];\n\nlet progr = programList[Math.floor(Math.random() * programList.length)];\nvar stat = getRandomInt(1,5);\nvar id = getRandomInt(1000,9999999);\n\nvar obj = {};\nobj._time = new Date();\nobj.Machine_Status = stat;\nobj.Program_Id = id;\nobj.Program_Name = progr;\n\nmsg.payload = obj;\nreturn msg;",
52 | "outputs": 1,
53 | "language": "javascript",
54 | "noerr": 0,
55 | "x": 440,
56 | "y": 120,
57 | "wires": [
58 | [
59 | "7f529f86.7fc4e"
60 | ]
61 | ]
62 | },
63 | {
64 | "id": "c5716581.b7e138",
65 | "type": "function",
66 | "z": "42c6ce94.a9202",
67 | "name": "Basic Machine Sensors",
68 | "func": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\nvar temp_pre = getRandomInt(80,100) + getRandomDouble(10,30);\nvar temp_work = getRandomInt(120,140) + getRandomDouble(10,60);\nvar press_pre = getRandomInt(10,20) + getRandomDouble(2,7);\nvar press_work = getRandomInt(2,5) + getRandomDouble(2,7);\n\nvar obj = {};\nobj._time = new Date();\nobj.Pressure_Preheater = press_pre;\nobj.Pressure_WorkingChamber = press_work;\nobj.Temp_Preheater = temp_pre;\nobj.Temp_WorkingChamber = temp_work;\n\nmsg.payload = obj;\nreturn msg;",
69 | "outputs": 1,
70 | "language": "javascript",
71 | "noerr": 0,
72 | "x": 440,
73 | "y": 180,
74 | "wires": [
75 | [
76 | "79dc13ad.bb2cac"
77 | ]
78 | ]
79 | },
80 | {
81 | "id": "6f440ba8.2034e4",
82 | "type": "function",
83 | "z": "42c6ce94.a9202",
84 | "name": "Basic Machine Status",
85 | "func": "function getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n\nlet programList = [\"EDS TTU 553 V8\",\"PA12 - KKT Vorheizen\",\"TC 3D AKF PA11\",\"detax v30\",\"Tool changing position\",\"EDS PT 3404 Balanced\",\"Postprocessing\", \"PT Black TL l-R\", \"PT White FT\", \"Preprocessing\", \"Cleaning\", \"PT M FT L-R\"];\n\nlet progr = programList[Math.floor(Math.random() * programList.length)];\nvar stat = getRandomInt(1,5);\nvar id = getRandomInt(1000,9999999);\n\nvar obj = {};\nobj._time = new Date();\nobj.Machine_Status = stat;\nobj.Program_Id = id;\nobj.Program_Name = progr;\n\nmsg.payload = obj;\nreturn msg;",
86 | "outputs": 1,
87 | "language": "javascript",
88 | "noerr": 0,
89 | "x": 440,
90 | "y": 280,
91 | "wires": [
92 | [
93 | "27a7aa93.b2ae06"
94 | ]
95 | ]
96 | },
97 | {
98 | "id": "6eebeb9e.d6f334",
99 | "type": "function",
100 | "z": "42c6ce94.a9202",
101 | "name": "Basic Machine Sensors",
102 | "func": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\nvar temp_pre = getRandomInt(80,100) + getRandomDouble(10,30);\nvar temp_work = getRandomInt(120,140) + getRandomDouble(10,60);\nvar press_pre = getRandomInt(10,20) + getRandomDouble(2,7);\nvar press_work = getRandomInt(2,5) + getRandomDouble(2,7);\n\nvar obj = {};\nobj._time = new Date();\nobj.Pressure_Preheater = press_pre;\nobj.Pressure_WorkingChamber = press_work;\nobj.Temp_Preheater = temp_pre;\nobj.Temp_WorkingChamber = temp_work;\n\nmsg.payload = obj;\nreturn msg;",
103 | "outputs": 1,
104 | "language": "javascript",
105 | "noerr": 0,
106 | "x": 440,
107 | "y": 340,
108 | "wires": [
109 | [
110 | "9499b1d7.0e5eb"
111 | ]
112 | ]
113 | },
114 | {
115 | "id": "846f330b.fd38c",
116 | "type": "function",
117 | "z": "42c6ce94.a9202",
118 | "name": "Basic Machine Status",
119 | "func": "function getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n\nlet programList = [\"EDS TTU 553 V8\",\"PA12 - KKT Vorheizen\",\"TC 3D AKF PA11\",\"detax v30\",\"Tool changing position\",\"EDS PT 3404 Balanced\",\"Postprocessing\", \"PT Black TL l-R\", \"PT White FT\", \"Preprocessing\", \"Cleaning\", \"PT M FT L-R\"];\n\nlet progr = programList[Math.floor(Math.random() * programList.length)];\nvar stat = getRandomInt(1,5);\nvar id = getRandomInt(1000,9999999);\n\nvar obj = {};\nobj._time = new Date();\nobj.Machine_Status = stat;\nobj.Program_Id = id;\nobj.Program_Name = progr;\n\nmsg.payload = obj;\nreturn msg;",
120 | "outputs": 1,
121 | "language": "javascript",
122 | "noerr": 0,
123 | "x": 440,
124 | "y": 440,
125 | "wires": [
126 | [
127 | "e684622d.42458"
128 | ]
129 | ]
130 | },
131 | {
132 | "id": "c6db8a58.f773c8",
133 | "type": "function",
134 | "z": "42c6ce94.a9202",
135 | "name": "Basic Machine Sensors",
136 | "func": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\nvar temp_pre = getRandomInt(80,100) + getRandomDouble(10,30);\nvar temp_work = getRandomInt(120,140) + getRandomDouble(10,60);\nvar press_pre = getRandomInt(10,20) + getRandomDouble(2,7);\nvar press_work = getRandomInt(2,5) + getRandomDouble(2,7);\n\nvar obj = {};\nobj._time = new Date();\nobj.Pressure_Preheater = press_pre;\nobj.Pressure_WorkingChamber = press_work;\nobj.Temp_Preheater = temp_pre;\nobj.Temp_WorkingChamber = temp_work;\n\nmsg.payload = obj;\nreturn msg;",
137 | "outputs": 1,
138 | "language": "javascript",
139 | "noerr": 0,
140 | "x": 440,
141 | "y": 500,
142 | "wires": [
143 | [
144 | "25e44221.d6425e"
145 | ]
146 | ]
147 | },
148 | {
149 | "id": "31e8510f.54df0e",
150 | "type": "inject",
151 | "z": "42c6ce94.a9202",
152 | "name": "",
153 | "topic": "",
154 | "payload": "",
155 | "payloadType": "date",
156 | "repeat": "300",
157 | "repeatEnd": "0",
158 | "endTime": "0",
159 | "crontab": "",
160 | "offset": "",
161 | "once": false,
162 | "properties": "",
163 | "timezone": "utc",
164 | "betweentimesunit": "m",
165 | "enableRuleEngine": false,
166 | "showNextExecution": true,
167 | "powerMode": false,
168 | "x": 130,
169 | "y": 260,
170 | "wires": [
171 | [
172 | "cc846ce2.eef4a",
173 | "c5716581.b7e138",
174 | "6f440ba8.2034e4",
175 | "6eebeb9e.d6f334",
176 | "846f330b.fd38c",
177 | "c6db8a58.f773c8"
178 | ]
179 | ]
180 | },
181 | {
182 | "id": "7f529f86.7fc4e",
183 | "type": "write timeseries",
184 | "z": "42c6ce94.a9202",
185 | "name": "",
186 | "topic": "4c011fd02a2b4990a80d2c4c6d25ef23/Dashboard_Machine_Status",
187 | "topicData": "{\"asset\":\"4c011fd02a2b4990a80d2c4c6d25ef23\",\"assetName\":\"Basic Machine\",\"aspect\":\"7600f42a1d324f73b10d00ec963febfd\",\"aspectName\":\"Dashboard_Machine_Status\",\"variable\":null,\"variableName\":null}",
188 | "topicLabel": "Basic Machine/Dashboard_Machine_Status",
189 | "assetName": "",
190 | "aspectName": "",
191 | "useMerging": false,
192 | "x": 950,
193 | "y": 120,
194 | "wires": []
195 | },
196 | {
197 | "id": "79dc13ad.bb2cac",
198 | "type": "write timeseries",
199 | "z": "42c6ce94.a9202",
200 | "name": "",
201 | "topic": "4c011fd02a2b4990a80d2c4c6d25ef23/Dashboard_Machine_Sensor",
202 | "topicData": "{\"asset\":\"4c011fd02a2b4990a80d2c4c6d25ef23\",\"assetName\":\"Basic Machine\",\"aspect\":\"59e5446feebb454eaf3ef7ce24565dfb\",\"aspectName\":\"Dashboard_Machine_Sensor\",\"variable\":null,\"variableName\":null}",
203 | "topicLabel": "Basic Machine/Dashboard_Machine_Sensor",
204 | "assetName": "",
205 | "aspectName": "",
206 | "useMerging": false,
207 | "x": 950,
208 | "y": 180,
209 | "wires": []
210 | },
211 | {
212 | "id": "27a7aa93.b2ae06",
213 | "type": "write timeseries",
214 | "z": "42c6ce94.a9202",
215 | "name": "",
216 | "topic": "a12faec62d33439ea297adcde30ef5d2/Dashboard_Machine_Status",
217 | "topicData": "{\"asset\":\"a12faec62d33439ea297adcde30ef5d2\",\"assetName\":\"Performance Machine\",\"aspect\":\"7600f42a1d324f73b10d00ec963febfd\",\"aspectName\":\"Dashboard_Machine_Status\",\"variable\":null,\"variableName\":null}",
218 | "topicLabel": "Performance Machine/Dashboard_Machine_Status",
219 | "assetName": "",
220 | "aspectName": "",
221 | "useMerging": false,
222 | "x": 970,
223 | "y": 280,
224 | "wires": []
225 | },
226 | {
227 | "id": "9499b1d7.0e5eb",
228 | "type": "write timeseries",
229 | "z": "42c6ce94.a9202",
230 | "name": "",
231 | "topic": "a12faec62d33439ea297adcde30ef5d2/Dashboard_Machine_Sensor",
232 | "topicData": "{\"asset\":\"a12faec62d33439ea297adcde30ef5d2\",\"assetName\":\"Performance Machine\",\"aspect\":\"59e5446feebb454eaf3ef7ce24565dfb\",\"aspectName\":\"Dashboard_Machine_Sensor\",\"variable\":null,\"variableName\":null}",
233 | "topicLabel": "Performance Machine/Dashboard_Machine_Sensor",
234 | "assetName": "",
235 | "aspectName": "",
236 | "useMerging": false,
237 | "x": 980,
238 | "y": 340,
239 | "wires": []
240 | },
241 | {
242 | "id": "e684622d.42458",
243 | "type": "write timeseries",
244 | "z": "42c6ce94.a9202",
245 | "name": "",
246 | "topic": "1ccfd846e53447de88fdaaeeeddd6d78/Dashboard_Machine_Status",
247 | "topicData": "{\"asset\":\"1ccfd846e53447de88fdaaeeeddd6d78\",\"assetName\":\"Eco Machine\",\"aspect\":\"7600f42a1d324f73b10d00ec963febfd\",\"aspectName\":\"Dashboard_Machine_Status\",\"variable\":null,\"variableName\":null}",
248 | "topicLabel": "Eco Machine/Dashboard_Machine_Status",
249 | "assetName": "",
250 | "aspectName": "",
251 | "useMerging": false,
252 | "x": 950,
253 | "y": 440,
254 | "wires": []
255 | },
256 | {
257 | "id": "25e44221.d6425e",
258 | "type": "write timeseries",
259 | "z": "42c6ce94.a9202",
260 | "name": "",
261 | "topic": "1ccfd846e53447de88fdaaeeeddd6d78/Dashboard_Machine_Sensor",
262 | "topicData": "{\"asset\":\"1ccfd846e53447de88fdaaeeeddd6d78\",\"assetName\":\"Eco Machine\",\"aspect\":\"59e5446feebb454eaf3ef7ce24565dfb\",\"aspectName\":\"Dashboard_Machine_Sensor\",\"variable\":null,\"variableName\":null}",
263 | "topicLabel": "Eco Machine/Dashboard_Machine_Sensor",
264 | "assetName": "",
265 | "aspectName": "",
266 | "useMerging": false,
267 | "x": 950,
268 | "y": 500,
269 | "wires": []
270 | }
271 | ]
272 |
--------------------------------------------------------------------------------
/Dashboard_getting_started/Setup/DataGenerator.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "42c6ce94.a9202",
4 | "type": "tab",
5 | "allowCycles": false,
6 | "label": "Data Generator",
7 | "disabled": false,
8 | "info": ""
9 | },
10 | {
11 | "id": "92f8b622.df2838",
12 | "type": "comment",
13 | "z": "42c6ce94.a9202",
14 | "name": "Get Random Functions",
15 | "info": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n",
16 | "sticky": 1,
17 | "x": 300,
18 | "y": 680,
19 | "wires": []
20 | },
21 | {
22 | "id": "56f3fb32.1321b4",
23 | "type": "comment",
24 | "z": "42c6ce94.a9202",
25 | "name": "Basic Machine",
26 | "info": "",
27 | "sticky": 0,
28 | "x": 410,
29 | "y": 80,
30 | "wires": []
31 | },
32 | {
33 | "id": "cd612bbe.c1cd68",
34 | "type": "comment",
35 | "z": "42c6ce94.a9202",
36 | "name": "Performance Machine",
37 | "info": "",
38 | "sticky": 0,
39 | "x": 440,
40 | "y": 240,
41 | "wires": []
42 | },
43 | {
44 | "id": "5216b1db.909bc",
45 | "type": "comment",
46 | "z": "42c6ce94.a9202",
47 | "name": "Eco Machine",
48 | "info": "",
49 | "sticky": 0,
50 | "x": 410,
51 | "y": 400,
52 | "wires": []
53 | },
54 | {
55 | "id": "cc846ce2.eef4a",
56 | "type": "function",
57 | "z": "42c6ce94.a9202",
58 | "name": "Basic Machine Status",
59 | "func": "function getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n\nlet programList = [\"EDS TTU 553 V8\",\"PA12 - KKT Vorheizen\",\"TC 3D AKF PA11\",\"detax v30\",\"Tool changing position\",\"EDS PT 3404 Balanced\",\"Postprocessing\", \"PT Black TL l-R\", \"PT White FT\", \"Preprocessing\", \"Cleaning\", \"PT M FT L-R\"];\n\nlet progr = programList[Math.floor(Math.random() * programList.length)];\nvar stat = getRandomInt(1,5);\nvar id = getRandomInt(1000,9999999);\n\nvar obj = {};\nobj._time = new Date();\nobj.Machine_Status = stat;\nobj.Program_Id = id;\nobj.Program_Name = progr;\n\nmsg.payload = obj;\nreturn msg;",
60 | "outputs": 1,
61 | "language": "javascript",
62 | "noerr": 0,
63 | "x": 440,
64 | "y": 120,
65 | "wires": [
66 | [
67 | "7f529f86.7fc4e"
68 | ]
69 | ]
70 | },
71 | {
72 | "id": "c5716581.b7e138",
73 | "type": "function",
74 | "z": "42c6ce94.a9202",
75 | "name": "Basic Machine Sensors",
76 | "func": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\nvar temp_pre = getRandomInt(80,100) + getRandomDouble(10,30);\nvar temp_work = getRandomInt(120,140) + getRandomDouble(10,60);\nvar press_pre = getRandomInt(10,20) + getRandomDouble(2,7);\nvar press_work = getRandomInt(2,5) + getRandomDouble(2,7);\n\nvar obj = {};\nobj._time = new Date();\nobj.Pressure_Preheater = press_pre;\nobj.Pressure_WorkingChamber = press_work;\nobj.Temp_Preheater = temp_pre;\nobj.Temp_WorkingChamber = temp_work;\n\nmsg.payload = obj;\nreturn msg;",
77 | "outputs": 1,
78 | "language": "javascript",
79 | "noerr": 0,
80 | "x": 440,
81 | "y": 180,
82 | "wires": [
83 | [
84 | "79dc13ad.bb2cac"
85 | ]
86 | ]
87 | },
88 | {
89 | "id": "6f440ba8.2034e4",
90 | "type": "function",
91 | "z": "42c6ce94.a9202",
92 | "name": "Basic Machine Status",
93 | "func": "function getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n\nlet programList = [\"EDS TTU 553 V8\",\"PA12 - KKT Vorheizen\",\"TC 3D AKF PA11\",\"detax v30\",\"Tool changing position\",\"EDS PT 3404 Balanced\",\"Postprocessing\", \"PT Black TL l-R\", \"PT White FT\", \"Preprocessing\", \"Cleaning\", \"PT M FT L-R\"];\n\nlet progr = programList[Math.floor(Math.random() * programList.length)];\nvar stat = getRandomInt(1,5);\nvar id = getRandomInt(1000,9999999);\n\nvar obj = {};\nobj._time = new Date();\nobj.Machine_Status = stat;\nobj.Program_Id = id;\nobj.Program_Name = progr;\n\nmsg.payload = obj;\nreturn msg;",
94 | "outputs": 1,
95 | "language": "javascript",
96 | "noerr": 0,
97 | "x": 440,
98 | "y": 280,
99 | "wires": [
100 | [
101 | "27a7aa93.b2ae06"
102 | ]
103 | ]
104 | },
105 | {
106 | "id": "6eebeb9e.d6f334",
107 | "type": "function",
108 | "z": "42c6ce94.a9202",
109 | "name": "Basic Machine Sensors",
110 | "func": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\nvar temp_pre = getRandomInt(80,100) + getRandomDouble(10,30);\nvar temp_work = getRandomInt(120,140) + getRandomDouble(10,60);\nvar press_pre = getRandomInt(10,20) + getRandomDouble(2,7);\nvar press_work = getRandomInt(2,5) + getRandomDouble(2,7);\n\nvar obj = {};\nobj._time = new Date();\nobj.Pressure_Preheater = press_pre;\nobj.Pressure_WorkingChamber = press_work;\nobj.Temp_Preheater = temp_pre;\nobj.Temp_WorkingChamber = temp_work;\n\nmsg.payload = obj;\nreturn msg;",
111 | "outputs": 1,
112 | "language": "javascript",
113 | "noerr": 0,
114 | "x": 440,
115 | "y": 340,
116 | "wires": [
117 | [
118 | "9499b1d7.0e5eb"
119 | ]
120 | ]
121 | },
122 | {
123 | "id": "846f330b.fd38c",
124 | "type": "function",
125 | "z": "42c6ce94.a9202",
126 | "name": "Basic Machine Status",
127 | "func": "function getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\n\nlet programList = [\"EDS TTU 553 V8\",\"PA12 - KKT Vorheizen\",\"TC 3D AKF PA11\",\"detax v30\",\"Tool changing position\",\"EDS PT 3404 Balanced\",\"Postprocessing\", \"PT Black TL l-R\", \"PT White FT\", \"Preprocessing\", \"Cleaning\", \"PT M FT L-R\"];\n\nlet progr = programList[Math.floor(Math.random() * programList.length)];\nvar stat = getRandomInt(1,5);\nvar id = getRandomInt(1000,9999999);\n\nvar obj = {};\nobj._time = new Date();\nobj.Machine_Status = stat;\nobj.Program_Id = id;\nobj.Program_Name = progr;\n\nmsg.payload = obj;\nreturn msg;",
128 | "outputs": 1,
129 | "language": "javascript",
130 | "noerr": 0,
131 | "x": 440,
132 | "y": 440,
133 | "wires": [
134 | [
135 | "e684622d.42458"
136 | ]
137 | ]
138 | },
139 | {
140 | "id": "c6db8a58.f773c8",
141 | "type": "function",
142 | "z": "42c6ce94.a9202",
143 | "name": "Basic Machine Sensors",
144 | "func": "function getRandomDouble(min, max) {\n return (Math.random() * (max - min) + min).toString();\n}\nfunction getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return (Math.floor(Math.random() * (max - min + 1)) + min).toString();\n}\nvar temp_pre = getRandomInt(80,100) + getRandomDouble(10,30);\nvar temp_work = getRandomInt(120,140) + getRandomDouble(10,60);\nvar press_pre = getRandomInt(10,20) + getRandomDouble(2,7);\nvar press_work = getRandomInt(2,5) + getRandomDouble(2,7);\n\nvar obj = {};\nobj._time = new Date();\nobj.Pressure_Preheater = press_pre;\nobj.Pressure_WorkingChamber = press_work;\nobj.Temp_Preheater = temp_pre;\nobj.Temp_WorkingChamber = temp_work;\n\nmsg.payload = obj;\nreturn msg;",
145 | "outputs": 1,
146 | "language": "javascript",
147 | "noerr": 0,
148 | "x": 440,
149 | "y": 500,
150 | "wires": [
151 | [
152 | "25e44221.d6425e"
153 | ]
154 | ]
155 | },
156 | {
157 | "id": "31e8510f.54df0e",
158 | "type": "inject",
159 | "z": "42c6ce94.a9202",
160 | "name": "",
161 | "topic": "",
162 | "payload": "",
163 | "payloadType": "date",
164 | "repeat": "300",
165 | "repeatEnd": "0",
166 | "endTime": "0",
167 | "crontab": "",
168 | "offset": "",
169 | "once": false,
170 | "properties": "",
171 | "timezone": "utc",
172 | "betweentimesunit": "m",
173 | "enableRuleEngine": false,
174 | "showNextExecution": true,
175 | "powerMode": false,
176 | "x": 130,
177 | "y": 260,
178 | "wires": [
179 | [
180 | "cc846ce2.eef4a",
181 | "c5716581.b7e138",
182 | "6f440ba8.2034e4",
183 | "6eebeb9e.d6f334",
184 | "846f330b.fd38c",
185 | "c6db8a58.f773c8"
186 | ]
187 | ]
188 | },
189 | {
190 | "id": "7f529f86.7fc4e",
191 | "type": "write timeseries",
192 | "z": "42c6ce94.a9202",
193 | "name": "",
194 | "topic": "4c011fd02a2b4990a80d2c4c6d25ef23/Dashboard_Machine_Status",
195 | "topicData": "{\"asset\":\"4c011fd02a2b4990a80d2c4c6d25ef23\",\"assetName\":\"Basic Machine\",\"aspect\":\"7600f42a1d324f73b10d00ec963febfd\",\"aspectName\":\"Dashboard_Machine_Status\",\"variable\":null,\"variableName\":null}",
196 | "topicLabel": "Basic Machine/Dashboard_Machine_Status",
197 | "assetName": "",
198 | "aspectName": "",
199 | "useMerging": false,
200 | "x": 950,
201 | "y": 120,
202 | "wires": []
203 | },
204 | {
205 | "id": "79dc13ad.bb2cac",
206 | "type": "write timeseries",
207 | "z": "42c6ce94.a9202",
208 | "name": "",
209 | "topic": "4c011fd02a2b4990a80d2c4c6d25ef23/Dashboard_Machine_Sensor",
210 | "topicData": "{\"asset\":\"4c011fd02a2b4990a80d2c4c6d25ef23\",\"assetName\":\"Basic Machine\",\"aspect\":\"59e5446feebb454eaf3ef7ce24565dfb\",\"aspectName\":\"Dashboard_Machine_Sensor\",\"variable\":null,\"variableName\":null}",
211 | "topicLabel": "Basic Machine/Dashboard_Machine_Sensor",
212 | "assetName": "",
213 | "aspectName": "",
214 | "useMerging": false,
215 | "x": 950,
216 | "y": 180,
217 | "wires": []
218 | },
219 | {
220 | "id": "27a7aa93.b2ae06",
221 | "type": "write timeseries",
222 | "z": "42c6ce94.a9202",
223 | "name": "",
224 | "topic": "a12faec62d33439ea297adcde30ef5d2/Dashboard_Machine_Status",
225 | "topicData": "{\"asset\":\"a12faec62d33439ea297adcde30ef5d2\",\"assetName\":\"Performance Machine\",\"aspect\":\"7600f42a1d324f73b10d00ec963febfd\",\"aspectName\":\"Dashboard_Machine_Status\",\"variable\":null,\"variableName\":null}",
226 | "topicLabel": "Performance Machine/Dashboard_Machine_Status",
227 | "assetName": "",
228 | "aspectName": "",
229 | "useMerging": false,
230 | "x": 970,
231 | "y": 280,
232 | "wires": []
233 | },
234 | {
235 | "id": "9499b1d7.0e5eb",
236 | "type": "write timeseries",
237 | "z": "42c6ce94.a9202",
238 | "name": "",
239 | "topic": "a12faec62d33439ea297adcde30ef5d2/Dashboard_Machine_Sensor",
240 | "topicData": "{\"asset\":\"a12faec62d33439ea297adcde30ef5d2\",\"assetName\":\"Performance Machine\",\"aspect\":\"59e5446feebb454eaf3ef7ce24565dfb\",\"aspectName\":\"Dashboard_Machine_Sensor\",\"variable\":null,\"variableName\":null}",
241 | "topicLabel": "Performance Machine/Dashboard_Machine_Sensor",
242 | "assetName": "",
243 | "aspectName": "",
244 | "useMerging": false,
245 | "x": 980,
246 | "y": 340,
247 | "wires": []
248 | },
249 | {
250 | "id": "e684622d.42458",
251 | "type": "write timeseries",
252 | "z": "42c6ce94.a9202",
253 | "name": "",
254 | "topic": "1ccfd846e53447de88fdaaeeeddd6d78/Dashboard_Machine_Status",
255 | "topicData": "{\"asset\":\"1ccfd846e53447de88fdaaeeeddd6d78\",\"assetName\":\"Eco Machine\",\"aspect\":\"7600f42a1d324f73b10d00ec963febfd\",\"aspectName\":\"Dashboard_Machine_Status\",\"variable\":null,\"variableName\":null}",
256 | "topicLabel": "Eco Machine/Dashboard_Machine_Status",
257 | "assetName": "",
258 | "aspectName": "",
259 | "useMerging": false,
260 | "x": 950,
261 | "y": 440,
262 | "wires": []
263 | },
264 | {
265 | "id": "25e44221.d6425e",
266 | "type": "write timeseries",
267 | "z": "42c6ce94.a9202",
268 | "name": "",
269 | "topic": "1ccfd846e53447de88fdaaeeeddd6d78/Dashboard_Machine_Sensor",
270 | "topicData": "{\"asset\":\"1ccfd846e53447de88fdaaeeeddd6d78\",\"assetName\":\"Eco Machine\",\"aspect\":\"59e5446feebb454eaf3ef7ce24565dfb\",\"aspectName\":\"Dashboard_Machine_Sensor\",\"variable\":null,\"variableName\":null}",
271 | "topicLabel": "Eco Machine/Dashboard_Machine_Sensor",
272 | "assetName": "",
273 | "aspectName": "",
274 | "useMerging": false,
275 | "x": 950,
276 | "y": 500,
277 | "wires": []
278 | }
279 | ]
280 |
--------------------------------------------------------------------------------
/Dashboard_getting_started/Setup/readme.md:
--------------------------------------------------------------------------------
1 | # Setup steps for the getting started VFC Dashboard:
2 | This short tutorial will show you how to set up the simulated assets and the data generator for the VFC dashboard example.
3 |
4 | # Asset Setup:
5 | We want to create an Asset Type **VFC_Dashboard_Machine**:
6 |
7 | 
8 |
9 | with three Aspects assigned to the Asset type:
10 | - Dashboard_Machine_Location [Static]
11 | - Dashboard_Machine_Sensor [Dynamic]
12 | - Dashboard_Machine_Status [Dynamic]
13 |
14 | To do this, please follow the following steps and note the notation for the variables is [Unit, DATATYPE, Max. lenght]
15 | - [x] Setup static Aspect type Dashboard_Machine_Location with three variables:
16 | - latitude [-, DOUBLE, -]
17 | - longitude [-,DOUBLE, -]
18 | - Software_Version [-, STRING, 32]
19 |
20 | - [x] Setup dynamic Aspect type Dashboard_Machine_Location with four variables:
21 | - Pressure_Preheater [Bar, DOUBLE, -]
22 | - Pressure_WorkingChamber [Bar, DOUBLE, -]
23 | - Temp_Preheater [°C, DOUBLE, -]
24 | - Temp_WorkingChamber [°C, DOUBLE, -]
25 |
26 | - [x] Setup dynamic Aspect type Dashboard_Machine_Status with three variables:
27 | - Machine_Status [-, INT, -]
28 | - Program_Id [-, INT, -]
29 | - Program_Name [-, STRING, 255]
30 | - [x] Create an Asset Type of parent type core.basicasset, name it **VFC_Dashboard_Machine** and add the three created Aspect types under the Aspects dropdown window
31 |
32 | Your Asset type should look like this:
33 |
34 | 
35 |
36 | - [x] Now Create 3 Assets of type **VFC_Dashboard_Machine** and name them:
37 | - Basic
38 | - Performance
39 | - Eco
40 |
41 | For the purpose of this example, let's assume you are a factory manager that has three different machines (Basic, Performance and Eco), but they all share the same data model. Let's assume each machine is exhibited at a fair to showcase the power and potential of the IIoT with Mindsphere. Basic is located at Frankfurt, Performance at Munich and Eco at Berlin. We already created a static aspect *Dashboard_Machine_Location* to store the latitude, longitude and software version of each machine. Now, we have to initialize these Values. To do so, click on the edit symbol of the Asset, open the dropdown of *static aspects* and fill in the following under *Dashboard_Machine_Location*:
42 |
43 | - [x] For machine **Basic**:
44 | - latitude: 50.1109
45 | - longitude: 8.6508
46 | - Software_Version: 1.0.0.2
47 | - [x] For machine **Performance**:
48 | - latitude: 48.1353
49 | - longitude: 11.6962
50 | - Software_Version: 1.3.3.0
51 | - [x] For machine **Eco**:
52 | - latitude: 52.5040
53 | - longitude: 13.2733
54 | - Software_Version: 1.5.0.0
55 |
56 | Now you want to monitor them, but to do so, your machines need to send data. Let's generate some data using Mindspheres Visual Flow Creator application.
57 |
58 | # VFC Data Generator:
59 | The Visual Flow Creator (VFC) is a [Node-RED](https://nodered.org) based application that can simplify and automate a lot of tasks inside Mindsphere. If you are new to the VFC, please take a few minutes and go through the basics in our [Documentation](https://documentation.mindsphere.io/resources/html/visualflow-creator/en-US/index.html). It will help you understanding the concept of VFC tremendously.
60 |
61 | Start by creating a new flow and name it something like *DataGenerator*. Then copy the json data from the [DataGenerator.json](../Resources/IMPORT_DataGenerator.json) file to your clipboard and go back to the VFC.
62 |
63 | Under the options tab, click on import:
64 |
65 | 
66 |
67 | and paste the json data in the blank field. Click on import and you should have couple of nodes that you can now place in the flow. Then Click Save
68 |
69 | Your *DataGenerator* Flow should now look like this:
70 |
71 | 
72 |
73 | > This flow will be triggered by the inject node every 5 minutes. If you want to alter the interval data is written to your machines, feel free to do so.
74 |
75 | To finish this flow, you have to map the 6 write timeseries node to your own corresponding machines. Double click on a node and choose your asset & aspect by clicking on the three dots:
76 |
77 | 
78 |
79 | > Make sure you are writing to the correct machine and the correct aspect. **Do not write directly to a variable (-> leave the variable field blank)** as we are writing several variables of an Aspect at the same time. You will get an error message if you do so.
80 |
81 | :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark:
82 |
83 | Click Save. Your Data Generator is ready to go and will run in the background. Now **[Continue Here](../readme.md#dashboard-structure)** and get started building your VFC Dashboard!
84 |
85 | :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark:
86 |
87 | ### Data Generator best practices:
88 | VFC offers a build in method to simulate/generate data with the *generate node*. You can use it to create powerful data patterns and stack signals like: saw, sine, gauss, linear and noise.
89 |
90 | 
91 |
92 | However, sometimes the easy way also does the job. Why not simply take a random INT or DOUBLE from a defined interval?
93 | ```javascript
94 | function getRandomInt (min, max) {
95 | min = Math.ceil(min);
96 | max = Math.floor(max);
97 | return (Math.floor(Math.random() * (max - min + 1)) + min).toString();
98 | }
99 | ```
100 | ```javascript
101 | function getRandomDouble (min, max) {
102 | return (Math.random() * (max - min) + min).toString();
103 | }
104 | ```
105 | You can use these javascript code snippets in a *function node*:
106 |
107 | 
108 |
109 | generate the necessary data und pass them as *msg.payload* to our *write-timeseries node*.
110 | You can use the same (simple) logic to generate a string by picking a random index of a string array.
111 |
112 | ```javascript
113 | let StringList = ["String A", "String B", "String C", "String D", "String ...", "String X"];
114 | let RandomString = StringList[Math.floor(Math.random() * StringList.length)];
115 | ```
116 | A *function node* that gerates random integers and random strings and passes them to the *write-timeseries node* can look like this:
117 |
118 | ```javascript
119 | //declare your functions
120 | function getRandomInt(min, max) {
121 | min = Math.ceil(min);
122 | max = Math.floor(max);
123 | return (Math.floor(Math.random() * (max - min + 1)) + min).toString();
124 | }
125 | //set up your string array and pick a random string out of it
126 | let StringList = ["String A", "String B", "String C", "String D", "String ...", "String X"];
127 | let progr = StringList[Math.floor(Math.random() * StringList.length)];
128 |
129 | //generate some random integers using your getRandomInt function
130 | var stat = getRandomInt(1,5);
131 | var id = getRandomInt(1000,9999999);
132 |
133 | //initialize your payload object and send it as msg.payload
134 | var obj = {};
135 | obj._time = new Date();
136 | obj.Machine_Status = stat;
137 | obj.Program_Id = id;
138 | obj.Program_Name = progr;
139 |
140 | msg.payload = obj;
141 | return msg;
142 | ```
143 |
144 |
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/Data_Generator_Flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/Data_Generator_Flow.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/asset_complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/asset_complete.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/asset_switch.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/asset_switch.mp4
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/asset_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/asset_type.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/button_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/button_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/change_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/change_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/change_tab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/change_tab.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/check_nodes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/check_nodes.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/dashboard_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/dashboard_menu.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/dashpic_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/dashpic_1.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/event_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/event_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/event_table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/event_table.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_1.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_2.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_3.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_4.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_5.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_6.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/flowpic_7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/flowpic_7.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/function_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/function_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/generate_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/generate_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/group_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/group_edit.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/group_structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/group_structure.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/groups_content.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/groups_content.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/hide_show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/hide_show.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/import.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/led_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/led_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/logical_grouping.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/logical_grouping.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/map.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/map_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/map_text.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/notification_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/notification_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/open_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/open_dashboard.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/overview.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/read_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/read_location.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/readme.md:
--------------------------------------------------------------------------------
1 | # This folder stores the pictures used in the main and Setup readme.md
2 |
3 | You do not need the content of this folder to complete the getting started example Dashboard.
4 |
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/selector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/selector.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/store_ctx_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/store_ctx_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/switch_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/switch_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/tab_structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/tab_structure.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/tabs_groups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/tabs_groups.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/text_node.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/text_node.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/text_node_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/text_node_2.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/text_node_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/text_node_3.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/doc/write_timeseries.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/Dashboard_getting_started/doc/write_timeseries.png
--------------------------------------------------------------------------------
/Dashboard_getting_started/readme.md:
--------------------------------------------------------------------------------
1 | # VFC Dashboard - A Getting Started Example:
2 | This example will guide you step by step through the VFC Dahsboard functionalities. You will create a simple but interactive dashboard that shows the status of your three (simulated) machines that you already connected to Insights Hub. You will learn the essential nodes for dashboarding with the VFC and will be able to extend your dashboard according to your own needs. The Dashboard you create will look like this:
3 |
4 | 
5 |
6 | This tutorial is meant to start from scratch. You will set up your Assets, generate data for them and build your dashboard on the basis of this data. If you just want to check out the dashboard, import it [From Here](./Resources/IMPORT_Dashboard.json). Please note, that you have to change major components to fit the dashboard to your own tenant's asset model.
7 |
8 | # Prerequisites:
9 | - around 120 minutes of time
10 | - Visual Flow Creator
11 | - Asset Manager
12 | - basic Javascript knowledge is helpful, but not required
13 | > All required applications and resources are part of a [Start for free](https://siemens.mindsphere.io/en/start) tenant. You can follow this tutorial along regardless of your Insights Hub package.
14 |
15 | > This tutorial is designed for beginners. However, some fundamental knowledge about the VFC will make your learning journey more enjoyable. Learn the basics [Here](https://documentation.mindsphere.io/resources/html/visualflow-creator/en-US/index.html).
16 |
17 | # Setup:
18 | We will simulate three different versions of an industrial machine:
19 | - Basic
20 | - Performance
21 | - Eco
22 |
23 | This step requires you to be familiar with Insights Hub's asset structure and that you can create new aspects, assets and asset types. If this sounds like a big headache to you, please visit the [Asset Manager Tutorial](https://siemens.mindsphere.io/en/docs/tutorials/asset-manager) first.
24 |
25 | If not, please follow the [Setup Instructions](./Setup/readme.md) and come back once you completed the process.
26 |
27 | # Dashboard Structure:
28 | Start by creating a new flow and name it something like *Dashboard* or *MyFirstDashboard*. Then switch to the dashboard tab under Layout, which will be blank for now.
29 |
30 | 
31 |
32 | Here you can structure the basic layout of your dashboard using tabs and groups. A tab is the equivalent of a dashboard page. You can assign different content to each tab and it will then only be displayed on that that. Each tab will display your content in groups, which act like columns. For example, a structure that you created under *Tabs & Links* like this:
33 |
34 | 
35 |
36 | the corresponding dashboard page would be organized as shown below:
37 |
38 | 
39 |
40 | Inside a group (column), the dashboard content is structured vertically, from top to bottom. If you assigned three items to a single group on a single tab like this:
41 |
42 | 
43 |
44 | the corresponding dashboard page would be organized as shown below:
45 |
46 | 
47 |
48 | As you can see, *Group 1* is centered automatically on the tab. You don't have to worry about the position of your groups, Mindsphere does that automatically for you. Just remember the following rule of thumb:
49 |
50 | > **Tabs** are **individual dashboard pages**. You can only view one tab at once.
51 |
52 | > **Groups**, that are structured from **top to bottom**, will be displayed from **left to right** on your dashboard page.
53 |
54 | > **Content**, that is structured from **top to bottom**, will be displayed from **top to bottom** inside a group.
55 |
56 | Now let's start building the overview dashboard:
57 | - Create a tab and name it *Overview*
58 | - Under *Overview*, create three new groups
59 | - Rename these groups to *Selector*, *Asset Map* and *Info*
60 | - Remember the way the VFC is displaying groups. You want to place the *Selector* group on the left and the *Info* group on the right
61 |
62 | You can rename tabs and groups by hovering over them and clicking the *edit* button:
63 |
64 | 
65 |
66 | Now create a second tab called *Detail* with only one group named *Events*. We will use the *Detail* tab at the very end of this tutorial, so consider this a little teaser.
67 |
68 | # Designing the Dashboard:
69 | In this chapter, we will bring some life and functionality to our Overview dashboard. This tutorial is designed to build all elements from scratch and simultaneously show the logic behind a VFC dashboard. Some steps might be overcomplicated with the purpose of demonstrating several VFC nodes.
70 |
71 | > If you just want to check out the final result, you can copy paste the [Json Flow Data From Here](./Resources/IMPORT_Dashboard.json). It will import all elements, including nodes, tabs and groups. Remember to adjust all *read-timeseries* and *write-timeseries* nodes to your own assets.
72 |
73 | For the beginning, we will place three *text* nodes and three *button* nodes in the flow. This will be our Asset selector, where each machine has it's own button like below:
74 |
75 | 
76 |
77 | But before styling our nodes, we have to adjust the width of the group. Click *edit* on the *Selector* group and give it a width of 9. Rearrange your nodes in the flow, so that the *text* nodes are alternating with the *button* nodes, starting with the text node. Double click the first *text node* to open it's properties. Here you can assign the node to a group and change it's apperence. We will start with our Basic machine. Copy the following setting:
78 |
79 | 
80 |
81 | So we assigned the *text* node to our *Selector* group, gave it a form of 6x2 (width x height) and chose the:
*label* **value** (left aligned)
format, where *label* = Asset: and **value** = Basic. This text is static and will not change depending on the input.
Now rinse and repeat for the other two *text* nodes, but remember to change the **value** to Performance and Eco.
82 |
83 | Now apply the following settings to the three *button* nodes:
84 |
85 | 
86 |
87 | The positioning of nodes in the flow is not relevant for the structure of the dashboard. By organizing your flow, you will have a huge benefit once it get's complicated, but the order of the nodes under the *Selection* group is decisive. The check, which node in the group is the corresponding node in the flow, just hover over it. The node in the flow will be bordered red:
88 |
89 | 
90 |
91 | Your flow should look like this:
92 |
93 | 
94 |
95 | Now you want to switch to your dashboard and view your progress.
96 | >Hint: You can open your dashboard by clicking *Open dashboard in new tab*. Here, you can also reload all dashboards to apply changes made to the flow model.
97 | >
98 | >
99 |
100 | The *Selection* group of the dashboard should look like this:
101 |
102 | 
103 |
104 | The next step is to implement a map, where you can see the location of the asset you chose in the *Selector* group. Mindsphere offers some pre-build nodes, that reflect the Mindsphere look and feel and can be implemented into your VFC dashboards. You find them in the *MDSP Dashboard* node section. There is a date picker, timeseries chart, asset list, aspect variable selector, event table and the Mindsphere Map. But first, change the *Asset Map* group width to 122. Now drop the *MDSP Map* and another *text* node into your flow, assign them to the *Asset Map* group (the *MDSP Map* node is positioned below the *text* node) and configure them as follows:
105 |
106 | 
107 |
108 | 
109 |
110 | Maybe you have noticed that we already set initial position and zoom level for the *MDSP Map* node. Feel free to alter the position to your company's headquarters and experiment with the zoom level. Furthermore, the **value** of the *text* node is {{msg.name}}. We want to display a dynamic text which changes depending on your selection in the *Selector* group. The text node will check the incoming message to have a msg.name property and will display it`s value. Changing the text according to the selected Asset is great, but we want to display the stored location of this asset in the map too.
111 |
112 | > You can change the initial position of the *MDSP Map* by sending a payload with {latitude, longitude, zoomLevel}
113 |
114 | Let's assume, our three machines Basic, Performance and Eco are located on three different fairs in Germany as exhibition machines. Basic is located at fair Frankfurt, Performance at fair Munich and Eco at fair Berlin. We have already set the location of the machines in the [Setup](./Setup/readme.md#asset-setup) and want to get these locational informations into our flow. This can be achievend using the *read-aspect-static* node, as we want to read data from the static aspect *Dashboard_Machine_Location*. Configure one *read-aspect-static* node for each machine with the given example:
115 |
116 | 
117 |
118 | In the next step, we hava to transform the data to the form {latitude, longitude, zoomLevel}, so that the *MDSP Map* can interpret the input. We achieve this using *function* nodes. Create three *function* nodes (again, one for each machine) and use the following code:
119 |
120 | ```javascript
121 | var long = msg.payload.longitude;
122 | var lat = msg.payload.latitude;
123 |
124 | var maploc = {'longitude':long,'latitude': lat,'zoomLevel': 12};
125 | msg.payload = maploc;
126 | msg.name = 'INSERT MACHINE TYPE HERE';
127 | return msg;
128 | ```
129 | Obviously, change ***INSERT MACHINE TYPE HERE*** to the corresponding machine type in your function code.
130 |
131 | Now it is time to connect the nodes and complete our first dashboard functionality:
132 |
133 | 
134 |
135 | Now try out your dashboard. The *Location of* and Map view should change every time you click an Asset in the *Selector* group:
136 |
137 | https://user-images.githubusercontent.com/90254123/164717991-9ee5fa5a-f5b6-4deb-a426-beec63d6571a.mp4
138 |
139 | Our next topic will be the third group, the *Info* group. Here we want to display some quick info about the selected machine. In this case:
140 | - A status indicator
141 | - and the software version, the machine is running on
142 |
143 | First things first, adjust the width of the *Info* group to 12. Now we are facing a design problem: If we load or reload the dashboard (so no machine is selected), the whole skeleton of the *Info* group would be visible, but empty. So we want to hide the *Info* group by default and only display it if any of the machines is selected. We can use the *ui control* node from the *dashboard* section. The default function iss to change the currently displayed tab by sending the tab name as *msg.payload*, but you can also control the visibility of groups of widgets by sending a payload in the form:
144 | ```JSON
145 | {
146 | "group": {
147 | "hide": ["tab_name_group_name_with_underscores"],
148 | "show": ["reveal_another_group"],
149 | "focus": true
150 | }
151 | }
152 | ```
153 | >The "focus" : true is optional.
154 |
155 | Another feature of the ui node is that it emit's a msg when a browser client connects or looses connection. Let´s combine these funtionalities to create the following. When the dashboard is loaded, the ui node emit's a message and the *info* group is hidden. On the other hand, when you select one of the machines, the *info* group is displayed again:
156 |
157 | 
158 |
159 | To set the *msg.payload*, you could use a *function* node or just take advantage of the *change* node. Choose the *Set* property from the dropdown and set to msg. payload to a JSON object, like this:
160 |
161 | 
162 |
163 | By clicking the three dots in the change, node, you can insert JSON code. Use this code to hide the *Info* group:
164 | ```JSON
165 | {
166 | "group": {
167 | "hide": [
168 | "Overview_Info"
169 | ]
170 | }
171 | }
172 | ```
173 | And this code to show the *Info* group:
174 | ```JSON
175 | {
176 | "group": {
177 | "show": [
178 | "Overview_Info"
179 | ]
180 | }
181 | }
182 | ```
183 | Now that we implemented that functionality, let´s give the *Info* group some content! We want to display the Software Version of the machine and a status indicator, showing the actual status of our machine. The data generator is generating a status code between 1 and five, so lets' assume:
184 | - 1 = Status OK
185 | - 2 = Status Information
186 | - 3 = Status WARNING
187 | - 4 = Status FAULT
188 | - 5 = Status MAINTENANCE
189 |
190 | Remember, that the *Machine_Status* is a dynamic variable and the *Software_Version* is a static attribute. So we need three *read-timeseries* nodes and three *read-aspect-static* nodes from the *mindsphere* section. Drop them in your flow and arrange them as you like. Now adjust all six *read* nodes, so they read the right data from your assets. For the three *read-timeseries* nodes choose Mode *Period* and set the Period to *2 hours* with no offset. Group them logically, like so:
191 |
192 | 
193 |
194 | Now drop five more nodes into your flow:
195 | - 2 *function* nodes from the *function* node section
196 | - 2 *text* nodes from the *dashboard* node section
197 | - 1 *led* node from the *dashboard* node section
198 |
199 | and change the settings to the following for the first *text* node:
200 |
201 | 
202 |
203 | for the *led* node:
204 |
205 | 
206 |
207 | and for the second *text* node:
208 |
209 | 
210 |
211 | Now that these elements are set up, let's take care of the function nodes. The *read-timeseries* nodes return an array with multiple data points, but we only want to extract the latest value in this array and sent it as *msg.payload*. Name the first *function* node ***Extract Machine Status*** and the second *function* node ***Extract Software Version***. Use the following javascript code for the *Extract Machine Status* node:
212 | ```javascript
213 | var lastDataPoint = msg.payload.slice(-1)[0];
214 | msg.payload =lastDataPoint['Machine_Status'];
215 | return msg;
216 | ```
217 | and insert this code in the *Extract Software Version* node:
218 | ```javascript
219 | msg.payload = msg.payload['Software_Version'];
220 | return msg;
221 | ```
222 | Next we simply have to combine the nodes:
223 |
224 | 
225 |
226 | Try these new functionalities in your own dashboard. If you click on a machine, the led and Software Version should change dynamically:
227 |
228 | https://user-images.githubusercontent.com/90254123/166253526-9b203cf0-5e0d-42ab-9dd6-360943efe8bd.mp4
229 |
230 | Let's take a short summary. As a VFC user you have already visualized your three assets, their location and status. Now you want to take things to the next level. Imagine beeing a machine Operator, who wants to report a critical machine failure as quickly as possible directly from the dashboard. Furthermore, you want to be able to navigate to your machine and see what happened. Insights Hub offers a functionality that supports our idea, it' called **events**. So let's implement events in our dashboard. But we have to do something else first. The logic of our flow needs to know which machine is actually selected. We need to store some kind of indicator which machine is selected and we can do it in two different ways:
231 | 1. By sending the machine directly as *msg.payload* or as a *msg.xxxxx* property
232 | 2. By setting up a flow variable
233 | When you are declaring variables in a *function* node, they are of course only valid and accessible in the respective function. Flow variables however are stored on flow level and can be used to store some data and read it again later in the flow without the need to send it in the *msg*. We now want to store our selected machine in a flow variable called *ActiveAsset*. Drop three *change* nodes and one *store ctx* node into your flow.
234 |
235 | Configure each *change* node to only have one rule that sets the *msg.payload* to a string. The first node set's *msg.payload* to *Basic*, the second to *Performance* and the third to *Eco*. Use these settings for the *store ctx* node:
236 |
237 | 
238 |
239 | Now we will add a couple of nodes on top:
240 | - one *button* node
241 | - one *read ctx* node
242 | - one *switch* node
243 | - one *change* node
244 | - one *ui control* node
245 |
246 | First: the *button* node. Assign it to the *Info* Group and type *Go To Asset* in the *Label* field. Configure the *read ctx* node to *Context* = *Flow* and *Key* = *ActiveAsset*. By doing so, we will read the selected machine that was previosly stored in the *ActiveAsset* flow variable. Configure the switch node as follows:
247 |
248 | 
249 |
250 | The *switch* node now has three outputs and will route the *msg* signal with the given rules. So if *msg.payload* = *Basic*, the node will send a message to the first output. With the help of the *change* node, set the *msg.payload* to detail. Let's understand the purpose of these nodes. When you click on the button *Go To Asset*, the flow reads the *ActiveAsset* flow variable and will direct the flow in a way, that the dashboard changes to a new tab; the detail page for a machine. We will create one of these detail tabs, for our *Basic* machine. Add a new tab in the *Tabs&Links* menu and name it **Detail**. Then connect the nodes like this:
251 |
252 | 
253 |
254 | Connect the nodes to the rest of your flow and your flow should now have the following form:
255 |
256 | 
257 |
258 | So, if you have the *Basic* machine selected and click on *Go To Asset*, you should be redirected to a new blank tab. As a control mechanism, try to click on *Go To Asset* if *Performance* or *Eco* machine is selected. Nothing should happen there, as we have not connected any nodes to these routings of the *switch* node yet.
259 |
260 | Now let's do the same for our emergency button. Drop these buttons in the flow and place them in the right order (from left to right):
261 | - one *change* node
262 | - one *button* node
263 | - one *read ctx* node
264 | - one *switch* node
265 |
266 | On top of that, add three *create event* nodes and one *notification* node and place them on the right side of the flow. Let us configure the nodes together, but the logic is the same as for the tab switch. Configure the *change* node to set the *msg.payload* to a string *Critical Failure*. Assign the *button* node to the *Info* group and *Label* ist *Report emergency*. The *read ctx* node has a *Context* of *Flow* (so it can only read variables in the flow scope) and a *Key* of *ActiveAsset*. Configure the switch node in the same way as you did a few steps before:
267 |
268 | 
269 |
270 | You also have to change the settings of the *create event* nodes because you have to specify the type of event that VFC generates for you. These are the settings for the *Basic* machine:
271 |
272 | 
273 |
274 | Adjust the *create event* node settings for the other two machines as well, but change the target asset and the *Description* text. Finally, take these settings for the *notification* node:
275 |
276 | 
277 |
278 | Connect the nodes to make the flow logic functional:
279 |
280 | 
281 |
282 | And the whole bottom part of your flow should look like this:
283 |
284 | 
285 |
286 | But what exactly are these nodes doing? If a machine is selected and you click on the button *Report emergency* you create an event for this machine, which is saved and bound to your asset, so you can see and use this event in the future or execute other commands dependent of the event severity. At the same time, a notification pops out in the right corner of your browser to inform you that the event was successfully created.
287 |
288 | Now let's get this getting-started dashboard finished and implement one last feature: we want to see our events for a machine on our detail dashboard. Insights Hub offers the pre build *event table* node exactly for this purpose. Go to your *Detail* tab and create a new group called *Events* with a width of 26. Then drop the *event table* node from the *MDSP Dashboard* section in your flow and assign it to the *Events* group. Give the node a *Size* of 26 x 12. We want it to be big, to see al the details of the events. Choose the *Basic* machine in the Asset field and check these columns to show:
289 | - [x] Severity
290 | - [x] EntityId
291 | - [x] Timestamp
292 | - [x] Despriction
293 | - [ ] Source
294 | - [x] Acknowledged
295 | - [x] CorrlationId
296 | - [ ] TypeId
297 | - [ ] Code
298 |
299 | Then drop another *Button* node and *ui control* node in your flow. This button will take you back to the *Overview* tab. Try to configure these two nodes by yourself, so it appears on the Detail page and takes you back to the overview page when clicked.
300 | > Hint 1: Give the *Button* node a Size of 26 x 1
301 |
302 | > Hint 2: Send a JSON object as *msg.payload*
303 |
304 | > Hint 3: Send
305 | > ```JSON
306 | > {
307 | > "tab": "Overview"
308 | > }
309 | > ```
310 | > to change back to the Overview tab when clicked
311 |
312 | As you can see, displaying an event table and implementing a button that chages tabs can be achieved in only three nodes:
313 |
314 | 
315 |
316 | This will complete the content of this tutorial and your final flow should look something like this:
317 |
318 | 
319 |
320 | You finished your first dashboard! Check it out, try some things and experiment with creating events. As we all know, this dashboard is not perfect at all and has mainly the purpose to present different elements of VFC dashboarding. What would you do different? Now it's time to bring in your own ideas!
321 |
322 | # Next Steps
323 |
324 | You can extend this dashboard in many ways. See it as a starting point and add the content that you think would fit your own use case. If you are completely lost, here are some ideas what you could do:
325 | - Add more Data to the *Info* group
326 | - Create a detail dashboard for *Performance* and *Eco*
327 | 1. You can create a single tab for each machine
328 | 2. Or you can combine the three machines in one tab by creating a dynamic data layer
329 | - Implement a security check when creating an event (e.g.: Do you really want to create this event? Yes, No)
330 | - Alarm people automatically when an event is triggered
331 | - Design a dynamic text input for the triggered event
332 | - . . .
333 |
334 | # Questions and Answers
335 | Feel free to ask your questions in the [Insights Hub Developer Forum](https://community.sw.siemens.com/s/topic/0TO4O000000MihsWAC).
336 |
337 | Or open an [issue](https://github.com/mindsphere/vfc-examples/issues) if you find a bug in our examples.
338 |
339 | You want to contribute? Your pull request is always welcome!!!
340 |
341 |
--------------------------------------------------------------------------------
/DataLake_provideAccessToken/doc/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/DataLake_provideAccessToken/doc/example.png
--------------------------------------------------------------------------------
/DataLake_provideAccessToken/doc/result_IDL_AccessToken.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/DataLake_provideAccessToken/doc/result_IDL_AccessToken.png
--------------------------------------------------------------------------------
/DataLake_provideAccessToken/readme.md:
--------------------------------------------------------------------------------
1 | # Provide Access Token for Integrated Data Lake via API
2 |
3 | This small flow triggers sets up an API endpoint which can be called from external system to get an access token to Insights Hubs' Integrated Data Lake.
4 |
5 |
6 | 
7 |
8 | ## Prerequisites
9 |
10 | - Integrated Data Lake
11 |
12 | ## Setup & Configuration
13 | 1. Import the flow in Visual Flow Creator
14 | 2. Specify the API endpoint where the access token should be accessed via, e.g. `/getAccessTokenForIDL` in the HTTP-IN node (blue)
15 | 3. In the function node *configure Access Token* specify
16 | - Path inside your Integrated Data Lake where the access should be granted to (`path`)
17 | - Duration - how long should the token be valid (`durationSeconds`)
18 | - Permission to allow read or delete access to the path (`permission`) in the data lake for your files
19 | 4. Save the flow
20 |
21 | :cloud: :heavy_check_mark: You're ready ... - enjoy!
22 |
23 |
24 | ## How does this flow works
25 | The function delivers the body for the API request against the `/api/datalake/v3/generateAccessToken` endpoint. From here, the Access Token is provided and feedback to the user via the `http`-Node
26 |
27 | ## Result
28 | Once the API endpoint is accessed, the user is presented with a JSON response containing the Access Token for IDL.
29 | This can then be used in native S3-Tools to be worked with and connect to the IDL:
30 |
31 | In this example, calling the full API endpoint https://presiot-visualflowcreatorhttp.eu1.mindsphere.io/public/presiot/getAccessTokenForIDL?key=1a03090a3cc44d56c57d5cd7d545899219523b5127079317fcc2c637b3a0cab23cc1fcadce75196b36f761428e6ee80dacc64e4349928b23a2cf8e0e6495b897 results in a JSON response like shown below.
32 | 
33 |
34 |
35 | ## See also
36 | - [:shopping_cart: Insights Hub Store: Integrated Data Lake](https://www.dex.siemens.com/mindsphere/mindaccess/integrated-data-lake-essential)
37 | - [Developer Documentation: Integrated Data Lake Service](https://developer.mindsphere.io/apis/iot-integrated-data-lake/api-integrated-data-lake-overview.html)
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/DataLake_provideAccessToken/template.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "1baada46.8a7e06",
4 | "type": "debug",
5 | "z": "cba45765.fb58c8",
6 | "name": "",
7 | "active": true,
8 | "console": "false",
9 | "xaxis": "_time",
10 | "complete": "false",
11 | "x": 1140,
12 | "y": 1468.6666259765625,
13 | "wires": []
14 | },
15 | {
16 | "id": "f212685b.532758",
17 | "type": "function",
18 | "z": "cba45765.fb58c8",
19 | "name": "configure Access Token (path, duration)",
20 | "func": "\nmsg.payload=\n{\n \"path\": \"/myIdlDirectoryToAccess\", // your IDL path where you want access to\n \"durationSeconds\": 43200, // set how long token should be valid 43200sec = 12h\n \"permission\": \"READ\"\n}\nreturn msg;",
21 | "outputs": 1,
22 | "language": "javascript",
23 | "noerr": 0,
24 | "x": 580,
25 | "y": 1528.6666259765625,
26 | "wires": [
27 | [
28 | "b406ddbe.6cf27"
29 | ]
30 | ],
31 | "_type": "node"
32 | },
33 | {
34 | "id": "9904fce1.df6f3",
35 | "type": "http in",
36 | "z": "cba45765.fb58c8",
37 | "name": "[GET] /getAccessTokenForIDL",
38 | "endpoint": "/getAccessTokenForIDL",
39 | "method": "get",
40 | "upload": false,
41 | "access": "key",
42 | "key": "",
43 | "users": "",
44 | "powerMode": false,
45 | "x": 250,
46 | "y": 1528.6666259765625,
47 | "wires": [
48 | [
49 | "f212685b.532758"
50 | ]
51 | ],
52 | "_type": "node"
53 | },
54 | {
55 | "id": "b406ddbe.6cf27",
56 | "type": "http request",
57 | "z": "cba45765.fb58c8",
58 | "name": "generate IDL Access Token",
59 | "method": "POST",
60 | "ret": "txt",
61 | "url": "",
62 | "timeout": "",
63 | "mindspherePath": "/api/datalake/v3/generateAccessToken",
64 | "useMindsphereAuth": true,
65 | "isAdmin": false,
66 | "secretHeaders": "",
67 | "x": 867.0000228881836,
68 | "y": 1527.6666707992554,
69 | "wires": [
70 | [
71 | "1baada46.8a7e06",
72 | "3c215623.0aa24a"
73 | ]
74 | ],
75 | "_type": "node"
76 | },
77 | {
78 | "id": "3c215623.0aa24a",
79 | "type": "http response",
80 | "z": "cba45765.fb58c8",
81 | "name": "",
82 | "statusCode": "",
83 | "headers": {},
84 | "x": 1120,
85 | "y": 1528.6666259765625,
86 | "wires": []
87 | },
88 | {
89 | "id": "8776981f.1b3898",
90 | "type": "inject",
91 | "z": "cba45765.fb58c8",
92 | "name": "",
93 | "topic": "",
94 | "payload": "",
95 | "payloadType": "date",
96 | "repeat": "",
97 | "repeatEnd": "0",
98 | "endTime": "0",
99 | "crontab": "",
100 | "offset": "0",
101 | "once": false,
102 | "properties": "",
103 | "timezone": "utc",
104 | "betweentimesunit": "m",
105 | "enableRuleEngine": false,
106 | "showNextExecution": false,
107 | "powerMode": false,
108 | "x": 310,
109 | "y": 1468.6666259765625,
110 | "wires": [
111 | [
112 | "f212685b.532758"
113 | ]
114 | ]
115 | },
116 | {
117 | "id": "413823bc.fca6bc",
118 | "type": "comment",
119 | "z": "cba45765.fb58c8",
120 | "name": "Integrated Data Lake - generate access token via external API",
121 | "info": "- provides an URL endpoint to be accessed from external\n- delivers access token to MindSphere IDL",
122 | "sticky": 1,
123 | "x": 311,
124 | "y": 1388.6666641235352,
125 | "wires": [],
126 | "_type": "node"
127 | }
128 | ]
--------------------------------------------------------------------------------
/DataLake_scheduledImport/doc/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/DataLake_scheduledImport/doc/example.png
--------------------------------------------------------------------------------
/DataLake_scheduledImport/doc/result_IDL_Explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/DataLake_scheduledImport/doc/result_IDL_Explorer.png
--------------------------------------------------------------------------------
/DataLake_scheduledImport/readme.md:
--------------------------------------------------------------------------------
1 | # Scheduled Import of Timeseries Data to Integrated Data Lake
2 |
3 | This small flow triggers the import of timeseries data to the Integrated Data Lake for further usage.
4 |
5 |
6 | 
7 |
8 | ## Prerequisites
9 |
10 | - Integrated Data Lake
11 |
12 | ## Setup & Configuration
13 | 1. Import the flow in Visual Flow Creator
14 | 2. In the function node *buildTimeImportJobSeriesBody* specify
15 | - Asset (`assetIds`)
16 | - Aspect (`aspectNames`)
17 | - Output destination (`destination`) in the data lake for your files
18 | - [optional] specify a name for the import job based on your needs
19 | 3. Save the flow
20 |
21 | :cloud: :heavy_check_mark: You're ready ... - enjoy!
22 |
23 |
24 | ## How does this flow works
25 | The IDL endpoint to trigger the import job (from timeseries storage to IDL) is used and
26 | - asset
27 | - aspect
28 | - directory of export
29 | can be configured in the flow.
30 |
31 | ## Result
32 | After the data import was triggered via the flow and once the import job is finished, the data from timeseries storage can be found in the data lake.
33 | The IDL Explorer helps to browse the file structures.
34 | 
35 |
36 | ## See also
37 | - [:shopping_cart: MindSphere Store: Integrated Data Lake](https://www.dex.siemens.com/mindsphere/mindaccess/integrated-data-lake-essential)
38 | - [Developer Documentation: Integrated Data Lake Service](https://developer.mindsphere.io/apis/iot-integrated-data-lake/api-integrated-data-lake-overview.html)
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/DataLake_scheduledImport/template.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "cf1eb423.c22278",
4 | "type": "comment",
5 | "z": "cba45765.fb58c8",
6 | "name": "Dynamic export of timeseries data to Integrated Data Lake",
7 | "info": "- export timeseries data from an asset/aspect to Integrated Data Lake\n- runs every 24h\n- location in IDL where data is stored can be specified",
8 | "sticky": 1,
9 | "x": 360,
10 | "y": 1100,
11 | "wires": [],
12 | "_type": "node"
13 | },
14 | {
15 | "id": "9df841f3.541e2",
16 | "type": "debug",
17 | "z": "cba45765.fb58c8",
18 | "name": "",
19 | "active": true,
20 | "console": "false",
21 | "xaxis": "_time",
22 | "complete": "payload",
23 | "x": 870,
24 | "y": 1200,
25 | "wires": []
26 | },
27 | {
28 | "id": "76f6de48.a90eb",
29 | "type": "function",
30 | "z": "cba45765.fb58c8",
31 | "name": "buildTimeImportJobSeriesBody",
32 | "func": "/**set date time and jobname**/\nvar today = new Date();\nvar day=today.getDate();\nvar month=today.getMonth()+1;\nvar year =today.getFullYear();\n\n//build From and To date = one day (24h) window \nvar startDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()-1, 0, 0, 0);\nvar endDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(),0, 0, 0);\n\nvar from =startDate;\nvar to = endDate;\n\nmsg.payload={\n \"name\": \"TSIJob_test_\"+year+\"_\"+month+\"_\"+day,\n \"destination\": \"/export/\",\n \"aspectNames\": [\n \"myExportData\"\n ],\n \"assetIds\": [\n \"51a193966bb142aca0ab4658c1077cfd\"\n ],\n \"from\": from,\n \"to\": to\n}\nreturn msg;",
33 | "outputs": 1,
34 | "language": "javascript",
35 | "noerr": 0,
36 | "x": 450,
37 | "y": 1200,
38 | "wires": [
39 | [
40 | "e2287012.6b0bf"
41 | ]
42 | ],
43 | "_type": "node"
44 | },
45 | {
46 | "id": "e2287012.6b0bf",
47 | "type": "http request",
48 | "z": "cba45765.fb58c8",
49 | "name": "TSImportJob",
50 | "method": "POST",
51 | "ret": "txt",
52 | "url": "",
53 | "timeout": "",
54 | "mindspherePath": "/api/datalake/v3/timeSeriesImportJobs",
55 | "useMindsphereAuth": true,
56 | "isAdmin": false,
57 | "x": 690,
58 | "y": 1200,
59 | "wires": [
60 | [
61 | "9df841f3.541e2"
62 | ]
63 | ]
64 | },
65 | {
66 | "id": "5e17b196.34938",
67 | "type": "inject",
68 | "z": "cba45765.fb58c8",
69 | "name": "run every 24h",
70 | "topic": "",
71 | "payload": "",
72 | "payloadType": "date",
73 | "repeat": "86400",
74 | "repeatEnd": "0",
75 | "endTime": "0",
76 | "crontab": "",
77 | "offset": "41785848",
78 | "once": false,
79 | "properties": "",
80 | "timezone": "utc",
81 | "betweentimesunit": "m",
82 | "enableRuleEngine": false,
83 | "showNextExecution": true,
84 | "powerMode": false,
85 | "x": 200,
86 | "y": 1200,
87 | "wires": [
88 | [
89 | "76f6de48.a90eb"
90 | ]
91 | ]
92 | }
93 | ]
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Development License Agreement
4 |
5 | April 2023
6 |
7 | This Development License Agreement (the “License”) stipulates the rights that Siemens AG, Germany (“Siemens”) grants to you (“you”) in receipt of certain development material in relation to Insights Hub and Industrial IoT offerings (the "Platform"). This material may include software, sample code, scripts, libraries, software development kits, technology, documentation, and other proprietary material or information (collectively, the “Licensed Material”).
8 | Siemens retains the right to utilize its affiliated companies in pursuing any of its rights and fulfilling any of its obligations under this License. Therefore, the term “Siemens” as used herein may also refer to affiliated companies that are directly or indirectly owned or controlled by the ultimate parent company of Siemens AG and who have been authorized by Siemens AG to distribute the Licensed Material.
9 |
10 | ## 1. Proprietary Rights in the Licensed Material
11 |
12 | All rights, title, interest and know-how in and to the Licensed Material, any part and improvement thereof and all intellectual property rights in or to the foregoing, other than those rights expressly granted in this License, shall remain wholly vested in Siemens or its third party business partners and/or licensors.
13 |
14 | ## 2. License Grant
15 |
16 | If you have entered a separate commercial license agreement with Siemens that covers the Licensed Material, such license agreement shall prevail and this License shall not apply.
17 | You must accept this License to use the Licensed Material. If you use the Licensed Material, any such use shall constitute acceptance of this License. The Licensed Material is licensed, not sold.
18 | Subject to the terms and conditions of this License, Siemens grants you a non-exclusive, worldwide, royalty-free, non-transferable right to:
19 |
20 | * publish, modify and create derivative works of small source code examples (no longer than 50 lines of code) contained in Licensed Material,
21 | * integrate and publish Licensed Material in software that interoperates with the Platform, e.g. by transmission of data between applications, devices, systems or equipment and the Platform (hereinafter referred as “Customizations”), and license such Customizations to third parties to enable your offering of services relating to the Platform,
22 | * use, run and copy Licensed Material for your own internal use, and
23 | * sublicense Licensed Material to a service provider for the purposes of this section.
24 |
25 | You shall not:
26 |
27 | * use the Licensed Material for any other technology than the Platform, or
28 | * use the Licensed Material to abuse the Platform, or to compromise its integrity or security, or
29 | * disassemble or reverse-engineer any Licenses Material provided in object-code format, unless such action is permitted by an applicable Open Source license or the law that applies to you, or
30 | * remove or modify Siemens copyright, patent, trademark or attribution notices in the Licensed Material.
31 |
32 | ## 3. Feedback
33 |
34 | If you provide Siemens with feedback regarding the Licensed Material, you grant Siemens a non-exclusive, worldwide, royalty-free and perpetual right to use, copy, modify, distribute, and sublicense any such feedback in any way.
35 |
36 | ## 4. Open Source Software
37 |
38 | The Licensed Material may contain third-party software, including Open Source Software (“OSS”). If required, Siemens will furnish a notice file with the Licensed Material. To the extent the licenses terms applicable to such OSS are in contradiction to this License, the OSS license conditions shall prevail.
39 |
40 | ## 5. Responsibility for Use of the Licensed Material and Customizations
41 |
42 | Except any liability directly caused by Siemens violating its obligations under this License, you are responsible for the use of the Licensed Material (and all consequences arising therefrom), regardless of whether the use is undertaken by you, your employees or any third parties. You will ensure that the use of the Licensed Material by you, your employees or your customers complies with your obligations under this License. Should you become aware of any violation of your obligations under this License, you will (i) immediately inform Siemens thereof in reasonable detail and (ii) cease to use the Licensed Material.
43 | You are responsible for (i) properly integrating the Licensed Material into your Customizations, (ii) configuring and testing any Customization and making sure that a Customization is able to connect to and/or interoperate with the Platform, (iii) regular testing and monitoring of integrity, accuracy and timeliness of data transmission through a Customization (e.g. by monitoring over the Platform), (iv) the security of a Customization, and (v) the security of your and your customer’s system, any third party system or any data stored on such systems.
44 | You are responsible for the integrity, accuracy and timeliness of the exchange of data between a Customization and the Platform. Nothing in this License shall in any way constitute or be communicated by you or your customers to be an endorsement from us of a Customization in which you implemented the Licensed Material.
45 |
46 | ## 6. Warranty, Liability and Indemnification
47 |
48 | SIEMENS PROVIDES THE LICENSED MATERIAL FREE OF CHARGE AND THEREFORE “AS IS” WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. ANY STATEMENTS OR REPRESENTATIONS ABOUT THE LICENSED MATERIAL AND ITS RESPECTIVE FUNCTIONALITY IN THE LICENSED MATERIAL CONSTITUTE MERELY TECHNICAL INFORMATION AND ARE NEITHER A GUARANTEE NOR A WARRANTY. SIEMENS IS NOT AWARE THAT THE LICENSED MATERIAL VIOLATES ANY THIRD PARTY RIGHTS IF USED IN ACCORDANCE WITH THE LICENSE. FURTHERMORE, SIEMENS DOES NOT WARRANT THAT THE LICENSED MATERIAL IS FAIL-SAFE, FAULT-TOLERANT, ERROR-FREE OR THAT ANY DATA TRANSMITTED THROUGH THE LICENSED MATERIAL OR A CUSTOMIZATION WILL BE SECURE OR NOT OTHERWISE LOST OR DAMAGED.
49 | Siemens disclaims all liability for all damages of any kind irrespective of the legal ground in relation to the Licensed Material. However, nothing in this License shall exclude or limit Siemens’ liability in case of death or personal injury of any person, or in case of our willful misconduct, gross negligence, fraud or fraudulent misrepresentation. Any limitations of liability set forth in this License shall also apply for the benefit of Siemens’ subcontractors, employees, directors, agents or any other person acting for Siemens.
50 | You agree to indemnify, defend, and hold Siemens harmless from and against all losses, expenses, damages and costs, including reasonable attorneys’ fees, resulting from or arising out of any violation of this License by you or any other person you provided with the Licensed Material, regardless of your knowledge, including any claim, proceeding, action, fine, loss, cost and damages arising out of or relating to any non-compliance with export control regulations.
51 |
52 | ## 7. Term and Termination, Updates
53 |
54 | If Siemens reasonably determines that you are breaching this License and you fail to remediate such breach without undue delay, Siemens may suspend or terminate your Platform access temporarily or permanently and terminate this License at its sole discretion.
55 | Siemens may, at its sole discretion, make available updates or security patches for the Licensed Material. Outdated versions of the Licensed Material may not be able to connect to and/or interoperate with the Platform.
56 |
57 | ## 8. Applicable Law
58 |
59 | This License shall be governed by and construed in accordance with the laws of Switzerland, without giving effect to any choice-of-law rules that may require the application of the law of another jurisdiction. The UN Convention on Contracts for the International Sale of Goods shall not apply.
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Insights Hub Visual Flow Creator Examples
2 |
3 | [](https://documentation.mindsphere.io/MindSphere/index.html)
4 | [](https://community.sw.siemens.com/s/topic/0TO4O000000MihsWAC/insights-hub)
5 |
6 | # Welcome
7 | * You are interested in Insights Hub?
8 | * You want to know, what you can do with it?
9 | * You've heard about Visual Flow Creator and want to try it out?
10 | * You know already Visual Flow Creator but search for examples?
11 | * You want to get inspired by other flows from the community?
12 |
13 | This repository provides example flows to be used in Insights Hub Visual Flow Creator (VFC). You can use them and try it out to get an impression what is possible. Additionally you can customize them to your use cases. And of course you can contribute to this repository and share your knowledge to others.
14 |
15 | If you do not have already purchased the app, you can get it in the [Insights Hub Store](https://www.dex.siemens.com/mindsphere/applications/Visual-Flow-Creator). Or if you do not already have a Insights Hub account, get one at [Insights Hub Start](https://www.mindsphere.io/start).
16 |
17 | ## How does this work
18 |
19 | In the next chapter you will find example flows. There is always a readme with a short description, what this flow does.
20 | There is an image showing the flow to get an impression of the complexity.
21 |
22 | And there is the most important thing - the json file, which you can import as a new flow into your Visual Flow Creator.
23 |
24 | Please note, that the json-files are exported from another tenant. So their might be fields which you have to adapt, that the flow is able to run in your tenant.
25 |
26 | ## Example Overview
27 |
28 | ### Current examples in this repository for Visual Flow Creator:
29 |
30 | | Name | Description | Complexity Rating | Prerequisites |
31 | | --- | --- | --- | --- |
32 | | [Create custom API endpoints](./createCustomAPI_endpoint//readme.md) | | :star: | - |
33 | | [Integrate external API](./integrateExternalApi/readme.md) | | :star: | |
34 | | [Create rule for asset type](./createRuleForAssetType/readme.md) | Create a rule for all assets of this type | :star: | - |
35 | | [Data Lake - timeseries import](./DataLake_scheduledImport/readme.md) | Setup scheduled trigger to start import of data from timeseries storage to Integrated Data Lake | :star: | Integrated Data Lake |
36 | | [Data Lake - generate access token](./DataLake_provideAccessToken/readme.md) | Provides an API endpoint which feedbacks an access token for IDL data | :star: | Integrated Data Lake |
37 | | [24h sample data scenario replay](./data_simulation_24h//readme.md) | Simulate demo data by continuously replaying 24-hour reference data | :star: | - |
38 | | [Generate sample data](./generateSampleData/readme.md) | Demo data for different data types in Insights Hub | :star: | - |
39 | | [Send SMS notifications](./sendSmsNotifications/readme.md) | Send SMS notifications and dynamically specify recipient | :star: | - |
40 | | [Virtual machine simulator](./virtualMachineSimulator/readme.md) | | :star: | - |
41 | | [Write location data to your Asset](./WriteLocationToAsset/readme.md) | Write locational information directly to your Asset using the Asset Management API | :star: | - |
42 | | [Command MQTT devices connected via MindConnect](./commandMqttDevice_MindConnect/readme.md) | Send commands back to a device via MindConnect MQTT | :star: | MindConnect MQTT connected device |
43 | | [VFC Dashboard - Getting Started Guide](./Dashboard_getting_started/readme.md) | Create a dynamic Dashboard completely from scratch and learn the basics of VFC Dashboarding | :star: | - |
44 |
45 | You can add here your ideas or requests for further examples.
46 |
47 | ### Example template
48 | You want to create your own example? Just copy an existing folder, adapt it and send us your pull request.
49 | ## Remarks
50 | Please note that the screenshots show just the current state, when these examples have been created. They might differ to the latest software release.
51 |
52 | Each flow has to be adapted to your tenant. Ensure, that e.g. fixed tenant names or asset ids are adapted before/after you import the flow.
53 |
54 | ## Prerequisites
55 | All application examples shown in this repository require the Insights Hub Application *Visual Flow Creator (VFC)*.
56 |
57 | To use them, ensure that
58 | - VFC is available in your Insights Hub tenant ([VFC in Insights Hub Store](https://www.dex.siemens.com/mindsphere/applications/visual-flow-creator))
59 | 
60 | - you have *admin* or *user* access to VFC ([VFC user role settings](https://documentation.mindsphere.io/resources/html/visualflow-creator/en-US/108812512779.html))
61 | 
62 |
63 | If you can see Visual Flow Creator on your Launchpad, you're ready to start developments.
64 |
65 | ## Import of Examples
66 |
67 | - To import any of the examples shown in this repository, launch the VFC.
68 | - In the menu, select *Import* and paste the JSON template as found in the application examples.
69 | - Drop the nodes in the editor and save the just imported flow.
70 |
71 | 
72 |
73 | ## Questions and answers
74 |
75 | Feel free to ask your questions in the [Insights Hub Developer Forum](https://community.sw.siemens.com/s/topic/0TO4O000000MihsWAC).
76 |
77 | Or open an [issue](https://github.com/mindsphere/vfc-examples/issues) if you find a bug in our examples.
78 |
79 | You want to contribute? Your pull request is always welcome!!!
80 |
--------------------------------------------------------------------------------
/UserActivityTracker/UserInsights_AspectDefinition.csv:
--------------------------------------------------------------------------------
1 | "user_id";"STRING";"1";"50"
2 | "user_login";"BOOLEAN";"1";""
--------------------------------------------------------------------------------
/UserActivityTracker/doc/AM-Setup_Aspect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/UserActivityTracker/doc/AM-Setup_Aspect.png
--------------------------------------------------------------------------------
/UserActivityTracker/doc/AM-Setup_Asset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/UserActivityTracker/doc/AM-Setup_Asset.png
--------------------------------------------------------------------------------
/UserActivityTracker/doc/AM-Setup_AssetType.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/UserActivityTracker/doc/AM-Setup_AssetType.png
--------------------------------------------------------------------------------
/UserActivityTracker/doc/UserActivityTracker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/UserActivityTracker/doc/UserActivityTracker.png
--------------------------------------------------------------------------------
/UserActivityTracker/doc/UserActivityTracker_results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/UserActivityTracker/doc/UserActivityTracker_results.png
--------------------------------------------------------------------------------
/UserActivityTracker/readme.md:
--------------------------------------------------------------------------------
1 | # User Activity Tracker
2 |
3 | This flow monitors and tracks user login activities by collecting last login timestamps for all users. The flow automatically runs daily and stores the login data in a dedicated asset for historical analysis and tracking of user engagement patterns. Additional analysis for the login behaviour are then possible based on this data source.
4 |
5 | 
6 |
7 | ## Prerequisites
8 | - Access to Visual Flow Creator
9 | - Permissions to create assets and aspects in Asset Manager
10 |
11 | ## Setup & Configuration
12 |
13 | 1. Create the required asset structure in Asset Manager:
14 | - Create a new **Aspect** named "UserInsights" (or any custom name) with exaclty these parameters:
15 | | Variable Name | Data Type |
16 | |--------------|-----------|
17 | | user_login | BOOLEAN |
18 | | user_id | STRING |
19 | - Create an **Asset Type** that includes this aspect
20 | - Create an **Asset** from this asset type
21 | - Note down the **Asset ID** for configuration of the flow later
22 | (you can find this ID for example in the URL of your browser)
23 |
24 | 2. Import the flow in Visual Flow Creator using the [Flow Tempalte](template.json)
25 |
26 | 3. Configure the flow by:
27 | - Locate the "CONFIG" function node
28 | - Update the `assetId` variable with your created asset's ID
29 | - Update the `aspectName` variable if you used a custom aspect name
30 |
31 | 4. Save the flow
32 |
33 |
34 | ### Additional Setup Information
35 |
36 | Below are the visual references for the required setup in Asset Manager.
37 | 1. Create the Aspect "UserInsights":
38 | 
39 | *Creating the `UserInsights` Aspect with required variables*
40 |
41 | 2. Create the Asset Type:
42 | 
43 | *Creating an `UserActivity` Asset Type that includes the `UserInsights` Aspect*
44 |
45 | 3. Create the Asset:
46 | 
47 | *Final asset based on the `UserActivity` Asset Type with `UserInsights` Aspect which will received the data from the flow*
48 |
49 | :cloud: :heavy_check_mark: You're ready to track user login behavior!
50 |
51 | ## How does this flow work
52 |
53 | 1. The flow triggers automatically every 24 hours at 02:00 UTC
54 | 2. It fetches the data from the User Management API to retrieve all user information
55 | 3. For each user, it processes:
56 | - Last login timestamp
57 | - Identifies users who haven't logged in for over 365 days
58 | - Identifies users who have never logged in
59 | 4. The processed login data is written to the configured asset with timestamps showing the login time of the user
60 | 5. Inactive users (>365 days) and never-logged-in users are reported to the VFC console to enable further follow-up
61 |
62 | > Note:
63 | > The flow uses pagination to handle large user lists and includes error handling for robust operation. This might lead to an increased use of compute hours and flow duration.
64 |
65 | ## Result
66 |
67 | The flow generates:
68 | - Historical login data for each user stored in the asset
69 | - Console notifications for:
70 | - Users who haven't logged in for over 365 days
71 | - Users who have never logged in
72 | - Time-series data showing login patterns over time
73 |
74 | 
75 |
76 |
77 | ## See also
78 | - [Visual Flow Creator Documentation](https://documentation.mindsphere.io/MindSphere/apps/visual-flow-creator/introduction.html)
79 | - [Identity Management API Documentation](https://documentation.mindsphere.io/MindSphere/apis/core-identitymanagement/api-identitymanagement-overview.html)
80 |
81 |
82 |
--------------------------------------------------------------------------------
/UserActivityTracker/template.json:
--------------------------------------------------------------------------------
1 | [{"id":"3a1c72de.97e6fe","type":"tab","allowCycles":false,"label":"User Activity Tracker","disabled":false,"info":"author: christoph.doehl@siemens.com\n\n\ndescription:\n"},{"id":"95274343.d3a4b","type":"group","z":"3a1c72de.97e6fe","name":"User Activity Tracker ","style":{"label":true},"nodes":["4b9358dd.f20278","f9e40926.54cb78","5ecf13d3.8a4b7c","8eb647fe.e3f408","d64b471c.5ff018"],"x":75,"y":21,"w":1015,"h":524},{"id":"d64b471c.5ff018","type":"group","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"do not change me","style":{"label":true},"nodes":["c58799e7.633558","cd7735e2.5bff18","61f08245.d75eac","9289c15b.da14c","eb3e427b.6496"],"x":635,"y":320,"w":430,"h":200},{"id":"4b9358dd.f20278","type":"comment","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"User Activity Tracker","info":"+ runs every 24h and gets when users logged in last time\n+ get current user list and write when user logged in last time\n\nAdditions:\n+ logins older than 365 days are reported to the console\n+ users who never logged in are reported to console\n\nLimits:\n* does only work for the last 365 days of login\n","sticky":1,"x":340,"y":160,"wires":[],"_type":"node"},{"id":"8eb647fe.e3f408","type":"comment","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"adjust and config your flow here ⬆️⬆️⬆️","info":"DO ONLY setup here, no other changes are needed","sticky":1,"x":360,"y":420,"wires":[]},{"id":"c58799e7.633558","type":"debug","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"Debug","active":true,"xaxis":"","complete":"true","x":970,"y":440,"wires":[]},{"id":"f9e40926.54cb78","type":"function","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"CONFIG","func":"// ******************** CONFIGURATION ********************\n//\n// EDITABLE VALUES:\nvar assetId = \"fe290291bf044151a5d5d0abebbf211f\"; // Enter your asset ID\nvar aspectName = \"UserInsights\"; // Enter your aspect name\n//\n//\n// DO NOT MODIFY BELOW THIS LINE\n// **************************************************************\nmsg.userTracking_config = \n\n{\n \"assetId\": assetId,\n \"aspectName\": aspectName\n}\n\n// First request\nmsg.url = '/api/identitymanagement/v3/Users?count=250&page=1';\n\nreturn msg;","outputs":1,"language":"javascript","noerr":0,"x":440,"y":360,"wires":[["61f08245.d75eac"]],"_type":"node"},{"id":"cd7735e2.5bff18","type":"function","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"Check and Process","func":"// Store or append users\ncontext.users = context.users || [];\ncontext.users = context.users.concat(msg.payload.resources);\n\nconst currentPage = parseInt(msg.url.match(/page=(\\d+)/)[1]);\nconst neededPages = Math.ceil(msg.payload.totalResults / msg.payload.itemsPerPage)\n\n// Check if we need more requests\nif (currentPage <= neededPages) {\n // Need next page\n console.log(\"current page processed:\" + currentPage + \"/\" + neededPages)\n msg.url = `/api/identitymanagement/v3/Users?count=250&page=${currentPage + 1}`;\n console.log(\"requesting now: \" + msg.url);\n return [msg, null];\n} else {\n // Process all users\n let results = [];\n const oneYearAgo = new Date();\n oneYearAgo.setDate(oneYearAgo.getDate() - 365); // Get date 365 days ago\n\n for (const user of context.users) { \n if (user.hasOwnProperty('previousLogonTime')) {\n const lastLogon = new Date(user.lastLogonTime);\n \n if (lastLogon > oneYearAgo) {\n results.push({\n user_id: user.userName,\n user_login: \"TRUE\",\n _time: lastLogon.toISOString()\n });\n } else {\n console.log(\"User login is older than 365 days: \" + user.userName + \"(\" + lastLogon.toISOString() + \")\");\n }\n } else {\n console.log(\"user never logged in: \" + user.userName); \n }\n }\n \n // Clear context\n context.users = [];\n \n // Prepare output message\n msg.payload = results;\n msg.topic = msg.userTracking_config.assetId + \"/\" + msg.userTracking_config.aspectName;\n \n return [null, msg];\n}\n\n// if (user.hasOwnProperty('previousLogonTime')){\n// //user has logged in\n// data = [{\n// 'user_id': email,\n// 'user_login': \"TRUE\"}\n// ]\n \n// //var date = new Date(user.previousLogonTime);\n// //console.log(\"previousLogonTime = \" + Date(user.previousLogonTime)); \n \n// msg.payload = data[aspect]\n// msg._time = new Date(user.lastLogonTime).toISOString() //.toISOString() //new Date();\n \n// node.send(msg)\n \n// }\n// else{\n// //user never logged in\n// console.log(\"user never logged in: \" + email); \n// }\n","outputs":2,"language":"javascript","noerr":0,"x":750,"y":460,"wires":[["61f08245.d75eac"],["c58799e7.633558","9289c15b.da14c"]],"_type":"node"},{"id":"61f08245.d75eac","type":"http request","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"Fetch Users","method":"GET","ret":"obj","url":"","timeout":"","mindspherePath":"","useMindsphereAuth":true,"isAdmin":true,"secretHeaders":"","x":730,"y":360,"wires":[["cd7735e2.5bff18","eb3e427b.6496"]]},{"id":"5ecf13d3.8a4b7c","type":"inject","z":"3a1c72de.97e6fe","g":"95274343.d3a4b","name":"run every 24h","topic":"","payload":"","payloadType":"str","repeat":"","repeatEnd":"0","endTime":"0","crontab":"00 02 * * *","offset":"NaN","once":false,"properties":"","timezone":"utc","showNextExecution":false,"powerMode":true,"x":200,"y":360,"wires":[["f9e40926.54cb78"]],"_type":"node"},{"id":"9289c15b.da14c","type":"write timeseries","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"","topic":"","topicData":"","topicLabel":"","assetName":"","aspectName":"","useMerging":false,"x":980,"y":480,"wires":[]},{"id":"eb3e427b.6496","type":"debug","z":"3a1c72de.97e6fe","g":"d64b471c.5ff018","name":"","active":true,"console":"false","xaxis":"_time","complete":"false","x":950,"y":360,"wires":[]}]
--------------------------------------------------------------------------------
/WriteLocationToAsset/IMPORT_WriteLocationToAsset.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "f36b6875.db8608",
4 | "type": "delay",
5 | "z": "eeddfd21.19809",
6 | "name": "",
7 | "pauseType": "delay",
8 | "timeout": "5",
9 | "timeoutUnits": "seconds",
10 | "rate": "1",
11 | "nbRateUnits": "1",
12 | "rateUnits": "second",
13 | "randomFirst": "1",
14 | "randomLast": "5",
15 | "randomUnits": "seconds",
16 | "drop": false,
17 | "powerMode": false,
18 | "x": 2140,
19 | "y": 3640,
20 | "wires": [
21 | [
22 | "50f968ae.c48ab8"
23 | ]
24 | ]
25 | },
26 | {
27 | "id": "7d37f5d9.f7ee2c",
28 | "type": "function",
29 | "z": "eeddfd21.19809",
30 | "name": "Store e-tag",
31 | "func": "var data = msg.payload;\nvar tag = data[\"etag\"];\nmsg.payload = tag;\nreturn msg;",
32 | "outputs": 1,
33 | "language": "javascript",
34 | "noerr": 0,
35 | "x": 2310,
36 | "y": 3760,
37 | "wires": [
38 | [
39 | "cd796701.b45798"
40 | ]
41 | ]
42 | },
43 | {
44 | "id": "50f968ae.c48ab8",
45 | "type": "function",
46 | "z": "eeddfd21.19809",
47 | "name": "Headers & Body",
48 | "func": "var etag = flow.get('etag');\nmsg.headers = {};\nmsg.headers['If-Match'] = etag;\nvar body = {\n \n \"longitude\": 53.5125546,\n \"latitude\": 9.9763411\n}\n;\n\nmsg.payload = body;\nreturn msg;",
49 | "outputs": 1,
50 | "language": "javascript",
51 | "noerr": 0,
52 | "x": 2340,
53 | "y": 3640,
54 | "wires": [
55 | [
56 | "4777a2ca.61eeac"
57 | ]
58 | ]
59 | },
60 | {
61 | "id": "4dadbb3b.047224",
62 | "type": "http request",
63 | "z": "eeddfd21.19809",
64 | "name": "GET e-tag",
65 | "method": "GET",
66 | "ret": "txt",
67 | "url": "",
68 | "timeout": "",
69 | "mindspherePath": "/api/assetmanagement/v3/assets/7cb6736dd0d74c7792727242c9e5b9d5",
70 | "useMindsphereAuth": true,
71 | "isAdmin": false,
72 | "x": 2040,
73 | "y": 3760,
74 | "wires": [
75 | [
76 | "141262.1c759d9f"
77 | ]
78 | ]
79 | },
80 | {
81 | "id": "4777a2ca.61eeac",
82 | "type": "http request",
83 | "z": "eeddfd21.19809",
84 | "name": "PUT Location",
85 | "method": "PUT",
86 | "ret": "txt",
87 | "url": "",
88 | "timeout": "",
89 | "mindspherePath": "/api/assetmanagement/v3/assets/7cb6736dd0d74c7792727242c9e5b9d5/location",
90 | "useMindsphereAuth": true,
91 | "isAdmin": true,
92 | "x": 2550,
93 | "y": 3640,
94 | "wires": [
95 | []
96 | ]
97 | },
98 | {
99 | "id": "62a355ae.1ce6ec",
100 | "type": "inject",
101 | "z": "eeddfd21.19809",
102 | "name": "",
103 | "topic": "",
104 | "payload": "",
105 | "payloadType": "date",
106 | "repeat": "",
107 | "repeatEnd": "0",
108 | "endTime": "0",
109 | "crontab": "",
110 | "offset": "0",
111 | "once": false,
112 | "properties": "",
113 | "timezone": "utc",
114 | "betweentimesunit": "m",
115 | "enableRuleEngine": false,
116 | "showNextExecution": false,
117 | "powerMode": false,
118 | "x": 1824.5,
119 | "y": 3679,
120 | "wires": [
121 | [
122 | "4dadbb3b.047224",
123 | "f36b6875.db8608"
124 | ]
125 | ]
126 | },
127 | {
128 | "id": "141262.1c759d9f",
129 | "type": "json",
130 | "z": "eeddfd21.19809",
131 | "name": "",
132 | "pretty": false,
133 | "x": 2170,
134 | "y": 3760,
135 | "wires": [
136 | [
137 | "7d37f5d9.f7ee2c"
138 | ]
139 | ]
140 | },
141 | {
142 | "id": "cd796701.b45798",
143 | "type": "store-context",
144 | "z": "eeddfd21.19809",
145 | "name": "store etag",
146 | "key": "etag",
147 | "context": "flow",
148 | "x": 2460,
149 | "y": 3760,
150 | "wires": []
151 | }
152 | ]
153 |
--------------------------------------------------------------------------------
/WriteLocationToAsset/readme.md:
--------------------------------------------------------------------------------
1 | # How to write location data directly to your Asset using the Asset Management API
2 |
3 | How to use this flow:
4 | 1. Copy the json flow structure from [Here](./IMPORT_WriteLocationToAsset.json)
5 | 2. Click Import in the VFC and paste the json data in the blank field
6 | 3. Click Import
7 | 4. Change the asset id's in the GET and PUT call to the id of your own asset
8 | 5. Change the locational information by altering the body in the function node (optional)
9 | 6. Save the flow
10 |
11 | You are done! Your flow should now look like this:
12 |
13 | 
14 |
15 | If you execute the flow, your location is written directly to your assets static information. You can now use it in e.g. the Asset Manager and always check the current location of your Asset:
16 |
17 |
18 |
19 | https://user-images.githubusercontent.com/90254123/166235568-542ba4b4-f1ab-4f04-8ea0-b8f044007429.mp4
20 |
21 | You do not have to write all information (e.g. postal code, street address, country, ...) for the map to be functional. Writing longitude and latitude is sufficient. However, if you only sent longitude and latitude information, Asset Manager will show *now location available*. The Asset Map is still functional.
22 |
23 | > Take a look at the [Insights Hub Documentation](https://documentation.mindsphere.io/MindSphere/apis/advanced-assetmanagement/api-assetmanagement-api.html) if you want to know more about the Asset Management API.
24 |
--------------------------------------------------------------------------------
/commandMqttDevice_MindConnect/IMPORT_commandMqttDevice_MindConnect.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "e415ac9c.2a734",
4 | "type": "comment",
5 | "z": "cba45765.fb58c8",
6 | "name": "MindConnect MQTT - commading of a device",
7 | "info": "- sends a command to a device which is connected via MindConnect MQTT",
8 | "sticky": 1,
9 | "x": 320,
10 | "y": 1920,
11 | "wires": []
12 | },
13 | {
14 | "id": "daff595.58e3ea8",
15 | "type": "group",
16 | "z": "cba45765.fb58c8",
17 | "name": "manual setup of the API call for commanding // not recommended",
18 | "style": {
19 | "label": true
20 | },
21 | "nodes": [
22 | "5d4d2d1e.1be5f4",
23 | "6dadce05.535e5",
24 | "100131f0.458a6e",
25 | "21c0aab9.b71656",
26 | "8bd21774.9b5778"
27 | ],
28 | "x": 55,
29 | "y": 2161,
30 | "w": 1010,
31 | "h": 159
32 | },
33 | {
34 | "id": "5d4d2d1e.1be5f4",
35 | "type": "comment",
36 | "z": "cba45765.fb58c8",
37 | "g": "daff595.58e3ea8",
38 | "name": "adjust here:",
39 | "info": "- MQTT clientID(s)\n- commanding payload (data) for device",
40 | "sticky": 1,
41 | "x": 440,
42 | "y": 2220,
43 | "wires": []
44 | },
45 | {
46 | "id": "6dadce05.535e5",
47 | "type": "debug",
48 | "z": "cba45765.fb58c8",
49 | "g": "daff595.58e3ea8",
50 | "name": "",
51 | "active": true,
52 | "console": "false",
53 | "xaxis": "_time",
54 | "complete": "payload",
55 | "x": 950,
56 | "y": 2280,
57 | "wires": []
58 | },
59 | {
60 | "id": "100131f0.458a6e",
61 | "type": "function",
62 | "z": "cba45765.fb58c8",
63 | "g": "daff595.58e3ea8",
64 | "name": "edit clientID and data",
65 | "func": "/**in the body of the request, specify \n - clientID(s) which should received the command. Can be one or multiple clients\n - in the 'data' section, specify the command-payload to be send to the device. \n This will be received on the device at the command-subscription topic. \n \nExample: \n- tenant: presiot\n- device name: CloudFox-Laptop\n- clientID: presiot_CloudFox-Laptop\n- commanding topic: tc/presiot/presiot_CloudFox-Laptop/i/cmd_v3/c\n\n**/\nvar name = \"a commanding information for my device\";\nvar clientIDs = [\"presiot_CloudFox-Laptop\"]; \nvar commandingData = {\n \"configuration\": \"sample config v1.4.3\",\n \"data\": \"hello world\",\n \"INTvalue\": 5,\n \"light-status\": true,\n \"motor_rpm_setpoint\": 1200.5\n }\n\n//setup body for commanding request\nmsg.payload = {\n \"name\": name,\n \"clientIds\": clientIDs,\n \"data\": commandingData\n}\nreturn msg;",
66 | "outputs": 1,
67 | "language": "javascript",
68 | "noerr": 0,
69 | "x": 380,
70 | "y": 2280,
71 | "wires": [
72 | [
73 | "21c0aab9.b71656"
74 | ]
75 | ],
76 | "_type": "node"
77 | },
78 | {
79 | "id": "21c0aab9.b71656",
80 | "type": "http request",
81 | "z": "cba45765.fb58c8",
82 | "g": "daff595.58e3ea8",
83 | "name": "command to device",
84 | "method": "POST",
85 | "ret": "txt",
86 | "url": "",
87 | "timeout": "",
88 | "mindspherePath": "/api/commanding/v3/deliveryJobs",
89 | "useMindsphereAuth": true,
90 | "isAdmin": false,
91 | "secretHeaders": "",
92 | "x": 686,
93 | "y": 2280,
94 | "wires": [
95 | [
96 | "6dadce05.535e5"
97 | ]
98 | ]
99 | },
100 | {
101 | "id": "8bd21774.9b5778",
102 | "type": "inject",
103 | "z": "cba45765.fb58c8",
104 | "g": "daff595.58e3ea8",
105 | "name": "",
106 | "topic": "",
107 | "payload": "",
108 | "payloadType": "date",
109 | "repeat": "",
110 | "repeatEnd": "0",
111 | "endTime": "0",
112 | "crontab": "",
113 | "offset": "NaN",
114 | "once": false,
115 | "properties": "",
116 | "timezone": "utc",
117 | "betweentimesunit": "m",
118 | "showNextExecution": false,
119 | "powerMode": false,
120 | "x": 160,
121 | "y": 2280,
122 | "wires": [
123 | [
124 | "100131f0.458a6e"
125 | ]
126 | ]
127 | },
128 | {
129 | "id": "21c0892b.577e66",
130 | "type": "group",
131 | "z": "cba45765.fb58c8",
132 | "name": "Commanding MindConnect MQTT Agents",
133 | "style": {
134 | "stroke": "#92d04f",
135 | "label": true,
136 | "color": "#92d04f"
137 | },
138 | "nodes": [
139 | "ab1fc976.a28a08",
140 | "db2569e5.5bdc58",
141 | "1e8fa7.7bd4f05a",
142 | "1d379f8d.7f5c1",
143 | "ff1099c4.d74328",
144 | "3e55db85.3ac6c4"
145 | ],
146 | "x": 55,
147 | "y": 1971,
148 | "w": 1010,
149 | "h": 149
150 | },
151 | {
152 | "id": "ab1fc976.a28a08",
153 | "type": "command mindconnect",
154 | "z": "cba45765.fb58c8",
155 | "g": "21c0892b.577e66",
156 | "name": "",
157 | "mindconnectMqttId": "",
158 | "mindconnectTopic": "",
159 | "mindconnectTopicData": "",
160 | "x": 670,
161 | "y": 2080,
162 | "wires": [
163 | [
164 | "1d379f8d.7f5c1"
165 | ]
166 | ],
167 | "_type": "node"
168 | },
169 | {
170 | "id": "db2569e5.5bdc58",
171 | "type": "function",
172 | "z": "cba45765.fb58c8",
173 | "g": "21c0892b.577e66",
174 | "name": "edit data",
175 | "func": "/**in the body of the request, specify \n - in the 'data' section, specify the command-payload to be send to the device. \n This will be received on the device at the command-subscription topic. \n \n**/\n\nvar commandingData = {\n \"configuration\": \"sample config v1.4.3\",\n \"data\": \"hello world\",\n \"INTvalue\": 5,\n \"light-status\": true,\n \"motor_rpm_setpoint\": 1200.5\n }\n\n//setup body for commanding request\nmsg.payload = commandingData;\n\nreturn msg;",
176 | "outputs": 1,
177 | "language": "javascript",
178 | "noerr": 0,
179 | "x": 320,
180 | "y": 2080,
181 | "wires": [
182 | [
183 | "ab1fc976.a28a08"
184 | ]
185 | ],
186 | "_type": "node"
187 | },
188 | {
189 | "id": "1e8fa7.7bd4f05a",
190 | "type": "inject",
191 | "z": "cba45765.fb58c8",
192 | "g": "21c0892b.577e66",
193 | "name": "",
194 | "topic": "",
195 | "payload": "",
196 | "payloadType": "date",
197 | "repeat": "",
198 | "repeatEnd": "0",
199 | "endTime": "0",
200 | "crontab": "",
201 | "offset": "NaN",
202 | "once": false,
203 | "properties": "",
204 | "timezone": "utc",
205 | "betweentimesunit": "m",
206 | "showNextExecution": false,
207 | "powerMode": false,
208 | "x": 160,
209 | "y": 2080,
210 | "wires": [
211 | [
212 | "db2569e5.5bdc58"
213 | ]
214 | ]
215 | },
216 | {
217 | "id": "1d379f8d.7f5c1",
218 | "type": "debug",
219 | "z": "cba45765.fb58c8",
220 | "g": "21c0892b.577e66",
221 | "name": "",
222 | "active": true,
223 | "console": "false",
224 | "xaxis": "_time",
225 | "complete": "payload",
226 | "x": 950,
227 | "y": 2080,
228 | "wires": []
229 | },
230 | {
231 | "id": "ff1099c4.d74328",
232 | "type": "comment",
233 | "z": "cba45765.fb58c8",
234 | "g": "21c0892b.577e66",
235 | "name": "adjust here:",
236 | "info": "- commanding data) for device",
237 | "sticky": 1,
238 | "x": 370,
239 | "y": 2020,
240 | "wires": [],
241 | "_type": "node"
242 | },
243 | {
244 | "id": "3e55db85.3ac6c4",
245 | "type": "comment",
246 | "z": "cba45765.fb58c8",
247 | "g": "21c0892b.577e66",
248 | "name": "adjust here:",
249 | "info": "- select device(s)",
250 | "sticky": 1,
251 | "x": 650,
252 | "y": 2020,
253 | "wires": [],
254 | "_type": "node"
255 | }
256 | ]
--------------------------------------------------------------------------------
/commandMqttDevice_MindConnect/doc/VFC_setup_MindConnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/commandMqttDevice_MindConnect/doc/VFC_setup_MindConnect.png
--------------------------------------------------------------------------------
/commandMqttDevice_MindConnect/doc/commandMqttDevice_MC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/commandMqttDevice_MindConnect/doc/commandMqttDevice_MC.png
--------------------------------------------------------------------------------
/commandMqttDevice_MindConnect/doc/receive_command_MC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/commandMqttDevice_MindConnect/doc/receive_command_MC.png
--------------------------------------------------------------------------------
/commandMqttDevice_MindConnect/readme.md:
--------------------------------------------------------------------------------
1 | # Command device via MindConnect MQTT
2 |
3 | This flow demonstrates how you can use Visual Flow Creator to trigger sending of a command to a device connected to Insights Hub via [MindConnect MQTT](https://documentation.mindsphere.io/MindSphere/howto/howto-mindconnectmqtt-commanding.html) protocol.
4 | Every time the flow is triggered, the command specified in the payload is send to the device linked using the client-ID of the connect MQTT client.
5 | 
6 |
7 | ## Prerequisites
8 | - Access to Visual Flow Creator
9 | - a device connected to Insights Hub via MindConnect MQTT
10 |
11 | ## Setup & Configuration
12 |
13 | ### Setup your MQTT device
14 | Creation and connection of a device via MindConnect MQTT is not further described in this document. The core element to do so, are to be found on the Insights Hub Developer Website.
15 | In order to use this feature, make sure you have successfully completed step 1 - 3.
16 | 1) [Onboarding MindConnect MQTT Agent](https://documentation.mindsphere.io/MindSphere/howto/howto-onboard-mindconnect-mqtt.html)
17 | 2) [Creating Data Model from MQTT Agent](https://documentation.mindsphere.io/MindSphere/howto/howto-create-data-model-mqtt-agent.html)
18 | 3) [Sending Data from MindConnect MQTT Agent](https://documentation.mindsphere.io/MindSphere/howto/howto-send-data-from-mqtt-agent.html)
19 |
20 | ### Usage of commanding
21 | Once your device is connected to Insights Hub, you can start using the [MindConnect MQTT Commanding](https://documentation.mindsphere.io/MindSphere/howto/howto-mindconnectmqtt-commanding.html) feature.
22 | Commanding can be initiated via a dedicated API. Here we will use VFC to initiate the API call and request the commanding.
23 |
24 | ### Setup in Visual Flow Creator
25 |
26 | #### Using standard nodes for "MindConnect"
27 | A dedicated commanding node was added to the standard nodes of Visual Flow Creator.
28 | https://documentation.mindsphere.io/MindSphere/apps/visual-flow-creator/mindconnect-nodes.html#command-mindconnect
29 |
30 | Manual configuration towards the API endpoint for commanding is no longer needed but still shown in depth in the description below.
31 | With "MindConnect" nodes, you can send a command to MindConnect MQTT device and check the status of the sent command. For more information about MindConnect Elements, refer to [Connectivity](https://documentation.mindsphere.io/MindSphere/connectivity/overview.html).
32 |
33 |
34 | #### Manually setting up the API call
35 | 1. Import the flow in Visual Flow Creator
36 | 2. Adjust the payload body in the function node
37 | - ```name``` defines an internal name for the job to be send to the devices.
38 | - ```clientIds``` which should receive the command. Note that this can be 1-* devices (one, or multiple clients).
39 | - set the ```data``` you want to send to the device. This can be a JSON schema with multiple settings/information/commands. A few examples are shown below.
40 | ```JSON
41 | msg.payload = {
42 | "name": "a commanding information for my device",
43 | "clientIds": [
44 | "presiot_CloudFox-Laptop"],
45 | "data": {
46 | "configuration": "sample config v1.4.3",
47 | "data": "hello world",
48 | "INTvalue": 5,
49 | "light-status": true,
50 | "motor_rpm_setpoint": 1200.5
51 | }
52 | }
53 | ```
54 |
55 | 
56 | 3. Save the flow
57 |
58 | :cloud: :heavy_check_mark: You're ready to command a device once the flow is triggered - enjoy!
59 |
60 |
61 | ## Result
62 | Once the flow is executed, the device will receive on ```tc///i/cmd_v3/c``` (general schema) topic the command as specified in the VFC flow. Make sure that you have subscribed to this topic before the flow is being triggered.
63 | Follow the device logic to now acknowledge this command and use it for your application needs further on the device.
64 |
65 | **Device-View**
66 | The following is received at the device on the subscribed topic, given the following setup
67 | | parameter | value |
68 | | --- | --- |
69 | | tenant | presiot |
70 | | device-name | CloudFox-Laptop |
71 | | *clientID* | *presiot_CloudFox-Laptop* |
72 | | *commanding topic* | *tc/presiot/presiot_CloudFox-Laptop/i/cmd_v3/c* |
73 |
74 | > **_NOTE:_** The parameters written in *italics* are defined automatically based on tenant and device-name
75 |
76 | 
77 |
78 | ## See also
79 | - [Insights Hub MindConnect MQTT Broker - API specs](https://documentation.mindsphere.io/MindSphere/concepts/concept-mindsphere-mqtt-broker.html)
80 | - [Insights Hub MindConnect MQTT Broker - How To section](https://documentation.mindsphere.io/MindSphere/concepts/concept-mindsphere-mqtt-broker.html)
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/createCustomAPI_endpoint/IMPORT_createCustomEndpoint.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "d7e45377.0bd91",
4 | "type": "comment",
5 | "z": "cc37014d.14a9c",
6 | "name": "Public API endpoint to read asset data",
7 | "info": "- last 15min of selected asset data is feedback as JSON object\n- endpoint: https://-visualflowcreator.eu1.mindsphere.io/public//machinedata/v1",
8 | "sticky": 1,
9 | "x": 450,
10 | "y": 100,
11 | "wires": [],
12 | "_type": "node"
13 | },
14 | {
15 | "id": "79cfd4b8.669b9c",
16 | "type": "http in",
17 | "z": "cc37014d.14a9c",
18 | "name": "[GET] /machinedata/v1",
19 | "endpoint": "/machinedata/v1",
20 | "method": "get",
21 | "upload": false,
22 | "access": "key",
23 | "key": "",
24 | "users": "",
25 | "x": 200,
26 | "y": 180,
27 | "wires": [
28 | [
29 | "7327953f.63fb9c"
30 | ]
31 | ],
32 | "_type": "node"
33 | },
34 | {
35 | "id": "e09e25e4.470548",
36 | "type": "http response",
37 | "z": "cc37014d.14a9c",
38 | "name": "",
39 | "statusCode": "",
40 | "headers": {},
41 | "x": 770,
42 | "y": 180,
43 | "wires": []
44 | },
45 | {
46 | "id": "7327953f.63fb9c",
47 | "type": "read timeseries",
48 | "z": "cc37014d.14a9c",
49 | "name": "read last 15min of machine data",
50 | "topic": "",
51 | "topicLabel": "",
52 | "assetName": "",
53 | "period": "15",
54 | "offset": "0",
55 | "mode": "relative",
56 | "from": "",
57 | "datetimepickerFrom": "",
58 | "to": "",
59 | "datetimepickerTo": "",
60 | "timezoneoffset": 0,
61 | "x": 490,
62 | "y": 180,
63 | "wires": [
64 | [
65 | "e09e25e4.470548"
66 | ]
67 | ],
68 | "_type": "node"
69 | }
70 | ]
--------------------------------------------------------------------------------
/createCustomAPI_endpoint/doc/createCustomEndpoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/createCustomAPI_endpoint/doc/createCustomEndpoint.png
--------------------------------------------------------------------------------
/createCustomAPI_endpoint/doc/result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/createCustomAPI_endpoint/doc/result.png
--------------------------------------------------------------------------------
/createCustomAPI_endpoint/doc/setup_KeyGeneration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/createCustomAPI_endpoint/doc/setup_KeyGeneration.png
--------------------------------------------------------------------------------
/createCustomAPI_endpoint/doc/setup_selectAssetToRead.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/createCustomAPI_endpoint/doc/setup_selectAssetToRead.png
--------------------------------------------------------------------------------
/createCustomAPI_endpoint/readme.md:
--------------------------------------------------------------------------------
1 | # Create a custom API endpoint
2 |
3 | If you want to provide some external partners/users with your Insights Hub data though a customizable API endpoint, this is how you get started on this.
4 | The example shows how you can
5 | - specify a dedicated Insights Hub RestAPI endpoint
6 | - select the method the endpoint should support (GET, PUT, POST, DELETE)
7 | - choose who has access to this endpoint (only users of the flow, all users on the tenant, public access)
8 | - develop the API functionality using VFC nodes
9 |
10 | This flow demonstrates a simple getting-started example on how to provide machine data via an API for external access of the last 15min interval of machine data as JSON object.
11 | 
12 |
13 |
14 | ## Setup & Configuration
15 |
16 | 1. Import the flow in Visual Flow Creator
17 | 2. Setup the API endpoint in the HTTP-IN node (blue node)
18 | - enter you custom endpoint-URL
19 | - choose endpoint access
20 | - generate key in case of public API access
21 | - the URL shown in the node setup is the direct URL to access the service
22 | 
23 | 3. Select an Asset / Aspect / Variable(s) where you want to read the time series data from (yellow node)
24 | 
25 | 4. Save the flow
26 |
27 | > **Service-URL:** The URL to access the endpoint can be found in the *HTTP IN* node and has the schema as follows
28 | https://[TenantName]-visualflowcreatorhttp.eu1.mindsphere.io/public/presiot/machinedata/v1?key=[generatedKey]
29 |
30 | :cloud: :heavy_check_mark: You're ready to access the service via the URL shown in the *HTTP IN* node - enjoy!
31 |
32 | ## Result
33 |
34 | When querying the service URL e.g. via a Browser/Postman/Python/... the JSON-object with the timeseries data will be received.
35 | 
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/createRuleForAssetType/createRuleForAssetType.json:
--------------------------------------------------------------------------------
1 | [{
2 | "id": "8f12e86e.fc4c",
3 | "type": "asset-type",
4 | "z": "bf4ef0cb.2b46e8",
5 | "name": "",
6 | "topic": "[MobilePhone]/Acceleration/x",
7 | "assetType": "free4h1w.mobilephone",
8 | "asset": "",
9 | "exclude": "",
10 | "aspect": "Acceleration",
11 | "variable": "x",
12 | "x": 240,
13 | "y": 180,
14 | "wires": [
15 | ["a334ede2.883c2"]
16 | ],
17 | "_type": "node"
18 | }, {
19 | "id": "72e48473.3782dc",
20 | "type": "comment",
21 | "z": "bf4ef0cb.2b46e8",
22 | "name": "",
23 | "info": "select all assets of this type",
24 | "sticky": 1,
25 | "x": 310,
26 | "y": 140,
27 | "wires": [],
28 | "_type": "node"
29 | }, {
30 | "id": "9d1feea5.530c48",
31 | "type": "create event",
32 | "z": "bf4ef0cb.2b46e8",
33 | "name": "",
34 | "asset": "",
35 | "assetName": "",
36 | "severity": "40",
37 | "acknowledged": "false",
38 | "source": "VFC rule test",
39 | "description": "VFC rule triggered",
40 | "x": 910,
41 | "y": 360,
42 | "wires": [],
43 | "_type": "node"
44 | }, {
45 | "id": "efde183f.4a7a88",
46 | "type": "filter2",
47 | "z": "bf4ef0cb.2b46e8",
48 | "name": "my rule",
49 | "lambda": "element.x > 30",
50 | "x": 600,
51 | "y": 180,
52 | "wires": [
53 | ["9dd878e6.d1f218"]
54 | ],
55 | "_type": "node"
56 | }, {
57 | "id": "9dd878e6.d1f218",
58 | "type": "function",
59 | "z": "bf4ef0cb.2b46e8",
60 | "name": "",
61 | "func": "msg.asset = msg.topic.split('/')[0];\nreturn msg;",
62 | "outputs": 1,
63 | "noerr": 0,
64 | "x": 480,
65 | "y": 360,
66 | "wires": [
67 | ["27c8a409.05bcd4", "80b538c6.7f079"]
68 | ],
69 | "_type": "node"
70 | }, {
71 | "id": "d10d784d.7c141",
72 | "type": "inject",
73 | "z": "bf4ef0cb.2b46e8",
74 | "name": "Trigger",
75 | "topic": "",
76 | "payload": "",
77 | "payloadType": "date",
78 | "repeat": "",
79 | "crontab": "",
80 | "once": false,
81 | "properties": "",
82 | "timezone": "utc",
83 | "betweentimesunit": "m",
84 | "enableRuleEngine": false,
85 | "x": 110,
86 | "y": 180,
87 | "wires": [
88 | ["8f12e86e.fc4c"]
89 | ],
90 | "_type": "node"
91 | }, {
92 | "id": "a334ede2.883c2",
93 | "type": "read timeseries",
94 | "z": "bf4ef0cb.2b46e8",
95 | "name": "",
96 | "topic": "",
97 | "topicLabel": "",
98 | "assetName": "",
99 | "period": "60",
100 | "offset": "0",
101 | "mode": "relative",
102 | "from": "",
103 | "datetimepickerFrom": "",
104 | "to": "",
105 | "datetimepickerTo": "",
106 | "timezoneoffset": 0,
107 | "x": 400,
108 | "y": 180,
109 | "wires": [
110 | ["efde183f.4a7a88"]
111 | ],
112 | "_type": "node"
113 | }, {
114 | "id": "60954bf3.6cbbec",
115 | "type": "send email",
116 | "z": "bf4ef0cb.2b46e8",
117 | "name": "",
118 | "recipients": "",
119 | "subject": "Example rule per asset type has been triggered",
120 | "message": "Your rule has been triggered:\n\n${payload}",
121 | "mode": "subject",
122 | "categoryId": "",
123 | "category": "",
124 | "priority": "normal",
125 | "x": 910,
126 | "y": 320,
127 | "wires": [],
128 | "_type": "node"
129 | }, {
130 | "id": "80b538c6.7f079",
131 | "type": "debug",
132 | "z": "bf4ef0cb.2b46e8",
133 | "name": "",
134 | "active": true,
135 | "console": "false",
136 | "xaxis": "_time",
137 | "complete": "payload",
138 | "x": 670,
139 | "y": 400,
140 | "wires": [],
141 | "_type": "node"
142 | }, {
143 | "id": "27c8a409.05bcd4",
144 | "type": "switch",
145 | "z": "bf4ef0cb.2b46e8",
146 | "name": "",
147 | "property": "payload[0]",
148 | "propertyType": "msg",
149 | "rules": [{
150 | "t": "nnull"
151 | }],
152 | "checkall": "true",
153 | "outputs": 1,
154 | "x": 650,
155 | "y": 360,
156 | "wires": [
157 | ["9d1feea5.530c48"]
158 | ],
159 | "_type": "node"
160 | }, {
161 | "id": "6fe9315d.1fe0e",
162 | "type": "comment",
163 | "z": "bf4ef0cb.2b46e8",
164 | "name": "",
165 | "info": "read the timeseries data",
166 | "sticky": 1,
167 | "x": 430,
168 | "y": 220,
169 | "wires": [],
170 | "_type": "node"
171 | }, {
172 | "id": "9007c78e.7ea2e",
173 | "type": "comment",
174 | "z": "bf4ef0cb.2b46e8",
175 | "name": "",
176 | "info": "define the rule\nin this case: value > 30",
177 | "sticky": 1,
178 | "x": 650,
179 | "y": 120,
180 | "wires": [],
181 | "_type": "node"
182 | }, {
183 | "id": "68612bd.76696d4",
184 | "type": "comment",
185 | "z": "bf4ef0cb.2b46e8",
186 | "name": "",
187 | "info": "extract data and fire only an event,\nif the rule has been triggred",
188 | "sticky": 1,
189 | "x": 580,
190 | "y": 300,
191 | "wires": [],
192 | "_type": "node"
193 | }, {
194 | "id": "2ca5fc2c.159afc",
195 | "type": "comment",
196 | "z": "bf4ef0cb.2b46e8",
197 | "name": "",
198 | "info": "fire an action:\ncreate an event or\nsend a email",
199 | "sticky": 1,
200 | "x": 930,
201 | "y": 240,
202 | "wires": [],
203 | "_type": "node"
204 | }]
--------------------------------------------------------------------------------
/createRuleForAssetType/doc/createRuleForAssetType.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/createRuleForAssetType/doc/createRuleForAssetType.png
--------------------------------------------------------------------------------
/createRuleForAssetType/readme.md:
--------------------------------------------------------------------------------
1 | # FLOW: Create rule for assets of a specific asset type
2 |
3 | You might created a flow where you monitor a single variable for a defined condition. But how can you simply roll this out to all assets of this type without much effort? Just use the `asset type`-node and try the following example.
4 |
5 | # Example image
6 |
7 | 
8 |
9 | # How to
10 |
11 | - Import the flow in Visual Flow Creator
12 | - Double click the asset type node and select an asset type in your tenant
13 |
14 | # How does this flow works
15 |
16 | - the flow is triggered by the inject node
17 | - with the `asset type` node VFC will get all assets of a specific type and perform the action for all assets of this type
18 | - you can also disable specific assets, that they are not used
19 | - for all of this assets a rule is checked and an email can be sent or a Insights Hub event can be created
20 |
--------------------------------------------------------------------------------
/data_simulation_24h/doc/24h-replay-for_data-simulation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/data_simulation_24h/doc/24h-replay-for_data-simulation.png
--------------------------------------------------------------------------------
/data_simulation_24h/doc/FileUpload_AssetManager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/data_simulation_24h/doc/FileUpload_AssetManager.png
--------------------------------------------------------------------------------
/data_simulation_24h/doc/FileUpload_Monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/data_simulation_24h/doc/FileUpload_Monitor.png
--------------------------------------------------------------------------------
/data_simulation_24h/doc/explain-of-logic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/data_simulation_24h/doc/explain-of-logic.png
--------------------------------------------------------------------------------
/data_simulation_24h/flow_template.json:
--------------------------------------------------------------------------------
1 | [{"id":"8edcf448.d73278","type":"tab","allowCycles":false,"label":"24h Data Simulator","disabled":false,"info":"author: christoph.doehl@siemens.com\n\n\ndescription:\nData simulation system that replays a single day's \nreference dataset in a continuous loop. \n\nUses a 24-hour sample file as a template \nto generate repeating daily patterns \nfor testing and simulation purposes."},{"id":"960fe822.f78cd8","type":"group","z":"8edcf448.d73278","name":"Daily Reference Pattern Replay // Continous data ingest and simulation based on 24h scheme reference file ","style":{"label":true},"nodes":["2159bd3e.fbd582","48bd139.db610ec","ceec7ee7.e5625","1d69b214.0f6bfe","eeee3487.33cae8","f4518285.e6eaf","d1f2548d.d27528","52de7c95.f92fe4"],"x":75,"y":120,"w":1110,"h":189},{"id":"2159bd3e.fbd582","type":"debug","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"","active":true,"console":"false","xaxis":"_time","complete":"true","x":1090,"y":160,"wires":[],"_type":"node"},{"id":"48bd139.db610ec","type":"function","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"Filter last x minutes","func":"function filterAndUpdateTimestamps(msg, timeRangeMinutes) {\n var data = msg.payload;\n var now = new Date();\n var timeRangeMs = timeRangeMinutes * 60000; // Convert minutes to milliseconds\n var cutoffTime = new Date(now.getTime() - timeRangeMs);\n\n // Debug: Log input data length\n node.warn(`Input data length: ${data.length}`);\n node.warn(`Filtering last ${timeRangeMinutes} minutes, from ${cutoffTime.toISOString()} to ${now.toISOString()}`);\n\n if (!Array.isArray(data)) {\n node.error(\"Input data is not an array\");\n return [];\n }\n\n // First, update all timestamps to today's date\n var updatedData = data.map(entry => {\n if (!entry._time) {\n node.warn(`Entry missing _time field: ${JSON.stringify(entry)}`);\n return entry;\n }\n var entryTime = new Date(entry._time);\n if (isNaN(entryTime.getTime())) {\n node.warn(`Invalid date: ${entry._time}`);\n return entry;\n }\n var updatedTime = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n entryTime.getHours(),\n entryTime.getMinutes(),\n entryTime.getSeconds(),\n entryTime.getMilliseconds()\n );\n return {\n ...entry,\n _time: updatedTime.toISOString()\n };\n });\n\n // Then, filter the updated data\n var filteredData = updatedData.filter(entry => {\n var entryTime = new Date(entry._time);\n return entryTime >= cutoffTime && entryTime <= now;\n });\n\n // Debug: Log filtered data length\n node.warn(`Filtered data length: ${filteredData.length}`);\n\n return filteredData;\n}\n\n// Usage\n// This can be set to any value you want in MINUTES\nvar timeRangeMinutes = msg.flowSetting_simulatorRun // 5; \n\nmsg.payload = filterAndUpdateTimestamps(msg, timeRangeMinutes);\n\n// Debug: Log final payload length\nnode.warn(`Final payload length: ${msg.payload.length}`);\n\nreturn msg;","outputs":1,"language":"javascript","noerr":0,"x":710,"y":200,"wires":[["ceec7ee7.e5625"]],"_type":"node"},{"id":"ceec7ee7.e5625","type":"function","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"prep TS values","func":"msg.payload = msg.payload.map(entry => {\n // Create a new object with all properties from the entry\n return Object.assign({}, entry);\n \n // Alternatively, use the spread operator:\n // return { ...entry };\n});\nreturn msg;","outputs":1,"language":"javascript","noerr":0,"x":920,"y":200,"wires":[["2159bd3e.fbd582","52de7c95.f92fe4"]],"_type":"node"},{"id":"1d69b214.0f6bfe","type":"inject","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"every 5min","topic":"","payload":"","payloadType":"date","repeat":"300","repeatEnd":"0","endTime":"0","crontab":"","offset":"","once":false,"properties":"","timezone":"utc","betweentimesunit":"m","showNextExecution":true,"powerMode":false,"x":190,"y":200,"wires":[["f4518285.e6eaf"]]},{"id":"eeee3487.33cae8","type":"comment","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"⬆️⬆️⬆️ adjust and config your flow here","info":"DO ONLY setup here, no other changes are needed","sticky":1,"x":460,"y":260,"wires":[],"_type":"node"},{"id":"f4518285.e6eaf","type":"function","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"CONFIG","func":"// ******************** CONFIGURATION TEMPLATE ********************\n// //\n// // EDITABLE VALUES:\n// var assetId = \"myAssetId\"; // Enter your asset ID\n// var aspectName = \"myAspectName\"; // Enter your aspect name\n// var filename = \"myFileNameWithPath\"; // Enter your file path\n// var simulatorRun = 5; // Enter the occurance your flow is run in minutes [min]\n// //\n// // DO NOT MODIFY BELOW THIS LINE\n// // **************************************************************\n// msg.asset = assetId\n// msg.file = filename\n// msg.topic = assetId + \"/\" + aspectName;\n// return msg;\n// **************************************************************\n\n\n// EDITABLE VALUES:\nvar assetId = \"26a76a1e8d8f48d791fc4ded12e39686\"; // Enter your asset ID\nvar aspectName = \"environmentData\"; // Enter your aspect name\nvar filename = \"env-data.json\"; // Enter your file path\nvar simulatorRun = 5; // set to run every 5min\n//\n//\n// DO NOT MODIFY BELOW THIS LINE\n// **************************************************************\nmsg.asset = assetId\nmsg.file = filename\nmsg.topic = assetId + \"/\" + aspectName;\nmsg.flowSetting_simulatorRun = simulatorRun\n\nreturn msg;\n","outputs":1,"language":"javascript","noerr":0,"x":360,"y":200,"wires":[["d1f2548d.d27528"]],"_type":"node"},{"id":"d1f2548d.d27528","type":"read file","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"","asset":"","file":"","x":520,"y":200,"wires":[["48bd139.db610ec"]]},{"id":"52de7c95.f92fe4","type":"write timeseries","z":"8edcf448.d73278","g":"960fe822.f78cd8","name":"","topic":"","topicData":"","topicLabel":"","assetName":"","aspectName":"","useMerging":false,"x":1100,"y":200,"wires":[]}]
--------------------------------------------------------------------------------
/data_simulation_24h/readme.md:
--------------------------------------------------------------------------------
1 | # 24-hour Data Simulation Pattern Replay
2 |
3 | This flow creates a continuous data simulation by automatically repeating a 24-hour reference dataset.
4 | It transforms a single day's worth of sample data into an ongoing simulation pattern, making it perfect for industrial testing and monitoring scenarios.
5 |
6 | The diagram below illustrates the underlying logic:
7 | 
8 |
9 | Here's the Visual Flow Creator (VFC) implementation:
10 | 
11 |
12 | **Contents**
13 | - [24-hour Data Simulation Pattern Replay](#24-hour-data-simulation-pattern-replay)
14 | - [Prerequisites](#prerequisites)
15 | - [Reference Data File Structure](#reference-data-file-structure)
16 | - [Reference File Storage](#reference-file-storage)
17 | - [Setup \& Configuration](#setup--configuration)
18 | - [How It Works](#how-it-works)
19 | - [Results](#results)
20 | - [Additional Resources](#additional-resources)
21 | ## Prerequisites
22 |
23 | ### Reference Data File Structure
24 |
25 | Your reference file must contain timestamps (`_time`) and all variables defined in the Aspect. The timestamps must meet these requirements:
26 |
27 | - All timestamps must be from the same day
28 | - Data must span the full day (from `00:00` to `23:59`)
29 |
30 | You can customize the data sampling frequency (e.g., every 1 minute or 15 minutes) based on your needs. Important: Ensure your simulation schedule matches your reference data frequency. For example, if your reference data has 15-minute intervals but your flow runs every 5 minutes, some executions won't generate new data.
31 |
32 | ```json
33 | [
34 | {
35 | "_time": "2024-07-29T00:00:00.000000Z",
36 | "temperature": 24.77,
37 | "humidity": 42.02,
38 | "pressure": 979.1
39 | },
40 | {
41 | "_time": "2024-07-29T00:01:00.000000Z",
42 | "temperature": 24.77,
43 | "humidity": 42.02,
44 | "pressure": 979.1
45 | },
46 | ...
47 | {
48 | "_time": "2024-07-29T23:59:00.000000Z",
49 | "temperature": 29.73,
50 | "humidity": 46.08,
51 | "pressure": 982.2
52 | }
53 | ]
54 | ```
55 |
56 | ### Reference File Storage
57 |
58 | Upload your JSON reference file (containing 24 hours of sample data) directly to the asset. You have two options:
59 |
60 | 1. Via Asset Manager:
61 | 
62 | 2. Via Monitor:
63 | 
64 |
65 | ## Setup & Configuration
66 |
67 | 1. Import the provided flow into Visual Flow Creator
68 | 2. Update the CONFIG node with your specific parameters:
69 |
70 | ```javascript
71 | var assetId = "your-asset-id"; // Target asset identifier
72 | var aspectName = "your-aspect-name"; // Aspect to simulate
73 | var filename = "your-file.json"; // Reference data filename
74 | var simulatorRun = 5; // Simulation interval (minutes)
75 | ```
76 |
77 | 3. Verify that your reference file is available at the specified asset location
78 | 4. Deploy the flow
79 | 5. Save your configuration
80 |
81 | :cloud: :heavy_check_mark: Your simulation is now ready to run!
82 |
83 | ## How It Works
84 |
85 | 1. The flow activates at specified intervals (default: every 5 minutes)
86 | 2. Retrieves the reference data from your asset
87 | 3. Selects relevant data points based on the current time and last execution
88 | 4. Adjusts timestamps to match the current day while maintaining the original time patterns
89 | 5. Uploads the updated data to timeseries storage
90 |
91 | ## Results
92 |
93 | - Seamless, continuous data pattern simulation
94 | - Preserved time intervals between data points
95 | - Consistent daily pattern reproduction
96 | - Automatic timestamp updates
97 | - Hands-free operation once configured
98 |
99 | ## Additional Resources
100 |
101 | - [Industrial IoT - Insights Hub Documentation](https://documentation.mindsphere.io/resources/html/iot-hub/en-US/index.html)
102 | - [Visual Flow Creator Documentation](https://documentation.mindsphere.io/resources/html/visual-flow-creator/en-US/index.html)
103 |
--------------------------------------------------------------------------------
/docs/How_To_Import.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/docs/How_To_Import.gif
--------------------------------------------------------------------------------
/docs/Launchpad_VFC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/docs/Launchpad_VFC.png
--------------------------------------------------------------------------------
/docs/VFC_roles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/docs/VFC_roles.png
--------------------------------------------------------------------------------
/generateSampleData/doc/generateSampleData.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/generateSampleData/doc/generateSampleData.png
--------------------------------------------------------------------------------
/generateSampleData/generateSampleData.json:
--------------------------------------------------------------------------------
1 | [{
2 | "id": "b8724091.fad0d8",
3 | "type": "tab",
4 | "label": "GenerateSampleData",
5 | "disabled": false,
6 | "info": ""
7 | }, {
8 | "id": "e0edcfb3.cfea58",
9 | "type": "debug",
10 | "z": "b8724091.fad0d8",
11 | "name": "",
12 | "active": true,
13 | "console": "false",
14 | "xaxis": "_time",
15 | "complete": "false",
16 | "x": 970,
17 | "y": 200,
18 | "wires": []
19 | }, {
20 | "id": "c1280b00.455088",
21 | "type": "function",
22 | "z": "b8724091.fad0d8",
23 | "name": "String",
24 | "func": "var series = [];\n\nfor(var i = 0; i< msg.payload.length; i++) {\n var element ={_time:\"\", String:\"\"};\n element.String = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + '\\u0000\\u0007\\u0000';\n element._time = msg.payload[i]._time;\n series.push(element);\n}\n\nreturn {payload: series}\n",
25 | "outputs": "1",
26 | "noerr": "0",
27 | "x": 650,
28 | "y": 320,
29 | "wires": [
30 | []
31 | ],
32 | "inputLabels": ["outArray"]
33 | }, {
34 | "id": "575e1400.ddc184",
35 | "type": "function",
36 | "z": "b8724091.fad0d8",
37 | "name": "Boolean",
38 | "func": "var series = [];\n\nfor(var i = 0; i< msg.payload.length; i++) {\n var element ={_time:\"\", Boolean:false};\n element.Boolean = msg.payload[i].varNoise > 0;\n element._time = msg.payload[i]._time;\n series.push(element);\n}\n\nreturn {payload: series}\n",
39 | "outputs": 1,
40 | "noerr": 0,
41 | "x": 640,
42 | "y": 280,
43 | "wires": [
44 | []
45 | ],
46 | "inputLabels": ["outArray"]
47 | }, {
48 | "id": "13170dcf.f22f7a",
49 | "type": "function",
50 | "z": "b8724091.fad0d8",
51 | "name": "TimeStamp",
52 | "func": "var series = [];\n\nfor(var i = 0; i< msg.payload.length; i++) {\n var element ={_time:\"\", TimeStamp:\"\"};\n element.TimeStamp = msg.payload[i]._time;\n element._time = msg.payload[i]._time;\n series.push(element);\n}\n\nreturn {payload: series}\n",
53 | "outputs": 1,
54 | "noerr": 0,
55 | "x": 630,
56 | "y": 360,
57 | "wires": [
58 | []
59 | ],
60 | "inputLabels": ["outArray"]
61 | }, {
62 | "id": "ba671532.7e8cc",
63 | "type": "function",
64 | "z": "b8724091.fad0d8",
65 | "name": "BigString",
66 | "func": "var series = [];\n\nfor(var i = 0; i< msg.payload.length; i++) {\n var element ={_time:\"\", BigString:\"\"};\n element.BigString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + '\\u0000\\u0007\\u0000';\n element._time = msg.payload[i]._time;\n series.push(element);\n}\n\nreturn {payload: series}\n",
67 | "outputs": "1",
68 | "noerr": 0,
69 | "x": 640,
70 | "y": 400,
71 | "wires": [
72 | []
73 | ],
74 | "inputLabels": ["outArray"]
75 | }, {
76 | "id": "4ee1ce9a.a31a48",
77 | "type": "generate",
78 | "z": "b8724091.fad0d8",
79 | "name": "Double",
80 | "from": "",
81 | "datetimepickerFrom": "",
82 | "to": "",
83 | "datetimepickerTo": "",
84 | "parameterout": "Double",
85 | "period": "10",
86 | "mode": "relative",
87 | "basisUnit": "minute",
88 | "framesPerBasisUnit": "1",
89 | "numberOfDecimalPlaces": "3",
90 | "signals": "[{\"signal\":\"sine\",\"amplitude\":\"230\",\"frequency\":1,\"phase\":0,\"offset\":0,\"start\":0,\"stop\":1,\"excludeStart\":false,\"excludeStop\":false}]",
91 | "signal": "",
92 | "amplitude": "",
93 | "frequency": "",
94 | "phase": "",
95 | "offset": "",
96 | "start": "",
97 | "stop": "",
98 | "formula": "+",
99 | "x": 640,
100 | "y": 200,
101 | "wires": [
102 | []
103 | ]
104 | }, {
105 | "id": "1a9461cb.1456de",
106 | "type": "generate",
107 | "z": "b8724091.fad0d8",
108 | "name": "Integer",
109 | "from": "",
110 | "datetimepickerFrom": "",
111 | "to": "",
112 | "datetimepickerTo": "",
113 | "parameterout": "data",
114 | "period": "10",
115 | "mode": "relative",
116 | "basisUnit": "minute",
117 | "framesPerBasisUnit": "1",
118 | "numberOfDecimalPlaces": "0",
119 | "signals": "[{\"signal\":\"linear\",\"amplitude\":\"33\",\"frequency\":1,\"phase\":0,\"offset\":0,\"start\":0,\"stop\":1,\"excludeStart\":false,\"excludeStop\":false}]",
120 | "signal": "",
121 | "amplitude": "",
122 | "frequency": "",
123 | "phase": "",
124 | "offset": "",
125 | "start": "",
126 | "stop": "",
127 | "formula": "+",
128 | "x": 640,
129 | "y": 160,
130 | "wires": [
131 | ["ac338ebe.8c29b8", "e0edcfb3.cfea58"]
132 | ]
133 | }, {
134 | "id": "66f3174.6fddf68",
135 | "type": "generate",
136 | "z": "b8724091.fad0d8",
137 | "name": "Long",
138 | "from": "",
139 | "datetimepickerFrom": "",
140 | "to": "",
141 | "datetimepickerTo": "",
142 | "parameterout": "Long",
143 | "period": "10",
144 | "mode": "relative",
145 | "basisUnit": "minute",
146 | "framesPerBasisUnit": "1",
147 | "numberOfDecimalPlaces": "0",
148 | "signals": "[{\"signal\":\"noise\",\"amplitude\":\"266\",\"frequency\":1,\"phase\":0,\"offset\":0,\"start\":0,\"stop\":1,\"excludeStart\":false,\"excludeStop\":false}]",
149 | "signal": "",
150 | "amplitude": "",
151 | "frequency": "",
152 | "phase": "",
153 | "offset": "",
154 | "start": "",
155 | "stop": "",
156 | "formula": "+",
157 | "x": 650,
158 | "y": 240,
159 | "wires": [
160 | []
161 | ]
162 | }, {
163 | "id": "7f9f481.6a33fb8",
164 | "type": "generate",
165 | "z": "b8724091.fad0d8",
166 | "name": "Random Data",
167 | "from": "",
168 | "datetimepickerFrom": "",
169 | "to": "",
170 | "datetimepickerTo": "",
171 | "parameterout": "varNoise",
172 | "period": "10",
173 | "mode": "relative",
174 | "basisUnit": "minute",
175 | "framesPerBasisUnit": "10",
176 | "numberOfDecimalPlaces": "0",
177 | "signals": "[{\"signal\":\"noise\",\"amplitude\":\"1000\",\"frequency\":1,\"phase\":0,\"offset\":\"0\",\"start\":\"0\",\"stop\":\"1\"}]",
178 | "signal": "",
179 | "amplitude": "",
180 | "frequency": "",
181 | "phase": "",
182 | "offset": "",
183 | "start": "",
184 | "stop": "",
185 | "formula": "+",
186 | "x": 470,
187 | "y": 280,
188 | "wires": [
189 | ["575e1400.ddc184"]
190 | ],
191 | "outputLabels": ["outArray"],
192 | "_type": "node"
193 | }, {
194 | "id": "3a9fba6d.99cb76",
195 | "type": "generate",
196 | "z": "b8724091.fad0d8",
197 | "name": "Random Data",
198 | "from": "",
199 | "datetimepickerFrom": "",
200 | "to": "",
201 | "datetimepickerTo": "",
202 | "parameterout": "varNoise",
203 | "period": "10",
204 | "mode": "relative",
205 | "basisUnit": "minute",
206 | "framesPerBasisUnit": "10",
207 | "numberOfDecimalPlaces": "0",
208 | "signals": "[{\"signal\":\"noise\",\"amplitude\":\"1000\",\"frequency\":1,\"phase\":0,\"offset\":\"0\",\"start\":\"0\",\"stop\":\"1\"}]",
209 | "signal": "",
210 | "amplitude": "",
211 | "frequency": "",
212 | "phase": "",
213 | "offset": "",
214 | "start": "",
215 | "stop": "",
216 | "formula": "+",
217 | "x": 470,
218 | "y": 320,
219 | "wires": [
220 | ["c1280b00.455088"]
221 | ],
222 | "outputLabels": ["outArray"],
223 | "_type": "node"
224 | }, {
225 | "id": "72b50786.4c56d8",
226 | "type": "generate",
227 | "z": "b8724091.fad0d8",
228 | "name": "Random Data",
229 | "from": "",
230 | "datetimepickerFrom": "",
231 | "to": "",
232 | "datetimepickerTo": "",
233 | "parameterout": "varNoise",
234 | "period": "10",
235 | "mode": "relative",
236 | "basisUnit": "minute",
237 | "framesPerBasisUnit": "10",
238 | "numberOfDecimalPlaces": "0",
239 | "signals": "[{\"signal\":\"noise\",\"amplitude\":\"1000\",\"frequency\":1,\"phase\":0,\"offset\":\"0\",\"start\":\"0\",\"stop\":\"1\"}]",
240 | "signal": "",
241 | "amplitude": "",
242 | "frequency": "",
243 | "phase": "",
244 | "offset": "",
245 | "start": "",
246 | "stop": "",
247 | "formula": "+",
248 | "x": 470,
249 | "y": 360,
250 | "wires": [
251 | ["13170dcf.f22f7a"]
252 | ],
253 | "outputLabels": ["outArray"],
254 | "_type": "node"
255 | }, {
256 | "id": "228140c1.dc9d28",
257 | "type": "generate",
258 | "z": "b8724091.fad0d8",
259 | "name": "Noise",
260 | "from": "",
261 | "datetimepickerFrom": "",
262 | "to": "",
263 | "datetimepickerTo": "",
264 | "parameterout": "varNoise",
265 | "period": "10",
266 | "mode": "relative",
267 | "basisUnit": "minute",
268 | "framesPerBasisUnit": "10",
269 | "numberOfDecimalPlaces": "0",
270 | "signals": "[{\"signal\":\"noise\",\"amplitude\":\"1000\",\"frequency\":1,\"phase\":0,\"offset\":\"0\",\"start\":\"0\",\"stop\":\"1\"}]",
271 | "signal": "",
272 | "amplitude": "",
273 | "frequency": "",
274 | "phase": "",
275 | "offset": "",
276 | "start": "",
277 | "stop": "",
278 | "formula": "+",
279 | "x": 450,
280 | "y": 400,
281 | "wires": [
282 | ["ba671532.7e8cc"]
283 | ],
284 | "outputLabels": ["outArray"]
285 | }, {
286 | "id": "6eb44626.325a",
287 | "type": "inject",
288 | "z": "b8724091.fad0d8",
289 | "name": "Trigger",
290 | "topic": "",
291 | "payload": "",
292 | "payloadType": "date",
293 | "repeat": "",
294 | "crontab": "",
295 | "once": false,
296 | "properties": "",
297 | "timezone": "utc",
298 | "betweentimesunit": "m",
299 | "enableRuleEngine": false,
300 | "x": 250,
301 | "y": 260,
302 | "wires": [
303 | ["1a9461cb.1456de", "4ee1ce9a.a31a48", "66f3174.6fddf68", "228140c1.dc9d28", "72b50786.4c56d8", "3a9fba6d.99cb76", "7f9f481.6a33fb8"]
304 | ]
305 | }, {
306 | "id": "ac338ebe.8c29b8",
307 | "type": "write timeseries",
308 | "z": "b8724091.fad0d8",
309 | "name": "",
310 | "topic": "4b93918103014381a891cbc545029952/potiData/data",
311 | "topicLabel": "RPI Device/potiData/data",
312 | "assetName": "RPI Device",
313 | "x": 1010,
314 | "y": 160,
315 | "wires": []
316 | }, {
317 | "id": "7d50f268.bcb14c",
318 | "type": "comment",
319 | "z": "b8724091.fad0d8",
320 | "name": "",
321 | "info": "generate some sample data for different data types",
322 | "sticky": 1,
323 | "x": 510,
324 | "y": 100,
325 | "wires": [],
326 | "_type": "node"
327 | }, {
328 | "id": "c5963ac3.a6e468",
329 | "type": "comment",
330 | "z": "b8724091.fad0d8",
331 | "name": "",
332 | "info": "write the sample data to\nyour asset variable",
333 | "sticky": 1,
334 | "x": 1010,
335 | "y": 260,
336 | "wires": [],
337 | "_type": "node"
338 | }]
--------------------------------------------------------------------------------
/generateSampleData/readme.md:
--------------------------------------------------------------------------------
1 | # Generate sample data
2 |
3 | Did you sometimes asked yourself, how you get some sample data in your asset? Sample data e.g. for demonstration purposes, for debugging or for testing a new feature.
4 |
5 | With this example you are able to do that.
6 |
7 | # How to
8 |
9 | 
10 |
11 | - Import the flow in Visual Flow Creator
12 | - Select an asset / aspect / variable where you want to write time series data
13 | - Double click on the datatype node like `Integer` and rename the `Parameter out` value with the name of your data variable
14 | - Save the flow
15 | - Trigger the flow
--------------------------------------------------------------------------------
/integrateExternalApi/doc/API_KEY_details.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/integrateExternalApi/doc/API_KEY_details.png
--------------------------------------------------------------------------------
/integrateExternalApi/doc/external_API_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/integrateExternalApi/doc/external_API_image.png
--------------------------------------------------------------------------------
/integrateExternalApi/externalApi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "27d9cd3.b828732",
4 | "type": "group",
5 | "z": "216044f1.bc512c",
6 | "name": "Get weather data from external service",
7 | "style": {
8 | "label": true
9 | },
10 | "nodes": [
11 | "c0346697.e8ead8",
12 | "c5938bad.c5fa38",
13 | "ad0608a8.b597a8",
14 | "8ae6a14c.c24fd",
15 | "ad0dfb26.1fd928",
16 | "b50d362b.e41418",
17 | "99cd1a17.a81548"
18 | ],
19 | "x": 75,
20 | "y": 581,
21 | "w": 1170,
22 | "h": 418
23 | },
24 | {
25 | "id": "c0346697.e8ead8",
26 | "type": "function",
27 | "z": "216044f1.bc512c",
28 | "g": "27d9cd3.b828732",
29 | "name": "parse for desired data",
30 | "func": "const data = msg.payload;\n\nmsg.topic = \"5f634f70df3d484baabbbc361f5b9b9e/weather_data\";\n\nmsg.payload = {\n temperature: data.main.temp,\n pressure: data.main.pressure,\n humidity: data.main.humidity,\n wind_speed: data.wind.speed,\n wind_direction: data.wind.deg\n }\n\nreturn msg;",
31 | "outputs": 1,
32 | "language": "javascript",
33 | "noerr": 0,
34 | "x": 700,
35 | "y": 780,
36 | "wires": [
37 | [
38 | "c5938bad.c5fa38"
39 | ]
40 | ],
41 | "_type": "node"
42 | },
43 | {
44 | "id": "c5938bad.c5fa38",
45 | "type": "write timeseries",
46 | "z": "216044f1.bc512c",
47 | "g": "27d9cd3.b828732",
48 | "name": "",
49 | "topic": "",
50 | "topicData": "",
51 | "topicLabel": "",
52 | "assetName": "",
53 | "aspectName": "",
54 | "useMerging": false,
55 | "x": 1160,
56 | "y": 780,
57 | "wires": []
58 | },
59 | {
60 | "id": "ad0608a8.b597a8",
61 | "type": "comment",
62 | "z": "216044f1.bc512c",
63 | "g": "27d9cd3.b828732",
64 | "name": "Parses data from WeatherAPI",
65 | "info": "...just some metrics and forwards to write TS node\n+ temperature\n+ pressure\n+ humidity\n+ wind_speed\n+ wind_direction",
66 | "sticky": 1,
67 | "x": 790,
68 | "y": 900,
69 | "wires": [],
70 | "_type": "node"
71 | },
72 | {
73 | "id": "8ae6a14c.c24fd",
74 | "type": "http request",
75 | "z": "216044f1.bc512c",
76 | "g": "27d9cd3.b828732",
77 | "name": "Get Weather",
78 | "method": "GET",
79 | "ret": "obj",
80 | "url": "https://api.openweathermap.org/data/2.5/weather?q={{CITY}}&appid={{API_KEY}}&units=metric",
81 | "timeout": "",
82 | "mindspherePath": "",
83 | "useMindsphereAuth": false,
84 | "isAdmin": false,
85 | "secretHeaders": "",
86 | "x": 430,
87 | "y": 780,
88 | "wires": [
89 | [
90 | "b50d362b.e41418",
91 | "c0346697.e8ead8"
92 | ]
93 | ],
94 | "_type": "node"
95 | },
96 | {
97 | "id": "ad0dfb26.1fd928",
98 | "type": "inject",
99 | "z": "216044f1.bc512c",
100 | "g": "27d9cd3.b828732",
101 | "name": "Config: CITY & API_KEY",
102 | "topic": "",
103 | "payload": "",
104 | "payloadType": "date",
105 | "repeat": "",
106 | "repeatEnd": "0",
107 | "endTime": "0",
108 | "crontab": "",
109 | "offset": "NaN",
110 | "once": false,
111 | "properties": "[{\"name\":\"CITY\",\"value\":\"Erlangen\"},{\"name\":\"API_KEY\",\"value\":\"\"}]",
112 | "timezone": "utc",
113 | "betweentimesunit": "m",
114 | "showNextExecution": false,
115 | "powerMode": false,
116 | "x": 220,
117 | "y": 780,
118 | "wires": [
119 | [
120 | "8ae6a14c.c24fd"
121 | ]
122 | ],
123 | "_type": "node"
124 | },
125 | {
126 | "id": "b50d362b.e41418",
127 | "type": "debug",
128 | "z": "216044f1.bc512c",
129 | "g": "27d9cd3.b828732",
130 | "name": "",
131 | "active": true,
132 | "console": "false",
133 | "xaxis": "_time",
134 | "complete": "payload",
135 | "x": 670,
136 | "y": 740,
137 | "wires": [],
138 | "_type": "node"
139 | },
140 | {
141 | "id": "99cd1a17.a81548",
142 | "type": "comment",
143 | "z": "216044f1.bc512c",
144 | "g": "27d9cd3.b828732",
145 | "name": "Get weather data from OpenWeather.org // Procedure",
146 | "info": "Double click the City node. Pick a city name for which weather information is available.\nCreate an account in https://openweathermap.org/ for free. \nThen create API Key from https://home.openweathermap.org/api_keys.\nThis example uses Current Weather API documented at: 'https://openweathermap.org/current'.",
147 | "sticky": 1,
148 | "x": 490,
149 | "y": 660,
150 | "wires": [],
151 | "_type": "node"
152 | }
153 | ]
--------------------------------------------------------------------------------
/integrateExternalApi/readme.md:
--------------------------------------------------------------------------------
1 | # Integrate an external API
2 |
3 | Your business case may require to use external services over HTTP. Visual Flow Creator provides a means to consume such services.
4 |
5 | ## Example based on external weather data
6 | The example here demonstrates consuming a service from [OpenWeathermap](https://openweathermap.org) to bring weather information of a city.
7 |
8 | 
9 |
10 | ## Setup & Configuration
11 | 1. Import the flow into Visual Flow Creator.
12 | 2. Obtain the API Key from [OpenWeather](https://home.openweathermap.org/api_keys). This will require a free account to be created, if not already done.
13 | 3. Double click the node named **Config: CITY & API_KEY**.
14 | 4. Replace the value field of `API_KEY` with the newly obtained API KEY from the above URL.
15 | 5. Change the value of the `CITY` field to a city name. The API supports limited set of cities. Please look in to their documentation.
16 | 6. Save the flow after completing the needed changes.
17 | 7. Adopt the processing of the received information based on your needs. The example focuses on the weather details specified in the flow comment.
18 | 8. Click the inject node to trigger the sequence.
19 | 9. Output in the debug window shows the weather data for the chosen city.
20 |
21 | ## How does this flow work
22 |
23 | - The inject node passes the `CITY` and `API_KEY` information to HTTP Request node through `msg` object.
24 | - (**Get Weather**) node is the HTTP Request node and it contains the URL with query parameters.
25 | - This node performs the substitution of variables with the values it receives from the inject node.
26 | - Then HTTP request node fetches the data synchronously from Openweather service endpoint.
27 | - It converts the received response to JSON format and sets it as value for the payload field of the msg object.
28 | - Debug node in the end displays the contents of payload field to the debug window.
29 |
30 | ## Attachements
31 | Here the `API_KEY` can get obtained from the external weather service.
32 | 
33 |
34 |
35 | ## See also
36 | - [OpenWeathermap Website](https://openweathermap.org)
37 |
--------------------------------------------------------------------------------
/sendSmsNotifications/doc/SMS_result.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/sendSmsNotifications/doc/SMS_result.gif
--------------------------------------------------------------------------------
/sendSmsNotifications/doc/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/sendSmsNotifications/doc/example.png
--------------------------------------------------------------------------------
/sendSmsNotifications/doc/sendSmsNotifications.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/sendSmsNotifications/doc/sendSmsNotifications.png
--------------------------------------------------------------------------------
/sendSmsNotifications/readme.md:
--------------------------------------------------------------------------------
1 | # Send SMS Notifications
2 |
3 | This flow allows to send SMS notifications to a mobile phone. The template helps to specify the
4 |
5 | - recipient (name and phone number)
6 | - create template for the SMS
7 | - create notification category to bind recipient and template
8 | - send SMS using category
9 | ... in dedicated flows.
10 |
11 | 
12 |
13 | ## Setup & Configuration
14 |
15 | 1. Import the flow in Visual Flow Creator
16 | 2. Specify the recipient of your notification in the flow *1) Create Recipient* using the function node and trigger it's execution
17 | 3. Set you message content in the function node in flow *4) Send SMS using Category ID*
18 | 4. Save the flow
19 |
20 | :cloud: :heavy_check_mark: You're ready to receive your SMS notifications after all four flows are triggered in sequence 1-4. Enjoy!
21 |
22 | ## How does this flow works
23 |
24 | To send a SMS via Notification Service, a recipient, SMS template and notification category need to be setup before the actual message can be send. See also the Notification Service API descriptions to understand the overall workflow.
25 | During execution of flow 1), the recipient is added and it's ID is stored to a context variable as part of the VFC flow. Next a message template and template-set is created. It's internal IDs are also stored in context variables for usage in flow 3). Here, the notification category is set by linking the template to recipient(s). It feedbacks a category-ID which is then finally used in flow 4) to trigger the sending of the notification. Also the message content is specified in the last flow.
26 |
27 | ## Result
28 |
29 | After specifying recipient (name, phone number) as well as message text,
30 |
31 | 1. Execute flow *1) Create Recipient*
32 | 2. Execute flow *2) Create Template Set for the SMS*
33 | 3. Execute flow *3) Create Category to bind above recipient and template*
34 | 4. Execute flow *4) Send SMS using Category ID*
35 |
36 | And you should receive a SMS on the mobile number specified. :iphone: :bell:
37 |
38 | 
39 |
40 | ## See also
41 |
42 | - [Notification Service – API Overview](https://developer.mindsphere.io/apis/advanced-notification/api-notification-api.html)
43 |
--------------------------------------------------------------------------------
/sendSmsNotifications/sendSmsNotifications.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "6a88a65d.8b89a8",
4 | "type": "combine",
5 | "z": "2896fc68.d71b04",
6 | "name": "",
7 | "triggers": "1,0",
8 | "inputs": 2,
9 | "timeseries": false,
10 | "waitall": false,
11 | "reset": false,
12 | "x": 920,
13 | "y": 1340,
14 | "wires": [
15 | [
16 | "1398c9c7.d951d6"
17 | ]
18 | ]
19 | },
20 | {
21 | "id": "8edfa0c6.dbb2f",
22 | "type": "comment",
23 | "z": "2896fc68.d71b04",
24 | "name": "Send SMS Notifications",
25 | "info": "This template demonstrates how you can send SMS notifications based on a VFC flow. \nIt features a version for Notification Service API in v3 and v4. \n\nSee also: \nhttps://developer.mindsphere.io/apis/advanced-notification/api-notification-api.html\n",
26 | "sticky": 1,
27 | "x": 450,
28 | "y": 760,
29 | "wires": []
30 | },
31 | {
32 | "id": "c3b6e44f.ff6ac8",
33 | "type": "comment",
34 | "z": "2896fc68.d71b04",
35 | "name": "v3",
36 | "info": "adjust accordingly the notification \n- recipient (name and phone numeber)\n- message text",
37 | "sticky": 1,
38 | "x": 290,
39 | "y": 920,
40 | "wires": []
41 | },
42 | {
43 | "id": "78d2a46b.feba1c",
44 | "type": "comment",
45 | "z": "2896fc68.d71b04",
46 | "name": "v4 // PREVIEW ",
47 | "info": "NOT working in VFC at the moment!!\n\nVFC will have needed scope for API endpoint from July 2021 onwards. \nPlease use v3 API version until the release or issue a custom token for usage of this endpoint. ",
48 | "sticky": 1,
49 | "x": 480,
50 | "y": 1920,
51 | "wires": []
52 | },
53 | {
54 | "id": "75a47d9e.0b1ba4",
55 | "type": "comment",
56 | "z": "2896fc68.d71b04",
57 | "name": "adjust here:",
58 | "info": "- name \n- phone number ",
59 | "sticky": 1,
60 | "x": 520,
61 | "y": 1040,
62 | "wires": []
63 | },
64 | {
65 | "id": "5b2f22ad.58cccc",
66 | "type": "comment",
67 | "z": "2896fc68.d71b04",
68 | "name": "adjust here: ",
69 | "info": "- message ",
70 | "sticky": 1,
71 | "x": 734,
72 | "y": 1440,
73 | "wires": []
74 | },
75 | {
76 | "id": "8a50694a.2bf1e8",
77 | "type": "comment",
78 | "z": "2896fc68.d71b04",
79 | "name": "v3 - helper functions",
80 | "info": "",
81 | "sticky": 0,
82 | "x": 270,
83 | "y": 1640,
84 | "wires": []
85 | },
86 | {
87 | "id": "9233ec87.076c",
88 | "type": "debug",
89 | "z": "2896fc68.d71b04",
90 | "name": "ERROR",
91 | "active": true,
92 | "console": "false",
93 | "xaxis": "_time",
94 | "complete": "true",
95 | "x": 1370,
96 | "y": 1520,
97 | "wires": []
98 | },
99 | {
100 | "id": "1b792c07.19d284",
101 | "type": "debug",
102 | "z": "2896fc68.d71b04",
103 | "name": "debug",
104 | "active": true,
105 | "console": "false",
106 | "xaxis": "_time",
107 | "complete": "payload",
108 | "x": 850,
109 | "y": 2000,
110 | "wires": []
111 | },
112 | {
113 | "id": "2fc5c34d.eec90c",
114 | "type": "debug",
115 | "z": "2896fc68.d71b04",
116 | "name": "OK - successfully send SMS",
117 | "active": true,
118 | "console": "false",
119 | "xaxis": "_time",
120 | "complete": "payload",
121 | "x": 1440,
122 | "y": 1480,
123 | "wires": []
124 | },
125 | {
126 | "id": "204286e.6fb6b7a",
127 | "type": "debug",
128 | "z": "2896fc68.d71b04",
129 | "name": "ERROR",
130 | "active": true,
131 | "console": "false",
132 | "xaxis": "_time",
133 | "complete": "true",
134 | "x": 1750,
135 | "y": 1360,
136 | "wires": []
137 | },
138 | {
139 | "id": "47fa92d5.2ee38c",
140 | "type": "debug",
141 | "z": "2896fc68.d71b04",
142 | "name": "ERROR",
143 | "active": true,
144 | "console": "false",
145 | "xaxis": "_time",
146 | "complete": "true",
147 | "x": 1410,
148 | "y": 1260,
149 | "wires": []
150 | },
151 | {
152 | "id": "8605ad88.7065f",
153 | "type": "debug",
154 | "z": "2896fc68.d71b04",
155 | "name": "ERROR",
156 | "active": true,
157 | "console": "false",
158 | "xaxis": "_time",
159 | "complete": "true",
160 | "x": 1150,
161 | "y": 1140,
162 | "wires": []
163 | },
164 | {
165 | "id": "886d393.ea915c8",
166 | "type": "debug",
167 | "z": "2896fc68.d71b04",
168 | "name": "",
169 | "active": true,
170 | "console": "false",
171 | "xaxis": "_time",
172 | "complete": "false",
173 | "x": 830,
174 | "y": 1680,
175 | "wires": []
176 | },
177 | {
178 | "id": "2c72cf46.b7795",
179 | "type": "debug",
180 | "z": "2896fc68.d71b04",
181 | "name": "",
182 | "active": true,
183 | "console": "false",
184 | "xaxis": "_time",
185 | "complete": "false",
186 | "x": 830,
187 | "y": 1720,
188 | "wires": []
189 | },
190 | {
191 | "id": "44ce44c1.2fc67c",
192 | "type": "function",
193 | "z": "2896fc68.d71b04",
194 | "name": "recipient details",
195 | "func": "msg.payload = {\"recipientname\":\"My Recipient Name\",\n \"recipientdetail\":[\n {\"address\":\"+49172xxxxxxxx\",\"addresstypeid\":4}]\n } \n\nreturn msg;",
196 | "outputs": 1,
197 | "language": "javascript",
198 | "noerr": 0,
199 | "x": 520,
200 | "y": 1120,
201 | "wires": [
202 | [
203 | "57029503.2a921c"
204 | ]
205 | ],
206 | "_type": "node"
207 | },
208 | {
209 | "id": "a435f999.6e56a8",
210 | "type": "function",
211 | "z": "2896fc68.d71b04",
212 | "name": "template text",
213 | "func": "msg.payload = `` + \"[[${message}]]\" + ``;\nreturn msg;",
214 | "outputs": 1,
215 | "language": "javascript",
216 | "noerr": 0,
217 | "x": 610,
218 | "y": 1240,
219 | "wires": [
220 | [
221 | "54db3d68.ed0584"
222 | ]
223 | ]
224 | },
225 | {
226 | "id": "54db3d68.ed0584",
227 | "type": "function",
228 | "z": "2896fc68.d71b04",
229 | "name": "create multipart content",
230 | "func": "var pl = msg.payload\nnode.warn(pl)\n\nmsg.headers = {\n \"Content-Type\": \"multipart/form-data; boundary=------------------------d74496d66958873e\"\n}\n\nmsg.payload = '--------------------------d74496d66958873e\\r\\n'+\n'Content-Disposition: form-data; name=\"templateInfo\"\\r\\n'+\n'\\r\\n'+'{\"templateParam\": [{\"paramName\": \"Name\",\"defaultValue\": \"Mindsphere User\",\"placeHolderName\": \"name\",\"paramTypeId\": 4}],\"templatesetName\": \"TemplateForSMS\",\"templateChannelAndFile\": [{\"communicationChannel\": 2,\"fileName\": \"SMS.html\"}]}\\r\\n'+\n'--------------------------d74496d66958873e\\r\\n'+\n'Content-Disposition: form-data; name=\"templateFiles\"; filename=\"SMS.html\"\\r\\n'+\n'Content-Type: application/octet-stream\\r\\n'+\n'\\r\\n'+\nmsg.payload+'\\r\\n'+\n'--------------------------d74496d66958873e--\\r\\n';\n\nreturn msg;",
231 | "outputs": 1,
232 | "language": "javascript",
233 | "noerr": 0,
234 | "x": 810,
235 | "y": 1240,
236 | "wires": [
237 | [
238 | "920d1743.c3bef8"
239 | ]
240 | ]
241 | },
242 | {
243 | "id": "1398c9c7.d951d6",
244 | "type": "function",
245 | "z": "2896fc68.d71b04",
246 | "name": "category details",
247 | "func": "var recipientId = msg.payload[0]\nvar templateData = JSON.parse(msg.payload[1])\nvar templatesetId = templateData.templatesetId\nvar templateId = templateData.templateList[0].templateId\n\n\nmsg.payload = {\n \"msgCategoryName\" : \"My Category for SMS\",\n \"recipients\" : [ {\n \"recipientId\" : recipientId\n } ],\n \"templates\" : [ {\n \"templateId\" : templateId,\n \"commChannelName\" : \"SMS\",\n \"templatesetId\" : templatesetId\n } ]\n}\nreturn msg;",
248 | "outputs": 1,
249 | "language": "javascript",
250 | "noerr": 0,
251 | "x": 1080,
252 | "y": 1340,
253 | "wires": [
254 | [
255 | "bf9596f5.755688",
256 | "1717b633.3567ca"
257 | ]
258 | ],
259 | "_type": "node"
260 | },
261 | {
262 | "id": "b2e749eb.965678",
263 | "type": "function",
264 | "z": "2896fc68.d71b04",
265 | "name": "message details",
266 | "func": "var messageCategoryId = msg.payload;\n\nvar message = \"Hello MindSphere User!\\nYou have successfully setup your first SMS Notification via Visual Flow Creator\\n\\nYour MindSphere Team\";\n\nmsg.payload = {\n \"body\":{\"message\": message },\n \"messageCategoryId\": messageCategoryId\n}\n\nreturn msg;",
267 | "outputs": 1,
268 | "language": "javascript",
269 | "noerr": 0,
270 | "x": 740,
271 | "y": 1500,
272 | "wires": [
273 | [
274 | "5c34a0e3.fc3ac"
275 | ]
276 | ],
277 | "_type": "node"
278 | },
279 | {
280 | "id": "64a57d8c.50b4e4",
281 | "type": "function",
282 | "z": "2896fc68.d71b04",
283 | "name": "setup SMS text and recipients",
284 | "func": "msg.payload = {\n \"message\": \"Monthly machine data analysis completed.\",\n \"recipients\": [\n \"+491722189537\"],\n \"fromApplication\": \"string\"\n}\n\nreturn msg;",
285 | "outputs": 1,
286 | "language": "javascript",
287 | "noerr": 0,
288 | "x": 480,
289 | "y": 2000,
290 | "wires": [
291 | [
292 | "edbfa61c.5003e8"
293 | ]
294 | ]
295 | },
296 | {
297 | "id": "57029503.2a921c",
298 | "type": "http request",
299 | "z": "2896fc68.d71b04",
300 | "name": "/recipient",
301 | "method": "POST",
302 | "ret": "txt",
303 | "url": "",
304 | "timeout": "",
305 | "mindspherePath": "/api/notification/v3/recipient/",
306 | "useMindsphereAuth": true,
307 | "isAdmin": false,
308 | "secretHeaders": "",
309 | "x": 700,
310 | "y": 1120,
311 | "wires": [
312 | [
313 | "5493159a.4ec50c"
314 | ]
315 | ]
316 | },
317 | {
318 | "id": "920d1743.c3bef8",
319 | "type": "http request",
320 | "z": "2896fc68.d71b04",
321 | "name": "/template",
322 | "method": "POST",
323 | "ret": "txt",
324 | "url": "",
325 | "timeout": "",
326 | "mindspherePath": "/api/notification/v3/template/",
327 | "useMindsphereAuth": true,
328 | "isAdmin": false,
329 | "secretHeaders": "",
330 | "x": 1000,
331 | "y": 1240,
332 | "wires": [
333 | [
334 | "56d8bee3.b1ba3"
335 | ]
336 | ]
337 | },
338 | {
339 | "id": "bf9596f5.755688",
340 | "type": "http request",
341 | "z": "2896fc68.d71b04",
342 | "name": "/communicationcategories",
343 | "method": "POST",
344 | "ret": "txt",
345 | "url": "",
346 | "timeout": "",
347 | "mindspherePath": "/api/notification/v3/communicationcategories/",
348 | "useMindsphereAuth": true,
349 | "isAdmin": false,
350 | "secretHeaders": "",
351 | "x": 1310,
352 | "y": 1340,
353 | "wires": [
354 | [
355 | "ce9a4b59.ce8808"
356 | ]
357 | ]
358 | },
359 | {
360 | "id": "5c34a0e3.fc3ac",
361 | "type": "http request",
362 | "z": "2896fc68.d71b04",
363 | "name": "/publisher/messages",
364 | "method": "POST",
365 | "ret": "txt",
366 | "url": "",
367 | "timeout": "",
368 | "mindspherePath": "/api/notification/v3/publisher/messages",
369 | "useMindsphereAuth": true,
370 | "isAdmin": false,
371 | "secretHeaders": "",
372 | "x": 940,
373 | "y": 1500,
374 | "wires": [
375 | [
376 | "e9c6af5f.9c28e"
377 | ]
378 | ]
379 | },
380 | {
381 | "id": "edbfa61c.5003e8",
382 | "type": "http request",
383 | "z": "2896fc68.d71b04",
384 | "name": "send SMS",
385 | "method": "POST",
386 | "ret": "txt",
387 | "url": "",
388 | "timeout": "",
389 | "mindspherePath": "/api/notification/v4/multicastSMSNotificationJobs",
390 | "useMindsphereAuth": true,
391 | "isAdmin": false,
392 | "secretHeaders": "",
393 | "x": 700,
394 | "y": 2000,
395 | "wires": [
396 | [
397 | "1b792c07.19d284"
398 | ]
399 | ]
400 | },
401 | {
402 | "id": "d986bcd0.423ee",
403 | "type": "http request",
404 | "z": "2896fc68.d71b04",
405 | "name": "/communicationcategories",
406 | "method": "GET",
407 | "ret": "txt",
408 | "url": "",
409 | "timeout": "",
410 | "mindspherePath": "/api/notification/v3/communicationcategories/",
411 | "useMindsphereAuth": true,
412 | "isAdmin": false,
413 | "secretHeaders": "",
414 | "x": 610,
415 | "y": 1680,
416 | "wires": [
417 | [
418 | "886d393.ea915c8"
419 | ]
420 | ]
421 | },
422 | {
423 | "id": "dc80add1.96d9b",
424 | "type": "http request",
425 | "z": "2896fc68.d71b04",
426 | "name": "/template/templatelistdetails",
427 | "method": "GET",
428 | "ret": "txt",
429 | "url": "",
430 | "timeout": "",
431 | "mindspherePath": "/api/notification/v3/template/templatelistdetails",
432 | "useMindsphereAuth": true,
433 | "isAdmin": false,
434 | "x": 620,
435 | "y": 1720,
436 | "wires": [
437 | [
438 | "2c72cf46.b7795"
439 | ]
440 | ]
441 | },
442 | {
443 | "id": "599964b9.e554ac",
444 | "type": "inject",
445 | "z": "2896fc68.d71b04",
446 | "name": "1) Create Recipient",
447 | "topic": "",
448 | "payload": "",
449 | "payloadType": "date",
450 | "repeat": "",
451 | "repeatEnd": "0",
452 | "endTime": "0",
453 | "crontab": "",
454 | "offset": "NaN",
455 | "once": false,
456 | "properties": "",
457 | "timezone": "utc",
458 | "betweentimesunit": "m",
459 | "enableRuleEngine": false,
460 | "showNextExecution": false,
461 | "powerMode": false,
462 | "x": 310,
463 | "y": 1120,
464 | "wires": [
465 | [
466 | "44ce44c1.2fc67c"
467 | ]
468 | ]
469 | },
470 | {
471 | "id": "77da41e6.0fb9e",
472 | "type": "inject",
473 | "z": "2896fc68.d71b04",
474 | "name": "2) Create Template Set for the SMS",
475 | "topic": "",
476 | "payload": "",
477 | "payloadType": "date",
478 | "repeat": "",
479 | "repeatEnd": "0",
480 | "endTime": "0",
481 | "crontab": "",
482 | "offset": "NaN",
483 | "once": false,
484 | "properties": "",
485 | "timezone": "utc",
486 | "betweentimesunit": "m",
487 | "enableRuleEngine": false,
488 | "showNextExecution": false,
489 | "powerMode": false,
490 | "x": 340,
491 | "y": 1240,
492 | "wires": [
493 | [
494 | "a435f999.6e56a8"
495 | ]
496 | ]
497 | },
498 | {
499 | "id": "97205f73.2fb9c",
500 | "type": "inject",
501 | "z": "2896fc68.d71b04",
502 | "name": "3) Create Category to bind above recipient and template",
503 | "topic": "",
504 | "payload": "",
505 | "payloadType": "date",
506 | "repeat": "",
507 | "repeatEnd": "0",
508 | "endTime": "0",
509 | "crontab": "",
510 | "offset": "NaN",
511 | "once": false,
512 | "properties": "",
513 | "timezone": "utc",
514 | "betweentimesunit": "m",
515 | "enableRuleEngine": false,
516 | "showNextExecution": false,
517 | "powerMode": false,
518 | "x": 400,
519 | "y": 1340,
520 | "wires": [
521 | [
522 | "3a6c466a.7279ea",
523 | "5a7e49eb.4de7a8"
524 | ]
525 | ]
526 | },
527 | {
528 | "id": "57231cc.0b4bce4",
529 | "type": "inject",
530 | "z": "2896fc68.d71b04",
531 | "name": "4) Send SMS using Category ID",
532 | "topic": "",
533 | "payload": "",
534 | "payloadType": "date",
535 | "repeat": "",
536 | "repeatEnd": "0",
537 | "endTime": "0",
538 | "crontab": "",
539 | "offset": "NaN",
540 | "once": false,
541 | "properties": "",
542 | "timezone": "utc",
543 | "betweentimesunit": "m",
544 | "enableRuleEngine": false,
545 | "showNextExecution": false,
546 | "powerMode": false,
547 | "x": 320,
548 | "y": 1500,
549 | "wires": [
550 | [
551 | "532a9067.1e356"
552 | ]
553 | ]
554 | },
555 | {
556 | "id": "7e54f7d8.8f4b98",
557 | "type": "inject",
558 | "z": "2896fc68.d71b04",
559 | "name": "trigger SMS sending",
560 | "topic": "",
561 | "payload": "",
562 | "payloadType": "date",
563 | "repeat": "",
564 | "repeatEnd": "0",
565 | "endTime": "0",
566 | "crontab": "",
567 | "offset": "NaN",
568 | "once": false,
569 | "properties": "",
570 | "timezone": "utc",
571 | "betweentimesunit": "m",
572 | "enableRuleEngine": false,
573 | "showNextExecution": false,
574 | "powerMode": false,
575 | "x": 230,
576 | "y": 2000,
577 | "wires": [
578 | [
579 | "64a57d8c.50b4e4"
580 | ]
581 | ]
582 | },
583 | {
584 | "id": "917c4dd5.23f04",
585 | "type": "inject",
586 | "z": "2896fc68.d71b04",
587 | "name": "set recipientId manually",
588 | "topic": "",
589 | "payload": "10678",
590 | "payloadType": "num",
591 | "repeat": "",
592 | "repeatEnd": "0",
593 | "endTime": "0",
594 | "crontab": "",
595 | "offset": "NaN",
596 | "once": false,
597 | "properties": "",
598 | "timezone": "utc",
599 | "betweentimesunit": "m",
600 | "enableRuleEngine": false,
601 | "showNextExecution": false,
602 | "powerMode": false,
603 | "x": 940,
604 | "y": 1080,
605 | "wires": [
606 | [
607 | "5b551ea4.a832"
608 | ]
609 | ]
610 | },
611 | {
612 | "id": "7d690d25.061824",
613 | "type": "inject",
614 | "z": "2896fc68.d71b04",
615 | "name": "GET all communication categories",
616 | "topic": "",
617 | "payload": "",
618 | "payloadType": "date",
619 | "repeat": "",
620 | "repeatEnd": "0",
621 | "endTime": "0",
622 | "crontab": "",
623 | "offset": "NaN",
624 | "once": false,
625 | "properties": "",
626 | "timezone": "utc",
627 | "betweentimesunit": "m",
628 | "enableRuleEngine": false,
629 | "showNextExecution": false,
630 | "powerMode": false,
631 | "x": 350,
632 | "y": 1680,
633 | "wires": [
634 | [
635 | "d986bcd0.423ee"
636 | ]
637 | ]
638 | },
639 | {
640 | "id": "9bfc58f0.36dfb8",
641 | "type": "inject",
642 | "z": "2896fc68.d71b04",
643 | "name": "set templateSetId manually",
644 | "topic": "",
645 | "payload": "{\"templatesetId\":1813,\"templatesetName\":\"svwtemplate\",\"templateList\":[{\"templateId\":2413,\"commChannelId\":2,\"commChannelName\":\"SMS\"}]}",
646 | "payloadType": "str",
647 | "repeat": "",
648 | "repeatEnd": "0",
649 | "endTime": "0",
650 | "crontab": "",
651 | "offset": "NaN",
652 | "once": false,
653 | "properties": "",
654 | "timezone": "utc",
655 | "betweentimesunit": "m",
656 | "enableRuleEngine": false,
657 | "showNextExecution": false,
658 | "powerMode": false,
659 | "x": 1210,
660 | "y": 1200,
661 | "wires": [
662 | [
663 | "cd963f8c.05d48"
664 | ]
665 | ]
666 | },
667 | {
668 | "id": "95466ae8.115218",
669 | "type": "inject",
670 | "z": "2896fc68.d71b04",
671 | "name": "GET all templates",
672 | "topic": "",
673 | "payload": "",
674 | "payloadType": "date",
675 | "repeat": "",
676 | "repeatEnd": "0",
677 | "endTime": "0",
678 | "crontab": "",
679 | "offset": "NaN",
680 | "once": false,
681 | "properties": "",
682 | "timezone": "utc",
683 | "betweentimesunit": "m",
684 | "enableRuleEngine": false,
685 | "showNextExecution": false,
686 | "powerMode": false,
687 | "x": 296.17808532714844,
688 | "y": 1725.003890991211,
689 | "wires": [
690 | [
691 | "dc80add1.96d9b"
692 | ]
693 | ]
694 | },
695 | {
696 | "id": "3a6c466a.7279ea",
697 | "type": "read-context",
698 | "z": "2896fc68.d71b04",
699 | "name": "recipientId",
700 | "key": "recipientId",
701 | "context": "flow",
702 | "x": 730,
703 | "y": 1320,
704 | "wires": [
705 | [
706 | "6a88a65d.8b89a8"
707 | ]
708 | ],
709 | "_type": "node"
710 | },
711 | {
712 | "id": "5a7e49eb.4de7a8",
713 | "type": "read-context",
714 | "z": "2896fc68.d71b04",
715 | "name": "templateSetId",
716 | "key": "templateSetId",
717 | "context": "flow",
718 | "x": 740,
719 | "y": 1360,
720 | "wires": [
721 | [
722 | "6a88a65d.8b89a8:1"
723 | ]
724 | ]
725 | },
726 | {
727 | "id": "532a9067.1e356",
728 | "type": "read-context",
729 | "z": "2896fc68.d71b04",
730 | "name": "messageCategoryId",
731 | "key": "messageCategoryId",
732 | "context": "flow",
733 | "x": 550,
734 | "y": 1500,
735 | "wires": [
736 | [
737 | "b2e749eb.965678"
738 | ]
739 | ],
740 | "_type": "node"
741 | },
742 | {
743 | "id": "5b551ea4.a832",
744 | "type": "store-context",
745 | "z": "2896fc68.d71b04",
746 | "name": "recipientId",
747 | "key": "recipientId",
748 | "context": "flow",
749 | "ttl": 15811200,
750 | "x": 1170,
751 | "y": 1100,
752 | "wires": []
753 | },
754 | {
755 | "id": "cd963f8c.05d48",
756 | "type": "store-context",
757 | "z": "2896fc68.d71b04",
758 | "name": "templateSetId",
759 | "key": "templateSetId",
760 | "context": "flow",
761 | "ttl": 15811200,
762 | "x": 1440,
763 | "y": 1220,
764 | "wires": []
765 | },
766 | {
767 | "id": "8b92443b.16ca38",
768 | "type": "store-context",
769 | "z": "2896fc68.d71b04",
770 | "name": "messageCategoryId",
771 | "key": "messageCategoryId",
772 | "context": "flow",
773 | "ttl": 15811200,
774 | "x": 1790,
775 | "y": 1320,
776 | "wires": []
777 | },
778 | {
779 | "id": "e9c6af5f.9c28e",
780 | "type": "switch",
781 | "z": "2896fc68.d71b04",
782 | "name": "check status code",
783 | "property": "statusCode",
784 | "propertyType": "msg",
785 | "rules": [
786 | {
787 | "t": "eq",
788 | "v": "204",
789 | "vt": "str"
790 | },
791 | {
792 | "t": "else"
793 | }
794 | ],
795 | "checkall": "true",
796 | "outputs": 2,
797 | "x": 1170,
798 | "y": 1500,
799 | "wires": [
800 | [
801 | "2fc5c34d.eec90c"
802 | ],
803 | [
804 | "9233ec87.076c"
805 | ]
806 | ]
807 | },
808 | {
809 | "id": "ce9a4b59.ce8808",
810 | "type": "switch",
811 | "z": "2896fc68.d71b04",
812 | "name": "check status code (201)",
813 | "property": "statusCode",
814 | "propertyType": "msg",
815 | "rules": [
816 | {
817 | "t": "eq",
818 | "v": "201",
819 | "vt": "str"
820 | },
821 | {
822 | "t": "else"
823 | }
824 | ],
825 | "checkall": "true",
826 | "outputs": 2,
827 | "x": 1550,
828 | "y": 1340,
829 | "wires": [
830 | [
831 | "8b92443b.16ca38"
832 | ],
833 | [
834 | "204286e.6fb6b7a"
835 | ]
836 | ]
837 | },
838 | {
839 | "id": "56d8bee3.b1ba3",
840 | "type": "switch",
841 | "z": "2896fc68.d71b04",
842 | "name": "check status code (201)",
843 | "property": "statusCode",
844 | "propertyType": "msg",
845 | "rules": [
846 | {
847 | "t": "eq",
848 | "v": "201",
849 | "vt": "str"
850 | },
851 | {
852 | "t": "else"
853 | }
854 | ],
855 | "checkall": "true",
856 | "outputs": 2,
857 | "x": 1210,
858 | "y": 1240,
859 | "wires": [
860 | [
861 | "cd963f8c.05d48"
862 | ],
863 | [
864 | "47fa92d5.2ee38c"
865 | ]
866 | ]
867 | },
868 | {
869 | "id": "5493159a.4ec50c",
870 | "type": "switch",
871 | "z": "2896fc68.d71b04",
872 | "name": "check status code (201)",
873 | "property": "statusCode",
874 | "propertyType": "msg",
875 | "rules": [
876 | {
877 | "t": "eq",
878 | "v": "201",
879 | "vt": "str"
880 | },
881 | {
882 | "t": "else"
883 | }
884 | ],
885 | "checkall": "true",
886 | "outputs": 2,
887 | "x": 930,
888 | "y": 1120,
889 | "wires": [
890 | [
891 | "5b551ea4.a832"
892 | ],
893 | [
894 | "8605ad88.7065f"
895 | ]
896 | ],
897 | "_type": "node"
898 | },
899 | {
900 | "id": "1717b633.3567ca",
901 | "type": "debug",
902 | "z": "2896fc68.d71b04",
903 | "name": "",
904 | "active": true,
905 | "console": "false",
906 | "xaxis": "_time",
907 | "complete": "false",
908 | "x": 1335,
909 | "y": 1403,
910 | "wires": []
911 | }
912 | ]
--------------------------------------------------------------------------------
/templateFlow.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/templateFlow.zip
--------------------------------------------------------------------------------
/virtualMachineSimulator/IMPORT_virtualMachineSimulator.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "3cdca25b.29cf1e",
4 | "type": "comment",
5 | "z": "46afa01f.016bd",
6 | "name": "Virtual Machine Simulation",
7 | "info": "- generate some simulation data for a virtual machine ",
8 | "sticky": 1,
9 | "x": 340,
10 | "y": 160,
11 | "wires": []
12 | },
13 | {
14 | "id": "e885fa0.0bc2508",
15 | "type": "function",
16 | "z": "46afa01f.016bd",
17 | "name": "simulate virtual machine",
18 | "func": "var totalProductCounter = 150;\nvar random = Math.floor(Math.random() * 101);\nvar StateMsg = {payload : {}};\nvar CounterMsg = {payload : {}};\n\nvar prevTotalCounter = context.get('prevTotalCounter') || 0;\nvar prevGoodCounter = context.get('prevGoodCounter') || 0;\nvar prevBadCounter = context.get('prevBadCounter') || 0;\n\n//reset product counter \nif(prevTotalCounter > totalProductCounter) {\n prevTotalCounter = 0;\n prevGoodCounter = 0;\n prevBadCounter = 0;\n}\n\n\nStateMsg.payload = {\n \"Available\" : \"false\",\n \"E_Stop\" : \"false\",\n \"Fault\" : \"false\",\n \"Power_Off\" : \"false\",\n \"State\" : \"-1\",\n};\n\nif(random < 90) {\n StateMsg.payload.Available = true; \n StateMsg.payload.State = 1;\n}\nelse if(random == 90) {\n StateMsg.payload.Power_Off = true; \n StateMsg.payload.State = 3;\n}\nelse if(random <= 95) {\n StateMsg.payload.Fault = true;\n StateMsg.payload.State = 2;\n}\nelse {\n StateMsg.payload.E_Stop = true; \n StateMsg.payload.State = 4;\n}\n\n\nif(StateMsg.payload.Available === true) {\n var produced = Math.ceil(Math.random() * 6);\n prevTotalCounter += produced;\n if(random <= 5) {\n prevBadCounter += produced;\n }\n else {\n prevGoodCounter += produced;\n }\n}\n\nCounterMsg.payload = {\n \"Product_Counter\" : prevTotalCounter,\n \"Good_Counter\" : prevGoodCounter,\n \"Bad_Counter\" : prevBadCounter,\n};\n\ncontext.set('prevTotalCounter', prevTotalCounter);\ncontext.set('prevGoodCounter', prevGoodCounter);\ncontext.set('prevBadCounter', prevBadCounter);\n\nreturn [StateMsg, CounterMsg];",
19 | "outputs": "2",
20 | "noerr": 0,
21 | "x": 480,
22 | "y": 240,
23 | "wires": [
24 | [
25 | "5dd5301c.bdae6"
26 | ],
27 | [
28 | "25167cbb.7c60a4"
29 | ]
30 | ],
31 | "_type": "node"
32 | },
33 | {
34 | "id": "76cea489.bdb21c",
35 | "type": "inject",
36 | "z": "46afa01f.016bd",
37 | "name": "every 5s",
38 | "topic": "",
39 | "payload": "",
40 | "payloadType": "date",
41 | "repeat": "10",
42 | "repeatEnd": "0",
43 | "endTime": "0",
44 | "crontab": "",
45 | "once": false,
46 | "properties": "",
47 | "timezone": "utc",
48 | "betweentimesunit": "m",
49 | "enableRuleEngine": false,
50 | "showNextExecution": false,
51 | "x": 220,
52 | "y": 240,
53 | "wires": [
54 | [
55 | "e885fa0.0bc2508"
56 | ]
57 | ]
58 | },
59 | {
60 | "id": "25167cbb.7c60a4",
61 | "type": "write timeseries",
62 | "z": "46afa01f.016bd",
63 | "name": "Virtual Machine - Counter",
64 | "topic": "/Simulation_Counter",
65 | "topicLabel": "Virtual Machine/Simulation_Counter",
66 | "assetName": "Virtual Machine",
67 | "x": 770,
68 | "y": 260,
69 | "wires": [],
70 | "_type": "node"
71 | },
72 | {
73 | "id": "5dd5301c.bdae6",
74 | "type": "write timeseries",
75 | "z": "46afa01f.016bd",
76 | "name": "Virtual Machine - States",
77 | "topic": "/Simulation_States",
78 | "topicLabel": "Virtual Machine/Simulation_States",
79 | "assetName": "Virtual Machine",
80 | "x": 770,
81 | "y": 220,
82 | "wires": [],
83 | "_type": "node"
84 | }
85 | ]
--------------------------------------------------------------------------------
/virtualMachineSimulator/doc/Asset_Manager_AssetInstance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/virtualMachineSimulator/doc/Asset_Manager_AssetInstance.png
--------------------------------------------------------------------------------
/virtualMachineSimulator/doc/Asset_Manager_AssetType_virtualMachine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/virtualMachineSimulator/doc/Asset_Manager_AssetType_virtualMachine.png
--------------------------------------------------------------------------------
/virtualMachineSimulator/doc/Asset_Manager_Import_Aspect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/virtualMachineSimulator/doc/Asset_Manager_Import_Aspect.png
--------------------------------------------------------------------------------
/virtualMachineSimulator/doc/FleetManager_Results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/virtualMachineSimulator/doc/FleetManager_Results.png
--------------------------------------------------------------------------------
/virtualMachineSimulator/doc/VFC_setup_Asset-Aspect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/virtualMachineSimulator/doc/VFC_setup_Asset-Aspect.png
--------------------------------------------------------------------------------
/virtualMachineSimulator/doc/virtualMachineSimulator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/virtualMachineSimulator/doc/virtualMachineSimulator.png
--------------------------------------------------------------------------------
/virtualMachineSimulator/readme.md:
--------------------------------------------------------------------------------
1 | # Example Name
2 | Using this flow, you can generate virtual machine data consisting of both a simulation for
3 | - machine states
4 | - product counter
5 |
6 | It can be used if no physical assets are available or to learn about the features on Insights Hub to explore VFC and other apps using the data stored in the Asset Management. The data generated can also be used further to calculate the machine OEE, Availability or Quality of the virtual products produced.
7 |
8 | 
9 |
10 | ## Prerequisites
11 | - access to Asset-Management
12 |
13 | ## Setup & Configuration
14 | ### Setup machine asset
15 | 1. Open Asset Manager
16 | 2. Create a new *Aspect* named `machine_states` using the .csv files found in the src folder. To import the data model for the machine, choose "Import variables" and select the csv files accordingly.
17 | 
18 | 3. Create a second new *Aspect* named `product_counter` using the same logic
19 | 4. Create a new *Asset-Type* named `virtual machine` and assign the two just created *Aspects* to it. Your data model for the machine should then look as follow
20 | 
21 | 5. Create a asset instance of the just defined *Asset-Type* using a asset name of choice
22 | e.g. `my virtual machine`
23 | 
24 |
25 | ### Setup in Visual Flow Creator
26 | 1. Import the flow in Visual Flow Creator
27 | 2. Open the settings for the **upper** write-timeseries node select the previously generated asset instance `my virtual machine` and aspect `machine_states`. Do not select any variables.
28 | 
29 | 4. Repeat this for the **lower** write-timeseries node and select `my virtual machine` -> `product_counter`. Do not select any variables.
30 | 5. Adjust the execution interval for the simulation as desired in the link-in node.
31 | 6. Save the flow
32 |
33 | :cloud: :heavy_check_mark: You're done, your machine simulation is now running - enjoy!
34 |
35 |
36 | ## Result
37 | After saving the flow, the output of the simulation is written to the asset and you can monitor the results e.g. in Insights Hub Monitor. Based on this you can also now start calculating the machine KPIs (OEE, Availability, Quality, ...) using the VFC or other apps.
38 | 
39 |
40 | ## See also
41 | - [Asset Manager Documentation](https://documentation.mindsphere.io/resources/html/asset-manager/en-US/index.html)
42 |
--------------------------------------------------------------------------------
/virtualMachineSimulator/src/Aspect_machine-states.csv:
--------------------------------------------------------------------------------
1 | "Available";"BOOLEAN";"1";""
2 | "E_Stop";"BOOLEAN";"1";""
3 | "Error_Code";"INT";"1";""
4 | "Fault";"BOOLEAN";"1";""
5 | "Messages";"BIG_STRING";"1";"50000"
6 | "NotifierAlarm";"BOOLEAN";"1";""
7 | "Power_Off";"BOOLEAN";"1";""
8 | "State";"INT";"1";""
--------------------------------------------------------------------------------
/virtualMachineSimulator/src/Aspect_product_counter.csv:
--------------------------------------------------------------------------------
1 | "Bad_Counter";"INT";"pcs";""
2 | "Good_Counter";"INT";"pcs";""
3 | "Product_Counter";"INT";"pcs";""
--------------------------------------------------------------------------------
/x_templateFlow/doc/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mindsphere/vfc-examples/26608a081413557453432fd320205c949a99cb87/x_templateFlow/doc/example.png
--------------------------------------------------------------------------------
/x_templateFlow/readme.md:
--------------------------------------------------------------------------------
1 | # HEADING for vfc-application example
2 |
3 |
4 |
5 |
6 |
7 |
8 | ## Prerequisites
9 |
10 |
11 | ## Setup & Configuration
12 |
13 |
14 | 1. Import the flow in Visual Flow Creator using the [Flow Tempalte](template.json)
15 | 2. ...
16 |
17 | 3. Save the flow
18 |
19 | :cloud: :heavy_check_mark: You're ready ... - enjoy!
20 |
21 |
22 | ## How does this flow works
23 |
24 |
25 | ## Result
26 |
27 |
28 | ## See also
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/x_templateFlow/template.json:
--------------------------------------------------------------------------------
1 | // insert your exported json here
2 | // ensure that it does not contain any private data like
3 | // - e-mail addresses
4 | // - tenant or asset names
--------------------------------------------------------------------------------