From 285a2503d71f0016255a106ead9a9a8dd5153fa2 Mon Sep 17 00:00:00 2001 From: DasMoorhuhn Date: Wed, 3 Jul 2024 00:27:48 +0200 Subject: [PATCH] fix up some mess --- .media/demo.gif | Bin 0 -> 44099 bytes Dockerfile | 4 +-- README.md | 15 +++++------ python/docker_entrypoint.sh | 6 ++--- python/requierements.txt | 1 + python/src/load_env.py | 16 ------------ python/src/log_data.py | 4 ++- python/src/main.py | 20 +++++++++++---- run_docker.sh | 48 ++++++++++++++++++++++++++---------- 9 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 .media/demo.gif delete mode 100644 python/src/load_env.py diff --git a/.media/demo.gif b/.media/demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..5a550bceef0427aa30020e83840a71ead8407a84 GIT binary patch literal 44099 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 ij{ki3-KSAR%J0F;nJ literal 0 HcmV?d00001 diff --git a/Dockerfile b/Dockerfile index 3fb8851..bf958e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,12 +39,12 @@ WORKDIR /src COPY ./python/src/ . COPY ./python/docker_entrypoint.sh / RUN mkdir data -RUN touch DOCKER VOLUME /src/data RUN apk add --no-cache sudo bluez tzdata ENV TZ=Europe/Berlin -ENV DOCKER=TRUE +ENV DOCKER=true +ENV API=false # 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 diff --git a/README.md b/README.md index 602cfbf..a5e2f66 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ * [ATC_MiThermometer_Gateway](#atc_mithermometer_gateway) + * [Roadmap](#roadmap) * [Getting started](#getting-started) * [Run Gateway](#run-gateway) * [Shell Scripts](#shell-scripts) @@ -14,15 +15,16 @@ Python gateway for the [custom firmware](https://github.com/atc1441/ATC_MiThermo ![](.media/41N1IH9jwoL._AC_SL1024_.jpg) -**Features:** -- WIP +## Roadmap + +**Done:** +- Make in runnable in a docker container (because only cool people are using docker) +- Make docker image smaller. I mean shiiit 1GB D: should be possible to be under 500MB (It's now around 100MB) +- Implement a loop for fetching the data every X seconds **TODOs:** - [WIP] Can run on Raspberry Pi (3, 4, zero w) or any other Linux driven hardware which has BLE and WiFi support - [WIP] Storing temperature, humidity and battery state as json in a text file -- [WIP] Implement a loop for fetching the data every x minute -- [WIP] Make discoveries async -- [WIP] Make docker image smaller. I mean shiiit 1GB D: should be possible to be under 500MB - [TODO] Make a microPython version for using the raspberry pico w or any other microcontroller with BLE and WiFi support - [TODO] Collect data from multiple devices/gateways - [TODO] Command line tool for managing the devices @@ -31,11 +33,10 @@ Python gateway for the [custom firmware](https://github.com/atc1441/ATC_MiThermo - [TODO] MQTT publishing - [TODO] Maybe... a webinterface. But I suck at web stuff, so I don't know. - [TODO] Implement other BLE Sensors -- [BROK] Make in runnable in a docker container (because only cool people are using docker) **Current State** -![](.media/demo_001.gif) +![](.media/demo.gif) ## Getting started diff --git a/python/docker_entrypoint.sh b/python/docker_entrypoint.sh index 9e4f582..aeb780b 100644 --- a/python/docker_entrypoint.sh +++ b/python/docker_entrypoint.sh @@ -3,8 +3,8 @@ env > .env if [ "$API" = true ]; then - python3.12 api_endpoints.py & - sleep 1 + python3.12 api_endpoints.py & + sleep 1 fi -sudo python3.12 main.py \ No newline at end of file +python3.12 main.py \ No newline at end of file diff --git a/python/requierements.txt b/python/requierements.txt index bfe7725..b7ed443 100644 --- a/python/requierements.txt +++ b/python/requierements.txt @@ -1,3 +1,4 @@ +bluepy pyyaml bs4 requests diff --git a/python/src/load_env.py b/python/src/load_env.py deleted file mode 100644 index 641c4fa..0000000 --- a/python/src/load_env.py +++ /dev/null @@ -1,16 +0,0 @@ -# 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 diff --git a/python/src/log_data.py b/python/src/log_data.py index 54d541a..a157481 100644 --- a/python/src/log_data.py +++ b/python/src/log_data.py @@ -4,6 +4,8 @@ import json from data_class import Data from devices import Device +DEBUG = True if os.getenv('DEBUG') == 'true' else False + def log_to_json(devices): workdir, filename = os.path.split(os.path.abspath(__file__)) @@ -13,7 +15,7 @@ def log_to_json(devices): data_obj: Data from_config: Device file_name = f'{workdir}/data/{str(data_obj.mac).replace(":", "-")}.json' - print(file_name) + print(file_name) if DEBUG else {} try: with open(file_name, 'r') as file: data = json.load(file) diff --git a/python/src/main.py b/python/src/main.py index 934f877..2fd502a 100644 --- a/python/src/main.py +++ b/python/src/main.py @@ -2,16 +2,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 +DOCKER = True if os.getenv('DOCKER') == 'true' else False +DEBUG = True if os.getenv('DEBUG') == 'true' else False +interval = os.getenv('LOOP') +timeout = os.getenv('TIMEOUT') + +if DEBUG: + print(f"INTERVAL: {INTERVAL}") + print(f"TIMEOUT: {TIMEOUT}") + print(f"interval: {interval}") + print(f"timeout: {timeout}") + print(f"DOCKER: {DOCKER}") + print(f"DEBUG: {DEBUG}") + print("") if DOCKER: print("Running in docker") - interval = os.getenv('LOOP') - timeout = os.getenv('TIMEOUT') try:INTERVAL = int(interval) except:pass @@ -19,7 +28,8 @@ if DOCKER: try:TIMEOUT = int(timeout) except:pass - start_loop(INTERVAL, TIMEOUT) + if interval is None: log_to_json(start_discovery(timeout=TIMEOUT)) + else:start_loop(INTERVAL, TIMEOUT) else: start_loop(interval=40) diff --git a/run_docker.sh b/run_docker.sh index c6e4b24..81ef62b 100644 --- a/run_docker.sh +++ b/run_docker.sh @@ -1,13 +1,14 @@ -TAG=develop -CONTAINER=dasmoorhuhn/atc-mithermometer-gateway:$TAG -CONTAINER_NAME=ATC_MiThermometer_Gateway +TAG="develop" +CONTAINER="dasmoorhuhn/atc-mithermometer-gateway" +CONTAINER_NAME="ATC_MiThermometer_Gateway" VOLUME=YOUR_VOLUME -D="" -TIME_ZONE="Europe/Berlin" +BACKGROUND="" +TIME_ZONE="" INTERACTIVE=false BUILD=false API=false +DEBUG=false LOOP="0" TIMEOUT="0" @@ -19,20 +20,19 @@ HELP="USAGE: sh run_docker.sh [OPTIONS] \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" +[ -h | --help ] Get this dialog \n +[ --debug ] Set into debug mode" docker_run() { sudo killall -9 bluetoothd > /dev/null 2>&1 echo Killing old container... - docker stop $CONTAINER_NAME + docker stop $CONTAINER_NAME > /dev/null 2>&1 docker container rm $CONTAINER_NAME > /dev/null 2>&1 - COMMAND="docker run $D" + COMMAND="docker run $BACKGROUND" 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/" @@ -57,10 +57,28 @@ docker_run() { sh build_docker.sh --tag $TAG fi - echo $COMMAND + if [ "$TIME_ZONE" != "" ]; then + COMMAND="$COMMAND --env TZ=$TIME_ZONE" + fi + + if [ "$API" != false ]; then + COMMAND="$COMMAND --env API=$API" + fi + + if [ "$DEBUG" = true ]; then + COMMAND="$COMMAND --env DEBUG=$DEBUG" + COMMAND="$COMMAND $CONTAINER:$TAG" + echo + echo $COMMAND + echo + echo DEBUG MODE + else + COMMAND="$COMMAND $CONTAINER:$TAG" + fi + echo Start container... echo - $COMMAND $CONTAINER + $COMMAND docker container rm $CONTAINER_NAME > /dev/null 2>&1 } @@ -68,7 +86,11 @@ docker_run() { while [ "$1" != "" ]; do case $1 in -d ) - D="-d" + BACKGROUND="-d" + shift + ;; + --debug ) + DEBUG=true shift ;; -a | --api)