Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix configuration file handling and service unit file creation, remove unnecessary files #1

Merged
merged 5 commits into from
Sep 12, 2024
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
4 changes: 4 additions & 0 deletions .fpm
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
--depends python3-tz
--python-disable-dependency pybase64
--depends python3-unpaddedbase64
--depends libcap-dev
--deb-systemd service/sentinel_mrhat_cam.service
--deb-systemd-enable
--deb-systemd-auto-start
6 changes: 5 additions & 1 deletion .github/workflows/documentation-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libcap-dev

# ADJUST THIS: install all dependencies (including pdoc)
- run: pip install -e .
- run: pip install .
- run: pip install pdoc
# ADJUST THIS: build your documentation into docs/.
# We use a custom build script for pdoc itself, ideally you just run `pdoc -o docs/ ...` here.
Expand Down
31 changes: 0 additions & 31 deletions .github/workflows/python_release.yml

This file was deleted.

65 changes: 65 additions & 0 deletions .github/workflows/test_and_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Test and Release

on:
push:
branches: main
tags: v*.*.*

pull_request:
branches: [ "main" ]
types:
- synchronize
- opened
- reopened

concurrency:
group: ${{ github.workflow }}-${{ github.sha }}
cancel-in-progress: true

jobs:
test:
name: Build and test

runs-on: ubuntu-latest

permissions:
# Gives the action the necessary permissions for publishing new
# comments in pull requests.
pull-requests: write
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libcap-dev
- name: Verify changes
uses: EffectiveRange/python-verify-github-action@v1
with:
coverage-threshold: '0'

release:
if: startsWith(github.ref, 'refs/tags/')
needs: test

name: Publish and release

runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
- name: Package and publish
uses: EffectiveRange/python-package-github-action@v2
with:
use-devcontainer: 'true'
container-config: 'amd64-container'
debian-dist-command: 'sudo apt-get install -y libcap-dev && pack_python . --all'
install-packaging-tools: 'false'
add-wheel-dist: 'false'
- name: Release
uses: EffectiveRange/version-release-github-action@v1
File renamed without changes.
File renamed without changes.
33 changes: 0 additions & 33 deletions scripts/daemon.sh

This file was deleted.

8 changes: 1 addition & 7 deletions scripts/sentinel_mrhat_cam.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
#!/bin/bash

# Set the working directory
cd /home/admin

# Ensure the correct Python environment is used
export PATH="/usr/local/bin:$PATH"

# Configuration
RESTART_COUNT_FILE="/tmp/restart_count"

Expand All @@ -21,7 +15,7 @@ while true; do
start_time=$(date +%s)
echo "Starting Python script at $(date)"
# Run the Python script
python3 -m sentinel_mrhat_cam.main
python3 /usr/local/bin/sentinel_mrhat_cam_main.py
EXIT_CODE=$?

end_time=$(date +%s)
Expand Down
46 changes: 43 additions & 3 deletions sentinel_mrhat_cam/main.py → scripts/sentinel_mrhat_cam_main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from .app import App
from .logger import Logger
from .static_config import LOG_CONFIG_PATH, CONFIG_PATH
#!/usr/bin/env python3

import shutil
from os import makedirs
from os.path import dirname, exists, isdir, join
from pathlib import Path

from sentinel_mrhat_cam.app import App
from sentinel_mrhat_cam.logger import Logger
from sentinel_mrhat_cam.static_config import LOG_CONFIG_PATH, CONFIG_PATH, CONFIG_DIR
import logging
import sys

Expand Down Expand Up @@ -34,6 +41,9 @@ def main():
It sets up all necessary components and manages the main execution flow.
"""

# Setting up the configuration directory and copying the default configuration files if necessary
_set_up_configuration()

# Configuring and starting the logging
logger = Logger(LOG_CONFIG_PATH)
logger.start_logging()
Expand Down Expand Up @@ -61,5 +71,35 @@ def main():
logger.disconnect_mqtt()


def _set_up_configuration():
"""
Set up the configuration directory and copy the default configuration files if necessary.

This function creates the configuration directory if it does not exist and copies the default
configuration files to the configuration directory if they do not exist. Will not overwrite existing files.

