Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,35 @@
version: 2
updates:
# Maintain dependencies for the documentation system
- package-ecosystem: "pip"
directory: "/documentation"
- package-ecosystem: 'pip'
directory: '/documentation'
schedule:
interval: "monthly"
interval: 'monthly'

- package-ecosystem: 'pip'
directory: '/controller'
schedule:
interval: 'monthly'

- package-ecosystem: 'pip'
directory: '/segmenter'
schedule:
interval: 'monthly'

- package-ecosystem: 'npm'
directory: '/node-red'
schedule:
interval: 'monthly'

# Maintain dependencies for the Docker container to serve the documentation
- package-ecosystem: "docker"
- package-ecosystem: 'docker'
# Look for a Dockerfile in the `documentation` diectory
directory: "/documentation"
directory: '/documentation'
schedule:
interval: "monthly"
interval: 'monthly'

# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: "monthly"
interval: 'monthly'
27 changes: 26 additions & 1 deletion .github/workflows/build-segmenter.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build Docker container image for the segmenter
name: Build the segmenter

on:
push:
Expand Down Expand Up @@ -32,6 +32,31 @@ env:
PUSH_IMAGE: ${{ (github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork) || github.event_name == 'push' || github.event_name == 'push tag' }}

jobs:
ci-checks:
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4

- name: Install poetry
run: pipx install poetry==2.1.2

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'poetry'
cache-dependency-path: |
segmenter/poetry.lock

- name: Install build dependencies
working-directory: ./segmenter
run: |
poetry install --with dev

- name: Run checks
working-directory: ./segmenter
run: poetry run poe check

Comment thread
ethanjli marked this conversation as resolved.
build-container-image:
permissions:
contents: read
Expand Down
19 changes: 2 additions & 17 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,27 +1,12 @@
# General
# macOS
.DS_Store
*.dll
*.log
*.so
*.swp
export
img
tmp

