devagent-ignition 0.1.3__tar.gz → 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/PKG-INFO +1 -1
  2. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/SHA256SUMS.txt +7 -7
  3. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/operations_ui.js +24 -5
  4. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/three_scene.js +29 -1
  5. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/v076_fat_ui.js +6 -3
  6. devagent_ignition-0.1.5/devagent_spatial/__init__.py +1 -0
  7. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/preview_simulation.py +20 -0
  8. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/studio.py +2 -1
  9. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/v076_opc_fat.py +24 -5
  10. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/pyproject.toml +1 -1
  11. devagent_ignition-0.1.3/devagent_spatial/__init__.py +0 -1
  12. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/.gitignore +0 -0
  13. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/README.md +0 -0
  14. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/RELEASE_MANIFEST.json +0 -0
  15. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/SOURCE_PROVENANCE.json +0 -0
  16. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/agent.js +0 -0
  17. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator.css +0 -0
  18. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator_2d.mjs +0 -0
  19. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator_original_r9.mjs +0 -0
  20. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator_original_v8.mjs +0 -0
  21. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator_r9_diagnostics.mjs +0 -0
  22. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator_scene.mjs +0 -0
  23. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/creator_ui.mjs +0 -0
  24. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/customer_documents.js +0 -0
  25. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/equipment_controls.mjs +0 -0
  26. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/facility2d.css +0 -0
  27. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/facility2d_app.mjs +0 -0
  28. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/facility2d_core.mjs +0 -0
  29. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/facility2d_simulation.mjs +0 -0
  30. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/facility2d_viewer.html +0 -0
  31. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/fallback_scene.js +0 -0
  32. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/flow_geometry.mjs +0 -0
  33. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/harness.js +0 -0
  34. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/live_design_review.js +0 -0
  35. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/operator_viewer.html +0 -0
  36. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/project_package.js +0 -0
  37. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/r9_transport.mjs +0 -0
  38. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/runtime_feed.js +0 -0
  39. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/studio.html +0 -0
  40. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/style.css +0 -0
  41. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/test_workspace.html +0 -0
  42. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/unified_engineer.js +0 -0
  43. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/v078_command_ui.js +0 -0
  44. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/viewer.html +0 -0
  45. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/assets/viewer.js +0 -0
  46. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/design-system.json +0 -0
  47. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_hmi.py +0 -0
  48. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/agent_harness.py +0 -0
  49. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/agent_runtime.py +0 -0
  50. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/contract_opc_fat.py +0 -0
  51. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/contract_opc_source.py +0 -0
  52. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/control_intents.py +0 -0
  53. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/customer_intake.py +0 -0
  54. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/engineering_expertise.py +0 -0
  55. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/generator.py +0 -0
  56. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/ignition_native.py +0 -0
  57. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/ignition_project.py +0 -0
  58. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/live_lab_binding.py +0 -0
  59. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/model.py +0 -0
  60. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/native_reference.py +0 -0
  61. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/opc_snapshot.py +0 -0
  62. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/operations.py +0 -0
  63. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/operations_capture.py +0 -0
  64. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/operations_lab.py +0 -0
  65. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/original_r9.py +0 -0
  66. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/original_v8.py +0 -0
  67. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/preflight.py +0 -0
  68. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/project_package.py +0 -0
  69. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/qualification.py +0 -0
  70. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/strict_json.py +0 -0
  71. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/studio_workflow.py +0 -0
  72. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/test_reporting.py +0 -0
  73. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/v078_commands.py +0 -0
  74. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/v078_native_commands.py +0 -0
  75. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/v07_fat.py +0 -0
  76. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/v07_native.py +0 -0
  77. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/devagent_spatial/v083_native.py +0 -0
  78. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/CV101-command-contract-PENDING.json +0 -0
  79. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/cv101_guided.json +0 -0
  80. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/make_examples.py +0 -0
  81. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/single_floor.json +0 -0
  82. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/v0771_training_wizard.json +0 -0
  83. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/warehouse-3floor-standard-2d.json +0 -0
  84. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/warehouse-operations-synthetic.json +0 -0
  85. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/warehouse-v07-lab-bindings-PENDING.json +0 -0
  86. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/warehouse.json +0 -0
  87. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/examples/water.json +0 -0
  88. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/REFERENCE_SHA256.json +0 -0
  89. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/web/app.mjs +0 -0
  90. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/web/index.html +0 -0
  91. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/web/lab_panel.mjs +0 -0
  92. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/web/model.mjs +0 -0
  93. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/web/state_adapter.mjs +0 -0
  94. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-golden/web/styles.css +0 -0
  95. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/README_R9.md +0 -0
  96. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/SHA256SUMS.txt +0 -0
  97. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/SNAPSHOT_SHA256SUMS.txt +0 -0
  98. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/flow_routes.json +0 -0
  99. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/flow_sim.py +0 -0
  100. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/lab_control.py +0 -0
  101. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/app.mjs +0 -0
  102. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/index.html +0 -0
  103. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/lab_panel.mjs +0 -0
  104. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/model.mjs +0 -0
  105. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/state_adapter.mjs +0 -0
  106. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/styles.css +0 -0
  107. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/vendor/LICENSE-three.txt +0 -0
  108. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/vendor/SHA256SUMS.txt +0 -0
  109. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/vendor/addons/controls/OrbitControls.js +0 -0
  110. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/vendor/three.core.js +0 -0
  111. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/r9-original/web/vendor/three.module.js +0 -0
  112. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/README.md +0 -0
  113. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/SHA256SUMS.txt +0 -0
  114. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/model.py +0 -0
  115. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/run_demo.sh +0 -0
  116. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/server.py +0 -0
  117. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/tests/browser_smoke.py +0 -0
  118. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/tests/test_v8.py +0 -0
  119. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/topology.json +0 -0
  120. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/web/app.js +0 -0
  121. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/web/index.html +0 -0
  122. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/web/simulator.html +0 -0
  123. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/web/simulator.js +0 -0
  124. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/reference/v8-original/web/style.css +0 -0
  125. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/sample_customer_inputs/Plant_Equipment_Register.csv +0 -0
  126. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/sample_customer_inputs/Plant_Flow_Requirements.txt +0 -0
  127. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/sample_customer_inputs/Raw_PLC_Tag_Export.csv +0 -0
  128. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/templates/warehouse_connections.csv +0 -0
  129. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/templates/warehouse_equipment.csv +0 -0
  130. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/templates/warehouse_signals.csv +0 -0
  131. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/templates/water_connections.csv +0 -0
  132. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/templates/water_equipment.csv +0 -0
  133. {devagent_ignition-0.1.3 → devagent_ignition-0.1.5}/templates/water_signals.csv +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: devagent-ignition
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Offline industrial HMI engineering and Ignition Perspective candidate tools (production deployment not qualified)
5
5
  Project-URL: Repository, https://github.com/tomha85/devagent-ignition