Notes
-----
This function is called before the main function to ensure that the configuration files are
available before the application starts.
"""

# Setting the default configuration path
default_config_dir = str(Path(dirname(__file__)).parent.absolute().joinpath('config'))

# Ensuring configuration directory exists
if not isdir(CONFIG_DIR):
makedirs(dirname(CONFIG_DIR), exist_ok=True)

# Copying the default configuration files to the config directory, if they do not exist
if not exists(LOG_CONFIG_PATH):
default_log_config = join(default_config_dir, 'log_config.yaml')
shutil.copy(default_log_config, LOG_CONFIG_PATH)

if not exists(CONFIG_PATH):
default_config = join(default_config_dir, 'config.json')
shutil.copy(default_config, CONFIG_PATH)


if __name__ == "__main__":
main()
1 change: 0 additions & 1 deletion sentinel_mrhat_cam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,3 @@
from .camera import *
from .transmit import *
from .app import *
from .main import *
Binary file not shown.
Binary file removed sentinel_mrhat_cam/__pycache__/app.cpython-311.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed sentinel_mrhat_cam/__pycache__/main.cpython-311.pyc
Binary file not shown.
Binary file removed sentinel_mrhat_cam/__pycache__/mqtt.cpython-311.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed sentinel_mrhat_cam/__pycache__/utils.cpython-311.pyc
Binary file not shown.
16 changes: 9 additions & 7 deletions sentinel_mrhat_cam/app_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging
import json
import re
from typing import Any

from .mqtt import MQTT
from .static_config import CONFIGACKTOPIC, MINIMUM_WAIT_TIME, MAXIMUM_WAIT_TIME

Expand Down Expand Up @@ -94,7 +96,7 @@ def load(self) -> None:
raise

@staticmethod
def get_default_config() -> dict:
def get_default_config() -> dict[str, Any]:
"""
Defines and returns a default configuration dictionary.

Expand All @@ -108,12 +110,12 @@ def get_default_config() -> dict:
"mode": "periodic",
"period": 15,
"wakeUpTime": "06:59:31",
"shutDownTime": "22:00:00"
"shutDownTime": "22:00:00",
}
return default_config

@staticmethod
def validate_config(new_config) -> None:
def validate_config(new_config: dict[str, Any]) -> None:
"""
Validates the new configuration dictionary against the default configuration
and checks if specific rules are fulfilled.
Expand All @@ -123,7 +125,7 @@ def validate_config(new_config) -> None:

Parameters
----------
new_config : any
new_config : dict
The configuration dictionary to be validated.

Raises
Expand Down Expand Up @@ -156,13 +158,13 @@ def validate_config(new_config) -> None:
Config.validate_time_format(new_config)

@staticmethod
def validate_period(period) -> None:
def validate_period(period: int) -> None:
"""
Validates the period value in the new configuration dictionary.

Parameters
----------
period : any
period : int
The time period to be validated.

Raises
Expand All @@ -181,7 +183,7 @@ def validate_period(period) -> None:
raise ValueError("Period specified in the config is more than the maximum allowed wait time.")

@staticmethod
def validate_time_format(new_config: dict) -> None:
def validate_time_format(new_config: dict[str, Any]) -> None:
"""
Validates the wake-up and shut-down time formats in the new configuration dictionary.

Expand Down
8 changes: 5 additions & 3 deletions sentinel_mrhat_cam/camera.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from typing import Optional, Any
from unittest.mock import MagicMock

try:
from libcamera import controls
from picamera2 import Picamera2
Expand Down Expand Up @@ -32,7 +34,7 @@ class Camera:
The height of the captured image based on the quality setting.
"""

def __init__(self, config):
def __init__(self, config: dict[str, str]) -> None:
"""
Initializes the Camera class with the given configuration.

Expand Down Expand Up @@ -84,7 +86,7 @@ def start(self) -> None:
self.cam.start(show_preview=False)

@log_execution_time("Image capture time:")
def capture(self) -> np.ndarray:
def capture(self) -> Optional[np.ndarray[bool, Any]]:
"""
Captures an image from the camera and returns it as numpy array.

Expand All @@ -94,7 +96,7 @@ def capture(self) -> np.ndarray:
The captured image as a numpy array.
"""
try:
image = self.cam.capture_array()
image: np.ndarray[bool, Any] = self.cam.capture_array()
except Exception as e:
logging.error(f"Error during image capture: {e}")
return None
Expand Down
12 changes: 7 additions & 5 deletions sentinel_mrhat_cam/logger.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import logging
import logging.config
from typing import Any

import yaml
import os
import threading
Expand Down Expand Up @@ -50,8 +52,8 @@ def __init__(self, filepath: str):
"""
super().__init__()
self.filepath = filepath
self.log_queue = Queue()
self.mqtt = None
self.log_queue: Queue[str] = Queue()
self.mqtt: Any = None
self.start_event = threading.Event()
self.pool = ThreadPool(processes=5)

Expand All @@ -77,7 +79,7 @@ def start_logging(self) -> None:
self.create_mqtt_handler()
logging.info("Logging started")

except Exception as e:
except Exception:
exit(1)

def create_mqtt_handler(self) -> None:
Expand All @@ -89,8 +91,7 @@ def create_mqtt_handler(self) -> None:
"""
self.setLevel(LOG_LEVEL)
formatter = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S'
)
self.setFormatter(formatter)
logging.getLogger().addHandler(self)
Expand All @@ -103,6 +104,7 @@ def start_mqtt_logging(self) -> None:
broker, and signals that MQTT logging has started.
"""
from .mqtt import MQTT

self.mqtt = MQTT()
self.mqtt.connect()
self.start_event.set()
Expand Down
Loading
Loading