From 9ad319d03a3083afd3c53afd6034dff5ccd702f5 Mon Sep 17 00:00:00 2001 From: Timofey Date: Mon, 18 Aug 2025 10:33:25 +0300 Subject: [PATCH] feat / AEB-21 create db schema --- backend/sitemanagement/models.py | 82 +++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/backend/sitemanagement/models.py b/backend/sitemanagement/models.py index 71a8362..5bc7952 100644 --- a/backend/sitemanagement/models.py +++ b/backend/sitemanagement/models.py @@ -1,3 +1,83 @@ from django.db import models +from decimal import Decimal -# Create your models here. + +class Multiplexor(models.Model): + """Устройство-мультиплексор""" + name = models.CharField(max_length=50, unique=True) + ip = models.GenericIPAddressField(null=True, blank=True) + subnet = models.GenericIPAddressField(null=True, blank=True) + gateway = models.GenericIPAddressField(null=True, blank=True) + sd_path = models.CharField(max_length=255, null=True, blank=True) + + def __str__(self): + return self.name + + +class Channel(models.Model): + """Физический канал мультиплексора""" + multiplexor = models.ForeignKey(Multiplexor, on_delete=models.CASCADE, related_name="channels") + number = models.PositiveSmallIntegerField() # CH-1 ... CH-14 + # для "полканалов" можно использовать дробное значение (1, 1.5, 2, ...) + position = models.DecimalField(max_digits=4, decimal_places=1, default=Decimal("1.0")) + + class Meta: + unique_together = ("multiplexor", "number", "position") + + def __str__(self): + return f"{self.multiplexor.name} - CH{self.number} ({self.position})" + + +class SensorType(models.Model): + """Тип датчика: GA, PE, GLE""" + code = models.CharField(max_length=10, unique=True) # GA, PE, GLE + name = models.CharField(max_length=100) + description = models.TextField(blank=True, null=True) + + def __str__(self): + return self.code + + +class SignalFormat(models.Model): + """Формат сигнала и правило преобразования""" + sensor_type = models.ForeignKey(SensorType, on_delete=models.CASCADE, related_name="formats") + code = models.CharField(max_length=50) # например "4-20мА", "VW f<1600Hz", "NTC R>250Ohm" + unit = models.CharField(max_length=20, blank=True, null=True) # °C, мкм/м, мм и т.п. + conversion_rule = models.CharField(max_length=255, blank=True, null=True) + # можно хранить Python-путь к функции конвертации, например "sensors.convert.ga_current_to_angle" + + class Meta: + unique_together = ("sensor_type", "code") + + def __str__(self): + return f"{self.sensor_type.code} - {self.code}" + + +class Sensor(models.Model): + """Конкретный датчик, установленный в канале""" + channel = models.ForeignKey(Channel, on_delete=models.CASCADE, related_name="sensors") + sensor_type = models.ForeignKey(SensorType, on_delete=models.CASCADE) + signal_format = models.ForeignKey(SignalFormat, on_delete=models.SET_NULL, null=True, blank=True) + serial_number = models.CharField(max_length=50, blank=True, null=True) # CL 2106009 + name = models.CharField(max_length=50, blank=True, null=True) # GA-1, HLE-1 и т.п. + + def __str__(self): + return f"{self.name or self.sensor_type.code} ({self.serial_number})" + + +class Metric(models.Model): + """Значения, которые приходят из CSV""" + timestamp = models.DateTimeField() + sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE, related_name="metrics") + raw_value = models.CharField(max_length=50) # исходное значение из файла (например "11.964 (A)") + value = models.FloatField(null=True, blank=True) # преобразованное значение + status = models.CharField(max_length=20, blank=True, null=True) # No Rx, Error, NotAv и т.д. + + class Meta: + indexes = [ + models.Index(fields=["timestamp"]), + models.Index(fields=["sensor"]), + ] + + def __str__(self): + return f"{self.timestamp} {self.sensor} = {self.value} {self.sensor.signal_format.unit if self.sensor.signal_format else ''}" \ No newline at end of file