From 70d778a31e34cc6dcaddb1b1b5773919df879647 Mon Sep 17 00:00:00 2001 From: ferdzo Date: Wed, 28 Aug 2024 22:10:36 +0200 Subject: [PATCH] Big update --- .gitignore | 2 + db.sqlite3 | Bin 131072 -> 135168 bytes demo.db | Bin 28672 -> 28672 bytes iotDashboard/apps.py | 6 + iotDashboard/forms.py | 7 + iotDashboard/getInfoFromDevices.py | 2 +- iotDashboard/models.py | 11 +- iotDashboard/settings.py | 23 ++- iotDashboard/tasks.py | 37 ++++ iotDashboard/templates/chart.html | 182 ++++++++++++++++++ .../templates/device_confirm_delete.html | 51 +++++ iotDashboard/templates/device_form.html | 52 +++++ iotDashboard/templates/device_list.html | 73 +++++++ iotDashboard/urls.py | 10 +- iotDashboard/views.py | 90 +++++++-- proba.py | 13 +- 16 files changed, 530 insertions(+), 29 deletions(-) create mode 100644 iotDashboard/apps.py create mode 100644 iotDashboard/forms.py create mode 100644 iotDashboard/tasks.py create mode 100644 iotDashboard/templates/chart.html create mode 100644 iotDashboard/templates/device_confirm_delete.html create mode 100644 iotDashboard/templates/device_form.html create mode 100644 iotDashboard/templates/device_list.html diff --git a/.gitignore b/.gitignore index e69de29..7b5867d 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +/iotDashboard/.env +/.idea diff --git a/db.sqlite3 b/db.sqlite3 index 447433f36a7a26c638ced9ce00f0292c12661815..0995cd3f4fb3abee9125c89a0bdf20adf80aa6c3 100644 GIT binary patch delta 1697 zcmah~OKcle6rJaBI!5A8S~+9<#I*m0Z|HICyrAE${OJ5D2ln>+@Jmt3s_WkTv(K zEM{E=(%Nce`Q%_giU#?B7$yjU^s^kBWCL-Epp2bFZzt7@la@ZCsn2BU>ZOcEBUzYi zxUAfZ!8ruphnw(2n1-wH4LDaY;11ZOSEDr8nbaR<(rk!P=#*$X2&9rxzrctIR+3nr zYs{~94+AW}+1;+!RmmhVC?W6{_&K}{KY|ya1Xl|NVh--tD_iRx%UVu~6B%GLd!l65d#WfaZ2A%`%xs9Bcs&FD>zMbW4MbIMj`WnK+YVc3{em zZB%_36^aJ9$WBz*@d$OGPDUBpus}FmP6U}!HF^06P?&dKMA1g=W*(a)Rn^tnKeczY zn=;i`v}3hO&DVAKk;z)UkxsvD#%5>yv`6A%;}K@mHkFKw2%|%j z(~s#MqdvdIoa-5#wTspnrzz)iT4#HV!&4&`m)W>PvZpMm9`~@| z?XfSIxoL4sw4`VK9*O5?nZ;Qt78XY)#wg!{%Nt5ZM29OU*@h$TsC0ak<+vI9tZT|+ zHFI`%oNx)Lk*RdH(=|p~bF(M=NGV1LLZ68{K@%rpsbnTIF1Ykf~=bAR7S=sYcg-`ja`uECXD!ck9`U$vRe5N0~1&a4#;D+MTmmP}YwIN^v3S=_> z2j(ma99RRzTO+^&bo=xM19)K}83@Lit+9@X8}B8+6|_c&ZCLxkT5;70vbqk4JV2_B zR=%zJMzwd(k8;I?qJW-2uPTo^GEI1p=i@u0qp1WNW|P_f z?6j3s52@L1L81D)UnkbrO7bcq@MriH{0v@!=iv$zWg&bH?%yYOqP1=(`?8i5S8jlu zJeBYw0)K!X!;A8{dJQ%oK&{}(XAv!J=dZq5zw!M;a8OgaB>=pGz&r4LIs9EX*woOj ptE>z%VUgz(q=o7tdwRR%OQ4IS$z({7MGG;M5OFrma*^FZe*;My^sN8@ delta 587 zcmXw0T}V@L6#t)lZ@brRcV{07qeZS-(XzFVOF9+F;dgU5lj&1+OD4Je7|yBlK~}wO zL92`02uy<>gdRff;zAjOK1c;+u^zH0>%}7KrH60p37#rg2Un_ zggCX?soERI1aL2kbI93v4YV4f5^FxB?032hO4LzgtU4Sg_zg?=7{@V>w{cRjBt7Bg1wn?`;E}RPt7qTlLyG9p(xC#22`ZPjDXd+Uf*K`I8yi zZWJZ9!LJb=F)CumJ({+gDkL_#jcoEt#o37E%y4T{sA=RvB+(L!#p9`-{?TwOGv*p> z3N>Gv=t%gg8&7o)OtlX6b`CZMJIBI_)~c#5uh5h3O7@>_7s5iSKHv)o9>32M@Hzed zTAxrW1drF$1OwI8%CnI=Cr9x`Vp`{m8tVeD6lbFpN1;kk#Sfa+`^dQH2uMq_PUZar zx0AMGT4L8UjlOzR(x0x22lUJgL6_-G*<0N*KVi)2cJJzCW(>b~n);_6Zh*TWe{2R; zc?ql3;+lt2ms{WjP_Uu=VLddXCG}c5YFO2mZU5!UWwVWyLk&<+^Bs_}nQY`2!GtNv zKQw;TZ_1nqdnLd5n)*nDTNHTZ?mnoa2vG}t(91GcryZ>NJpq4dX`1I``!F1oC)>aw zLpzi}ufWDu=gk6R)?tp|4}6EuaS7)zr}-U6HTMdpv{-P3;1^ucFcq17bO@xUclOAi Hx1i!bcAv2# diff --git a/demo.db b/demo.db index 1ca4cd9fd7b135934606495cd91cd057cdc5f768..59e827989cc5df653f6ca0732a6fe49a065093e8 100644 GIT binary patch delta 191 zcmZp8z}WDBaRX-nvmQUsW}W~geisG?hD!|9O$Hp!RxzQ)sYS&xX{kjiRrxUimB|^2 zMY#b*`B|ySCB-qB`6Vui#TiNYiA5R` delta 125 zcmZp8z}WDBaRX-na~sd9%{&20{F4vFil`VFnwchAq!{TMrzR)qnwS_T=~@`3CF!P` zm>DG|nx+^S8m3OJi&bJ`sG2MgF9+6RU~HO}W|)+sn`mrdsB4m#XaZyDLU7+C=IC`?M=X1utWC*cb}09chJivR!s diff --git a/iotDashboard/apps.py b/iotDashboard/apps.py new file mode 100644 index 0000000..2c5b659 --- /dev/null +++ b/iotDashboard/apps.py @@ -0,0 +1,6 @@ + +from django.apps import AppConfig + +class IotDashboardConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'iotDashboard' diff --git a/iotDashboard/forms.py b/iotDashboard/forms.py new file mode 100644 index 0000000..315987a --- /dev/null +++ b/iotDashboard/forms.py @@ -0,0 +1,7 @@ +from django import forms +from .models import Device + +class DeviceForm(forms.ModelForm): + class Meta: + model = Device + fields = ['name', 'ip', 'protocol', 'temperature', 'humidity'] diff --git a/iotDashboard/getInfoFromDevices.py b/iotDashboard/getInfoFromDevices.py index 6955d74..797d89b 100644 --- a/iotDashboard/getInfoFromDevices.py +++ b/iotDashboard/getInfoFromDevices.py @@ -1,6 +1,6 @@ import requests -devices = {"livingroom":"192.168.1.56"} +devices = {"esp1":"192.168.244.131"} def getTemp(device): r = requests.get("http://"+devices[device]+"/sensor/temperature") diff --git a/iotDashboard/models.py b/iotDashboard/models.py index c5cd5ff..5e39517 100644 --- a/iotDashboard/models.py +++ b/iotDashboard/models.py @@ -1,17 +1,10 @@ from django.db import models - class Device(models.Model): name = models.CharField(max_length=50) ip = models.CharField(max_length=20) protocol = models.CharField(max_length=20) temperature = models.BooleanField(default=False) humidity = models.BooleanField(default=False) - brightness = models.BooleanField(default=False) - - - -class Measurement(models.Model): - temperature = models.CharField(required=False,max_length=10) - humidity = models.CharField(required=False,max_length=10) - brightness = models.CharField(required=False,max_length=10) + def __str__(self): + return self.name \ No newline at end of file diff --git a/iotDashboard/settings.py b/iotDashboard/settings.py index b684f52..4be3382 100644 --- a/iotDashboard/settings.py +++ b/iotDashboard/settings.py @@ -11,6 +11,9 @@ https://docs.djangoproject.com/en/4.2/ref/settings/ """ import environ from pathlib import Path +import os +from huey import SqliteHuey + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -24,6 +27,7 @@ environ.Env.read_env() # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = env('SECRET_KEY') +CONNECTION_STRING = env('CONNECTION_STRING') # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -40,6 +44,9 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'iotDashboard', + 'huey.contrib.djhuey', + ] MIDDLEWARE = [ @@ -57,7 +64,7 @@ ROOT_URLCONF = 'iotDashboard.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [os.path.join(BASE_DIR, 'iotDashboard/templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -86,8 +93,8 @@ DATABASES = { "NAME" : "example", "USER": "postgres", "PASSWORD": env('PASSWORD'), - "HOST": 'localhost', - "PORT": '5432', + "HOST": '10.10.0.1', + "PORT": '5555', } } @@ -132,3 +139,13 @@ STATIC_URL = 'static/' # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +HUEY = { + 'huey_class': 'huey.SqliteHuey', # Or 'huey.RedisHuey' for Redis + 'filename': 'demo.db', # SQLite file for task storage + 'results': True, + 'store_none': False, + 'immediate': False, + 'utc': True, +} \ No newline at end of file diff --git a/iotDashboard/tasks.py b/iotDashboard/tasks.py new file mode 100644 index 0000000..32120a2 --- /dev/null +++ b/iotDashboard/tasks.py @@ -0,0 +1,37 @@ +import psycopg2 +import requests +from huey import crontab +from huey.contrib.djhuey import periodic_task +from datetime import datetime +from django.conf import settings +from .models import Device # Import your Device model + +# Fetch data from the device using REST API +def fetch_data_from_device(device): + data = dict() + data["time"] = datetime.now() + data["device"] = device.name # Use device name + r = requests.get(f"http://{device.ip}/sensor/tempreature") + data["temperature"] = r.json()['value'] + r = requests.get(f"http://{device.ip}/sensor/humidity") + data["humidity"] = r.json()['value'] + return (data["time"], data["device"], data["temperature"], data["humidity"]) + +# Insert data into the database +def insert_data(device): + data = fetch_data_from_device(device) + with psycopg2.connect(settings.CONNECTION_STRING) as conn: # Use Django's connection string + cursor = conn.cursor() + insert_query = """ + INSERT INTO conditions (time, device, temperature, humidity) + VALUES (%s, %s, %s, %s) + """ + cursor.execute(insert_query, data) + conn.commit() + +# Periodic task to fetch data from all devices every minute +@periodic_task(crontab(minute='*/1')) +def fetch_data_from_all_devices(): + devices = Device.objects.all() # Fetch all devices from the database + for device in devices: + insert_data(device) \ No newline at end of file diff --git a/iotDashboard/templates/chart.html b/iotDashboard/templates/chart.html new file mode 100644 index 0000000..7791ef9 --- /dev/null +++ b/iotDashboard/templates/chart.html @@ -0,0 +1,182 @@ + + + + + + + Conditions Chart with Chart.js + + + + + + + + +
+

