Files
syncrow-app/lib/features/devices/bloc/acs_bloc/acs_bloc.dart
2025-02-26 12:17:57 +03:00

492 lines
15 KiB
Dart

import 'dart:async';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
import 'package:syncrow_app/features/devices/model/ac_model.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ACsBloc extends Bloc<AcsEvent, AcsState> {
final String acId;
AcStatusModel deviceStatus = AcStatusModel(
countdown1: 0,
uuid: '',
acSwitch: true,
modeString: 'hot',
tempSet: 300,
currentTemp: 315,
fanSpeedsString: 'low',
childLock: false);
List<AcStatusModel> deviceStatusList = [];
List<DeviceModel> devicesList = [];
bool allAcsPage = false;
bool allAcsOn = true;
bool allTempSame = true;
int globalTemp = 250;
Timer? _timer;
ACsBloc({required this.acId}) : super(AcsInitialState()) {
on<AcsInitial>(_fetchAcsStatus);
on<AcSwitch>(_changeAcSwitch);
on<IncreaseCoolToTemp>(_increaseCoolTo);
on<DecreaseCoolToTemp>(_decreaseCoolTo);
on<ChangeLock>(_changeLockValue);
on<ChangeAcMode>(_changeAcMode);
on<ChangeFanSpeed>(_changeFanSpeed);
on<ChangeAllSwitch>(_changeAllAcSwitch);
on<IncreaseAllTemp>(_increaseAllTemp);
on<DecreaseAllTemp>(_decreaseAllTemp);
on<AcUpdated>(_onAcUpdated);
on<OnClose>(_onClose);
on<GetCounterEvent>(_getCounterValue);
on<SetCounterValue>(_setCounterValue);
on<TickTimer>(_onTickTimer);
// on<SetTimeOutValue>(_setTimeOutAlarm);
}
void _fetchAcsStatus(AcsInitial event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
try {
allAcsPage = event.allAcs;
if (event.allAcs) {
await _getAllAcs();
emit(GetAllAcsStatusState(
allAcsStatues: deviceStatusList,
allAcs: devicesList,
allOn: allAcsOn,
allTempSame: allTempSame,
temp: globalTemp));
} else {
var response = await DevicesAPI.getDeviceStatus(acId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
emit(GetAcStatusState(acStatusModel: deviceStatus));
Future.delayed(const Duration(milliseconds: 500));
_listenToChanges(acId);
}
} catch (e) {
emit(AcsFailedState(errorMessage: e.toString()));
return;
}
}
StreamSubscription<DatabaseEvent>? _streamSubscription;
void _listenToChanges(acId) {
try {
_streamSubscription?.cancel();
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$acId');
Stream<DatabaseEvent> stream = ref.onValue;
_streamSubscription = stream.listen((DatabaseEvent event) {
Map<dynamic, dynamic> usersMap =
event.snapshot.value as Map<dynamic, dynamic>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus =
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
add(AcUpdated());
});
} catch (_) {}
}
@override
Future<void> close() async {
_streamSubscription?.cancel();
_streamSubscription = null;
return super.close();
}
_onAcUpdated(AcUpdated event, Emitter<AcsState> emit) {
emit(GetAcStatusState(acStatusModel: deviceStatus));
}
_getAllAcs() async {
deviceStatusList = [];
devicesList = [];
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC');
for (int i = 0; i < devicesList.length; i++) {
_listenToChanges(devicesList[i].uuid);
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatusList.add(AcStatusModel.fromJson(devicesList[i].uuid ?? '', statusModelList));
}
_setAllAcsTempsAndSwitches();
}
void _changeAcSwitch(AcSwitch event, Emitter<AcsState> emit) async {
final acSwitchValue = !event.acSwitch;
if (allAcsPage) {
emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.deviceId) {
ac.acSwitch = acSwitchValue;
}
}
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
} else {
emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.acSwitch = acSwitchValue;
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
}
void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
if (deviceStatusList.length == devicesList.length) {
for (int i = 0; i < deviceStatusList.length; i++) {
deviceStatusList[i].acSwitch = event.value;
}
}
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
_runDeBouncerForAllAcs(code: 'switch', value: event.value);
}
void _increaseAllTemp(IncreaseAllTemp event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
double tempValue = event.value + 0.5;
int value = (tempValue * 10).toInt();
if (!_checkTemperatureValue(tempValue, emit)) {
return;
}
if (deviceStatusList.length == devicesList.length) {
for (int i = 0; i < deviceStatusList.length; i++) {
deviceStatusList[i].tempSet = value;
}
}
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
_runDeBouncerForAllAcs(code: 'temp_set', value: value);
}
void _decreaseAllTemp(DecreaseAllTemp event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
double tempValue = event.value - 0.5;
int value = (tempValue * 10).toInt();
if (!_checkTemperatureValue(tempValue, emit)) {
return;
}
if (deviceStatusList.length == devicesList.length) {
for (int i = 0; i < deviceStatusList.length; i++) {
deviceStatusList[i].tempSet = value;
}
}
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
_runDeBouncerForAllAcs(code: 'temp_set', value: value);
}
void _changeLockValue(ChangeLock event, Emitter<AcsState> emit) async {
emit(AcChangeLoading(acStatusModel: deviceStatus));
final lockValue = !event.lockBool;
deviceStatus.childLock = lockValue;
emit(AcModifyingState(acStatusModel: deviceStatus));
await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
}
void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async {
emit(AcChangeLoading(acStatusModel: deviceStatus));
double tempValue = event.value + 0.5;
int value = (tempValue * 10).toInt();
if (!_checkTemperatureValue(tempValue, emit)) {
return;
}
if (allAcsPage) {
emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.deviceId) {
ac.tempSet = value;
}
}
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
} else {
emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.tempSet = value;
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
}
void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async {
emit(AcChangeLoading(acStatusModel: deviceStatus));
double tempValue = event.value - 0.5;
int value = (tempValue * 10).toInt();
if (!_checkTemperatureValue(tempValue, emit)) {
return;
}
if (allAcsPage) {
emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.deviceId) {
ac.tempSet = value;
}
}
_setAllAcsTempsAndSwitches();
_emitAcsStatus(emit);
} else {
emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.tempSet = value;
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
}
void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async {
final tempMode = tempModesMap[getNextItem(tempModesMap, event.tempModes)]!;
if (allAcsPage) {
emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.deviceId) {
ac.modeString = getACModeString(tempMode);
ac.acMode = AcStatusModel.getACMode(getACModeString(tempMode));
}
}
_emitAcsStatus(emit);
} else {
emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.modeString = getACModeString(tempMode);
deviceStatus.acMode = AcStatusModel.getACMode(getACModeString(tempMode));
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'mode', value: getACModeString(tempMode));
}
void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async {
emit(AcChangeLoading(acStatusModel: deviceStatus));
final fanSpeed = event.fanSpeeds;
if (allAcsPage) {
emit(AcsLoadingState());
for (AcStatusModel ac in deviceStatusList) {
if (ac.uuid == event.deviceId) {
ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
ac.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
}
}
_emitAcsStatus(emit);
} else {
emit(AcChangeLoading(acStatusModel: deviceStatus));
deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
deviceStatus.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
emit(AcModifyingState(acStatusModel: deviceStatus));
}
await _runDeBouncerForOneDevice(
deviceId: event.deviceId, code: 'level', value: getNextFanSpeedKey(fanSpeed));
}
String getACModeString(TempModes value) {
if (value == TempModes.cold) {
return 'cold';
} else if (value == TempModes.hot) {
return 'hot';
} else if (value == TempModes.wind) {
return 'wind';
} else {
return 'cold';
}
}
void _setAllAcsTempsAndSwitches() {
allAcsOn = true;
allTempSame = true;
if (deviceStatusList.isNotEmpty) {
int temp = deviceStatusList.first.tempSet;
for (var element in deviceStatusList) {
if (!element.acSwitch) {
allAcsOn = false;
}
if (element.tempSet != temp) {
allTempSame = false;
}
}
if (allTempSame) {
globalTemp = temp;
}
}
}
_runDeBouncerForAllAcs({required String code, required dynamic value}) {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(seconds: 1), () async {
if (deviceStatusList.length == devicesList.length) {
for (int i = 0; i < deviceStatusList.length; i++) {
try {
await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: devicesList[i].uuid, code: code, value: value),
devicesList[i].uuid ?? '');
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const AcsInitial(allAcs: true));
}
}
}
});
}
_runDeBouncerForOneDevice({
required String deviceId,
required String code,
required dynamic value,
}) {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(seconds: 1), () async {
try {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: allAcsPage ? deviceId : acId, code: code, value: value),
allAcsPage ? deviceId : acId);
if (!response['success']) {
add(AcsInitial(allAcs: allAcsPage));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(AcsInitial(allAcs: allAcsPage));
}
});
}
bool _checkTemperatureValue(double value, Emitter<AcsState> emit) {
if (value >= 20 && value <= 30) {
return true;
} else {
emit(const AcsFailedState(errorMessage: 'The temperature must be between 20 and 30'));
emit(GetAllAcsStatusState(
allAcsStatues: deviceStatusList,
allAcs: devicesList,
allOn: allAcsOn,
allTempSame: allTempSame,
temp: globalTemp));
return false;
}
}
_emitAcsStatus(Emitter<AcsState> emit) {
emit(GetAllAcsStatusState(
allAcsStatues: deviceStatusList,
allAcs: devicesList,
allOn: allAcsOn,
allTempSame: allTempSame,
temp: globalTemp));
}
void _setCounterValue(SetCounterValue event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
int seconds = 0;
try {
seconds = event.seconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(deviceId: acId, code: 'countdown_time', value: event.duration), acId);
if (response['success'] ?? false) {
deviceStatus.countdown1 = seconds;
} else {
emit(const AcsFailedState(errorMessage: 'Something went wrong'));
return;
}
} catch (e) {
emit(AcsFailedState(errorMessage: e.toString()));
return;
}
if (event.duration > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(GetCounterEvent event, Emitter<AcsState> emit) async {
emit(AcsLoadingState());
var response = await DevicesAPI.getDeviceStatus(acId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
deviceStatus.countdown1;
var duration;
if (deviceStatus.countdown1 == 5) {
duration = const Duration(minutes: 30);
var countNum = duration.inSeconds;
_onStartTimer(countNum);
} else if (deviceStatus.countdown1 > 5) {
duration = Duration(minutes: deviceStatus.countdown1 * 6);
var countNum = duration.inSeconds;
_onStartTimer(countNum);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(remainingTime: seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<AcsState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _onClose(OnClose event, Emitter<AcsState> emit) {
_timer?.cancel(); // Cancel the timer
}
}