# Parameter System

The parameter system is the metadata and validation layer used by device classes in PlestyLib.

It defines what can be queried or written, validates user input, stores cached values, and supports typed parsing of device responses.

Core implementation: `ConfigSystem` in `plestylib.device.params`.

## What It Does

`ConfigSystem` provides:

1. Parameter registration through code (`register_config`) or schema (`register_params_from_schema`).
2. Optional grouping of parameters (`register_config_group`).
3. Validation for type, range, and categorical options.
4. Read/write permission flags (`read_only`, `write_only`).
5. Current value cache per parameter (`value`).
6. Automatic response casting through `AutoResponseParser`.
7. Human-readable summaries (`param_summary`).

## Main Data Structures

### ConfigParameter

Represents one parameter, including:

1. `name`
2. `dtype`
3. `default` and current `value`
4. `unit`
5. `read_only`, `write_only`
6. `min_value`, `max_value`
7. `options`
8. `command` (string or `Command` object)
9. `parser` (optional custom response parser)
10. `description`

### ConfigGroup

Represents a parameter group with:

1. Group name
2. Group parameter dictionary
3. Optional command prefix
4. Optional list of group-level allowed commands
5. Group description

### Command

Command metadata object used in grouped schemas:

1. `name`
2. `command` # some devices may provide command to query or set parameters in this group
3. `required_params` # defines required parameters for the group command
4. `optional_params` # defines optional paramters for the group command
5. `mode` (`write` or `query`)
6. `description`

## Register Parameters in Code

```python
from plestylib.device.base_visa_scpi_device import BaseVisaScpiDevice


class PowermeterDevice(BaseVisaScpiDevice):
		def __init__(self, address: str):
				super().__init__(address)

				self.register_config("POWER", dtype=float, unit="watt", read_only=True, command="MEAS:SCAL:POW")
				self.register_config("WAVELENGTH", dtype=int, unit="nm", min_value=400, max_value=1100, command="SENS:CORR:WAV")
				self.register_config("AUTO_RANGE", dtype=bool, default=True, command="SENS:POW:RANG:AUTO")
```

## Register Parameters from Schema

`register_params_from_schema` supports loading from a JSON file in the following shape:


```json
{
	"ROSCillatorFrequency": {
		"type": "float",
		"command": "SOUR:ROSC:FREQ",
		"description": "Set or query the frequency of the internal reference oscillator."
	},
	"SyncClockoutValue": {
		"type": "integer",
		"command": "SYNC:VAL",
		"read_only": true
	}
}
```


Load schema from file path or dictionary:

```python
from plestylib.device.params import ConfigSystem

cfg = ConfigSystem(param_schema="param_schema.json")
# or
# cfg = ConfigSystem(param_schema=schema_dict)
```

Load schema directly in a base-device constructor (`BaseDeviceSyncModel`):

```python
from plestylib.device.base_device_sync import BaseDeviceSyncModel


class MyDevice(BaseDeviceSyncModel):
	def __init__(self, id: str, param_schema):
		super().__init__(id=id, param_schema=param_schema)

	def connect(self):
		...

	def disconnect(self):
		...

	def check_errors(self) -> list[str]:
		return []

	def check_operatability(self) -> bool:
		return True

	def _write_(self, key, value) -> bool:
		return True

	def _query_(self, key) -> str:
		return "0"


dev_a = MyDevice(id="dev-1", param_schema="param_schema.json")
# or
# dev_b = MyDevice(id="dev-2", param_schema=schema_dict)
```

## Validation Rules

Validation happens at registration and at write-time checks.

1. Type checks: values must match `dtype`.
2. Numeric range checks: `min_value <= value <= max_value`.
3. Option checks: categorical values must be in `options`.
4. Permission checks: cannot write `read_only` parameters.

Important behavior:

1. Registration errors raise exceptions.
2. `check_write_config` raises on invalid values.
3. `set_config_value` attempts auto-casting before range/options validation.

## Query/Write Flow Integration

In synchronized devices, high-level methods in `BaseDeviceSyncModel` use `ConfigSystem` as follows:

1. `write(key, value)`
2. `check_write_config(key, value)` validates the request
3. Device-specific `_write_` sends command to hardware
4. On success, `set_config_value` updates cached value

For queries:

1. `query(key)`
2. `check_query_config(key)` validates access
3. Device-specific `_query_` gets raw response
4. `response_to_target_type` parses/casts response
5. `set_config_value` stores parsed value

## Response Parsing

By default, `AutoResponseParser` tries to cast response text to the parameter dtype.

Examples:

1. `"42" -> int`
2. `"3.14" -> float`
3. `"true"/"1" -> bool` (via basic cast helper)
4. Delimited strings for typed list/tuple annotations

If needed, provide a custom parser in parameter metadata via `parser`.

## Useful API Methods

1. `register_config(...)`
2. `register_config_group(...)`
3. `register_params_from_schema(...)`
4. `get_config(key, group="default")`
5. `get_config_list(group="default")`
6. `get_group_list()`
7. `set_config_value(key, value)`
8. `get_config_value(key)`
9. `set_config_min_max(key, min_value, max_value)`
10. `param_summary(constraints=True, description=False)`

## Minimal End-to-End Example

```python
from plestylib.device.params import ConfigSystem

system = ConfigSystem()

system.register_config(
		key="GAIN",
		dtype=int,
		min_value=1,
		max_value=10,
		default=5,
		command="CONF:GAIN",
)

system.check_write_config("GAIN", 7)
system.set_config_value("GAIN", "7")  # auto-cast to int

print(system.get_config_value("GAIN"))
print(system.param_summary())
```

## Best Practices

1. Always set `dtype` for robust validation and auto-casting.
2. Prefer explicit `min_value` and `max_value` for numeric parameters.
3. Use `options` for categorical values.
4. Keep command strings in parameter metadata so solver logic stays generic.
5. Use schema-driven registration for larger devices.
6. Include `description` and `unit` fields to improve generated summaries and docs.