├── .gitignore ├── README.md ├── data └── demo-models.json ├── dictionary.json ├── index.html ├── package.json ├── res ├── hopscotch.css ├── img │ ├── sprite-green.png │ └── sprite-orange.png └── tour.css ├── rover.js ├── scripts ├── demo-objects.js ├── demo-time-conductor.js ├── demo-tour.js ├── scaled-image.js └── tour.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.swp 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open MCT Live Demo 2 | 3 | __NOTE__: This demo is available online at https://openmct-demo.herokuapp.com. This guide is intended for those wishing to setup and run the Open MCT demo locally. 4 | 5 | ## Dependencies 6 | The Open MCT demo depends on [node.js](https://nodejs.org/en/). Life is also easier with [git](https://git-scm.com/downloads), but it's not a requirement for installing and running the demo. 7 | 8 | ## Setup and Installation 9 | Either download or clone the `openmct-demo` repository. Git is the preferred way of working with the Open MCT Demo repository, but it's not a requirement to get the demo running. If you're using git, the steps necessary to download and install the Open MCT demo are included below 10 | 11 | ``` 12 | git clone https://github.com/nasa/openmct-demo.git 13 | cd openmct-demo 14 | npm install 15 | npm start 16 | ``` 17 | 18 | If you're not using git, you can download a [zip of the repository](https://github.com/nasa/openmct-demo/archive/master.zip) and after unzipping it and switching to the directory it was unzipped to, run `npm install` and `npm start`. 19 | 20 | ## Overview 21 | This is a functional demo of the [Open MCT](https://github.com/nasa/openmct) mission operations framework using a combination of real and mock data. The real data is historical weather data taken from the REMS instrument on the Curiosity rover, which is kindly made available via a web service provided by the Centro de Astrobiología of the Spanish National Research Council, to whom we are eternally grateful http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php 22 | 23 | ## Dependency on Open MCT Tutorials 24 | This demo depends on the [Open MCT Tutorial](https://github.com/nasa/openmct-tutorial) project. The demo reuses the realtime and historical servers and their associated adapters, but uses a customized dictionary and spacecraft object. This dependency should be considered when making significant code changes to the tutorials. 25 | -------------------------------------------------------------------------------- /data/demo-models.json: -------------------------------------------------------------------------------- 1 | { 2 | "demo:f3744144-8842-4b7a-bddc-4abbf21315d9": { 3 | "composition": ["demo:79b89853-6947-4516-8d8c-bfe239c83836", "demo:02d98e70-792e-4de9-9b1e-9b36685bff29", "msl_tlm:pressure", "demo:6b2c3426-6d35-42ad-8720-95543567241f", "demo:11247663-fad1-481a-93d8-429ba159bf6b"], 4 | "name": "Mars Weather Display Layout", 5 | "type": "layout", 6 | "configuration": { 7 | "layout": { 8 | "panels": { 9 | "msl_tlm:min_temp": { 10 | "position": [0, 0], 11 | "dimensions": [12, 8] 12 | }, 13 | "msl_tlm:max_temp": { 14 | "position": [12, 0], 15 | "dimensions": [12, 8] 16 | }, 17 | "msl_tlm:min_gts_temp": { 18 | "position": [0, 8], 19 | "dimensions": [12, 8] 20 | }, 21 | "msl_tlm:max_gts_temp": { 22 | "position": [12, 8], 23 | "dimensions": [12, 8] 24 | }, 25 | "demo:9b297044-84be-4814-9400-cbe2d4e72589": { 26 | "position": [24, 9], 27 | "dimensions": [24, 9] 28 | }, 29 | "demo:79b89853-6947-4516-8d8c-bfe239c83836": { 30 | "position": [0, 0], 31 | "dimensions": [14, 8] 32 | }, 33 | "demo:02d98e70-792e-4de9-9b1e-9b36685bff29": { 34 | "position": [0, 8], 35 | "dimensions": [14, 8] 36 | }, 37 | "demo:b66be4e2-b918-42d2-ad0a-f70c7a6f4102": { 38 | "position": [24, 10], 39 | "dimensions": [12, 8] 40 | }, 41 | "msl_tlm:pressure": { 42 | "position": [0, 16], 43 | "dimensions": [14, 8] 44 | }, 45 | "demo:e2f57978-dcae-4fe2-a637-4707929286ae": { 46 | "position": [24, 0], 47 | "dimensions": [24, 9] 48 | }, 49 | "demo:6b2c3426-6d35-42ad-8720-95543567241f": { 50 | "position": [14, 16], 51 | "dimensions": [20, 8] 52 | }, 53 | "demo:11247663-fad1-481a-93d8-429ba159bf6b": { 54 | "position": [14, 0], 55 | "dimensions": [20, 16] 56 | } 57 | } 58 | } 59 | }, 60 | "modified": 1461720385628, 61 | "location": "demo:demo-objects", 62 | "persisted": 1461720385628 63 | }, 64 | "demo:79b89853-6947-4516-8d8c-bfe239c83836": { 65 | "composition": [ 66 | "msl_tlm:min_temp", 67 | "msl_tlm:max_temp" 68 | ], 69 | "name": "Air Temperature", 70 | "type": "telemetry.panel", 71 | "modified": 1459888924618, 72 | "location": "demo:f3744144-8842-4b7a-bddc-4abbf21315d9", 73 | "persisted": 1459888924618 74 | }, 75 | "demo:02d98e70-792e-4de9-9b1e-9b36685bff29": { 76 | "composition": [ 77 | "msl_tlm:min_gts_temp", 78 | "msl_tlm:max_gts_temp" 79 | ], 80 | "name": "Ground Temperature", 81 | "type": "telemetry.panel", 82 | "modified": 1459888918032, 83 | "location": "demo:f3744144-8842-4b7a-bddc-4abbf21315d9", 84 | "persisted": 1459888918032 85 | }, 86 | "demo:be3d5df3-cc6e-4b8b-9865-fcd844e55b94": { 87 | "composition": [ 88 | "demo:64b43121-ae85-490e-81ce-ebea885b3515", 89 | "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 90 | "demo:329bf4c5-2f1a-4ce6-9a4d-18610c145f44" 91 | ], 92 | "name": "Rover Subsystems", 93 | "type": "collection", 94 | "modified": 1459890405689, 95 | "location": "demo:realtime", 96 | "persisted": 1459890405689 97 | }, 98 | "demo:1325c1a1-65c9-4a82-9f1c-4ef27482d54c": { 99 | "telemetry": { 100 | "period": 1000 101 | }, 102 | "name": "Battery A State of Charge", 103 | "type": "demo-telemetry", 104 | "modified": 1459890376832, 105 | "location": "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 106 | "persisted": 1459890376832 107 | }, 108 | "demo:c8700fa3-fc53-44a2-82a8-7854813803de": { 109 | "telemetry": { 110 | "period": 1000 111 | }, 112 | "name": "CPU Load", 113 | "type": "demo-telemetry", 114 | "modified": 1459890405485, 115 | "location": "demo:329bf4c5-2f1a-4ce6-9a4d-18610c145f44", 116 | "persisted": 1459890405485 117 | }, 118 | "demo:e043bd38-1cea-41ec-a90e-40763bd49c3a": { 119 | "telemetry": { 120 | "period": 1000 121 | }, 122 | "name": "Battery B State of Charge", 123 | "type": "demo-telemetry", 124 | "modified": 1459890367539, 125 | "location": "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 126 | "persisted": 1459890367539 127 | }, 128 | "demo:4bfe7c56-88a1-4a0a-886d-ee2366af9a2f": { 129 | "telemetry": { 130 | "period": 1000 131 | }, 132 | "name": "Battery A Voltage", 133 | "type": "demo-telemetry", 134 | "modified": 1459890340623, 135 | "location": "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 136 | "persisted": 1459890340623 137 | }, 138 | "demo:2910cf8f-c1d9-4153-b3ab-0d18108f6cc4": { 139 | "telemetry": { 140 | "period": 1000 141 | }, 142 | "name": "Battery B Voltage", 143 | "type": "demo-telemetry", 144 | "modified": 1459890356955, 145 | "location": "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 146 | "persisted": 1459890356955 147 | }, 148 | "demo:dfac7fe1-c8ee-4534-988d-af22a2e67a70": { 149 | "telemetry": { 150 | "period": 1000 151 | }, 152 | "name": "Wheel FL Temp.", 153 | "type": "demo-telemetry", 154 | "modified": 1459890304389, 155 | "location": "demo:64b43121-ae85-490e-81ce-ebea885b3515", 156 | "persisted": 1459890304389 157 | }, 158 | "demo:3711d99e-b6be-45b1-bbb2-d2a8c333aab6": { 159 | "telemetry": { 160 | "period": 1000 161 | }, 162 | "name": "Wheel FR Temp", 163 | "type": "demo-telemetry", 164 | "modified": 1459890295721, 165 | "location": "demo:64b43121-ae85-490e-81ce-ebea885b3515", 166 | "persisted": 1459890295721 167 | }, 168 | "demo:7cf47710-26ab-4689-b903-b0e6297ffe49": { 169 | "telemetry": { 170 | "period": 1000 171 | }, 172 | "name": "Wheel RL Temp.", 173 | "type": "demo-telemetry", 174 | "modified": 1459890280682, 175 | "location": "demo:64b43121-ae85-490e-81ce-ebea885b3515", 176 | "persisted": 1459890280682 177 | }, 178 | "demo:b66be4e2-b918-42d2-ad0a-f70c7a6f4102": { 179 | "telemetry": { 180 | "period": "10000" 181 | }, 182 | "name": "Wheel RR Temp.", 183 | "type": "demo-telemetry", 184 | "modified": 1459990106313, 185 | "location": "demo:64b43121-ae85-490e-81ce-ebea885b3515", 186 | "persisted": 1459990106313 187 | }, 188 | "demo:64b43121-ae85-490e-81ce-ebea885b3515": { 189 | "composition": [ 190 | "demo:b66be4e2-b918-42d2-ad0a-f70c7a6f4102", 191 | "demo:7cf47710-26ab-4689-b903-b0e6297ffe49", 192 | "demo:3711d99e-b6be-45b1-bbb2-d2a8c333aab6", 193 | "demo:dfac7fe1-c8ee-4534-988d-af22a2e67a70" 194 | ], 195 | "name": "Thermal", 196 | "type": "collection", 197 | "modified": 1459890428668, 198 | "location": "demo:be3d5df3-cc6e-4b8b-9865-fcd844e55b94", 199 | "persisted": 1459890428668 200 | }, 201 | "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0": { 202 | "composition": [ 203 | "demo:4bfe7c56-88a1-4a0a-886d-ee2366af9a2f", 204 | "demo:2910cf8f-c1d9-4153-b3ab-0d18108f6cc4", 205 | "demo:e043bd38-1cea-41ec-a90e-40763bd49c3a", 206 | "demo:1325c1a1-65c9-4a82-9f1c-4ef27482d54c", 207 | "demo:abc420b8-86dc-4abd-99c4-80828d5f8476", 208 | "demo:dd39ba74-f1d1-4a63-8ac2-5e4194667e38" 209 | ], 210 | "name": "Power", 211 | "type": "collection", 212 | "modified": 1459890477967, 213 | "location": "demo:be3d5df3-cc6e-4b8b-9865-fcd844e55b94", 214 | "persisted": 1459890477967 215 | }, 216 | "demo:329bf4c5-2f1a-4ce6-9a4d-18610c145f44": { 217 | "composition": [ 218 | "demo:c8700fa3-fc53-44a2-82a8-7854813803de", 219 | "demo:eb70c9e8-6671-4981-94fc-bf30ef8e86ae" 220 | ], 221 | "name": "Flight Computer", 222 | "type": "collection", 223 | "modified": 1459985915700, 224 | "location": "demo:be3d5df3-cc6e-4b8b-9865-fcd844e55b94", 225 | "persisted": 1459985915700 226 | }, 227 | "demo:abc420b8-86dc-4abd-99c4-80828d5f8476": { 228 | "telemetry": { 229 | "period": 1000 230 | }, 231 | "name": "Bus A Current", 232 | "type": "demo-telemetry", 233 | "modified": 1459890460757, 234 | "location": "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 235 | "persisted": 1459890460757 236 | }, 237 | "demo:dd39ba74-f1d1-4a63-8ac2-5e4194667e38": { 238 | "telemetry": { 239 | "period": 1000 240 | }, 241 | "name": "Bus B Current", 242 | "type": "demo-telemetry", 243 | "modified": 1459890477953, 244 | "location": "demo:195ca42c-285c-4e3b-afd3-d530ad959bb0", 245 | "persisted": 1459890477953 246 | }, 247 | "demo:930dd0b9-9d98-4908-b19c-c1c887117d42": { 248 | "composition": [ 249 | "demo:4d5ca79c-9ad4-438a-beaf-affdda43b7da", 250 | "demo:b8858147-8e4f-4249-badb-b4031dba90f9" 251 | ], 252 | "name": "Rover Imagery", 253 | "type": "collection", 254 | "modified": 1459972004430, 255 | "location": "demo:realtime", 256 | "persisted": 1459972004430 257 | }, 258 | "demo:4d5ca79c-9ad4-438a-beaf-affdda43b7da": { 259 | "telemetry": { 260 | "values": [{ 261 | "name": "Time", 262 | "key": "utc", 263 | "format": "utc", 264 | "hints": { 265 | "domain": 1 266 | } 267 | }, { 268 | "name": "Image", 269 | "key": "url", 270 | "format": "image", 271 | "hints": { 272 | "image": 1 273 | } 274 | }] 275 | }, 276 | "name": "Navcam Left", 277 | "type": "example.imagery", 278 | "modified": 1459971993053, 279 | "location": "demo:930dd0b9-9d98-4908-b19c-c1c887117d42", 280 | "persisted": 1459971993053 281 | }, 282 | "demo:b8858147-8e4f-4249-badb-b4031dba90f9": { 283 | "telemetry": { 284 | "values": [{ 285 | "name": "Time", 286 | "key": "utc", 287 | "format": "utc", 288 | "hints": { 289 | "domain": 1 290 | } 291 | }, { 292 | "name": "Image", 293 | "key": "url", 294 | "format": "image", 295 | "hints": { 296 | "image": 1 297 | } 298 | }] 299 | }, 300 | "name": "Navcam Right", 301 | "type": "example.imagery", 302 | "modified": 1459972004417, 303 | "location": "demo:930dd0b9-9d98-4908-b19c-c1c887117d42", 304 | "persisted": 1459972004417 305 | }, 306 | "demo:a330490d-59ba-4c0c-b046-e5450f29f39b": { 307 | "composition": [ 308 | "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 309 | "demo:3aada5a2-9ffb-4295-8aef-0b9eeca7ffae", 310 | "demo:57375672-6388-45dd-ae78-a782e3abd366", 311 | "demo:68fdc972-4d06-46d1-a26f-5cd0c7ee33b8" 312 | ], 313 | "name": "Planning", 314 | "type": "folder", 315 | "modified": 1459986141623, 316 | "location": "demo:demo-objects", 317 | "persisted": 1459986141623 318 | }, 319 | "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78": { 320 | "composition": [ 321 | "demo:3b6a8e80-3d53-4824-ba30-4006e6bdc458", 322 | "demo:e2bbceb5-f1a5-4976-b8dc-699f6ce6900f", 323 | "demo:f0b332ed-7b39-4cc3-8a35-8a13bc3a6d85", 324 | "demo:785b714f-18eb-4edb-94da-a43a065c99b0", 325 | "demo:832f7b65-6160-4387-b9cf-3d5bba439fed" 326 | ], 327 | "start": { 328 | "timestamp": 0, 329 | "epoch": "SET" 330 | }, 331 | "name": "Rover Surface Operations", 332 | "type": "timeline", 333 | "capacity": 100000, 334 | "modified": 1460058634216, 335 | "location": "demo:a330490d-59ba-4c0c-b046-e5450f29f39b", 336 | "persisted": 1460058634216, 337 | "configuration": { 338 | "timeline": { 339 | "zoomLevel": 13 340 | } 341 | } 342 | }, 343 | "demo:46499226-4a23-48d2-9037-366a0813f0d1": { 344 | "resources": { 345 | "comms": 100, 346 | "power": 500 347 | }, 348 | "name": "Driving", 349 | "type": "mode", 350 | "modified": 1459972183814, 351 | "location": "demo:3aada5a2-9ffb-4295-8aef-0b9eeca7ffae", 352 | "persisted": 1459972183814 353 | }, 354 | "demo:8294800a-b30f-4e5b-9059-7cd0cc86140c": { 355 | "resources": { 356 | "comms": 200, 357 | "power": 400 358 | }, 359 | "name": "Drilling", 360 | "type": "mode", 361 | "modified": 1459972191963, 362 | "location": "demo:3aada5a2-9ffb-4295-8aef-0b9eeca7ffae", 363 | "persisted": 1459972191963 364 | }, 365 | "demo:3aada5a2-9ffb-4295-8aef-0b9eeca7ffae": { 366 | "composition": [ 367 | "demo:46499226-4a23-48d2-9037-366a0813f0d1", 368 | "demo:8294800a-b30f-4e5b-9059-7cd0cc86140c", 369 | "demo:92f662cd-504a-4b9b-92fb-1c3cba275a39", 370 | "demo:ee314011-250a-4592-aa9c-fb21c3b5b071" 371 | ], 372 | "name": "Activity Modes", 373 | "type": "folder", 374 | "modified": 1459972776139, 375 | "location": "demo:a330490d-59ba-4c0c-b046-e5450f29f39b", 376 | "persisted": 1459972776139 377 | }, 378 | "demo:e2bbceb5-f1a5-4976-b8dc-699f6ce6900f": { 379 | "composition": [], 380 | "relationships": { 381 | "modes": [ 382 | "demo:46499226-4a23-48d2-9037-366a0813f0d1" 383 | ] 384 | }, 385 | "start": { 386 | "timestamp": 7200000, 387 | "epoch": "SET" 388 | }, 389 | "duration": { 390 | "timestamp": 3600000, 391 | "epoch": "SET" 392 | }, 393 | "name": "Lander Egress", 394 | "type": "activity", 395 | "modified": 1459972737043, 396 | "location": "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 397 | "persisted": 1459972737043 398 | }, 399 | "demo:92f662cd-504a-4b9b-92fb-1c3cba275a39": { 400 | "resources": { 401 | "comms": 100, 402 | "power": 300 403 | }, 404 | "name": "Phone Home", 405 | "type": "mode", 406 | "modified": 1459972306466, 407 | "location": "demo:3aada5a2-9ffb-4295-8aef-0b9eeca7ffae", 408 | "persisted": 1459972306466 409 | }, 410 | "demo:3b6a8e80-3d53-4824-ba30-4006e6bdc458": { 411 | "composition": [], 412 | "relationships": { 413 | "modes": [ 414 | "demo:92f662cd-504a-4b9b-92fb-1c3cba275a39" 415 | ] 416 | }, 417 | "start": { 418 | "timestamp": 0, 419 | "epoch": "SET" 420 | }, 421 | "duration": { 422 | "timestamp": 7200000, 423 | "epoch": "SET" 424 | }, 425 | "name": "Post-landing shakedown", 426 | "type": "activity", 427 | "modified": 1459972678291, 428 | "location": "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 429 | "persisted": 1459972678291 430 | }, 431 | "demo:f0b332ed-7b39-4cc3-8a35-8a13bc3a6d85": { 432 | "composition": [], 433 | "relationships": { 434 | "modes": [ 435 | "demo:46499226-4a23-48d2-9037-366a0813f0d1" 436 | ] 437 | }, 438 | "start": { 439 | "timestamp": 10800000, 440 | "epoch": "SET" 441 | }, 442 | "duration": { 443 | "timestamp": 2124000, 444 | "epoch": "SET" 445 | }, 446 | "name": "Driving", 447 | "type": "activity", 448 | "modified": 1459972678291, 449 | "location": "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 450 | "persisted": 1459972678291 451 | }, 452 | "demo:785b714f-18eb-4edb-94da-a43a065c99b0": { 453 | "composition": [], 454 | "relationships": { 455 | "modes": [ 456 | "demo:8294800a-b30f-4e5b-9059-7cd0cc86140c" 457 | ] 458 | }, 459 | "start": { 460 | "timestamp": 12924000, 461 | "epoch": "SET" 462 | }, 463 | "duration": { 464 | "timestamp": 6588000, 465 | "epoch": "SET" 466 | }, 467 | "name": "Drilling", 468 | "type": "activity", 469 | "modified": 1459972678290, 470 | "location": "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 471 | "persisted": 1459972678290 472 | }, 473 | "demo:fa9572c2-a38c-42ac-9a46-a98d28131b6f": { 474 | "composition": [], 475 | "relationships": { 476 | "modes": [] 477 | }, 478 | "start": { 479 | "timestamp": 0, 480 | "epoch": "SET" 481 | }, 482 | "duration": { 483 | "timestamp": 1800000, 484 | "epoch": "SET" 485 | }, 486 | "name": "Second Traverse", 487 | "type": "activity", 488 | "modified": 1459972678290, 489 | "location": "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 490 | "persisted": 1459972678290 491 | }, 492 | "demo:832f7b65-6160-4387-b9cf-3d5bba439fed": { 493 | "composition": [], 494 | "relationships": { 495 | "modes": [ 496 | "demo:92f662cd-504a-4b9b-92fb-1c3cba275a39", 497 | "demo:ee314011-250a-4592-aa9c-fb21c3b5b071" 498 | ] 499 | }, 500 | "start": { 501 | "timestamp": 19512000, 502 | "epoch": "SET" 503 | }, 504 | "duration": { 505 | "timestamp": 1944000, 506 | "epoch": "SET" 507 | }, 508 | "name": "Sample Analysis", 509 | "type": "activity", 510 | "modified": 1459972767660, 511 | "location": "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 512 | "persisted": 1459972767660 513 | }, 514 | "demo:ee314011-250a-4592-aa9c-fb21c3b5b071": { 515 | "resources": { 516 | "comms": 0, 517 | "power": 500 518 | }, 519 | "name": "Oven", 520 | "type": "mode", 521 | "modified": 1459972693087, 522 | "location": "demo:3aada5a2-9ffb-4295-8aef-0b9eeca7ffae", 523 | "persisted": 1459972693087 524 | }, 525 | "demo:00ba2221-f35a-44ab-bec9-50ecca5ee450": { 526 | "telemetry": { 527 | "period": 1000 528 | }, 529 | "name": "Unnamed Sine Wave Generator", 530 | "type": "demo-telemetry", 531 | "modified": 1459985234652, 532 | "location": "demo:934b199f-917e-46a2-9935-3117a9e29218", 533 | "persisted": 1459985234652 534 | }, 535 | "demo:b15191b5-cd91-4d18-b36e-5802f3616a79": { 536 | "telemetry": { 537 | "period": 1000 538 | }, 539 | "name": "Battery Panel", 540 | "type": "demo-telemetry", 541 | "modified": 1459985792191, 542 | "location": "demo:934b199f-917e-46a2-9935-3117a9e29218", 543 | "persisted": 1459985792191 544 | }, 545 | "demo:eb70c9e8-6671-4981-94fc-bf30ef8e86ae": { 546 | "telemetry": { 547 | "period": 1000 548 | }, 549 | "name": "Memory Available", 550 | "type": "demo-telemetry", 551 | "modified": 1459985881929, 552 | "location": "demo:329bf4c5-2f1a-4ce6-9a4d-18610c145f44", 553 | "persisted": 1459985881929 554 | }, 555 | "demo:d7980e59-129a-4ded-b18a-dc6cda96a83e": { 556 | "telemetry": { 557 | "period": 1000 558 | }, 559 | "name": "Memory Used", 560 | "type": "demo-telemetry", 561 | "modified": 1459985896190, 562 | "location": "demo:329bf4c5-2f1a-4ce6-9a4d-18610c145f44", 563 | "persisted": 1459985896190 564 | }, 565 | "demo:57375672-6388-45dd-ae78-a782e3abd366": { 566 | "clockFormat": [ 567 | "YYYY/MM/DD hh:mm:ss", 568 | "clock24" 569 | ], 570 | "name": "Mission Elapsed Time (MET)", 571 | "type": "clock", 572 | "modified": 1459986068409, 573 | "location": "demo:a330490d-59ba-4c0c-b046-e5450f29f39b", 574 | "persisted": 1459986068409 575 | }, 576 | "demo:68fdc972-4d06-46d1-a26f-5cd0c7ee33b8": { 577 | "clockFormat": [ 578 | "YYYY/DDD hh:mm:ss", 579 | "clock24" 580 | ], 581 | "name": "Spacecraft Event Time", 582 | "type": "clock", 583 | "modified": 1459986141608, 584 | "location": "demo:a330490d-59ba-4c0c-b046-e5450f29f39b", 585 | "persisted": 1459986141608 586 | }, 587 | "demo:6b2c3426-6d35-42ad-8720-95543567241f": { 588 | "composition": ["msl_tlm:pressure"], 589 | "name": "Atmospheric Pressure", 590 | "type": "table", 591 | "configuration": { 592 | "table": { 593 | "columns": { 594 | "Name": true, 595 | "Time": true, 596 | "pascals": true 597 | } 598 | } 599 | }, 600 | "modified": 1461350853034, 601 | "location": "demo:f3744144-8842-4b7a-bddc-4abbf21315d9", 602 | "persisted": 1461350853034 603 | }, 604 | "demo:21a89560-680d-4eae-b1f7-c44cfa3b68da": { 605 | "telemetry": {}, 606 | "name": "Navcam Right", 607 | "type": "example.imagery", 608 | "modified": 1461703126642, 609 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 610 | "persisted": 1461703126642 611 | }, 612 | "demo:33323b29-f4b0-4d02-98a4-b8d57ed9c254": { 613 | "composition": [], 614 | "relationships": { 615 | "modes": ["demo:92f662cd-504a-4b9b-92fb-1c3cba275a39"] 616 | }, 617 | "start": { 618 | "timestamp": 0, 619 | "epoch": "SET" 620 | }, 621 | "duration": { 622 | "timestamp": 7200000, 623 | "epoch": "SET" 624 | }, 625 | "name": "Post-landing shakedown", 626 | "type": "activity", 627 | "modified": 1461703126653, 628 | "location": "demo:a36a131a-4bdb-4fd3-bc51-5385f060ee32", 629 | "persisted": 1461703126653 630 | }, 631 | "demo:200c3926-45fe-482b-b19d-e6793b02e67e": { 632 | "composition": [], 633 | "relationships": { 634 | "modes": ["demo:46499226-4a23-48d2-9037-366a0813f0d1"] 635 | }, 636 | "start": { 637 | "timestamp": 7200000, 638 | "epoch": "SET" 639 | }, 640 | "duration": { 641 | "timestamp": 3600000, 642 | "epoch": "SET" 643 | }, 644 | "name": "Lander Egress", 645 | "type": "activity", 646 | "modified": 1461703126653, 647 | "location": "demo:a36a131a-4bdb-4fd3-bc51-5385f060ee32", 648 | "persisted": 1461703126653 649 | }, 650 | "demo:312714bb-bb6a-42aa-aeca-3cd5d7121817": { 651 | "composition": [], 652 | "relationships": { 653 | "modes": ["demo:46499226-4a23-48d2-9037-366a0813f0d1"] 654 | }, 655 | "start": { 656 | "timestamp": 10800000, 657 | "epoch": "SET" 658 | }, 659 | "duration": { 660 | "timestamp": 2124000, 661 | "epoch": "SET" 662 | }, 663 | "name": "Driving", 664 | "type": "activity", 665 | "modified": 1461703126654, 666 | "location": "demo:a36a131a-4bdb-4fd3-bc51-5385f060ee32", 667 | "persisted": 1461703126654 668 | }, 669 | "demo:27758dd3-1c90-4525-8e7a-9bf902d719de": { 670 | "composition": [], 671 | "relationships": { 672 | "modes": ["demo:8294800a-b30f-4e5b-9059-7cd0cc86140c"] 673 | }, 674 | "start": { 675 | "timestamp": 12924000, 676 | "epoch": "SET" 677 | }, 678 | "duration": { 679 | "timestamp": 6588000, 680 | "epoch": "SET" 681 | }, 682 | "name": "Drilling", 683 | "type": "activity", 684 | "modified": 1461703126654, 685 | "location": "demo:a36a131a-4bdb-4fd3-bc51-5385f060ee32", 686 | "persisted": 1461703126654 687 | }, 688 | "demo:b07a7101-0e6c-4bc0-9f59-1334953d28a7": { 689 | "composition": [], 690 | "relationships": { 691 | "modes": ["demo:92f662cd-504a-4b9b-92fb-1c3cba275a39", "demo:ee314011-250a-4592-aa9c-fb21c3b5b071"] 692 | }, 693 | "start": { 694 | "timestamp": 19512000, 695 | "epoch": "SET" 696 | }, 697 | "duration": { 698 | "timestamp": 1944000, 699 | "epoch": "SET" 700 | }, 701 | "name": "Sample Analysis", 702 | "type": "activity", 703 | "modified": 1461703126654, 704 | "location": "demo:a36a131a-4bdb-4fd3-bc51-5385f060ee32", 705 | "persisted": 1461703126654 706 | }, 707 | "demo:a36a131a-4bdb-4fd3-bc51-5385f060ee32": { 708 | "composition": ["demo:33323b29-f4b0-4d02-98a4-b8d57ed9c254", "demo:200c3926-45fe-482b-b19d-e6793b02e67e", "demo:312714bb-bb6a-42aa-aeca-3cd5d7121817", "demo:27758dd3-1c90-4525-8e7a-9bf902d719de", "demo:b07a7101-0e6c-4bc0-9f59-1334953d28a7"], 709 | "start": { 710 | "timestamp": 0, 711 | "epoch": "SET" 712 | }, 713 | "name": "Rover Surface Operations", 714 | "type": "timeline", 715 | "capacity": 100000, 716 | "configuration": { 717 | "timeline": { 718 | "zoomLevel": 13 719 | } 720 | }, 721 | "modified": 1461703126651, 722 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 723 | "persisted": 1461703126651 724 | }, 725 | "demo:9d6d1789-ab39-4e90-865e-c587cd0ccacb": { 726 | "telemetry": { 727 | "period": 1000 728 | }, 729 | "name": "Battery A Voltage", 730 | "type": "demo-telemetry", 731 | "modified": 1461703126655, 732 | "location": "demo:80ddeac5-5f8e-444d-a1ad-94ecda8e3f38", 733 | "persisted": 1461703126655 734 | }, 735 | "demo:fa4c3575-645a-494f-be12-8566d23d84fb": { 736 | "telemetry": { 737 | "period": 1000 738 | }, 739 | "name": "Battery B Voltage", 740 | "type": "demo-telemetry", 741 | "modified": 1461703126655, 742 | "location": "demo:80ddeac5-5f8e-444d-a1ad-94ecda8e3f38", 743 | "persisted": 1461703126655 744 | }, 745 | "demo:e67c7a15-c21c-44dc-86cd-b7c161fcd598": { 746 | "telemetry": { 747 | "period": 1000 748 | }, 749 | "name": "Bus A Current", 750 | "type": "demo-telemetry", 751 | "modified": 1461703126655, 752 | "location": "demo:80ddeac5-5f8e-444d-a1ad-94ecda8e3f38", 753 | "persisted": 1461703126655 754 | }, 755 | "demo:353be267-5e96-4202-8fae-13b578df1c27": { 756 | "telemetry": { 757 | "period": 1000 758 | }, 759 | "name": "Bus B Current", 760 | "type": "demo-telemetry", 761 | "modified": 1461703126656, 762 | "location": "demo:80ddeac5-5f8e-444d-a1ad-94ecda8e3f38", 763 | "persisted": 1461703126656 764 | }, 765 | "demo:80ddeac5-5f8e-444d-a1ad-94ecda8e3f38": { 766 | "composition": ["demo:9d6d1789-ab39-4e90-865e-c587cd0ccacb", "demo:fa4c3575-645a-494f-be12-8566d23d84fb", "demo:e67c7a15-c21c-44dc-86cd-b7c161fcd598", "demo:353be267-5e96-4202-8fae-13b578df1c27"], 767 | "name": "Power Panel", 768 | "type": "telemetry.panel", 769 | "modified": 1461703126654, 770 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 771 | "persisted": 1461703126654 772 | }, 773 | "demo:72a8dd63-c92b-46d3-9ab4-da8728c46171": { 774 | "telemetry": { 775 | "period": 1000 776 | }, 777 | "name": "Battery B State of Charge", 778 | "type": "demo-telemetry", 779 | "modified": 1461703126656, 780 | "location": "demo:f018583c-c364-4942-83a1-78458a44c1f6", 781 | "persisted": 1461703126656 782 | }, 783 | "demo:e14cbf78-6bfd-47d0-bd72-736076d37fc4": { 784 | "telemetry": { 785 | "period": 1000 786 | }, 787 | "name": "Battery A State of Charge", 788 | "type": "demo-telemetry", 789 | "modified": 1461703126656, 790 | "location": "demo:f018583c-c364-4942-83a1-78458a44c1f6", 791 | "persisted": 1461703126656 792 | }, 793 | "demo:f018583c-c364-4942-83a1-78458a44c1f6": { 794 | "composition": ["demo:72a8dd63-c92b-46d3-9ab4-da8728c46171", "demo:e14cbf78-6bfd-47d0-bd72-736076d37fc4"], 795 | "name": "Battery Panel", 796 | "type": "telemetry.panel", 797 | "modified": 1461703126656, 798 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 799 | "persisted": 1461703126656 800 | }, 801 | "demo:9622cdee-96ba-40dd-b1ba-469d92574daf": { 802 | "clockFormat": ["YYYY/MM/DD hh:mm:ss", "clock24"], 803 | "name": "Mission Elapsed Time (MET)", 804 | "type": "clock", 805 | "modified": 1461703126657, 806 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 807 | "persisted": 1461703126657 808 | }, 809 | "demo:00f8c193-bbc3-497d-baf6-a7698948fca3": { 810 | "clockFormat": ["YYYY/DDD hh:mm:ss", "clock24"], 811 | "name": "Spacecraft Event Time", 812 | "type": "clock", 813 | "modified": 1461703126657, 814 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 815 | "persisted": 1461703126657 816 | }, 817 | "demo:2cac7fc5-9295-4b22-bf47-4cb805ea7b25": { 818 | "telemetry": { 819 | "period": "10000" 820 | }, 821 | "name": "Wheel RR Temp.", 822 | "type": "demo-telemetry", 823 | "modified": 1461703126658, 824 | "location": "demo:422f8488-541b-4d00-9413-18b3a11e43cd", 825 | "persisted": 1461703126658 826 | }, 827 | "demo:c51438a5-2f4c-4e61-9a27-248c8bd463c0": { 828 | "telemetry": { 829 | "period": 1000 830 | }, 831 | "name": "Wheel RL Temp.", 832 | "type": "demo-telemetry", 833 | "modified": 1461703126658, 834 | "location": "demo:422f8488-541b-4d00-9413-18b3a11e43cd", 835 | "persisted": 1461703126658 836 | }, 837 | "demo:4813dfe0-ec5b-4dc4-a073-d057e13188ec": { 838 | "telemetry": { 839 | "period": 1000 840 | }, 841 | "name": "Wheel FR Temp", 842 | "type": "demo-telemetry", 843 | "modified": 1461703126659, 844 | "location": "demo:422f8488-541b-4d00-9413-18b3a11e43cd", 845 | "persisted": 1461703126659 846 | }, 847 | "demo:a971f68b-72f0-49e9-b42b-8e15788eb57c": { 848 | "telemetry": { 849 | "period": 1000 850 | }, 851 | "name": "Wheel FL Temp.", 852 | "type": "demo-telemetry", 853 | "modified": 1461703126659, 854 | "location": "demo:422f8488-541b-4d00-9413-18b3a11e43cd", 855 | "persisted": 1461703126659 856 | }, 857 | "demo:422f8488-541b-4d00-9413-18b3a11e43cd": { 858 | "composition": ["demo:2cac7fc5-9295-4b22-bf47-4cb805ea7b25", "demo:c51438a5-2f4c-4e61-9a27-248c8bd463c0", "demo:4813dfe0-ec5b-4dc4-a073-d057e13188ec", "demo:a971f68b-72f0-49e9-b42b-8e15788eb57c"], 859 | "name": "Thermal Panel", 860 | "type": "telemetry.panel", 861 | "modified": 1461703126657, 862 | "location": "demo:a32079d0-676b-4e9f-ade7-86d5d2f152fc", 863 | "persisted": 1461703126657 864 | }, 865 | "demo:11247663-fad1-481a-93d8-429ba159bf6b": { 866 | "name": "Where is Curiosity?", 867 | "type": "image-include", 868 | "url": "http://mars.nasa.gov/msl/imgs/2016/04/MSL_TraverseMap_Sol1298-br2.jpg", 869 | "modified": 1461720290507, 870 | "location": "demo:f3744144-8842-4b7a-bddc-4abbf21315d9", 871 | "persisted": 1461720290507 872 | }, 873 | 874 | "demo:96592bba-a9f4-46d9-8d9f-a4efb45bcfc1": { 875 | "composition": 876 | ["example.taxonomy:pwr.temp", 877 | "example.taxonomy:pwr.c", 878 | "demo:34cbe01c-3fe6-4406-b1d4-5abf79890e41", 879 | "demo:1b155f02-5230-4cbb-a259-fa8e14d6aaf2", 880 | "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78", 881 | "example.taxonomy:pwr.v", 882 | "demo:1713049f-bcb2-4a52-88d1-908b05598696", 883 | "example.taxonomy:pwr.soc", 884 | "demo:28f8865b-a9f3-45da-93ee-249b4affe3d3" 885 | ], 886 | "name":"Rover Operator Layout", 887 | "type":"layout", 888 | "modified":1489943660703, 889 | "location":"demo:demo-objects", 890 | "persisted":1489943660703, 891 | "configuration":{ 892 | "layout":{ 893 | "panels":{ 894 | "example.taxonomy:pwr.v":{ 895 | "position":[12,2], 896 | "dimensions":[12,8] 897 | }, 898 | "example.taxonomy:pwr.c":{ 899 | "position":[0,18], 900 | "dimensions":[12,8] 901 | }, 902 | "example.taxonomy:pwr.temp":{ 903 | "position":[12,18], 904 | "dimensions":[12,8] 905 | }, 906 | "demo:28f8865b-a9f3-45da-93ee-249b4affe3d3":{ 907 | "position":[0,0], 908 | "dimensions":[7,2] 909 | }, 910 | "demo:34cbe01c-3fe6-4406-b1d4-5abf79890e41":{ 911 | "position":[7,0], 912 | "dimensions":[7,2] 913 | }, 914 | "demo:1b155f02-5230-4cbb-a259-fa8e14d6aaf2":{ 915 | "position":[24,2], 916 | "dimensions":[12,8] 917 | }, 918 | "demo:aa1ea485-c4b9-4763-9c48-0ca06789cc78":{ 919 | "position":[0,10], 920 | "dimensions":[36,8] 921 | }, 922 | "demo:1713049f-bcb2-4a52-88d1-908b05598696":{ 923 | "position":[0,2], 924 | "dimensions":[12,8]}, 925 | "example.taxonomy:pwr.soc":{ 926 | "position":[24,18],"dimensions":[12,8] 927 | } 928 | } 929 | } 930 | } 931 | }, 932 | "demo:28f8865b-a9f3-45da-93ee-249b4affe3d3":{ 933 | "clockFormat":["YYYY/MM/DD hh:mm:ss","clock24"], 934 | "name":"UTC", 935 | "type":"clock", 936 | "modified":1489942534032, 937 | "location":"demo:96592bba-a9f4-46d9-8d9f-a4efb45bcfc1", 938 | "persisted":1489942534032 939 | }, 940 | "demo:34cbe01c-3fe6-4406-b1d4-5abf79890e41":{ 941 | "timerFormat":"long", 942 | "name":"Mission Elapsed Time", 943 | "type":"timer", 944 | "modified":1489942584773, 945 | "location":"demo:96592bba-a9f4-46d9-8d9f-a4efb45bcfc1", 946 | "persisted":1489942584773, 947 | "timestamp":1489942584773 948 | }, 949 | "demo:dd67977a-870a-45cb-8bbe-c87580bceeb2":{ 950 | "composition":[ 951 | "example.taxonomy:comms.recd", 952 | "example.taxonomy:comms.sent" 953 | ], 954 | "name":"Comms Table", 955 | "type":"table", 956 | "location":"demo:96592bba-a9f4-46d9-8d9f-a4efb45bcfc1", 957 | "modified":1489942657507, 958 | "configuration":{ 959 | "table":{ 960 | "columns":{ 961 | "Value":true, 962 | "Timestamp":true 963 | } 964 | } 965 | }, 966 | "persisted":1489942657507 967 | }, 968 | "demo:1b155f02-5230-4cbb-a259-fa8e14d6aaf2":{ 969 | "composition":[ 970 | "example.taxonomy:comms.recd", 971 | "example.taxonomy:comms.sent" 972 | ], 973 | "name":"Comms Table", 974 | "type":"table", 975 | "configuration":{ 976 | "table":{ 977 | "columns":{ 978 | "Value":true, 979 | "Timestamp":true 980 | } 981 | } 982 | }, 983 | "modified":1489942657577, 984 | "location":"demo:96592bba-a9f4-46d9-8d9f-a4efb45bcfc1", 985 | "persisted":1489942657577 986 | }, 987 | "demo:1713049f-bcb2-4a52-88d1-908b05598696":{ 988 | "telemetry": { 989 | "values": [{ 990 | "name": "Time", 991 | "key": "utc", 992 | "format": "utc", 993 | "hints": { 994 | "domain": 1 995 | } 996 | }, { 997 | "name": "Image", 998 | "key": "url", 999 | "format": "image", 1000 | "hints": { 1001 | "image": 1 1002 | } 1003 | }] 1004 | }, 1005 | "name":"Rover Navcam 1", 1006 | "type":"example.imagery", 1007 | "modified":1489943543498, 1008 | "location":"demo:96592bba-a9f4-46d9-8d9f-a4efb45bcfc1", 1009 | "persisted":1489943543498 1010 | } 1011 | 1012 | } 1013 | -------------------------------------------------------------------------------- /dictionary.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Example Rover", 3 | "key": "sc", 4 | "measurements": [ 5 | { 6 | "name": "Battery State of Charge", 7 | "key": "pwr.soc", 8 | "values": [ 9 | { 10 | "key": "value", 11 | "name": "Value", 12 | "units": "%", 13 | "format": "float", 14 | "hints": { 15 | "y": 1, 16 | "range": 1 17 | } 18 | }, 19 | { 20 | "key": "utc", 21 | "source": "timestamp", 22 | "name": "Timestamp", 23 | "format": "utc", 24 | "hints": { 25 | "x": 1, 26 | "domain": 1 27 | } 28 | } 29 | ] 30 | }, 31 | { 32 | "name": "Wheel Motors", 33 | "key": "pwr.motors", 34 | "values": [ 35 | { 36 | "key": "value", 37 | "name": "Value", 38 | "format": "enum", 39 | "enumerations": [ 40 | { 41 | "string": "On", 42 | "value": 1 43 | }, 44 | { 45 | "string": "Off", 46 | "value": 0 47 | } 48 | ], 49 | "hints": { 50 | "y": 1, 51 | "range": 1 52 | } 53 | }, 54 | { 55 | "key": "utc", 56 | "source": "timestamp", 57 | "name": "Timestamp", 58 | "format": "utc", 59 | "hints": { 60 | "x": 1, 61 | "domain": 1 62 | } 63 | } 64 | ] 65 | }, 66 | { 67 | "name": "Received", 68 | "key": "comms.recd", 69 | "values": [ 70 | { 71 | "key": "value", 72 | "name": "Value", 73 | "units": "bytes", 74 | "format": "integer", 75 | "hints": { 76 | "y": 1, 77 | "range": 1 78 | } 79 | }, 80 | { 81 | "key": "utc", 82 | "source": "timestamp", 83 | "name": "Timestamp", 84 | "format": "utc", 85 | "hints": { 86 | "x": 1, 87 | "domain": 1 88 | } 89 | } 90 | ] 91 | }, 92 | { 93 | "name": "Sent", 94 | "key": "comms.sent", 95 | "values": [ 96 | { 97 | "key": "value", 98 | "name": "Value", 99 | "units": "bytes", 100 | "format": "integer", 101 | "hints": { 102 | "y": 1, 103 | "range": 1 104 | } 105 | }, 106 | { 107 | "key": "utc", 108 | "source": "timestamp", 109 | "name": "Timestamp", 110 | "format": "utc", 111 | "hints": { 112 | "x": 1, 113 | "domain": 1 114 | } 115 | } 116 | ] 117 | }, 118 | { 119 | "name": "Battery Temperature", 120 | "key": "pwr.temp", 121 | "values": [ 122 | { 123 | "key": "value", 124 | "name": "Value", 125 | "units": "℃", 126 | "format": "float", 127 | "hints": { 128 | "y": 1, 129 | "range": 1 130 | } 131 | }, 132 | { 133 | "key": "utc", 134 | "source": "timestamp", 135 | "name": "Timestamp", 136 | "format": "utc", 137 | "hints": { 138 | "x": 1, 139 | "domain": 1 140 | } 141 | } 142 | ] 143 | }, 144 | { 145 | "name": "Battery Current", 146 | "key": "pwr.c", 147 | "values": [ 148 | { 149 | "key": "value", 150 | "name": "Value", 151 | "units": "Amps", 152 | "format": "float", 153 | "hints": { 154 | "y": 1, 155 | "range": 1 156 | } 157 | }, 158 | { 159 | "key": "utc", 160 | "source": "timestamp", 161 | "name": "Timestamp", 162 | "format": "utc", 163 | "hints": { 164 | "x": 1, 165 | "domain": 1 166 | } 167 | } 168 | ] 169 | }, 170 | { 171 | "name": "Battery Voltage", 172 | "key": "pwr.v", 173 | "values": [ 174 | { 175 | "key": "value", 176 | "name": "Value", 177 | "units": "Volts", 178 | "format": "float", 179 | "hints": { 180 | "y": 1, 181 | "range": 1 182 | } 183 | }, 184 | { 185 | "key": "utc", 186 | "source": "timestamp", 187 | "name": "Timestamp", 188 | "format": "utc", 189 | "hints": { 190 | "x": 1, 191 | "domain": 1 192 | } 193 | } 194 | ] 195 | } 196 | ] 197 | } 198 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Open MCT Tutorials 5 | 6 | 7 | 8 | 9 | 10 | 105 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "live-demo", 3 | "version": "0.0.1", 4 | "description": "Public demonstration of the Open MCT platform", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "postinstall": "npm run install:openmct && npm run install:tutorial", 9 | "install:openmct": "cd node_modules/openmct && npm install", 10 | "install:tutorial": "npm install --ignore-scripts nasa/openmct-tutorial#tutorial-updates", 11 | "start": "node server.js" 12 | }, 13 | "author": "National Aeronautics and Space Administration", 14 | "license": "Apache-2.0", 15 | "dependencies": { 16 | "express": "^4.15.2", 17 | "express-ws": "^3.0.0", 18 | "hopscotch": "^0.2.7", 19 | "minimist": "^1.2.0", 20 | "openmct": "github:nasa/openmct#ea77e014b8d82b04f938ec3f845ecedc5c200fa7", 21 | "request": "^2.81.0", 22 | "requirejs": "^2.3.3", 23 | "text": "github:requirejs/text" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /res/hopscotch.css: -------------------------------------------------------------------------------- 1 | /**! hopscotch - v0.2.5 2 | * 3 | * Copyright 2015 LinkedIn Corp. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | /** 18 | * This fade animation is based on Dan Eden's animate.css (http://daneden.me/animate/), under the terms of the MIT license. 19 | * 20 | * Copyright 2013 Dan Eden. 21 | * 22 | * Permission is hereby granted, free of charge, to any person obtaining a copy 23 | * of this software and associated documentation files (the "Software"), to deal 24 | * in the Software without restriction, including without limitation the rights 25 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | * copies of the Software, and to permit persons to whom the Software is 27 | * furnished to do so, subject to the following conditions: 28 | * 29 | * The above copyright notice and this permission notice shall be included in 30 | * all copies or substantial portions of the Software. 31 | * 32 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 | * THE SOFTWARE. 39 | */ 40 | .animated { 41 | -webkit-animation-fill-mode: both; 42 | -moz-animation-fill-mode: both; 43 | -ms-animation-fill-mode: both; 44 | -o-animation-fill-mode: both; 45 | animation-fill-mode: both; 46 | -webkit-animation-duration: 1s; 47 | -moz-animation-duration: 1s; 48 | -ms-animation-duration: 1s; 49 | -o-animation-duration: 1s; 50 | animation-duration: 1s; 51 | } 52 | @-webkit-keyframes fadeInUp { 53 | 0% { 54 | opacity: 0; 55 | -webkit-transform: translateY(20px); 56 | } 57 | 100% { 58 | opacity: 1; 59 | -webkit-transform: translateY(0); 60 | } 61 | } 62 | @-moz-keyframes fadeInUp { 63 | 0% { 64 | opacity: 0; 65 | -moz-transform: translateY(20px); 66 | } 67 | 100% { 68 | opacity: 1; 69 | -moz-transform: translateY(0); 70 | } 71 | } 72 | @-o-keyframes fadeInUp { 73 | 0% { 74 | opacity: 0; 75 | -o-transform: translateY(20px); 76 | } 77 | 100% { 78 | opacity: 1; 79 | -o-transform: translateY(0); 80 | } 81 | } 82 | @keyframes fadeInUp { 83 | 0% { 84 | opacity: 0; 85 | transform: translateY(20px); 86 | } 87 | 100% { 88 | opacity: 1; 89 | transform: translateY(0); 90 | } 91 | } 92 | .fade-in-up { 93 | -webkit-animation-name: fadeInUp; 94 | -moz-animation-name: fadeInUp; 95 | -o-animation-name: fadeInUp; 96 | animation-name: fadeInUp; 97 | } 98 | @-webkit-keyframes fadeInDown { 99 | 0% { 100 | opacity: 0; 101 | -webkit-transform: translateY(-20px); 102 | } 103 | 100% { 104 | opacity: 1; 105 | -webkit-transform: translateY(0); 106 | } 107 | } 108 | @-moz-keyframes fadeInDown { 109 | 0% { 110 | opacity: 0; 111 | -moz-transform: translateY(-20px); 112 | } 113 | 100% { 114 | opacity: 1; 115 | -moz-transform: translateY(0); 116 | } 117 | } 118 | @-o-keyframes fadeInDown { 119 | 0% { 120 | opacity: 0; 121 | -ms-transform: translateY(-20px); 122 | } 123 | 100% { 124 | opacity: 1; 125 | -ms-transform: translateY(0); 126 | } 127 | } 128 | @keyframes fadeInDown { 129 | 0% { 130 | opacity: 0; 131 | transform: translateY(-20px); 132 | } 133 | 100% { 134 | opacity: 1; 135 | transform: translateY(0); 136 | } 137 | } 138 | .fade-in-down { 139 | -webkit-animation-name: fadeInDown; 140 | -moz-animation-name: fadeInDown; 141 | -o-animation-name: fadeInDown; 142 | animation-name: fadeInDown; 143 | } 144 | @-webkit-keyframes fadeInRight { 145 | 0% { 146 | opacity: 0; 147 | -webkit-transform: translateX(-20px); 148 | } 149 | 100% { 150 | opacity: 1; 151 | -webkit-transform: translateX(0); 152 | } 153 | } 154 | @-moz-keyframes fadeInRight { 155 | 0% { 156 | opacity: 0; 157 | -moz-transform: translateX(-20px); 158 | } 159 | 100% { 160 | opacity: 1; 161 | -moz-transform: translateX(0); 162 | } 163 | } 164 | @-o-keyframes fadeInRight { 165 | 0% { 166 | opacity: 0; 167 | -o-transform: translateX(-20px); 168 | } 169 | 100% { 170 | opacity: 1; 171 | -o-transform: translateX(0); 172 | } 173 | } 174 | @keyframes fadeInRight { 175 | 0% { 176 | opacity: 0; 177 | transform: translateX(-20px); 178 | } 179 | 100% { 180 | opacity: 1; 181 | transform: translateX(0); 182 | } 183 | } 184 | .fade-in-right { 185 | -webkit-animation-name: fadeInRight; 186 | -moz-animation-name: fadeInRight; 187 | -o-animation-name: fadeInRight; 188 | animation-name: fadeInRight; 189 | } 190 | @-webkit-keyframes fadeInLeft { 191 | 0% { 192 | opacity: 0; 193 | -webkit-transform: translateX(20px); 194 | } 195 | 100% { 196 | opacity: 1; 197 | -webkit-transform: translateX(0); 198 | } 199 | } 200 | @-moz-keyframes fadeInLeft { 201 | 0% { 202 | opacity: 0; 203 | -moz-transform: translateX(20px); 204 | } 205 | 100% { 206 | opacity: 1; 207 | -moz-transform: translateX(0); 208 | } 209 | } 210 | @-o-keyframes fadeInLeft { 211 | 0% { 212 | opacity: 0; 213 | -o-transform: translateX(20px); 214 | } 215 | 100% { 216 | opacity: 1; 217 | -o-transform: translateX(0); 218 | } 219 | } 220 | @keyframes fadeInLeft { 221 | 0% { 222 | opacity: 0; 223 | transform: translateX(20px); 224 | } 225 | 100% { 226 | opacity: 1; 227 | transform: translateX(0); 228 | } 229 | } 230 | .fade-in-left { 231 | -webkit-animation-name: fadeInLeft; 232 | -moz-animation-name: fadeInLeft; 233 | -o-animation-name: fadeInLeft; 234 | animation-name: fadeInLeft; 235 | } 236 | div.hopscotch-bubble .hopscotch-nav-button { 237 | /* borrowed from katy styles */ 238 | font-weight: bold; 239 | border-width: 1px; 240 | border-style: solid; 241 | cursor: pointer; 242 | margin: 0; 243 | overflow: visible; 244 | text-decoration: none !important; 245 | width: auto; 246 | padding: 0 10px; 247 | height: 26px; 248 | line-height: 24px; 249 | font-size: 12px; 250 | *zoom: 1; 251 | white-space: nowrap; 252 | display: -moz-inline-stack; 253 | display: inline-block; 254 | *vertical-align: auto; 255 | zoom: 1; 256 | *display: inline; 257 | vertical-align: middle; 258 | -moz-border-radius: 3px; 259 | -ms-border-radius: 3px; 260 | -o-border-radius: 3px; 261 | -webkit-border-radius: 3px; 262 | border-radius: 3px; 263 | -webkit-box-sizing: border-box; 264 | -moz-box-sizing: border-box; 265 | box-sizing: border-box; 266 | } 267 | div.hopscotch-bubble .hopscotch-nav-button:hover { 268 | *zoom: 1; 269 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); 270 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); 271 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); 272 | } 273 | div.hopscotch-bubble .hopscotch-nav-button:active { 274 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25) inset; 275 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25) inset; 276 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25) inset; 277 | } 278 | div.hopscotch-bubble .hopscotch-nav-button.next { 279 | border-color: #1b5480; 280 | color: #fff; 281 | margin: 0 0 0 10px; 282 | /* HS specific*/ 283 | text-shadow: 0 1px 1px rgba(0, 0, 0, 0.35); 284 | background-color: #287bbc; 285 | filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#287bbc', endColorstr='#23639a'); 286 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #287bbc), color-stop(100%, #23639a)); 287 | background-image: -webkit-linear-gradient(top, #287bbc 0%, #23639a 100%); 288 | background-image: -moz-linear-gradient(top, #287bbc 0%, #23639a 100%); 289 | background-image: -o-linear-gradient(top, #287bbc 0%, #23639a 100%); 290 | background-image: linear-gradient(top, #287bbc 0%, #23639a 100%); 291 | } 292 | div.hopscotch-bubble .hopscotch-nav-button.next:hover { 293 | background-color: #2672ae; 294 | filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#2672ae', endColorstr='#1e4f7e'); 295 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #2672ae), color-stop(100%, #1e4f7e)); 296 | background-image: -webkit-linear-gradient(top, #2672ae 0%, #1e4f7e 100%); 297 | background-image: -moz-linear-gradient(top, #2672ae 0%, #1e4f7e 100%); 298 | background-image: -o-linear-gradient(top, #2672ae 0%, #1e4f7e 100%); 299 | background-image: linear-gradient(top, #2672ae 0%, #1e4f7e 100%); 300 | } 301 | div.hopscotch-bubble .hopscotch-nav-button.prev { 302 | border-color: #a7a7a7; 303 | color: #444; 304 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 305 | background-color: #f2f2f2; 306 | filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#f2f2f2', endColorstr='#e9e9e9'); 307 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f2f2f2), color-stop(100%, #e9e9e9)); 308 | background-image: -webkit-linear-gradient(top, #f2f2f2 0%, #e9e9e9 100%); 309 | background-image: -moz-linear-gradient(top, #f2f2f2 0%, #e9e9e9 100%); 310 | background-image: -o-linear-gradient(top, #f2f2f2 0%, #e9e9e9 100%); 311 | background-image: linear-gradient(top, #f2f2f2 0%, #e9e9e9 100%); 312 | } 313 | div.hopscotch-bubble .hopscotch-nav-button.prev:hover { 314 | background-color: #e8e8e8; 315 | filter: progid:DXImageTransform.Microsoft.gradient(gradientType=0, startColorstr='#FFE8E8E8', endColorstr='#FFA9A9A9'); 316 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #e8e8e8), color-stop(13%, #e3e3e3), color-stop(32%, #d7d7d7), color-stop(71%, #b9b9b9), color-stop(100%, #a9a9a9)); 317 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #e3e3e3 13%, #d7d7d7 32%, #b9b9b9 71%, #a9a9a9 100%); 318 | background-image: -moz-linear-gradient(top, #e8e8e8 0%, #e3e3e3 13%, #d7d7d7 32%, #b9b9b9 71%, #a9a9a9 100%); 319 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #e3e3e3 13%, #d7d7d7 32%, #b9b9b9 71%, #a9a9a9 100%); 320 | background-image: linear-gradient(top, #e8e8e8 0%, #e3e3e3 13%, #d7d7d7 32%, #b9b9b9 71%, #a9a9a9 100%); 321 | } 322 | div.hopscotch-bubble { 323 | background-color: #ffffff; 324 | border: 5px solid #000000; 325 | border-radius: 10px; 326 | /* default */ 327 | border: 5px solid rgba(0, 0, 0, 0.3); 328 | /* transparent, if supported */ 329 | color: #333; 330 | font-family: 'Helvetica Neue', Helvetica, Arial; 331 | font-size: 13px; 332 | position: absolute; 333 | z-index: 999999; 334 | -webkit-box-sizing: content-box; 335 | -moz-box-sizing: content-box; 336 | box-sizing: content-box; 337 | -moz-background-clip: padding; 338 | /* for Mozilla browsers*/ 339 | -webkit-background-clip: padding; 340 | /* Webkit */ 341 | background-clip: padding-box; 342 | /* browsers with full support */ 343 | } 344 | div.hopscotch-bubble * { 345 | -webkit-box-sizing: content-box; 346 | -moz-box-sizing: content-box; 347 | box-sizing: content-box; 348 | } 349 | div.hopscotch-bubble.animate { 350 | -moz-transition-property: top, left; 351 | -moz-transition-duration: 1s; 352 | -moz-transition-timing-function: ease-in-out; 353 | -ms-transition-property: top, left; 354 | -ms-transition-duration: 1s; 355 | -ms-transition-timing-function: ease-in-out; 356 | -o-transition-property: top, left; 357 | -o-transition-duration: 1s; 358 | -o-transition-timing-function: ease-in-out; 359 | -webkit-transition-property: top, left; 360 | -webkit-transition-duration: 1s; 361 | -webkit-transition-timing-function: ease-in-out; 362 | transition-property: top, left; 363 | transition-duration: 1s; 364 | transition-timing-function: ease-in-out; 365 | } 366 | div.hopscotch-bubble.invisible { 367 | opacity: 0; 368 | } 369 | div.hopscotch-bubble.hide, 370 | div.hopscotch-bubble .hide, 371 | div.hopscotch-bubble .hide-all { 372 | display: none; 373 | } 374 | div.hopscotch-bubble h3 { 375 | color: #000; 376 | font-family: Helvetica, Arial; 377 | font-size: 16px; 378 | font-weight: bold; 379 | line-height: 19px; 380 | margin: -1px 15px 0 0; 381 | padding: 0; 382 | } 383 | div.hopscotch-bubble .hopscotch-bubble-container { 384 | padding: 15px; 385 | position: relative; 386 | text-align: left; 387 | -webkit-font-smoothing: antialiased; 388 | /* to fix text flickering */ 389 | } 390 | div.hopscotch-bubble .hopscotch-content { 391 | font-family: 'Helvetica Neue', Helvetica, Arial; 392 | font-weight: normal; 393 | line-height: 17px; 394 | margin: -5px 0 11px; 395 | padding-top: 8px; 396 | } 397 | div.hopscotch-bubble .hopscotch-bubble-content { 398 | margin: 0; 399 | } 400 | div.hopscotch-bubble.no-number .hopscotch-bubble-content { 401 | margin: 0; 402 | } 403 | div.hopscotch-bubble .hopscotch-bubble-close { 404 | -webkit-appearance: none; 405 | -moz-appearance: none; 406 | appearance: none; 407 | border: 0; 408 | color: #000; 409 | background: transparent url(../res/img/sprite-green.png) -192px -92px no-repeat; 410 | display: block; 411 | padding: 8px; 412 | position: absolute; 413 | text-decoration: none; 414 | text-indent: -9999px; 415 | width: 8px; 416 | height: 8px; 417 | top: 0; 418 | right: 0; 419 | } 420 | div.hopscotch-bubble .hopscotch-bubble-close.hide, 421 | div.hopscotch-bubble .hopscotch-bubble-close.hide-all { 422 | display: none; 423 | } 424 | div.hopscotch-bubble .hopscotch-bubble-number { 425 | display: none; 426 | } 427 | div.hopscotch-bubble .hopscotch-bubble-arrow-container { 428 | position: absolute; 429 | width: 34px; 430 | height: 34px; 431 | } 432 | div.hopscotch-bubble .hopscotch-bubble-arrow-container .hopscotch-bubble-arrow, 433 | div.hopscotch-bubble .hopscotch-bubble-arrow-container .hopscotch-bubble-arrow-border { 434 | width: 0; 435 | height: 0; 436 | } 437 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.up { 438 | top: -22px; 439 | left: 10px; 440 | } 441 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.up .hopscotch-bubble-arrow { 442 | border-bottom: 17px solid #ffffff; 443 | border-left: 17px solid transparent; 444 | border-right: 17px solid transparent; 445 | position: relative; 446 | top: -10px; 447 | } 448 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.up .hopscotch-bubble-arrow-border { 449 | border-bottom: 17px solid #000000; 450 | border-bottom: 17px solid rgba(0, 0, 0, 0.5); 451 | border-left: 17px solid transparent; 452 | border-right: 17px solid transparent; 453 | } 454 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.down { 455 | bottom: -39px; 456 | left: 10px; 457 | } 458 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.down .hopscotch-bubble-arrow { 459 | border-top: 17px solid #ffffff; 460 | border-left: 17px solid transparent; 461 | border-right: 17px solid transparent; 462 | position: relative; 463 | top: -24px; 464 | } 465 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.down .hopscotch-bubble-arrow-border { 466 | border-top: 17px solid #000000; 467 | border-top: 17px solid rgba(0, 0, 0, 0.5); 468 | border-left: 17px solid transparent; 469 | border-right: 17px solid transparent; 470 | } 471 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.left { 472 | top: 10px; 473 | left: -22px; 474 | } 475 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.left .hopscotch-bubble-arrow { 476 | border-bottom: 17px solid transparent; 477 | border-right: 17px solid #ffffff; 478 | border-top: 17px solid transparent; 479 | position: relative; 480 | left: 7px; 481 | top: -34px; 482 | } 483 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.left .hopscotch-bubble-arrow-border { 484 | border-right: 17px solid #000000; 485 | border-right: 17px solid rgba(0, 0, 0, 0.5); 486 | border-bottom: 17px solid transparent; 487 | border-top: 17px solid transparent; 488 | } 489 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.right { 490 | top: 10px; 491 | right: -39px; 492 | } 493 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.right .hopscotch-bubble-arrow { 494 | border-bottom: 17px solid transparent; 495 | border-left: 17px solid #ffffff; 496 | border-top: 17px solid transparent; 497 | position: relative; 498 | left: -7px; 499 | top: -34px; 500 | } 501 | div.hopscotch-bubble .hopscotch-bubble-arrow-container.right .hopscotch-bubble-arrow-border { 502 | border-left: 17px solid #000000; 503 | border-left: 17px solid rgba(0, 0, 0, 0.5); 504 | border-bottom: 17px solid transparent; 505 | border-top: 17px solid transparent; 506 | } 507 | div.hopscotch-bubble .hopscotch-actions { 508 | margin: 10px 0 0; 509 | text-align: right; 510 | } 511 | -------------------------------------------------------------------------------- /res/img/sprite-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/openmct-demo/dd99ce68e7440df1f83957f494f5f9893253702f/res/img/sprite-green.png -------------------------------------------------------------------------------- /res/img/sprite-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/openmct-demo/dd99ce68e7440df1f83957f494f5f9893253702f/res/img/sprite-orange.png -------------------------------------------------------------------------------- /res/tour.css: -------------------------------------------------------------------------------- 1 | .mct-tour { 2 | z-index: 100; 3 | } 4 | .hopscotch-content a { 5 | color: #999; 6 | } 7 | .hopscotch-content a { 8 | color: #999; 9 | } 10 | .hopscotch-content a:hover { 11 | color: #0099cc; 12 | } 13 | -------------------------------------------------------------------------------- /rover.js: -------------------------------------------------------------------------------- 1 | /* 2 | Rover.js simulates a small spacecraft generating telemetry. 3 | */ 4 | 5 | function Rover() { 6 | this.state = { 7 | "pwr.soc": 100, 8 | "pwr.motors": "OFF", 9 | "comms.recd": 0, 10 | "comms.sent": 0, 11 | "pwr.temp": 245, 12 | "pwr.c": 8.15, 13 | "pwr.v": 30 14 | }; 15 | this.history = {}; 16 | this.listeners = []; 17 | Object.keys(this.state).forEach(function (k) { 18 | this.history[k] = []; 19 | }, this); 20 | 21 | setInterval(function () { 22 | this.updateState(); 23 | this.generateTelemetry(); 24 | }.bind(this), 1000); 25 | 26 | console.log("Example spacecraft launched!"); 27 | console.log("Press Enter to toggle thruster state."); 28 | 29 | process.stdin.on('data', function () { 30 | this.state['pwr.motors'] = 31 | (this.state['pwr.motors'] === "OFF") ? "ON" : "OFF"; 32 | this.state['comms.recd'] += 32; 33 | console.log("Thrusters " + this.state["pwr.motors"]); 34 | this.generateTelemetry(); 35 | }.bind(this)); 36 | }; 37 | 38 | Rover.prototype.updateState = function () { 39 | this.state["pwr.soc"] = Math.max( 40 | 0, 41 | this.state["pwr.soc"] - 42 | (this.state["pwr.motors"] === "ON" ? 0.5 : 0) 43 | ); 44 | this.state["pwr.temp"] = this.state["pwr.temp"] * 0.985 45 | + Math.random() * 0.25 + Math.sin(Date.now()); 46 | if (this.state["pwr.motors"] === "ON") { 47 | this.state["pwr.c"] = 8.15; 48 | } else { 49 | this.state["pwr.c"] = this.state["pwr.c"] * 0.985; 50 | } 51 | this.state["pwr.v"] = 30 + Math.pow(Math.random(), 3); 52 | }; 53 | 54 | /** 55 | * Takes a measurement of spacecraft state, stores in history, and notifies 56 | * listeners. 57 | */ 58 | Rover.prototype.generateTelemetry = function () { 59 | var timestamp = Date.now(), sent = 0; 60 | Object.keys(this.state).forEach(function (id) { 61 | var state = { timestamp: timestamp, value: this.state[id], id: id}; 62 | this.notify(state); 63 | this.history[id].push(state); 64 | this.state["comms.sent"] += JSON.stringify(state).length; 65 | }, this); 66 | }; 67 | 68 | Rover.prototype.notify = function (point) { 69 | this.listeners.forEach(function (l) { 70 | l(point); 71 | }); 72 | }; 73 | 74 | Rover.prototype.listen = function (listener) { 75 | this.listeners.push(listener); 76 | return function () { 77 | this.listeners = this.listeners.filter(function (l) { 78 | return l !== listener; 79 | }); 80 | }.bind(this); 81 | }; 82 | 83 | module.exports = function () { 84 | return new Rover() 85 | }; 86 | -------------------------------------------------------------------------------- /scripts/demo-objects.js: -------------------------------------------------------------------------------- 1 | define( 2 | [ 3 | 'text!../data/demo-models.json' 4 | ], function ( 5 | demoModels 6 | ) { 7 | demoModels = JSON.parse(demoModels); 8 | return function () { 9 | return function install(openmct){ 10 | 11 | function serializeId(id) { 12 | return id.namespace + ':' + id.key; 13 | } 14 | 15 | function deserializeId(serializedId) { 16 | var tokens = serializedId.split(':'); 17 | return { 18 | namespace: tokens[0], 19 | key: tokens[1] 20 | }; 21 | } 22 | 23 | function addIdentifier(object, identifier) { 24 | object.identifier = identifier; 25 | return object; 26 | } 27 | 28 | //1. Add new root for demo objects 29 | openmct.objects.addRoot({ 30 | namespace: 'demo', 31 | key: 'demo-objects' 32 | }); 33 | //2. Add composition provider for demo objects 34 | openmct.composition.addProvider({ 35 | appliesTo: function (object) { 36 | return object.identifier.namespace === 'demo' && 37 | object.composition !== undefined && 38 | (object.identifier.key === 'demo-objects' || 39 | demoModels[serializeId(object.identifier)] !== undefined); 40 | }, 41 | load: function (model) { 42 | var id = model.identifier; 43 | if (id.key === 'demo-objects') { 44 | return Promise.resolve(Object.keys(demoModels).filter(function (key) { 45 | return demoModels[key].location === 'demo:demo-objects'; 46 | }).map(function (key) { 47 | var childId = deserializeId(key); 48 | return { 49 | namespace: childId.namespace, 50 | key: childId.key 51 | }; 52 | })); 53 | } else { 54 | return Promise.resolve( 55 | demoModels[serializeId(id)].composition.map(function (key) { 56 | var childId = deserializeId(key); 57 | return { 58 | namespace: childId.namespace, 59 | key: childId.key 60 | } 61 | }) 62 | ); 63 | } 64 | } 65 | }); 66 | 67 | //3. Add object provider 68 | openmct.objects.addProvider('demo', { 69 | get: function (id) { 70 | if (id.key === 'demo-objects') { 71 | return Promise.resolve({ 72 | identifier: { 73 | key: 'demo-objects', 74 | namespace: 'demo' 75 | }, 76 | type: 'folder', 77 | location: 'ROOT', 78 | name: 'Demo Objects', 79 | composition: [] 80 | }); 81 | } else { 82 | return Promise.resolve(addIdentifier(demoModels[serializeId(id)], id)); 83 | } 84 | } 85 | }); 86 | } 87 | } 88 | } 89 | ); 90 | -------------------------------------------------------------------------------- /scripts/demo-time-conductor.js: -------------------------------------------------------------------------------- 1 | define([], function () { 2 | return function (options) { 3 | var REALTIME_SPACECRAFT_LAYOUT = '96592bba-a9f4-46d9-8d9f-a4efb45bcfc1'; 4 | var DEMO_NAMESPACE = 'demo'; 5 | var TUTORIAL_NAMESPACE = 'example.taxonomy'; 6 | var DEMO_ROOT = 'demo-objects'; 7 | var MSL_NAMESPACE = 'msl_tlm'; 8 | var MSL_LAYOUT = 'f3744144-8842-4b7a-bddc-4abbf21315d9'; 9 | var MSL_BOUNDS = { 10 | start: Date.parse('2012-08-06'), 11 | end: Date.now() 12 | }; 13 | 14 | return function install(openmct) { 15 | 16 | function isRealtimeObject(object) { 17 | var identifier = object.identifier; 18 | return identifier.namespace === TUTORIAL_NAMESPACE || 19 | identifier.key === REALTIME_SPACECRAFT_LAYOUT; 20 | } 21 | 22 | function isHistoricalObject(object) { 23 | var identifier = object.identifier; 24 | return identifier.namespace === MSL_NAMESPACE || 25 | identifier.key === MSL_LAYOUT; 26 | } 27 | 28 | openmct.on('navigation', function (object) { 29 | var o = object.useCapability('adapter'); 30 | 31 | if (isRealtimeObject(o)) { 32 | openmct.time.clock('local', { 33 | start: -15 * 60 * 1000, 34 | end: 0 35 | }); 36 | } else if (isHistoricalObject(o)) { 37 | setTimeout(function () { 38 | openmct.time.stopClock(); 39 | openmct.time.bounds(MSL_BOUNDS); 40 | }); 41 | } 42 | }); 43 | 44 | openmct.legacyExtension('runs', { 45 | depends: [ 46 | '$location' 47 | ], 48 | implementation: function ($location) { 49 | //For default route, redirect user to layout 50 | if ($location.path().length == 0 || $location.path() === "/") { 51 | $location.url("browse/" + DEMO_NAMESPACE + ":" + DEMO_ROOT + "/" + DEMO_NAMESPACE + ":" + REALTIME_SPACECRAFT_LAYOUT + "?view=layout"); 52 | } 53 | } 54 | }); 55 | } 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /scripts/demo-tour.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'hopscotch', 3 | 'text!./tour.json' 4 | ], function (hopscotch, tourConfig) { 5 | return function () { 6 | tourConfig = JSON.parse(tourConfig); 7 | return function (openmct) { 8 | openmct.legacyExtension('runs', { 9 | depends: ['agentService'], 10 | implementation: function (agentService) { 11 | if (!agentService.isMobile() && 12 | !window.opener) { 13 | setTimeout(function () { 14 | hopscotch.endTour(true); 15 | hopscotch.startTour(tourConfig); 16 | }, 3000); 17 | } 18 | } 19 | }); 20 | 21 | } 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /scripts/scaled-image.js: -------------------------------------------------------------------------------- 1 | define([], 2 | function () { 3 | return function (options){ 4 | return function install (openmct) { 5 | openmct.types.addType('image-include', { 6 | name: 'Image include', 7 | cssClass: 'icon-image', 8 | description: 'An image include that resizes to fit its container', 9 | views: [ 10 | 'image-view' 11 | ], 12 | form: [ 13 | { 14 | key: 'url', 15 | name: 'URL', 16 | control: 'textfield', 17 | pattern: '^(ftp|https?)\\:\\/\\/\\w+(\\.\\w+)*(\\:\\d+)?(\\/\\S*)*$', 18 | required: true, 19 | cssClass: 'l-input-lg' 20 | } 21 | ] 22 | }); 23 | openmct.legacyExtension('views', { 24 | template: '
', 25 | name: 'ImageInclude', 26 | type: 'image-include', 27 | key: 'image-view', 28 | editable: false 29 | }); 30 | } 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /scripts/tour.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "hello-hopscotch", 3 | "steps": [ 4 | { 5 | "title": "Welcome to Open MCT", 6 | "content": "This brief tour will introduce you to the main elements and concepts of the application. To cancel at any time, click the 'x' in the top right of this box, or click 'Next' to continue.", 7 | "target": "body", 8 | "placement": "top", 9 | "xOffset": "center", 10 | "yOffset": "center", 11 | "arrowOffset": "100000px" 12 | }, 13 | { 14 | "title": "Object Tree", 15 | "content": "This contains all the objects you have access to, including telemetry objects, prebuilt displays, and user-created objects. ", 16 | "target": "mct-tree ul.tree", 17 | "placement": "right" 18 | }, 19 | { 20 | "title": "View Area", 21 | "content": "This area shows the contents of a selected item. Different types of items provide different views of their contents.", 22 | "target": ".object-holder-main", 23 | "placement": "top", 24 | "xOffset": "center", 25 | "yOffset": "200px", 26 | "arrowOffset": "center" 27 | }, 28 | { 29 | "title": "Inspection Pane", 30 | "content": "This pane shows useful information about the currently selected item.", 31 | "target": ".split-pane-component.t-inspect", 32 | "placement": "left" 33 | }, 34 | { 35 | "title": "Search", 36 | "content": "Search filters items in the Object Tree by their name. You can also filter by object type by clicking the 'down' arrow in the right side of the input.", 37 | "target": ".search-bar", 38 | "placement": "right", 39 | "yOffset": "-20px" 40 | }, 41 | { 42 | "title": "Editing", 43 | "content": "This part of the tour will step you through editing an object. Click 'Next' to continue.", 44 | "target": "body", 45 | "placement": "top", 46 | "xOffset": "center", 47 | "yOffset": "center", 48 | "arrowOffset": "100000px" 49 | }, 50 | { 51 | "title": "Creating a New Object", 52 | "content": "We're going to create and edit a new Display Layout object. First, select the 'My Items' folder. Objects can be created and edited under 'My Items'. Click 'Next' when you're ready to continue.", 53 | "target": "mct-tree ul.tree", 54 | "placement": "right", 55 | "yOffset": "20px" 56 | }, 57 | { 58 | "title": "Create Button", 59 | "content": "Many objects in the application are created via this button. Click it now to view the Create menu, and rollover each item in the menu to see more information about it. Select Display Layout to begin editing a new Display Layout object. Click next to continue.", 60 | "target": ".create-button", 61 | "placement": "right", 62 | "yOffset": "-10px" 63 | }, 64 | { 65 | "title": "Editing", 66 | "content": "Each type of object can be edited in different ways. This Display Layout allows you to add, position, size and remove many different types of objects. ", 67 | "target": "body", 68 | "placement": "top", 69 | "xOffset": "center", 70 | "yOffset": "center", 71 | "arrowOffset": "100000px", 72 | "nextOnTargetClick": true 73 | }, 74 | { 75 | "title": "Adding an Object", 76 | "content": "Let’s add a telemetry element into our layout. Expand 'Example Rover', then drag 'Battery Temperature', into the empty space in the example layout, then click 'Next' to continue.", 77 | "target": "mct-tree ul.tree", 78 | "yOffset": "50px", 79 | "placement": "right" 80 | }, 81 | { 82 | "title": "Positioning and Resizing", 83 | "content": "Any object in a layout can be positioned and resized. Mouse over the object, and grab a corner and drag it to change the size. Click anywhere inside it, and drag it around to move it. When you’re done, click 'Next' to continue.", 84 | "target": ".object-holder-main", 85 | "placement": "right", 86 | "xOffset": "-200px" 87 | }, 88 | { 89 | "title": "Elements Pool", 90 | "content": "When the Object Inspector is expanded, this area lists all objects in the current object. To remove an object, right-click it and choose 'Remove' from the context menu.", 91 | "target": ".holder-elements", 92 | "placement": "left" 93 | }, 94 | { 95 | "title": "Saving", 96 | "content": "When you are done editing, click 'Save' to save and exit editing. To exit without saving any changes, click the 'X' button.", 97 | "target": ".t-save", 98 | "width": "200px", 99 | "placement": "bottom", 100 | "nextOnTargetClick": true 101 | }, 102 | { 103 | "title": "Object Types", 104 | "content": "Try experimenting by creating different object types, and adding objects to them by dragging them from the tree. Only certain types of objects can be dragged into a given object type - if a type of object can’t be added, it simply won’t. ", 105 | "target": "body", 106 | "placement": "top", 107 | "xOffset": "center", 108 | "yOffset": "center", 109 | "arrowOffset": "100000px" 110 | }, 111 | { 112 | "title": "Thank You", 113 | "content": "

