Interfaces used internally
config.json
The config file under config/config.json
contains all parameters to tweak Pyra's operation. Schema: /docs/api-reference/core/types/config#class-configdict.
In addition to this schema, there are value rules that are validated when parsing the config object:
assertions: list[Callable[[], None]] = [
lambda: assert_min_max("general.seconds_per_core_interval", 5, 600),
lambda: assert_min_max("general.min_sun_elevation", 0, 90),
lambda: assert_ip_address("opus.em27_ip"),
lambda: assert_file_path("opus.executable_path"),
lambda: assert_file_path("opus.experiment_path"),
lambda: assert_file_path("opus.macro_path"),
lambda: assert_file_path("camtracker.config_path"),
lambda: assert_file_path("camtracker.executable_path"),
lambda: assert_file_path("camtracker.learn_az_elev_path"),
lambda: assert_file_path("camtracker.sun_intensity_path"),
lambda: assert_min_max("camtracker.motor_offset_threshold", -360, 360),
lambda: assert_min_max("measurement_triggers.min_sun_elevation", 0, 90),
lambda: assert_min_max("measurement_triggers.start_time.hour", 0, 23),
lambda: assert_min_max("measurement_triggers.stop_time.hour", 0, 23),
lambda: assert_min_max("measurement_triggers.start_time.minute", 0, 59),
lambda: assert_min_max("measurement_triggers.stop_time.minute", 0, 59),
lambda: assert_min_max("measurement_triggers.start_time.second", 0, 59),
lambda: assert_min_max("measurement_triggers.stop_time.second", 0, 59),
lambda: assert_ip_address("tum_plc.ip"),
lambda: assert_min_max("helios.camera_id", 0, 999999),
lambda: assert_min_max("helios.evaluation_size", 1, 100),
lambda: assert_min_max("helios.seconds_per_interval", 5, 600),
lambda: assert_min_max("helios.edge_detection_threshold", 0, 1),
lambda: assert_ip_address("upload.host"),
]
state.json
and persistent-state.json
The state file is generated under runtime-data/state.json
. Pyra Core writes its internal values to this file. The state file is used to communicate between modules as well as with the "outside" world (UI, CLI). Schema: /docs/api-reference/core/types/state#class-statedict.
The persistent-state file is generated under logs/persistent-state.json
. It is currently only used by the Core and will not be reset with a restart of the Core. Schema: /docs/api-reference/core/types/persistent_state#class-persistentstatedict.
Validation strategy
MyPy will make full use of the schemas included above (see testing). Whenever loading the config- or state files, the respective schema validation will run. Hence, Pyra will detect when a JSON file does not have the expected schema and raise a precise Exception. All internal code interfaces (function calls, etc.) are covered by the strict MyPy validation.
With pyra-cli config get
, only the schema will be validated, not the value rules. This command is necessary because the UI can deal with invalid values, but not with an invalid schema.
How the UI reads logs and state
The UI reads the log files and the state file periodically using Tauri's file system API. We tested using sockets or file watchers, but both did not work well on Windows, and reading it periodically is the most basic implementation.
Logging
All scripts that output messages at runtime should use the Logger
class:
from packages.core import utils
logger = utils.Logger()
logger.debug("...")
logger.info("...")
logger.warning("...")
logger.critical("...")
logger.error("...")
# By default, it will log from a "pyra.core" origin
logger = utils.Logger()
# Here, it will log from a "camtracker" origin
logger = utils.Logger(origin="camtracker")
Messages from all log levels can be found in logs/debug.log
, and messages from levels INFO/WARNING/CRITICAL/ERROR can be found in logs/info.log
.
Activity Log
Pyra Core will write important events to "activity logs" stored in logs/activity/activity-YYYY-MM-DD.json
. This is the same information as in the regular log files but significantly easier to parse.
export type activityHistory = {
localTime: string;
event:
| 'start-core'
| 'stop-core'
| 'start-measurements'
| 'stop-measurements'
| 'error-occured'
| 'errors-resolved';
}[];
Pyra CLI commands from UI
All write operations from the UI (update config, etc.) are done by running Pyra CLI commands. This is why we have to use the global Python interpreter instead of a virtual environment: We did not make it work that the shell interface from Tauri can make use of a virtual environment.