Files
aerbim-ht-monitor/backend/sitemanagement/models.py
2025-08-18 10:56:37 +03:00

114 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.db import models
from decimal import Decimal
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)
# пороговые значения для всех сенсоров этого типа
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
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)
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 ''}"
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}"