diff --git a/.gitignore b/.gitignore index bf63fc5..b3c90c0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ db.sqlite3 demo.db demo.db-shm demo.db-wal -__pycache__/ \ No newline at end of file +__pycache__/ diff --git a/iotDashboard/__pycache__/__init__.cpython-311.pyc b/iotDashboard/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 72f2c2c..0000000 Binary files a/iotDashboard/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/apps.cpython-311.pyc b/iotDashboard/__pycache__/apps.cpython-311.pyc deleted file mode 100644 index 2bd9865..0000000 Binary files a/iotDashboard/__pycache__/apps.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/forms.cpython-311.pyc b/iotDashboard/__pycache__/forms.cpython-311.pyc deleted file mode 100644 index 48a2e62..0000000 Binary files a/iotDashboard/__pycache__/forms.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/getInfoFromDevices.cpython-311.pyc b/iotDashboard/__pycache__/getInfoFromDevices.cpython-311.pyc deleted file mode 100644 index a37e53b..0000000 Binary files a/iotDashboard/__pycache__/getInfoFromDevices.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/models.cpython-311.pyc b/iotDashboard/__pycache__/models.cpython-311.pyc deleted file mode 100644 index 9c4ab47..0000000 Binary files a/iotDashboard/__pycache__/models.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/settings.cpython-311.pyc b/iotDashboard/__pycache__/settings.cpython-311.pyc deleted file mode 100644 index ed36fdd..0000000 Binary files a/iotDashboard/__pycache__/settings.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/tasks.cpython-311.pyc b/iotDashboard/__pycache__/tasks.cpython-311.pyc deleted file mode 100644 index 3e86615..0000000 Binary files a/iotDashboard/__pycache__/tasks.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/urls.cpython-311.pyc b/iotDashboard/__pycache__/urls.cpython-311.pyc deleted file mode 100644 index fc30403..0000000 Binary files a/iotDashboard/__pycache__/urls.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/views.cpython-311.pyc b/iotDashboard/__pycache__/views.cpython-311.pyc deleted file mode 100644 index fa574a5..0000000 Binary files a/iotDashboard/__pycache__/views.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/__pycache__/wsgi.cpython-311.pyc b/iotDashboard/__pycache__/wsgi.cpython-311.pyc deleted file mode 100644 index b5c238e..0000000 Binary files a/iotDashboard/__pycache__/wsgi.cpython-311.pyc and /dev/null differ diff --git a/iotDashboard/db_create.py b/iotDashboard/db_create.py index e69de29..d76df4c 100644 --- a/iotDashboard/db_create.py +++ b/iotDashboard/db_create.py @@ -0,0 +1,54 @@ +import psycopg2 +from psycopg2 import sql +import os +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +# Define your database connection parameters +DATABASE_NAME = os.getenv('DB_NAME', 'example') +USER = os.getenv('DB_USER', 'postgres') +PASSWORD = os.getenv('DB_PASSWORD', 'coolermaster') +HOST = os.getenv('DB_HOST', '10.10.0.1') +PORT = os.getenv('DB_PORT', '5555') + +def create_sensor_readings_table(): + """Create the sensor_readings table if it does not exist.""" + try: + # Establish connection to the database + conn = psycopg2.connect( + dbname=DATABASE_NAME, + user=USER, + password=PASSWORD, + host=HOST, + port=PORT + ) + + with conn.cursor() as cursor: + # SQL command to create the sensor_readings table + create_table_query = """ + CREATE TABLE IF NOT EXISTS sensor_readings ( + time TIMESTAMPTZ NOT NULL, + device_name VARCHAR(255) NOT NULL, -- Use device_name as a string + metric VARCHAR(50) NOT NULL, -- Type of sensor + value DOUBLE PRECISION NOT NULL, -- The sensor's value + PRIMARY KEY (time, device_name, metric) -- Composite primary key + ); + """ + cursor.execute(create_table_query) + print("Table 'sensor_readings' created or already exists.") + + # Commit changes + conn.commit() + + except Exception as e: + print(f"Error during database operations: {e}") + + finally: + if conn: + conn.close() + print("Database connection closed.") + +if __name__ == "__main__": + create_sensor_readings_table() \ No newline at end of file diff --git a/iotDashboard/forms.py b/iotDashboard/forms.py index ca797f4..8c09f2e 100644 --- a/iotDashboard/forms.py +++ b/iotDashboard/forms.py @@ -1,48 +1,72 @@ from django import forms from .models import Device, Sensor, SensorType -# Form for adding/editing devices class DeviceForm(forms.ModelForm): - class Meta: - model = Device - fields = ['name', 'ip', 'protocol'] # Fields based on your Device model - widgets = { - 'name': forms.TextInput(attrs={'class': 'form-control'}), - 'ip': forms.TextInput(attrs={'class': 'form-control'}), - 'protocol': forms.Select(attrs={'class': 'form-control'}), - } - -# Form for adding a sensor with its type, including topic and endpoint for SensorType -class SensorWithTypeForm(forms.ModelForm): - type = forms.ModelChoiceField( - queryset=SensorType.objects.all(), - widget=forms.Select(attrs={'class': 'form-control'}), - label="Sensor Type" + # Optionally include sensors as choices in the form if relevant + sensors = forms.ModelMultipleChoiceField( + queryset=Sensor.objects.all(), + required=False, + widget=forms.CheckboxSelectMultiple, + label='Sensors' ) class Meta: - model = Sensor - fields = ['device', 'type', 'enabled'] # Fields from your Sensor model - widgets = { - 'device': forms.Select(attrs={'class': 'form-control'}), - 'enabled': forms.CheckboxInput(attrs={'class': 'form-check-input'}), - } + model = Device + fields = ['name', 'ip', 'protocol'] + + def __init__(self, *args, **kwargs): + # Optionally pass initial sensors for editing an existing device + if 'instance' in kwargs: + initial_sensors = kwargs['instance'].sensors.all() if kwargs['instance'] else None + initial = kwargs.get('initial', {}) + initial['sensors'] = initial_sensors + kwargs['initial'] = initial + super(DeviceForm, self).__init__(*args, **kwargs) def save(self, commit=True): - sensor = super().save(commit=False) + # Save the device instance + device = super(DeviceForm, self).save(commit=False) + + if commit: + device.save() + self.save_m2m() # Ensure M2M save happens + + return device +class SensorWithTypeForm(forms.ModelForm): + # Add fields for SensorType directly in the form + type_name = forms.CharField(max_length=50, label="Sensor Type Name") + unit = forms.CharField(max_length=20, label="Unit", required=False) + protocol = forms.ChoiceField( + choices=[('mqtt', 'MQTT'), ('http', 'HTTP')], + label="Protocol" + ) + topic = forms.CharField(max_length=100, label="Topic", required=False) + endpoint = forms.CharField(max_length=100, label="Endpoint", required=False) + + class Meta: + model = Sensor + fields = ['device', 'enabled'] + + def save(self, commit=True): + # Create or get the SensorType + try: + sensor_type = SensorType.objects.get(name=self.cleaned_data['type_name']) + except SensorType.DoesNotExist: + sensor_type = SensorType( + name=self.cleaned_data['type_name'], + unit=self.cleaned_data['unit'], + protocol=self.cleaned_data['protocol'], + topic=self.cleaned_data['topic'], + endpoint=self.cleaned_data['endpoint'] + ) + if commit: + sensor_type.save() + + # Create Sensor with the SensorType found or created + sensor = super(SensorWithTypeForm, self).save(commit=False) + sensor.type = sensor_type + if commit: sensor.save() - return sensor -# Form for creating or editing SensorType -class SensorTypeForm(forms.ModelForm): - class Meta: - model = SensorType - fields = ['name', 'unit', 'protocol', 'topic', 'endpoint'] # Fields from your SensorType model - widgets = { - 'name': forms.TextInput(attrs={'class': 'form-control'}), - 'unit': forms.TextInput(attrs={'class': 'form-control'}), - 'protocol': forms.Select(attrs={'class': 'form-control'}), - 'topic': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Optional for MQTT'}), - 'endpoint': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Optional for HTTP'}), - } + return sensor \ No newline at end of file diff --git a/iotDashboard/migrations/0002_sensortype_remove_device_humidity_and_more.py b/iotDashboard/migrations/0002_sensortype_remove_device_humidity_and_more.py new file mode 100644 index 0000000..6944faf --- /dev/null +++ b/iotDashboard/migrations/0002_sensortype_remove_device_humidity_and_more.py @@ -0,0 +1,47 @@ +# Generated by Django 4.2.5 on 2024-10-08 10:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('iotDashboard', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='SensorType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, unique=True)), + ('unit', models.CharField(max_length=20)), + ('protocol', models.CharField(choices=[('mqtt', 'MQTT'), ('http', 'HTTP')], max_length=20)), + ('topic', models.CharField(blank=True, max_length=100, null=True)), + ('endpoint', models.CharField(blank=True, max_length=100, null=True)), + ], + ), + migrations.RemoveField( + model_name='device', + name='humidity', + ), + migrations.RemoveField( + model_name='device', + name='temperature', + ), + migrations.AlterField( + model_name='device', + name='protocol', + field=models.CharField(choices=[('mqtt', 'MQTT'), ('http', 'HTTP')], max_length=20), + ), + migrations.CreateModel( + name='Sensor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('enabled', models.BooleanField(default=True)), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sensors', to='iotDashboard.device')), + ('type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='iotDashboard.sensortype')), + ], + ), + ] diff --git a/iotDashboard/tasks.py b/iotDashboard/tasks.py index 459d904..44e29ab 100644 --- a/iotDashboard/tasks.py +++ b/iotDashboard/tasks.py @@ -105,7 +105,7 @@ def insert_data(data, sensor_type): except Exception as e: print(f"Failed to insert data: {e}") -@periodic_task(crontab(minute='*/1')) +@periodi c_task(crontab(minute='*/1')) def fetch_data_from_all_devices(): """Fetch and insert data for all devices based on their protocol.""" devices = Device.objects.all()