PyAutomationIO 2.0.13__tar.gz → 2.1.0__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.
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/PKG-INFO +1 -1
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/PyAutomationIO.egg-info/PKG-INFO +1 -1
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/PyAutomationIO.egg-info/SOURCES.txt +5 -1
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/core.py +282 -6
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/__init__.py +2 -1
- pyautomationio-2.1.0/automation/dbmodels/linear_referencing_geospatial.py +156 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/tags.py +8 -0
- pyautomationio-2.0.13/automation/hmi/assets/index-CFaA_HVS.js → pyautomationio-2.1.0/automation/hmi/assets/index-Bq8WzzWp.js +75 -75
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/index.html +1 -1
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/datalogger.py +124 -39
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/managers/db.py +2 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/__init__.py +3 -1
- pyautomationio-2.1.0/automation/modules/linear_referencing/__init__.py +1 -0
- pyautomationio-2.1.0/automation/modules/linear_referencing/resources/__init__.py +7 -0
- pyautomationio-2.1.0/automation/modules/linear_referencing/resources/linear_referencing_geospatial.py +246 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/tags/resources/tags.py +35 -3
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tags/cvt.py +42 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tags/tag.py +23 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tests/test_core.py +94 -1
- pyautomationio-2.1.0/version.py +2 -0
- pyautomationio-2.0.13/version.py +0 -2
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/LICENSE +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/MANIFEST.in +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/PyAutomationIO.egg-info/dependency_links.txt +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/PyAutomationIO.egg-info/requires.txt +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/PyAutomationIO.egg-info/top_level.txt +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/README.md +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/alarms/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/alarms/states.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/alarms/trigger.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/buffer.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/core.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/events.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/logs.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/machines.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/opcua.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/opcua_server.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/dbmodels/users.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/extensions/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/extensions/api.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/extensions/cors.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/filter/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/bootstrap-icons-BeopsB42.woff +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/bootstrap-icons-mSm7cUeB.woff2 +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-brands-400-D1LuMI3I.ttf +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-brands-400-D_cYUPeE.woff2 +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-regular-400-BjRzuEpd.woff2 +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-regular-400-DZaxPHgR.ttf +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-solid-900-CTAAxXor.woff2 +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-solid-900-D0aA9rwL.ttf +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-v4compatibility-C9RhG_FT.woff2 +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/fa-v4compatibility-CCth-dXg.ttf +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/assets/index-fe9Q2n8A.css +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/90/302/260 curve 2.svg" +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/Analog gauge.svg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/Cool pump.svg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/Hand valve 4.svg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/Mass flowmeter.svg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/Short horizontal pipe.svg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/hmi/industrial_pallete_icons/Tank 16.svg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/iad/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/iad/frozen_data.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/iad/out_of_range.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/iad/outliers.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/core.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/events.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/logdict.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/logs.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/machines.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/opcua_server.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/logger/users.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/managers/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/managers/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/managers/opcua_client.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/managers/state_machine.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/models.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/alarms/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/alarms/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/alarms/resources/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/alarms/resources/summary.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/database/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/database/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/database/resources/database.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/events/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/events/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/events/resources/events.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/events/resources/logs.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/health/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/health/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/health/resources/health.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/machines/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/machines/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/machines/resources/machines.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/opcua/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/opcua/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/opcua/resources/clients.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/opcua/resources/server.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/settings/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/settings/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/settings/resources/settings.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/tags/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/tags/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/resources/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/resources/models/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/resources/models/roles.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/resources/models/users.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/resources/roles.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/resources/users.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/roles.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/modules/users/users.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/opcua/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/opcua/models.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/opcua/subscription.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/alarms_history.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/assets/styles.css +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/alarms_summary.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/db.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/filter.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/machines.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/machines_detailed.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/opcua.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/opcua_server.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/tags.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/callbacks/trends.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/communications.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/alarms_summary.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/database.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/gaussian_filter.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/machines.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/opcua.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/opcua_server.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/tags.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/components/trends.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/database.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/filter.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/machines.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/machines_detailed.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/main.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/opcua_server.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/tags.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/pages/trends.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/singleton.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/state_machine.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tags/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tags/filter.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tests/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tests/test_alarms.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tests/test_opcua_serialization.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tests/test_unit.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/tests/test_user.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/utils/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/utils/decorators.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/utils/observer.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/utils/units.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/adimentional.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/current.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/density.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/eng_time.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/force.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/length.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/mass.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/mass_flow.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/percentage.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/power.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/pressure.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/temperature.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/volume.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/variables/volumetric_flow.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/workers/__init__.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/workers/logger.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/workers/state_machine.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/automation/workers/worker.py +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/requirements.txt +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/setup.cfg +0 -0
- {pyautomationio-2.0.13 → pyautomationio-2.1.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyAutomationIO
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A python framework to develop automation industrial processes applications and Artificial Intelligence applications for the industrial field
|
|
5
5
|
Home-page: https://github.com/know-ai/PyAutomation
|
|
6
6
|
Author: KnowAI
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyAutomationIO
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A python framework to develop automation industrial processes applications and Artificial Intelligence applications for the industrial field
|
|
5
5
|
Home-page: https://github.com/know-ai/PyAutomation
|
|
6
6
|
Author: KnowAI
|
|
@@ -22,6 +22,7 @@ automation/dbmodels/__init__.py
|
|
|
22
22
|
automation/dbmodels/alarms.py
|
|
23
23
|
automation/dbmodels/core.py
|
|
24
24
|
automation/dbmodels/events.py
|
|
25
|
+
automation/dbmodels/linear_referencing_geospatial.py
|
|
25
26
|
automation/dbmodels/logs.py
|
|
26
27
|
automation/dbmodels/machines.py
|
|
27
28
|
automation/dbmodels/opcua.py
|
|
@@ -43,7 +44,7 @@ automation/hmi/assets/fa-solid-900-CTAAxXor.woff2
|
|
|
43
44
|
automation/hmi/assets/fa-solid-900-D0aA9rwL.ttf
|
|
44
45
|
automation/hmi/assets/fa-v4compatibility-C9RhG_FT.woff2
|
|
45
46
|
automation/hmi/assets/fa-v4compatibility-CCth-dXg.ttf
|
|
46
|
-
automation/hmi/assets/index-
|
|
47
|
+
automation/hmi/assets/index-Bq8WzzWp.js
|
|
47
48
|
automation/hmi/assets/index-fe9Q2n8A.css
|
|
48
49
|
automation/hmi/industrial_pallete_icons/90° curve 2.svg
|
|
49
50
|
automation/hmi/industrial_pallete_icons/Analog gauge.svg
|
|
@@ -86,6 +87,9 @@ automation/modules/events/resources/logs.py
|
|
|
86
87
|
automation/modules/health/__init__.py
|
|
87
88
|
automation/modules/health/resources/__init__.py
|
|
88
89
|
automation/modules/health/resources/health.py
|
|
90
|
+
automation/modules/linear_referencing/__init__.py
|
|
91
|
+
automation/modules/linear_referencing/resources/__init__.py
|
|
92
|
+
automation/modules/linear_referencing/resources/linear_referencing_geospatial.py
|
|
89
93
|
automation/modules/machines/__init__.py
|
|
90
94
|
automation/modules/machines/resources/__init__.py
|
|
91
95
|
automation/modules/machines/resources/machines.py
|
|
@@ -357,6 +357,7 @@ class PyAutomation(Singleton):
|
|
|
357
357
|
node_namespace=str|type(None),
|
|
358
358
|
scan_time=int|float|type(None),
|
|
359
359
|
dead_band=int|float|type(None),
|
|
360
|
+
kp=int|float|type(None),
|
|
360
361
|
process_filter=bool,
|
|
361
362
|
gaussian_filter=bool,
|
|
362
363
|
gaussian_filter_threshold=float|int,
|
|
@@ -393,6 +394,7 @@ class PyAutomation(Singleton):
|
|
|
393
394
|
frozen_data_detection:bool=False,
|
|
394
395
|
segment:str|None="",
|
|
395
396
|
manufacturer:str|None="",
|
|
397
|
+
kp:float|None=None,
|
|
396
398
|
id:str=None,
|
|
397
399
|
user:User|None=None,
|
|
398
400
|
reload:bool=False,
|
|
@@ -490,6 +492,7 @@ class PyAutomation(Singleton):
|
|
|
490
492
|
frozen_data_detection=frozen_data_detection,
|
|
491
493
|
segment=segment,
|
|
492
494
|
manufacturer=manufacturer,
|
|
495
|
+
kp=kp,
|
|
493
496
|
id=id,
|
|
494
497
|
user=user
|
|
495
498
|
)
|
|
@@ -564,7 +567,7 @@ class PyAutomation(Singleton):
|
|
|
564
567
|
return self.cvt.get_tags()
|
|
565
568
|
|
|
566
569
|
@logging_error_handler
|
|
567
|
-
@validate_types(output=list)
|
|
570
|
+
@validate_types(manufacturer=str|None, segment=str|None, output=list)
|
|
568
571
|
def get_tags_list(self, manufacturer:str=None, segment:str=None)->list:
|
|
569
572
|
r"""
|
|
570
573
|
Retrieves a non-paginated list of tags with only name, display_unit, variable, display_name.
|
|
@@ -581,6 +584,240 @@ class PyAutomation(Singleton):
|
|
|
581
584
|
"""
|
|
582
585
|
return self.cvt.get_tags_filtered(manufacturer=manufacturer, segment=segment)
|
|
583
586
|
|
|
587
|
+
@logging_error_handler
|
|
588
|
+
@validate_types(kp_min=int|float, kp_max=int|float, output=list)
|
|
589
|
+
def get_tags_by_kp_range(self, kp_min:float, kp_max:float)->list:
|
|
590
|
+
r"""
|
|
591
|
+
Retrieves tags whose KP is between kp_min and kp_max (inclusive).
|
|
592
|
+
|
|
593
|
+
**Parameters:**
|
|
594
|
+
|
|
595
|
+
* **kp_min** (float): Lower KP bound.
|
|
596
|
+
* **kp_max** (float): Upper KP bound.
|
|
597
|
+
|
|
598
|
+
**Returns:**
|
|
599
|
+
|
|
600
|
+
* **list**: Serialized tags in the requested KP range.
|
|
601
|
+
"""
|
|
602
|
+
return self.cvt.get_tags_by_kp_range(kp_min=kp_min, kp_max=kp_max)
|
|
603
|
+
|
|
604
|
+
@logging_error_handler
|
|
605
|
+
@validate_types(segment_name=str, kp=int|float, latitude=int|float, longitude=int|float, elevation=int|float|type(None), output=tuple)
|
|
606
|
+
def create_linear_referencing_geospatial(
|
|
607
|
+
self,
|
|
608
|
+
segment_name:str,
|
|
609
|
+
kp:float,
|
|
610
|
+
latitude:float,
|
|
611
|
+
longitude:float,
|
|
612
|
+
elevation:float|None=None
|
|
613
|
+
)->tuple[dict|None, str]:
|
|
614
|
+
r"""
|
|
615
|
+
Creates a new linear-referencing geospatial point for a segment.
|
|
616
|
+
"""
|
|
617
|
+
if not self.is_db_connected():
|
|
618
|
+
return None, "Database not connected"
|
|
619
|
+
|
|
620
|
+
from .dbmodels import LinearReferencingGeospatial
|
|
621
|
+
point, message = LinearReferencingGeospatial.create(
|
|
622
|
+
segment_name=segment_name,
|
|
623
|
+
kp=kp,
|
|
624
|
+
latitude=latitude,
|
|
625
|
+
longitude=longitude,
|
|
626
|
+
elevation=elevation
|
|
627
|
+
)
|
|
628
|
+
if point is None:
|
|
629
|
+
return None, message
|
|
630
|
+
return point.serialize(), message
|
|
631
|
+
|
|
632
|
+
@logging_error_handler
|
|
633
|
+
@validate_types(output=list)
|
|
634
|
+
def get_linear_referencing_geospatial_points(self)->list:
|
|
635
|
+
r"""
|
|
636
|
+
Retrieves all linear-referencing geospatial points.
|
|
637
|
+
"""
|
|
638
|
+
if not self.is_db_connected():
|
|
639
|
+
return []
|
|
640
|
+
|
|
641
|
+
from .dbmodels import LinearReferencingGeospatial
|
|
642
|
+
return LinearReferencingGeospatial.read_all()
|
|
643
|
+
|
|
644
|
+
@logging_error_handler
|
|
645
|
+
@validate_types(segment_name=str, output=list)
|
|
646
|
+
def get_linear_referencing_geospatial_points_by_segment(self, segment_name:str)->list:
|
|
647
|
+
r"""
|
|
648
|
+
Retrieves linear-referencing points for a segment ordered by KP.
|
|
649
|
+
"""
|
|
650
|
+
if not self.is_db_connected():
|
|
651
|
+
return []
|
|
652
|
+
|
|
653
|
+
from .dbmodels import LinearReferencingGeospatial
|
|
654
|
+
query = LinearReferencingGeospatial.read_by_segment_name(segment_name=segment_name)
|
|
655
|
+
return [point.serialize() for point in query]
|
|
656
|
+
|
|
657
|
+
@logging_error_handler
|
|
658
|
+
@validate_types(id=int, output=dict|None)
|
|
659
|
+
def get_linear_referencing_geospatial_point(self, id:int)->dict|None:
|
|
660
|
+
r"""
|
|
661
|
+
Retrieves one linear-referencing geospatial point by ID.
|
|
662
|
+
"""
|
|
663
|
+
if not self.is_db_connected():
|
|
664
|
+
return None
|
|
665
|
+
|
|
666
|
+
from .dbmodels import LinearReferencingGeospatial
|
|
667
|
+
point = LinearReferencingGeospatial.read(id=id)
|
|
668
|
+
if point is None:
|
|
669
|
+
return None
|
|
670
|
+
return point.serialize()
|
|
671
|
+
|
|
672
|
+
@logging_error_handler
|
|
673
|
+
def update_linear_referencing_geospatial_point(self, id:int, **kwargs)->tuple[dict|None, str]:
|
|
674
|
+
r"""
|
|
675
|
+
Updates a linear-referencing geospatial point by ID.
|
|
676
|
+
"""
|
|
677
|
+
if not self.is_db_connected():
|
|
678
|
+
return None, "Database not connected"
|
|
679
|
+
|
|
680
|
+
from .dbmodels import LinearReferencingGeospatial, Segment
|
|
681
|
+
point = LinearReferencingGeospatial.read(id=id)
|
|
682
|
+
if point is None:
|
|
683
|
+
return None, f"Linear referencing geospatial point {id} not found"
|
|
684
|
+
|
|
685
|
+
fields = kwargs.copy()
|
|
686
|
+
if "segment_name" in fields:
|
|
687
|
+
segment_name = fields.pop("segment_name")
|
|
688
|
+
segment_obj = Segment.read_by_name(name=segment_name)
|
|
689
|
+
if segment_obj is None:
|
|
690
|
+
return None, f"Segment {segment_name} does not exist into database"
|
|
691
|
+
fields["segment"] = segment_obj
|
|
692
|
+
|
|
693
|
+
if not fields:
|
|
694
|
+
return point.serialize(), "No fields to update"
|
|
695
|
+
|
|
696
|
+
LinearReferencingGeospatial.put(id=id, **fields)
|
|
697
|
+
updated = LinearReferencingGeospatial.read(id=id)
|
|
698
|
+
return updated.serialize(), "Linear referencing geospatial point updated successfully"
|
|
699
|
+
|
|
700
|
+
@logging_error_handler
|
|
701
|
+
@validate_types(id=int, output=tuple)
|
|
702
|
+
def delete_linear_referencing_geospatial_point(self, id:int)->tuple[bool, str]:
|
|
703
|
+
r"""
|
|
704
|
+
Deletes a linear-referencing geospatial point by ID.
|
|
705
|
+
"""
|
|
706
|
+
if not self.is_db_connected():
|
|
707
|
+
return False, "Database not connected"
|
|
708
|
+
|
|
709
|
+
from .dbmodels import LinearReferencingGeospatial
|
|
710
|
+
rows = LinearReferencingGeospatial.delete_by_id(id=id)
|
|
711
|
+
if rows == 0:
|
|
712
|
+
return False, f"Linear referencing geospatial point {id} not found"
|
|
713
|
+
return True, "Linear referencing geospatial point deleted successfully"
|
|
714
|
+
|
|
715
|
+
@logging_error_handler
|
|
716
|
+
@validate_types(segment_name=str, kp=int|float, output=tuple)
|
|
717
|
+
def get_geospatial_by_segment_and_kp(self, segment_name:str, kp:float)->tuple[dict|None, str]:
|
|
718
|
+
r"""
|
|
719
|
+
Retrieves geospatial coordinates by segment and KP with interpolation support.
|
|
720
|
+
"""
|
|
721
|
+
if not self.is_db_connected():
|
|
722
|
+
return None, "Database not connected"
|
|
723
|
+
|
|
724
|
+
from .dbmodels import LinearReferencingGeospatial
|
|
725
|
+
return LinearReferencingGeospatial.interpolate_by_segment_and_kp(
|
|
726
|
+
segment_name=segment_name,
|
|
727
|
+
kp=kp
|
|
728
|
+
)
|
|
729
|
+
|
|
730
|
+
@logging_error_handler
|
|
731
|
+
@validate_types(rows=list, default_segment_name=str|type(None), update_existing=bool, output=dict)
|
|
732
|
+
def import_linear_referencing_profile(
|
|
733
|
+
self,
|
|
734
|
+
rows:list[dict],
|
|
735
|
+
default_segment_name:str|None=None,
|
|
736
|
+
update_existing:bool=True
|
|
737
|
+
)->dict:
|
|
738
|
+
r"""
|
|
739
|
+
Imports a complete linear-referencing profile from parsed rows (CSV/XLSX).
|
|
740
|
+
"""
|
|
741
|
+
result = {
|
|
742
|
+
"created": 0,
|
|
743
|
+
"updated": 0,
|
|
744
|
+
"skipped": 0,
|
|
745
|
+
"errors": []
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if not self.is_db_connected():
|
|
749
|
+
result["errors"].append("Database not connected")
|
|
750
|
+
return result
|
|
751
|
+
|
|
752
|
+
from .dbmodels import LinearReferencingGeospatial, Segment
|
|
753
|
+
|
|
754
|
+
for idx, row in enumerate(rows, start=1):
|
|
755
|
+
try:
|
|
756
|
+
segment_name = row.get("segment_name") or default_segment_name
|
|
757
|
+
if not segment_name:
|
|
758
|
+
result["errors"].append(f"Row {idx}: missing segment_name")
|
|
759
|
+
continue
|
|
760
|
+
|
|
761
|
+
segment_obj = Segment.read_by_name(name=segment_name)
|
|
762
|
+
if segment_obj is None:
|
|
763
|
+
result["errors"].append(f"Row {idx}: segment {segment_name} does not exist")
|
|
764
|
+
continue
|
|
765
|
+
|
|
766
|
+
if row.get("kp") is None:
|
|
767
|
+
result["errors"].append(f"Row {idx}: missing kp")
|
|
768
|
+
continue
|
|
769
|
+
if row.get("latitude") is None:
|
|
770
|
+
result["errors"].append(f"Row {idx}: missing latitude")
|
|
771
|
+
continue
|
|
772
|
+
if row.get("longitude") is None:
|
|
773
|
+
result["errors"].append(f"Row {idx}: missing longitude")
|
|
774
|
+
continue
|
|
775
|
+
|
|
776
|
+
kp = float(row.get("kp"))
|
|
777
|
+
latitude = float(row.get("latitude"))
|
|
778
|
+
longitude = float(row.get("longitude"))
|
|
779
|
+
elevation = row.get("elevation")
|
|
780
|
+
if elevation in ("", None):
|
|
781
|
+
elevation = None
|
|
782
|
+
else:
|
|
783
|
+
elevation = float(elevation)
|
|
784
|
+
|
|
785
|
+
current = LinearReferencingGeospatial.get_or_none(
|
|
786
|
+
(LinearReferencingGeospatial.segment == segment_obj)
|
|
787
|
+
& (LinearReferencingGeospatial.kp == kp)
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
if current is None:
|
|
791
|
+
point, message = LinearReferencingGeospatial.create(
|
|
792
|
+
segment_name=segment_name,
|
|
793
|
+
kp=kp,
|
|
794
|
+
latitude=latitude,
|
|
795
|
+
longitude=longitude,
|
|
796
|
+
elevation=elevation
|
|
797
|
+
)
|
|
798
|
+
if point is None:
|
|
799
|
+
result["errors"].append(f"Row {idx}: {message}")
|
|
800
|
+
else:
|
|
801
|
+
result["created"] += 1
|
|
802
|
+
else:
|
|
803
|
+
if not update_existing:
|
|
804
|
+
result["skipped"] += 1
|
|
805
|
+
continue
|
|
806
|
+
LinearReferencingGeospatial.put(
|
|
807
|
+
id=current.id,
|
|
808
|
+
latitude=latitude,
|
|
809
|
+
longitude=longitude,
|
|
810
|
+
elevation=elevation
|
|
811
|
+
)
|
|
812
|
+
result["updated"] += 1
|
|
813
|
+
|
|
814
|
+
except Exception as err:
|
|
815
|
+
result["errors"].append(f"Row {idx}: {str(err)}")
|
|
816
|
+
|
|
817
|
+
result["processed"] = len(rows)
|
|
818
|
+
result["success"] = len(result["errors"]) == 0
|
|
819
|
+
return result
|
|
820
|
+
|
|
584
821
|
@logging_error_handler
|
|
585
822
|
@validate_types(names=list, output=list)
|
|
586
823
|
def get_tags_by_names(self, names:list)->list[Tag|None]:
|
|
@@ -4274,7 +4511,7 @@ class PyAutomation(Singleton):
|
|
|
4274
4511
|
|
|
4275
4512
|
Exports configuration tables: Manufacturer, Segment, Variables, Units, DataTypes,
|
|
4276
4513
|
Tags, AlarmTypes, AlarmStates, Alarms, Roles, Users, OPCUA, AccessType,
|
|
4277
|
-
OPCUAServer, Machines, TagsMachines.
|
|
4514
|
+
OPCUAServer, Machines, TagsMachines, LinearReferencingGeospatial.
|
|
4278
4515
|
|
|
4279
4516
|
Excludes historical tables: TagValue, Events, Logs, AlarmSummary.
|
|
4280
4517
|
|
|
@@ -4301,7 +4538,7 @@ class PyAutomation(Singleton):
|
|
|
4301
4538
|
Manufacturer, Segment, Variables, Units, DataTypes,
|
|
4302
4539
|
Tags, AlarmTypes, AlarmStates, Alarms,
|
|
4303
4540
|
Roles, Users, OPCUA, AccessType, OPCUAServer,
|
|
4304
|
-
Machines, TagsMachines
|
|
4541
|
+
Machines, TagsMachines, LinearReferencingGeospatial
|
|
4305
4542
|
)
|
|
4306
4543
|
|
|
4307
4544
|
config = {
|
|
@@ -4328,7 +4565,8 @@ class PyAutomation(Singleton):
|
|
|
4328
4565
|
"AccessType": [at.serialize() for at in AccessType.select()],
|
|
4329
4566
|
"OPCUAServer": [os_obj.serialize() for os_obj in OPCUAServer.select()],
|
|
4330
4567
|
"Machines": [m.serialize() for m in Machines.select()],
|
|
4331
|
-
"TagsMachines": [tm.serialize() for tm in TagsMachines.select()]
|
|
4568
|
+
"TagsMachines": [tm.serialize() for tm in TagsMachines.select()],
|
|
4569
|
+
"LinearReferencingGeospatial": [lr.serialize() for lr in LinearReferencingGeospatial.select()]
|
|
4332
4570
|
}
|
|
4333
4571
|
}
|
|
4334
4572
|
|
|
@@ -4373,7 +4611,7 @@ class PyAutomation(Singleton):
|
|
|
4373
4611
|
Manufacturer, Segment, Variables, Units, DataTypes,
|
|
4374
4612
|
Tags, AlarmTypes, AlarmStates, Alarms,
|
|
4375
4613
|
Roles, Users, OPCUA, AccessType, OPCUAServer,
|
|
4376
|
-
Machines, TagsMachines
|
|
4614
|
+
Machines, TagsMachines, LinearReferencingGeospatial
|
|
4377
4615
|
)
|
|
4378
4616
|
|
|
4379
4617
|
results = {
|
|
@@ -4503,6 +4741,7 @@ class PyAutomation(Singleton):
|
|
|
4503
4741
|
manufacturer=manufacturer_name or "",
|
|
4504
4742
|
scan_time=item.get("scan_time"),
|
|
4505
4743
|
dead_band=item.get("dead_band"),
|
|
4744
|
+
kp=item.get("kp"),
|
|
4506
4745
|
active=item.get("active", True),
|
|
4507
4746
|
process_filter=item.get("process_filter", False),
|
|
4508
4747
|
gaussian_filter=item.get("gaussian_filter", False),
|
|
@@ -4520,7 +4759,44 @@ class PyAutomation(Singleton):
|
|
|
4520
4759
|
except Exception as e:
|
|
4521
4760
|
results["errors"].setdefault("Tags", []).append(f"{item.get('name', 'unknown')}: {str(e)}")
|
|
4522
4761
|
|
|
4523
|
-
# 7.
|
|
4762
|
+
# 7. LinearReferencingGeospatial (depends on Segment)
|
|
4763
|
+
if "LinearReferencingGeospatial" in data:
|
|
4764
|
+
for item in data["LinearReferencingGeospatial"]:
|
|
4765
|
+
try:
|
|
4766
|
+
segment_name = item.get("segment_name")
|
|
4767
|
+
if not segment_name:
|
|
4768
|
+
results["errors"].setdefault("LinearReferencingGeospatial", []).append(f"{item.get('id', 'unknown')}: Missing segment_name")
|
|
4769
|
+
continue
|
|
4770
|
+
|
|
4771
|
+
segment_obj = Segment.read_by_name(segment_name)
|
|
4772
|
+
if segment_obj is None:
|
|
4773
|
+
results["errors"].setdefault("LinearReferencingGeospatial", []).append(f"{item.get('id', 'unknown')}: Segment {segment_name} not found")
|
|
4774
|
+
continue
|
|
4775
|
+
|
|
4776
|
+
exists = LinearReferencingGeospatial.get_or_none(
|
|
4777
|
+
(LinearReferencingGeospatial.segment == segment_obj)
|
|
4778
|
+
& (LinearReferencingGeospatial.kp == item.get("kp"))
|
|
4779
|
+
)
|
|
4780
|
+
if exists is None:
|
|
4781
|
+
point, message = LinearReferencingGeospatial.create(
|
|
4782
|
+
segment_name=segment_name,
|
|
4783
|
+
kp=item.get("kp"),
|
|
4784
|
+
latitude=item.get("latitude"),
|
|
4785
|
+
longitude=item.get("longitude"),
|
|
4786
|
+
elevation=item.get("elevation")
|
|
4787
|
+
)
|
|
4788
|
+
if point is None:
|
|
4789
|
+
results["errors"].setdefault("LinearReferencingGeospatial", []).append(f"{item.get('id', 'unknown')}: {message}")
|
|
4790
|
+
else:
|
|
4791
|
+
results["imported"].setdefault("LinearReferencingGeospatial", 0)
|
|
4792
|
+
results["imported"]["LinearReferencingGeospatial"] += 1
|
|
4793
|
+
else:
|
|
4794
|
+
results["skipped"].setdefault("LinearReferencingGeospatial", 0)
|
|
4795
|
+
results["skipped"]["LinearReferencingGeospatial"] += 1
|
|
4796
|
+
except Exception as e:
|
|
4797
|
+
results["errors"].setdefault("LinearReferencingGeospatial", []).append(f"{item.get('id', 'unknown')}: {str(e)}")
|
|
4798
|
+
|
|
4799
|
+
# 8. AlarmTypes (no dependencies)
|
|
4524
4800
|
if "AlarmTypes" in data:
|
|
4525
4801
|
for item in data["AlarmTypes"]:
|
|
4526
4802
|
try:
|
|
@@ -20,4 +20,5 @@ from .users import Roles, Users
|
|
|
20
20
|
from .events import Events
|
|
21
21
|
from .logs import Logs
|
|
22
22
|
from .machines import Machines, TagsMachines
|
|
23
|
-
from .opcua_server import AccessType, OPCUAServer
|
|
23
|
+
from .opcua_server import AccessType, OPCUAServer
|
|
24
|
+
from .linear_referencing_geospatial import LinearReferencingGeospatial
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from peewee import ForeignKeyField, FloatField
|
|
2
|
+
from .core import BaseModel
|
|
3
|
+
from .tags import Segment
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LinearReferencingGeospatial(BaseModel):
|
|
7
|
+
r"""
|
|
8
|
+
Database model for geospatial linear-referencing points of a pipeline segment.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
segment = ForeignKeyField(Segment, backref='linear_referencing_points', on_delete='CASCADE')
|
|
12
|
+
kp = FloatField()
|
|
13
|
+
latitude = FloatField()
|
|
14
|
+
longitude = FloatField()
|
|
15
|
+
elevation = FloatField(null=True)
|
|
16
|
+
|
|
17
|
+
class Meta:
|
|
18
|
+
indexes = (
|
|
19
|
+
(('segment', 'kp'), True),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def create(
|
|
24
|
+
cls,
|
|
25
|
+
segment_name:str,
|
|
26
|
+
kp:float,
|
|
27
|
+
latitude:float,
|
|
28
|
+
longitude:float,
|
|
29
|
+
elevation:float=None
|
|
30
|
+
):
|
|
31
|
+
r"""
|
|
32
|
+
Creates a new linear-referencing geospatial point.
|
|
33
|
+
"""
|
|
34
|
+
segment_obj = Segment.read_by_name(name=segment_name)
|
|
35
|
+
if segment_obj is None:
|
|
36
|
+
return None, f"Segment {segment_name} does not exist into database"
|
|
37
|
+
|
|
38
|
+
duplicated = cls.get_or_none((cls.segment == segment_obj) & (cls.kp == kp))
|
|
39
|
+
if duplicated is not None:
|
|
40
|
+
return None, f"Duplicated linear referencing point: {segment_name} KP {kp}"
|
|
41
|
+
|
|
42
|
+
query = cls(
|
|
43
|
+
segment=segment_obj,
|
|
44
|
+
kp=kp,
|
|
45
|
+
latitude=latitude,
|
|
46
|
+
longitude=longitude,
|
|
47
|
+
elevation=elevation
|
|
48
|
+
)
|
|
49
|
+
query.save()
|
|
50
|
+
return query, "Linear referencing geospatial point created successfully"
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def read_by_segment_name(cls, segment_name:str):
|
|
54
|
+
r"""
|
|
55
|
+
Retrieves all points by segment name ordered by KP ascending.
|
|
56
|
+
"""
|
|
57
|
+
segment_obj = Segment.read_by_name(name=segment_name)
|
|
58
|
+
if segment_obj is None:
|
|
59
|
+
return []
|
|
60
|
+
query = cls.select().where(cls.segment == segment_obj).order_by(cls.kp.asc())
|
|
61
|
+
return query
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def delete_by_id(cls, id:int):
|
|
65
|
+
r"""
|
|
66
|
+
Deletes a point by its numeric ID.
|
|
67
|
+
"""
|
|
68
|
+
if not cls.id_exists(id):
|
|
69
|
+
return 0
|
|
70
|
+
query = cls.delete().where(cls.id == id)
|
|
71
|
+
return query.execute()
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def interpolate_by_segment_and_kp(cls, segment_name:str, kp:float):
|
|
75
|
+
r"""
|
|
76
|
+
Retrieves geospatial data by segment and KP using linear interpolation if needed.
|
|
77
|
+
"""
|
|
78
|
+
segment_obj = Segment.read_by_name(name=segment_name)
|
|
79
|
+
if segment_obj is None:
|
|
80
|
+
return None, f"Segment {segment_name} does not exist into database"
|
|
81
|
+
|
|
82
|
+
exact = cls.get_or_none((cls.segment == segment_obj) & (cls.kp == kp))
|
|
83
|
+
if exact is not None:
|
|
84
|
+
data = exact.serialize()
|
|
85
|
+
data["interpolated"] = False
|
|
86
|
+
return data, "Exact KP match"
|
|
87
|
+
|
|
88
|
+
lower = (
|
|
89
|
+
cls.select()
|
|
90
|
+
.where((cls.segment == segment_obj) & (cls.kp < kp))
|
|
91
|
+
.order_by(cls.kp.desc())
|
|
92
|
+
.first()
|
|
93
|
+
)
|
|
94
|
+
upper = (
|
|
95
|
+
cls.select()
|
|
96
|
+
.where((cls.segment == segment_obj) & (cls.kp > kp))
|
|
97
|
+
.order_by(cls.kp.asc())
|
|
98
|
+
.first()
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if lower is None and upper is None:
|
|
102
|
+
return None, f"No geospatial points configured for segment {segment_name}"
|
|
103
|
+
|
|
104
|
+
if lower is None:
|
|
105
|
+
data = upper.serialize()
|
|
106
|
+
data["requested_kp"] = kp
|
|
107
|
+
data["interpolated"] = False
|
|
108
|
+
data["interpolation_note"] = "Requested KP below available range; nearest upper point returned"
|
|
109
|
+
return data, "Nearest point returned"
|
|
110
|
+
|
|
111
|
+
if upper is None:
|
|
112
|
+
data = lower.serialize()
|
|
113
|
+
data["requested_kp"] = kp
|
|
114
|
+
data["interpolated"] = False
|
|
115
|
+
data["interpolation_note"] = "Requested KP above available range; nearest lower point returned"
|
|
116
|
+
return data, "Nearest point returned"
|
|
117
|
+
|
|
118
|
+
kp_span = upper.kp - lower.kp
|
|
119
|
+
if kp_span == 0:
|
|
120
|
+
return None, "Invalid interpolation range (duplicated KP points)"
|
|
121
|
+
|
|
122
|
+
ratio = (kp - lower.kp) / kp_span
|
|
123
|
+
latitude = lower.latitude + (upper.latitude - lower.latitude) * ratio
|
|
124
|
+
longitude = lower.longitude + (upper.longitude - lower.longitude) * ratio
|
|
125
|
+
elevation = None
|
|
126
|
+
if lower.elevation is not None and upper.elevation is not None:
|
|
127
|
+
elevation = lower.elevation + (upper.elevation - lower.elevation) * ratio
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
"id": None,
|
|
131
|
+
"segment_id": segment_obj.id,
|
|
132
|
+
"segment_name": segment_obj.name,
|
|
133
|
+
"kp": kp,
|
|
134
|
+
"latitude": latitude,
|
|
135
|
+
"longitude": longitude,
|
|
136
|
+
"elevation": elevation,
|
|
137
|
+
"interpolated": True,
|
|
138
|
+
"interpolation_bounds": {
|
|
139
|
+
"lower_kp": lower.kp,
|
|
140
|
+
"upper_kp": upper.kp
|
|
141
|
+
}
|
|
142
|
+
}, "Interpolated KP location"
|
|
143
|
+
|
|
144
|
+
def serialize(self):
|
|
145
|
+
r"""
|
|
146
|
+
Serializes the linear-referencing geospatial point.
|
|
147
|
+
"""
|
|
148
|
+
return {
|
|
149
|
+
"id": self.id,
|
|
150
|
+
"segment_id": self.segment.id,
|
|
151
|
+
"segment_name": self.segment.name,
|
|
152
|
+
"kp": self.kp,
|
|
153
|
+
"latitude": self.latitude,
|
|
154
|
+
"longitude": self.longitude,
|
|
155
|
+
"elevation": self.elevation
|
|
156
|
+
}
|
|
@@ -434,6 +434,7 @@ class Tags(BaseModel):
|
|
|
434
434
|
node_namespace = CharField(null=True)
|
|
435
435
|
scan_time = IntegerField(null=True)
|
|
436
436
|
dead_band = FloatField(null=True)
|
|
437
|
+
kp = FloatField(null=True)
|
|
437
438
|
active = BooleanField(default=True)
|
|
438
439
|
process_filter = BooleanField(default=False)
|
|
439
440
|
gaussian_filter = BooleanField(default=False)
|
|
@@ -460,6 +461,7 @@ class Tags(BaseModel):
|
|
|
460
461
|
manufacturer:str="",
|
|
461
462
|
scan_time:int=0,
|
|
462
463
|
dead_band:float=0.0,
|
|
464
|
+
kp:float=None,
|
|
463
465
|
active:bool=True,
|
|
464
466
|
process_filter:bool=False,
|
|
465
467
|
gaussian_filter:bool=False,
|
|
@@ -535,6 +537,7 @@ class Tags(BaseModel):
|
|
|
535
537
|
node_namespace=node_namespace,
|
|
536
538
|
scan_time=scan_time,
|
|
537
539
|
dead_band=dead_band,
|
|
540
|
+
kp=kp,
|
|
538
541
|
active=active,
|
|
539
542
|
process_filter=process_filter,
|
|
540
543
|
gaussian_filter=gaussian_filter,
|
|
@@ -559,6 +562,7 @@ class Tags(BaseModel):
|
|
|
559
562
|
node_namespace=node_namespace,
|
|
560
563
|
scan_time=scan_time,
|
|
561
564
|
dead_band=dead_band,
|
|
565
|
+
kp=kp,
|
|
562
566
|
active=active,
|
|
563
567
|
process_filter=process_filter,
|
|
564
568
|
gaussian_filter=gaussian_filter,
|
|
@@ -617,6 +621,7 @@ class Tags(BaseModel):
|
|
|
617
621
|
"node_namespace":node_namespace,
|
|
618
622
|
"scan_time":scan_time,
|
|
619
623
|
"dead_band":dead_band,
|
|
624
|
+
"kp":kp,
|
|
620
625
|
"active": True
|
|
621
626
|
}
|
|
622
627
|
cls.put(id=tag.id, **payload)
|
|
@@ -790,6 +795,7 @@ class Tags(BaseModel):
|
|
|
790
795
|
'node_namespace': self.node_namespace,
|
|
791
796
|
'scan_time': self.scan_time,
|
|
792
797
|
'dead_band': self.dead_band,
|
|
798
|
+
'kp': self.kp,
|
|
793
799
|
'variable': self.unit.variable_id.name,
|
|
794
800
|
'active': self.active,
|
|
795
801
|
'process_filter': self.process_filter,
|
|
@@ -817,6 +823,8 @@ class TagValue(BaseModel):
|
|
|
817
823
|
class Meta:
|
|
818
824
|
indexes = (
|
|
819
825
|
(('timestamp',), False),
|
|
826
|
+
# Consultas típicas de tendencias: por tag + rango de tiempo
|
|
827
|
+
(('tag', 'timestamp'), False),
|
|
820
828
|
)
|
|
821
829
|
|
|
822
830
|
@classmethod
|