deb04c9315
Sprint 0 completo del producto VMS-Sailor (Vessel Management System integrado para buques 30-40m). Brief de referencia en VMS_Sailor_v2_Parte_*.md (intacto). Core (vmssailor.core, 95.17% coverage, 99 tests verde): - ShipCoord: sistema naval x_pp/y_cl/z_bl frozen - Vessel, Deck, Bulkhead - Equipment, EquipmentModel, Sensor, EquipmentSpec - Tag, AlarmConfig, TagBinding, Scaling - CardInstance, Bus, Topology con validacion 21 puntos I/O AR-NMEA-IO-v1.0 - Alarm, PermissiveRule, Condition - Project agregado raiz con validacion cross-entity - Persistencia portable .vmsproj (SQLite) con roundtrip verificable Biblioteca curada seed (vmssailor.library): - systems_catalog.json completo (catalogo maestro Parte 1 sec 7) - 2 vessels: Sunseeker 76, Ferretti 850 - 2 motores: MTU 12V 2000 M96, Volvo D13-900 - 1 genset: Northern Lights M65C13 - yacht_motor_planeo.yaml (reglas heuristicas) - TODO marcado data_source=seed_estimate - requiere validacion datasheets Tools: - vms-validate-library: CLI valida biblioteca completa - vms-generate-test-project: CLI demo + verificacion roundtrip persistencia Design System + 8 mockups HTML estaticos: - docs/design_system.md (paleta Deep Ocean, gradientes, typography, motion) - docs/brand/ (logo + variantes SVG) - docs/mockups/splash, studio_main, runtime_overview, runtime_mimic_fuel (P&ID animado), runtime_alarms, runtime_trim (panel estrella con horizonte artificial), mobile_overview, mobile_trim - docs/mockups/index.html (galeria) Firmware (Sprint 12+ implementacion): - firmware/ar_nmea_io_v1/src/config/pinout.h con macros GPIO Decisiones autonomas documentadas en docs/decisions_sprint0.md. Stack: Python 3.11 + uv + Pydantic v2 + SQLite stdlib + hatchling + pytest 9 + ruff + mypy. Sin PySide6, FastAPI, Flutter ni firmware funcional (entran en sprints siguientes). Criterio de aceptacion Sprint 0: cumplido. - uv sync: OK - pytest: 99/99 verde - cov vmssailor.core: 95.17% (objetivo >=80%) - ruff: clean - vms-validate-library: OK - vms-generate-test-project: INTEGRIDAD OK Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
360 lines
9.8 KiB
Python
360 lines
9.8 KiB
Python
"""Enums del modelo de datos core.
|
|
|
|
Toda enumeración del producto vive aquí para tener una única fuente de
|
|
verdad y poder serializarla consistentemente a `.vmsproj` y `.vmspack`.
|
|
|
|
Convención de valores: snake_case_minúsculas ASCII para que sean estables
|
|
en JSON/YAML/SQLite sin problemas de encoding.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from enum import StrEnum
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Buque
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class VesselType(StrEnum):
|
|
"""Categoría principal del buque (Parte 2 sec 3, Paso 1)."""
|
|
|
|
YACHT_MOTOR = "yacht_motor"
|
|
YACHT_SAIL = "yacht_sail"
|
|
FISHING = "fishing"
|
|
PATROL = "patrol"
|
|
FERRY = "ferry"
|
|
OFFSHORE_SUPPORT = "offshore_support"
|
|
|
|
|
|
class VesselSubtype(StrEnum):
|
|
"""Subcategoría que afina el tipo principal."""
|
|
|
|
# Yacht motor
|
|
PLANING = "planing"
|
|
SEMI_PLANING = "semi_planing"
|
|
DISPLACEMENT = "displacement"
|
|
# Fishing
|
|
PURSE_SEINER = "purse_seiner" # cerquero
|
|
TRAWLER = "trawler" # arrastrero
|
|
LONGLINER = "longliner" # palangrero
|
|
# Patrol
|
|
COASTAL = "coastal"
|
|
OCEANIC = "oceanic"
|
|
# Ferry
|
|
PASSENGER = "passenger"
|
|
ROLL_ON_ROLL_OFF = "ro_ro"
|
|
# Offshore support
|
|
AHTS = "ahts" # Anchor Handling Tug Supply
|
|
PSV = "psv" # Platform Supply Vessel
|
|
# Catch-all
|
|
OTHER = "other"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Catálogo maestro de sistemas (Parte 1 sec 7)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class SystemId(StrEnum):
|
|
"""ID estable de cada sistema del catálogo maestro.
|
|
|
|
Coincide con `vmssailor/library/systems_catalog.json`. El menú lateral del
|
|
Runtime se genera a partir de los sistemas que el proyecto tenga
|
|
habilitados.
|
|
"""
|
|
|
|
# Propulsión y maquinaria
|
|
MAIN_ENGINE = "main_engine"
|
|
TRANSMISSION = "transmission"
|
|
SHAFT_PROPELLER = "shaft_propeller"
|
|
THRUSTER = "thruster"
|
|
# Maniobra y trimado
|
|
TRIM_STERNDRIVE = "trim_sterndrive"
|
|
TRIM_TABS = "trim_tabs"
|
|
CPP = "cpp"
|
|
GYROSTABILIZER = "gyrostabilizer"
|
|
FIN_STABILIZER = "fin_stabilizer"
|
|
JOYSTICK_DOCKING = "joystick_docking"
|
|
# Generación eléctrica
|
|
GENSET = "genset"
|
|
SHORE_POWER = "shore_power"
|
|
INVERTER_CHARGER = "inverter_charger"
|
|
BATTERY_BANK = "battery_bank"
|
|
MSB = "msb"
|
|
ESB = "esb"
|
|
UPS = "ups"
|
|
SOLAR = "solar"
|
|
SMART_DC_BUSBAR = "smart_dc_busbar"
|
|
SMART_PANEL = "smart_panel"
|
|
# Aislamiento eléctrico
|
|
SECTIONALIZING = "sectionalizing"
|
|
EMERGENCY_ISOLATION = "emergency_isolation"
|
|
BREAKERS = "breakers"
|
|
LOCKOUT_TAGOUT = "lockout_tagout"
|
|
# Fluidos
|
|
FUEL = "fuel"
|
|
LUBE_OIL = "lube_oil"
|
|
HYDRAULIC_OIL = "hydraulic_oil"
|
|
FW_COOLING = "fw_cooling"
|
|
SW_COOLING = "sw_cooling"
|
|
STARTING_AIR = "starting_air"
|
|
BILGE = "bilge"
|
|
BALLAST = "ballast"
|
|
GREY_WATER = "grey_water"
|
|
BLACK_WATER = "black_water"
|
|
POTABLE_WATER = "potable_water"
|
|
SW_SERVICE = "sw_service"
|
|
WATERMAKER = "watermaker"
|
|
# Seguridad
|
|
FIRE_DETECTION = "fire_detection"
|
|
FIRE_EXTINGUISHING = "fire_extinguishing"
|
|
FIFI_EXTERNAL = "fifi_external"
|
|
EMERGENCY_BILGE = "emergency_bilge"
|
|
GAS_DETECTION = "gas_detection"
|
|
MOB = "mob"
|
|
# Ambiente
|
|
HVAC = "hvac"
|
|
ENGINE_VENT = "engine_vent"
|
|
HEATING = "heating"
|
|
REFRIGERATION = "refrigeration"
|
|
# Iluminación
|
|
NAV_LIGHTS = "nav_lights"
|
|
DECK_LIGHTS = "deck_lights"
|
|
INTERIOR_LIGHTS = "interior_lights"
|
|
EMERGENCY_LIGHTS = "emergency_lights"
|
|
SEARCHLIGHTS = "searchlights"
|
|
# Tanques estructurales
|
|
FUEL_TANKS = "fuel_tanks"
|
|
WATER_TANKS = "water_tanks"
|
|
GREY_BLACK_TANKS = "grey_black_tanks"
|
|
VOIDS = "voids"
|
|
COFFERDAMS = "cofferdams"
|
|
# Cubierta y maniobra
|
|
WINDLASS = "windlass"
|
|
ANCHOR_SYSTEM = "anchor_system"
|
|
MOORING = "mooring"
|
|
DAVITS = "davits"
|
|
GANGWAY = "gangway"
|
|
CRANE = "crane"
|
|
# Específicos por tipo
|
|
FISHING_MACHINERY = "fishing_machinery"
|
|
LARGE_FRIDGE_HOLDS = "large_fridge_holds"
|
|
ROV = "rov"
|
|
DIVING_SYSTEM = "diving_system"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Equipos
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class EquipmentCategory(StrEnum):
|
|
"""Categoría de un EquipmentModel para clasificar la biblioteca."""
|
|
|
|
ENGINE_MAIN = "engine_main"
|
|
GENSET = "genset"
|
|
PUMP = "pump"
|
|
VALVE = "valve"
|
|
TANK = "tank"
|
|
HEAT_EXCHANGER = "heat_exchanger"
|
|
FILTER_SEPARATOR = "filter_separator"
|
|
COMPRESSOR = "compressor"
|
|
SENSOR = "sensor"
|
|
INDICATOR = "indicator"
|
|
BREAKER = "breaker"
|
|
INVERTER = "inverter"
|
|
BATTERY = "battery"
|
|
THRUSTER = "thruster"
|
|
STABILIZER = "stabilizer"
|
|
WATERMAKER = "watermaker"
|
|
LIGHTING = "lighting"
|
|
HVAC_UNIT = "hvac_unit"
|
|
OTHER = "other"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Señales físicas y canales de tarjeta
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ChannelType(StrEnum):
|
|
"""Tipo de canal físico en la tarjeta AR-NMEA-IO-v1.0."""
|
|
|
|
AI = "ai" # Analog Input (4 por tarjeta)
|
|
DI = "di" # Digital Input (5 por tarjeta)
|
|
DO = "do" # Digital Output (10 por tarjeta)
|
|
RPM = "rpm" # Frequency input (1 por tarjeta)
|
|
|
|
|
|
class SignalType(StrEnum):
|
|
"""Tipo eléctrico de la señal conectada a un canal."""
|
|
|
|
# Analógicas
|
|
SIG_4_20_MA = "4-20ma"
|
|
SIG_0_10_V = "0-10v"
|
|
SIG_0_5_V = "0-5v"
|
|
RTD_PT100 = "rtd_pt100"
|
|
RTD_PT1000 = "rtd_pt1000"
|
|
THERMOCOUPLE_K = "thermocouple_k"
|
|
THERMOCOUPLE_J = "thermocouple_j"
|
|
RESISTIVE_SENDER = "resistive_sender" # tank sender, etc.
|
|
VOLTAGE_DIVIDER = "voltage_divider" # batería con divisor
|
|
# Digitales / discretas
|
|
DRY_CONTACT = "dry_contact"
|
|
CONTACT_24VDC = "contact_24vdc"
|
|
RELAY_NO = "relay_no"
|
|
RELAY_NC = "relay_nc"
|
|
# Frecuencia
|
|
PULSE_MAGNETIC_PICKUP = "pulse_magnetic_pickup"
|
|
PULSE_INDUCTIVE = "pulse_inductive"
|
|
PULSE_TACHO = "pulse_tacho"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Protocolos y buses
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class Protocol(StrEnum):
|
|
"""Protocolo por el que se accede a un tag."""
|
|
|
|
MODBUS_RTU = "modbus_rtu"
|
|
MODBUS_TCP = "modbus_tcp"
|
|
NMEA2000 = "nmea2000"
|
|
J1939 = "j1939"
|
|
INTERNAL = "internal" # tags virtuales calculados, no van al bus
|
|
|
|
|
|
class BusRole(StrEnum):
|
|
"""Rol de una tarjeta en su bus (Parte 2 sec 3, Paso 7)."""
|
|
|
|
MODBUS_SLAVE = "modbus_slave"
|
|
MODBUS_MASTER = "modbus_master"
|
|
NMEA2000_NODE = "nmea2000_node"
|
|
DUAL = "dual" # Modbus + NMEA 2000 simultáneo
|
|
BRIDGE = "bridge" # Lee NMEA 2000, expone como Modbus
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Filtros locales (firmware tarjeta)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class FilterType(StrEnum):
|
|
"""Filtro local que aplica la tarjeta antes de reportar (Parte 4 sec 7)."""
|
|
|
|
NONE = "none"
|
|
MOVING_AVG = "moving_avg"
|
|
MEDIAN = "median"
|
|
DEADBAND = "deadband"
|
|
RATE_LIMIT = "rate_limit"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tags: control, autoridad, calidad
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ControlMode(StrEnum):
|
|
"""Estado del tag respecto a control.
|
|
|
|
Filosofía monitor-now / control-later: todos los tags se definen con
|
|
capacidad de control desde el día 1 aunque empiecen como MONITOR.
|
|
"""
|
|
|
|
MONITOR = "monitor"
|
|
MANUAL = "manual"
|
|
AUTO = "auto"
|
|
FUTURE = "future" # actuador físico aún no instalado
|
|
|
|
|
|
class AuthorityRequired(StrEnum):
|
|
"""Qué estación debe tener autoridad para ejecutar el control."""
|
|
|
|
BRIDGE = "bridge"
|
|
ENGINE = "engine"
|
|
EITHER = "either"
|
|
|
|
|
|
class Quality(StrEnum):
|
|
"""Calidad del valor leído (OPC UA estilo)."""
|
|
|
|
GOOD = "good"
|
|
BAD = "bad"
|
|
UNCERTAIN = "uncertain"
|
|
STALE = "stale" # último conocido pero sensor offline
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Alarmas
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class AlarmPriority(StrEnum):
|
|
"""Prioridad de alarma (Parte 3 sec 3, Parte 1 sec 6)."""
|
|
|
|
EMERGENCY = "emergency"
|
|
HIGH = "high"
|
|
LOW = "low"
|
|
INFO = "info"
|
|
|
|
|
|
class AlarmState(StrEnum):
|
|
"""Estado de una alarma activa."""
|
|
|
|
ACTIVE = "active" # disparada, no ack
|
|
ACK = "ack" # ack pero condición persiste
|
|
CLEARED = "cleared" # condición resuelta
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Unidades SI obligatorias internas
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class UnitSI(StrEnum):
|
|
"""Lista cerrada de unidades SI permitidas en `Tag.unit_si` / `Sensor.unit_si`.
|
|
|
|
Regla de oro: todo internamente en SI. Conversión a imperial solo en UI.
|
|
"""
|
|
|
|
# Sin unidad / boolean
|
|
NONE = "none"
|
|
BOOL = "bool"
|
|
PERCENT = "%"
|
|
# Eléctricas
|
|
VOLT = "V"
|
|
AMPERE = "A"
|
|
WATT = "W"
|
|
KILOWATT = "kW"
|
|
KILOWATT_HOUR = "kWh"
|
|
HERTZ = "Hz"
|
|
OHM = "ohm"
|
|
# Mecánicas
|
|
RPM = "rpm"
|
|
NEWTON_METER = "Nm"
|
|
METER = "m"
|
|
METER_PER_SECOND = "m/s"
|
|
METER_PER_SECOND_SQ = "m/s2"
|
|
DEGREE = "deg"
|
|
DEGREE_PER_SECOND = "deg/s"
|
|
# Fluidos
|
|
PASCAL = "Pa"
|
|
KILOPASCAL = "kPa"
|
|
BAR = "bar"
|
|
LITER = "L"
|
|
CUBIC_METER = "m3"
|
|
LITER_PER_HOUR = "L/h"
|
|
LITER_PER_MINUTE = "L/min"
|
|
CUBIC_METER_PER_HOUR = "m3/h"
|
|
# Térmicas
|
|
DEGREE_CELSIUS = "C"
|
|
KELVIN = "K"
|
|
# Tiempo
|
|
SECOND = "s"
|
|
HOUR = "h"
|
|
# Masa
|
|
KILOGRAM = "kg"
|
|
TONNE = "t"
|