Files
cacto 45b8733d22 Каркас приложения: авторизация, зоны/устройства/правила, управление устройствами
HTTP-клиент к /api/v1 с Sanctum-токеном (хранится в secure storage),
модели зеркалят Laravel API Resources. Экраны: логин, список устройств
с живым статусом, детальная страница устройства (история телеметрии,
turn-on/turn-off/set-level с проверкой capability), списки зон и правил
автоматизации (пока только чтение — формы создания/редактирования впереди).
2026-08-12 01:12:39 +05:00

81 lines
2.6 KiB
Dart

import 'device_type.dart';
import 'zone.dart';
class Device {
Device({
required this.id,
required this.name,
required this.externalId,
required this.protocol,
required this.status,
this.zone,
this.deviceType,
});
final int id;
final String name;
final String externalId;
final String protocol;
final String status; // "online" | "offline" | "unknown"
final Zone? zone;
final DeviceType? deviceType;
factory Device.fromJson(Map<String, dynamic> json) => Device(
id: json['id'] as int,
name: json['name'] as String,
externalId: json['external_id'] as String,
protocol: json['protocol'] as String,
status: json['status'] as String? ?? 'unknown',
zone: json['zone'] is Map ? Zone.fromJson(json['zone'] as Map<String, dynamic>) : null,
deviceType: json['device_type'] is Map
? DeviceType.fromJson(json['device_type'] as Map<String, dynamic>)
: null,
);
}
/// The extra data returned only by `GET /devices/{id}`: Device Shadow
/// snapshot (Redis) plus recent telemetry readings (ClickHouse, sensors only).
class DeviceDetail {
DeviceDetail({
required this.device,
required this.lastSeen,
required this.desiredState,
required this.reportedState,
required this.telemetry,
});
final Device device;
final DateTime? lastSeen;
final Map<String, dynamic> desiredState;
final Map<String, dynamic> reportedState;
final List<TelemetryReading> telemetry;
factory DeviceDetail.fromJson(Map<String, dynamic> json) {
final shadow = json['shadow'] as Map<String, dynamic>;
return DeviceDetail(
device: Device.fromJson(json['data'] as Map<String, dynamic>),
lastSeen: shadow['last_seen'] != null ? DateTime.tryParse(shadow['last_seen'] as String) : null,
desiredState: Map<String, dynamic>.from(shadow['desired_state'] as Map? ?? const {}),
reportedState: Map<String, dynamic>.from(shadow['reported_state'] as Map? ?? const {}),
telemetry: (json['telemetry'] as List? ?? const [])
.map((e) => TelemetryReading.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
}
class TelemetryReading {
TelemetryReading({required this.sensorType, required this.value, required this.recordedAt});
final String sensorType;
final double value;
final String recordedAt;
factory TelemetryReading.fromJson(Map<String, dynamic> json) => TelemetryReading(
sensorType: json['sensor_type'] as String,
value: (json['value'] as num).toDouble(),
recordedAt: json['recorded_at'] as String,
);
}