diff --git a/assets/icons/automation_records.svg b/assets/icons/automation_records.svg
new file mode 100644
index 00000000..2f5a1038
--- /dev/null
+++ b/assets/icons/automation_records.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/water_leak_detected.svg b/assets/icons/water_leak_detected.svg
new file mode 100644
index 00000000..3d6f13b0
--- /dev/null
+++ b/assets/icons/water_leak_detected.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/water_leak_normal.svg b/assets/icons/water_leak_normal.svg
new file mode 100644
index 00000000..f1165c07
--- /dev/null
+++ b/assets/icons/water_leak_normal.svg
@@ -0,0 +1,11 @@
+
diff --git a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart
index f9429bd6..d4b5b21a 100644
--- a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart
+++ b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart
@@ -30,6 +30,8 @@ import 'package:syncrow_web/pages/device_managment/wall_sensor/view/wall_sensor_
import 'package:syncrow_web/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/view/water_heater_batch_control.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/view/water_heater_device_control.dart';
+import 'package:syncrow_web/pages/device_managment/water_leak/view/water_leak_batch_control_view.dart';
+import 'package:syncrow_web/pages/device_managment/water_leak/view/water_leak_control_view.dart';
import '../../one_g_glass_switch/view/one_gang_glass_switch_control_view.dart';
@@ -88,6 +90,10 @@ mixin RouteControlsBasedCode {
return GarageDoorControlView(
deviceId: device.uuid!,
);
+ case 'WL':
+ return WaterLeakView(
+ deviceId: device.uuid!,
+ );
default:
return const SizedBox();
}
@@ -211,6 +217,13 @@ mixin RouteControlsBasedCode {
.map((e) => e.uuid!)
.toList(),
);
+ case 'WL':
+ return WaterLeakBatchControlView(
+ deviceIds: devices
+ .where((e) => (e.productType == 'WL'))
+ .map((e) => e.uuid!)
+ .toList(),
+ );
default:
return const SizedBox();
}
diff --git a/lib/pages/device_managment/shared/table/report_table.dart b/lib/pages/device_managment/shared/table/report_table.dart
index 527ae783..892bdd1a 100644
--- a/lib/pages/device_managment/shared/table/report_table.dart
+++ b/lib/pages/device_managment/shared/table/report_table.dart
@@ -14,6 +14,7 @@ class ReportsTable extends StatelessWidget {
bool? hideValueShowDescription;
bool? mainDoorSensor;
bool? garageDoorSensor;
+ bool? waterLeak;
ReportsTable({
super.key,
@@ -25,6 +26,7 @@ class ReportsTable extends StatelessWidget {
this.hideValueShowDescription,
this.mainDoorSensor,
this.garageDoorSensor,
+ this.waterLeak,
});
@override
@@ -55,7 +57,8 @@ class ReportsTable extends StatelessWidget {
DeviceEvent data = entry.value;
// Parse eventTime into Date and Time
- DateTime eventDateTime = DateTime.fromMillisecondsSinceEpoch(data.eventTime!);
+ DateTime eventDateTime =
+ DateTime.fromMillisecondsSinceEpoch(data.eventTime!);
String date = DateFormat('dd/MM/yyyy').format(eventDateTime);
String time = DateFormat('HH:mm').format(eventDateTime);
@@ -63,8 +66,12 @@ class ReportsTable extends StatelessWidget {
if (hideValueShowDescription == true) {
if (mainDoorSensor != null && mainDoorSensor == true) {
value = data.value == 'true' ? 'Open' : 'Close';
- } else if (garageDoorSensor != null && garageDoorSensor == true) {
+ } else if (garageDoorSensor != null &&
+ garageDoorSensor == true) {
value = data.value == 'true' ? 'Opened' : 'Closed';
+ } else if (waterLeak != null && waterLeak == true) {
+ value =
+ data.value == 'normal' ? 'Normal' : 'Leak Detected';
} else {
value = '${data.value!} ${thirdColumnDescription ?? ''}';
}
diff --git a/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart b/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart
new file mode 100644
index 00000000..f1063dc9
--- /dev/null
+++ b/lib/pages/device_managment/water_leak/bloc/water_leak_bloc.dart
@@ -0,0 +1,173 @@
+import 'package:bloc/bloc.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
+import 'package:syncrow_web/pages/device_managment/water_leak/bloc/water_leak_event.dart';
+import 'package:syncrow_web/pages/device_managment/water_leak/bloc/water_leak_state.dart';
+import 'package:syncrow_web/pages/device_managment/water_leak/model/water_leak_status_model.dart';
+
+import 'dart:async';
+
+import 'package:syncrow_web/services/devices_mang_api.dart';
+
+class WaterLeakBloc extends Bloc {
+ WaterLeakStatusModel? deviceStatus;
+ Timer? _timer;
+ final String deviceId;
+
+ WaterLeakBloc(this.deviceId) : super(WaterLeakInitialState()) {
+ on(_onFetchWaterLeakStatus);
+ on(_onControl);
+ on(_onBatchControl);
+ on(_onFetchBatchStatus);
+ on(_onFetchWaterLeakReports);
+ on(_onFactoryReset);
+ }
+
+ Future _onFetchWaterLeakStatus(
+ FetchWaterLeakStatusEvent event, Emitter emit) async {
+ emit(WaterLeakLoadingState());
+ try {
+ final response =
+ await DevicesManagementApi().getDeviceStatus(event.deviceId);
+ deviceStatus = WaterLeakStatusModel.fromJson(deviceId, response.status);
+ emit(WaterLeakLoadedState(deviceStatus!));
+ } catch (e) {
+ emit(WaterLeakErrorState(e.toString()));
+ }
+ }
+
+ Future _onControl(
+ WaterLeakControlEvent event, Emitter emit) async {
+ final oldValue = deviceStatus!.watersensorState;
+
+ _updateLocalValue(event.code, event.value);
+ emit(WaterLeakLoadedState(deviceStatus!));
+
+ await _runDebounce(
+ deviceId: event.deviceId,
+ code: event.code,
+ value: event.value,
+ oldValue: oldValue,
+ emit: emit,
+ isBatch: false,
+ );
+ }
+
+ Future _onFactoryReset(
+ WaterLeakFactoryResetEvent event, Emitter emit) async {
+ emit(WaterLeakLoadingState());
+ try {
+ final response = await DevicesManagementApi().factoryReset(
+ event.factoryReset,
+ event.deviceId,
+ );
+ if (response) {
+ emit(WaterLeakInitialState());
+ } else {
+ emit(const WaterLeakErrorState('Factory reset failed'));
+ }
+ } catch (e) {
+ emit(WaterLeakErrorState(e.toString()));
+ }
+ }
+
+ Future _onBatchControl(
+ WaterLeakBatchControlEvent event, Emitter emit) async {
+ final oldValue = deviceStatus!.watersensorState;
+
+ _updateLocalValue(event.code, event.value);
+ emit(WaterLeakBatchStatusLoadedState(deviceStatus!));
+
+ await _runDebounce(
+ deviceId: event.deviceIds,
+ code: event.code,
+ value: event.value,
+ oldValue: oldValue,
+ emit: emit,
+ isBatch: true,
+ );
+ }
+
+ Future _onFetchBatchStatus(FetchWaterLeakBatchStatusEvent event,
+ Emitter emit) async {
+ emit(WaterLeakLoadingState());
+ try {
+ final response =
+ await DevicesManagementApi().getBatchStatus(event.deviceIds);
+ deviceStatus = WaterLeakStatusModel.fromJson(deviceId, response.status);
+ emit(WaterLeakBatchStatusLoadedState(deviceStatus!));
+ } catch (e) {
+ emit(WaterLeakErrorState(e.toString()));
+ }
+ }
+
+ Future _runDebounce({
+ required dynamic deviceId,
+ required String code,
+ required dynamic value,
+ required dynamic oldValue,
+ required Emitter emit,
+ required bool isBatch,
+ }) async {
+ late String id;
+ if (deviceId is List) {
+ id = deviceId.first;
+ } else {
+ id = deviceId;
+ }
+
+ if (_timer != null) {
+ _timer!.cancel();
+ }
+
+ _timer = Timer(const Duration(milliseconds: 500), () async {
+ try {
+ late bool response;
+ if (isBatch) {
+ response = await DevicesManagementApi()
+ .deviceBatchControl(deviceId, code, value);
+ } else {
+ response = await DevicesManagementApi()
+ .deviceControl(deviceId, Status(code: code, value: value));
+ }
+
+ if (!response) {
+ _revertValueAndEmit(id, code, oldValue, emit);
+ }
+ } catch (e) {
+ _revertValueAndEmit(id, code, oldValue, emit);
+ }
+ });
+ }
+
+ void _updateLocalValue(String code, dynamic value) {
+ if (code == 'watersensor_state') {
+ deviceStatus = deviceStatus!.copyWith(watersensorState: value);
+ } else if (code == 'battery_percentage') {
+ deviceStatus = deviceStatus!.copyWith(batteryPercentage: value);
+ }
+ }
+
+ void _revertValueAndEmit(String deviceId, String code, dynamic oldValue,
+ Emitter emit) {
+ _updateLocalValue(code, oldValue);
+ emit(WaterLeakLoadedState(deviceStatus!));
+ }
+
+ Future _onFetchWaterLeakReports(
+ FetchWaterLeakReportsEvent event, Emitter emit) async {
+ emit(WaterLeakReportsLoadingState());
+ try {
+ final from = DateTime.now()
+ .subtract(const Duration(days: 30))
+ .millisecondsSinceEpoch;
+ final to = DateTime.now().millisecondsSinceEpoch;
+ final DeviceReport records =
+ await DevicesManagementApi.getDeviceReportsByDate(
+ event.deviceId, event.code, from.toString(), to.toString());
+ emit(WaterLeakReportsLoadedState(records));
+ } catch (e) {
+ emit(WaterLeakReportsFailedState(e.toString()));
+ }
+ }
+}
diff --git a/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart b/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart
new file mode 100644
index 00000000..9c048280
--- /dev/null
+++ b/lib/pages/device_managment/water_leak/bloc/water_leak_event.dart
@@ -0,0 +1,87 @@
+import 'package:equatable/equatable.dart';
+import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
+
+abstract class WaterLeakEvent extends Equatable {
+ const WaterLeakEvent();
+
+ @override
+ List