6
6
  Project-URL: Documentation, https://github.com/tomha85/devagent-ignition#readme
@@ -83,7 +83,7 @@ ea11d9fe8c7702a73abf22a6d681db30bda2db80d481732dfa0ac824e87a1ce3 assets/fallbac
83
83
  a250a3277aec5347eafbb498222038e7063f8d56fe0b0e797426777f9a77d92d assets/flow_geometry.mjs
84
84
  29bd6b4e87460f13491f0c1830b656d894136411e9018e111b8c6230b9530264 assets/harness.js
85
85
  9c5cb2f70186e5b450cb8c0635d40e82ccdd4373279b19156b16e45f8280051b assets/live_design_review.js
86
- 714bf9bf226796a9a154c0fd8a6eaea23a840b0f636124b4ba00e2e33aa5e1c1 assets/operations_ui.js
86
+ 8111d6adc9083db4621bef2068827039ebff43080a7af428bd3c0ec48d61e36c assets/operations_ui.js
87
87
  cd369a2d284b50177ee947adac54a47b035e288bcbda5c47486e2cf6720e42c5 assets/operator_viewer.html
88
88
  651aba65c955883581268e7aa9e07b25fe3a77a2a5140338a624aa32feaba21d assets/project_package.js
89
89
  8e5d8505ac3c84df822ff90c9d04083ce6dece4e51448a84e72dfaddda47bac0 assets/r9_transport.mjs
@@ -91,15 +91,15 @@ c6b47941a2ffe72d297d329899b252f898904a0f37c1592689eeb81e0815147c assets/runtime
91
91
  6f0dcc9f218455b708552daa0536b2afb2d68b4095a1a6956f2147c329a6ff2f assets/studio.html
92
92
  c9f87624386bbe84ab7d71f93708f00f91a69e0d9693738cfee51913e5831fdf assets/style.css
93
93
  fd0d07ddec872de25c4e485573d5aa5b0c7a2c3137a93e65c6406b637fad7ad7 assets/test_workspace.html
94
- d7b86f7cf6d22e08f2fe00c593db9d20ddf9e46bdb945781d8afea7af3ff2688 assets/three_scene.js
94
+ 4377c0980f62a4c9605c9a040424d8c5904bd8312aa204b0697a493cccd074ee assets/three_scene.js
95
95
  af23f86ef51e18dfc94355e77fe9fb52570db14466d05d6dadededf17458fe25 assets/unified_engineer.js
