diff --git a/CHANGES.md b/CHANGES.md index 863df3e..319e5d4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ in their terminal after installation, which will fire up the backend and open the browser - Add versioneer +- Enable user to specify pump configuration directory - Update to `react-scripts` 2.1.3 2018.11.07 diff --git a/pyqmix_backend/backend_app.py b/pyqmix_backend/backend_app.py index ba821e5..42fad6e 100644 --- a/pyqmix_backend/backend_app.py +++ b/pyqmix_backend/backend_app.py @@ -112,7 +112,17 @@ class SetUpConfig(Resource): def get(self): # Return a list of available config-dirs and send to frontend - list_of_available_configurations = config.get_available_qmix_configs() + try: + list_of_available_configurations = config.get_available_qmix_configs() + except: + list_of_available_configurations = [] # If the default configuration does not exist + + if list_of_available_configurations: + configuration_path = config.DEFAULT_CONFIGS_DIR + else: # If the default configuration path does not exist or if there are no configurations + configuration_path = op.expanduser('~') + list_of_available_configurations = config.get_available_qmix_configs(configs_dir=configuration_path) + list_of_available_syringe_sizes = list(syringes.keys()) # Return status of pump-setup @@ -120,7 +130,8 @@ def get(self): setup_dict = {'is_config_set_up': config_setup, 'available_configs': list_of_available_configurations, - 'available_syringes': list_of_available_syringe_sizes} + 'available_syringes': list_of_available_syringe_sizes, + 'configuration_path': configuration_path} return setup_dict @api.expect(config_setup) @@ -132,6 +143,21 @@ def put(self): set_up_config(config_name=config_name) +@api.route('/api/config_update') +class UpdateConfig(Resource): + + def put(self): + payload = request.json + configuration_path = payload['configPath'] + try: + list_of_available_configurations = config.get_available_qmix_configs(configs_dir=configuration_path) + except: # Return empty list if path does not exist + list_of_available_configurations = [] + setup_dict = {'available_configs': list_of_available_configurations} + + return setup_dict + + @api.route('/api/pumps') class InitiateOrDisconnectPumps(Resource): @@ -268,6 +294,7 @@ def disconnect_pumps(): print(f'Bus after "closing": {session_paramters["bus"]}') session_paramters['pumps'] = {} + config.delete_config() return True @@ -296,8 +323,8 @@ def get_pump_state(pump_id): return pump_status -def pump_set_fill_level(pump_id, target_volume, flow_rate): +def pump_set_fill_level(pump_id, target_volume, flow_rate): if app.config['test_session']: print(f'Starting virtual pump: {pump_id} and setting ' f'target_volume to {target_volume} mL ' diff --git a/pyqmix_frontend/src/App.js b/pyqmix_frontend/src/App.js index c177920..228738b 100644 --- a/pyqmix_frontend/src/App.js +++ b/pyqmix_frontend/src/App.js @@ -12,10 +12,11 @@ class PumpForm extends Component { // System setup webConnectedToPumps: false, // Does the website think the pumps are connected (based on user-input, not backend) - isPumpConfigSetUp: false, // Are the pumps set up in the backend + isPumpConfigSetUp: false, // Are the pumps configured in the backend userEnteredPumpConfiguration: false, // Method to wait for user input on config-name and pump-type availableConfigurations: [], availableSyringeTypes: [], + configurationPath: "", selectedQmixConfig: "", selectedSyringeType: "", userEnteredBubbleToggle: "", @@ -78,6 +79,10 @@ class PumpForm extends Component { // --- Update state by Configuration and Syringe Size fields --- // handleConfigNameChange = (e) => this.setState({selectedQmixConfig: e.target.innerText}); handleSyringeTypeChange = (e) => this.setState({selectedSyringeType: e.target.innerText}); + handleConfigPathChange = (e) => { + this.setState({configurationPath: e.target.value}); + this.updateAvailableConfigurations(e.target.value); + }; handleLocatingConfig = () => { this.toggle('locateConfigFiles'); this.setState({userEnteredPumpConfiguration: true}) @@ -321,9 +326,12 @@ class PumpForm extends Component { }, }); const json = await response.json(); - await this.asyncSetState({isPumpConfigSetUp: json['is_config_set_up']}); + // Uncommented since I want to configure pumps every time I press 'Detect Pumps' + // await this.asyncSetState({isPumpConfigSetUp: json['is_config_set_up']}); + await this.asyncSetState({isPumpConfigSetUp: false}); await this.asyncSetState({availableConfigurations: json['available_configs']}); await this.asyncSetState({availableSyringeTypes: json['available_syringes']}); + await this.asyncSetState({configurationPath: json['configuration_path']}); // Use first item as default. const defaultConfig = this.state.availableConfigurations[0]; @@ -332,6 +340,23 @@ class PumpForm extends Component { await this.asyncSetState({selectedSyringeType: defaultSyringeType}) }; + updateAvailableConfigurations = async (configPath) => { + let payload = {configPath: configPath}; + const response = await fetch('/api/config_update', { + method: 'put', + headers: { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + const json = await response.json(); + await this.asyncSetState({availableConfigurations: json['available_configs']}); + + const defaultConfig = this.state.availableConfigurations[0]; + await this.asyncSetState({selectedQmixConfig: defaultConfig}); + }; + // --- Function to wait for user input --- // waitForConfigFilesToBeSet = async () => { do { @@ -713,26 +738,47 @@ class PumpForm extends Component { onSubmit={(e) => { e.preventDefault(); }}> - {/*Dropdown for config name*/} - - this.toggle('configDropDownOpen')}> - - {this.state.selectedQmixConfig} - - - {this.state.availableConfigurations.map(config => - - {config} - - )} - - - + +
+
+ +
+ {/*Specify configuration directory*/} +
Configuration directory:
+ + + +
+ +
+ {/*Dropdown to choose configuration*/} +
Select configuration:
+ + this.toggle('configDropDownOpen')}> + + {this.state.selectedQmixConfig} + + + {this.state.availableConfigurations.map(config => + + {config} + + )} + + + +
+
+
+
Select syringe type:
this.toggle('syringeDropDownOpen')}> @@ -755,6 +801,7 @@ class PumpForm extends Component { @@ -765,8 +812,15 @@ class PumpForm extends Component { className={this.props.className}> Error - no pumps were detected. - Check that (1) the pumps are powered on and connected to the computer, and (2) that the bus is not - connected already. Then try again. + Ensure that: +
    +
  • You followed the gustometer installation instructions.
  • +
  • That you selected a valid pump configuration.
  • +
  • That the pumps are powered on and connected to the computer.
  • +
  • That the bus is not in use by another program, for example QmixElements.
  • +
  • If the above approaches are unsuccessful, then try adding the directory of the Qmix SDK DLL's to the Windows path variable.
  • +
+ Then try again.