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 447433f..0995cd3 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/demo.db b/demo.db index 1ca4cd9..59e8279 100644 Binary files a/demo.db and b/demo.db differ 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']