diff --git a/CHANGELOG.md b/CHANGELOG.md index 669ff4bc..9ea33ae3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - faster UI response times when starting jobs. - faster syncing configs. - faster copying files across cluster via `pio cp`. + - faster clean up of jobs using PWMs. - new database table in `/tmp/local_intermittent_pioreactor_metadata.sqlite` called `pio_job_published_settings` that stores the published settings for each job. This powers the next API endpoints: - New API endpoints for getting the current settings of a _running_ job: - Per pioreactor: @@ -36,6 +37,7 @@ - updating the UI software won't prematurely stop any currently running activities - correct ethernet mac address on RPi5s - We weren't passing all the OS environment variables when jobs were started from the UI. This is fixed now. + - Fixed circulate media / alt. media in the UI. ### 24.10.1 diff --git a/pioreactor/actions/pump.py b/pioreactor/actions/pump.py index 5ee438a5..557919c0 100644 --- a/pioreactor/actions/pump.py +++ b/pioreactor/actions/pump.py @@ -496,7 +496,7 @@ def click_add_alt_media( continuously: bool, source_of_event: Optional[str], manually: bool, -) -> float: +) -> pt.mL: """ Remove waste/media from unit """ @@ -531,7 +531,7 @@ def click_remove_waste( continuously: bool, source_of_event: Optional[str], manually: bool, -) -> float: +) -> pt.mL: """ Remove waste/media from unit """ @@ -566,7 +566,7 @@ def click_add_media( continuously: bool, source_of_event: Optional[str], manually: bool, -) -> float: +) -> pt.mL: """ Add media to unit """ @@ -582,3 +582,39 @@ def click_add_media( experiment=experiment, manually=manually, ) + + +@click.command(name="circulate_media") +@click.option("--duration", required=True, type=float) +def click_circulate_media( + duration: Optional[pt.Seconds], +) -> tuple[pt.mL, pt.mL]: + """ + Cycle waste/media from unit + """ + unit = get_unit_name() + experiment = get_assigned_experiment_name(unit) + + return circulate_media( + duration=duration, + unit=unit, + experiment=experiment, + ) + + +@click.command(name="circulate_alt_media") +@click.option("--duration", required=True, type=float) +def click_circulate_alt_media( + duration: Optional[pt.Seconds], +) -> tuple[pt.mL, pt.mL]: + """ + Cycle waste/alt media from unit + """ + unit = get_unit_name() + experiment = get_assigned_experiment_name(unit) + + return circulate_alt_media( + duration=duration, + unit=unit, + experiment=experiment, + ) diff --git a/pioreactor/background_jobs/monitor.py b/pioreactor/background_jobs/monitor.py index 30fbdadb..00460dad 100644 --- a/pioreactor/background_jobs/monitor.py +++ b/pioreactor/background_jobs/monitor.py @@ -211,33 +211,36 @@ def did_find_network() -> bool: utils.boolean_retry(did_find_network, retries=3, sleep_for=2) self.ipv4 = get_ip() - def get_first_mac(interface_type: str) -> Optional[str]: + def get_mac_addresses(interface_type: str) -> str: """ - Finds the first network interface of the given type (wireless or wired) and retrieves its MAC address. + Finds all network interfaces of the given type (wireless or wired) and retrieves their MAC addresses. + Returns a comma-separated string of MAC addresses. """ net_path = Path("/sys/class/net") + mac_addresses = [] + for iface_path in net_path.iterdir(): if iface_path.is_dir(): try: - # Check the type of the interface using 'type' and presence of 'wireless' directory. iface_type_path = iface_path / "type" is_wireless = (iface_path / "wireless").exists() if iface_type_path.exists(): iface_type = iface_type_path.read_text().strip() - # Match the interface type: '1' means Ethernet, and the presence of 'wireless' means Wi-Fi. + # Collect MAC addresses for specified type if interface_type == "wireless" and is_wireless: - return (iface_path / "address").read_text().strip() + mac_addresses.append((iface_path / "address").read_text().strip()) elif interface_type == "wired" and iface_type == "1" and not is_wireless: - return (iface_path / "address").read_text().strip() + mac_addresses.append((iface_path / "address").read_text().strip()) except (FileNotFoundError, ValueError): continue - return None - # Get the MAC addresses for the first wireless and wired interfaces - self.wlan_mac_address = get_first_mac("wireless") or "Not available" - self.eth_mac_address = get_first_mac("wired") or "Not available" + return ", ".join(mac_addresses) if mac_addresses else "Not available" + + # Get MAC addresses for all wireless and wired interfaces + self.wlan_mac_address = get_mac_addresses("wireless") + self.eth_mac_address = get_mac_addresses("wired") self.logger.debug(f"IPv4 address: {self.ipv4}") self.logger.debug(f"WLAN MAC address: {self.wlan_mac_address}") diff --git a/pioreactor/cli/run.py b/pioreactor/cli/run.py index a5d8ce86..9b8ccf04 100644 --- a/pioreactor/cli/run.py +++ b/pioreactor/cli/run.py @@ -42,6 +42,8 @@ def run() -> None: run.add_command(actions.pump.click_add_alt_media) run.add_command(actions.pump.click_add_media) run.add_command(actions.pump.click_remove_waste) +run.add_command(actions.pump.click_circulate_media) +run.add_command(actions.pump.click_circulate_alt_media) run.add_command(actions.od_blank.click_od_blank) run.add_command(actions.self_test.click_self_test) run.add_command(actions.stirring_calibration.click_stirring_calibration)