shepherd-core 2025.6.4__tar.gz → 2025.10.1__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.
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/PKG-INFO +4 -6
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/experiment_generic_var1.py +2 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/experiment_generic_var2.py +2 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/experiment_models.py +2 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/firmware_model.py +3 -2
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/firmware_modification.py +2 -1
- shepherd_core-2025.6.4/examples/simulate_vharvester.py → shepherd_core-2025.10.1/examples/simulations/vharvester.py +13 -8
- shepherd_core-2025.6.4/examples/simulate_vsource.py → shepherd_core-2025.10.1/examples/simulations/vsource.py +19 -10
- shepherd_core-2025.10.1/examples/simulations/vstorage.py +239 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/pyproject.toml +2 -5
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/__init__.py +4 -2
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/content.py +2 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/__init__.py +4 -2
- shepherd_core-2025.6.4/shepherd_core/data_models/content/virtual_harvester.py → shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_harvester_config.py +3 -3
- shepherd_core-2025.6.4/shepherd_core/data_models/content/virtual_source.py → shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_source_config.py +82 -58
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/virtual_source_fixture.yaml +24 -24
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_config.py +426 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_creator.py +267 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_ideal.yaml +637 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_lead.yaml +49 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_lipo.yaml +735 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_mlcc.yaml +200 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_param_experiments.py +151 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_super.yaml +150 -0
- shepherd_core-2025.10.1/shepherd_core/data_models/content/virtual_storage_fixture_tantal.yaml +550 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/experiment/observer_features.py +8 -2
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/experiment/target_config.py +1 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/emulation.py +9 -6
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/firmware_mod.py +1 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/harvest.py +4 -4
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/observer_tasks.py +5 -2
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/programming.py +1 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/testbed_tasks.py +6 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/decoder_waveform/uart.py +2 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/fw_tools/patcher.py +60 -34
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/fw_tools/validation.py +7 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/inventory/system.py +1 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/reader.py +4 -3
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/version.py +1 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/vsource/__init__.py +4 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/vsource/virtual_converter_model.py +27 -26
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/vsource/virtual_harvester_model.py +27 -19
- shepherd_core-2025.10.1/shepherd_core/vsource/virtual_harvester_simulation.py +71 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/vsource/virtual_source_model.py +17 -13
- shepherd_core-2025.10.1/shepherd_core/vsource/virtual_source_simulation.py +143 -0
- shepherd_core-2025.10.1/shepherd_core/vsource/virtual_storage_model.py +164 -0
- shepherd_core-2025.10.1/shepherd_core/vsource/virtual_storage_model_fixed_point_math.py +58 -0
- shepherd_core-2025.10.1/shepherd_core/vsource/virtual_storage_models_kibam.py +449 -0
- shepherd_core-2025.10.1/shepherd_core/vsource/virtual_storage_simulator.py +104 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core.egg-info/PKG-INFO +4 -6
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core.egg-info/SOURCES.txt +18 -5
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core.egg-info/requires.txt +3 -5
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/conftest.py +1 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_config_emulator.yaml +2 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_config_virtsource.yaml +9 -8
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_base_models.py +0 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_content_fixtures.py +4 -4
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_content_models.py +9 -8
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_experiment_models.py +3 -3
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_task_generation.py +2 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_task_models.py +3 -2
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_testbed_models.py +0 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/decoder_waveform/test_decoder.py +0 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/test_patcher.py +9 -3
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/inventory/test_inventory.py +0 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/test_cal_hw.py +0 -1
- shepherd_core-2025.10.1/tests/test_examples.py +53 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/vsource/test_converter.py +11 -14
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/vsource/test_harvester.py +3 -3
- shepherd_core-2025.6.4/shepherd_core/data_models/virtual_source_doc.txt +0 -207
- shepherd_core-2025.6.4/shepherd_core/vsource/virtual_harvester_simulation.py +0 -72
- shepherd_core-2025.6.4/shepherd_core/vsource/virtual_source_simulation.py +0 -145
- shepherd_core-2025.6.4/tests/test_examples.py +0 -42
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/README.md +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/eenv_generator.py +1 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/experiment_from_yaml.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/inventory.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/uart_decode_waveform.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/uart_raw2.csv +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/examples/vsource_debug_sim.py +2 -2
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/setup.cfg +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/calibration_hw_def.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/commons.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/config.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/cal_measurement.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/calibration.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/shepherd.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/timezone.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/wrapper.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/energy_environment.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/firmware.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/experiment/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/experiment/experiment.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/readme.md +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/task/helper_paths.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/cape.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/cape_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/gpio.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/mcu.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/observer.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/observer_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/target.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/target_fixture.old1 +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/target_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/testbed.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/fw_tools/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/fw_tools/converter.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/fw_tools/converter_elf.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/inventory/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/inventory/python.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/inventory/target.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/logger.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/testbed_client/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/testbed_client/cache_path.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/testbed_client/client_abc_fix.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/testbed_client/client_web.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/testbed_client/fixtures.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/testbed_client/user_model.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/vsource/target_model.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/writer.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core.egg-info/dependency_links.txt +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core.egg-info/top_level.txt +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core.egg-info/zip-safe +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/conftest.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_cal_data.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_cal_data_faulty.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_cal_meas.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_config_experiment.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_config_harvester.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/example_config_testbed.yaml +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_examples.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/data_models/test_testbed_fixtures.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/build_msp.elf +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/build_nrf.elf +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/conftest.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/test_converter.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/fw_tools/test_validation.py +1 -1
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/inventory/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/test_logger.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/test_reader.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/test_writer.py +4 -4
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/testbed_client/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/vsource/__init__.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/vsource/conftest.py +0 -0
- {shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/tests/vsource/test_z.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_core
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.10.1
|
|
4
4
|
Summary: Programming- and CLI-Interface for the h5-dataformat of the Shepherd-Testbed
|
|
5
5
|
Author-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
6
6
|
Maintainer-email: Ingmar Splitt <ingmar.splitt@tu-dresden.de>
|
|
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
26
|
Classifier: License :: OSI Approved :: MIT License
|
|
26
27
|
Classifier: Operating System :: OS Independent
|
|
27
28
|
Classifier: Natural Language :: English
|
|
@@ -43,15 +44,12 @@ Requires-Dist: pwntools-elf-only; extra == "elf"
|
|
|
43
44
|
Provides-Extra: inventory
|
|
44
45
|
Requires-Dist: psutil; extra == "inventory"
|
|
45
46
|
Provides-Extra: dev
|
|
46
|
-
Requires-Dist: twine; extra == "dev"
|
|
47
|
-
Requires-Dist: pre-commit; extra == "dev"
|
|
48
|
-
Requires-Dist: pyright; extra == "dev"
|
|
49
|
-
Requires-Dist: ruff; extra == "dev"
|
|
50
|
-
Requires-Dist: mypy; extra == "dev"
|
|
51
47
|
Requires-Dist: types-PyYAML; extra == "dev"
|
|
52
48
|
Provides-Extra: test
|
|
53
49
|
Requires-Dist: pytest; extra == "test"
|
|
54
50
|
Requires-Dist: coverage; extra == "test"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: shepherd-core[dev,elf,inventory,test]; extra == "all"
|
|
55
53
|
|
|
56
54
|
# Core Library
|
|
57
55
|
|
|
@@ -16,10 +16,11 @@ What the code does:
|
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
18
|
import shepherd_core.data_models as sm
|
|
19
|
-
from shepherd_core import WebClient
|
|
20
19
|
from shepherd_core.data_models.task import TestbedTasks
|
|
21
20
|
from shepherd_core.data_models.testbed import MCU
|
|
22
21
|
|
|
22
|
+
from shepherd_core import WebClient
|
|
23
|
+
|
|
23
24
|
# For online-queries the lib can be connected to the testbed-server.
|
|
24
25
|
# NOTE: there are 3 states:
|
|
25
26
|
# - unconnected -> demo-fixtures are queried (locally)
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
|
|
17
17
|
import shepherd_core.data_models as sm
|
|
18
|
-
from shepherd_core import WebClient
|
|
19
18
|
from shepherd_core.data_models.task import TestbedTasks
|
|
20
19
|
|
|
20
|
+
from shepherd_core import WebClient
|
|
21
|
+
|
|
21
22
|
# For online-queries the lib can be connected to the testbed-server.
|
|
22
23
|
# NOTE: there are 3 states:
|
|
23
24
|
# - unconnected -> demo-fixtures are queried (locally)
|
|
@@ -19,9 +19,10 @@ How to define an experiment:
|
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
21
|
import shepherd_core.data_models as sm
|
|
22
|
-
from shepherd_core import WebClient
|
|
23
22
|
from shepherd_core.data_models.task import TestbedTasks
|
|
24
23
|
|
|
24
|
+
from shepherd_core import WebClient
|
|
25
|
+
|
|
25
26
|
# generate description for all parameters -> base for web-forms
|
|
26
27
|
sm.Experiment.schema_to_file("experiment_schema.yaml")
|
|
27
28
|
|
|
@@ -6,11 +6,12 @@ or shepherd-core[elf].
|
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from shepherd_core import WebClient
|
|
10
|
-
from shepherd_core import fw_tools
|
|
11
9
|
from shepherd_core.data_models import Firmware
|
|
12
10
|
from shepherd_core.data_models import FirmwareDType
|
|
13
11
|
|
|
12
|
+
from shepherd_core import WebClient
|
|
13
|
+
from shepherd_core import fw_tools
|
|
14
|
+
|
|
14
15
|
path_elf = Path(__file__).parent.parent / "tests/fw_tools/build_msp.elf"
|
|
15
16
|
|
|
16
17
|
# Option 1 - fully manual
|
|
@@ -8,10 +8,11 @@ Note: make sure to have installed
|
|
|
8
8
|
import shutil
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
|
-
from shepherd_core import fw_tools
|
|
12
11
|
from shepherd_core.data_models import Firmware
|
|
13
12
|
from shepherd_core.data_models import FirmwareDType
|
|
14
13
|
|
|
14
|
+
from shepherd_core import fw_tools
|
|
15
|
+
|
|
15
16
|
path_src = Path(__file__).parent.parent / "tests/fw_tools/build_msp.elf"
|
|
16
17
|
path_elf = Path(__file__).with_name("firmware_msp.elf")
|
|
17
18
|
|
|
@@ -6,26 +6,31 @@
|
|
|
6
6
|
|
|
7
7
|
Output:
|
|
8
8
|
E_out = 0.000 mWs -> cv20
|
|
9
|
-
E_out = 17.
|
|
10
|
-
E_out = 17.
|
|
11
|
-
E_out = 17.
|
|
12
|
-
E_out = 13.
|
|
13
|
-
E_out = 15.
|
|
9
|
+
E_out = 17.143 mWs -> cv10
|
|
10
|
+
E_out = 17.384 mWs -> mppt_voc
|
|
11
|
+
E_out = 17.249 mWs -> mppt_bq_solar
|
|
12
|
+
E_out = 13.954 mWs -> mppt_bq_thermoelectric
|
|
13
|
+
E_out = 15.001 mWs -> mppt_po
|
|
14
14
|
E_out = 17.811 mWs -> mppt_opt
|
|
15
|
+
|
|
15
16
|
"""
|
|
16
17
|
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
|
|
19
|
-
from shepherd_core import Reader
|
|
20
20
|
from shepherd_core.data_models import VirtualHarvesterConfig
|
|
21
21
|
from shepherd_core.vsource import simulate_harvester
|
|
22
|
+
|
|
23
|
+
from shepherd_core import Reader
|
|
22
24
|
from shepherd_data import ivonne
|
|
23
25
|
|
|
24
26
|
# config simulation
|
|
25
27
|
sim_duration = 32
|
|
26
|
-
file_ivonne = Path(__file__).
|
|
28
|
+
file_ivonne = Path(__file__).parents[3] / "shepherd_data/examples/jogging_10m.iv"
|
|
27
29
|
file_ivcurve = Path(__file__).parent / "jogging_ivcurve.h5"
|
|
28
30
|
|
|
31
|
+
if not file_ivonne.exists():
|
|
32
|
+
raise FileNotFoundError("Input-File not found - check path")
|
|
33
|
+
|
|
29
34
|
hrv_list = [
|
|
30
35
|
"cv20",
|
|
31
36
|
# ⤷ fails due to lower solar voltage
|
|
@@ -39,7 +44,7 @@ hrv_list = [
|
|
|
39
44
|
"mppt_opt",
|
|
40
45
|
]
|
|
41
46
|
|
|
42
|
-
save_files: bool =
|
|
47
|
+
save_files: bool = True
|
|
43
48
|
|
|
44
49
|
# convert IVonne to IVCurve
|
|
45
50
|
if not file_ivcurve.exists():
|
|
@@ -10,20 +10,22 @@ The output file can be analyzed and plotted with shepherds tool suite.
|
|
|
10
10
|
|
|
11
11
|
Output:
|
|
12
12
|
E_out = 220.001 mWs -> direct (no current-limit)
|
|
13
|
-
E_out =
|
|
14
|
-
E_out =
|
|
15
|
-
E_out =
|
|
16
|
-
E_out =
|
|
17
|
-
E_out =
|
|
18
|
-
E_out =
|
|
13
|
+
E_out = 14.670 mWs -> diode+capacitor
|
|
14
|
+
E_out = 14.563 mWs -> diode+resistor+capacitor
|
|
15
|
+
E_out = 16.718 mWs -> BQ25504
|
|
16
|
+
E_out = 16.805 mWs -> BQ25504s
|
|
17
|
+
E_out = 16.369 mWs -> BQ25570
|
|
18
|
+
E_out = 16.387 mWs -> BQ25570s
|
|
19
19
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
|
|
24
24
|
from shepherd_core.data_models import VirtualSourceConfig
|
|
25
|
+
from shepherd_core.data_models import VirtualStorageConfig
|
|
25
26
|
from shepherd_core.vsource import ResistiveTarget
|
|
26
27
|
from shepherd_core.vsource import simulate_source
|
|
28
|
+
|
|
27
29
|
from shepherd_data import Reader
|
|
28
30
|
|
|
29
31
|
# config simulation
|
|
@@ -41,6 +43,11 @@ src_list = [
|
|
|
41
43
|
tgt = ResistiveTarget(R_Ohm=1_000, controlled=True)
|
|
42
44
|
save_files = True
|
|
43
45
|
|
|
46
|
+
if not file_input.exists():
|
|
47
|
+
raise FileNotFoundError(
|
|
48
|
+
"Input-File not found - please run harvester-simulation first to create it."
|
|
49
|
+
)
|
|
50
|
+
|
|
44
51
|
for src_name in src_list:
|
|
45
52
|
file_output = file_input.with_stem(file_input.stem + "_emu_" + src_name) if save_files else None
|
|
46
53
|
|
|
@@ -48,10 +55,12 @@ for src_name in src_list:
|
|
|
48
55
|
config=VirtualSourceConfig(
|
|
49
56
|
name=src_name,
|
|
50
57
|
C_output_uF=0,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# jogging-dataset has
|
|
54
|
-
|
|
58
|
+
V_intermediate_enable_output_threshold_mV=1,
|
|
59
|
+
V_intermediate_disable_output_threshold_mV=0,
|
|
60
|
+
# jogging-dataset has maximum VOC of ~1.6 V -> lower set-point for non-boost
|
|
61
|
+
storage=VirtualStorageConfig.capacitor(C_uF=100, V_rated=10.0)
|
|
62
|
+
if "direct" not in src_name
|
|
63
|
+
else None,
|
|
55
64
|
V_pwr_good_enable_threshold_mV=1300 if "dio" in src_name else 2800,
|
|
56
65
|
V_pwr_good_disable_threshold_mV=1000 if "dio" in src_name else 2400,
|
|
57
66
|
V_input_drop_mV=150 if "dio" in src_name else 0,
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""A set of experiments to validate and qualify the virtual storage algorithms.
|
|
2
|
+
|
|
3
|
+
Some general Notes:
|
|
4
|
+
|
|
5
|
+
- ShpCap is also displayed when emulating Lipo and lead-acid, but it can't and won't behave similar
|
|
6
|
+
- during charging the model KiBaM-Plus will deviate from normal KiBaM and KiBaM-Simple,
|
|
7
|
+
as it supports the rate capacity effect and transients (during charging)
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import multiprocessing
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
from datetime import timedelta
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from pydantic import PositiveFloat
|
|
18
|
+
from pydantic import validate_call
|
|
19
|
+
from shepherd_core.data_models.content.virtual_storage_config import VirtualStorageConfig
|
|
20
|
+
from shepherd_core.data_models.content.virtual_storage_config import soc_t
|
|
21
|
+
from shepherd_core.vsource.virtual_storage_model import ModelStorage
|
|
22
|
+
from shepherd_core.vsource.virtual_storage_model import VirtualStorageModel
|
|
23
|
+
from shepherd_core.vsource.virtual_storage_models_kibam import ModelKiBaM
|
|
24
|
+
from shepherd_core.vsource.virtual_storage_models_kibam import ModelKiBaMPlus
|
|
25
|
+
from shepherd_core.vsource.virtual_storage_models_kibam import ModelKiBaMSimple
|
|
26
|
+
from shepherd_core.vsource.virtual_storage_models_kibam import ModelShpCap
|
|
27
|
+
from shepherd_core.vsource.virtual_storage_simulator import StorageSimulator
|
|
28
|
+
|
|
29
|
+
from shepherd_core import log
|
|
30
|
+
|
|
31
|
+
path_here = Path(__file__).parent
|
|
32
|
+
|
|
33
|
+
duration_max = 20 if "PYTEST_CURRENT_TEST" in os.environ else sys.float_info.max
|
|
34
|
+
# ⤷ limits runtime for pytest
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@validate_call
|
|
38
|
+
def get_models(
|
|
39
|
+
SoC_init: soc_t, config: VirtualStorageConfig, dt_s: PositiveFloat
|
|
40
|
+
) -> list[ModelStorage]:
|
|
41
|
+
"""Models to include in experiments."""
|
|
42
|
+
return [
|
|
43
|
+
ModelKiBaM(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
|
|
44
|
+
ModelKiBaMPlus(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
|
|
45
|
+
ModelKiBaMSimple(SoC_init=SoC_init, cfg=config, dt_s=dt_s, optimize_clamp=True),
|
|
46
|
+
ModelKiBaMSimple(SoC_init=SoC_init, cfg=config, dt_s=dt_s, interpolate=True),
|
|
47
|
+
VirtualStorageModel(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
|
|
48
|
+
ModelShpCap(SoC_init=SoC_init, cfg=config, dt_s=dt_s),
|
|
49
|
+
][1:5]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CurrentPulsed:
|
|
53
|
+
"""A simple constant current source that is pulsed until a target SoC is reached."""
|
|
54
|
+
|
|
55
|
+
@validate_call
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
I_pulse: float,
|
|
59
|
+
period_pulse: PositiveFloat,
|
|
60
|
+
duration_pulse: PositiveFloat,
|
|
61
|
+
SoC_target: soc_t,
|
|
62
|
+
) -> None:
|
|
63
|
+
self.I_pulse = I_pulse
|
|
64
|
+
self.period_pulse = period_pulse
|
|
65
|
+
self.duration_pulse = duration_pulse
|
|
66
|
+
self.SoC_target = SoC_target
|
|
67
|
+
|
|
68
|
+
def step(self, t_s: float, SoC: float, _v: float) -> float:
|
|
69
|
+
if (self.I_pulse < 0 and SoC <= self.SoC_target) or (
|
|
70
|
+
self.I_pulse > 0 and SoC >= self.SoC_target
|
|
71
|
+
):
|
|
72
|
+
return 0
|
|
73
|
+
return self.I_pulse if t_s % self.period_pulse < self.duration_pulse else 0
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ResistiveChargePulsed:
|
|
77
|
+
"""A pulsed charger that is 'current limited' by a resistor."""
|
|
78
|
+
|
|
79
|
+
@validate_call
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
V_target: PositiveFloat,
|
|
83
|
+
R_Ohm: PositiveFloat,
|
|
84
|
+
period_pulse: PositiveFloat,
|
|
85
|
+
duration_pulse: PositiveFloat,
|
|
86
|
+
) -> None:
|
|
87
|
+
self.R_Ohm = R_Ohm
|
|
88
|
+
self.V_target = V_target
|
|
89
|
+
self.period_pulse = period_pulse
|
|
90
|
+
self.duration_pulse = duration_pulse
|
|
91
|
+
|
|
92
|
+
def step(self, t_s: float, _s: float, V: float) -> float:
|
|
93
|
+
I_A = (self.V_target - V) / self.R_Ohm
|
|
94
|
+
return I_A if t_s % self.period_pulse < self.duration_pulse else 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def experiment_current_ramp_pos(config: VirtualStorageConfig) -> None:
|
|
98
|
+
"""Charge virtual storage with a positive current ramp (increasing power)."""
|
|
99
|
+
dt_s = 0.1
|
|
100
|
+
SoC_start = 0.5
|
|
101
|
+
duration_s = min(200, duration_max)
|
|
102
|
+
sim = StorageSimulator(
|
|
103
|
+
models=get_models(SoC_start, config, dt_s),
|
|
104
|
+
dt_s=dt_s,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def current_trace(t_s: float, _s: float, _v: float) -> float:
|
|
108
|
+
return 0.1 + 0.15 * t_s / duration_s # pru-model can handle +- 268 mA
|
|
109
|
+
|
|
110
|
+
sim.run(fn=current_trace, duration_s=duration_s)
|
|
111
|
+
sim.plot(path_here, f"XP {config.name}, current charge ramp (positive)")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def experiment_current_ramp_neg(config: VirtualStorageConfig) -> None:
|
|
115
|
+
"""Discharge virtual storage with a negative current ramp (increasing power)."""
|
|
116
|
+
dt_s = 0.1
|
|
117
|
+
SoC_start = 0.5
|
|
118
|
+
duration_s = min(200, duration_max)
|
|
119
|
+
sim = StorageSimulator(
|
|
120
|
+
models=get_models(SoC_start, config, dt_s),
|
|
121
|
+
dt_s=dt_s,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def current_trace(t_s: float, _s: float, _v: float) -> float:
|
|
125
|
+
return -(0.1 + 0.14 * t_s / duration_s) # pru-model can handle +- 268 mA
|
|
126
|
+
|
|
127
|
+
sim.run(fn=current_trace, duration_s=duration_s)
|
|
128
|
+
sim.plot(path_here, f"XP {config.name}, current discharge ramp (negative)")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def experiment_pulsed_discharge(config: VirtualStorageConfig) -> None:
|
|
132
|
+
"""Discharge virtual storage with a pulsed constant current."""
|
|
133
|
+
dt_s = 0.2
|
|
134
|
+
SoC_start = 1.0
|
|
135
|
+
SoC_target = 0.0
|
|
136
|
+
i_pulse = CurrentPulsed(
|
|
137
|
+
I_pulse=-0.1, period_pulse=200, duration_pulse=100, SoC_target=SoC_target
|
|
138
|
+
) # pru-model can handle +- 268 mA
|
|
139
|
+
sim = StorageSimulator(
|
|
140
|
+
models=get_models(SoC_start, config, dt_s),
|
|
141
|
+
dt_s=dt_s,
|
|
142
|
+
)
|
|
143
|
+
sim.run(fn=i_pulse.step, duration_s=min(1_000, duration_max))
|
|
144
|
+
sim.plot(path_here, f"XP {config.name}, pulsed discharge .1A, 1000 s (figure_9a)")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def experiment_pulsed_charge(config: VirtualStorageConfig) -> None:
|
|
148
|
+
"""Charge virtual storage with a pulsed constant current."""
|
|
149
|
+
dt_s = 0.2
|
|
150
|
+
SoC_start = 0.0
|
|
151
|
+
SoC_target = 1.0
|
|
152
|
+
i_pulse = CurrentPulsed(
|
|
153
|
+
I_pulse=0.1, period_pulse=200, duration_pulse=100, SoC_target=SoC_target
|
|
154
|
+
) # pru-model can handle +- 268 mA
|
|
155
|
+
sim = StorageSimulator(
|
|
156
|
+
models=get_models(SoC_start, config, dt_s),
|
|
157
|
+
dt_s=dt_s,
|
|
158
|
+
)
|
|
159
|
+
sim.run(fn=i_pulse.step, duration_s=min(1_000, duration_max))
|
|
160
|
+
sim.plot(path_here, f"XP {config.name}, pulsed charge .1A, 1000 s (figure_9b)")
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def experiment_pulsed_resistive_charge(config: VirtualStorageConfig) -> None:
|
|
164
|
+
"""Charge virtual storage with a resistive constant voltage."""
|
|
165
|
+
dt_s = 0.5
|
|
166
|
+
SoC_start = 0.0
|
|
167
|
+
i_pulse = ResistiveChargePulsed(R_Ohm=20, V_target=4.2, period_pulse=200, duration_pulse=100)
|
|
168
|
+
sim = StorageSimulator(
|
|
169
|
+
models=get_models(SoC_start, config, dt_s),
|
|
170
|
+
dt_s=dt_s,
|
|
171
|
+
)
|
|
172
|
+
sim.run(fn=i_pulse.step, duration_s=min(3_000, duration_max))
|
|
173
|
+
sim.plot(path_here, f"XP {config.name}, pulsed resistive charge 20 Ohm to 4.2 V, 3000 s")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def experiment_resistive_load(config: VirtualStorageConfig) -> None:
|
|
177
|
+
"""Charge virtual storage with a resistive constant voltage."""
|
|
178
|
+
dt_s = 0.5
|
|
179
|
+
SoC_start = 1.0
|
|
180
|
+
|
|
181
|
+
def i_charge(_t_s: float, _s: float, V: float) -> float:
|
|
182
|
+
return -V / 20
|
|
183
|
+
|
|
184
|
+
sim = StorageSimulator(
|
|
185
|
+
models=get_models(SoC_start, config, dt_s),
|
|
186
|
+
dt_s=dt_s,
|
|
187
|
+
)
|
|
188
|
+
sim.run(fn=i_charge, duration_s=min(1_000, duration_max))
|
|
189
|
+
sim.plot(path_here, f"XP {config.name}, resistive load 20 Ohm from 4.2 V, 1000 s")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def experiment_self_discharge() -> None:
|
|
193
|
+
"""Observe self-discharge behavior of virtual storage models."""
|
|
194
|
+
dt_s = 0.2
|
|
195
|
+
SoC_start = 1.0
|
|
196
|
+
SoC_target = 0.9
|
|
197
|
+
duration = timedelta(minutes=25)
|
|
198
|
+
store = VirtualStorageConfig.capacitor(C_uF=100, V_rated=6.3)
|
|
199
|
+
R_leak = store.calc_R_leak_capacitor(duration=duration, SoC_final=SoC_target, SoC_0=SoC_start)
|
|
200
|
+
log.info("R_leak = %.2f Ohm", R_leak)
|
|
201
|
+
config = VirtualStorageConfig.capacitor(C_uF=100, V_rated=6.3, R_leak_Ohm=R_leak)
|
|
202
|
+
sim = StorageSimulator(
|
|
203
|
+
models=get_models(SoC_start, config, dt_s),
|
|
204
|
+
dt_s=dt_s,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def step(_t: float, _s: float, _v: float) -> float:
|
|
208
|
+
return 0
|
|
209
|
+
|
|
210
|
+
sim.run(fn=step, duration_s=min(duration.total_seconds(), duration_max))
|
|
211
|
+
sim.plot(
|
|
212
|
+
path_here,
|
|
213
|
+
f"XP {config.name}, self-discharge, "
|
|
214
|
+
f"SoC {SoC_start} to {SoC_target} in {duration.total_seconds()} s",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
if __name__ == "__main__":
|
|
219
|
+
with multiprocessing.Pool() as pool:
|
|
220
|
+
pool.apply_async(experiment_self_discharge)
|
|
221
|
+
|
|
222
|
+
configs = [
|
|
223
|
+
VirtualStorageConfig.capacitor(C_uF=10e6, V_rated=4.2), # match charge with batteries
|
|
224
|
+
VirtualStorageConfig.lipo(q_mAh=10),
|
|
225
|
+
VirtualStorageConfig.lead_acid(q_mAh=10),
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
for cfg in configs:
|
|
229
|
+
pool.apply_async(experiment_pulsed_charge, args=(cfg,))
|
|
230
|
+
pool.apply_async(experiment_pulsed_discharge, args=(cfg,))
|
|
231
|
+
pool.apply_async(experiment_current_ramp_pos, args=(cfg,))
|
|
232
|
+
pool.apply_async(experiment_current_ramp_neg, args=(cfg,))
|
|
233
|
+
|
|
234
|
+
for cfg in configs[0:2]:
|
|
235
|
+
pool.apply_async(experiment_pulsed_resistive_charge, args=(cfg,))
|
|
236
|
+
pool.apply_async(experiment_resistive_load, args=(cfg,))
|
|
237
|
+
|
|
238
|
+
pool.close()
|
|
239
|
+
pool.join()
|
|
@@ -18,6 +18,7 @@ classifiers = [
|
|
|
18
18
|
"Programming Language :: Python :: 3.11",
|
|
19
19
|
"Programming Language :: Python :: 3.12",
|
|
20
20
|
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
21
22
|
"License :: OSI Approved :: MIT License",
|
|
22
23
|
"Operating System :: OS Independent",
|
|
23
24
|
"Natural Language :: English",
|
|
@@ -52,11 +53,6 @@ inventory = [
|
|
|
52
53
|
]
|
|
53
54
|
|
|
54
55
|
dev = [
|
|
55
|
-
"twine",
|
|
56
|
-
"pre-commit",
|
|
57
|
-
"pyright",
|
|
58
|
-
"ruff",
|
|
59
|
-
"mypy",
|
|
60
56
|
"types-PyYAML",
|
|
61
57
|
]
|
|
62
58
|
|
|
@@ -64,6 +60,7 @@ test = [
|
|
|
64
60
|
"pytest",
|
|
65
61
|
"coverage",
|
|
66
62
|
]
|
|
63
|
+
all = ["shepherd-core[elf,inventory,dev,test]"]
|
|
67
64
|
|
|
68
65
|
[project.readme]
|
|
69
66
|
file = "README.md"
|
|
@@ -22,8 +22,9 @@ from .content.energy_environment import EnergyDType
|
|
|
22
22
|
from .content.energy_environment import EnergyEnvironment
|
|
23
23
|
from .content.firmware import Firmware
|
|
24
24
|
from .content.firmware import FirmwareDType
|
|
25
|
-
from .content.
|
|
26
|
-
from .content.
|
|
25
|
+
from .content.virtual_harvester_config import VirtualHarvesterConfig
|
|
26
|
+
from .content.virtual_source_config import VirtualSourceConfig
|
|
27
|
+
from .content.virtual_storage_config import VirtualStorageConfig
|
|
27
28
|
from .experiment.experiment import Experiment
|
|
28
29
|
from .experiment.observer_features import GpioActuation
|
|
29
30
|
from .experiment.observer_features import GpioEvent
|
|
@@ -58,5 +59,6 @@ __all__ = [
|
|
|
58
59
|
"UartLogging",
|
|
59
60
|
"VirtualHarvesterConfig",
|
|
60
61
|
"VirtualSourceConfig",
|
|
62
|
+
"VirtualStorageConfig",
|
|
61
63
|
"Wrapper",
|
|
62
64
|
]
|
{shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/base/content.py
RENAMED
|
@@ -36,10 +36,12 @@ class ContentModel(ShpModel):
|
|
|
36
36
|
default_factory=id_default,
|
|
37
37
|
)
|
|
38
38
|
name: NameStr
|
|
39
|
+
""" ⤷ name of virtual content, models can be queried by this slug."""
|
|
39
40
|
description: Annotated[SafeStr | None, Field(description="Required when public")] = None
|
|
40
41
|
comment: SafeStr | None = None
|
|
41
42
|
created: datetime = Field(default_factory=datetime.now)
|
|
42
43
|
updated_last: datetime = Field(default_factory=datetime.now)
|
|
44
|
+
# TODO: add dedicated 'inherit_from' field?
|
|
43
45
|
|
|
44
46
|
# Ownership & Access
|
|
45
47
|
# TODO: remove owner & group, only needed for DB
|
{shepherd_core-2025.6.4 → shepherd_core-2025.10.1}/shepherd_core/data_models/content/__init__.py
RENAMED
|
@@ -7,8 +7,9 @@ from .energy_environment import EnergyDType
|
|
|
7
7
|
from .energy_environment import EnergyEnvironment
|
|
8
8
|
from .firmware import Firmware
|
|
9
9
|
from .firmware_datatype import FirmwareDType
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
10
|
+
from .virtual_harvester_config import VirtualHarvesterConfig
|
|
11
|
+
from .virtual_source_config import VirtualSourceConfig
|
|
12
|
+
from .virtual_storage_config import VirtualStorageConfig
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
"EnergyDType",
|
|
@@ -17,4 +18,5 @@ __all__ = [
|
|
|
17
18
|
"FirmwareDType",
|
|
18
19
|
"VirtualHarvesterConfig",
|
|
19
20
|
"VirtualSourceConfig",
|
|
21
|
+
"VirtualStorageConfig",
|
|
20
22
|
]
|
|
@@ -332,11 +332,11 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
|
|
|
332
332
|
@model_validator(mode="after")
|
|
333
333
|
def post_validation(self) -> Self:
|
|
334
334
|
if self.voltage_min_mV > self.voltage_max_mV:
|
|
335
|
-
raise ValueError("Voltage
|
|
335
|
+
raise ValueError("Voltage minimum > max")
|
|
336
336
|
if self.voltage_mV < self.voltage_min_mV:
|
|
337
|
-
raise ValueError("Voltage below
|
|
337
|
+
raise ValueError("Voltage below minimum")
|
|
338
338
|
if self.voltage_mV > self.voltage_max_mV:
|
|
339
|
-
raise ValueError("Voltage above
|
|
339
|
+
raise ValueError("Voltage above maximum")
|
|
340
340
|
|
|
341
341
|
return self
|
|
342
342
|
|