sciveo 0.1.72__tar.gz → 0.1.73__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.73}/PKG-INFO +3 -1
- sciveo-0.1.73/sciveo/db/read_table.py +204 -0
- sciveo-0.1.73/sciveo/monitoring/power/ems300.py +108 -0
- sciveo-0.1.73/sciveo/monitoring/power/sim.py +71 -0
- sciveo-0.1.73/sciveo/monitoring/power/tools.py +378 -0
- sciveo-0.1.73/sciveo/tools/draw/__init__.py +0 -0
- sciveo-0.1.73/sciveo/version.py +2 -0
- sciveo-0.1.73/sciveo/web/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo.egg-info/PKG-INFO +3 -1
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo.egg-info/SOURCES.txt +6 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo.egg-info/requires.txt +8 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/setup.py +8 -0
- sciveo-0.1.72/sciveo/version.py +0 -2
- {sciveo-0.1.72 → sciveo-0.1.73}/README.md +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/api/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/api/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/api/predictors.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/api/server.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/api/upload.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/cli.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/common/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/common/configuration.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/common/model.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/common/optimizers.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/common/sampling.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/content/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/content/dataset.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/content/experiment.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/content/project.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/content/runner.py +0 -0
- {sciveo-0.1.72/sciveo/media → sciveo-0.1.73/sciveo/db}/__init__.py +0 -0
- {sciveo-0.1.72/sciveo/media/capture → sciveo-0.1.73/sciveo/media}/__init__.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml → sciveo-0.1.73/sciveo/media/capture}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/capture/cam.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/capture/motion_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/capture/nvr.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/capture/readers.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml/encoders → sciveo-0.1.73/sciveo/media/ml}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/base.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml/nlp → sciveo-0.1.73/sciveo/media/ml/encoders}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/encoders/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/encoders/normalizer.py +0 -0
- {sciveo-0.1.72/sciveo/media/ml/time_series → sciveo-0.1.73/sciveo/media/ml/nlp}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/nlp/search.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines → sciveo-0.1.73/sciveo/media/ml/time_series}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/time_series/dataset.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/time_series/predictor.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/time_series/trainer.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/ml/time_series/window_generator.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/layouts → sciveo-0.1.73/sciveo/media/pipelines}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/job_daemon.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/postprocessors → sciveo-0.1.73/sciveo/media/pipelines/layouts}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/layouts/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/pipeline.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors → sciveo-0.1.73/sciveo/media/pipelines/postprocessors}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/postprocessors/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/postprocessors/default.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/audio → sciveo-0.1.73/sciveo/media/pipelines/processors}/__init__.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/file → sciveo-0.1.73/sciveo/media/pipelines/processors/audio}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/audio/audio.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/audio/audio_extractor_process.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/aws.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/base.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/image → sciveo-0.1.73/sciveo/media/pipelines/processors/file}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/file/archive.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/nlp → sciveo-0.1.73/sciveo/media/pipelines/processors/image}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/album.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/album_in_image.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/depth_esimation.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/embeddings.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/filters.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/generators.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/histogram.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/mask.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/object_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/resize.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/segmentation.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/image/watermark.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/media_info.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/sci → sciveo-0.1.73/sciveo/media/pipelines/processors/nlp}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/nlp/address.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/qr.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/sci/time_series → sciveo-0.1.73/sciveo/media/pipelines/processors/sci}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/sci/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/sci/dataset.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/processors/video → sciveo-0.1.73/sciveo/media/pipelines/processors/sci/time_series}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/sci/time_series/predictor.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/sci/time_series/trainer.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/tpu_base.py +0 -0
- {sciveo-0.1.72/sciveo/media/pipelines/web → sciveo-0.1.73/sciveo/media/pipelines/processors/video}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/video/generators.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/video/motion_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/video/resize.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/video/video_album.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/video/video_frames.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/processors/video/video_resample.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/queues.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/server.py +0 -0
- {sciveo-0.1.72/sciveo/media/tools → sciveo-0.1.73/sciveo/media/pipelines/web}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/pipelines/web/server.py +0 -0
- {sciveo-0.1.72/sciveo/ml → sciveo-0.1.73/sciveo/media/tools}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/media/tools/video_interactive.py +0 -0
- {sciveo-0.1.72/sciveo/ml/dataset → sciveo-0.1.73/sciveo/ml}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/base.py +0 -0
- {sciveo-0.1.72/sciveo/ml/evaluation → sciveo-0.1.73/sciveo/ml/dataset}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/dataset/object_detection.py +0 -0
- {sciveo-0.1.72/sciveo/ml/images → sciveo-0.1.73/sciveo/ml/evaluation}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/evaluation/markdown.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/evaluation/object_detection.py +0 -0
- {sciveo-0.1.72/sciveo/ml/nlp → sciveo-0.1.73/sciveo/ml/images}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/images/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/images/description.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/images/embeddings.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/images/object_detection.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/images/tools.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/images/transformers.py +0 -0
- {sciveo-0.1.72/sciveo/ml/nlp/tokenizers → sciveo-0.1.73/sciveo/ml/nlp}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/nlp/embeddings.py +0 -0
- {sciveo-0.1.72/sciveo/ml/video → sciveo-0.1.73/sciveo/ml/nlp/tokenizers}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/nlp/tokenizers/bpe.py +0 -0
- {sciveo-0.1.72/sciveo/monitoring → sciveo-0.1.73/sciveo/ml/video}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/ml/video/description.py +0 -0
- {sciveo-0.1.72/sciveo/monitoring/watchdog → sciveo-0.1.73/sciveo/monitoring}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/monitoring/monitor.py +0 -0
- {sciveo-0.1.72/sciveo/network → sciveo-0.1.73/sciveo/monitoring/power}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/monitoring/start.py +0 -0
- {sciveo-0.1.72/sciveo/tools → sciveo-0.1.73/sciveo/monitoring/watchdog}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/monitoring/watchdog/base.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/monitoring/watchdog/process.py +0 -0
- {sciveo-0.1.72/sciveo/tools/aws → sciveo-0.1.73/sciveo/network}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/network/camera.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/network/sniffer.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/network/tools.py +0 -0
- {sciveo-0.1.72/sciveo/tools/draw → sciveo-0.1.73/sciveo/tools}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/array.py +0 -0
- {sciveo-0.1.72/sciveo/web → sciveo-0.1.73/sciveo/tools/aws}/__init__.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/aws/priority_queue.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/aws/s3.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/common.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/complexity.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/compress.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/configuration.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/crypto.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/daemon.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/draw/contours.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/formating.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/hardware.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/http.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/logger.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/os.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/queue.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/random.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/remote.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/simple_counter.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/synchronized.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/timers.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/tools/totp.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo/web/common.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo.egg-info/dependency_links.txt +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo.egg-info/entry_points.txt +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/sciveo.egg-info/top_level.txt +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/setup.cfg +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_complexity.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_compress.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_configuration.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_crypto.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_eval_markdown.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_ml_datasets.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_monitoring.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_runner.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_sampling.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/test/test_tokenizers.py +0 -0
- {sciveo-0.1.72 → sciveo-0.1.73}/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.73
|
|
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
|
|
|
@@ -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,108 @@
|
|
|
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
|
+
from pymodbus.client import ModbusTcpClient
|
|
14
|
+
from sciveo.tools.logger import *
|
|
15
|
+
from sciveo.tools.daemon import DaemonBase
|
|
16
|
+
from sciveo.monitoring.power.tools import *
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PowerEMS300(DaemonBase):
|
|
20
|
+
def __init__(self, host, port=502, device_id=247, delay=0.01, period=30):
|
|
21
|
+
super().__init__(period=period)
|
|
22
|
+
self.host = host
|
|
23
|
+
self.port = port
|
|
24
|
+
self.device_id = device_id
|
|
25
|
+
self.delay = delay
|
|
26
|
+
self.client = None
|
|
27
|
+
|
|
28
|
+
self.client = ModbusTcpClient(host=self.host, port=self.port)
|
|
29
|
+
self.connected = False
|
|
30
|
+
|
|
31
|
+
def connect(self):
|
|
32
|
+
if not (self.connected or self.client.connect()):
|
|
33
|
+
error("Connect FAIL", (self.host, self.port))
|
|
34
|
+
self.connected = False
|
|
35
|
+
else:
|
|
36
|
+
self.connected = True
|
|
37
|
+
return self.connected
|
|
38
|
+
|
|
39
|
+
def loop(self):
|
|
40
|
+
self.connect()
|
|
41
|
+
if not self.connected:
|
|
42
|
+
warning("Not connected", (self.host, self.port))
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
# iterate known addresses in map (sorted)
|
|
47
|
+
for addr in sorted(REG_MAP.keys()):
|
|
48
|
+
dtype, factor, name = REG_MAP[addr]
|
|
49
|
+
count = count_for_type(dtype)
|
|
50
|
+
protocol_addr = addr - 1 # doc addresses start at 1; pymodbus expects zero-based
|
|
51
|
+
try:
|
|
52
|
+
rr = self.client.read_input_registers(address=protocol_addr, count=count, device_id=self.device_id)
|
|
53
|
+
if rr is None:
|
|
54
|
+
warning(f"No response for {addr} ({name})")
|
|
55
|
+
continue
|
|
56
|
+
if hasattr(rr, "isError") and rr.isError():
|
|
57
|
+
warning(f"Modbus exception at {addr} ({name}): {rr}")
|
|
58
|
+
continue
|
|
59
|
+
regs = getattr(rr, "registers", None)
|
|
60
|
+
if not regs or len(regs) < count:
|
|
61
|
+
warning(f"Incomplete registers at {addr} ({name}): {regs}")
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
val_raw = decode_registers(regs, dtype)
|
|
65
|
+
if val_raw is None:
|
|
66
|
+
warning(f"Unable to decode {addr} ({name}) regs={regs}")
|
|
67
|
+
continue
|
|
68
|
+
# apply factor
|
|
69
|
+
value = val_raw * factor
|
|
70
|
+
# format integer-looking floats without trailing .0
|
|
71
|
+
if isinstance(value, float) and value.is_integer():
|
|
72
|
+
value = int(value)
|
|
73
|
+
info(f"{addr} {name}: raw={regs} -> {value} (factor={factor}, type={dtype})")
|
|
74
|
+
except Exception as e:
|
|
75
|
+
error(f"Error reading {addr} ({name}): {e}")
|
|
76
|
+
time.sleep(self.delay)
|
|
77
|
+
|
|
78
|
+
# Optionally scan remaining addresses 8000..8200 for any non-zero single-register values
|
|
79
|
+
info("\nQuick scan for single-register non-zero values (8000..8200):")
|
|
80
|
+
for addr in range(8000, 8201):
|
|
81
|
+
if addr in REG_MAP:
|
|
82
|
+
continue
|
|
83
|
+
try:
|
|
84
|
+
rr = self.client.read_input_registers(address=addr - 1, count=1, device_id=self.device_id)
|
|
85
|
+
if rr is None:
|
|
86
|
+
continue
|
|
87
|
+
if hasattr(rr, "isError") and rr.isError():
|
|
88
|
+
continue
|
|
89
|
+
regs = getattr(rr, "registers", None)
|
|
90
|
+
if regs and regs[0] != 0:
|
|
91
|
+
info(f"{addr}: {regs[0]} (0x{regs[0]:04X})")
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
time.sleep(0.005)
|
|
95
|
+
except Exception as e:
|
|
96
|
+
exception(e)
|
|
97
|
+
|
|
98
|
+
def close(self):
|
|
99
|
+
self.client.close()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
|
|
104
|
+
mon = PowerEMS300(host="localhost", port=1502, period=10)
|
|
105
|
+
mon.start()
|
|
106
|
+
|
|
107
|
+
while(True):
|
|
108
|
+
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)
|