# Python
/*.py[cod]
/__pycache__
/.benchmark
/.coverage*
/.pytest_cache
__pycache__

# npm
node_modules

# Node-Red
/.main.json.backup
/flow_backup.json

# PlanktoScope config files
hardware.json
config.json
3 changes: 2 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"esbenp.prettier-vscode",
"charliermarsh.ruff",
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint"
"dbaeumer.vscode-eslint",
"ms-python.mypy-type-checker"

],
// List of extensions recommended by VSCodium that should not be recommended for users of this workspace.
Expand Down
13 changes: 8 additions & 5 deletions controller/adafruithat/planktoscope/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
# We can use collections.deque https://docs.python.org/3/library/collections.html#collections.deque
import paho.mqtt.client as mqtt
import json
from os import getenv

# Logger library compatible with multiprocessing
from loguru import logger
Expand All @@ -84,7 +85,9 @@ class MQTT_Client:
when creating this object
"""

def __init__(self, topic, server="127.0.0.1", port=1883, name="client"):
def __init__(
self, topic, hostname=getenv("MQTT_HOSTNAME", "localhost"), port=1883, name="client"
):
# Declare the global variables command and args
self.command = ""
self.args = ""
Expand All @@ -95,17 +98,17 @@ def __init__(self, topic, server="127.0.0.1", port=1883, name="client"):
self.client = mqtt.Client()
# self.client.enable_logger(logger)
self.topic = topic
self.server = server
self.hostname = hostname
self.port = port
self.name = name
self.connect()

@logger.catch
def connect(self):
logger.info(f"trying to connect to {self.server}:{self.port}")
logger.info(f"trying to connect to {self.hostname}:{self.port}")
# TODO #104 add try: except ConnectionRefusedError: block here
# This is a symptom that Mosquitto may have failed to start
self.client.connect(self.server, self.port, 60)
self.client.connect(self.hostname, self.port, 60)
self.client.on_connect = self.on_connect
self.client.on_subscribe = self.on_subscribe
self.client.on_message = self.on_message
Expand All @@ -128,7 +131,7 @@ def on_connect(self, client, userdata, flags, rc):
"5: Connection refused - not authorised",
]
# Print when connected
logger.success(f"{self.name} connected to {self.server}:{self.port}! - {reason[rc]}")
logger.success(f"{self.name} connected to {self.hostname}:{self.port}! - {reason[rc]}")
# When connected, run subscribe()
self.client.subscribe(self.topic)

Expand Down
13 changes: 8 additions & 5 deletions controller/planktoscopehat/planktoscope/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
# We can use collections.deque https://docs.python.org/3/library/collections.html#collections.deque
import paho.mqtt.client as mqtt
import json
from os import getenv

# Logger library compatible with multiprocessing
from loguru import logger
Expand All @@ -67,7 +68,9 @@ class MQTT_Client:
when creating this object
"""

def __init__(self, topic, server="127.0.0.1", port=1883, name="client"):
def __init__(
self, topic, hostname=getenv("MQTT_HOSTNAME", "localhost"), port=1883, name="client"
):
# Declare the global variables command and args
self.args = ""
self.__new_message = False
Expand All @@ -77,17 +80,17 @@ def __init__(self, topic, server="127.0.0.1", port=1883, name="client"):
self.client = mqtt.Client()
# self.client.enable_logger(logger)
self.topic = topic
self.server = server
self.hostname = hostname
self.port = port
self.name = name
self.connect()

@logger.catch
def connect(self):
logger.info(f"trying to connect to {self.server}:{self.port}")
logger.info(f"trying to connect to {self.hostname}:{self.port}")
# TODO #104 add try: except ConnectionRefusedError: block here
# This is a symptom that Mosquitto may have failed to start
self.client.connect(self.server, self.port, 60)
self.client.connect(self.hostname, self.port, 60)
self.client.on_connect = self.on_connect
self.client.on_subscribe = self.on_subscribe
self.client.on_message = self.on_message
Expand All @@ -110,7 +113,7 @@ def on_connect(self, client, userdata, flags, rc):
"5: Connection refused - not authorised",
]
# Print when connected
logger.success(f"{self.name} connected to {self.server}:{self.port}! - {reason[rc]}")
logger.success(f"{self.name} connected to {self.hostname}:{self.port}! - {reason[rc]}")
# When connected, run subscribe()
self.client.subscribe(self.topic)

Expand Down
4 changes: 3 additions & 1 deletion segmenter/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM docker.io/library/python:3.9.18-slim-bullseye
FROM docker.io/library/python:3.11-slim-bookworm

# Install OS dependencies

Expand All @@ -16,6 +16,8 @@ USER pi:pi
RUN mkdir -p /home/pi/PlanktoScope/segmenter
WORKDIR /home/pi/PlanktoScope/segmenter

ENV MQTT_HOSTNAME=host.docker.internal

# Install Python dependencies

# Note: cmake is needed to install ninja which is needed to install pyproject.toml-based projects.
Expand Down
31 changes: 30 additions & 1 deletion segmenter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,36 @@ Currently, the simplest way to deploy the segmenter on any computer is using the

### Development

TBD
Install all dependencies including development tooling:

```sh
poetry install --with dev
```

Start controller for development:

```sh
docker ps
# copy the container id of the segmenter
docker stop <container-id>

poetry run python -u main.py
# make changes and restart
```

Run the code auto-formatter on the project:

```sh
poetry run poe fmt
```

Run all checks (including code formatting and linting):

```sh
poetry run poe check
```

We recommand using [https://code.visualstudio.com/docs/remote/ssh](https://code.visualstudio.com/docs/remote/ssh)

### Prerequisites

Expand Down
10 changes: 3 additions & 7 deletions segmenter/apt-packages
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
# numpy/scipy dependencies
libopenblas0
libatlas3-base
Comment thread
sonnyp marked this conversation as resolved.
libatomic1

# opencv dependencies
libhdf5-103-1
Comment thread
sonnyp marked this conversation as resolved.
libopenjp2-7
libopenexr25
Comment thread
sonnyp marked this conversation as resolved.
libavcodec58
libavformat58
libswscale5
libavcodec59
libavformat59
libswscale6
8 changes: 2 additions & 6 deletions segmenter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ def handler_stop_signals(signum, _):

if __name__ == "__main__":
logger.info("Welcome!")
logger.info(
"Initialising signals handling and sanitizing the directories (step 1/2)"
)
logger.info("Initialising signals handling and sanitizing the directories (step 1/2)")
signal.signal(signal.SIGINT, handler_stop_signals)
signal.signal(signal.SIGTERM, handler_stop_signals)

Expand All @@ -82,9 +80,7 @@ def handler_stop_signals(signum, _):
# Starts the segmenter process
logger.info("Starting the segmenter control process (step 2/2)")
try:
segmenter_thread = planktoscope.segmenter.SegmenterProcess(
shutdown_event, "/home/pi/data"
)
segmenter_thread = planktoscope.segmenter.SegmenterProcess(shutdown_event, "/home/pi/data")
except Exception:
logger.error("The segmenter control process could not be started")
segmenter_thread = None
Expand Down
8 changes: 4 additions & 4 deletions segmenter/planktoscope/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Copyright (C) 2021 Romain Bazile
#
#
# This file is part of the PlanktoScope software.
#
#
# PlanktoScope is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# PlanktoScope is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with PlanktoScope. If not, see <http://www.gnu.org/licenses/>.

5 changes: 3 additions & 2 deletions segmenter/planktoscope/identity.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# TODO: keep this as the default path, but allow changing it with an environment variable
MACHINE_NAME_PATH = '/run/machine-name'
MACHINE_NAME_PATH = "/run/machine-name"


def load_machine_name(path=MACHINE_NAME_PATH):
"""Returns the machine name specified by the file at MACHINE_NAMEPATH.

Returns:
str: the machine name stored in the file at the path.
"""
with open(path, encoding='utf-8') as file:
with open(path, encoding="utf-8") as file:
return file.readline().strip()
Loading