diff --git a/.gitignore b/.gitignore index 8647625..8b10401 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ __pycache__ -devices.yml \ No newline at end of file +devices.yml +history.* \ No newline at end of file diff --git a/Charts/data.json b/Charts/data.json new file mode 100644 index 0000000..032d501 --- /dev/null +++ b/Charts/data.json @@ -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" + } + } +] \ No newline at end of file diff --git a/Charts/index.html b/Charts/index.html new file mode 100644 index 0000000..1ff615a --- /dev/null +++ b/Charts/index.html @@ -0,0 +1,143 @@ + + + + + + Geräte-Diagramme + + + + +

Geräte-Diagramme

+
+ + + + diff --git a/Charts/script.js b/Charts/script.js new file mode 100644 index 0000000..2ba5ddc --- /dev/null +++ b/Charts/script.js @@ -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)); +}); diff --git a/Charts/styles.css b/Charts/styles.css new file mode 100644 index 0000000..9cfcc97 --- /dev/null +++ b/Charts/styles.css @@ -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); +} diff --git a/python/src/data_class.py b/python/src/data_class.py index 79213e7..490c059 100644 --- a/python/src/data_class.py +++ b/python/src/data_class.py @@ -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, } diff --git a/python/src/devices.py b/python/src/devices.py index f0af17f..603b611 100644 --- a/python/src/devices.py +++ b/python/src/devices.py @@ -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 = [] diff --git a/python/src/discovery.py b/python/src/discovery.py index 88e1bbe..0b7451b 100644 --- a/python/src/discovery.py +++ b/python/src/discovery.py @@ -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: @@ -37,8 +38,8 @@ class ScanDelegate(DefaultDelegate): device_from_config = get_device(dev) - try:print(f"Device: {dev.addr.upper()} ({dev.addrType}), RSSI: {dev.rssi} dB, Room: {device_from_config.room}") - except:print(f"Device: {dev.addr.upper()} ({dev.addrType}), RSSI: {dev.rssi} dB, Room: ?") + try:print(f"Device: {dev.addr.upper()} ({dev.addrType}), RSSI: {dev.rssi}dB, Room: {device_from_config.room}") + except:print(f"Device: {dev.addr.upper()} ({dev.addrType}), RSSI: {dev.rssi}dB, Room: ?") print(f'\tTemp: {data_obj.temperature}°C, Humid: {data_obj.humidity}%, Batt: {data_obj.battery_percent}%\n') return True diff --git a/python/src/log_data.py b/python/src/log_data.py index 4640904..2724848 100644 --- a/python/src/log_data.py +++ b/python/src/log_data.py @@ -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 + diff --git a/python/src/main.py b/python/src/main.py index b2f60ab..420c42b 100644 --- a/python/src/main.py +++ b/python/src/main.py @@ -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)