96
- 4fdffe6e9fb2af75745b8e8413b7eaf416e61952c8c82befde8b584fb6799f90 assets/v076_fat_ui.js
96
+ 531c378fe3aae0c1d0686da48d7a4eba371ca7641b343b952dc8448f1cf65dc1 assets/v076_fat_ui.js
97
97
  d009f79a79ed1278911c81818b97a7dbce72464b599bb00f6116b81e1b1f9b5c assets/v078_command_ui.js
98
98
  9d95941755b73fc16aaa0ef8af0550ee64f15d60d6f3792eb00d82844a48a75b assets/viewer.html
99
99
  600d23649659fd9b435e6b828a5b191b95cae721784b2eed4d7594b783b56681 assets/viewer.js
100
100
  54ee77ca35589b06bd093204c9e5b28eabb69a8b2158ef1be5897386d3676c3f design-system.json
101
101
  287744606d4ec09533bb0af2ab6c1e059e614a7d87bc8c365d0f1e16c646bff8 devagent_hmi.py
102
- b99b3280c5cc291c3eeea856a230239e99bc1853d753ddb15ba5c0f0ee46c056 devagent_spatial/__init__.py
102
+ 0d08971ea4370b6f5fffefb27bb6953033e7213ae5f4cd33314e362d8638f331 devagent_spatial/__init__.py
103
103
  a6b1a2a97e2ec31e2de7f4c576b9482f66d3aa7fb356b06f0475bcd221dd8116 devagent_spatial/agent_harness.py
104
104
  a54c22bb64e5ff6b8d720bc44a73d851388f3f55adcba0f5f17098349895f2a4 devagent_spatial/agent_runtime.py
105
105
  f57e58f596ab5395b5a9692158cca43866de32ec9f8d07bdec363a36610e3d2b devagent_spatial/contract_opc_fat.py
@@ -120,14 +120,14 @@ cae72ca33644c7715faf49da021b221ff0a9c494803ba2893cc0fb66a6c19462 devagent_spati
120
120
  d013f40d6a913126b7466fccfb97617f249e655ce1d5183d8d21e47f81a7e2d4 devagent_spatial/original_r9.py
121
121
  16a779d62303d739e7cfe3fb885004e774aa84b57a8ca6cb39d43c4ae356ef53 devagent_spatial/original_v8.py
122
122
  3f8560455c11c3196c306c26ad1d5cc1f0754ebfc9182ad256cbfffed3178731 devagent_spatial/preflight.py
123
- 9242b928c54a1def044c8537bcc7c2201892a381b50f61ac3eb2a5d0222be30e devagent_spatial/preview_simulation.py
123
+ 724bb194a3d80297eb57f5839049d52de03c2c1fbe4a5a47f150acaa144e2264 devagent_spatial/preview_simulation.py
124
124
  b63c232a9218a6c7dc350f8510af0ccb9d7af61b6ffbc448918ae0a4beaef07d devagent_spatial/project_package.py
125
125
  74cbfb179c33304851dade43687d6ff7075d72305e696dab7d5de126b0ec253e devagent_spatial/qualification.py
126
126
  05b93e0f13f2e59251bed066975944a3a21f084a6447ea5607c8620c0e489aef devagent_spatial/strict_json.py
127
- 0a452313484154d2faa1d0d1eb5041c6f10db2698fc2b867e0800522c915ecfa devagent_spatial/studio.py
127
+ 050f4c23b07ae54367626777a50c771233bae60c0217f3f74c5c6f08d6c5348e devagent_spatial/studio.py
128
128
  7f58410cba0fd20fbeb9be75b0afdad2bb443eb361eb510a9fd78d250145e21e devagent_spatial/studio_workflow.py
129
129
  e8058af1dbe09d877700144b41451440c0fee4602fffcf658b497b34efe9b30b devagent_spatial/test_reporting.py
130
- 8bf0d6d6ba213e0623c1115e5fa29a6a7eae0e510a4921a63727f447b95dfaf6 devagent_spatial/v076_opc_fat.py
130
+ 4a712465d91b0c93a4d0d13569dc6fb96b5d7ec7cef7da3d643fc56768c257b1 devagent_spatial/v076_opc_fat.py
131
131
  ae48eeebcc0e1df2a93bca41d6344c17c66b19ef8b492f6af41d7cdd554b863f devagent_spatial/v078_commands.py
