A MADSci node module for the Eurotherm nanodac temperature/process controller, communicating over Modbus/TCP. Deployed at APS beamline 9-BM.
src/nanodac_interface.py—Nanodacdriver class:connect/disconnect,get_status, andget_temperature/set_temperature(plus setpoint, working setpoint, output, mode). Pure Modbus/TCP viapymodbus, no MADSci dependency.src/nanodac_rest_node.py—NanodacNode(RestNode): wraps the driver as a MADSci REST node with actionsget_temperature,get_setpoint,set_temperature,get_output.
This is a simple device — no MADSci resource tracking is used.
Confirmed on nanodac v5.50 (slave id 1):
- Loop.1.Main parameters start at base address 512 (Loop.2 at 640, +128 apart) — not the canonical register 1.
- REAL (float) parameters are read/written through the IEEE-float mirror:
int_address + 0x8000, two 16-bit registers, big-endian high-word-first. - Unwritten floats read back as the sentinel
(0x0000, 0x8000)(~4.59e-41), mapped toNone. - Bool/enum params (AutoMan, etc.) are plain 1-register int reads.
git clone https://github.com/AD-SDL/nanodac_module.git
cd nanodac_module
pdm install # dev on the private subnet: prefix with the SOCKS proxy env (see below)Or, using released packages directly:
pip install -e .Edit node.settings.yaml (discovered via MADSci walk-up), or override via env vars / CLI:
| Setting | Default | Description |
|---|---|---|
nanodac_ip |
(required) | Controller IP (Modbus/TCP) |
nanodac_port |
502 | Modbus/TCP port |
unit_id |
1 | Modbus slave/unit id |
loop |
1 | Default control loop |
node_url |
— | REST API base URL (e.g. http://0.0.0.0:2010) |
# quick driver smoke test (no MADSci needed)
python src/nanodac_interface.py
# run the REST node
python -m nanodac_rest_node # or: pdm run python -m nanodac_rest_nodeOr via Docker (base image ghcr.io/ad-sdl/madsci:latest):
docker compose upcompose.yaml mounts node.settings.yaml and .madsci/ into the container and runs python -m nanodac_rest_node.
ruff check src/ # lint
ruff format src/ # format
pre-commit install # enable the pre-commit hooksdocs/Configuration.md and .env.example are auto-generated by pydantic-settings-export
(wired into pyproject.toml and the pre-commit config) from NanodacNodeConfig; do not edit them by hand.
If the controller host has no direct internet (private subnet), install packages through your lab's SOCKS proxy:
export ALL_PROXY=socks5h://<proxy-host>:<port>
export HTTPS_PROXY=$ALL_PROXY HTTP_PROXY=$ALL_PROXY https_proxy=$ALL_PROXY http_proxy=$ALL_PROXYRead actions (get_temperature, get_setpoint, get_output, state polling) are validated against nanodac v5.50. set_temperature is experimental/unverified — the setpoint-write path on this firmware still needs confirmation via the Eurotherm comms manual (HA030554) / iTools; see the note in set_temperature.