From be94df7c8ab93edeefb37560de3ccb7500a3b368 Mon Sep 17 00:00:00 2001 From: Julian Stirling Date: Sun, 13 Jul 2025 11:14:20 +0100 Subject: [PATCH] Merge SettingsManager and SystemControl Things. --- ofm_config_full.json | 3 +- ofm_config_simulation.json | 3 +- .../things/{settings_manager.py => system.py} | 58 ++++++++++++++++--- .../things/system_control.py | 48 --------------- webapp/src/App.vue | 2 +- .../aboutComponents/statusPane.vue | 2 +- .../tabContentComponents/powerContent.vue | 6 +- 7 files changed, 57 insertions(+), 65 deletions(-) rename src/openflexure_microscope_server/things/{settings_manager.py => system.py} (57%) delete mode 100644 src/openflexure_microscope_server/things/system_control.py diff --git a/ofm_config_full.json b/ofm_config_full.json index 38a76685..1cfedb26 100644 --- a/ofm_config_full.json +++ b/ofm_config_full.json @@ -5,8 +5,7 @@ "/auto_recentre_stage/": "openflexure_microscope_server.things.auto_recentre_stage:RecentringThing", "/autofocus/": "openflexure_microscope_server.things.autofocus:AutofocusThing", "/camera_stage_mapping/": "openflexure_microscope_server.things.camera_stage_mapping:CameraStageMapper", - "/system_control/": "openflexure_microscope_server.things.system_control:SystemControlThing", - "/settings/": "openflexure_microscope_server.things.settings_manager:SettingsManager", + "/system/": "openflexure_microscope_server.things.system:OpenFlexureSystem", "/smart_scan/": { "class": "openflexure_microscope_server.things.smart_scan:SmartScanThing", "kwargs": { diff --git a/ofm_config_simulation.json b/ofm_config_simulation.json index 9acf747b..a254fa85 100644 --- a/ofm_config_simulation.json +++ b/ofm_config_simulation.json @@ -5,8 +5,7 @@ "/auto_recentre_stage/": "openflexure_microscope_server.things.auto_recentre_stage:RecentringThing", "/autofocus/": "openflexure_microscope_server.things.autofocus:AutofocusThing", "/camera_stage_mapping/": "openflexure_microscope_server.things.camera_stage_mapping:CameraStageMapper", - "/system_control/": "openflexure_microscope_server.things.system_control:SystemControlThing", - "/settings/": "openflexure_microscope_server.things.settings_manager:SettingsManager", + "/system/": "openflexure_microscope_server.things.system:OpenFlexureSystem", "/smart_scan/": { "class": "openflexure_microscope_server.things.smart_scan:SmartScanThing", "kwargs": { diff --git a/src/openflexure_microscope_server/things/settings_manager.py b/src/openflexure_microscope_server/things/system.py similarity index 57% rename from src/openflexure_microscope_server/things/settings_manager.py rename to src/openflexure_microscope_server/things/system.py index df0e144d..bd3f23f9 100644 --- a/src/openflexure_microscope_server/things/settings_manager.py +++ b/src/openflexure_microscope_server/things/system.py @@ -1,25 +1,39 @@ -"""OpenFlexure Settings Management. +"""OpenFlexure System. -This module provides some settings management across the other Things, and -for code that currently lives in clients but needs to persist settings on -the server. +A module to control the underlying microscope system and to expose information about +the microscope, server, and thing states to the web API. """ from collections.abc import Mapping from socket import gethostname from typing import Optional from uuid import UUID, uuid4 +import subprocess +import os + +from pydantic import BaseModel import labthings_fastapi as lt from openflexure_microscope_server.utilities import VersionData, robust_version_strings -class SettingsManager(lt.Thing): - """Provides functionality to other Things about the current server state. +class CommandOutput(BaseModel): + """A pydantic model passing the STDOUT and STDERR from a subprocess over HTTP.""" - The SettingsManager is used to get information the microscope ID, the hostname - and the state of other Things. + output: str + error: str + + +class OpenFlexureSystem(lt.Thing): + """Describe and control the OpenFlexure system. + + This Things: + + * Exposes information about the Microscope, Server, and Thing states to the web + API. + * Controls the underlying OS on the Raspberry Pi allowing shutdown and restarting + of the system. """ _microscope_id: Optional[str] = None @@ -58,6 +72,34 @@ class SettingsManager(lt.Thing): self._version_data = robust_version_strings() return self._version_data + @lt.thing_property + def is_raspberrypi(self) -> bool: + """Return True if running on a Raspberry Pi.""" + return os.path.exists("/usr/bin/raspi-config") + + @lt.thing_action + def shutdown(self) -> CommandOutput: + """Attempt to shutdown the device.""" + p = subprocess.Popen( + ["sudo", "shutdown", "-h", "now"], + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + out, err = p.communicate() + return CommandOutput(output=out, error=err) + + @lt.thing_action + def reboot(self) -> CommandOutput: + """Attempt to reboot the device.""" + p = subprocess.Popen( + ["sudo", "shutdown", "-r", "now"], + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + out, err = p.communicate() + return CommandOutput(output=out, error=err) + @lt.thing_action def get_things_state(self, metadata_getter: lt.deps.GetThingStates) -> Mapping: """Metadata summarising the current state of all Things in the server.""" diff --git a/src/openflexure_microscope_server/things/system_control.py b/src/openflexure_microscope_server/things/system_control.py deleted file mode 100644 index 82dc276a..00000000 --- a/src/openflexure_microscope_server/things/system_control.py +++ /dev/null @@ -1,48 +0,0 @@ -"""OpenFlexure Microscope system control Thing. - -This module defines a Thing that can shut down or restart the host computer. -""" - -import subprocess -import os -import labthings_fastapi as lt -from pydantic import BaseModel - - -class CommandOutput(BaseModel): - """A pydantic model passing the STDOUT and STDERR from a subprocess over HTTP.""" - - output: str - error: str - - -class SystemControlThing(lt.Thing): - """Attempt to shutdown the device.""" - - @lt.thing_action - def shutdown(self) -> CommandOutput: - """Attempt to shutdown the device.""" - p = subprocess.Popen( - ["sudo", "shutdown", "-h", "now"], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - ) - - out, err = p.communicate() - return CommandOutput(output=out, error=err) - - @lt.thing_property - def is_raspberrypi() -> bool: - """Return True if running on a Raspberry Pi.""" - return os.path.exists("/usr/bin/raspi-config") - - @lt.thing_action - def reboot(self) -> CommandOutput: - """Attempt to reboot the device.""" - p = subprocess.Popen( - ["sudo", "shutdown", "-r", "now"], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - ) - out, err = p.communicate() - return CommandOutput(output=out, error=err) diff --git a/webapp/src/App.vue b/webapp/src/App.vue index 97c46c19..3f76338e 100644 --- a/webapp/src/App.vue +++ b/webapp/src/App.vue @@ -236,7 +236,7 @@ export default { } } try { - let hostname = await this.readThingProperty("settings", "hostname"); + let hostname = await this.readThingProperty("system", "hostname"); this.$store.commit("changeMicroscopeHostname", hostname); document.title = `OpenFlexure Microscope: ${hostname}`; } catch { diff --git a/webapp/src/components/tabContentComponents/aboutComponents/statusPane.vue b/webapp/src/components/tabContentComponents/aboutComponents/statusPane.vue index 6314666f..4d8d032d 100644 --- a/webapp/src/components/tabContentComponents/aboutComponents/statusPane.vue +++ b/webapp/src/components/tabContentComponents/aboutComponents/statusPane.vue @@ -76,7 +76,7 @@ export default { async mounted() { let version_data = await this.readThingProperty( - "settings", + "system", "version_data" ); this.version = version_data.version; diff --git a/webapp/src/components/tabContentComponents/powerContent.vue b/webapp/src/components/tabContentComponents/powerContent.vue index 855174d8..b442a796 100644 --- a/webapp/src/components/tabContentComponents/powerContent.vue +++ b/webapp/src/components/tabContentComponents/powerContent.vue @@ -9,14 +9,14 @@