132
132
  ba2b1147d1871266c6150e229a35fc4132ab492860d2fae40ccc8a31f1424db6 devagent_spatial/v078_native_commands.py
133
133
  4269e8b41f06982b99ac6f0d6d7a2a027e3bb24456f5752c1f6fb8f879f72ae2 devagent_spatial/v07_fat.py
@@ -7,7 +7,7 @@ export function installOperations({model,selectAsset,scene,policy}) {
7
7
  no_reads:'noread',total_scans:'scans',
8
8
  parcels_in_transit:'transit', delivered:'delivered',last_scan_result:'scanresult',last_barcode:'barcode',
9
9
  signal_health:'quality'};
10
- let receipt=null,frameNumber=0,labLive=false,syntheticMode=false,virtualPE=new Map(),simAcknowledged=false,simFaultAsset=null;
10
+ let receipt=null,frameNumber=0,labLive=false,syntheticMode=false,virtualPE=new Map(),equipmentStates=new Map(),simAcknowledged=false,simFaultAsset=null;
11
11
  for(const [key,definition] of Object.entries(policy.metrics)){
12
12
  if(!definition.supported && ids[key]){
13
13
  const kpi=$('kpi-'+ids[key]);if(kpi?.closest)kpi.closest('.ops-metric').hidden=true;
@@ -113,14 +113,15 @@ export function installOperations({model,selectAsset,scene,policy}) {
113
113
  // Parameter rows are customer-mapped values only. Never infer PE IN/OUT or
114
114
  // derive belt velocity from VFD Hz without approved mechanical parameters.
115
115
  const asset=model.equipment.find(e=>e.id===selected),params=$('selected-parameters');
116
+ const demo=syntheticMode?equipmentStates.get(selected):null;
116
117
  if(asset&&params){
117
118
  const find=role=>states.find(x=>x.role===role);
118
119
  const val=(role,renderValue)=>{const x=find(role);return x?.valid ? renderValue(x) : 'UNKNOWN / N/A';};
119
120
  const rows=[];const row=(name,value)=>{const el=document.createElement('div');el.className='detail-row';
120
121
  const k=document.createElement('label');k.textContent=name;const v=document.createElement('strong');v.textContent=String(value);el.append(k,v);rows.push(el);};
121
122
  if(['conveyor','sorter','spiral'].includes(asset.kind)){
122
- row('RUN FEEDBACK',val('run_feedback',x=>x.value===true?'RUNNING':'STOPPED'));
123
- row('MOTOR FAULT',val('fault',x=>x.active===true?'FAULT':'CLEAR'));
123
+ row('RUN FEEDBACK',demo?.motor_run_sim===null||!demo?'UNKNOWN / N/A':(demo.motor_run_sim?'RUNNING · SIM':'STOPPED · SIM'));
124
+ row('MOTOR FAULT',demo?.motor_fault_sim===null||!demo?'UNKNOWN / N/A':(demo.motor_fault_sim?'FAULT · SIM':'CLEAR · SIM'));
124
125
  const ports=syntheticMode?virtualPE.get(asset.id):null;
125
126
  row(syntheticMode?'PE IN · SIM':'PE IN',ports?(ports.pe_in?'BLOCKED':'CLEAR'):'NOT MAPPED');
126
127
  row(syntheticMode?'PE OUT · SIM':'PE OUT',ports?(ports.pe_out?'BLOCKED':'CLEAR'):'NOT MAPPED');
@@ -170,6 +171,14 @@ export function installOperations({model,selectAsset,scene,policy}) {
170
171
  }
171
172
  params.replaceChildren(...rows);
172
173
  }
174
+ if(syntheticMode&&demo){
175
+ const status=[...$('asset-meta').children].find(x=>x.firstElementChild?.textContent==='STATUS');
176
+ if(status)status.lastElementChild.textContent=demo.status+' · SIM';
177
+ const quality=[...$('asset-meta').children].find(x=>x.firstElementChild?.textContent==='DATA QUALITY');
178
+ if(quality)quality.lastElementChild.textContent='SYNTHETIC PREVIEW · NOT PLC';
179
+ }
180
+ const virtualState=syntheticMode?virtualPE: new Map();
181
+ scene()?.syntheticPorts?.(virtualState);
173
182
  const note=$('selected-mapping-note');
174
183
  if(note&&['conveyor','sorter','spiral'].includes(asset?.kind))
175
184
  note.textContent=syntheticMode?'PE IN/OUT are VIRTUAL SIMULATOR PORTS, not customer-mapped sensors.':'PE IN/OUT need approved sensor-to-conveyor mappings.';
@@ -248,7 +257,7 @@ export function installOperations({model,selectAsset,scene,policy}) {
248
257
  }
249
258
  validateReceipt(result.receipt);
250
259
  if(result.receipt.origin!=='ISOLATED_LAB_OPC_READ_ONLY')throw Error('LAB_RECEIPT_ORIGIN_HOLD');
251
- receipt=result.receipt;labLive=true;syntheticMode=false;virtualPE.clear();simAcknowledged=false;simFaultAsset=null;frameNumber=receipt.frames.length-1;scene()?.parcels?.([]);render();
260
+ receipt=result.receipt;labLive=true;syntheticMode=false;virtualPE.clear();equipmentStates.clear();scene()?.syntheticPorts?.(new Map());simAcknowledged=false;simFaultAsset=null;frameNumber=receipt.frames.length-1;scene()?.parcels?.([]);render();
252
261
  if($('ops-upload'))$('ops-upload').disabled=true;
253
262
  },
254
263
  applySyntheticReading:result=>{
@@ -265,12 +274,22 @@ export function installOperations({model,selectAsset,scene,policy}) {
265
274
  if(result.virtual_pe.length>transport.size||new Set(result.virtual_pe.map(x=>x.asset_id)).size!==result.virtual_pe.length||
266
275
  result.virtual_pe.some(x=>!transport.has(x.asset_id)||typeof x.pe_in!=='boolean'||typeof x.pe_out!=='boolean'))throw Error('VIRTUAL_PE_UNDECLARED_ASSET');
267
276
  virtualPE=new Map(result.virtual_pe.map(x=>[x.asset_id,x]));
277
+ if(result.equipment_states_source!=='SYNTHETIC_PREVIEW_NOT_PLC'||!Array.isArray(result.equipment_states)||
278
+ result.equipment_states.length!==model.equipment.length||
279
+ new Set(result.equipment_states.map(x=>x.asset_id)).size!==model.equipment.length||
280
+ result.equipment_states.some(x=>!model.equipment.some(e=>e.id===x.asset_id&&e.kind===x.kind)||
281
+ x.source!=='SYNTHETIC_PREVIEW_NOT_PLC'||!['RUNNING','STOPPED','FAULT','NOT_SIMULATED'].includes(x.status)||
282
+ ![true,false,null].includes(x.motor_run_sim)||![true,false,null].includes(x.motor_fault_sim)||
283
+ ![true,false,null].includes(x.pe_in_sim)||![true,false,null].includes(x.pe_out_sim)||
284
+ x.vfd_frequency_hz_sim!==null||x.motor_current_a_sim!==null||
285
+ x.motor_rpm_sim!==null||x.belt_speed_mps_sim!==null))throw Error('INVALID_SYNTHETIC_EQUIPMENT_STATES');
286
+ equipmentStates=new Map(result.equipment_states.map(x=>[x.asset_id,x]));
268
287
  simAcknowledged=result.acknowledged===true;simFaultAsset=typeof result.fault_asset==='string'?result.fault_asset:null;
269
288
  receipt=result.receipt;labLive=true;syntheticMode=true;frameNumber=receipt.frames.length-1;
270
289
  scene()?.parcels?.(result.parcels);render();
271
290
  },
272
291
  sourceUnavailable:()=>{
273
- receipt=null;labLive=false;syntheticMode=false;virtualPE.clear();simAcknowledged=false;simFaultAsset=null;frameNumber=0;
292
+ receipt=null;labLive=false;syntheticMode=false;virtualPE.clear();equipmentStates.clear();scene()?.syntheticPorts?.(new Map());simAcknowledged=false;simFaultAsset=null;frameNumber=0;
274
293
  scene()?.parcels?.([]);
275
294
  if($('ops-upload'))$('ops-upload').disabled=true;
276
295
  scene()?.alarms?.([]);scene()?.operatingStates?.([]);
@@ -341,6 +341,34 @@ export async function startThree(model,host,onSelect){
341
341
  }
342
342
  }
343
343
 
344
+ // Synthetic PE indicators are separate overlays, never recolor hardware or
345
+ // represent a commissioned physical photoeye-to-conveyor association.
346
+ const syntheticPortMarkers=new Map();
347
+ function syntheticPorts(ports){
348
+ for(const arr of syntheticPortMarkers.values())for(const o of arr){
349
+ scene.remove(o);o.geometry.dispose();o.material.dispose();
350
+ }
351
+ syntheticPortMarkers.clear();
352
+ if(!(ports instanceof Map))return;
353
+ for(const [id,state] of ports){
354
+ const e=model.equipment.find(x=>x.id===id);
355
+ if(!e||!assets.has(id)||!state||
356
+ typeof state.pe_in!=='boolean'||typeof state.pe_out!=='boolean')continue;
357
+ const marks=[];
358
+ for(const [out,blocked] of [[false,state.pe_in],[true,state.pe_out]]){
359
+ const material=new T.MeshBasicMaterial({color:blocked?0xffc04d:0x3cbb8c,
360
+ transparent:true,opacity:.95,depthTest:false});
361
+ const marker=new T.Mesh(new T.SphereGeometry(.22,12,8),material);
362
+ const sign=out?1:-1;
363
+ marker.position.set(e.position.x+sign*Math.max(.35,e.dimensions.x*.34),
364
+ e.position.y+1.8,e.position.z);
365
+ marker.visible=visibleFloor==='all'||String(e.floor)===visibleFloor;
366
+ marker.userData.syntheticOnly=true;
367
+ scene.add(marker);marks.push(marker);
368
+ }
369
+ syntheticPortMarkers.set(id,marks);
370
+ }
371
+ }
344
372
  function alarms(entries){
345
373
  for(const old of replayRings.values()){scene.remove(old);old.geometry.dispose();old.material.dispose();}
346
374
  replayRings.clear();
@@ -438,5 +466,5 @@ export async function startThree(model,host,onSelect){
438
466
  renderer.render(scene,camera);requestAnimationFrame(frame);
439
467
  }requestAnimationFrame(frame);
440
468
  window.addEventListener('pagehide',()=>{active=false;obs.disconnect();renderer.dispose();},{once:true});
441
- return {select:selected,floor,view,focus,overview,alarms,operatingStates,parcels,mount:id=>sensorMounts[id]||null};
469
+ return {select:selected,floor,view,focus,overview,alarms,operatingStates,syntheticPorts,parcels,mount:id=>sensorMounts[id]||null};
442
470
  }
@@ -26,13 +26,16 @@ button.addEventListener('click',async()=>{
26
26
  finally{clearTimeout(timeout);}
27
27
  const result=await response.json();
28
28
  if(response.ok&&result.status==='PASS_LAB_OPC_PROTOCOL_ONLY'){
29
- state.textContent='Synthetic OPC UA protocol: '+result.cases_passed+'/'+result.cases_planned+
30
- ' readbacks PASS. Ignition HMI FAT: NOT VERIFIED. Production: HOLD. ';
29
+ const scope=result.test_scope==='SYNTHETIC_TRANSPORT_ONLY_NO_CUSTOMER_SIGNALS'
30
+ ? 'Transport-only synthetic equipment probes; NO customer signal mappings or device behaviors verified. '
31
+ : 'Synthetic protocol exercise of declared signal definitions; physical mappings NOT VERIFIED. ';
32
+ state.textContent=scope+'OPC UA: '+result.cases_passed+'/'+result.cases_planned+
33
+ ' TCP readbacks PASS. Ignition HMI FAT: NOT VERIFIED. Production: HOLD. ';
31
34
  if(result.report_url){const link=document.createElement('a');link.href=result.report_url;
32
35
  link.target='_blank';link.rel='noopener';link.textContent='Open lab evidence ↗';state.append(link);}
33
36
  }else{
34
37
  state.textContent='HOLD '+(result.reason||result.status||'UNKNOWN')+
35
- '. For a real fake OPC test install optional asyncua in the app Python environment. No pass was recorded.';
38
+ '. Synthetic OPC UA FAT did not complete; no PASS was recorded.';
36
39
  }
37
40
  }catch(e){state.textContent='HOLD: fake OPC UA protocol test unavailable. No FAT PASS.';}
38
41
  finally{busy=false;button.disabled=false;}
@@ -0,0 +1 @@
1
+ __version__ = '0.1.5'
@@ -153,6 +153,25 @@ class PreviewSimulator:
153
153
  (sensor['position']['z']-equipment[k]['position']['z'])**2,
154
154
  k) for k in run['path'] if equipment[k]['floor']==sensor['floor']]
155
155
  if candidates:virtual_sensor_owners[sensor['id']]=min(candidates)[1]
156
+ # Synthetic operator diagnostics use only deterministic preview state.
157
+ # Never infer motor RPM, VFD Hz, current or belt speed from parcel pace.
158
+ running=not run['paused'] and run['fault_asset'] is None
159
+ equipment_states=[]
160
+ for asset in model['equipment']:
161
+ kind=asset['kind'];aid=asset['id']
162
+ ports=gates.get(aid)
163
+ data={'asset_id':aid,'kind':kind,
164
+ 'status':'FAULT' if run['fault_asset']==aid else
165
+ ('RUNNING' if running and aid in run['path'] else
166
+ 'STOPPED' if aid in run['path'] else 'NOT_SIMULATED'),
167
+ 'source':'SYNTHETIC_PREVIEW_NOT_PLC',
168
+ 'motor_run_sim':running if aid in run['path'] else None,
169
+ 'motor_fault_sim':run['fault_asset']==aid if aid in run['path'] else None,
170
+ 'pe_in_sim':ports['in'] if ports else None,
171
+ 'pe_out_sim':ports['out'] if ports else None,
172
+ 'vfd_frequency_hz_sim':None,'motor_current_a_sim':None,
173
+ 'motor_rpm_sim':None,'belt_speed_mps_sim':None}
174
+ equipment_states.append(data)
156
175
  at=dt.datetime.now(dt.timezone.utc)
157
176
  # monotonic wall-clock for the operations engine, even on rapid requests
158
177
  if run['history']:
@@ -183,6 +202,7 @@ class PreviewSimulator:
183
202
  return {'status':'PASS_SYNTHETIC_PREVIEW_ONLY','source':'IN_MEMORY_SYNTHETIC_NOT_OPC',
184
203
  'authority':'PROJECT_SCOPED_DEMO_ONLY','receipt':receipt,'parcels':parcels,
185
204
  'virtual_pe':virtual_pe,'virtual_pe_source':'CONCEPTUAL_SYNTHETIC_PORTS_NOT_MAPPED',
205
+ 'equipment_states':equipment_states,'equipment_states_source':'SYNTHETIC_PREVIEW_NOT_PLC',
186
206
  'acknowledged':run['acknowledged'],
187
207
  'paused':run['paused'],'fault_asset':run['fault_asset'],
188
208
  'ignition':'NOT_VERIFIED','opc_verified':False,'production':'HOLD','opc_writes':False,
@@ -588,12 +588,13 @@ class StudioHandler(BaseHTTPRequestHandler):
588
588
  raise LabHold('LAB_BUSY')
589
589
  try:
590
590
  import asyncio
591
- result=asyncio.run(asyncio.wait_for(run_loopback_fat(model,port=4898),timeout=50))
591
+ result=asyncio.run(asyncio.wait_for(run_loopback_fat(model,port=4898,allow_transport_only=not bool(model['signals'])),timeout=50))
592
592
  rid=secrets.token_hex(6)
593
593
  from .studio_workflow import project_lab_dir
594
594
  save_new(project_lab_dir(self.server.workspace,pid)/'opc-fat'/('lab-opc-v076-'+rid+'.json'),result)
595
595
  result={'status':result['status'],'cases_passed':result['cases_passed'],
596
596
  'cases_planned':result['cases_planned'],
597
+ 'test_scope':result.get('test_scope','UNSPECIFIED'),
597
598
  'report_url':f'/api/v076-opc/{pid}/report/{rid}',
598
599
  'gateway':'NOT_VERIFIED','production':'HOLD'}
599
600
  return self.output(200 if result['status']=='PASS_LAB_OPC_PROTOCOL_ONLY' else 422,result)
@@ -26,12 +26,19 @@ class LabHold(ValueError):pass
26
26
  def model_hash(model):
27
27
  return hashlib.sha256(json.dumps(model,sort_keys=True,ensure_ascii=False,separators=(',',':')).encode()).hexdigest()
28
28
 
29
- def lab_manifest(model):
29
+ def lab_manifest(model, *, allow_transport_only=False):
30
30
  """Generate a separate synthetic mapping, never overwrite customer OPC identities."""
31
31
  if qualify(model)['status']=='HOLD':raise LabHold('ENGINEERING_MODEL_HOLD')
32
32
  signals=model['signals']
33
- if not signals:raise LabHold('LAB_HAS_NO_DECLARED_SIGNALS')
34
33
  if len(signals)>MAX_LAB_SIGNALS:raise LabHold('LAB_LIMIT_200_SIGNALS')
34
+ # No customer OPC mapping? Probe protocol transport using explicit, synthetic
35
+ # equipment-identity fixtures only. This is NOT a photoeye, VFD, run/fault,
36
+ # scanner or other operational signal test.
37
+ transport_only=not signals and allow_transport_only is True
38
+ if not signals and not transport_only:
39
+ raise LabHold('LAB_HAS_NO_DECLARED_SIGNALS')
40
+ if transport_only and not model['equipment']:
41
+ raise LabHold('LAB_HAS_NO_EQUIPMENT_FOR_SYNTHETIC_PROBE')
35
42
  digest=model_hash(model)
36
43
  uri=LAB_URI_PREFIX+digest[:16]
37
44
  rows=[]
@@ -45,7 +52,18 @@ def lab_manifest(model):
45
52
  'production_namespace_uri':None,'production_node_id':None,
46
53
  'binding_review':'PENDING_ENGINEER_REVIEW',
47
54
  'source':'GENERATED_SYNTHETIC_LAB_NOT_CUSTOMER_MAPPING'})
55
+ if transport_only:
56
+ for equipment in model['equipment'][:MAX_LAB_SIGNALS]:
57
+ eid=equipment['id']
58
+ rows.append({'signal_id':'LAB_PROBE_'+eid,'equipment_id':eid,
59
+ 'role':'lab_transport_probe','datatype':'Boolean',
60
+ 'lab_namespace_uri':uri,'lab_node_id':'LAB/PROBE/'+eid,
61
+ 'ignition_lab_tag_path':None,
62
+ 'production_namespace_uri':None,'production_node_id':None,
63
+ 'binding_review':'NOT_A_PHYSICAL_MAPPING',
64
+ 'source':'GENERATED_SYNTHETIC_TRANSPORT_PROBE_ONLY'})
48
65
  return {'schema':'devagent.opc.synthetic_manifest.v076','status':'PLAN_ONLY_NOT_EXECUTED',
66
+ 'test_scope':'SYNTHETIC_TRANSPORT_ONLY_NO_CUSTOMER_SIGNALS' if transport_only else 'SYNTHETIC_DECLARED_SIGNAL_PROTOCOL',
49
67
  'model_sha256':digest,'lab_namespace_uri':uri,'signals':rows,
50
68
  'physical_mapping':'NOT_VERIFIED','ignition_binding':'NOT_CONFIGURED',
51
69
  'production_release':'HOLD','write_authority':'DISABLED'}
@@ -91,14 +109,14 @@ def _verified_phase(manifest,step,readbacks):
91
109
  'actual_value_recorded':False})