That’s the end of the tour. Thanks for your time, and we hope you enjoy using and contributing to Open MCT!

To find out more about Open MCT, please visit our website -

https://nasa.github.io/openmct", 114 | "target": "body", 115 | "placement": "top", 116 | "xOffset": "center", 117 | "yOffset": "center", 118 | "arrowOffset": "100000px" 119 | }] 120 | } 121 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /*global require,process,console*/ 2 | 3 | /** 4 | * Usage: 5 | * 6 | * npm install minimist express 7 | * node app.js [options] 8 | */ 9 | 10 | (function () { 11 | "use strict"; 12 | 13 | var BUNDLE_FILE = 'bundles.json'; 14 | var options = require('minimist')(process.argv.slice(2)); 15 | var express = require('express'); 16 | var app = express(); 17 | require('express-ws')(app); 18 | 19 | var fs = require('fs'); 20 | var request = require('request'); 21 | var Rover = require('./rover.js'); 22 | var RealtimeServer = require('openmct-tutorials/example-server/realtime-server'); 23 | var HistoryServer = require('openmct-tutorials/example-server/history-server'); 24 | 25 | var proxyUrls = [ 26 | 'http://cab.inta-csic.es/rems/wp-content/plugins/marsweather-widget/api.php' 27 | ]; 28 | 29 | // Defaults 30 | options.port = process.env.PORT || options.port || options.p || 8080; 31 | options.directory = options.directory || options.D || '.'; 32 | ['include', 'exclude', 'i', 'x'].forEach(function (opt) { 33 | options[opt] = options[opt] || []; 34 | // Make sure includes/excludes always end up as arrays 35 | options[opt] = Array.isArray(options[opt]) ? 36 | options[opt] : [options[opt]]; 37 | }); 38 | 39 | // Show command line options 40 | if (options.help || options.h) { 41 | console.log("\nUsage: node server.js [options]\n"); 42 | console.log("Options:"); 43 | console.log(" --help, -h Show this message."); 44 | console.log(" --port, -p Specify port."); 45 | console.log(" --directory, -D Serve files from specified directory."); 46 | console.log(""); 47 | process.exit(0); 48 | } 49 | 50 | app.use('/proxyUrl', function proxyRequest(req, res, next) { 51 | if (proxyUrls.indexOf(req.query.url) !== -1) { 52 | res.header("Access-Control-Allow-Origin", "https://nasa.github.io"); 53 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 54 | 55 | console.log('Proxying request to: ', req.query.url); 56 | req.pipe(request({ 57 | url: req.query.url, 58 | strictSSL: false 59 | }).on('error', next)).pipe(res); 60 | } else { 61 | res.status(400).send(); 62 | } 63 | }); 64 | 65 | var spacecraft = new Rover(); 66 | var realtime = new RealtimeServer(spacecraft); 67 | var history = new HistoryServer(spacecraft); 68 | app.use('/realtime', realtime); 69 | app.use('/history', history); 70 | 71 | // Expose everything else as static files 72 | app.use(express['static'](options.directory)); 73 | // Finally, open the HTTP server 74 | app.listen(options.port, function () { 75 | console.log('Open MCT hosted at http://localhost:' + options.port); 76 | console.log('History hosted at http://localhost:' + options.port + '/history'); 77 | console.log('Realtime hosted at ws://localhost:' + options.port + '/realtime'); 78 | }); 79 | }()); 80 | --------------------------------------------------------------------------------