Temperature and Humidity Over Time

+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ +
+
+
+
+ + + + + + + + diff --git a/iotDashboard/templates/device_confirm_delete.html b/iotDashboard/templates/device_confirm_delete.html new file mode 100644 index 0000000..044383d --- /dev/null +++ b/iotDashboard/templates/device_confirm_delete.html @@ -0,0 +1,51 @@ + + + + + + Delete Device + + + + +
+

Delete Device

+ +

Are you sure you want to delete the device "{{ device.name }}"?

+ +
+ {% csrf_token %} + + Cancel +
+
+ + diff --git a/iotDashboard/templates/device_form.html b/iotDashboard/templates/device_form.html new file mode 100644 index 0000000..ff9c424 --- /dev/null +++ b/iotDashboard/templates/device_form.html @@ -0,0 +1,52 @@ + + + + + + {% if form.instance.pk %}Edit{% else %}Add{% endif %} Device + + + + +
+

{% if form.instance.pk %}Edit{% else %}Add{% endif %} Device

+ +
+ {% csrf_token %} +
+ {{ form.as_p }} +
+ + Cancel +
+
+ + diff --git a/iotDashboard/templates/device_list.html b/iotDashboard/templates/device_list.html new file mode 100644 index 0000000..ad23c91 --- /dev/null +++ b/iotDashboard/templates/device_list.html @@ -0,0 +1,73 @@ + + + + + + Device Management + + + + +
+

