Skip to content

Commit 4190bc4

Browse files
XR in the UI, and hardware check when the model changes
1 parent 2707810 commit 4190bc4

File tree

15 files changed

+239
-26
lines changed

15 files changed

+239
-26
lines changed

core/pioreactor/calibrations/protocols/pump_duration_based.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ def render(self, ctx: SessionContext) -> CalibrationStep:
175175
return steps.info(
176176
"Pump calibration",
177177
(
178-
"This routine calibrates the pump on this Pioreactor. You will need:\n"
179-
"1. This Pioreactor.\n"
178+
f"This routine calibrates the {pump_device} pump. You will need:\n"
179+
"1. Pioreactor hardware.\n"
180180
"2. A vial on a scale (0.1g resolution) or a graduated cylinder.\n"
181181
"3. A larger container filled with water.\n"
182182
f"4. {pump_device} connected to PWM channel {channel}.\n\n"

core/pioreactor/cli/pio.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,15 @@ def update_app(
714714
"""
715715
# initialize logger and build commands based on input parameters
716716
logger = create_logger("update_app", unit=whoami.get_unit_name(), experiment=whoami.UNIVERSAL_EXPERIMENT)
717+
logger.debug(
718+
"Starting app update. branch=%s repo=%s source=%s version=%s no_deps=%s defer_web_restart=%s",
719+
branch,
720+
repo,
721+
source,
722+
version,
723+
no_deps,
724+
defer_web_restart,
725+
)
717726
commands_and_priority, version_installed = get_update_app_commands(
718727
branch,
719728
repo,
@@ -722,13 +731,22 @@ def update_app(
722731
no_deps=no_deps,
723732
defer_web_restart=defer_web_restart,
724733
)
734+
logger.debug(
735+
"Prepared %s update commands. target_version=%s", len(commands_and_priority), version_installed
736+
)
725737

726-
for command, _ in sorted(commands_and_priority, key=lambda t: t[1]):
738+
for index, (command, priority) in enumerate(sorted(commands_and_priority, key=lambda t: t[1]), start=1):
727739
if whoami.is_testing_env():
728-
logger.debug(f"DRY-RUN: {command}")
740+
logger.debug("DRY-RUN (step %s, priority %s): %s", index, priority, command)
729741
continue
730742

731-
logger.debug(command)
743+
logger.debug(
744+
"Running update step %s/%s (priority %s): %s",
745+
index,
746+
len(commands_and_priority),
747+
priority,
748+
command,
749+
)
732750

733751
p = subprocess.run(
734752
command,
@@ -738,12 +756,17 @@ def update_app(
738756
stderr=subprocess.PIPE,
739757
)
740758
if p.returncode != 0:
741-
logger.debug(p.stderr)
742-
logger.error("Update failed. See logs.")
759+
if p.stdout:
760+
logger.debug("Update step %s stdout: %s", index, p.stdout)
761+
if p.stderr:
762+
logger.debug("Update step %s stderr: %s", index, p.stderr)
763+
logger.debug("Update failed at step %s with returncode %s.", index, p.returncode)
743764
# end early
744765
raise click.Abort()
745766
elif p.stdout:
746-
logger.debug(p.stdout)
767+
logger.debug("Update step %s stdout: %s", index, p.stdout)
768+
if p.stderr:
769+
logger.debug("Update step %s stderr: %s", index, p.stderr)
747770

748771
logger.notice(f"Updated Pioreactor app to version {version_installed}.") # type: ignore
749772
# everything work? Let's publish to MQTT. This is a terrible hack, as monitor should do this.

core/pioreactor/hardware.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ def get_layered_mod_config(mod: str) -> dict[str, Any]:
111111
return data
112112

113113

114+
def get_layered_mod_config_for_model(mod: str, model_name: str, model_version: str) -> dict[str, Any]:
115+
"""Load one mod's YAML by layering hats -> provided model."""
116+
base = Path(environ["DOT_PIOREACTOR"]) / "hardware"
117+
118+
if hardware_version_info is None:
119+
raise exc.HardwareNotFoundError("HAT not found")
120+
assert hardware_version_info is not None
121+
122+
model_dir = base / "models" / model_name / model_version
123+
hat_dir = base / "hats" / tuple_to_text(hardware_version_info)
124+
125+
data: dict[str, Any] = {}
126+
data = _deep_merge(data, _load_yaml_if_exists(hat_dir / f"{mod}.yaml"))
127+
data = _deep_merge(data, _load_yaml_if_exists(model_dir / f"{mod}.yaml"))
128+
return data
129+
130+
114131
@cache
115132
def determine_gpiochip() -> pt.GpioChip:
116133
"""Return the GPIO chip index for the current Raspberry Pi."""

core/pioreactor/web/api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,6 +2798,14 @@ def change_worker_model(pioreactor_unit: str) -> ResponseReturnValue:
27982798
task="worker_model",
27992799
level="INFO",
28002800
)
2801+
# When new model versions are added, consider extending hardware checks here
2802+
# (see /unit_api/hardware/check and tasks.check_model_hardware).
2803+
if model_version == "1.5":
2804+
tasks.post_into_unit(
2805+
pioreactor_unit,
2806+
"/unit_api/hardware/check",
2807+
json={"model_name": model_name, "model_version": model_version},
2808+
)
28012809
return {"status": "success"}, 200
28022810
else:
28032811
abort_with(404, f"Worker {pioreactor_unit} not found")

core/pioreactor/web/static/asset-manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"files": {
33
"main.css": "/static/static/css/main.9c7a48b7.css",
4-
"main.js": "/static/static/js/main.13eb0766.js",
4+
"main.js": "/static/static/js/main.40638d9a.js",
55
"static/media/pioreactor_cloud.webp": "/static/static/media/pioreactor_cloud.b15b29e435797dc69d76.webp",
66
"static/media/roboto-all-500-normal.woff": "/static/static/media/roboto-all-500-normal.0ab669b7a0d19b178f57.woff",
77
"static/media/roboto-all-700-normal.woff": "/static/static/media/roboto-all-700-normal.a457fde362a540fcadff.woff",
@@ -30,10 +30,10 @@
3030
"static/media/roboto-greek-ext-700-normal.woff2": "/static/static/media/roboto-greek-ext-700-normal.bd9854c751441ccc1a70.woff2",
3131
"index.html": "/static/index.html",
3232
"main.9c7a48b7.css.map": "/static/static/css/main.9c7a48b7.css.map",
33-
"main.13eb0766.js.map": "/static/static/js/main.13eb0766.js.map"
33+
"main.40638d9a.js.map": "/static/static/js/main.40638d9a.js.map"
3434
},
3535
"entrypoints": [
3636
"static/css/main.9c7a48b7.css",
37-
"static/js/main.13eb0766.js"
37+
"static/js/main.40638d9a.js"
3838
]
3939
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/static/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Pioreactor"/><link rel="apple-touch-icon" href="/static/logo192.png"/><link rel="manifest" href="/static/manifest.json"/><script defer="defer" src="/static/static/js/main.13eb0766.js"></script><link href="/static/static/css/main.9c7a48b7.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
1+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/static/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Pioreactor"/><link rel="apple-touch-icon" href="/static/logo192.png"/><link rel="manifest" href="/static/manifest.json"/><script defer="defer" src="/static/static/js/main.40638d9a.js"></script><link href="/static/static/css/main.9c7a48b7.css" rel="stylesheet"></head><body><div id="root"></div></body></html>

core/pioreactor/web/static/static/js/main.13eb0766.js renamed to core/pioreactor/web/static/static/js/main.40638d9a.js

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/pioreactor/web/static/static/js/main.13eb0766.js.LICENSE.txt renamed to core/pioreactor/web/static/static/js/main.40638d9a.js.LICENSE.txt

File renamed without changes.

core/pioreactor/web/static/static/js/main.13eb0766.js.map renamed to core/pioreactor/web/static/static/js/main.40638d9a.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/pioreactor/web/tasks.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
from huey.exceptions import ResultTimeout
3232
from huey.exceptions import TaskException
3333
from msgspec import DecodeError
34+
from pioreactor import exc
35+
from pioreactor import hardware
3436
from pioreactor import types as pt
3537
from pioreactor import whoami
3638
from pioreactor.config import config as pioreactor_config
@@ -268,6 +270,45 @@ def add_new_pioreactor(new_pioreactor_name: str, version: str, model: str) -> bo
268270
return True
269271

270272

273+
def _get_adc_addresses_for_model(model_name: str, model_version: str) -> set[int]:
274+
adc_cfg = hardware.get_layered_mod_config_for_model("adc", model_name, model_version)
275+
addresses: set[int] = set()
276+
for adc_data in adc_cfg.values():
277+
address = adc_data.get("address")
278+
addresses.add(int(address))
279+
return addresses
280+
281+
282+
@huey.task(priority=10)
283+
def check_model_hardware(model_name: str, model_version: str) -> None:
284+
if model_version != "1.5":
285+
return None
286+
287+
try:
288+
addresses = _get_adc_addresses_for_model(model_name, model_version)
289+
except exc.HardwareNotFoundError as err:
290+
logger.warning(
291+
f"Hardware check skipped on {get_unit_name()}: {err}",
292+
)
293+
return None
294+
295+
if not addresses:
296+
logger.debug(
297+
f"Hardware check found no ADC addresses for {model_name} {model_version} on {get_unit_name()}."
298+
)
299+
return None
300+
301+
missing = sorted(addr for addr in addresses if not hardware.is_i2c_device_present(addr))
302+
if missing:
303+
missing_hex = ", ".join(hex(addr) for addr in missing)
304+
logger.warning(
305+
f"Hardware check failed for {model_name} {model_version} on {get_unit_name()}: "
306+
f"missing I2C devices at {missing_hex}."
307+
)
308+
309+
return None
310+
311+
271312
@huey.task()
272313
def update_app_across_cluster() -> bool:
273314
# CPU heavy / IO heavy

0 commit comments

Comments
 (0)