multiplatform build

This commit is contained in:
DasMoorhuhn 2024-06-29 03:32:54 +02:00
parent 345666cb2e
commit 5029e46359
11 changed files with 235 additions and 38 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@ __pycache__
devices.yml
history.*
data/
*.iso
*.cow

View File

@ -1,4 +1,7 @@
FROM python:3.12-alpine3.20 AS build_bluepy
# This is the build stage for getting all python libs. Mainly it's for reducing the final image size because for building and installing the pips, many tools are needed which are just bloat to the final image.
FROM python:3.12-alpine3.20 AS pip_build_stage
COPY ./python/requierements.txt /
RUN apk add \
make \
@ -8,17 +11,32 @@ RUN apk add \
build-base \
freetype-dev \
libpng-dev \
openblas-dev
openblas-dev \
libxml2-dev \
libxslt-dev
# BluePy needs to be build here... idk why but pip install fails on alpine somehow
RUN git clone https://github.com/IanHarvey/bluepy.git && \
cd bluepy && \
python3.12 setup.py build && \
python3.12 setup.py install
python3.12 setup.py install && \
cd /
# Normal pip install for pyyaml failed on RPI4, so I build it here
RUN git clone https://github.com/yaml/pyyaml.git && \
cd pyyaml && \
python3.12 setup.py build && \
python3.12 setup.py install && \
cd /
RUN pip3.12 install -r requierements.txt
# This is the stage for the final image
FROM python:3.12-alpine3.20
WORKDIR /src
COPY ./python/src/ .
COPY ./python/requierements.txt .
COPY ./python/docker_entrypoint.sh /
RUN mkdir data
RUN touch DOCKER
@ -26,12 +44,10 @@ VOLUME /src/data
RUN apk add --no-cache sudo bluez tzdata
ENV TZ=Europe/Berlin
ENV DOCKER=TRUE
# Copy bluepy from the bluepy build stage
COPY --from=build_bluepy /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=build_bluepy /usr/local/bin /usr/local/bin
RUN pip3.12 install -r requierements.txt && rm requierements.txt
# RUN echo '@reboot root python3.12 /src/serve_json.py' >> /etc/crontab
# Copy pips from the pip build stage
COPY --from=pip_build_stage /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=pip_build_stage /usr/local/bin /usr/local/bin
ENTRYPOINT sh /docker_entrypoint.sh

35
build_docker.sh Normal file
View File

@ -0,0 +1,35 @@
ARCH=linux/arm/v6
#ARCH=linux/amd64
TAG=develop
HELP="USAGE: sh build_docker.sh \n
[ -a | --architecture ] Select a architecture. Default is auto\n
[ -t | --tag ] Set a docker tag. Default is develop \n
[ -h | --help ] Get this dialog"
docker_build(){
docker build --build-arg TARGETPLATFORM=$ARCH --platform $ARCH --tag dasmoorhuhn/atc-mithermometer-gateway:$TAG .
}
while [ "$1" != "" ]; do
case $1 in
-a | --architecture )
shift
ARCH=$1
shift
;;
-t | --tag )
shift
TAG=$1
shift
;;
-h | --help )
echo $HELP
exit
;;
* )
echo $HELP
exit 1
esac
done
docker_build

View File

@ -0,0 +1,10 @@
TAG=develop
set e
docker buildx version
unset e
docker buildx create --name builder
docker buildx use builder
docker buildx build --tag dasmoorhuhn/atc-mithermometer-gateway:$TAG --platform=linux/amd64,linux/arm64,linux/arm --push .

View File

@ -1,4 +1,10 @@
#!/bin/sh
python3.12 api_endpoints.py &
env > .env
if [ "$API" = true ]; then
python3.12 api_endpoints.py &
sleep 1
fi
sudo python3.12 main.py

View File

@ -1,6 +1,5 @@
pyyaml
bs4
lxml
requests
flask
flask_cors

View File

@ -49,7 +49,7 @@ def cleanup():
devices = []
def start_discovery(timeout=20.0):
def start_discovery(timeout=20):
cleanup()
global devices
print(f'Start discovery with timout {timeout}s...')

16
python/src/load_env.py Normal file
View File

@ -0,0 +1,16 @@
# This is a quick and dirty hack since the ENVs from the docker run command won't show up in the main.py
# I echo the output from the env command of a .env file, read and load it here into the os.environ.
# https://stackoverflow.com/questions/78684481/python-wont-find-the-env-in-my-docker-container
import os
def load_env():
if 'DOCKER' not in os.listdir('.'): return False
with open(file='.env', mode='r') as file: ENV = file.readlines()
for env in ENV:
env = env.strip()
key, value = env.split('=')
os.environ[key] = value
return True

View File

