feat / AEB-62 add additional DB schema for objects logic

This commit is contained in:
Timofey
2025-10-06 14:55:46 +03:00
parent a822ea587c
commit 5a0bb27c95
11 changed files with 426 additions and 31 deletions

View File

@@ -1,6 +1,6 @@
from django.db import models
from decimal import Decimal
from sitemanagement.constants.image_file_path import register_object_upload_path
class Multiplexor(models.Model):
"""Устройство-мультиплексор"""
@@ -61,9 +61,9 @@ class SensorType(models.Model):
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)
code = models.CharField(max_length=50, verbose_name="Код") # например "4-20мА", "VW f<1600Hz", "NTC R>250Ohm"
unit = models.CharField(max_length=20, blank=True, null=True, verbose_name="Единица измерения") # °C, мкм/м, мм и т.п.
conversion_rule = models.CharField(max_length=255, blank=True, null=True, verbose_name="Правило преобразования")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
@@ -79,13 +79,13 @@ class SignalFormat(models.Model):
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 и т.п.
sensor_type = models.ForeignKey(SensorType, on_delete=models.CASCADE, verbose_name="Тип сенсора")
signal_format = models.ForeignKey(SignalFormat, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Формат сигнала")
serial_number = models.CharField(max_length=50, blank=True, null=True, verbose_name="Серийный номер") # CL 2106009
name = models.CharField(max_length=50, blank=True, null=True, verbose_name="Название") # GA-1, HLE-1 и т.п.
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
math_formula = models.CharField(null=True, blank=True, max_length=255)
math_formula = models.CharField(null=True, blank=True, max_length=255, verbose_name="Математическая формула")
class Meta:
verbose_name = "Датчик"
@@ -99,10 +99,10 @@ class Sensor(models.Model):
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 и т.д.
sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE, related_name="metrics", verbose_name="Датчик")
raw_value = models.CharField(max_length=50, verbose_name="Исходное значение") # исходное значение из файла (например "11.964 (A)")
value = models.FloatField(null=True, blank=True, verbose_name="Преобразованное значение") # преобразованное значение
status = models.CharField(max_length=20, blank=True, null=True, verbose_name="Статус") # No Rx, Error, NotAv и т.д.
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
@@ -121,21 +121,22 @@ class Metric(models.Model):
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)
sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE, related_name="alerts", verbose_name="Датчик")
metric = models.ForeignKey(Metric, on_delete=models.CASCADE, related_name="alerts", verbose_name="Метрика")
sensor_type = models.ForeignKey(SensorType, on_delete=models.CASCADE, related_name="alerts", verbose_name="Тип сенсора")
message = models.CharField(max_length=255, verbose_name="Сообщение")
severity = models.CharField(
max_length=20,
choices=[
("warning", "Warning"),
("critical", "Critical"),
],
default="warning"
default="warning",
verbose_name="Уровень тревоги"
)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
resolved = models.BooleanField(default=False)
resolved = models.BooleanField(default=False, verbose_name="Статус обработки")
class Meta:
indexes = [
@@ -148,4 +149,40 @@ class Alert(models.Model):
ordering = ["created_at", "sensor"]
def __str__(self):
return f"ALERT {self.sensor} @ {self.metric.timestamp}: {self.message}"
return f"ALERT {self.sensor} @ {self.metric.timestamp}: {self.message}"
class Object(models.Model):
"""Объект"""
title = models.CharField(max_length=255, verbose_name="Название")
description = models.TextField(blank=True, null=True, verbose_name="Описание")
image = models.ImageField(upload_to=register_object_upload_path, null=True, blank=True, verbose_name="Изображение")
address = models.CharField(max_length=255, verbose_name="Адрес")
floors = models.PositiveSmallIntegerField(verbose_name="Количество этажей")
area = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Площадь")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Объект"
verbose_name_plural = "Объекты"
ordering = ["title"]
def __str__(self):
return self.title
class Zone(models.Model):
"""Зона"""
object = models.ForeignKey(Object, on_delete=models.CASCADE, related_name="zones", verbose_name="Объект")
name = models.CharField(max_length=255, verbose_name="Название")
sensors = models.ManyToManyField(Sensor, related_name="zones", verbose_name="Датчики")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Зона"
verbose_name_plural = "Зоны"
ordering = ["object", "name"]
def __str__(self):
return f"{self.object.title} - {self.name}"