diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a26f197..50b5137e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ - more resilience to "UI state" diverging from "bioreactor state". Often, this occurred when two jobs stared almost immediately (often a networking issue), and the last job would halt since it couldn't get the required resources, however MQTT any data would be overwritten by the last job. Now, multiple places in the request pipeline will reduce duplication. - Improved stirring clean up when stopped in quick succession after starting. +#### Breaking changes + + - in config.ini, the section `od_config` is now `od_reading.config`, and `stirring` is `stirring.config`. When you update, a script will run to automatically update these names in your config.inis. + ### 24.7.18 #### Enhancements diff --git a/pioreactor/actions/od_calibration.py b/pioreactor/actions/od_calibration.py index 4d37d1e8..9f56ffc2 100644 --- a/pioreactor/actions/od_calibration.py +++ b/pioreactor/actions/od_calibration.py @@ -90,7 +90,7 @@ def get_name_from_user() -> str: def get_metadata_from_user() -> tuple[pt.OD600, pt.OD600, pt.mL, pt.PdAngle, pt.PdChannel]: - if config["od_config"]["ir_led_intensity"] == "auto": + if config["od_reading.config"]["ir_led_intensity"] == "auto": raise ValueError( "Can't use auto with OD calibrations. Change ir_led_intensity in your config.ini to a numeric value (70 is good default)." ) @@ -166,7 +166,7 @@ def start_stirring(): echo("Starting stirring and blocking until near target RPM.") st = stirring( - target_rpm=config.getfloat("stirring", "target_rpm"), + target_rpm=config.getfloat("stirring.config", "target_rpm"), unit=get_unit_name(), experiment=get_testing_experiment_name(), ) @@ -476,7 +476,7 @@ def save_results( curve_type=curve_type, voltages=voltages, od600s=od600s, - ir_led_intensity=float(config["od_config"]["ir_led_intensity"]), + ir_led_intensity=float(config["od_reading.config"]["ir_led_intensity"]), pd_channel=pd_channel, ) @@ -565,11 +565,11 @@ def od_calibration(data_file: str | None) -> None: echo() echo(f"Finished calibration of `{name}` ✅") - if not config.getboolean("od_config", "use_calibration", fallback=False): + if not config.getboolean("od_reading.config", "use_calibration", fallback=False): echo() echo( bold( - "Currently [od_config][use_calibration] is set to 0 in your config.ini. This should be set to 1 to use calibrations.", + "Currently [od_reading.config][use_calibration] is set to 0 in your config.ini. This should be set to 1 to use calibrations.", ) ) return diff --git a/pioreactor/actions/self_test.py b/pioreactor/actions/self_test.py index 66423026..73b526d3 100644 --- a/pioreactor/actions/self_test.py +++ b/pioreactor/actions/self_test.py @@ -271,7 +271,7 @@ def test_REF_is_lower_than_0_dot_256_volts( ) -> None: reference_channel = cast(PdChannel, config.get("od_config.photodiode_channel_reverse", REF_keyword)) ir_channel = cast(LedChannel, config["leds_reverse"][IR_keyword]) - config_ir_intensity = config.get("od_config", "ir_led_intensity") + config_ir_intensity = config.get("od_reading.config", "ir_led_intensity") if config_ir_intensity == "auto": ir_intensity = 50.0 # this has been our historical default, and should generally work. Default now is "auto", which targets 0.225 V into REF else: @@ -400,7 +400,7 @@ def test_positive_correlation_between_rpm_and_stirring( initial_dc = rpm_coef * 700 + intercept else: - initial_dc = config.getfloat("stirring", "initial_duty_cycle") + initial_dc = config.getfloat("stirring.config", "initial_duty_cycle") dcs = [] measured_rpms = [] diff --git a/pioreactor/actions/stirring_calibration.py b/pioreactor/actions/stirring_calibration.py index b7f0e2ef..1782d7e9 100644 --- a/pioreactor/actions/stirring_calibration.py +++ b/pioreactor/actions/stirring_calibration.py @@ -139,7 +139,7 @@ def click_stirring_calibration(min_dc: int, max_dc: int) -> None: if max_dc is None and min_dc is None: # seed with initial_duty_cycle - config_initial_duty_cycle = config.getfloat("stirring", "initial_duty_cycle") + config_initial_duty_cycle = config.getfloat("stirring.config", "initial_duty_cycle") min_dc, max_dc = round(config_initial_duty_cycle * 0.75), round(config_initial_duty_cycle * 1.33) elif (max_dc is not None) and (min_dc is not None): assert min_dc < max_dc, "min_dc >= max_dc" diff --git a/pioreactor/automations/temperature/thermostat.py b/pioreactor/automations/temperature/thermostat.py index 4b8ac1bf..86fb9862 100644 --- a/pioreactor/automations/temperature/thermostat.py +++ b/pioreactor/automations/temperature/thermostat.py @@ -77,15 +77,11 @@ def execute(self) -> UpdatedHeaterDC: def set_target_temperature(self, target_temperature: float | str) -> None: """ - Parameters ------------ target_temperature: float the new target temperature - update_dc_now: bool - if possible, update the DC% to approach the new target temperature - """ target_temperature = float(target_temperature) self.target_temperature = self._clamp_target_temperature(target_temperature) diff --git a/pioreactor/background_jobs/base.py b/pioreactor/background_jobs/base.py index a8d87caf..04a74794 100644 --- a/pioreactor/background_jobs/base.py +++ b/pioreactor/background_jobs/base.py @@ -973,11 +973,6 @@ def _check_for_duplicate_activity(self) -> None: if is_pio_job_running(self.job_name) and not is_testing_env(): self.logger.warning(f"{self.job_name} is already running. Skipping") raise RuntimeError(f"{self.job_name} is already running. Skipping") - # elif is_pio_job_running("self_test"): - # # don't ever run anything while self_test runs. - # self.logger.error("self_test is running.") - # raise RuntimeError("self_test is running.") - ### this doesn't work because self_test invokes jobs, and we hit this line. def __setattr__(self, name: str, value: t.Any) -> None: super(_BackgroundJob, self).__setattr__(name, value) @@ -1149,6 +1144,7 @@ def sneak_in(ads_interval, post_delay, pre_delay) -> None: if self.state != self.READY: return + self.is_after_period = True self.action_to_do_after_od_reading() sleep(ads_interval - self.OD_READING_DURATION - (post_delay + pre_delay)) self.is_after_period = False @@ -1160,13 +1156,13 @@ def sneak_in(ads_interval, post_delay, pre_delay) -> None: ads_start_time_msg = subscribe( f"pioreactor/{self.unit}/{self.experiment}/od_reading/first_od_obs_time" ) - if ads_start_time_msg: + if ads_start_time_msg and ads_start_time_msg.payload: ads_start_time = float(ads_start_time_msg.payload) else: return ads_interval_msg = subscribe(f"pioreactor/{self.unit}/{self.experiment}/od_reading/interval") - if ads_interval_msg: + if ads_interval_msg and ads_interval_msg.payload: ads_interval = float(ads_interval_msg.payload) else: return diff --git a/pioreactor/background_jobs/dosing_automation.py b/pioreactor/background_jobs/dosing_automation.py index f03fdc14..bb9c727e 100644 --- a/pioreactor/background_jobs/dosing_automation.py +++ b/pioreactor/background_jobs/dosing_automation.py @@ -263,7 +263,7 @@ def set_duration(self, duration: Optional[float]) -> None: # there is a race condition here: self.run() will run immediately (see run_immediately), but the state of the job is not READY, since # set_duration is run in the __init__ (hence the job is INIT). So we wait 2 seconds for the __init__ to finish, and then run. # Later: in fact, we actually want this to run after an OD reading cycle so we have internal data, so it should wait a cycle of that. - run_after = 1.0 / config.getfloat("od_config", "samples_per_second") + run_after = 1.0 / config.getfloat("od_reading.config", "samples_per_second") self.run_thread = RepeatedTimer( self.duration * 60, diff --git a/pioreactor/background_jobs/growth_rate_calculating.py b/pioreactor/background_jobs/growth_rate_calculating.py index 822f91a8..1878d07b 100644 --- a/pioreactor/background_jobs/growth_rate_calculating.py +++ b/pioreactor/background_jobs/growth_rate_calculating.py @@ -98,7 +98,7 @@ def __init__( self.source_obs_from_mqtt = source_obs_from_mqtt self.ignore_cache = ignore_cache self.time_of_previous_observation: datetime | None = None - self.expected_dt = 1 / (60 * 60 * config.getfloat("od_config", "samples_per_second")) + self.expected_dt = 1 / (60 * 60 * config.getfloat("od_reading.config", "samples_per_second")) def on_ready(self) -> None: # this is here since the below is long running, and if kept in the init(), there is a large window where diff --git a/pioreactor/background_jobs/led_automation.py b/pioreactor/background_jobs/led_automation.py index 6bbc758c..551018d7 100644 --- a/pioreactor/background_jobs/led_automation.py +++ b/pioreactor/background_jobs/led_automation.py @@ -98,7 +98,7 @@ def set_duration(self, duration: float) -> None: # set_duration is run in the __init__ (hence the job is INIT). So we wait 2 seconds for the __init__ to finish, and then run. # Later: in fact, we actually want this to run after an OD reading cycle so we have internal data, so it should wait a cycle of that. run_after = min( - 1.0 / config.getfloat("od_config", "samples_per_second"), 10 + 1.0 / config.getfloat("od_reading.config", "samples_per_second"), 10 ) # max so users aren't waiting forever to see lights come on... self.run_thread = RepeatedTimer( diff --git a/pioreactor/background_jobs/od_reading.py b/pioreactor/background_jobs/od_reading.py index 8d353f57..4248e9ba 100644 --- a/pioreactor/background_jobs/od_reading.py +++ b/pioreactor/background_jobs/od_reading.py @@ -173,8 +173,8 @@ def __init__( self.penalizer = penalizer self.oversampling_count = oversampling_count - if "local_ac_hz" in config["od_config"]: - self.most_appropriate_AC_hz: Optional[float] = config.getfloat("od_config", "local_ac_hz") + if "local_ac_hz" in config["od_reading.config"]: + self.most_appropriate_AC_hz: Optional[float] = config.getfloat("od_reading.config", "local_ac_hz") else: self.most_appropriate_AC_hz = None @@ -604,7 +604,9 @@ class PhotodiodeIrLedReferenceTrackerStaticInit(IrLedReferenceTracker): def __init__(self, channel: pt.PdChannel) -> None: super().__init__() - self.led_output_ema = ExponentialMovingAverage(config.getfloat("od_config", "pd_reference_ema")) + self.led_output_ema = ExponentialMovingAverage( + config.getfloat("od_reading.config", "pd_reference_ema") + ) self.led_output_emstd = ExponentialMovingStd(alpha=0.95, ema_alpha=0.8) self.channel = channel # self.logger.debug(f"Using PD channel {channel} as IR LED reference.") @@ -684,10 +686,11 @@ def hydate_models_from_disk(self, channel_angle_map: dict[pt.PdChannel, pt.PdAng calibration_data = decode(c[angle], type=structs.AnyODCalibration) # type: ignore name = calibration_data.name - if config.get("od_config", "ir_led_intensity") != "auto" and ( - calibration_data.ir_led_intensity != config.getfloat("od_config", "ir_led_intensity") + if config.get("od_reading.config", "ir_led_intensity") != "auto" and ( + calibration_data.ir_led_intensity + != config.getfloat("od_reading.config", "ir_led_intensity") ): - msg = f"The calibration `{name}` was calibrated with a different IR LED intensity ({calibration_data.ir_led_intensity} vs current: {config.getfloat('od_config', 'ir_led_intensity')}). Either re-calibrate, turn off calibration, or change the ir_led_intensity in the config.ini." + msg = f"The calibration `{name}` was calibrated with a different IR LED intensity ({calibration_data.ir_led_intensity} vs current: {config.getfloat('od_reading.config', 'ir_led_intensity')}). Either re-calibrate, turn off calibration, or change the ir_led_intensity in the config.ini." self.logger.error(msg) raise exc.CalibrationError(msg) # confirm that PD channel is the same as when calibration was performed @@ -870,7 +873,7 @@ def __init__( self._set_for_iterating = threading.Event() self.ir_channel: pt.LedChannel = self._get_ir_led_channel_from_configuration() - config_ir_led_intensity = config.get("od_config", "ir_led_intensity") + config_ir_led_intensity = config.get("od_reading.config", "ir_led_intensity") self.ir_led_intensity: pt.LedIntensityValue if config_ir_led_intensity == "auto": @@ -1212,11 +1215,11 @@ def create_channel_angle_map( def start_od_reading( od_angle_channel1: Optional[pt.PdAngleOrREF] = None, od_angle_channel2: Optional[pt.PdAngleOrREF] = None, - interval: Optional[float] = 1 / config.getfloat("od_config", "samples_per_second"), + interval: Optional[float] = 1 / config.getfloat("od_reading.config", "samples_per_second"), fake_data: bool = False, unit: Optional[str] = None, experiment: Optional[str] = None, - use_calibration: bool = config.getboolean("od_config", "use_calibration"), + use_calibration: bool = config.getboolean("od_reading.config", "use_calibration"), ) -> ODReader: """ This function prepares ODReader and other necessary transformation objects. It's a higher level API than using ODReader. @@ -1262,7 +1265,7 @@ def start_od_reading( calibration_transformer = NullCalibrationTransformer() # type: ignore if interval is not None: - penalizer = config.getfloat("od_config", "smoothing_penalizer", fallback=700.0) / interval + penalizer = config.getfloat("od_reading.config", "smoothing_penalizer", fallback=700.0) / interval else: penalizer = 0.0 diff --git a/pioreactor/background_jobs/stirring.py b/pioreactor/background_jobs/stirring.py index 81da91ef..4ddd6aec 100644 --- a/pioreactor/background_jobs/stirring.py +++ b/pioreactor/background_jobs/stirring.py @@ -191,9 +191,7 @@ class Stirrer(BackgroundJob): "duty_cycle": {"datatype": "float", "settable": True, "unit": "%"}, } - duty_cycle: float = config.getfloat( - "stirring", "initial_duty_cycle" - ) # only used if calibration isn't defined. + duty_cycle: float = 0 _previous_duty_cycle: float = 0 _measured_rpm: Optional[float] = None @@ -203,7 +201,6 @@ def __init__( unit: str, experiment: str, rpm_calculator: Optional[RpmCalculator] = None, - hertz: float = config.getfloat("stirring", "pwm_hz"), ) -> None: super(Stirrer, self).__init__(unit=unit, experiment=experiment) self.rpm_calculator = rpm_calculator @@ -231,7 +228,9 @@ def __init__( return pin: pt.GpioPin = hardware.PWM_TO_PIN[channel] - self.pwm = PWM(pin, hertz, unit=self.unit, experiment=self.experiment) + self.pwm = PWM( + pin, config.getfloat("stirring.config", "pwm_hz"), unit=self.unit, experiment=self.experiment + ) self.pwm.lock() if target_rpm is not None and self.rpm_calculator is not None: @@ -257,7 +256,7 @@ def __init__( # set up thread to periodically check the rpm self.rpm_check_repeated_thread = RepeatedTimer( - config.getfloat("stirring", "duration_between_updates_seconds", fallback=23.0), + config.getfloat("stirring.config", "duration_between_updates_seconds", fallback=23.0), self.poll_and_update_dc, job_name=self.job_name, run_immediately=True, @@ -478,10 +477,10 @@ def block_until_rpm_is_close_to_target( def start_stirring( - target_rpm: float = config.getfloat("stirring", "target_rpm", fallback=400), + target_rpm: float = config.getfloat("stirring.config", "target_rpm", fallback=400), unit: Optional[str] = None, experiment: Optional[str] = None, - use_rpm: bool = config.getboolean("stirring", "use_rpm", fallback="true"), + use_rpm: bool = config.getboolean("stirring.config", "use_rpm", fallback="true"), ) -> Stirrer: unit = unit or get_unit_name() experiment = experiment or get_assigned_experiment_name(unit) @@ -508,12 +507,14 @@ def start_stirring( @click.command(name="stirring") @click.option( "--target-rpm", - default=config.getfloat("stirring", "target_rpm", fallback=400), + default=config.getfloat("stirring.config", "target_rpm", fallback=400), help="set the target RPM", show_default=True, type=click.FloatRange(0, 1500, clamp=True), ) -@click.option("--use-rpm/--ignore-rpm", default=config.getboolean("stirring", "use_rpm", fallback="true")) +@click.option( + "--use-rpm/--ignore-rpm", default=config.getboolean("stirring.config", "use_rpm", fallback="true") +) def click_stirring(target_rpm: float, use_rpm: bool) -> None: """ Start the stirring of the Pioreactor. diff --git a/pioreactor/cli/pios.py b/pioreactor/cli/pios.py index 616a6e0f..37f223f9 100644 --- a/pioreactor/cli/pios.py +++ b/pioreactor/cli/pios.py @@ -121,7 +121,7 @@ def sync_config_files(unit: str, shared: bool, specific: bool) -> None: except Exception as e: click.echo( - f"Did you forget to create a config_{unit}.ini to deploy to {unit}?", + f"Error syncing config_{unit}.ini to {unit} - do they exist?", err=True, ) raise e diff --git a/pioreactor/tests/test_growth_rate_calculating.py b/pioreactor/tests/test_growth_rate_calculating.py index 0c8d09e2..3da50cbb 100644 --- a/pioreactor/tests/test_growth_rate_calculating.py +++ b/pioreactor/tests/test_growth_rate_calculating.py @@ -432,7 +432,7 @@ def test_end_to_end(self) -> None: experiment = "test_end_to_end" interval = 0.1 - config["od_config"]["samples_per_second"] = "0.2" + config["od_reading.config"]["samples_per_second"] = "0.2" with start_od_reading( "REF", @@ -455,7 +455,7 @@ def test_180_angle(self) -> None: unit = get_unit_name() experiment = "test_180_angle" samples_per_second = 0.2 - config["od_config"]["samples_per_second"] = str(samples_per_second) + config["od_reading.config"]["samples_per_second"] = str(samples_per_second) config["od_config.photodiode_channel"]["1"] = "180" config["od_config.photodiode_channel"]["2"] = None # type: ignore @@ -506,7 +506,7 @@ def test_90_angle(self) -> None: unit = get_unit_name() experiment = "test_90_angle" samples_per_second = 0.2 - config["od_config"]["samples_per_second"] = str(samples_per_second) + config["od_reading.config"]["samples_per_second"] = str(samples_per_second) config["od_config.photodiode_channel"]["1"] = "90" config["od_config.photodiode_channel"]["2"] = None # type: ignore @@ -787,7 +787,7 @@ def test_single_outlier_spike_gets_absorbed(self) -> None: unit = get_unit_name() experiment = "test_single_outlier_spike_gets_absorbed" - config["od_config"]["samples_per_second"] = "0.2" + config["od_reading.config"]["samples_per_second"] = "0.2" # clear mqtt publish( @@ -885,7 +885,7 @@ def test_baseline_shift_gets_absorbed(self) -> None: unit = get_unit_name() experiment = "test_baseline_shift_gets_absorbed" - config["od_config"]["samples_per_second"] = "0.2" + config["od_reading.config"]["samples_per_second"] = "0.2" # clear mqtt publish( @@ -950,7 +950,7 @@ def test_massive_outlier_spike_gets_absorbed(self) -> None: unit = get_unit_name() experiment = "test_massive_outlier_spike_gets_absorbed" - config["od_config"]["samples_per_second"] = "0.2" + config["od_reading.config"]["samples_per_second"] = "0.2" # clear mqtt publish( diff --git a/pioreactor/tests/test_mqtt_to_db_streaming.py b/pioreactor/tests/test_mqtt_to_db_streaming.py index 2596531a..d63c449c 100644 --- a/pioreactor/tests/test_mqtt_to_db_streaming.py +++ b/pioreactor/tests/test_mqtt_to_db_streaming.py @@ -145,7 +145,7 @@ def test_dosing_events_land_in_db() -> None: def test_kalman_filter_entries() -> None: config["storage"]["database"] = "test.sqlite" - config["od_config"]["samples_per_second"] = "0.2" + config["od_reading.config"]["samples_per_second"] = "0.2" config["od_config.photodiode_channel"]["1"] = "135" config["od_config.photodiode_channel"]["2"] = "90" diff --git a/pioreactor/tests/test_od_reading.py b/pioreactor/tests/test_od_reading.py index af2374de..3a5c436e 100644 --- a/pioreactor/tests/test_od_reading.py +++ b/pioreactor/tests/test_od_reading.py @@ -795,7 +795,7 @@ def test_calibration_multi_modal() -> None: def test_calibration_errors_when_ir_led_differs() -> None: experiment = "test_calibration_errors_when_ir_led_differs" - config["od_config"]["ir_led_intensity"] = "90" + config["od_reading.config"]["ir_led_intensity"] = "90" with local_persistant_storage("current_od_calibration") as c: c["90"] = encode( @@ -825,7 +825,7 @@ def test_calibration_errors_when_ir_led_differs() -> None: with local_persistant_storage("current_od_calibration") as c: del c["90"] - config["od_config"]["ir_led_intensity"] = "auto" + config["od_reading.config"]["ir_led_intensity"] = "auto" def test_calibration_errors_when_pd_channel_differs() -> None: @@ -998,42 +998,42 @@ def test_calibration_data_from_user2() -> None: def test_auto_ir_led_intensit_REF_and_90() -> None: - existing_intensity = config["od_config"]["ir_led_intensity"] + existing_intensity = config["od_reading.config"]["ir_led_intensity"] - config["od_config"]["ir_led_intensity"] = "auto" + config["od_reading.config"]["ir_led_intensity"] = "auto" experiment = "test_auto_ir_led_intensity" with start_od_reading("REF", "90", interval=None, fake_data=True, experiment=experiment) as od: assert abs(od.ir_led_intensity - 67.19794921875) < 0.001 - config["od_config"]["ir_led_intensity"] = existing_intensity + config["od_reading.config"]["ir_led_intensity"] = existing_intensity def test_auto_ir_led_intensity_90_only() -> None: - existing_intensity = config["od_config"]["ir_led_intensity"] + existing_intensity = config["od_reading.config"]["ir_led_intensity"] - config["od_config"]["ir_led_intensity"] = "auto" + config["od_reading.config"]["ir_led_intensity"] = "auto" experiment = "test_auto_ir_led_intensity" with start_od_reading(None, "90", interval=None, fake_data=True, experiment=experiment) as od: assert od.ir_led_intensity == 70.0 - config["od_config"]["ir_led_intensity"] = existing_intensity + config["od_reading.config"]["ir_led_intensity"] = existing_intensity def test_auto_ir_led_intensity_90_and_90() -> None: - existing_intensity = config["od_config"]["ir_led_intensity"] + existing_intensity = config["od_reading.config"]["ir_led_intensity"] - config["od_config"]["ir_led_intensity"] = "auto" + config["od_reading.config"]["ir_led_intensity"] = "auto" experiment = "test_auto_ir_led_intensity" with start_od_reading("90", "90", interval=None, fake_data=True, experiment=experiment) as od: assert od.ir_led_intensity == 70.0 - config["od_config"]["ir_led_intensity"] = existing_intensity + config["od_reading.config"]["ir_led_intensity"] = existing_intensity def test_at_least_one_channel() -> None: diff --git a/pioreactor/utils/mock.py b/pioreactor/utils/mock.py index 40465fc8..ae93ea99 100644 --- a/pioreactor/utils/mock.py +++ b/pioreactor/utils/mock.py @@ -64,13 +64,13 @@ def read_from_channel(self, channel: pt.AdcChannel): return self.from_voltage_to_raw(0.250 + random.normalvariate(0, sigma=0.001) / 2**10) else: self.gr = self.growth_rate( - self._counter / config.getfloat("od_config", "samples_per_second"), am_i_REF + self._counter / config.getfloat("od_reading.config", "samples_per_second"), am_i_REF ) self.state *= np.exp( self.gr / 60 / 60 - / config.getfloat("od_config", "samples_per_second") + / config.getfloat("od_reading.config", "samples_per_second") / 32 # divide by N from oversampling_count ) self._counter += 1.0 / 32 # divide by N from oversampling_count @@ -170,7 +170,7 @@ def __and__(self, other): class MockRpmCalculator: - ALWAYS_RETURN_RPM = config.getfloat("stirring", "target_rpm") + ALWAYS_RETURN_RPM = config.getfloat("stirring.config", "target_rpm") def setup(self): pass diff --git a/update_scripts/upcoming/update.sh b/update_scripts/upcoming/update.sh index 6dfd2c43..bd37d20b 100644 --- a/update_scripts/upcoming/update.sh +++ b/update_scripts/upcoming/update.sh @@ -9,7 +9,7 @@ export LC_ALL=C PIO_DIR=/home/pioreactor/.pioreactor # all pioreactors get a unit_config, include leader-only pioworekrs -touch PIO_DIR/unit_config.ini +touch $PIO_DIR/unit_config.ini HOSTNAME=$(hostname) @@ -19,5 +19,64 @@ LEADER_HOSTNAME=$(crudini --get $PIO_DIR/config.ini cluster.topology leader_host if [ "$HOSTNAME" = "$LEADER_HOSTNAME" ]; then + # stirring -> stirring.config + # Iterate over each ini file in the directory + for ini_file in "$PIO_DIR"/config*.ini; do + echo "Processing file: $ini_file" + + # Check if the [stirring] section exists in the file + if crudini --get "$ini_file" stirring &> /dev/null; then + echo "Found [stirring] section in $ini_file. Changing to [stirring.config]." + + # Create a temporary file to work with + tmp_file=$(mktemp) + echo "[stirring.config]" >> "$tmp_file" + crudini --format=sh --get "$ini_file" stirring >> "$tmp_file" + + # Use crudini to rename the section + crudini --merge "$ini_file" < "$tmp_file" + + # Replace the original file with the updated file + #mv "$tmp_file" "$ini_file" + + # Optionally remove the original [stirring] section + crudini --del "$ini_file" stirring + + else + echo "No [stirring] section found in $ini_file. Skipping." + fi + done + + + # od_config -> od_reading.config + # Iterate over each ini file in the directory + for ini_file in "$PIO_DIR"/config*.ini; do + + echo "Processing file: $ini_file" + + # Check if the [od_config] section exists in the file + if crudini --get "$ini_file" od_config &> /dev/null; then + echo "Found [od_config] section in $ini_file. Changing to [od_reading.config]." + + # Create a temporary file to work with + tmp_file=$(mktemp) + echo "[od_reading.config]" >> "$tmp_file" + crudini --format=sh --get "$ini_file" od_config >> "$tmp_file" + + # Use crudini to rename the section + crudini --merge "$ini_file" < "$tmp_file" + + # Replace the original file with the updated file + #mv "$tmp_file" "$ini_file" + + # Optionally remove the original [od_config] section + crudini --del "$ini_file" od_config + + else + echo "No [od_config] section found in $ini_file. Skipping." + fi + done + + sudo -u pioreactor pios sync-configs fi