diff --git a/backend/sitemanagement/models.py b/backend/sitemanagement/models.py index 5bc7952..8fe2556 100644 --- a/backend/sitemanagement/models.py +++ b/backend/sitemanagement/models.py @@ -4,7 +4,7 @@ from decimal import Decimal class Multiplexor(models.Model): """Устройство-мультиплексор""" - name = models.CharField(max_length=50, unique=True) + 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) @@ -19,14 +19,14 @@ 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")) + 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""" @@ -34,6 +34,10 @@ class SensorType(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True, null=True) + # пороговые значения для всех сенсоров этого типа + min_value = models.DecimalField(max_digits=12, decimal_places=4, null=True, blank=True) + max_value = models.DecimalField(max_digits=12, decimal_places=4, null=True, blank=True) + def __str__(self): return self.code @@ -44,7 +48,6 @@ class SignalFormat(models.Model): 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") @@ -80,4 +83,32 @@ class Metric(models.Model): ] 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 + return f"{self.timestamp} {self.sensor} = {self.value} {self.sensor.signal_format.unit if self.sensor.signal_format else ''}" + + +class Alert(models.Model): + """Тревоги по метрикам""" + sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE, related_name="alerts") + metric = models.ForeignKey(Metric, on_delete=models.CASCADE, related_name="alerts") + sensor_type = models.ForeignKey(SensorType, on_delete=models.CASCADE, related_name="alerts") + message = models.CharField(max_length=255) + severity = models.CharField( + max_length=20, + choices=[ + ("warning", "Warning"), + ("critical", "Critical"), + ], + default="warning" + ) + created_at = models.DateTimeField(auto_now_add=True) + resolved = models.BooleanField(default=False) + + class Meta: + indexes = [ + models.Index(fields=["created_at"]), + models.Index(fields=["sensor"]), + models.Index(fields=["sensor_type"]), + ] + + def __str__(self): + return f"ALERT {self.sensor} @ {self.metric.timestamp}: {self.message}" \ No newline at end of file