This commit is contained in:
DasMoorhuhn 2024-06-27 04:02:36 +02:00
parent 9581a3ce2c
commit 345666cb2e
11 changed files with 213 additions and 29 deletions

View File

@ -1,9 +1,9 @@
FROM python:3.12-alpine3.20 AS build_bluepy
RUN apk add \
bluez \
make \
git \glib-dev \
git \
glib-dev \
gcc \
build-base \
freetype-dev \
@ -16,20 +16,22 @@ RUN git clone https://github.com/IanHarvey/bluepy.git && \
python3.12 setup.py install
FROM python:3.12-alpine3.20
WORKDIR = /src
COPY python/src/ .
COPY python/requierements.txt .
COPY python/docker_entrypoint.sh /
WORKDIR /src
COPY ./python/src/ .
COPY ./python/requierements.txt .
COPY ./python/docker_entrypoint.sh /
RUN mkdir data
VOLUME data
RUN touch DOCKER
VOLUME /src/data
RUN apk add sudo bluez
RUN apk add --no-cache sudo bluez tzdata
ENV TZ=Europe/Berlin
# 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
ENTRYPOINT sh /docker_entrypoint.sh

View File

@ -3,5 +3,5 @@ version: '3'
services:
atc_mithermometer_gateway:
image: dasmoorhuhn/atc-mithermometer-gateway:develop-alpine
container_name: ATC_MiThermometer_Gateway
container_name: ATC_MiThermometer_Gateway_Build
build: .

View File

@ -1,8 +1,4 @@
#!/bin/bash
#!/bin/sh
# service dbus start
# bluetoothd &
/bin/sh
sudo python3 main.py
python3.12 api_endpoints.py &
sudo python3.12 main.py

View File

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

View File

@ -0,0 +1,39 @@
import os
from flask import Flask
from flask import jsonify
from flask import send_from_directory
from flask_cors import CORS
from flask_cors import cross_origin
class API:
"""
API endpoints
"""
def __init__(self):
self.app = Flask(import_name='backend', static_folder='/data', static_url_path='')
CORS(self.app)
self.app.config['CORS_HEADERS'] = 'Content-Type'
# --------Static Routes-------
@self.app.route('/charts')
@cross_origin()
def serve_index():
return send_from_directory('/src', 'chart.html')
@self.app.route('/json')
@cross_origin()
def serve_get_list_of_json():
workdir, filename = os.path.split(os.path.abspath(__file__))
return jsonify(os.listdir(f'{workdir}/data'))
@self.app.route('/json/<path:path>')
@cross_origin()
def serve_json(path):
workdir, filename = os.path.split(os.path.abspath(__file__))
return send_from_directory(f'{workdir}/data', path)
api = API()
api.app.run(host='0.0.0.0', port=8000)

128
python/src/chart.html Normal file
View File

@ -0,0 +1,128 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Messdaten Charts</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.chartContainer {
width: 100%;
max-width: 800px;
height: 500px;
margin-bottom: 40px;
}
canvas {
width: 100% !important;
height: 100% !important;
}
</style>
</head>
<body>
<h1>Messdaten Charts</h1>
<div id="charts"></div>
<script>
async function fetchJSONFiles() {
try {
const response = await fetch('http://localhost:8000/json');
const jsonFiles = await response.json();
return jsonFiles;
} catch (error) {
console.error('Fehler beim Abrufen der JSON-Dateien:', error);
return [];
}
}
async function fetchData(filename) {
try {
const response = await fetch(`http://localhost:8000/json/${filename}`);
const data = await response.json();
return data;
} catch (error) {
console.error(`Fehler beim Abrufen der Datei ${filename}:`, error);
return [];
}
}
function parseChartData(data) {
const timestamps = data.map(entry => new Date(entry.timestamp));
const temperatures = data.map(entry => entry.temperature);
const humidity = data.map(entry => entry.humidity);
const name = data.length > 0 ? data[0].name : 'Unbekannt';
const room = data.length > 0 ? data[0].room : 'Unbekannt';
return { timestamps, temperatures, humidity, name, room };
}
async function renderCharts() {
const jsonFiles = await fetchJSONFiles();
const chartsContainer = document.getElementById('charts');
for (const file of jsonFiles) {
const data = await fetchData(file);
const { timestamps, temperatures, humidity, name, room } = parseChartData(data);
const chartContainer = document.createElement('div');
chartContainer.className = 'chartContainer';
chartContainer.innerHTML = `<h2>Gerät: ${name}, Raum: ${room}</h2><canvas></canvas>`;
chartsContainer.appendChild(chartContainer);
const ctx = chartContainer.querySelector('canvas').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: timestamps,
datasets: [
{
label: 'Temperatur (°C)',
data: temperatures,
borderColor: 'rgba(255, 99, 132, 1)',
backgroundColor: 'rgba(255, 99, 132, 0.2)',
fill: false,
},
{
label: 'Luftfeuchtigkeit (%)',
data: humidity,
borderColor: 'rgba(54, 162, 235, 1)',
backgroundColor: 'rgba(54, 162, 235, 0.2)',
fill: false,
}
]
},
options: {
maintainAspectRatio: false,
scales: {
x: {
type: 'time',
time: {
unit: 'minute'
}
},
y: {
beginAtZero: true
}
},
plugins: {
title: {
display: true,
text: `Gerät: ${name}, Raum: ${room}`
}
}
}
});
}
}
renderCharts();
</script>
</body>
</html>

View File

@ -1,17 +1,19 @@
import os
import sys
import json
from data_class import Data
from devices import Device
workdir, filename = os.path.split(os.path.abspath(__file__))
def log_to_json(devices):
workdir, filename = os.path.split(os.path.abspath(__file__))
for device in devices:
dev, data_obj, from_config = device
data_obj: Data
from_config: Device
file_name = f'{workdir}{os.sep}data{os.sep}{str(data_obj.mac).replace(":", "-")}.json'
file_name = f'{workdir}/data/{str(data_obj.mac).replace(":", "-")}.json'
print(file_name)
try:
with open(file_name, 'r') as file: data = json.load(file)

View File

@ -1,9 +1,10 @@
from time import sleep
from log_data import log_to_json
from discovery import start_discovery
def start_loop(interval=60):
while True:
start_discovery()
devices = start_discovery()
log_to_json(devices)
sleep(interval)

View File

@ -1,7 +1,9 @@
from discovery import start_discovery
from loop import start_loop
from log_data import log_to_json
from loop import start_loop
devices = start_discovery()
log_to_json(devices)
# devices = start_discovery()
# log_to_json(devices)
start_loop()

View File

@ -1,12 +1,21 @@
TAG=develop-alpine
CONTAINER=dasmoorhuhn/atc-mithermometer-gateway:$TAG
sudo killall -9 bluetoothd
docker stop $CONTAINER > /dev/null 2>&1
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
$CONTAINER \
docker container rm ATC_MiThermometer_Gateway > /dev/null 2>&1

3
stop_docker.sh Normal file
View File

@ -0,0 +1,3 @@
echo Stopping container gracefully...
docker stop ATC_MiThermometer_Gateway
echo Done