Skip to content
Open
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
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
.git
.gitignore
.gitmodules
.dockerignore
Dockerfile
.env
.env.example
.vscode
wxenv
logs/
cache/
__pycache__/
*.pyc
audio_generator/
scripts/
README.md
LICENSE
setup.sh
run-docker.sh
sr0wx.wav
requirements-rpi.txt
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ audio_generator/mp3
sr0wx.wav
wxenv

logs/*.log
logs/*
!logs/.keep
47 changes: 29 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
# Dockerfile for SR0WX
FROM debian:12

RUN apt-get update && apt-get upgrade
RUN apt-get install -y python3 python3-pip python3-venv pulseaudio git
# UID/GID of the host user, so that the mounted logs directory and the
# PulseAudio socket stay writable from inside the container
ARG UID=1000
ARG GID=1000

RUN useradd --create-home --shell /bin/bash -G audio sr0wx
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv pulseaudio \
&& rm -rf /var/lib/apt/lists/*

USER sr0wx

WORKDIR /home/sr0wx

RUN mkdir ./sr0wx
RUN mkdir ./sr0wx/logs
RUN groupadd -g ${GID} sr0wx \
&& useradd --create-home --shell /bin/bash -u ${UID} -g ${GID} -G audio,dialout sr0wx

USER sr0wx
WORKDIR /home/sr0wx/sr0wx

COPY requirements.txt ./
COPY sr0wx.py config.py .env colorcodes.py sr0wx_module.py ./
COPY modules/ ./modules/
COPY pl_google/ ./pl_google/
COPY pyliczba/ ./pyliczba/
COPY .git/ ./.git/
RUN mkdir -p logs cache

# requirements first, so that a code change does not invalidate the
# (slow) dependency layer
COPY --chown=sr0wx:sr0wx requirements.txt ./
RUN python3 -m venv wxenv \
&& ./wxenv/bin/pip install --no-cache-dir --upgrade pip \
&& ./wxenv/bin/pip install --no-cache-dir -r requirements.txt

RUN python3 -m venv wxenv
COPY --chown=sr0wx:sr0wx sr0wx.py config.py colorcodes.py sr0wx_module.py ./
COPY --chown=sr0wx:sr0wx modules/ ./modules/
COPY --chown=sr0wx:sr0wx pl_google/ ./pl_google/
COPY --chown=sr0wx:sr0wx pyliczba/ ./pyliczba/

RUN . ./wxenv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt
# .env is deliberately not copied -- image layers are readable by anyone who
# can pull the image. Pass the secrets at runtime with `docker run --env-file`.
# .git is not copied either, so the update check in sr0wx.py will log a single
# error and carry on; set check_for_updates = False in config.py to silence it.

CMD ["./wxenv/bin/python3", "sr0wx.py"]
ENTRYPOINT ["./wxenv/bin/python3", "sr0wx.py"]
CMD []
52 changes: 32 additions & 20 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import os
import logging
import logging.handlers
from datetime import datetime

from colorcodes import *

Expand All @@ -21,6 +20,9 @@ def my_import(name):
return mod


# katalog na logi, na świeżym klonie repo go nie ma
os.makedirs("logs", exist_ok=True)

# logger
dict_log_config = {
"version": 1,
Expand Down Expand Up @@ -49,35 +51,45 @@ def my_import(name):
"formatter": "colored_console",
"stream": "ext://sys.stdout",
},
# stała nazwa pliku, rotacja o północy, 30 dni historii. Znacznik
# czasu w nazwie dawał nowy plik przy każdym uruchomieniu, więc
# rotacja nigdy się nie odpalała i pliki narastały bez końca.
"file": {
"level": "INFO",
"class": "logging.handlers.RotatingFileHandler",
"class": "logging.handlers.TimedRotatingFileHandler",
"formatter": "format_for_file",
"filename": "logs/"
+ str(datetime.now().strftime("%Y-%m-%d_%H:%M"))
+ ".log",
"maxBytes": 500000,
"filename": "logs/sr0wx.log",
"when": "midnight",
"backupCount": 30,
"encoding": "utf-8",
},
},
}

# dane z pliku .env
# dane z pliku .env, a przy uruchomieniu w kontenerze prosto ze środowiska
# (docker run --env-file), dlatego brak pliku nie jest błędem
if os.path.exists(".env"):
load_dotenv()
airly_key = os.getenv("AIRLY_KEY")
openweather_key = os.getenv("OPENWEATHER_KEY")
meteostation_ip = os.getenv("METEOSTATION_IP").split(",")
LATITUDE = float(os.getenv("LATITUDE"))
LONGITUDE = float(os.getenv("LONGITUDE"))
MAP_CALL = os.getenv("MAP_CALL")
MAP_INFO = os.getenv("MAP_INFO")
HEALTHCHECK_UUID = os.getenv("HEALTHCHECK_UUID")
APRS_CALL = os.getenv("APRS_CALL")
APRS_PASSWD = os.getenv("APRS_PASSWD")
APRS_COMMENT = os.getenv("APRS_COMMENT")
else:
raise FileNotFoundError("No .env file present.")

missing = [k for k in ("LATITUDE", "LONGITUDE") if not os.getenv(k)]
if missing:
raise RuntimeError(
"Brak wymaganej konfiguracji: "
+ ", ".join(missing)
+ ". Skopiuj .env.example do .env i uzupełnij, albo podaj wartości w zmiennych środowiskowych."
)

airly_key = os.getenv("AIRLY_KEY")
openweather_key = os.getenv("OPENWEATHER_KEY")
meteostation_ip = os.getenv("METEOSTATION_IP", "").split(",")
LATITUDE = float(os.getenv("LATITUDE"))
LONGITUDE = float(os.getenv("LONGITUDE"))
MAP_CALL = os.getenv("MAP_CALL")
MAP_INFO = os.getenv("MAP_INFO")
HEALTHCHECK_UUID = os.getenv("HEALTHCHECK_UUID")
APRS_CALL = os.getenv("APRS_CALL")
APRS_PASSWD = os.getenv("APRS_PASSWD")
APRS_COMMENT = os.getenv("APRS_COMMENT")

#####################

Expand Down
40 changes: 26 additions & 14 deletions config_baltyk.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import os
import logging
import logging.handlers
from datetime import datetime

from colorcodes import *

Expand All @@ -21,6 +20,10 @@ def my_import(name):
return mod


# katalog na logi, na świeżym klonie repo go nie ma
os.makedirs("logs", exist_ok=True)


# logger
dict_log_config = {
"version": 1,
Expand Down Expand Up @@ -49,29 +52,38 @@ def my_import(name):
"formatter": "colored_console",
"stream": "ext://sys.stdout",
},
# stała nazwa pliku, rotacja o północy, 30 dni historii. Znacznik
# czasu w nazwie dawał nowy plik przy każdym uruchomieniu, więc
# rotacja nigdy się nie odpalała i pliki narastały bez końca.
"file": {
"level": "INFO",
"class": "logging.handlers.RotatingFileHandler",
"class": "logging.handlers.TimedRotatingFileHandler",
"formatter": "format_for_file",
"filename": "logs/baltyk_"
+ str(datetime.now().strftime("%Y-%m-%d_%H:%M"))
+ ".log",
"maxBytes": 500000,
"filename": "logs/baltyk.log",
"when": "midnight",
"backupCount": 30,
"encoding": "utf-8",
},
},
}

# dane z pliku .env
# dane z pliku .env, a przy uruchomieniu w kontenerze prosto ze środowiska
# (docker run --env-file), dlatego brak pliku nie jest błędem
if os.path.exists(".env"):
load_dotenv()
LATITUDE = float(os.getenv("LATITUDE"))
LONGITUDE = float(os.getenv("LONGITUDE"))
MAP_INFO_BALTYK=os.getenv("MAP_INFO_BALTYK")
CALL = os.getenv("CALL")

else:
raise FileNotFoundError("No .env file present.")

missing = [k for k in ("LATITUDE", "LONGITUDE") if not os.getenv(k)]
if missing:
raise RuntimeError(
"Brak wymaganej konfiguracji: "
+ ", ".join(missing)
+ ". Skopiuj .env.example do .env i uzupełnij, albo podaj wartości w zmiennych środowiskowych."
)

LATITUDE = float(os.getenv("LATITUDE"))
LONGITUDE = float(os.getenv("LONGITUDE"))
MAP_INFO_BALTYK = os.getenv("MAP_INFO_BALTYK")
CALL = os.getenv("CALL")

#####################

Expand Down
Binary file modified pl_google/samples/I.ogg
Binary file not shown.
Binary file modified pl_google/samples/W.ogg
Binary file not shown.
Binary file modified pl_google/samples/Z.ogg
Binary file not shown.
70 changes: 64 additions & 6 deletions run-docker.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
docker build -t sr0wx:latest .
docker run -it \
-e PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native \
-v ${XDG_RUNTIME_DIR}/pulse/native:${XDG_RUNTIME_DIR}/pulse/native \
-v ~/.config/pulse/cookie:/root/.config/pulse/cookie \
sr0wx:latest
#!/bin/bash -e

# Build and run SR0WX in a container.
# Any arguments given here are passed straight to sr0wx.py, e.g.:
# ./run-docker.sh -t -m sun_rise_set

cd "$(dirname "$(realpath "$0")")"

if [ ! -f .env ]; then
echo "No .env file. Copy .env.example to .env and fill it in first." >&2
exit 1
fi

# pl_google needs the pyliczba submodule, an empty directory breaks the import
git submodule update --init --recursive

docker build \
--build-arg UID="$(id -u)" \
--build-arg GID="$(id -g)" \
-t sr0wx:latest .

mkdir -p logs

ARGS=(
--rm
--env-file .env
-v "$(pwd)/logs:/home/sr0wx/sr0wx/logs"
)

# interactive only when there is a terminal, so cron/systemd runs work too
if [ -t 0 ]; then
ARGS+=(-it)
fi

# audio via the host PulseAudio daemon
if [ -n "${XDG_RUNTIME_DIR}" ] && [ -S "${XDG_RUNTIME_DIR}/pulse/native" ]; then
ARGS+=(
-e "PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/native"
-v "${XDG_RUNTIME_DIR}/pulse/native:${XDG_RUNTIME_DIR}/pulse/native"
)
else
echo "Warning: no PulseAudio socket found, there will be no audio output." >&2
fi

# the cookie lives in the container user's home, not in /root
if [ -f "${HOME}/.config/pulse/cookie" ]; then
ARGS+=(-v "${HOME}/.config/pulse/cookie:/home/sr0wx/.config/pulse/cookie:ro")
fi

# PTT via Raspberry Pi GPIO
if [ -e /dev/gpiomem ]; then
ARGS+=(--device /dev/gpiomem)
fi

# PTT via serial, set SR0WX_SERIAL to the device path (e.g. /dev/ttyUSB0)
if [ -n "${SR0WX_SERIAL}" ]; then
if [ -e "${SR0WX_SERIAL}" ]; then
ARGS+=(--device "${SR0WX_SERIAL}")
else
echo "Warning: SR0WX_SERIAL=${SR0WX_SERIAL} does not exist, skipping." >&2
fi
fi

docker run "${ARGS[@]}" sr0wx:latest "$@"
22 changes: 19 additions & 3 deletions setup.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
#!/bin/bash -e

# Safe to re-run, e.g. after changing requirements.txt.
# Pass -r to install the Raspberry Pi requirements instead.

cd "$(dirname "$(realpath "$0")")"

REQUIREMENTS="requirements.txt"
if [ "$1" = "-r" ]; then
REQUIREMENTS="requirements-rpi.txt"
fi

# Init git submodules (pyliczba)
git submodule update --init --recursive

Expand All @@ -9,7 +19,13 @@ source wxenv/bin/activate

# Update and install requirements
pip install --upgrade pip
pip install -r requirements.txt
pip install -r "${REQUIREMENTS}"

# Initiate .env file
cp .env.example .env
# Initiate .env file, never overwrite the one already there -- it holds the
# API keys and the APRS passcode
if [ -f .env ]; then
echo ".env already exists, leaving it alone."
else
cp .env.example .env
echo "Created .env from .env.example, fill it in before running sr0wx.py."
fi
Loading