From c84ea3bdef269d21b353f554292416330dd58fbd Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 12 Jan 2024 14:32:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0timescaledb=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enp/admin.py | 14 +++++- apps/enp/migrations/0001_initial.py | 75 +++++++++++++++++++++++++++++ apps/enp/migrations/0002_envdata.py | 48 ++++++++++++++++++ apps/enp/models.py | 50 +++++++++++++++++++ apps/enp/timedb.py | 21 ++++++++ 5 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 apps/enp/migrations/0001_initial.py create mode 100644 apps/enp/migrations/0002_envdata.py create mode 100644 apps/enp/timedb.py diff --git a/apps/enp/admin.py b/apps/enp/admin.py index 8c38f3f3..5dd059f1 100644 --- a/apps/enp/admin.py +++ b/apps/enp/admin.py @@ -1,3 +1,15 @@ from django.contrib import admin - +from .models import Drain, Equipment, DrainEquip +from django import forms # Register your models here. + + +class DrainEquipInline(admin.TabularInline): + model = DrainEquip + extra = 1 + + +@admin.register(Drain) +class DrainAdmin(admin.ModelAdmin): + inlines = [DrainEquipInline] + list_display = ('id', 'number', 'name') diff --git a/apps/enp/migrations/0001_initial.py b/apps/enp/migrations/0001_initial.py new file mode 100644 index 00000000..e7a4ad1e --- /dev/null +++ b/apps/enp/migrations/0001_initial.py @@ -0,0 +1,75 @@ +# Generated by Django 3.2.12 on 2024-01-10 09:37 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('system', '0003_alter_permission_parent'), + ('mtm', '0025_auto_20231120_1139'), + ('em', '0010_auto_20240110_1232'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Drain', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('type', models.PositiveSmallIntegerField(choices=[(10, '排放口'), (20, '污染源')], help_text="((10, '排放口'), (20, '污染源'))", verbose_name='类型')), + ('number', models.CharField(max_length=20, verbose_name='编号')), + ('name', models.CharField(max_length=20, verbose_name='名称')), + ('level', models.PositiveSmallIntegerField(choices=[(10, '主要排放口'), (20, '次要排放口')], default=20, help_text="((10, '主要排放口'), (20, '次要排放口'))", verbose_name='排口等级')), + ('cate', models.CharField(blank=True, choices=[('product', '生产工艺'), ('mtrans', '物料输送'), ('mstore', '物料储存')], help_text="(('product', '生产工艺'), ('mtrans', '物料输送'), ('mstore', '物料储存'))", max_length=10, null=True, verbose_name='分类')), + ('height', models.PositiveSmallIntegerField(default=0, verbose_name='排气筒高度')), + ('treatment_capacity', models.CharField(default='', max_length=20, verbose_name='处理量')), + ('pm_limit', models.FloatField(default=10, help_text='单位:mg/m³', verbose_name='PM超低排放限值')), + ('measure', models.CharField(default='', max_length=20, verbose_name='治理措施')), + ('coordinates', models.JSONField(default=dict, null=True, verbose_name='坐标')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='drain_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='drain_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='DrainEquip', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('params_list', models.JSONField(default=list, null=True, verbose_name='监测参数列表')), + ('drain', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enp.drain', verbose_name='排口')), + ('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='关联设备')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='drain', + name='equipments', + field=models.ManyToManyField(blank=True, related_name='drain_equipments', through='enp.DrainEquip', to='em.Equipment', verbose_name='关联设备'), + ), + migrations.AddField( + model_name='drain', + name='mgroup', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.mgroup', verbose_name='所属工段'), + ), + migrations.AddField( + model_name='drain', + name='update_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='drain_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'), + ), + ] diff --git a/apps/enp/migrations/0002_envdata.py b/apps/enp/migrations/0002_envdata.py new file mode 100644 index 00000000..fbadf48a --- /dev/null +++ b/apps/enp/migrations/0002_envdata.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2.12 on 2024-01-12 04:17 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('em', '0010_auto_20240110_1232'), + ('enp', '0001_initial'), + ] + + operations = [ + migrations.RunSQL( + sql=[( + """ +CREATE TABLE public.enp_envdata ( + "time" timestamp NOT NULL, + "equipment_id" text NOT NULL, + "is_online" bool NOT NULL, + "is_runing" bool NOT NULL, + "dust_rtd" decimal, + "dust_zs" decimal, + "temperature" decimal, + "pressure" decimal, + "speed" decimal, + "humidity" decimal, + "flux" decimal, + "pm25" decimal, + "pm10" decimal, + "tsp" decimal, + "wind_speed" decimal, + "so2_rtd" decimal, + "so2_zs" decimal, + "nox_rtd" decimal, + "nox_zs" decimal, + "o2" decimal, + CONSTRAINT enp_envdata_pkey PRIMARY KEY (time, equipment_id) +); +SELECT create_hypertable('enp_envdata', 'time'); + """ + )], + reverse_sql=[ + "DROP TABLE IF EXISTS public.enp_envdata;" + ] + ) + ] diff --git a/apps/enp/models.py b/apps/enp/models.py index 3f25a095..3014cdee 100644 --- a/apps/enp/models.py +++ b/apps/enp/models.py @@ -39,6 +39,8 @@ class Drain(CommonBModel): coordinates = models.JSONField('坐标', default=dict, null=True) mgroup = models.ForeignKey( Mgroup, verbose_name='所属工段', on_delete=models.CASCADE) + equipments = models.ManyToManyField( + Equipment, verbose_name='关联设备', through='DrainEquip', related_name='drain_equipments', blank=True) class DrainEquip(BaseModel): @@ -50,3 +52,51 @@ class DrainEquip(BaseModel): equipment = models.ForeignKey( Equipment, verbose_name='关联设备', on_delete=models.CASCADE) params_list = models.JSONField('监测参数列表', default=list, null=True) + + +class EnvData(models.Model): + """ + 环保监测数据 + """ + equipment = models.ForeignKey( + Equipment, verbose_name='关联设备', on_delete=models.CASCADE) + time = models.DateTimeField('采集时间', primary_key=True) + is_online = models.BooleanField('是否在线', default=True) + is_runing = models.BooleanField('是否运行', default=True) + dust_rtd = models.DecimalField( + '颗粒物实测(mg/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + dust_zs = models.DecimalField( + '颗粒物折算(mg/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + tempreture = models.DecimalField( + '温度(℃)', max_digits=10, decimal_places=4, null=True, blank=True) + pressure = models.DecimalField( + '压力(kPa)', max_digits=10, decimal_places=4, null=True, blank=True) + speed = models.DecimalField( + '流速(m/s)', max_digits=10, decimal_places=4, null=True, blank=True) + humidity = models.DecimalField( + '湿度(%)', max_digits=10, decimal_places=4, null=True, blank=True) + flux = models.DecimalField( + '流量(m3/h)', max_digits=10, decimal_places=4, null=True, blank=True) + pm25 = models.DecimalField( + 'PM2.5(ug/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + pm10 = models.DecimalField( + 'PM10(ug/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + tsp = models.DecimalField( + 'TSP(ug/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + wind_speed = models.DecimalField( + '风速(m/s)', max_digits=10, decimal_places=4, null=True, blank=True) + so2_rtd = models.DecimalField( + '二氧化硫实测(mg/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + so2_zs = models.DecimalField( + '二氧化硫折算(mg/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + nox_rtd = models.DecimalField( + '氮氧化物实测(mg/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + nox_zs = models.DecimalField( + '氮氧化物折算(mg/m3)', max_digits=10, decimal_places=4, null=True, blank=True) + o2 = models.DecimalField('含氧量(%)', max_digits=10, + decimal_places=4, null=True, blank=True) + + class Meta: + db_table = 'enp.envdata' + managed = False + unique_together = (('equipment', 'time'), ) diff --git a/apps/enp/timedb.py b/apps/enp/timedb.py new file mode 100644 index 00000000..8249b8b7 --- /dev/null +++ b/apps/enp/timedb.py @@ -0,0 +1,21 @@ +import psycopg2 +CONNECTION = "postgres://postgres:zcDsj2021@49.232.14.174:5432/ehs_develop" +with psycopg2.connect(CONNECTION) as conn: + cursor = conn.cursor() + query = """ +SELECT generate_series(now() - interval '24 hour', now(), interval '5 minute') AS time, + '3491356310052896768' as equipment_id, + random()*100 AS temperature, + random() AS pressure; + """ + cursor.execute(query) + values = cursor.fetchall() + for i in values: + query_insert = """ +INSERT INTO enp_envdata (time, equipment_id, is_online, is_runing, temperature, pressure) values (%s, %s, true, true, %s, %s) + """ + try: + cursor.execute(query_insert, (i[0], i[1], i[2], i[3])) + except (Exception, psycopg2.Error) as error: + print(error.pgerror) + conn.commit()