@ -3,8 +3,9 @@ from log_data import log_to_json
from discovery import start_discovery
def start_loop(interval=60):
def start_loop(interval=40, timeout=20):
print(f"Starting loop with interval {interval}s")
while True:
devices = start_discovery()
devices = start_discovery(timeout=timeout)
log_to_json(devices)
sleep(interval)

View File

@ -1,9 +1,25 @@
import os
from discovery import start_discovery
from log_data import log_to_json
from loop import start_loop
from load_env import load_env
DOCKER = load_env()
INTERVAL = 40
TIMEOUT = 20
# devices = start_discovery()
# log_to_json(devices)
if DOCKER:
print("Running in docker")
interval = os.getenv('LOOP')
timeout = os.getenv('TIMEOUT')
start_loop()
try:INTERVAL = int(interval)
except:pass
try:TIMEOUT = int(timeout)
except:pass
start_loop(INTERVAL, TIMEOUT)
else:
start_loop(interval=40)

View File

@ -1,21 +1,117 @@
TAG=develop-alpine
TAG=develop
CONTAINER=dasmoorhuhn/atc-mithermometer-gateway:$TAG
CONTAINER_NAME=ATC_MiThermometer_Gateway
VOLUME=YOUR_VOLUME
sudo killall -9 bluetoothd > /dev/null 2>&1
# docker stop $CONTAINER > /dev/null 2>&1
sh stop_docker.sh
docker container rm ATC_MiThermometer_Gateway > /dev/null 2>&1
echo Start container...
docker run \
--cap-add=SYS_ADMIN \
--cap-add=NET_ADMIN \
--net=host \
--name=ATC_MiThermometer_Gateway \
--restart unless-stopped \
--tty \
-ti \
-v /var/run/dbus/:/var/run/dbus/ \
-v ./data:/src/data \
$CONTAINER \
D=""
TIME_ZONE="Europe/Berlin"
INTERACTIVE=false
BUILD=false
API=false
LOOP="0"
TIMEOUT="0"
HELP="USAGE: sh run_docker.sh [OPTIONS] \n
[ -d ] Run in Backgrund \n
[ -t | --tag ] Set a docker tag \n
[ -b | --build ] Build the image before running the container \n
[ -l | --loop ] Start the gateway in looping mode. e.g.: --loop 40 will set the interval of the loop to 40s. Default is single run mode \n
[ -a | --api ] Start with the API \n
[ -tz | --timezone ] Set the timezone. Default is Europe/Berlin \n
[ -to | --timeout ] Set the timeout for the bluetooth scan. default is 20s \n
[ -h | --help ] Get this dialog"
docker_run() {
sudo killall -9 bluetoothd > /dev/null 2>&1
echo Killing old container...
docker stop $CONTAINER_NAME
docker container rm $CONTAINER_NAME > /dev/null 2>&1
COMMAND="docker run $D"
COMMAND="$COMMAND --cap-add=SYS_ADMIN"
COMMAND="$COMMAND --cap-add=NET_ADMIN"
COMMAND="$COMMAND --net=host"
COMMAND="$COMMAND --env TZ=$TIME_ZONE"
COMMAND="$COMMAND --env API=$API"
COMMAND="$COMMAND --name=$CONTAINER_NAME"
COMMAND="$COMMAND --restart=on-failure"
COMMAND="$COMMAND --volume=/var/run/dbus/:/var/run/dbus/"
COMMAND="$COMMAND --volume=$VOLUME:/src/data"
if [ "$INTERACTIVE" = true ]; then
COMMAND="$COMMAND --interactive"
COMMAND="$COMMAND --tty"
COMMAND="$COMMAND --attach=stdout"
COMMAND="$COMMAND --attach=stdin"
fi
if [ "$LOOP" != "0" ]; then
COMMAND="$COMMAND --env LOOP=$LOOP"
fi
if [ "$TIMEOUT" != "0" ]; then
COMMAND="$COMMAND --env TIMEOUT=$TIMEOUT"
fi
if [ "$BUILD" = true ]; then
sh build_docker.sh --tag $TAG
fi
echo $COMMAND
echo Start container...
echo
$COMMAND $CONTAINER
docker container rm $CONTAINER_NAME > /dev/null 2>&1
}
while [ "$1" != "" ]; do
case $1 in
-d )
D="-d"
shift
;;
-a | --api)
API=true
shift
;;
-b | --build )
BUILD=true
shift
;;
-tz | --timezone )
shift
TIME_ZONE=$1
shift
;;
-to | --timeout )
shift
TIMEOUT=$1
shift
;;
-t | --tag )
shift
TAG=$1
shift
;;
-l | --loop )
shift
LOOP=$1
shift
;;
-i | --interactive )
INTERACTIVE=true
shift
;;
-h | --help )
echo $HELP
exit
;;
* )
echo $HELP
exit 1
esac
done
docker_run
docker container rm ATC_MiThermometer_Gateway > /dev/null 2>&1