Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
leventenyiri committed Sep 12, 2024
2 parents a5ad5e3 + d75bfa8 commit 6038152
Show file tree
Hide file tree
Showing 40 changed files with 355 additions and 185 deletions.
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
51 changes: 51 additions & 0 deletions .github/workflows/documentation-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Documentation release

# build the documentation whenever there are new commits on main
on:
push:
branches:
- '**'

# security: restrict permissions for CI jobs.
permissions:
contents: read

jobs:
# Build the documentation and upload the static HTML files as an artifact.
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- 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 .
- 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.
- run: pdoc --output-dir docs --docformat numpy sentinel_mrhat_cam

- uses: actions/upload-pages-artifact@v3
with:
path: docs/

# Deploy the artifact to GitHub pages.
# This is a separate job so that only actions/deploy-pages has the necessary permissions.
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
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.
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
2 changes: 1 addition & 1 deletion scripts/sentinel_mrhat_cam_daemon.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ sudo systemctl daemon-reload
# Optional: Start the service immediately
# sudo systemctl start sentinel_mrhat_cam.service

echo "Service has been created successfully, enable it and reboot the system for the changes to take effect."
echo "Service has been created successfully, enable it and reboot the system for the changes to take effect."
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
Loading

0 comments on commit 6038152

Please sign in to comment.