diff --git a/device-backend/control/adafruithat/__init__.py b/device-backend/control/adafruithat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/device-backend/control/adafruithat/main.py b/device-backend/control/adafruithat/main.py index f72c8e799..695d61a9b 100644 --- a/device-backend/control/adafruithat/main.py +++ b/device-backend/control/adafruithat/main.py @@ -23,37 +23,8 @@ from loguru import logger # for logging with multiprocessing -import planktoscope.mqtt -import planktoscope.stepper -import planktoscope.light # Fan HAT LEDs -import planktoscope.identity -import planktoscope.display # Fan HAT OLED screen -from planktoscope.imager import mqtt as imager - -# enqueue=True is necessary so we can log across modules -# rotation happens everyday at 01:00 if not restarted -logs_path = "/home/pi/device-backend-logs/control" -if not os.path.exists(logs_path): - os.makedirs(logs_path) -logger.add( - # sys.stdout, - "/home/pi/device-backend-logs/control/{time}.log", - rotation="5 MB", - retention="1 week", - compression=".tar.gz", - enqueue=True, - level="DEBUG", -) - -# The available level for the logger are as follows: -# Level name Severity Logger method -# TRACE 5 logger.trace() -# DEBUG 10 logger.debug() -# INFO 20 logger.info() -# SUCCESS 25 logger.success() -# WARNING 30 logger.warning() -# ERROR 40 logger.error() -# CRITICAL 50 logger.critical() +from adafruithat.planktoscope import stepper, light, identity, display +from adafruithat.planktoscope.imager import mqtt as imager logger.info("Starting the PlanktoScope hardware controller!") @@ -67,7 +38,7 @@ def handler_stop_signals(signum, _): run = False -if __name__ == "__main__": +def main(): logger.info("Welcome!") logger.info( "Initialising signals handling and sanitizing the directories (step 1/4)" @@ -97,9 +68,7 @@ def handler_stop_signals(signum, _): # create the path! os.makedirs(img_path) - logger.info( - f"This PlanktoScope's machine name is {planktoscope.identity.load_machine_name()}" - ) + logger.info(f"This PlanktoScope's machine name is {identity.load_machine_name()}") # Prepare the event for a graceful shutdown shutdown_event = multiprocessing.Event() @@ -107,7 +76,7 @@ def handler_stop_signals(signum, _): # Starts the stepper process for actuators logger.info("Starting the stepper control process (step 2/4)") - stepper_thread = planktoscope.stepper.StepperProcess(shutdown_event) + stepper_thread = stepper.StepperProcess(shutdown_event) stepper_thread.start() # Starts the imager control process @@ -121,10 +90,10 @@ def handler_stop_signals(signum, _): imager_thread.start() logger.info("Starting the display module (step 4/4)") - display = planktoscope.display.Display() + display = display.Display() logger.success("Looks like the controller is set up and running, have fun!") - planktoscope.light.ready() + light.ready() while run: # TODO look into ways of restarting the dead threads diff --git a/device-backend/control/adafruithat/planktoscope/camera/mqtt.py b/device-backend/control/adafruithat/planktoscope/camera/mqtt.py index 2a00b4bc4..ee2df81cd 100644 --- a/device-backend/control/adafruithat/planktoscope/camera/mqtt.py +++ b/device-backend/control/adafruithat/planktoscope/camera/mqtt.py @@ -8,8 +8,8 @@ import loguru -from planktoscope import mqtt as messaging -from planktoscope.camera import hardware, mjpeg +from .. import mqtt as messaging +from . import hardware, mjpeg loguru.logger.info("planktoscope.camera is loaded") diff --git a/device-backend/control/adafruithat/planktoscope/camera/test_preview.py b/device-backend/control/adafruithat/planktoscope/camera/test_preview.py index 62e2c9886..dcf450dcc 100644 --- a/device-backend/control/adafruithat/planktoscope/camera/test_preview.py +++ b/device-backend/control/adafruithat/planktoscope/camera/test_preview.py @@ -8,7 +8,7 @@ import picamera2 # type: ignore from picamera2 import encoders, outputs -from planktoscope.camera import hardware, mjpeg +from . import hardware, mjpeg def main() -> None: diff --git a/device-backend/control/adafruithat/planktoscope/display.py b/device-backend/control/adafruithat/planktoscope/display.py index 2e002d315..49e3d46ef 100644 --- a/device-backend/control/adafruithat/planktoscope/display.py +++ b/device-backend/control/adafruithat/planktoscope/display.py @@ -18,18 +18,15 @@ # Logger library compatible with multiprocessing from loguru import logger -import datetime -import os - import Adafruit_SSD1306 import PIL.Image import PIL.ImageDraw import PIL.ImageFont -logger.info("planktoscope.display is loading") +from . import identity -import planktoscope.identity +logger.info("planktoscope.display is loading") class Display(object): @@ -54,7 +51,7 @@ def __init__(self): def display_machine_name(self): if self.display_available: self.__clear() - machineName = planktoscope.identity.load_machine_name() + machineName = identity.load_machine_name() self.display_text(machineName.replace(" ", "\n")) def display_text(self, message): diff --git a/device-backend/control/adafruithat/planktoscope/imager/mqtt.py b/device-backend/control/adafruithat/planktoscope/imager/mqtt.py index c7516d2ae..35b91b03a 100644 --- a/device-backend/control/adafruithat/planktoscope/imager/mqtt.py +++ b/device-backend/control/adafruithat/planktoscope/imager/mqtt.py @@ -10,9 +10,9 @@ import loguru -from planktoscope import identity, integrity, mqtt -from planktoscope.camera import mqtt as camera -from planktoscope.imager import stopflow +from .. import identity, integrity, mqtt +from ..camera import mqtt as camera +from . import stopflow loguru.logger.info("planktoscope.imager is loaded") diff --git a/device-backend/control/adafruithat/planktoscope/stepper.py b/device-backend/control/adafruithat/planktoscope/stepper.py index d21b1ea54..cb88e2f2c 100644 --- a/device-backend/control/adafruithat/planktoscope/stepper.py +++ b/device-backend/control/adafruithat/planktoscope/stepper.py @@ -21,11 +21,11 @@ import time import json import os -import planktoscope.mqtt -import planktoscope.light import multiprocessing import RPi.GPIO +from . import mqtt, light + # Logger library compatible with multiprocessing from loguru import logger @@ -203,11 +203,11 @@ def __message_pump(self, last_message): "status/pump", '{"status":"Interrupted"}' ) - planktoscope.light.ready() + light.ready() elif last_message["action"] == "move": logger.debug("We have received a move pump command") - planktoscope.light.pumping() + light.pumping() if ( "direction" not in last_message @@ -256,11 +256,11 @@ def __message_focus(self, last_message): "status/focus", '{"status":"Interrupted"}' ) - planktoscope.light.ready() + light.ready() elif last_message["action"] == "move": logger.debug("We have received a move focus command") - planktoscope.light.focusing() + light.focusing() if "direction" not in last_message or "distance" not in last_message: logger.error( @@ -422,7 +422,7 @@ def run(self): # it doesn't see changes and calls made by self.actuator_client because this one # only exist in the master process # see https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class - self.actuator_client = planktoscope.mqtt.MQTT_Client( + self.actuator_client = mqtt.MQTT_Client( topic="actuator/#", name="actuator_client" ) # Publish the status "Ready" to via MQTT to Node-RED @@ -437,14 +437,14 @@ def run(self): self.treat_command() if self.pump_stepper.move(): delay = 0.0001 - planktoscope.light.ready() + light.ready() self.actuator_client.client.publish( "status/pump", '{"status":"Done"}', ) if self.focus_stepper.move(): delay = 0.0001 - planktoscope.light.ready() + light.ready() self.actuator_client.client.publish( "status/focus", '{"status":"Done"}', diff --git a/device-backend/control/main.py b/device-backend/control/main.py new file mode 100644 index 000000000..d354ea8e8 --- /dev/null +++ b/device-backend/control/main.py @@ -0,0 +1,80 @@ +import json +from os import makedirs, path + +from loguru import logger + +# enqueue=True is necessary so we can log across modules +# rotation happens everyday at 01:00 if not restarted +logs_path = "/home/pi/device-backend-logs/control" +if not path.exists(logs_path): + makedirs(logs_path) +logger.add( + # sys.stdout, + "/home/pi/device-backend-logs/control/{time}.log", + rotation="5 MB", + retention="1 week", + compression=".tar.gz", + enqueue=True, + level="DEBUG", +) + +# The available level for the logger are as follows: +# Level name Severity Logger method +# TRACE 5 logger.trace() +# DEBUG 10 logger.debug() +# INFO 20 logger.info() +# SUCCESS 25 logger.success() +# WARNING 30 logger.warning() +# ERROR 40 logger.error() +# CRITICAL 50 logger.critical() + +# This is a special case for legacy hardware; new hardware designs should all be part of the +# planktoscopehat codebase: +CONFIG_PATH = "/home/pi/PlanktoScope/config.json" + + +def load_variant_setting(config_path: str = CONFIG_PATH): + config = {} + try: + with open(config_path, "r") as file: + try: + config = json.load(file) + except Exception: + logger.exception(f"Couldn't parse {config_path} as JSON file") + return None + except Exception: + logger.exception(f"Couldn't open {config_path}") + return None + + if "acq_instrument" not in config: + logger.error(f"{config_path} lacks a 'acq_instrument' field") + return None + + if config["acq_instrument"] == "PlanktoScope v2.1": + return "adafruithat" + return "planktoscopehat" + + +def main(): + logger.info("Determining configured hardware variant...") + variant = load_variant_setting() + if variant is None: + variant = "planktoscopehat" + logger.warning( + f"Couldn't load hardware variant setting from config, defaulting to {variant}" + ) + logger.info(f"Hardware variant: {variant}") + + if variant == "adafruithat": + from adafruithat import main as platform # noqa: IMR200 + else: + from planktoscopehat import main as platform # noqa: IMR200 + + platform.main() + + +if __name__ == "__main__": + try: + main() + except Exception: + logger.exception("Unhandled exception") diff --git a/device-backend/control/planktoscopehat/__init__.py b/device-backend/control/planktoscopehat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/device-backend/control/planktoscopehat/main.py b/device-backend/control/planktoscopehat/main.py index d3d87e76c..d7555873c 100644 --- a/device-backend/control/planktoscopehat/main.py +++ b/device-backend/control/planktoscopehat/main.py @@ -7,37 +7,8 @@ from loguru import logger -import planktoscope.mqtt -import planktoscope.pump -import planktoscope.focus -import planktoscope.light -import planktoscope.identity -from planktoscope.imager import mqtt as imager - -# enqueue=True is necessary so we can log across modules -# rotation happens everyday at 01:00 if not restarted -logs_path = "/home/pi/device-backend-logs/control" -if not os.path.exists(logs_path): - os.makedirs(logs_path) -logger.add( - # sys.stdout, - "/home/pi/device-backend-logs/control/{time}.log", - rotation="5 MB", - retention="1 week", - compression=".tar.gz", - enqueue=True, - level="DEBUG", -) - -# The available level for the logger are as follows: -# Level name Severity Logger method -# TRACE 5 logger.trace() -# DEBUG 10 logger.debug() -# INFO 20 logger.info() -# SUCCESS 25 logger.success() -# WARNING 30 logger.warning() -# ERROR 40 logger.error() -# CRITICAL 50 logger.critical() +from planktoscopehat.planktoscope import pump, focus, light, identity +from planktoscopehat.planktoscope.imager import mqtt as imager logger.info("Starting the PlanktoScope python script!") @@ -51,7 +22,7 @@ def handler_stop_signals(signum, frame): run = False -if __name__ == "__main__": +def main(): logger.info("Welcome!") logger.info( "Initialising configuration, signals handling and sanitizing the directories (step 1/5)" @@ -81,9 +52,7 @@ def handler_stop_signals(signum, frame): # create the path! os.makedirs(img_path) - logger.info( - f"This PlanktoScope's machine name is {planktoscope.identity.load_machine_name()}" - ) + logger.info(f"This PlanktoScope's machine name is {identity.load_machine_name()}") try: with open("/home/pi/PlanktoScope/hardware.json", "r") as config_file: @@ -100,12 +69,12 @@ def handler_stop_signals(signum, frame): # Starts the pump process logger.info("Starting the pump control process (step 2/5)") - pump_thread = planktoscope.pump.PumpProcess(shutdown_event, configuration) + pump_thread = pump.PumpProcess(shutdown_event, configuration) pump_thread.start() # Starts the focus process logger.info("Starting the focus control process (step 3/5)") - focus_thread = planktoscope.focus.FocusProcess(shutdown_event, configuration) + focus_thread = focus.FocusProcess(shutdown_event, configuration) focus_thread.start() # TODO try to isolate the imager thread (or another thread) @@ -122,7 +91,7 @@ def handler_stop_signals(signum, frame): # Starts the light process logger.info("Starting the light control process (step 5/5)") try: - light_thread = planktoscope.light.LightProcess(shutdown_event, configuration) + light_thread = light.LightProcess(shutdown_event, configuration) except Exception: logger.error("The light control process could not be started") light_thread = None diff --git a/device-backend/control/planktoscopehat/planktoscope/camera/mqtt.py b/device-backend/control/planktoscopehat/planktoscope/camera/mqtt.py index 4ce1a8bc0..101ada319 100644 --- a/device-backend/control/planktoscopehat/planktoscope/camera/mqtt.py +++ b/device-backend/control/planktoscopehat/planktoscope/camera/mqtt.py @@ -7,8 +7,8 @@ import loguru -from planktoscope import mqtt as messaging -from planktoscope.camera import hardware, mjpeg +from .. import mqtt as messaging +from . import hardware, mjpeg loguru.logger.info("planktoscope.camera is loaded") diff --git a/device-backend/control/planktoscopehat/planktoscope/camera/test_preview.py b/device-backend/control/planktoscopehat/planktoscope/camera/test_preview.py index 62e2c9886..dcf450dcc 100644 --- a/device-backend/control/planktoscopehat/planktoscope/camera/test_preview.py +++ b/device-backend/control/planktoscopehat/planktoscope/camera/test_preview.py @@ -8,7 +8,7 @@ import picamera2 # type: ignore from picamera2 import encoders, outputs -from planktoscope.camera import hardware, mjpeg +from . import hardware, mjpeg def main() -> None: diff --git a/device-backend/control/planktoscopehat/planktoscope/focus.py b/device-backend/control/planktoscopehat/planktoscope/focus.py index 7169e3411..4a241f542 100644 --- a/device-backend/control/planktoscopehat/planktoscope/focus.py +++ b/device-backend/control/planktoscopehat/planktoscope/focus.py @@ -4,9 +4,8 @@ from loguru import logger -from planktoscope.stepper import stepper - from . import mqtt +from .stepper import stepper logger.info("planktoscope.focus is loaded") diff --git a/device-backend/control/planktoscopehat/planktoscope/imager/mqtt.py b/device-backend/control/planktoscopehat/planktoscope/imager/mqtt.py index db5e7c0d6..387c0dddf 100644 --- a/device-backend/control/planktoscopehat/planktoscope/imager/mqtt.py +++ b/device-backend/control/planktoscopehat/planktoscope/imager/mqtt.py @@ -10,9 +10,9 @@ import loguru -from planktoscope import identity, integrity, mqtt -from planktoscope.camera import mqtt as camera -from planktoscope.imager import stopflow +from .. import identity, integrity, mqtt +from ..camera import mqtt as camera +from . import stopflow loguru.logger.info("planktoscope.imager is loaded") diff --git a/device-backend/control/planktoscopehat/planktoscope/module.py b/device-backend/control/planktoscopehat/planktoscope/module.py index 8cf3bbf5d..93a09d0ca 100644 --- a/device-backend/control/planktoscopehat/planktoscope/module.py +++ b/device-backend/control/planktoscopehat/planktoscope/module.py @@ -10,7 +10,7 @@ import multiprocessing # Basic planktoscope communication libraries -import planktoscope.mqtt +from . import mqtt logger.info("planktoscope.module is loaded") @@ -69,7 +69,7 @@ def run(self): ) # MQTT Service connection - self.module_client = planktoscope.mqtt.MQTT_Client( + self.module_client = mqtt.MQTT_Client( topic="module/#", name="module_client" ) @@ -93,4 +93,4 @@ def run(self): # This is called if this script is launched directly if __name__ == "__main__": # This should be tests of your module - pass \ No newline at end of file + pass diff --git a/device-backend/control/planktoscopehat/planktoscope/pump.py b/device-backend/control/planktoscopehat/planktoscope/pump.py index 053bb7fbd..c32a7f277 100644 --- a/device-backend/control/planktoscopehat/planktoscope/pump.py +++ b/device-backend/control/planktoscopehat/planktoscope/pump.py @@ -4,9 +4,8 @@ from loguru import logger -from planktoscope.stepper import stepper - from . import mqtt +from .stepper import stepper logger.info("planktoscope.pump is loaded") diff --git a/software/distro/setup/ci-record-version.sh b/software/distro/setup/ci-record-version.sh index fdf41dc2d..8dda3dbd0 100755 --- a/software/distro/setup/ci-record-version.sh +++ b/software/distro/setup/ci-record-version.sh @@ -5,7 +5,7 @@ # REPO (the repo used for setup, e.g. github.com/PlanktoScope/PlanktoScope) # VERSION_QUERY (the version query, e.g. a commit hash) # QUERY_TYPE (eitiher branch, tag, or hash) -# HARDWARE (either none, segmenter-only, adafruithat, or planktoscopehat) +# HARDWARE (either none, adafruithat, or planktoscopehat) # VERSION_QUERY_DIR (the filesystem path of the git repo used for getting version info) # Utilities for user interaction diff --git a/software/distro/setup/cleanup.sh b/software/distro/setup/cleanup.sh index ef3494a83..7d44389f9 100755 --- a/software/distro/setup/cleanup.sh +++ b/software/distro/setup/cleanup.sh @@ -7,7 +7,7 @@ setup_scripts_root=$(dirname $(realpath $BASH_SOURCE)) # Get command-line args -hardware_type="$1" # should be either none, adafruithat, planktoscopehat, or segmenter-only +hardware_type="$1" # should be either none, adafruithat, or planktoscopehat # Set up pretty error printing diff --git a/software/distro/setup/planktoscope-app-env/node-red-frontend/install.sh b/software/distro/setup/planktoscope-app-env/node-red-frontend/install.sh index cb028e2dd..2004d7b91 100755 --- a/software/distro/setup/planktoscope-app-env/node-red-frontend/install.sh +++ b/software/distro/setup/planktoscope-app-env/node-red-frontend/install.sh @@ -5,20 +5,12 @@ config_files_root=$(dirname "$(realpath "$BASH_SOURCE")") # Get command-line args -hardware_type="$1" # should be either adafruithat, planktoscopehat, fairscope-latest, or segmenter-only +hardware_type="$1" # should be either adafruithat, planktoscopehat, or fairscope-latest default_config="$hardware_type-latest" -case "$hardware_type" in -"fairscope-latest") +if [ "$hardware_type" = "fairscope-latest" ]; then hardware_type="planktoscopehat" default_config="fairscope-latest" - ;; -"segmenter-only") - # FIXME: instead set up the segmenter-only version of the Node-RED dashboard! - echo "Warning: setting up adafruithat version of Node-RED dashboard for hardware type: $hardware_type" - hardware_type=adafruithat - default_config="adafruithat-latest" - ;; -esac +fi # Install dependencies # smbus is needed by some python3 nodes in the Node-RED dashboard for the Adafruit HAT. @@ -50,5 +42,5 @@ cp "$HOME/PlanktoScope/software/node-red-dashboard/default-configs/$default_conf "$HOME"/PlanktoScope/config.json # Configure node-red -npm --prefix "$HOME"/PlanktoScope/software/node-red-dashboard install -npm --prefix "$HOME"/PlanktoScope/software/node-red-dashboard/$hardware_type install +npm --prefix "$HOME/PlanktoScope/software/node-red-dashboard/adafruithat" install +npm --prefix "$HOME/PlanktoScope/software/node-red-dashboard/planktoscopehat" install diff --git a/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller-planktoscopehat.service b/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller-planktoscopehat.service deleted file mode 100644 index d271e77b4..000000000 --- a/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller-planktoscopehat.service +++ /dev/null @@ -1,18 +0,0 @@ -[Unit] -Description=Run the PlanktoScope hardware controller for the PlanktoScope HAT -# Wait for Forklift to bring up mosquitto, in case the controller needs to start after mosquitto -Wants=forklift-apply.service -After=forklift-apply.service -# Start after Node-RED so that Node-RED can catch all MQTT messages emitted at startup -After=nodered.service - -[Service] -Type=simple -Environment=HOME=/home/pi -WorkingDirectory=/home/pi/PlanktoScope/device-backend/control -ExecStart=/home/pi/.local/bin/poetry run python -u planktoscopehat/main.py -User=pi -Group=pi - -[Install] -WantedBy=multi-user.target diff --git a/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller-adafruithat.service b/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller.service similarity index 75% rename from software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller-adafruithat.service rename to software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller.service index ce32e4a51..d49cc1d88 100644 --- a/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller-adafruithat.service +++ b/software/distro/setup/planktoscope-app-env/python-hardware-controller/etc/systemd/system/planktoscope-org.device-backend.controller.service @@ -1,5 +1,5 @@ [Unit] -Description=Run the PlanktoScope hardware controller for the Adafruit HAT +Description=Run the PlanktoScope hardware controller # Wait for Forklift to bring up mosquitto, in case the controller needs to start after mosquitto Wants=forklift-apply.service After=forklift-apply.service @@ -10,7 +10,7 @@ After=nodered.service Type=simple Environment=HOME=/home/pi WorkingDirectory=/home/pi/PlanktoScope/device-backend/control -ExecStart=/home/pi/.local/bin/poetry run python -u adafruithat/main.py +ExecStart=/home/pi/.local/bin/poetry run python -u main.py User=pi Group=pi diff --git a/software/distro/setup/planktoscope-app-env/python-hardware-controller/install.sh b/software/distro/setup/planktoscope-app-env/python-hardware-controller/install.sh index f838dcef3..96c99a281 100755 --- a/software/distro/setup/planktoscope-app-env/python-hardware-controller/install.sh +++ b/software/distro/setup/planktoscope-app-env/python-hardware-controller/install.sh @@ -34,14 +34,11 @@ sudo -E apt-get install -y --no-install-recommends -o Dpkg::Progress-Fancy=0 \ i2c-tools libopenjp2-7 python3-picamera2 poetry --directory "$HOME/PlanktoScope/device-backend/control" install \ --no-root --compile -file="/etc/systemd/system/planktoscope-org.device-backend.controller-adafruithat.service" -sudo cp "$config_files_root$file" "$file" -# or for the PlanktoScope HAT -file="/etc/systemd/system/planktoscope-org.device-backend.controller-planktoscopehat.service" +file="/etc/systemd/system/planktoscope-org.device-backend.controller.service" sudo cp "$config_files_root$file" "$file" +sudo systemctl enable "planktoscope-org.device-backend.controller.service" # Select the enabled hardware controller mkdir -p "$HOME/PlanktoScope" -sudo systemctl enable "planktoscope-org.device-backend.controller-$hardware_type.service" cp "$HOME/PlanktoScope/device-backend/default-configs/$default_config.hardware.json" \ "$HOME/PlanktoScope/hardware.json" diff --git a/software/distro/setup/planktoscope-app-env/setup.sh b/software/distro/setup/planktoscope-app-env/setup.sh index 5b0b748ae..c70f927bb 100755 --- a/software/distro/setup/planktoscope-app-env/setup.sh +++ b/software/distro/setup/planktoscope-app-env/setup.sh @@ -11,7 +11,7 @@ build_scripts_root=$(dirname "$(realpath "$BASH_SOURCE")") # Get command-line args -hardware_type="$1" # should be either adafruithat, planktoscopehat, fairscope-latest, or segmenter-only +hardware_type="$1" # should be either adafruithat, planktoscopehat, fairscope-latest # Set up pretty error printing @@ -53,11 +53,6 @@ else panic "$description" fi -if [ "$hardware_type" = "segmenter-only" ]; then - echo "Warning: skipping PlanktoScope hardware-specific setup because hardware type was specified as: $hardware_type" - exit 0 -fi - description="set up Python hardware controller" report_starting "$description" if "$build_scripts_root/python-hardware-controller/install.sh" "$hardware_type"; then diff --git a/software/distro/setup/setup.sh b/software/distro/setup/setup.sh index c4ba79d97..7303c4931 100755 --- a/software/distro/setup/setup.sh +++ b/software/distro/setup/setup.sh @@ -11,7 +11,7 @@ setup_scripts_root=$(dirname "$(realpath "$BASH_SOURCE")") # Get command-line args -hardware_type="$1" # should be either none, adafruithat, planktoscopehat, fairscope-latest, or segmenter-only +hardware_type="$1" # should be either none, adafruithat, planktoscopehat, or fairscope-latest # Set up pretty error printing diff --git a/software/node-red-dashboard/adafruithat/flows.json b/software/node-red-dashboard/adafruithat/flows.json index 96d774c43..8e03caceb 100644 --- a/software/node-red-dashboard/adafruithat/flows.json +++ b/software/node-red-dashboard/adafruithat/flows.json @@ -7118,7 +7118,7 @@ "id": "bd5cceef.b17ad", "type": "exec", "z": "9daf9e2b.019fc", - "command": "sudo systemctl restart planktoscope-org.device-backend.controller-adafruithat.service", + "command": "sudo systemctl restart planktoscope-org.device-backend.controller.service", "addpay": false, "append": "", "useSpawn": "false", @@ -9096,4 +9096,4 @@ ] ] } -] \ No newline at end of file +] diff --git a/software/node-red-dashboard/package-lock.json b/software/node-red-dashboard/package-lock.json deleted file mode 100644 index e33bc6c7a..000000000 --- a/software/node-red-dashboard/package-lock.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "node-red-dashboard", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "node-red-dashboard", - "dependencies": { - "js-yaml": "^4.1.0" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - } - } -} diff --git a/software/node-red-dashboard/package.json b/software/node-red-dashboard/package.json deleted file mode 100644 index eb37479cb..000000000 --- a/software/node-red-dashboard/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "node-red-dashboard", - "private": true, - "dependencies": { - "js-yaml": "^4.1.0" - } -} diff --git a/software/node-red-dashboard/planktoscopehat/flows.json b/software/node-red-dashboard/planktoscopehat/flows.json index 604a62787..d0671342e 100644 --- a/software/node-red-dashboard/planktoscopehat/flows.json +++ b/software/node-red-dashboard/planktoscopehat/flows.json @@ -7084,7 +7084,7 @@ "id": "c54d948575dbcff8", "type": "exec", "z": "9daf9e2b.019fc", - "command": "sudo systemctl restart planktoscope-org.device-backend.controller-planktoscopehat.service", + "command": "sudo systemctl restart planktoscope-org.device-backend.controller.service", "addpay": false, "append": "", "useSpawn": "false", @@ -8746,4 +8746,4 @@ "y": 120, "wires": [] } -] \ No newline at end of file +] diff --git a/software/node-red-dashboard/settings.js b/software/node-red-dashboard/settings.js index f613732a8..250a2dc98 100644 --- a/software/node-red-dashboard/settings.js +++ b/software/node-red-dashboard/settings.js @@ -1,13 +1,48 @@ // https://nodered.org/docs/user-guide/runtime/configuration -const yaml = require("js-yaml"); const fs = require("fs"); const path = require("path"); -const doc = yaml.load( - fs.readFileSync("/usr/share/planktoscope/installer-config.yml", "utf8"), -); -const userDir = path.join(__dirname, doc.hardware); +// This is a special case for legacy hardware; new hardware designs should all be part of the +// planktoscopehat codebase: +const CONFIG_PATH = "/home/pi/PlanktoScope/config.json"; +function load_variant_setting(config_path = CONFIG_PATH) { + let config = {}; + try { + const file = fs.readFileSync(config_path, "utf8"); + try { + config = JSON.parse(file); + } catch (e) { + console.error(`Couldn't parse ${config_path} as JSON file`); + return undefined; + } + } catch (e) { + console.error(`Couldn't open ${config_path}`); + return undefined; + } + + if (config.acq_instrument === undefined) { + console.error(`${config_path} lacks a 'acq_instrument' field`); + return undefined; + } + + if (config.acq_instrument === "PlanktoScope v2.1") { + return "adafruithat"; + } + return "planktoscopehat"; +} + + +console.log("Determining configured hardware variant..."); +let variant = load_variant_setting(); +if (variant === undefined) { + variant = "planktoscopehat"; + console.warn( + `Couldn't load hardware variant setting from config, defaulting to ${variant}`, + ); +} +console.log(`Hardware variant: ${variant}`); +const userDir = path.join(__dirname, variant); module.exports = { /*******************************************************************************