- modbus_models.dart : ModbusRtuMaster, SerialPort, enums parity/dataBits/stopBits, modbusErrorMessage() - nymea_service : 5 RPC typées (GetSerialPorts, GetModbusRtuMasters, Add/Reconfigure/Remove), erreurs ModbusRtuError -> FR, guards sim/déco - protocols_screen : liste + empty state, form add/edit (dropdowns contraints), suppression confirmée (avert. orphelinage), garde-fou installateur - main.dart : route /settings/system/protocols (remplace le stub) Validé contre nymea réel (hems .75) : champs/enums/modbusError confirmés, cas port USB absent géré. Réf. UI_DATA_CONTRACT.md §6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
169 lines
6.1 KiB
Dart
169 lines
6.1 KiB
Dart
// 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<String, dynamic> 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<String, dynamic> 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<int> kBaudrates = [9600, 19200, 38400, 57600, 115200];
|
|
|
|
/// Enum SerialPortParity — sans la sentinelle `Unknown`.
|
|
const List<String> kParityValues = [
|
|
'SerialPortParityNoParity',
|
|
'SerialPortParityEvenParity',
|
|
'SerialPortParityOddParity',
|
|
'SerialPortParitySpaceParity',
|
|
'SerialPortParityMarkParity',
|
|
];
|
|
|
|
/// Enum SerialPortDataBits — sans `Unknown`.
|
|
const List<String> kDataBitsValues = [
|
|
'SerialPortDataBitsData5',
|
|
'SerialPortDataBitsData6',
|
|
'SerialPortDataBitsData7',
|
|
'SerialPortDataBitsData8',
|
|
];
|
|
|
|
/// Enum SerialPortStopBits — sans `Unknown`.
|
|
const List<String> 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',
|
|
};
|