// Modèles Modbus RTU — calqués exactement sur l'introspection nymea // (docs/reference/jsonRPC.txt, namespace ModbusRtu). Valeurs d'enum = les // chaînes fil préfixées ; aucun champ inventé. /// Port série exposé par l'hôte (`ModbusRtu.GetSerialPorts` → `SerialPort`). /// L'identifiant passé en paramètre `serialPort` est [systemLocation]. class SerialPort { final String systemLocation; // ex. /dev/ttyUSB0 — c'est l'id à envoyer final String description; final String manufacturer; final String serialNumber; const SerialPort({ required this.systemLocation, this.description = '', this.manufacturer = '', this.serialNumber = '', }); factory SerialPort.fromJson(Map j) => SerialPort( systemLocation: (j['systemLocation'] as String?) ?? '', description: (j['description'] as String?) ?? '', manufacturer: (j['manufacturer'] as String?) ?? '', serialNumber: (j['serialNumber'] as String?) ?? '', ); String get label => description.isNotEmpty ? '$systemLocation · $description' : systemLocation; } /// Master Modbus RTU configuré (`ModbusRtu.GetModbusRtuMasters`). class ModbusRtuMaster { final String modbusUuid; final String serialPort; final int baudrate; final String parity; // enum SerialPortParity (valeur fil) final String dataBits; // enum SerialPortDataBits final String stopBits; // enum SerialPortStopBits final int numberOfRetries; final int timeout; // ms final bool connected; const ModbusRtuMaster({ required this.modbusUuid, required this.serialPort, required this.baudrate, required this.parity, required this.dataBits, required this.stopBits, required this.numberOfRetries, required this.timeout, this.connected = false, }); factory ModbusRtuMaster.fromJson(Map j) => ModbusRtuMaster( modbusUuid: (j['modbusUuid'] as String?) ?? '', serialPort: (j['serialPort'] as String?) ?? '', baudrate: (j['baudrate'] as num?)?.toInt() ?? 0, parity: (j['parity'] as String?) ?? kDefaultParity, dataBits: (j['dataBits'] as String?) ?? kDefaultDataBits, stopBits: (j['stopBits'] as String?) ?? kDefaultStopBits, numberOfRetries: (j['numberOfRetries'] as num?)?.toInt() ?? 0, timeout: (j['timeout'] as num?)?.toInt() ?? 0, connected: j['connected'] == true, ); /// Résumé compact « 9600 bps · 8N1 ». String get summary => '$baudrate bps · ${dataBitsLabel(dataBits)}${parityShort(parity)}${stopBitsShort(stopBits)}'; } // ── Valeurs autorisées (dropdowns contraints) ──────────────────────────────── /// Baudrates standard proposés. À l'édition, la valeur courante du master est /// ajoutée si non standard (voir l'écran). const List kBaudrates = [9600, 19200, 38400, 57600, 115200]; /// Enum SerialPortParity — sans la sentinelle `Unknown`. const List kParityValues = [ 'SerialPortParityNoParity', 'SerialPortParityEvenParity', 'SerialPortParityOddParity', 'SerialPortParitySpaceParity', 'SerialPortParityMarkParity', ]; /// Enum SerialPortDataBits — sans `Unknown`. const List kDataBitsValues = [ 'SerialPortDataBitsData5', 'SerialPortDataBitsData6', 'SerialPortDataBitsData7', 'SerialPortDataBitsData8', ]; /// Enum SerialPortStopBits — sans `Unknown`. const List kStopBitsValues = [ 'SerialPortStopBitsOneStop', 'SerialPortStopBitsOneAndHalfStop', 'SerialPortStopBitsTwoStop', ]; // Défauts Modbus RTU classiques : 9600 8N1, 3 retries, 1000 ms. const String kDefaultParity = 'SerialPortParityNoParity'; const String kDefaultDataBits = 'SerialPortDataBitsData8'; const String kDefaultStopBits = 'SerialPortStopBitsOneStop'; const int kDefaultBaudrate = 9600; const int kDefaultRetries = 3; const int kDefaultTimeout = 1000; // ── Labels d'affichage ─────────────────────────────────────────────────────── String parityLabel(String v) => switch (v) { 'SerialPortParityNoParity' => 'Aucune (N)', 'SerialPortParityEvenParity' => 'Paire (E)', 'SerialPortParityOddParity' => 'Impaire (O)', 'SerialPortParitySpaceParity' => 'Space', 'SerialPortParityMarkParity' => 'Mark', _ => v, }; String parityShort(String v) => switch (v) { 'SerialPortParityNoParity' => 'N', 'SerialPortParityEvenParity' => 'E', 'SerialPortParityOddParity' => 'O', 'SerialPortParitySpaceParity' => 'S', 'SerialPortParityMarkParity' => 'M', _ => '?', }; String dataBitsLabel(String v) => switch (v) { 'SerialPortDataBitsData5' => '5', 'SerialPortDataBitsData6' => '6', 'SerialPortDataBitsData7' => '7', 'SerialPortDataBitsData8' => '8', _ => '?', }; String stopBitsLabel(String v) => switch (v) { 'SerialPortStopBitsOneStop' => '1', 'SerialPortStopBitsOneAndHalfStop' => '1.5', 'SerialPortStopBitsTwoStop' => '2', _ => '?', }; String stopBitsShort(String v) => switch (v) { 'SerialPortStopBitsOneStop' => '1', 'SerialPortStopBitsOneAndHalfStop' => '1.5', 'SerialPortStopBitsTwoStop' => '2', _ => '?', }; /// Mappe un `ModbusRtuError` fil → message lisible (français). Chaîne vide pour /// `NoError`. String modbusErrorMessage(String code) => switch (code) { 'ModbusRtuErrorNoError' => '', 'ModbusRtuErrorNotAvailable' => 'Service Modbus RTU indisponible sur la box.', 'ModbusRtuErrorUuidNotFound' => 'Master introuvable (déjà supprimé ?).', 'ModbusRtuErrorHardwareNotFound' => 'Port série introuvable (adaptateur débranché ?).', 'ModbusRtuErrorResourceBusy' => 'Port série occupé par un autre processus.', 'ModbusRtuErrorNotSupported' => 'Opération non supportée.', 'ModbusRtuErrorInvalidTimeoutValue' => 'Timeout invalide (minimum 10 ms).', 'ModbusRtuErrorConnectionFailed' => 'Échec de connexion au port série.', _ => 'Erreur Modbus : $code', };