Manage Devices

+ + Add Device + + + + + + + + + + + + + + {% for device in devices %} + + + + + + + + + {% endfor %} + +
NameIP AddressProtocolTemperature MonitoringHumidity MonitoringActions
{{ device.name }}{{ device.ip }}{{ device.protocol }}{{ device.temperature|yesno:"Yes,No" }}{{ device.humidity|yesno:"Yes,No" }} + Edit + Delete +
+
+ + diff --git a/iotDashboard/urls.py b/iotDashboard/urls.py index e78e28f..dc44a96 100644 --- a/iotDashboard/urls.py +++ b/iotDashboard/urls.py @@ -20,5 +20,13 @@ from iotDashboard import views urlpatterns = [ path('admin/', admin.site.urls), - path('',views.index) + path('',views.index), + path('fetch_device_data/', views.fetch_device_data, name='fetch_device_data'), + path('chart/',views.chart,name='chart'), + path('devices/', views.device_list, name='device_list'), + path('devices/add/', views.add_device, name='add_device'), + path('devices/edit//', views.edit_device, name='edit_device'), + path('devices/delete//', views.delete_device, name='delete_device'), + path('login/', views.login_view, name='login'), + path('logout/', views.logout_view, name='logout'), ] diff --git a/iotDashboard/views.py b/iotDashboard/views.py index 0ad9fbe..c4f8bd8 100644 --- a/iotDashboard/views.py +++ b/iotDashboard/views.py @@ -1,18 +1,86 @@ -from django.http import HttpResponse +from django.http import HttpResponse, request, JsonResponse from django.db import connections - -def my_custom_sql(): - with connections['data'].cursor() as cursor: - # cursor.execute("SELECT * FROM conditions WHERE device='livingroom';" - cursor.execute("SELECT * FROM conditions WHERE time > NOW() - INTERVAL '50 days' ;") - row = cursor.fetchall() - keys = ("time","device","tempreature","humidity") - return row +from django.shortcuts import render, redirect, get_object_or_404 +from .models import Device +from .forms import DeviceForm +def fetch_device_data(request): + device = request.GET.get('device', 'livingroom') + start_date = request.GET.get('start_date') + end_date = request.GET.get('end_date') + + query = """ + SELECT time, temperature, humidity + FROM conditions + WHERE device = %s + """ + params = [device] + + if start_date: + query += " AND time >= %s" + params.append(start_date) + + if end_date: + query += " AND time <= %s" + params.append(end_date) + + with connections["data"].cursor() as cursor: + cursor.execute(query, params) + rows = cursor.fetchall() + + times = [row[0].strftime('%Y-%m-%d %H:%M:%S') for row in rows] + temperatures = [row[1] for row in rows] + humidities = [row[2] for row in rows] + + return JsonResponse({ + 'times': times, + 'temperatures': temperatures, + 'humidities': humidities, + }) +def chart(request): + devices = Device.objects.all() + context = {'devices': devices} + return render(request, 'chart.html', context) def index(request): if request.user.is_authenticated: - return HttpResponse(my_custom_sql()) - return HttpResponse("NOT AUTHENTICATED!!!") \ No newline at end of file + return HttpResponse(chart()) + return HttpResponse("NOT AUTHENTICATED!!!") +def device_list(request): + devices = Device.objects.all() + return render(request, 'device_list.html', {'devices': devices}) + +def add_device(request): + if request.method == 'POST': + form = DeviceForm(request.POST) + if form.is_valid(): + form.save() + return redirect('device_list') + else: + form = DeviceForm() + return render(request, 'device_form.html', {'form': form}) + +def edit_device(request, pk): + device = get_object_or_404(Device, pk=pk) + if request.method == 'POST': + form = DeviceForm(request.POST, instance=device) + if form.is_valid(): + form.save() + return redirect('device_list') + else: + form = DeviceForm(instance=device) + return render(request, 'device_form.html', {'form': form}) + +def delete_device(request, pk): + device = get_object_or_404(Device, pk=pk) + if request.method == 'POST': + device.delete() + return redirect('device_list') + return render(request, 'device_confirm_delete.html', {'device': device}) + +def login_view(): + pass +def logout_view(): + pass \ No newline at end of file diff --git a/proba.py b/proba.py index 81d575a..b9c2ba0 100644 --- a/proba.py +++ b/proba.py @@ -1,18 +1,23 @@ +import dotenv import psycopg2 from psycopg2 import sql from datetime import datetime import requests from huey import SqliteHuey, crontab +from dotenv import load_dotenv +from pathlib import Path + # Initialize scheduler huey = SqliteHuey(filename='demo.db') - +dotenv_path = Path("iotDashboard/.env") +load_dotenv(dotenv_path=dotenv_path) +CONNECTION = dotenv.dotenv_values(dotenv_path)["CONNECTION_STRING"] # Database connection -CONNECTION = "postgres://postgres:postgres*@localhost:5432/example" conn = psycopg2.connect(CONNECTION) # Devices -devices = {"livingroom": "192.168.1.56","bedroom":"192.168.1.57"} +devices = {"livingroom": "192.168.244.131"} # Func for fetching data from device using REST API @@ -20,7 +25,7 @@ def fetch_data_from_device(device): data = dict() data["time"] = datetime.now() data["device"] = device - r = requests.get("http://" + devices[device] + "/sensor/temperature") + r = requests.get("http://" + devices[device] + "/sensor/tempreature") data["temperature"] = r.json()['value'] r = requests.get("http://" + devices[device] + "/sensor/humidity") data["humidity"] = r.json()['value']