added charts
This commit is contained in:
parent
961fba65be
commit
72762340ce
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
__pycache__
|
||||
devices.yml
|
||||
history.*
|
||||
194
Charts/data.json
Normal file
194
Charts/data.json
Normal file
@ -0,0 +1,194 @@
|
||||
[
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-22T23:59:06+02:00",
|
||||
"mac": "A4:C1:38:46:D7:75",
|
||||
"temperature": 20.4,
|
||||
"humidity": 69,
|
||||
"battery_percent": 87,
|
||||
"battery_volt": 2.985,
|
||||
"count": 241
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:46:D7:75",
|
||||
"name": "4",
|
||||
"room": "dinner_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-22T23:59:07+02:00",
|
||||
"mac": "A4:C1:38:DD:9F:EB",
|
||||
"temperature": 20.3,
|
||||
"humidity": 70,
|
||||
"battery_percent": 85,
|
||||
"battery_volt": 2.975,
|
||||
"count": 240
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:DD:9F:EB",
|
||||
"name": "5",
|
||||
"room": "kitchen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-22T23:59:07+02:00",
|
||||
"mac": "A4:C1:38:9A:81:25",
|
||||
"temperature": 25.1,
|
||||
"humidity": 51,
|
||||
"battery_percent": 82,
|
||||
"battery_volt": 2.946,
|
||||
"count": 143
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:9A:81:25",
|
||||
"name": "6",
|
||||
"room": "server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-22T23:59:09+02:00",
|
||||
"mac": "A4:C1:38:83:05:E8",
|
||||
"temperature": 22.2,
|
||||
"humidity": 61,
|
||||
"battery_percent": 80,
|
||||
"battery_volt": 2.933,
|
||||
"count": 32
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:83:05:E8",
|
||||
"name": "my_room",
|
||||
"room": "my_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:13:48+02:00",
|
||||
"mac": "A4:C1:38:DD:9F:EB",
|
||||
"temperature": 20.3,
|
||||
"humidity": 70,
|
||||
"battery_percent": 85,
|
||||
"battery_volt": 2.974,
|
||||
"count": 1
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:DD:9F:EB",
|
||||
"name": "5",
|
||||
"room": "kitchen"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:13:49+02:00",
|
||||
"mac": "A4:C1:38:46:D7:75",
|
||||
"temperature": 20.4,
|
||||
"humidity": 69,
|
||||
"battery_percent": 87,
|
||||
"battery_volt": 2.986,
|
||||
"count": 2
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:46:D7:75",
|
||||
"name": "4",
|
||||
"room": "dinner_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:13:50+02:00",
|
||||
"mac": "A4:C1:38:83:05:E8",
|
||||
"temperature": 22.2,
|
||||
"humidity": 61,
|
||||
"battery_percent": 80,
|
||||
"battery_volt": 2.932,
|
||||
"count": 90
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:83:05:E8",
|
||||
"name": "my_room",
|
||||
"room": "my_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:13:55+02:00",
|
||||
"mac": "A4:C1:38:9A:81:25",
|
||||
"temperature": 25.1,
|
||||
"humidity": 51,
|
||||
"battery_percent": 82,
|
||||
"battery_volt": 2.945,
|
||||
"count": 160
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:9A:81:25",
|
||||
"name": "6",
|
||||
"room": "server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:14:11+02:00",
|
||||
"mac": "A4:C1:38:83:05:E8",
|
||||
"temperature": 22.3,
|
||||
"humidity": 61,
|
||||
"battery_percent": 81,
|
||||
"battery_volt": 2.932,
|
||||
"count": 92
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:83:05:E8",
|
||||
"name": "my_room",
|
||||
"room": "my_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:14:11+02:00",
|
||||
"mac": "A4:C1:38:46:D7:75",
|
||||
"temperature": 20.4,
|
||||
"humidity": 69,
|
||||
"battery_percent": 87,
|
||||
"battery_volt": 2.986,
|
||||
"count": 2
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:46:D7:75",
|
||||
"name": "4",
|
||||
"room": "dinner_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:14:12+02:00",
|
||||
"mac": "A4:C1:38:9A:81:25",
|
||||
"temperature": 25.1,
|
||||
"humidity": 51,
|
||||
"battery_percent": 82,
|
||||
"battery_volt": 2.945,
|
||||
"count": 160
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:9A:81:25",
|
||||
"name": "6",
|
||||
"room": "server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"timestamp": "2024-06-23T00:14:12+02:00",
|
||||
"mac": "A4:C1:38:DD:9F:EB",
|
||||
"temperature": 20.3,
|
||||
"humidity": 70,
|
||||
"battery_percent": 85,
|
||||
"battery_volt": 2.974,
|
||||
"count": 1
|
||||
},
|
||||
"device": {
|
||||
"mac": "A4:C1:38:DD:9F:EB",
|
||||
"name": "5",
|
||||
"room": "kitchen"
|
||||
}
|
||||
}
|
||||
]
|
||||
143
Charts/index.html
Normal file
143
Charts/index.html
Normal file
@ -0,0 +1,143 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Geräte-Diagramme</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #121212;
|
||||
color: #ffffff;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.chart-container {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #1e1e1e;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.chart {
|
||||
padding: 10px;
|
||||
}
|
||||
.device-info {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Geräte-Diagramme</h1>
|
||||
<div id="charts"></div>
|
||||
|
||||
<script>
|
||||
fetch('data.json')
|
||||
.then(response => response.json())
|
||||
.then(jsonData => {
|
||||
const deviceDataMap = new Map();
|
||||
jsonData.forEach(entry => {
|
||||
const deviceMac = entry.device.mac;
|
||||
if (!deviceDataMap.has(deviceMac)) {
|
||||
deviceDataMap.set(deviceMac, {info: entry.device, data: []});
|
||||
}
|
||||
deviceDataMap.get(deviceMac).data.push(entry.data);
|
||||
});
|
||||
|
||||
deviceDataMap.forEach((deviceData, deviceMac) => createChart(deviceData));
|
||||
})
|
||||
.catch(error => console.error('Error loading data:', error));
|
||||
|
||||
function createChart(deviceData) {
|
||||
const labels = deviceData.data.map(entry => new Date(entry.timestamp).toLocaleTimeString());
|
||||
const temperatures = deviceData.data.map(entry => entry.temperature);
|
||||
const humidities = deviceData.data.map(entry => entry.humidity);
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.className = 'chart-container';
|
||||
|
||||
const deviceInfo = document.createElement('div');
|
||||
deviceInfo.className = 'device-info';
|
||||
deviceInfo.innerHTML = `<strong>${deviceData.info.name}</strong> (${deviceData.info.room})`;
|
||||
container.appendChild(deviceInfo);
|
||||
|
||||
const ctx = document.createElement('canvas');
|
||||
ctx.className = 'chart';
|
||||
container.appendChild(ctx);
|
||||
|
||||
document.getElementById('charts').appendChild(container);
|
||||
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Temperatur (°C)',
|
||||
data: temperatures,
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||
yAxisID: 'y-axis-temp'
|
||||
},
|
||||
{
|
||||
label: 'Feuchtigkeit (%)',
|
||||
data: humidities,
|
||||
borderColor: 'rgba(153, 102, 255, 1)',
|
||||
backgroundColor: 'rgba(153, 102, 255, 0.2)',
|
||||
yAxisID: 'y-axis-humidity'
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [
|
||||
{
|
||||
id: 'y-axis-temp',
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
fontColor: 'white'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Temperatur (°C)',
|
||||
fontColor: 'white'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'y-axis-humidity',
|
||||
type: 'linear',
|
||||
position: 'right',
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
fontColor: 'white'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Feuchtigkeit (%)',
|
||||
fontColor: 'white'
|
||||
}
|
||||
}
|
||||
],
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
fontColor: 'white'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
legend: {
|
||||
labels: {
|
||||
fontColor: 'white'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
107
Charts/script.js
Normal file
107
Charts/script.js
Normal file
@ -0,0 +1,107 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
fetch('data.json')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok ' + response.statusText);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
const devices = {};
|
||||
|
||||
data.forEach(entry => {
|
||||
const mac = entry.device.mac;
|
||||
if (!devices[mac]) {
|
||||
devices[mac] = {
|
||||
temperatureData: [],
|
||||
humidityData: [],
|
||||
labels: [],
|
||||
name: entry.device.name,
|
||||
room: entry.device.room
|
||||
};
|
||||
}
|
||||
devices[mac].labels.push(new Date(entry.data.timestamp));
|
||||
devices[mac].temperatureData.push(entry.data.temperature);
|
||||
devices[mac].humidityData.push(entry.data.humidity);
|
||||
});
|
||||
|
||||
const chartsContainer = document.getElementById('chartsContainer');
|
||||
|
||||
Object.keys(devices).forEach(mac => {
|
||||
const device = devices[mac];
|
||||
|
||||
const chartContainer = document.createElement('div');
|
||||
chartContainer.className = 'chart-container';
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.id = `chart-${mac}`;
|
||||
|
||||
const title = document.createElement('h3');
|
||||
title.textContent = `Device ${device.name} in ${device.room}`;
|
||||
|
||||
chartContainer.appendChild(title);
|
||||
chartContainer.appendChild(canvas);
|
||||
chartsContainer.appendChild(chartContainer);
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: device.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Temperatur (°C)',
|
||||
data: device.temperatureData,
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||
borderWidth: 1,
|
||||
yAxisID: 'y1'
|
||||
},
|
||||
{
|
||||
label: 'Luftfeuchtigkeit (%)',
|
||||
data: device.humidityData,
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||
borderWidth: 1,
|
||||
yAxisID: 'y2'
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'minute',
|
||||
tooltipFormat: 'll HH:mm'
|
||||
}
|
||||
},
|
||||
y1: {
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Temperatur (°C)'
|
||||
}
|
||||
},
|
||||
y2: {
|
||||
type: 'linear',
|
||||
position: 'right',
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Luftfeuchtigkeit (%)'
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error loading JSON data:', error));
|
||||
});
|
||||
20
Charts/styles.css
Normal file
20
Charts/styles.css
Normal file
@ -0,0 +1,20 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 80%;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
canvas {
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@ -29,11 +29,11 @@ class Data:
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
'timestamp': self.timestamp,
|
||||
'mac': self.mac,
|
||||
'temperature': self.temperature,
|
||||
'humidity': self.humidity,
|
||||
'battery_percent': self.battery_percent,
|
||||
'battery_volt': self.battery_volt,
|
||||
'count': self.count,
|
||||
"timestamp": self.timestamp,
|
||||
"mac": self.mac,
|
||||
"temperature": self.temperature,
|
||||
"humidity": self.humidity,
|
||||
"battery_percent": self.battery_percent,
|
||||
"battery_volt": self.battery_volt,
|
||||
"count": self.count,
|
||||
}
|
||||
|
||||
@ -11,6 +11,13 @@ class Device:
|
||||
self.name = data['name']
|
||||
self.room = data['room']
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"mac": self.mac,
|
||||
"name": self.name,
|
||||
"room": self.room
|
||||
}
|
||||
|
||||
|
||||
def get_devices():
|
||||
devices_list = []
|
||||
|
||||
@ -29,7 +29,8 @@ class ScanDelegate(DefaultDelegate):
|
||||
if len(val) != 30: return False
|
||||
return True
|
||||
|
||||
def is_atc_device(self, dev, data_obj):
|
||||
@staticmethod
|
||||
def is_atc_device(dev, data_obj):
|
||||
global devices
|
||||
if 'A4:C1:38' not in dev.addr.upper(): return False
|
||||
for device in devices:
|
||||
|
||||
@ -1 +1,32 @@
|
||||
# TODO
|
||||
import os
|
||||
import json
|
||||
from data_class import Data
|
||||
from devices import Device
|
||||
|
||||
workdir, filename = os.path.split(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def log_to_txt(devices):
|
||||
with open(f'{workdir}{os.sep}history.json', 'r') as file:
|
||||
data = json.load(file)
|
||||
|
||||
with open(f'{workdir}{os.sep}history.json', 'w') as file:
|
||||
for device in devices:
|
||||
dev, data_obj, from_config = device
|
||||
data_obj:Data
|
||||
from_config:Device
|
||||
data.append({
|
||||
"data": data_obj.to_json(),
|
||||
"device": from_config.to_json()
|
||||
})
|
||||
final_data = {"measurements": data}
|
||||
file.write(json.dumps(data, indent=2))
|
||||
|
||||
|
||||
def log_to_mongodb(data):
|
||||
pass
|
||||
|
||||
|
||||
def log_to_mqtt(data):
|
||||
pass
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
from discovery import start_discovery
|
||||
from loop import start_loop
|
||||
from log_data import log_to_txt
|
||||
|
||||
|
||||
devices = start_discovery()
|
||||
log_to_txt(devices)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user