sciveo 0.1.72__tar.gz → 0.1.74__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.
- {sciveo-0.1.72 → sciveo-0.1.74}/PKG-INFO +3 -1
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/cli.py +11 -3
- sciveo-0.1.74/sciveo/db/read_table.py +204 -0
- sciveo-0.1.74/sciveo/monitoring/power/ems300.py +107 -0
- sciveo-0.1.74/sciveo/monitoring/power/sim.py +71 -0
- sciveo-0.1.74/sciveo/monitoring/power/tools.py +394 -0
- sciveo-0.1.74/sciveo/tools/draw/__init__.py +0 -0
- sciveo-0.1.74/sciveo/version.py +2 -0
- sciveo-0.1.74/sciveo/web/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo.egg-info/PKG-INFO +3 -1
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo.egg-info/SOURCES.txt +6 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo.egg-info/requires.txt +8 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/setup.py +8 -0
- sciveo-0.1.72/sciveo/version.py +0 -2
- {sciveo-0.1.72 → sciveo-0.1.74}/README.md +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/api/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/api/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/api/predictors.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/api/server.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/api/upload.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/common/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/common/configuration.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/common/model.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/common/optimizers.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/common/sampling.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/content/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/content/dataset.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/content/experiment.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/content/project.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/content/runner.py +0 -0
- {sciveo-0.1.72/sciveo/media → sciveo-0.1.74/sciveo/db}/__init__.py +0 -0
- {sciveo-0.1.72/sciveo/media/capture → sciveo-0.1.74/sciveo/media}/__init__.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml → sciveo-0.1.74/sciveo/media/capture}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/capture/cam.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/capture/motion_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/capture/nvr.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/capture/readers.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml/encoders → sciveo-0.1.74/sciveo/media/ml}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/base.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml/nlp → sciveo-0.1.74/sciveo/media/ml/encoders}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/encoders/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/encoders/normalizer.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml/time_series → sciveo-0.1.74/sciveo/media/ml/nlp}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/nlp/search.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines → sciveo-0.1.74/sciveo/media/ml/time_series}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/time_series/dataset.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/time_series/predictor.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/time_series/trainer.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/ml/time_series/window_generator.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/layouts → sciveo-0.1.74/sciveo/media/pipelines}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/job_daemon.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/postprocessors → sciveo-0.1.74/sciveo/media/pipelines/layouts}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/layouts/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/pipeline.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors → sciveo-0.1.74/sciveo/media/pipelines/postprocessors}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/postprocessors/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/postprocessors/default.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/audio → sciveo-0.1.74/sciveo/media/pipelines/processors}/__init__.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/file → sciveo-0.1.74/sciveo/media/pipelines/processors/audio}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/audio/audio.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/audio/audio_extractor_process.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/aws.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/base.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/image → sciveo-0.1.74/sciveo/media/pipelines/processors/file}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/file/archive.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/nlp → sciveo-0.1.74/sciveo/media/pipelines/processors/image}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/album.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/album_in_image.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/depth_esimation.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/embeddings.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/filters.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/generators.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/histogram.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/mask.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/object_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/resize.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/segmentation.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/image/watermark.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/media_info.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/sci → sciveo-0.1.74/sciveo/media/pipelines/processors/nlp}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/nlp/address.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/qr.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/sci/time_series → sciveo-0.1.74/sciveo/media/pipelines/processors/sci}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/sci/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/sci/dataset.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/video → sciveo-0.1.74/sciveo/media/pipelines/processors/sci/time_series}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/sci/time_series/predictor.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/sci/time_series/trainer.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/tpu_base.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/web → sciveo-0.1.74/sciveo/media/pipelines/processors/video}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/video/generators.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/video/motion_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/video/resize.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/video/video_album.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/video/video_frames.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/processors/video/video_resample.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/queues.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/server.py +0 -0
- {sciveo-0.1.72/sciveo/media/tools → sciveo-0.1.74/sciveo/media/pipelines/web}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/pipelines/web/server.py +0 -0
- {sciveo-0.1.72/sciveo/ml → sciveo-0.1.74/sciveo/media/tools}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/media/tools/video_interactive.py +0 -0
- {sciveo-0.1.72/sciveo/ml/dataset → sciveo-0.1.74/sciveo/ml}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/base.py +0 -0
- {sciveo-0.1.72/sciveo/ml/evaluation → sciveo-0.1.74/sciveo/ml/dataset}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/dataset/object_detection.py +0 -0
- {sciveo-0.1.72/sciveo/ml/images → sciveo-0.1.74/sciveo/ml/evaluation}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/evaluation/markdown.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/evaluation/object_detection.py +0 -0
- {sciveo-0.1.72/sciveo/ml/nlp → sciveo-0.1.74/sciveo/ml/images}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/images/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/images/description.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/images/embeddings.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/images/object_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/images/tools.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/images/transformers.py +0 -0
- {sciveo-0.1.72/sciveo/ml/nlp/tokenizers → sciveo-0.1.74/sciveo/ml/nlp}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/nlp/embeddings.py +0 -0
- {sciveo-0.1.72/sciveo/ml/video → sciveo-0.1.74/sciveo/ml/nlp/tokenizers}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/nlp/tokenizers/bpe.py +0 -0
- {sciveo-0.1.72/sciveo/monitoring → sciveo-0.1.74/sciveo/ml/video}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/ml/video/description.py +0 -0
- {sciveo-0.1.72/sciveo/monitoring/watchdog → sciveo-0.1.74/sciveo/monitoring}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/monitoring/monitor.py +0 -0
- {sciveo-0.1.72/sciveo/network → sciveo-0.1.74/sciveo/monitoring/power}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/monitoring/start.py +0 -0
- {sciveo-0.1.72/sciveo/tools → sciveo-0.1.74/sciveo/monitoring/watchdog}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/monitoring/watchdog/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/monitoring/watchdog/process.py +0 -0
- {sciveo-0.1.72/sciveo/tools/aws → sciveo-0.1.74/sciveo/network}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/network/camera.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/network/sniffer.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/network/tools.py +0 -0
- {sciveo-0.1.72/sciveo/tools/draw → sciveo-0.1.74/sciveo/tools}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/array.py +0 -0
- {sciveo-0.1.72/sciveo/web → sciveo-0.1.74/sciveo/tools/aws}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/aws/priority_queue.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/aws/s3.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/common.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/complexity.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/compress.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/configuration.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/crypto.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/daemon.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/draw/contours.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/formating.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/hardware.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/http.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/logger.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/os.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/queue.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/random.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/remote.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/simple_counter.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/synchronized.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/timers.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/tools/totp.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo/web/common.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo.egg-info/dependency_links.txt +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo.egg-info/entry_points.txt +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/sciveo.egg-info/top_level.txt +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/setup.cfg +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_complexity.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_compress.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_configuration.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_crypto.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_eval_markdown.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_ml_datasets.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_monitoring.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_runner.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_sampling.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_tokenizers.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.74}/test/test_totp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sciveo
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.74
|
|
4
4
|
Description-Content-Type: text/markdown
|
|
5
5
|
Provides-Extra: mon
|
|
6
6
|
Provides-Extra: net
|
|
@@ -8,6 +8,8 @@ Provides-Extra: server
|
|
|
8
8
|
Provides-Extra: media
|
|
9
9
|
Provides-Extra: media-ml
|
|
10
10
|
Provides-Extra: web
|
|
11
|
+
Provides-Extra: db
|
|
12
|
+
Provides-Extra: power
|
|
11
13
|
Provides-Extra: all
|
|
12
14
|
Provides-Extra: ml
|
|
13
15
|
|
|
@@ -29,7 +29,7 @@ def main():
|
|
|
29
29
|
choices=[
|
|
30
30
|
'init', 'monitor', 'scan', 'nvr', 'predictors-server',
|
|
31
31
|
'media-server', 'media-run',
|
|
32
|
-
'watchdog'
|
|
32
|
+
'watchdog',
|
|
33
33
|
],
|
|
34
34
|
help='Command to execute')
|
|
35
35
|
|
|
@@ -54,12 +54,20 @@ def main():
|
|
|
54
54
|
parser.add_argument('--threshold', type=float, default=None, help='Threshold')
|
|
55
55
|
parser.add_argument('--execute', type=str, default=None, help='Execute command')
|
|
56
56
|
parser.add_argument('--pid', type=int, default=None, help='Process PID')
|
|
57
|
+
parser.add_argument('--serial', type=str, default=None, help='Serial Name')
|
|
57
58
|
|
|
58
59
|
args = parser.parse_args()
|
|
59
60
|
|
|
60
61
|
if args.command == 'monitor':
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
if args.src is None:
|
|
63
|
+
from sciveo.monitoring.start import MonitorStart
|
|
64
|
+
MonitorStart(period=args.period, block=args.block, output_path=args.output_path)()
|
|
65
|
+
elif args.src.startswith("power"):
|
|
66
|
+
from sciveo.monitoring.power.ems300 import PowerEMS300
|
|
67
|
+
mon = PowerEMS300(serial=args.serial, host=args.host, port=args.port, period=args.period, output_path=args.output_path)
|
|
68
|
+
mon.start()
|
|
69
|
+
while(True):
|
|
70
|
+
time.sleep(3600)
|
|
63
71
|
elif args.command == 'scan':
|
|
64
72
|
from sciveo.network.tools import NetworkTools
|
|
65
73
|
host=args.host
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Pavlin Georgiev, Softel Labs
|
|
3
|
+
#
|
|
4
|
+
# This is a proprietary file and may not be copied,
|
|
5
|
+
# distributed, or modified without express permission
|
|
6
|
+
# from the owner. For licensing inquiries, please
|
|
7
|
+
# contact pavlin@softel.bg.
|
|
8
|
+
#
|
|
9
|
+
# 2025
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import json
|
|
14
|
+
import psycopg2
|
|
15
|
+
import numpy as np
|
|
16
|
+
import pandas as pd
|
|
17
|
+
from sciveo.tools.logger import *
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BaseTable:
|
|
21
|
+
def __init__(self, table_name, config=None, batch_size=10_000, save_path=None, id_col="id"):
|
|
22
|
+
self.table_name = table_name
|
|
23
|
+
self.batch_size = batch_size
|
|
24
|
+
self.save_path = save_path
|
|
25
|
+
self.id_col = id_col
|
|
26
|
+
self.last_id = None
|
|
27
|
+
|
|
28
|
+
if config is None:
|
|
29
|
+
self.config = {
|
|
30
|
+
'dbname': os.environ.get('DB_NAME'),
|
|
31
|
+
'user': os.environ.get('DB_USERNAME'),
|
|
32
|
+
'password': os.environ.get('DB_PASSWORD'),
|
|
33
|
+
'host': os.environ.get('DB_HOST', 'localhost'),
|
|
34
|
+
'port': int(os.environ.get('DB_PORT', 5432)),
|
|
35
|
+
}
|
|
36
|
+
else:
|
|
37
|
+
self.config = config
|
|
38
|
+
|
|
39
|
+
self.conn = psycopg2.connect(**self.config)
|
|
40
|
+
self.cursor = self.conn.cursor()
|
|
41
|
+
self.df = pd.DataFrame()
|
|
42
|
+
|
|
43
|
+
def load_file(self, file_path=None):
|
|
44
|
+
if not os.path.exists(file_path):
|
|
45
|
+
warning(f"File not found: {file_path}")
|
|
46
|
+
self.latest_df = pd.DataFrame()
|
|
47
|
+
return self.latest_df
|
|
48
|
+
|
|
49
|
+
if file_path.endswith(".parquet"):
|
|
50
|
+
self.latest_df = pd.read_parquet(file_path)
|
|
51
|
+
else:
|
|
52
|
+
self.latest_df = pd.read_csv(file_path)
|
|
53
|
+
info(f"Loaded {len(self.latest_df)} records from {file_path}")
|
|
54
|
+
return self.latest_df
|
|
55
|
+
|
|
56
|
+
def load(self, base_path=None):
|
|
57
|
+
if base_path is None and self.save_path is not None:
|
|
58
|
+
base_path = self.save_path
|
|
59
|
+
|
|
60
|
+
if base_path is None:
|
|
61
|
+
self.df = pd.DataFrame()
|
|
62
|
+
return self.df
|
|
63
|
+
|
|
64
|
+
files = [os.path.join(base_path, f) for f in os.listdir(base_path) if f.startswith(self.table_name) and f.endswith(".parquet")]
|
|
65
|
+
|
|
66
|
+
if not files:
|
|
67
|
+
info(f"There are no files in {base_path} to read")
|
|
68
|
+
self.df = pd.DataFrame()
|
|
69
|
+
return self.df
|
|
70
|
+
|
|
71
|
+
dfs = []
|
|
72
|
+
for file_path in sorted(files):
|
|
73
|
+
try:
|
|
74
|
+
df_part = self.load_file(file_path)
|
|
75
|
+
from_id = int(df_part[self.id_col].min())
|
|
76
|
+
to_id = int(df_part[self.id_col].max())
|
|
77
|
+
dfs.append(df_part)
|
|
78
|
+
debug(f"Loaded {len(df_part)} records from {file_path} id: [{from_id} - {to_id}]")
|
|
79
|
+
except Exception as e:
|
|
80
|
+
warning(f"Failed to load {file_path}: {e}")
|
|
81
|
+
|
|
82
|
+
if dfs:
|
|
83
|
+
self.df = pd.concat(dfs, ignore_index=True)
|
|
84
|
+
else:
|
|
85
|
+
self.df = pd.DataFrame()
|
|
86
|
+
|
|
87
|
+
self.last_id = int(self.df[self.id_col].max()) if not self.df.empty else None
|
|
88
|
+
|
|
89
|
+
info(f"Total loaded records: {len(self.df)} last_id: {self.last_id}")
|
|
90
|
+
return self.df
|
|
91
|
+
|
|
92
|
+
def _sanitize_df(self, df):
|
|
93
|
+
PANDAS_MIN_YEAR = 1677
|
|
94
|
+
PANDAS_MAX_YEAR = 2262
|
|
95
|
+
datetime_cols = []
|
|
96
|
+
|
|
97
|
+
# datetime cleanup
|
|
98
|
+
for col in df.columns:
|
|
99
|
+
if pd.api.types.is_datetime64_any_dtype(df[col]) or 'date' in col.lower() or 'time' in col.lower():
|
|
100
|
+
datetime_cols.append(col)
|
|
101
|
+
|
|
102
|
+
for col in datetime_cols:
|
|
103
|
+
def safe_dt(x):
|
|
104
|
+
if pd.isna(x):
|
|
105
|
+
return pd.NaT
|
|
106
|
+
if isinstance(x, str):
|
|
107
|
+
return pd.to_datetime(x, errors='coerce')
|
|
108
|
+
if hasattr(x, 'year'):
|
|
109
|
+
year = x.year
|
|
110
|
+
else:
|
|
111
|
+
return pd.NaT
|
|
112
|
+
if PANDAS_MIN_YEAR <= year <= PANDAS_MAX_YEAR:
|
|
113
|
+
return pd.Timestamp(x)
|
|
114
|
+
return pd.NaT
|
|
115
|
+
df[col] = df[col].apply(safe_dt)
|
|
116
|
+
|
|
117
|
+
# drop rows with invalid datetime
|
|
118
|
+
df = df.dropna(subset=datetime_cols)
|
|
119
|
+
|
|
120
|
+
# object columns: convert dict/list to JSON string
|
|
121
|
+
for col in df.columns:
|
|
122
|
+
if df[col].dtype == object:
|
|
123
|
+
df[col] = df[col].apply(lambda x: json.dumps(x) if isinstance(x, (dict, list)) else str(x) if x is not None else None)
|
|
124
|
+
|
|
125
|
+
df = df.reset_index(drop=True)
|
|
126
|
+
return df
|
|
127
|
+
|
|
128
|
+
def fetch_next_batch(self, last_id=None):
|
|
129
|
+
query = f"SELECT * FROM {self.table_name}"
|
|
130
|
+
if last_id is not None:
|
|
131
|
+
query += f" WHERE id > {last_id}"
|
|
132
|
+
query += f" ORDER BY id ASC LIMIT {self.batch_size};"
|
|
133
|
+
|
|
134
|
+
self.cursor.execute(query)
|
|
135
|
+
rows = self.cursor.fetchall()
|
|
136
|
+
if not rows:
|
|
137
|
+
return pd.DataFrame()
|
|
138
|
+
|
|
139
|
+
colnames = [desc[0] for desc in self.cursor.description]
|
|
140
|
+
df_new = pd.DataFrame(rows, columns=colnames)
|
|
141
|
+
return self._sanitize_df(df_new)
|
|
142
|
+
|
|
143
|
+
def append(self, df_new):
|
|
144
|
+
if not df_new.empty:
|
|
145
|
+
self.df = pd.concat([self.df, df_new], ignore_index=True)
|
|
146
|
+
debug(f"Added {len(df_new)} new rows (total {len(self.df)})")
|
|
147
|
+
self.last_id = int(self.df[self.id_col].max()) if not self.df.empty else None
|
|
148
|
+
debug(f"last {self.id_col} [{self.last_id}]")
|
|
149
|
+
|
|
150
|
+
def sync_incremental(self, last_id=None):
|
|
151
|
+
if last_id is None:
|
|
152
|
+
last_id = int(self.df[self.id_col].max()) if not self.df.empty else None
|
|
153
|
+
debug("reading from", last_id)
|
|
154
|
+
df_new = self.fetch_next_batch(last_id)
|
|
155
|
+
self.append(df_new)
|
|
156
|
+
if df_new.empty:
|
|
157
|
+
info("No new rows found")
|
|
158
|
+
return df_new
|
|
159
|
+
|
|
160
|
+
def save(self, file_path=None):
|
|
161
|
+
if self.save_path is not None and self.last_id is not None:
|
|
162
|
+
from_id = int(self.latest_df[self.id_col].min())
|
|
163
|
+
to_id = int(self.latest_df[self.id_col].max())
|
|
164
|
+
file_path = os.path.join(self.save_path, f"{self.table_name}--{from_id}-{to_id}.parquet")
|
|
165
|
+
|
|
166
|
+
if file_path.endswith(".parquet"):
|
|
167
|
+
self.latest_df.to_parquet(file_path, index=False)
|
|
168
|
+
else:
|
|
169
|
+
self.latest_df.to_csv(file_path, index=False)
|
|
170
|
+
info(f"Saved {len(self.latest_df)} rows to {file_path}")
|
|
171
|
+
|
|
172
|
+
def update(self, last_id=None):
|
|
173
|
+
if self.df.empty:
|
|
174
|
+
self.load()
|
|
175
|
+
self.latest_df = self.sync_incremental(last_id=last_id)
|
|
176
|
+
self.save()
|
|
177
|
+
return self.latest_df
|
|
178
|
+
|
|
179
|
+
def close(self):
|
|
180
|
+
self.cursor.close()
|
|
181
|
+
self.conn.close()
|
|
182
|
+
|
|
183
|
+
def __enter__(self):
|
|
184
|
+
return self
|
|
185
|
+
|
|
186
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
187
|
+
self.close()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
if __name__ == "__main__":
|
|
191
|
+
with BaseTable("video_record_predictions", batch_size=10_000, save_path="/home/ml/video_predictions/data") as T:
|
|
192
|
+
|
|
193
|
+
T.update(last_id=1_000_000)
|
|
194
|
+
T.load()
|
|
195
|
+
if not T.df.empty:
|
|
196
|
+
debug(T.df.columns)
|
|
197
|
+
debug(T.df[["key", "people", "is_valid", "updated_at", "data"]].head())
|
|
198
|
+
|
|
199
|
+
while(True):
|
|
200
|
+
df = T.update()
|
|
201
|
+
if df.empty:
|
|
202
|
+
info("Finished", T.df.shape)
|
|
203
|
+
break
|
|
204
|
+
info("read", df.shape, df[["key", "people"]].head())
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Stanislav Georgiev, Softel Labs
|
|
3
|
+
#
|
|
4
|
+
# This is a proprietary file and may not be copied,
|
|
5
|
+
# distributed, or modified without express permission
|
|
6
|
+
# from the owner. For licensing inquiries, please
|
|
7
|
+
# contact s.georgiev@softel.bg.
|
|
8
|
+
#
|
|
9
|
+
# 2025
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import json
|
|
14
|
+
import datetime
|
|
15
|
+
import time
|
|
16
|
+
from pymodbus.client import ModbusTcpClient
|
|
17
|
+
from sciveo.tools.logger import *
|
|
18
|
+
from sciveo.tools.daemon import DaemonBase
|
|
19
|
+
# from sciveo.api.base import APIRemoteClient
|
|
20
|
+
from sciveo.monitoring.power.tools import *
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PowerEMS300(DaemonBase):
|
|
24
|
+
def __init__(self, serial, host, port=502, device_id=247, delay=0.01, period=30, output_path=None):
|
|
25
|
+
super().__init__(period=period)
|
|
26
|
+
self.serial = serial
|
|
27
|
+
self.host = host
|
|
28
|
+
self.port = port
|
|
29
|
+
self.device_id = device_id
|
|
30
|
+
self.delay = delay
|
|
31
|
+
self.client = None
|
|
32
|
+
|
|
33
|
+
if output_path is not None and os.path.isdir(output_path):
|
|
34
|
+
self.output_path = os.path.join(output_path, f"{self.serial}.json")
|
|
35
|
+
else:
|
|
36
|
+
self.output_path = output_path
|
|
37
|
+
|
|
38
|
+
# self.api = APIRemoteClient()
|
|
39
|
+
self.client = ModbusTcpClient(host=self.host, port=self.port)
|
|
40
|
+
|
|
41
|
+
def connect(self):
|
|
42
|
+
if not self.client.connected:
|
|
43
|
+
if self.client.connect():
|
|
44
|
+
info(type(self.client).__name__, "connected", (self.host, self.port))
|
|
45
|
+
else:
|
|
46
|
+
error("Connect FAIL", (self.host, self.port))
|
|
47
|
+
return self.client.connected
|
|
48
|
+
|
|
49
|
+
def send(self, data):
|
|
50
|
+
api_result = self.api.POST_SCI("monitor", {"data": data})
|
|
51
|
+
debug(data, "api_result", api_result)
|
|
52
|
+
|
|
53
|
+
def output_write(self, data):
|
|
54
|
+
if os.path.isfile(self.output_path):
|
|
55
|
+
with open(self.output_path, "rb+") as fp:
|
|
56
|
+
fp.seek(-2, 2)
|
|
57
|
+
fp.truncate()
|
|
58
|
+
with open(self.output_path, "a") as fp:
|
|
59
|
+
fp.write(f", {json.dumps(data)}]\n")
|
|
60
|
+
else:
|
|
61
|
+
with open(self.output_path, "w") as fp:
|
|
62
|
+
fp.write(json.dumps([data]) + "\n")
|
|
63
|
+
|
|
64
|
+
def save(self, data):
|
|
65
|
+
try:
|
|
66
|
+
if self.output_path is not None:
|
|
67
|
+
info("save", self.output_path, data)
|
|
68
|
+
self.output_write(data)
|
|
69
|
+
except Exception as e:
|
|
70
|
+
error(e, "writing failed for", self.output_path)
|
|
71
|
+
|
|
72
|
+
def loop(self):
|
|
73
|
+
if not self.connect():
|
|
74
|
+
warning("Not connected", (self.host, self.port))
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
data = {
|
|
79
|
+
"local_time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
80
|
+
"serial": self.serial,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
current_info = [8026, 8044, 8060, 8776, 8778, 10101, 10103, 10105, 10713, 10715, 10716, 10945]
|
|
84
|
+
for addr in current_info:
|
|
85
|
+
result = read_input_registers(self.client, EMS300_REG_MAP, addr, self.device_id)
|
|
86
|
+
if result is not None:
|
|
87
|
+
value, name, dtype = result
|
|
88
|
+
debug(f"{name}: {value}")
|
|
89
|
+
data[name] = value
|
|
90
|
+
time.sleep(self.delay)
|
|
91
|
+
|
|
92
|
+
# self.send(data)
|
|
93
|
+
self.save(data)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
exception(e)
|
|
96
|
+
|
|
97
|
+
def close(self):
|
|
98
|
+
self.client.close()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
if __name__ == "__main__":
|
|
102
|
+
|
|
103
|
+
mon = PowerEMS300(serial="EMS300-1", host="192.168.86.184", port=502, period=30, output_path="ems300.json")
|
|
104
|
+
mon.start()
|
|
105
|
+
|
|
106
|
+
while(True):
|
|
107
|
+
time.sleep(30)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Stanislav Georgiev, Softel Labs
|
|
3
|
+
#
|
|
4
|
+
# This is a proprietary file and may not be copied,
|
|
5
|
+
# distributed, or modified without express permission
|
|
6
|
+
# from the owner. For licensing inquiries, please
|
|
7
|
+
# contact s.georgiev@softel.bg.
|
|
8
|
+
#
|
|
9
|
+
# 2025
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
import threading
|
|
14
|
+
import time
|
|
15
|
+
from pymodbus.server import StartTcpServer
|
|
16
|
+
from pymodbus.datastore import ModbusServerContext, ModbusSparseDataBlock
|
|
17
|
+
from threading import Thread
|
|
18
|
+
from sciveo.tools.logger import *
|
|
19
|
+
from sciveo.tools.daemon import DaemonBase
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Example read-only registers
|
|
23
|
+
# INITIAL_REGISTERS = {
|
|
24
|
+
# 8044: 12500, # Plant Active Power
|
|
25
|
+
# 8060: 8200, # PV Active Power
|
|
26
|
+
# 8038: -1500, # Storage Power
|
|
27
|
+
# 8048: 600, # Reactive Power
|
|
28
|
+
# 9082: 3000, # Dynamic Allowable Charge Power
|
|
29
|
+
# 9084: 3500, # Dynamic Allowable Discharge Power
|
|
30
|
+
# }
|
|
31
|
+
INITIAL_REGISTERS = {
|
|
32
|
+
8060: 8200, # PV Active Power
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class SimulatorEMS300(DaemonBase):
|
|
36
|
+
def __init__(self, host="127.0.0.1", port=5020, period=1):
|
|
37
|
+
super().__init__(num_threads=1, period=period)
|
|
38
|
+
self.host = host
|
|
39
|
+
self.port = port
|
|
40
|
+
|
|
41
|
+
# Only input registers
|
|
42
|
+
self.ir_block = ModbusSparseDataBlock(INITIAL_REGISTERS.copy())
|
|
43
|
+
|
|
44
|
+
self.context = ModbusServerContext(
|
|
45
|
+
{ 247: { # unit_id -> datastore dict
|
|
46
|
+
'di': ModbusSparseDataBlock({}), # discrete inputs
|
|
47
|
+
'co': ModbusSparseDataBlock({}), # coils
|
|
48
|
+
'hr': ModbusSparseDataBlock({}), # holding registers
|
|
49
|
+
'ir': self.ir_block # input registers
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
single=False # multiple units not used here, keep False
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
def loop(self):
|
|
56
|
+
# Slowly vary PV Active Power
|
|
57
|
+
pv = self.ir_block.getValues(8060, count=1)[0]
|
|
58
|
+
pv = (pv + 50) % 15000
|
|
59
|
+
self.ir_block.setValues(8060, [pv])
|
|
60
|
+
info(f"Simulated PV Active Power: {pv}")
|
|
61
|
+
|
|
62
|
+
def start_server(self):
|
|
63
|
+
StartTcpServer(self.context, address=(self.host, self.port))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
sim = SimulatorEMS300(host="127.0.0.1", port=1502)
|
|
68
|
+
sim.start()
|
|
69
|
+
sim.start_server()
|
|
70
|
+
while True:
|
|
71
|
+
time.sleep(10)
|