mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
working on water heater
This commit is contained in:
@ -1,7 +1,10 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/fake_door_sensor.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
import '../models/fake_heater_device.dart';
|
||||
part 'device_managment_event.dart';
|
||||
part 'device_managment_state.dart';
|
||||
|
||||
@ -31,6 +34,11 @@ class DeviceManagementBloc
|
||||
try {
|
||||
final devices = await DevicesManagementApi().fetchDevices();
|
||||
_selectedDevices.clear();
|
||||
|
||||
/// add fake device for heater
|
||||
devices.insert(0, fakeWaterHeaterDevice);
|
||||
devices.insert(1, fakeMainDoorSensor);
|
||||
////
|
||||
_devices = devices;
|
||||
_filteredDevices = devices;
|
||||
_calculateDeviceCounts();
|
||||
|
@ -19,6 +19,7 @@ import 'package:syncrow_web/pages/device_managment/two_gang_switch/view/wall_lig
|
||||
import 'package:syncrow_web/pages/device_managment/two_gang_switch/view/wall_light_device_control.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/wall_sensor/view/wall_sensor_batch_control.dart';
|
||||
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_device_control.dart';
|
||||
|
||||
mixin RouteControlsBasedCode {
|
||||
Widget routeControlsWidgets({required AllDevicesModel device}) {
|
||||
@ -53,6 +54,8 @@ mixin RouteControlsBasedCode {
|
||||
);
|
||||
case 'AC':
|
||||
return AcDeviceControlsView(device: device);
|
||||
case 'WH':
|
||||
return WaterHeaterDeviceControl(device: device,);
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||
|
||||
AllDevicesModel fakeMainDoorSensor = AllDevicesModel(
|
||||
room: DevicesModelRoom(
|
||||
uuid: "12de8f60-7104-4726-b5f8-ea426c0c7c3d", name: "Main Hall"),
|
||||
unit: DevicesModelUnit(
|
||||
uuid: "08fd3dcf-d13a-40db-970d-d0ce893df30e", name: "Entrance Unit 1"),
|
||||
productUuid: "fake-uuid-main-door-sensor",
|
||||
productType: "DS",
|
||||
permissionType: "CONTROLLABLE",
|
||||
activeTime: 1722178888,
|
||||
category: "sensor",
|
||||
categoryName: "Door Sensor",
|
||||
createTime: 1722178888,
|
||||
gatewayId: "b49df7395gfd8c19047krmk",
|
||||
icon: "smart/icon/bay1642572935122vdsS/2b2f5fffaa5bbf81c3164fc313df2023.png",
|
||||
ip: "",
|
||||
lat: "31.92",
|
||||
localKey: "A/43+<n/![jk>:7M",
|
||||
lon: "35.85",
|
||||
model: "D03ZLSDSA2",
|
||||
name: "Main Door Sensor",
|
||||
nodeId: "70a523ffece8a7f9",
|
||||
online: true,
|
||||
ownerId: "199300932",
|
||||
sub: true,
|
||||
timeZone: "+03:00",
|
||||
updateTime: 1723627123,
|
||||
uuid: "9c32dac5-ce0c-4c85-b45c-8e16511174cg",
|
||||
batteryLevel: 85,
|
||||
);
|
@ -0,0 +1,33 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/room.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/unit.dart';
|
||||
|
||||
AllDevicesModel fakeWaterHeaterDevice = AllDevicesModel(
|
||||
room: DevicesModelRoom(
|
||||
uuid: "75ea7d60-5104-4726-b5f8-ea426c0c6a1b", name: "Kitchen"),
|
||||
unit: DevicesModelUnit(
|
||||
uuid: "04fd1dcf-f24a-40db-970d-d0be884ed30f", name: "Flat 101"),
|
||||
productUuid: "fake-uuid-kitchen-water-heater",
|
||||
productType: "WH",
|
||||
permissionType: "CONTROLLABLE",
|
||||
activeTime: 1722173778,
|
||||
category: "kg",
|
||||
categoryName: "Water Heater",
|
||||
createTime: 1722173778,
|
||||
gatewayId: "bf0294123ed2c19067skrk",
|
||||
icon: "smart/icon/bay1642572935385vcsA/2b1f5efbaa5bbf81c3164fa312cf2032.png",
|
||||
ip: "",
|
||||
lat: "31.97",
|
||||
localKey: "T/39+<l/![iv>:9M",
|
||||
lon: "35.89",
|
||||
model: "S01ZLSWBSA3",
|
||||
name: "Kitchen Water Heater",
|
||||
nodeId: "60a423fffed5a7f6",
|
||||
online: true,
|
||||
ownerId: "199200732",
|
||||
sub: true,
|
||||
timeZone: "+03:00",
|
||||
updateTime: 1723626515,
|
||||
uuid: "5b31dae4-ce9c-4c70-b52b-7e150654sdf56",
|
||||
batteryLevel: null,
|
||||
);
|
@ -10,6 +10,7 @@ class ToggleWidget extends StatelessWidget {
|
||||
final String code;
|
||||
final String deviceId;
|
||||
final String label;
|
||||
final String? icon;
|
||||
final Function(dynamic value) onChange;
|
||||
|
||||
const ToggleWidget({
|
||||
@ -19,6 +20,7 @@ class ToggleWidget extends StatelessWidget {
|
||||
required this.deviceId,
|
||||
required this.label,
|
||||
required this.onChange,
|
||||
this.icon,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -42,7 +44,7 @@ class ToggleWidget extends StatelessWidget {
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: SvgPicture.asset(
|
||||
Assets.lightPulp,
|
||||
icon ?? Assets.lightPulp,
|
||||
width: 60,
|
||||
height: 60,
|
||||
fit: BoxFit.cover,
|
||||
|
@ -0,0 +1,132 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
||||
|
||||
part 'water_heater_event.dart';
|
||||
part 'water_heater_state.dart';
|
||||
|
||||
class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
||||
WaterHeaterBloc() : super(WaterHeaterInitial()) {
|
||||
on<WaterHeaterFetchStatusEvent>(_fetchWaterHeaterStatus);
|
||||
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
||||
on<UpdateScheduleEvent>(_updateScheduleEvent);
|
||||
on<StopScheduleEvent>(_stopScheduleEvent);
|
||||
}
|
||||
|
||||
late WaterHeaterStatusModel deviceStatus;
|
||||
Timer? _timer;
|
||||
|
||||
FutureOr<void> _updateScheduleEvent(
|
||||
UpdateScheduleEvent event,
|
||||
Emitter<WaterHeaterState> emit,
|
||||
) {
|
||||
emit(WaterHeaterScheduleState(
|
||||
scheduleType: event.scheduleType,
|
||||
hours: event.hours,
|
||||
minutes: event.minutes,
|
||||
isActive: true,
|
||||
));
|
||||
}
|
||||
|
||||
FutureOr<void> _stopScheduleEvent(
|
||||
StopScheduleEvent event,
|
||||
Emitter<WaterHeaterState> emit,
|
||||
) {
|
||||
if (state is WaterHeaterScheduleState) {
|
||||
final currentState = state as WaterHeaterScheduleState;
|
||||
emit(WaterHeaterScheduleState(
|
||||
scheduleType: currentState.scheduleType,
|
||||
hours: currentState.hours,
|
||||
minutes: currentState.minutes,
|
||||
isActive: false,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _controlWaterHeater(
|
||||
ToggleWaterHeaterEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
final oldValue = deviceStatus.heaterSwitch;
|
||||
|
||||
_updateLocalValue(event.isOn);
|
||||
|
||||
emit(WaterHeaterToggleState(isOn: event.isOn));
|
||||
|
||||
await _runDebounce(
|
||||
deviceId: event.deviceId,
|
||||
value: event.isOn,
|
||||
oldValue: oldValue,
|
||||
emit: emit,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _runDebounce({
|
||||
required String deviceId,
|
||||
required bool value,
|
||||
required bool oldValue,
|
||||
required Emitter<WaterHeaterState> emit,
|
||||
}) async {
|
||||
if (_timer != null) {
|
||||
_timer!.cancel();
|
||||
}
|
||||
|
||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
||||
try {
|
||||
//// TODO: implement control
|
||||
|
||||
// final status = await DevicesManagementApi().deviceControl(
|
||||
// deviceId, Status(value: value, code: 'heaterSwitch'));
|
||||
|
||||
// if (!status) {
|
||||
// _revertValueAndEmit(deviceId, oldValue, emit);
|
||||
// }
|
||||
} catch (e) {
|
||||
_revertValueAndEmit(deviceId, oldValue, emit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _revertValueAndEmit(
|
||||
String deviceId, bool oldValue, Emitter<WaterHeaterState> emit) {
|
||||
_updateLocalValue(oldValue);
|
||||
emit(WaterHeaterToggleState(isOn: oldValue));
|
||||
}
|
||||
|
||||
void _updateLocalValue(bool value) {
|
||||
deviceStatus = deviceStatus.copyWith(heaterSwitch: value);
|
||||
}
|
||||
|
||||
FutureOr<void> _fetchWaterHeaterStatus(
|
||||
WaterHeaterFetchStatusEvent event, Emitter<WaterHeaterState> emit) async {
|
||||
emit(WaterHeaterLoadingState());
|
||||
|
||||
try {
|
||||
// final status =
|
||||
// await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
// deviceStatus =
|
||||
// WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||
|
||||
final List<Status> fakeStatusList = [
|
||||
Status(code: 'switch', value: true),
|
||||
Status(code: 'schedule_mode', value: 'countdown'),
|
||||
Status(code: 'countdown_hours', value: 6),
|
||||
Status(code: 'countdown_minutes', value: 23),
|
||||
];
|
||||
|
||||
final fakeWaterHeaterStatus =
|
||||
WaterHeaterStatusModel.fromJson(event.deviceId, fakeStatusList);
|
||||
|
||||
emit(WaterHeaterDeviceStatusLoaded(fakeWaterHeaterStatus));
|
||||
} catch (e) {
|
||||
emit(WaterHeaterFailedState(error: e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_timer?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
part of 'water_heater_bloc.dart';
|
||||
|
||||
sealed class WaterHeaterEvent extends Equatable {
|
||||
const WaterHeaterEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
final class ToggleWaterHeaterEvent extends WaterHeaterEvent {
|
||||
final bool isOn;
|
||||
final String deviceId;
|
||||
|
||||
const ToggleWaterHeaterEvent({required this.isOn, required this.deviceId});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [isOn];
|
||||
}
|
||||
|
||||
final class UpdateScheduleEvent extends WaterHeaterEvent {
|
||||
final ScheduleType scheduleType;
|
||||
final int hours;
|
||||
final int minutes;
|
||||
|
||||
const UpdateScheduleEvent(this.scheduleType, this.hours, this.minutes);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [scheduleType, hours, minutes];
|
||||
}
|
||||
|
||||
final class StopScheduleEvent extends WaterHeaterEvent {}
|
||||
|
||||
class WaterHeaterFetchStatusEvent extends WaterHeaterEvent {
|
||||
final String deviceId;
|
||||
|
||||
const WaterHeaterFetchStatusEvent(this.deviceId);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [deviceId];
|
||||
}
|
||||
|
||||
class WaterHeaterFetchBatchStatusEvent extends WaterHeaterEvent {
|
||||
final String deviceId;
|
||||
|
||||
const WaterHeaterFetchBatchStatusEvent(this.deviceId);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [deviceId];
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
part of 'water_heater_bloc.dart';
|
||||
|
||||
enum ScheduleType { countdown, schedule, circulate, inching }
|
||||
|
||||
sealed class WaterHeaterState extends Equatable {
|
||||
const WaterHeaterState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
final class WaterHeaterInitial extends WaterHeaterState {}
|
||||
|
||||
final class WaterHeaterToggleState extends WaterHeaterState {
|
||||
final bool isOn;
|
||||
|
||||
const WaterHeaterToggleState({required this.isOn});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [isOn];
|
||||
}
|
||||
|
||||
final class WaterHeaterScheduleState extends WaterHeaterState {
|
||||
final ScheduleType scheduleType;
|
||||
final int hours;
|
||||
final int minutes;
|
||||
final bool isActive;
|
||||
|
||||
const WaterHeaterScheduleState({
|
||||
required this.scheduleType,
|
||||
required this.hours,
|
||||
required this.minutes,
|
||||
required this.isActive,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [scheduleType, hours, minutes, isActive];
|
||||
}
|
||||
|
||||
final class WaterHeaterDeviceStatusLoaded extends WaterHeaterState {
|
||||
final WaterHeaterStatusModel status;
|
||||
|
||||
const WaterHeaterDeviceStatusLoaded(this.status);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status];
|
||||
}
|
||||
|
||||
final class WaterHeaterBatchStatusLoaded extends WaterHeaterState {
|
||||
final WaterHeaterStatusModel status;
|
||||
|
||||
const WaterHeaterBatchStatusLoaded(this.status);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status];
|
||||
}
|
||||
|
||||
final class WaterHeaterFailedState extends WaterHeaterState {
|
||||
final String error;
|
||||
|
||||
const WaterHeaterFailedState({required this.error});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [error];
|
||||
}
|
||||
|
||||
final class WaterHeaterBatchFailedState extends WaterHeaterState {
|
||||
final String error;
|
||||
|
||||
const WaterHeaterBatchFailedState({required this.error});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [error];
|
||||
}
|
||||
|
||||
final class WaterHeaterLoadingState extends WaterHeaterState {}
|
@ -0,0 +1,83 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
|
||||
enum ScheduleModes { countdown, schedule, circulate, inching }
|
||||
|
||||
class WaterHeaterStatusModel {
|
||||
final String uuid;
|
||||
final bool heaterSwitch;
|
||||
final String scheduleModeString;
|
||||
final int countdownHours;
|
||||
final int countdownMinutes;
|
||||
final ScheduleModes scheduleMode;
|
||||
|
||||
WaterHeaterStatusModel({
|
||||
required this.uuid,
|
||||
required this.heaterSwitch,
|
||||
required this.scheduleModeString,
|
||||
required this.countdownHours,
|
||||
required this.countdownMinutes,
|
||||
}) : scheduleMode = getScheduleMode(scheduleModeString);
|
||||
|
||||
factory WaterHeaterStatusModel.fromJson(String id, List<Status> jsonList) {
|
||||
late bool heaterSwitch;
|
||||
late String scheduleMode;
|
||||
late int countdownHours;
|
||||
late int countdownMinutes;
|
||||
|
||||
for (var status in jsonList) {
|
||||
switch (status.code) {
|
||||
case 'switch':
|
||||
heaterSwitch = status.value ?? false;
|
||||
break;
|
||||
case 'schedule_mode':
|
||||
scheduleMode = status.value ?? 'countdown';
|
||||
break;
|
||||
case 'countdown_hours':
|
||||
countdownHours = status.value ?? 0;
|
||||
break;
|
||||
case 'countdown_minutes':
|
||||
countdownMinutes = status.value ?? 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return WaterHeaterStatusModel(
|
||||
uuid: id,
|
||||
heaterSwitch: heaterSwitch,
|
||||
scheduleModeString: scheduleMode,
|
||||
countdownHours: countdownHours,
|
||||
countdownMinutes: countdownMinutes,
|
||||
);
|
||||
}
|
||||
|
||||
WaterHeaterStatusModel copyWith({
|
||||
String? uuid,
|
||||
bool? heaterSwitch,
|
||||
String? scheduleModeString,
|
||||
int? countdownHours,
|
||||
int? countdownMinutes,
|
||||
}) {
|
||||
return WaterHeaterStatusModel(
|
||||
uuid: uuid ?? this.uuid,
|
||||
heaterSwitch: heaterSwitch ?? this.heaterSwitch,
|
||||
scheduleModeString: scheduleModeString ?? this.scheduleModeString,
|
||||
countdownHours: countdownHours ?? this.countdownHours,
|
||||
countdownMinutes: countdownMinutes ?? this.countdownMinutes,
|
||||
);
|
||||
}
|
||||
|
||||
static ScheduleModes getScheduleMode(String value) {
|
||||
switch (value) {
|
||||
case 'countdown':
|
||||
return ScheduleModes.countdown;
|
||||
case 'schedule':
|
||||
return ScheduleModes.schedule;
|
||||
case 'circulate':
|
||||
return ScheduleModes.circulate;
|
||||
case 'inching':
|
||||
return ScheduleModes.inching;
|
||||
default:
|
||||
return ScheduleModes.countdown;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/widgets/living_toggle_widget.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class WaterHeaterDeviceControl extends StatelessWidget
|
||||
with HelperResponsiveLayout {
|
||||
const WaterHeaterDeviceControl({super.key, required this.device});
|
||||
|
||||
final AllDevicesModel device;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) =>
|
||||
WaterHeaterBloc()..add(WaterHeaterFetchStatusEvent(device.uuid!)),
|
||||
child: BlocBuilder<WaterHeaterBloc, WaterHeaterState>(
|
||||
builder: (context, state) {
|
||||
if (state is WaterHeaterLoadingState) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is WaterHeaterDeviceStatusLoaded) {
|
||||
return _buildStatusControls(context, state.status);
|
||||
} else if (state is WaterHeaterFailedState ||
|
||||
state is WaterHeaterBatchFailedState) {
|
||||
return const Center(child: Text('Error fetching status'));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildStatusControls(
|
||||
BuildContext context, WaterHeaterStatusModel status) {
|
||||
final isExtraLarge = isExtraLargeScreenSize(context);
|
||||
final isLarge = isLargeScreenSize(context);
|
||||
final isMedium = isMediumScreenSize(context);
|
||||
return GridView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isLarge || isExtraLarge
|
||||
? 3
|
||||
: isMedium
|
||||
? 2
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
children: [
|
||||
const SizedBox(),
|
||||
ToggleWidget(
|
||||
deviceId: device.uuid!,
|
||||
code: 'water_heater',
|
||||
value: false,
|
||||
label: 'Water Heater',
|
||||
onChange: (value) {
|
||||
context.read<WaterHeaterBloc>().add(ToggleWaterHeaterEvent(
|
||||
deviceId: device.uuid!,
|
||||
isOn: value,
|
||||
));
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user