92
110
  return cases,failures
93
111
 
94
- async def run_loopback_fat(model,port:int=4898):
112
+ async def run_loopback_fat(model,port:int=4898,*,allow_transport_only=False):
95
113
  """Create OPC UA server on loopback, stimulate synthetic signals, read with a client.
96
114
 
97
115
  All nodes are read-only to clients; writes only occur from this server process.
98
116
  Does not import to Ignition or touch any customer PLC. Returns fail-closed.
99
117
  """
100
118
  if type(port) is not int or not 1024<=port<=65535:raise LabHold('LAB_PORT_INVALID')
101
- manifest=lab_manifest(model)
119
+ manifest=lab_manifest(model,allow_transport_only=allow_transport_only)
102
120
  try:
103
121
  from asyncua import Client, Server, ua
104
122
  except ImportError as exc:raise LabHold('ASYNCUA_NOT_INSTALLED') from exc
@@ -158,6 +176,7 @@ async def run_loopback_fat(model,port:int=4898):
158
176
  return {'schema':'devagent.fat.lab_run.v076',
159
177
  'status':'PASS_LAB_OPC_PROTOCOL_ONLY' if passed else 'FAIL_LAB_OPC_PROTOCOL',
160
178
  'model_sha256':manifest['model_sha256'],
179
+ 'test_scope':manifest['test_scope'],
161
180
  'lab_namespace_uri':manifest['lab_namespace_uri'],
162
181
  'opc_endpoint_scope':'LOOPBACK_ONLY','source':'SYNTHETIC_NOT_CUSTOMER',
163
182
  'cases_planned':len(manifest['signals'])*3,
@@ -169,7 +188,7 @@ async def run_loopback_fat(model,port:int=4898):
169
188
  'ignition_gateway':'NOT_VERIFIED','perspective_hmi':'NOT_VERIFIED',
170
189
  'physical_mapping':'NOT_VERIFIED','production_release':'HOLD',
171
190
  'recorded_utc':dt.datetime.now(dt.timezone.utc).isoformat(),
172
- 'qualification_boundary':'OPC protocol synthetic fixtures only; no machine process, Ignition FAT or PLC proof.'}
191
+ 'qualification_boundary':'OPC protocol synthetic fixtures only; no machine process, signal mapping, Ignition FAT or PLC proof.'}
173
192
 
174
193
  def save_new(path:Path,data:dict):
175
194
  path=Path(path)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "devagent-ignition"
7
- version = "0.1.3"
7
+ version = "0.1.5"
8
8
  description = "Offline industrial HMI engineering and Ignition Perspective candidate tools (production deployment not qualified)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13,<3.14"
@@ -1 +0,0 @@
1
- __version__ = '0.1.3'