shepherd-core 2025.5.3__tar.gz → 2025.6.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.5.3 → shepherd_core-2025.6.1}/PKG-INFO +12 -12
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/README.md +9 -9
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/pyproject.toml +2 -2
- shepherd_core-2025.6.1/shepherd_core/commons.py +6 -0
- shepherd_core-2025.6.1/shepherd_core/config.py +34 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/calibration.py +13 -8
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/wrapper.py +4 -4
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/energy_environment.py +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/firmware.py +10 -5
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/virtual_harvester.py +10 -10
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/virtual_source.py +36 -28
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/virtual_source_fixture.yaml +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/experiment/experiment.py +28 -18
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/experiment/observer_features.py +30 -11
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/experiment/target_config.py +17 -7
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/emulation.py +38 -25
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/firmware_mod.py +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/harvest.py +14 -13
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/observer_tasks.py +4 -3
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/programming.py +2 -2
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/testbed_tasks.py +4 -7
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/cape_fixture.yaml +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/observer.py +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/observer_fixture.yaml +2 -2
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/target.py +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/target_fixture.old1 +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/target_fixture.yaml +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/testbed.py +8 -9
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/fw_tools/patcher.py +7 -8
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/inventory/system.py +1 -3
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/reader.py +9 -2
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/testbed_client/cache_path.py +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/testbed_client/client_web.py +2 -2
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/version.py +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/writer.py +2 -2
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core.egg-info/PKG-INFO +12 -12
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core.egg-info/SOURCES.txt +1 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_config_emulator.yaml +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_config_harvester.yaml +1 -1
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_experiment_models.py +1 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/test_patcher.py +6 -6
- shepherd_core-2025.5.3/shepherd_core/commons.py +0 -8
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/eenv_generator.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/experiment_from_yaml.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/experiment_generic_var1.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/experiment_generic_var2.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/experiment_models.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/firmware_model.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/firmware_modification.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/inventory.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/simulate_vharvester.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/simulate_vsource.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/uart_decode_waveform.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/uart_raw2.csv +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/examples/vsource_debug_sim.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/setup.cfg +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/calibration_hw_def.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/cal_measurement.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/content.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/shepherd.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/timezone.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/_external_fixtures.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/energy_environment_fixture.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/firmware_datatype.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/virtual_harvester_fixture.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/experiment/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/readme.md +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/task/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/cape.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/gpio.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/gpio_fixture.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/mcu.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/mcu_fixture.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/testbed/testbed_fixture.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/virtual_source_doc.txt +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/decoder_waveform/uart.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/fw_tools/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/fw_tools/converter.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/fw_tools/converter_elf.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/fw_tools/validation.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/inventory/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/inventory/python.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/inventory/target.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/logger.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/testbed_client/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/testbed_client/client_abc_fix.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/testbed_client/fixtures.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/testbed_client/user_model.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/target_model.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/virtual_converter_model.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/virtual_harvester_model.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/virtual_harvester_simulation.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/virtual_source_model.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/vsource/virtual_source_simulation.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core.egg-info/dependency_links.txt +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core.egg-info/requires.txt +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core.egg-info/top_level.txt +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core.egg-info/zip-safe +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/conftest.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/conftest.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_cal_data.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_cal_data_faulty.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_cal_meas.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_cal_meas_faulty1.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_cal_meas_faulty2.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_config_experiment.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_config_experiment_alternative.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_config_testbed.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/example_config_virtsource.yaml +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_base_models.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_content_fixtures.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_content_models.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_examples.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_task_generation.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_task_models.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_testbed_fixtures.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/data_models/test_testbed_models.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/decoder_waveform/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/decoder_waveform/test_decoder.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/build_msp.elf +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/build_nrf.elf +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/conftest.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/test_converter.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/fw_tools/test_validation.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/inventory/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/inventory/test_inventory.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/test_cal_hw.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/test_examples.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/test_logger.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/test_reader.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/test_writer.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/testbed_client/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/vsource/__init__.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/vsource/conftest.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/vsource/test_converter.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/vsource/test_harvester.py +0 -0
- {shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/tests/vsource/test_z.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shepherd_core
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.6.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>
|
|
7
|
-
Project-URL: Documentation, https://github.com/
|
|
8
|
-
Project-URL: Issues, https://github.com/
|
|
7
|
+
Project-URL: Documentation, https://github.com/nes-lab/shepherd-tools/blob/main/README.md
|
|
8
|
+
Project-URL: Issues, https://github.com/nes-lab/shepherd-tools/issues
|
|
9
9
|
Project-URL: Source, https://pypi.org/project/shepherd-core/
|
|
10
10
|
Keywords: testbed,beaglebone,pru,batteryless,energyharvesting,solar
|
|
11
11
|
Platform: unix
|
|
@@ -56,16 +56,16 @@ Requires-Dist: coverage; extra == "test"
|
|
|
56
56
|
|
|
57
57
|
# Core Library
|
|
58
58
|
|
|
59
|
-
[](https://pypi.org/project/shepherd_core)
|
|
60
60
|
[](https://pypi.python.org/pypi/shepherd-core)
|
|
61
|
-
[](https://github.com/nes-lab/shepherd-tools/actions/workflows/quality_assurance.yaml)
|
|
62
62
|
[](https://github.com/astral-sh/ruff)
|
|
63
63
|
|
|
64
|
-
**Main Documentation**: <https://
|
|
64
|
+
**Main Documentation**: <https://nes-lab.github.io/shepherd>
|
|
65
65
|
|
|
66
|
-
**Source Code**: <https://github.com/
|
|
66
|
+
**Source Code**: <https://github.com/nes-lab/shepherd-tools>
|
|
67
67
|
|
|
68
|
-
**Main Project**: <https://github.com/
|
|
68
|
+
**Main Project**: <https://github.com/nes-lab/shepherd>
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
|
@@ -87,7 +87,7 @@ For postprocessing shepherds .h5-files usage of [shepherd_data](https://pypi.org
|
|
|
87
87
|
- decode waveforms (gpio-state & timestamp) to UART
|
|
88
88
|
- create an inventory (for deployed versions of software, hardware)
|
|
89
89
|
|
|
90
|
-
See [official documentation](https://
|
|
90
|
+
See [official documentation](https://nes-lab.github.io/shepherd) or [example scripts](https://github.com/nes-lab/shepherd-tools/tree/main/shepherd_core/examples) for more details and usage. Most functionality is showcased in both. The [extra](https://github.com/nes-lab/shepherd-tools/tree/main/shepherd_core/extra)-directory holds data-generators relevant for the testbed. Notably is a [trafficbench](https://github.com/nes-lab/TrafficBench)-experiment that's used to derive the link-matrix of the testbed-nodes.
|
|
91
91
|
|
|
92
92
|
## Config-Models in Detail
|
|
93
93
|
|
|
@@ -145,9 +145,9 @@ pip install shepherd-data -U
|
|
|
145
145
|
For bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
|
|
146
146
|
|
|
147
147
|
```Shell
|
|
148
|
-
pip install git+https://github.com/
|
|
148
|
+
pip install git+https://github.com/nes-lab/shepherd-tools.git@dev#subdirectory=shepherd_core -U
|
|
149
149
|
# and on sheep with newer debian
|
|
150
|
-
sudo pip install git+https://github.com/
|
|
150
|
+
sudo pip install git+https://github.com/nes-lab/shepherd-tools.git@dev#subdirectory=shepherd_core -U --break-system-packages
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
If you are working with ``.elf``-files (embedding into experiments) you make "objcopy" accessible to python. In Ubuntu, you can either install ``build-essential`` or ``binutils-$ARCH`` with arch being ``msp430`` or ``arm-none-eabi`` for the nRF52.
|
|
@@ -179,7 +179,7 @@ To run the testbench, follow these steps:
|
|
|
179
179
|
3. run the testbench (~ 320 tests):
|
|
180
180
|
|
|
181
181
|
```Shell
|
|
182
|
-
cd shepherd-
|
|
182
|
+
cd shepherd-tools/shepherd_core
|
|
183
183
|
pip3 install ./[tests]
|
|
184
184
|
pytest
|
|
185
185
|
```
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Core Library
|
|
2
2
|
|
|
3
|
-
[](https://pypi.org/project/shepherd_core)
|
|
4
4
|
[](https://pypi.python.org/pypi/shepherd-core)
|
|
5
|
-
[](https://github.com/nes-lab/shepherd-tools/actions/workflows/quality_assurance.yaml)
|
|
6
6
|
[](https://github.com/astral-sh/ruff)
|
|
7
7
|
|
|
8
|
-
**Main Documentation**: <https://
|
|
8
|
+
**Main Documentation**: <https://nes-lab.github.io/shepherd>
|
|
9
9
|
|
|
10
|
-
**Source Code**: <https://github.com/
|
|
10
|
+
**Source Code**: <https://github.com/nes-lab/shepherd-tools>
|
|
11
11
|
|
|
12
|
-
**Main Project**: <https://github.com/
|
|
12
|
+
**Main Project**: <https://github.com/nes-lab/shepherd>
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -31,7 +31,7 @@ For postprocessing shepherds .h5-files usage of [shepherd_data](https://pypi.org
|
|
|
31
31
|
- decode waveforms (gpio-state & timestamp) to UART
|
|
32
32
|
- create an inventory (for deployed versions of software, hardware)
|
|
33
33
|
|
|
34
|
-
See [official documentation](https://
|
|
34
|
+
See [official documentation](https://nes-lab.github.io/shepherd) or [example scripts](https://github.com/nes-lab/shepherd-tools/tree/main/shepherd_core/examples) for more details and usage. Most functionality is showcased in both. The [extra](https://github.com/nes-lab/shepherd-tools/tree/main/shepherd_core/extra)-directory holds data-generators relevant for the testbed. Notably is a [trafficbench](https://github.com/nes-lab/TrafficBench)-experiment that's used to derive the link-matrix of the testbed-nodes.
|
|
35
35
|
|
|
36
36
|
## Config-Models in Detail
|
|
37
37
|
|
|
@@ -89,9 +89,9 @@ pip install shepherd-data -U
|
|
|
89
89
|
For bleeding-edge-features or dev-work it is possible to install directly from GitHub-Sources (here `dev`-branch):
|
|
90
90
|
|
|
91
91
|
```Shell
|
|
92
|
-
pip install git+https://github.com/
|
|
92
|
+
pip install git+https://github.com/nes-lab/shepherd-tools.git@dev#subdirectory=shepherd_core -U
|
|
93
93
|
# and on sheep with newer debian
|
|
94
|
-
sudo pip install git+https://github.com/
|
|
94
|
+
sudo pip install git+https://github.com/nes-lab/shepherd-tools.git@dev#subdirectory=shepherd_core -U --break-system-packages
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
If you are working with ``.elf``-files (embedding into experiments) you make "objcopy" accessible to python. In Ubuntu, you can either install ``build-essential`` or ``binutils-$ARCH`` with arch being ``msp430`` or ``arm-none-eabi`` for the nRF52.
|
|
@@ -123,7 +123,7 @@ To run the testbench, follow these steps:
|
|
|
123
123
|
3. run the testbench (~ 320 tests):
|
|
124
124
|
|
|
125
125
|
```Shell
|
|
126
|
-
cd shepherd-
|
|
126
|
+
cd shepherd-tools/shepherd_core
|
|
127
127
|
pip3 install ./[tests]
|
|
128
128
|
pytest
|
|
129
129
|
```
|
|
@@ -71,8 +71,8 @@ file = "README.md"
|
|
|
71
71
|
content-type = "text/markdown"
|
|
72
72
|
|
|
73
73
|
[project.urls]
|
|
74
|
-
Documentation = "https://github.com/
|
|
75
|
-
Issues = "https://github.com/
|
|
74
|
+
Documentation = "https://github.com/nes-lab/shepherd-tools/blob/main/README.md"
|
|
75
|
+
Issues = "https://github.com/nes-lab/shepherd-tools/issues"
|
|
76
76
|
Source = "https://pypi.org/project/shepherd-core/"
|
|
77
77
|
|
|
78
78
|
[build-system]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Container for a common configuration.
|
|
2
|
+
|
|
3
|
+
This can be adapted by the user by importing 'config' and changing its variables.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
from pydantic import HttpUrl
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConfigDefault(BaseModel):
|
|
11
|
+
"""Container for a common configuration."""
|
|
12
|
+
|
|
13
|
+
__slots__ = ()
|
|
14
|
+
|
|
15
|
+
TESTBED: str = "shepherd_tud_nes"
|
|
16
|
+
"""name of the testbed to validate against - if enabled - see switch below"""
|
|
17
|
+
VALIDATE_INFRA: bool = True
|
|
18
|
+
"""switch to turn on / off deep validation of data models also considering the current
|
|
19
|
+
layout & infrastructure of the testbed.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
SAMPLERATE_SPS: int = 100_000
|
|
23
|
+
"""Rate of IV-Recording of the testbed."""
|
|
24
|
+
|
|
25
|
+
UID_NAME: str = "SHEPHERD_NODE_ID"
|
|
26
|
+
"""Variable name to patch in ELF-file"""
|
|
27
|
+
UID_SIZE: int = 2
|
|
28
|
+
"""Variable size in Byte"""
|
|
29
|
+
|
|
30
|
+
TESTBED_SERVER: HttpUrl = "https://shepherd.cfaed.tu-dresden.de:8000/"
|
|
31
|
+
"""Server that holds up to date testbed fixtures"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
config = ConfigDefault()
|
{shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/base/calibration.py
RENAMED
|
@@ -95,14 +95,19 @@ cal_hrv_legacy = { # legacy translator
|
|
|
95
95
|
"adc_voltage": "adc_V_Sense", # datalog voltage
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
# defaults (pre-init complex types)
|
|
99
|
+
cal_pair_dac_V = CalibrationPair.from_fn(dac_voltage_to_raw, unit="V")
|
|
100
|
+
cal_pair_adc_V = CalibrationPair.from_fn(adc_voltage_to_raw, unit="V")
|
|
101
|
+
cal_pair_adc_C = CalibrationPair.from_fn(adc_current_to_raw, unit="A")
|
|
102
|
+
|
|
98
103
|
|
|
99
104
|
class CalibrationHarvester(ShpModel):
|
|
100
105
|
"""Container for all calibration-pairs for that device."""
|
|
101
106
|
|
|
102
|
-
dac_V_Hrv: CalibrationPair =
|
|
103
|
-
dac_V_Sim: CalibrationPair =
|
|
104
|
-
adc_V_Sense: CalibrationPair =
|
|
105
|
-
adc_C_Hrv: CalibrationPair =
|
|
107
|
+
dac_V_Hrv: CalibrationPair = cal_pair_dac_V
|
|
108
|
+
dac_V_Sim: CalibrationPair = cal_pair_dac_V
|
|
109
|
+
adc_V_Sense: CalibrationPair = cal_pair_adc_V
|
|
110
|
+
adc_C_Hrv: CalibrationPair = cal_pair_adc_C
|
|
106
111
|
|
|
107
112
|
def export_for_sysfs(self) -> dict:
|
|
108
113
|
"""Convert and write the essential data.
|
|
@@ -143,10 +148,10 @@ class CalibrationEmulator(ShpModel):
|
|
|
143
148
|
Differentiates between both target-ports A/B.
|
|
144
149
|
"""
|
|
145
150
|
|
|
146
|
-
dac_V_A: CalibrationPair =
|
|
147
|
-
dac_V_B: CalibrationPair =
|
|
148
|
-
adc_C_A: CalibrationPair =
|
|
149
|
-
adc_C_B: CalibrationPair =
|
|
151
|
+
dac_V_A: CalibrationPair = cal_pair_dac_V
|
|
152
|
+
dac_V_B: CalibrationPair = cal_pair_dac_V
|
|
153
|
+
adc_C_A: CalibrationPair = cal_pair_adc_C
|
|
154
|
+
adc_C_B: CalibrationPair = cal_pair_adc_C
|
|
150
155
|
|
|
151
156
|
def export_for_sysfs(self) -> dict:
|
|
152
157
|
"""Convert and write the essential data.
|
|
@@ -17,11 +17,11 @@ class Wrapper(BaseModel):
|
|
|
17
17
|
"""Generalized web- & file-interface for all models with dynamic typecasting."""
|
|
18
18
|
|
|
19
19
|
datatype: str
|
|
20
|
-
|
|
20
|
+
""" ⤷ model-name"""
|
|
21
21
|
comment: Optional[SafeStrClone] = None
|
|
22
22
|
created: Optional[datetime] = None
|
|
23
|
-
|
|
23
|
+
""" ⤷ Optional metadata"""
|
|
24
24
|
lib_ver: Optional[str] = version
|
|
25
|
-
|
|
25
|
+
""" ⤷ for debug-purposes and later compatibility-checks"""
|
|
26
26
|
parameters: dict
|
|
27
|
-
|
|
27
|
+
""" ⤷ ShpModel"""
|
|
@@ -28,7 +28,7 @@ class EnergyEnvironment(ContentModel):
|
|
|
28
28
|
data_path: Path
|
|
29
29
|
data_type: EnergyDType
|
|
30
30
|
data_local: bool = True
|
|
31
|
-
|
|
31
|
+
""" ⤷ signals that file has to be copied to testbed"""
|
|
32
32
|
|
|
33
33
|
duration: PositiveFloat
|
|
34
34
|
energy_Ws: PositiveFloat
|
{shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/content/firmware.py
RENAMED
|
@@ -62,7 +62,7 @@ class Firmware(ContentModel, title="Firmware of Target"):
|
|
|
62
62
|
data_type: FirmwareDType
|
|
63
63
|
data_hash: Optional[str] = None
|
|
64
64
|
data_local: bool = True
|
|
65
|
-
|
|
65
|
+
""" ⤷ signals that file has to be copied to testbed"""
|
|
66
66
|
|
|
67
67
|
@model_validator(mode="before")
|
|
68
68
|
@classmethod
|
|
@@ -125,12 +125,17 @@ class Firmware(ContentModel, title="Firmware of Target"):
|
|
|
125
125
|
if "mcu" not in kwargs:
|
|
126
126
|
kwargs["mcu"] = arch_to_mcu[arch]
|
|
127
127
|
|
|
128
|
+
# verification of ELF - warn if something is off
|
|
129
|
+
# -> adds ARCH if it is able to derive
|
|
128
130
|
if kwargs["data_type"] == FirmwareDType.base64_elf:
|
|
129
131
|
arch = fw_tools.read_arch(file)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
try:
|
|
133
|
+
if "msp430" in arch and not fw_tools.is_elf_msp430(file):
|
|
134
|
+
raise ValueError("File is not a ELF for msp430")
|
|
135
|
+
if ("nrf52" in arch or "arm" in arch) and not fw_tools.is_elf_nrf52(file):
|
|
136
|
+
raise ValueError("File is not a ELF for nRF52")
|
|
137
|
+
except RuntimeError:
|
|
138
|
+
logger.warning("ObjCopy not found -> Arch of Firmware can't be verified")
|
|
134
139
|
logger.debug("ELF-File '%s' has arch: %s", file.name, arch)
|
|
135
140
|
if "mcu" not in kwargs:
|
|
136
141
|
kwargs["mcu"] = arch_to_mcu[arch]
|
|
@@ -10,7 +10,7 @@ from pydantic import Field
|
|
|
10
10
|
from pydantic import model_validator
|
|
11
11
|
from typing_extensions import Self
|
|
12
12
|
|
|
13
|
-
from shepherd_core.
|
|
13
|
+
from shepherd_core.config import config
|
|
14
14
|
from shepherd_core.data_models.base.calibration import CalibrationHarvester
|
|
15
15
|
from shepherd_core.data_models.base.content import ContentModel
|
|
16
16
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
@@ -363,9 +363,9 @@ class VirtualHarvesterConfig(ContentModel, title="Config for the Harvester"):
|
|
|
363
363
|
def calc_timings_ms(self, *, for_emu: bool) -> tuple[float, float]:
|
|
364
364
|
"""factor-in model-internal timing-constraints."""
|
|
365
365
|
window_length = self.samples_n * (1 + self.wait_cycles)
|
|
366
|
-
time_min_ms = (1 + self.wait_cycles) * 1_000 /
|
|
366
|
+
time_min_ms = (1 + self.wait_cycles) * 1_000 / config.SAMPLERATE_SPS
|
|
367
367
|
if for_emu:
|
|
368
|
-
window_ms = window_length * 1_000 /
|
|
368
|
+
window_ms = window_length * 1_000 / config.SAMPLERATE_SPS
|
|
369
369
|
time_min_ms = max(time_min_ms, window_ms)
|
|
370
370
|
|
|
371
371
|
interval_ms = min(max(self.interval_ms, time_min_ms), 1_000_000)
|
|
@@ -453,16 +453,16 @@ class HarvesterPRUConfig(ShpModel):
|
|
|
453
453
|
voltage_min_uV: u32
|
|
454
454
|
voltage_max_uV: u32
|
|
455
455
|
voltage_step_uV: u32
|
|
456
|
-
|
|
456
|
+
""" ⤷ for window-based algo like ivcurve"""
|
|
457
457
|
current_limit_nA: u32
|
|
458
|
-
|
|
458
|
+
""" ⤷ lower bound to detect zero current"""
|
|
459
459
|
setpoint_n8: u32
|
|
460
460
|
interval_n: u32
|
|
461
|
-
|
|
461
|
+
""" ⤷ between measurements"""
|
|
462
462
|
duration_n: u32
|
|
463
|
-
|
|
463
|
+
""" ⤷ of measurement"""
|
|
464
464
|
wait_cycles_n: u32
|
|
465
|
-
|
|
465
|
+
""" ⤷ for DAC to settle"""
|
|
466
466
|
|
|
467
467
|
@classmethod
|
|
468
468
|
def from_vhrv(
|
|
@@ -517,7 +517,7 @@ class HarvesterPRUConfig(ShpModel):
|
|
|
517
517
|
voltage_step_uV=round(voltage_step_mV * 10**3),
|
|
518
518
|
current_limit_nA=round(data.current_limit_uA * 10**3),
|
|
519
519
|
setpoint_n8=round(min(255, data.setpoint_n * 2**8)),
|
|
520
|
-
interval_n=round(interval_ms *
|
|
521
|
-
duration_n=round(duration_ms *
|
|
520
|
+
interval_n=round(interval_ms * config.SAMPLERATE_SPS * 1e-3),
|
|
521
|
+
duration_n=round(duration_ms * config.SAMPLERATE_SPS * 1e-3),
|
|
522
522
|
wait_cycles_n=data.wait_cycles,
|
|
523
523
|
)
|
|
@@ -7,7 +7,7 @@ from pydantic import Field
|
|
|
7
7
|
from pydantic import model_validator
|
|
8
8
|
from typing_extensions import Self
|
|
9
9
|
|
|
10
|
-
from shepherd_core.
|
|
10
|
+
from shepherd_core.config import config
|
|
11
11
|
from shepherd_core.data_models.base.content import ContentModel
|
|
12
12
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
13
13
|
from shepherd_core.logger import logger
|
|
@@ -23,6 +23,9 @@ NormedNum = Annotated[float, Field(ge=0.0, le=1.0)]
|
|
|
23
23
|
LUT1D = Annotated[list[NormedNum], Field(min_length=LUT_SIZE, max_length=LUT_SIZE)]
|
|
24
24
|
LUT2D = Annotated[list[LUT1D], Field(min_length=LUT_SIZE, max_length=LUT_SIZE)]
|
|
25
25
|
|
|
26
|
+
# defaults (pre-init complex types for improved perf) TODO: is documentation still fine?
|
|
27
|
+
vhrv_mppt_opt = VirtualHarvesterConfig(name="mppt_opt")
|
|
28
|
+
|
|
26
29
|
|
|
27
30
|
class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
28
31
|
"""The vSrc uses the energy environment (file) for supplying the Target Node.
|
|
@@ -41,46 +44,48 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
41
44
|
# General Metadata & Ownership -> ContentModel
|
|
42
45
|
|
|
43
46
|
enable_boost: bool = False
|
|
44
|
-
|
|
47
|
+
""" ⤷ if false -> v_intermediate = v_input, output-switch-hysteresis is still usable"""
|
|
45
48
|
enable_buck: bool = False
|
|
46
|
-
|
|
49
|
+
""" ⤷ if false -> v_output = v_intermediate"""
|
|
47
50
|
enable_feedback_to_hrv: bool = False
|
|
48
|
-
|
|
51
|
+
""" src can control a cv-harvester for ivcurve"""
|
|
49
52
|
|
|
50
53
|
interval_startup_delay_drain_ms: Annotated[float, Field(ge=0, le=10_000)] = 0
|
|
51
54
|
|
|
52
|
-
harvester: VirtualHarvesterConfig =
|
|
55
|
+
harvester: VirtualHarvesterConfig = vhrv_mppt_opt
|
|
53
56
|
|
|
54
57
|
V_input_max_mV: Annotated[float, Field(ge=0, le=10_000)] = 10_000
|
|
55
58
|
I_input_max_mA: Annotated[float, Field(ge=0, le=4.29e3)] = 4_200
|
|
56
59
|
V_input_drop_mV: Annotated[float, Field(ge=0, le=4.29e6)] = 0
|
|
57
|
-
|
|
60
|
+
""" ⤷ simulate input-diode"""
|
|
58
61
|
R_input_mOhm: Annotated[float, Field(ge=0, le=4.29e6)] = 0
|
|
59
|
-
|
|
62
|
+
""" ⤷ resistance only active with disabled boost, range [1 mOhm; 1MOhm]"""
|
|
60
63
|
|
|
61
64
|
# primary storage-Cap
|
|
62
65
|
C_intermediate_uF: Annotated[float, Field(ge=0, le=100_000)] = 0
|
|
63
66
|
V_intermediate_init_mV: Annotated[float, Field(ge=0, le=10_000)] = 3_000
|
|
64
|
-
|
|
67
|
+
""" ⤷ allow a proper / fast startup"""
|
|
65
68
|
I_intermediate_leak_nA: Annotated[float, Field(ge=0, le=4.29e9)] = 0
|
|
66
69
|
|
|
67
70
|
V_intermediate_enable_threshold_mV: Annotated[float, Field(ge=0, le=10_000)] = 1
|
|
68
|
-
|
|
71
|
+
""" ⤷ target gets connected (hysteresis-combo with next value)"""
|
|
69
72
|
V_intermediate_disable_threshold_mV: Annotated[float, Field(ge=0, le=10_000)] = 0
|
|
70
|
-
|
|
73
|
+
""" ⤷ target gets disconnected"""
|
|
71
74
|
interval_check_thresholds_ms: Annotated[float, Field(ge=0, le=4.29e3)] = 0
|
|
72
|
-
|
|
75
|
+
""" ⤷ some ICs (BQ) check every 64 ms if output should be disconnected"""
|
|
73
76
|
# TODO: add intervals for input-disable, output-disable & power-good-signal
|
|
74
77
|
|
|
75
78
|
# pwr-good: target is informed on output-pin (hysteresis) -> for intermediate voltage
|
|
76
79
|
V_pwr_good_enable_threshold_mV: Annotated[float, Field(ge=0, le=10_000)] = 2_800
|
|
77
80
|
V_pwr_good_disable_threshold_mV: Annotated[float, Field(ge=0, le=10_000)] = 2200
|
|
78
81
|
immediate_pwr_good_signal: bool = True
|
|
79
|
-
|
|
82
|
+
""" ⤷ 1: activate instant schmitt-trigger, 0: stay in interval for checking thresholds"""
|
|
80
83
|
|
|
81
|
-
# final (always last) stage to compensate undetectable current spikes
|
|
82
|
-
# when enabling power for target
|
|
83
84
|
C_output_uF: Annotated[float, Field(ge=0, le=4.29e6)] = 1.0
|
|
85
|
+
"""
|
|
86
|
+
final (always last) stage to compensate undetectable current spikes when
|
|
87
|
+
enabling power for target
|
|
88
|
+
"""
|
|
84
89
|
# TODO: C_output is handled internally as delta-V, but should be a I_transient
|
|
85
90
|
# that makes it visible in simulation as additional i_out_drain
|
|
86
91
|
# TODO: potential weakness, ACD lowpass is capturing transient,
|
|
@@ -88,32 +93,35 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
88
93
|
|
|
89
94
|
# Extra
|
|
90
95
|
V_output_log_gpio_threshold_mV: Annotated[float, Field(ge=0, le=4.29e6)] = 1_400
|
|
91
|
-
|
|
96
|
+
""" ⤷ min voltage needed to enable recording changes in gpio-bank"""
|
|
92
97
|
|
|
93
98
|
# Boost Converter
|
|
94
99
|
V_input_boost_threshold_mV: Annotated[float, Field(ge=0, le=10_000)] = 0
|
|
95
|
-
|
|
100
|
+
""" ⤷ min input-voltage for the boost converter to work"""
|
|
96
101
|
V_intermediate_max_mV: Annotated[float, Field(ge=0, le=10_000)] = 10_000
|
|
97
|
-
|
|
102
|
+
""" ⤷ boost converter shuts off"""
|
|
98
103
|
|
|
99
104
|
LUT_input_efficiency: LUT2D = 12 * [12 * [1.00]]
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
""" ⤷ rows are current -> first row a[V=0][:]
|
|
106
|
+
|
|
107
|
+
input-LUT[12][12] depending on array[inp_voltage][log(inp_current)],
|
|
108
|
+
influence of cap-voltage is not implemented
|
|
109
|
+
"""
|
|
110
|
+
|
|
103
111
|
LUT_input_V_min_log2_uV: Annotated[int, Field(ge=0, le=20)] = 0
|
|
104
|
-
|
|
112
|
+
""" ⤷ i.e. 2^7 = 128 uV -> LUT[0][:] is for inputs < 128 uV"""
|
|
105
113
|
LUT_input_I_min_log2_nA: Annotated[int, Field(ge=1, le=20)] = 1
|
|
106
|
-
|
|
114
|
+
""" ⤷ i.e. 2^8 = 256 nA -> LUT[:][0] is for inputs < 256 nA"""
|
|
107
115
|
|
|
108
116
|
# Buck Converter
|
|
109
117
|
V_output_mV: Annotated[float, Field(ge=0, le=5_000)] = 2_400
|
|
110
118
|
V_buck_drop_mV: Annotated[float, Field(ge=0, le=5_000)] = 0
|
|
111
|
-
|
|
119
|
+
""" ⤷ simulate LDO / diode min voltage differential or output-diode"""
|
|
112
120
|
|
|
113
121
|
LUT_output_efficiency: LUT1D = 12 * [1.00]
|
|
114
|
-
|
|
122
|
+
""" ⤷ array[12] depending on output_current"""
|
|
115
123
|
LUT_output_I_min_log2_nA: Annotated[int, Field(ge=1, le=20)] = 1
|
|
116
|
-
|
|
124
|
+
""" ⤷ 2^8 = 256 nA -> LUT[0] is for inputs < 256 nA, see notes on LUT_input for explanation"""
|
|
117
125
|
|
|
118
126
|
@model_validator(mode="before")
|
|
119
127
|
@classmethod
|
|
@@ -242,7 +250,7 @@ class VirtualSourceConfig(ContentModel, title="Config for the virtual Source"):
|
|
|
242
250
|
dV[uV] = constant[us/nF] * current[nA] = constant[us*V/nAs] * current[nA]
|
|
243
251
|
"""
|
|
244
252
|
C_cap_uF = max(self.C_intermediate_uF, 0.001)
|
|
245
|
-
return int((10**3 * (2**28)) // (C_cap_uF *
|
|
253
|
+
return int((10**3 * (2**28)) // (C_cap_uF * config.SAMPLERATE_SPS))
|
|
246
254
|
|
|
247
255
|
|
|
248
256
|
u32 = Annotated[int, Field(ge=0, lt=2**32)]
|
|
@@ -317,7 +325,7 @@ class ConverterPRUConfig(ShpModel):
|
|
|
317
325
|
dtype_in, log_intermediate_node=log_intermediate_node
|
|
318
326
|
),
|
|
319
327
|
interval_startup_delay_drain_n=round(
|
|
320
|
-
data.interval_startup_delay_drain_ms *
|
|
328
|
+
data.interval_startup_delay_drain_ms * config.SAMPLERATE_SPS * 1e-3
|
|
321
329
|
),
|
|
322
330
|
V_input_max_uV=round(data.V_input_max_mV * 1e3),
|
|
323
331
|
I_input_max_nA=round(data.I_input_max_mA * 1e6),
|
|
@@ -330,7 +338,7 @@ class ConverterPRUConfig(ShpModel):
|
|
|
330
338
|
V_disable_output_threshold_uV=round(states["V_disable_output_threshold_mV"] * 1e3),
|
|
331
339
|
dV_enable_output_uV=round(states["dV_enable_output_mV"] * 1e3),
|
|
332
340
|
interval_check_thresholds_n=round(
|
|
333
|
-
data.interval_check_thresholds_ms *
|
|
341
|
+
data.interval_check_thresholds_ms * config.SAMPLERATE_SPS * 1e-3
|
|
334
342
|
),
|
|
335
343
|
V_pwr_good_enable_threshold_uV=round(data.V_pwr_good_enable_threshold_mV * 1e3),
|
|
336
344
|
V_pwr_good_disable_threshold_uV=round(data.V_pwr_good_disable_threshold_mV * 1e3),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# info:
|
|
2
2
|
# - compendium of all parameters & description
|
|
3
|
-
# - base for neutral fallback values if provided
|
|
3
|
+
# - base for neutral fallback values if provided yaml is sparse
|
|
4
4
|
# - -> it is encouraged to omit redundant parameters
|
|
5
5
|
---
|
|
6
6
|
- datatype: VirtualSourceConfig
|
{shepherd_core-2025.5.3 → shepherd_core-2025.6.1}/shepherd_core/data_models/experiment/experiment.py
RENAMED
|
@@ -11,11 +11,12 @@ from pydantic import model_validator
|
|
|
11
11
|
from typing_extensions import Self
|
|
12
12
|
from typing_extensions import deprecated
|
|
13
13
|
|
|
14
|
+
from shepherd_core.config import config
|
|
14
15
|
from shepherd_core.data_models.base.content import IdInt
|
|
15
16
|
from shepherd_core.data_models.base.content import NameStr
|
|
16
17
|
from shepherd_core.data_models.base.content import SafeStr
|
|
17
|
-
from shepherd_core.data_models.base.content import id_default
|
|
18
18
|
from shepherd_core.data_models.base.shepherd import ShpModel
|
|
19
|
+
from shepherd_core.data_models.base.timezone import local_now
|
|
19
20
|
from shepherd_core.data_models.testbed.target import Target
|
|
20
21
|
from shepherd_core.data_models.testbed.testbed import Testbed
|
|
21
22
|
from shepherd_core.version import version
|
|
@@ -23,33 +24,28 @@ from shepherd_core.version import version
|
|
|
23
24
|
from .observer_features import SystemLogging
|
|
24
25
|
from .target_config import TargetConfig
|
|
25
26
|
|
|
27
|
+
# defaults (pre-init complex types)
|
|
28
|
+
sys_log_all = SystemLogging() # = all active
|
|
29
|
+
|
|
26
30
|
|
|
27
31
|
class Experiment(ShpModel, title="Config of an Experiment"):
|
|
28
32
|
"""Config for experiments on the testbed emulating energy environments for target nodes."""
|
|
29
33
|
|
|
30
34
|
# General Properties
|
|
31
|
-
id: int = Field(description="Unique ID", default_factory=id_default)
|
|
32
|
-
# ⤷ TODO: automatic ID is problematic for identification by hash
|
|
33
|
-
|
|
34
35
|
name: NameStr
|
|
35
36
|
description: Annotated[
|
|
36
37
|
Optional[SafeStr], Field(description="Required for public instances")
|
|
37
38
|
] = None
|
|
38
39
|
comment: Optional[SafeStr] = None
|
|
39
|
-
created: datetime = Field(default_factory=datetime.now)
|
|
40
|
-
|
|
41
|
-
# Ownership & Access
|
|
42
|
-
owner_id: Optional[IdInt] = None
|
|
43
40
|
|
|
44
41
|
# feedback
|
|
45
|
-
email_results: bool =
|
|
42
|
+
email_results: bool = True
|
|
46
43
|
|
|
47
|
-
sys_logging: SystemLogging =
|
|
44
|
+
sys_logging: SystemLogging = sys_log_all
|
|
48
45
|
|
|
49
46
|
# schedule
|
|
50
47
|
time_start: Optional[datetime] = None # = ASAP
|
|
51
48
|
duration: Optional[timedelta] = None # = till EOF
|
|
52
|
-
abort_on_error: Annotated[bool, deprecated("has no effect")] = False
|
|
53
49
|
|
|
54
50
|
# targets
|
|
55
51
|
target_configs: Annotated[list[TargetConfig], Field(min_length=1, max_length=128)]
|
|
@@ -57,13 +53,16 @@ class Experiment(ShpModel, title="Config of an Experiment"):
|
|
|
57
53
|
# debug
|
|
58
54
|
lib_ver: Optional[str] = version
|
|
59
55
|
|
|
56
|
+
# deprecated fields, TODO: remove before public release
|
|
57
|
+
id: Annotated[Optional[int], deprecated("not needed")] = None
|
|
58
|
+
created: Annotated[Optional[datetime], deprecated("not needed")] = None
|
|
59
|
+
abort_on_error: Annotated[bool, deprecated("has no effect")] = False
|
|
60
|
+
owner_id: Annotated[Optional[IdInt], deprecated("not needed")] = None
|
|
61
|
+
|
|
60
62
|
@model_validator(mode="after")
|
|
61
63
|
def post_validation(self) -> Self:
|
|
62
|
-
|
|
63
|
-
# or with cached fixtures
|
|
64
|
-
testbed = Testbed() # this will query the first (and only) entry of client
|
|
64
|
+
self._validate_observers(self.target_configs)
|
|
65
65
|
self._validate_targets(self.target_configs)
|
|
66
|
-
self._validate_observers(self.target_configs, testbed)
|
|
67
66
|
if self.duration and self.duration.total_seconds() < 0:
|
|
68
67
|
raise ValueError("Duration of experiment can't be negative.")
|
|
69
68
|
return self
|
|
@@ -75,8 +74,9 @@ class Experiment(ShpModel, title="Config of an Experiment"):
|
|
|
75
74
|
for _config in configs:
|
|
76
75
|
for _id in _config.target_IDs:
|
|
77
76
|
target_ids.append(_id)
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
if config.VALIDATE_INFRA:
|
|
78
|
+
Target(id=_id)
|
|
79
|
+
# ⤷ this can raise exception for non-existing targets
|
|
80
80
|
if _config.custom_IDs is not None:
|
|
81
81
|
custom_ids = custom_ids + _config.custom_IDs[: len(_config.target_IDs)]
|
|
82
82
|
else:
|
|
@@ -87,7 +87,10 @@ class Experiment(ShpModel, title="Config of an Experiment"):
|
|
|
87
87
|
raise ValueError("Custom Target-ID are faulty (some form of id-collisions)!")
|
|
88
88
|
|
|
89
89
|
@staticmethod
|
|
90
|
-
def _validate_observers(configs: Iterable[TargetConfig]
|
|
90
|
+
def _validate_observers(configs: Iterable[TargetConfig]) -> None:
|
|
91
|
+
if not config.VALIDATE_INFRA:
|
|
92
|
+
return
|
|
93
|
+
testbed = Testbed()
|
|
91
94
|
target_ids = [_id for _config in configs for _id in _config.target_IDs]
|
|
92
95
|
obs_ids = [testbed.get_observer(_id).id for _id in target_ids]
|
|
93
96
|
if len(target_ids) > len(set(obs_ids)):
|
|
@@ -105,3 +108,10 @@ class Experiment(ShpModel, title="Config of an Experiment"):
|
|
|
105
108
|
# gets already caught in target_config - but keep:
|
|
106
109
|
msg = f"Target-ID {target_id} was not found in Experiment '{self.name}'"
|
|
107
110
|
raise ValueError(msg)
|
|
111
|
+
|
|
112
|
+
def folder_name(self, custom_date: Optional[datetime] = None) -> str:
|
|
113
|
+
date = custom_date if custom_date is not None else self.time_start
|
|
114
|
+
timestamp = local_now() if date is None else date
|
|
115
|
+
timestrng = timestamp.strftime("%Y-%m-%d_%H-%M-%S")
|
|
116
|
+
# ⤷ closest to ISO 8601, avoids ":"
|
|
117
|
+
return f"{timestrng}_{self.name.replace(' ', '_')}"
|