Completed wall sensor implementation

This commit is contained in:
Abdullah Alassaf
2025-01-12 00:12:08 +03:00
parent b1368bf4d7
commit 90812f78e8
12 changed files with 134 additions and 56 deletions

2
.gitignore vendored
View File

@ -5,9 +5,11 @@
*.swp *.swp
.DS_Store .DS_Store
.atom/ .atom/
.build/
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
.swiftpm/
migrate_working_dir/ migrate_working_dir/
# IntelliJ related # IntelliJ related

View File

@ -329,4 +329,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 4243bd7f9184f79552dd731a7c9d5cad03bd2706 PODFILE CHECKSUM: 4243bd7f9184f79552dd731a7c9d5cad03bd2706
COCOAPODS: 1.15.2 COCOAPODS: 1.16.2

View File

@ -1,7 +1,7 @@
import UIKit import UIKit
import Flutter import Flutter
@UIApplicationMain @main
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,

View File

@ -18,6 +18,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
on<ChangeIndicatorEvent>(_changeIndicator); on<ChangeIndicatorEvent>(_changeIndicator);
on<ChangeValueEvent>(_changeValue); on<ChangeValueEvent>(_changeValue);
on<WallSensorUpdatedEvent>(_wallSensorUpdated); on<WallSensorUpdatedEvent>(_wallSensorUpdated);
on<GetDeviceReportsEvent>(_getDeviceReports);
} }
void _fetchCeilingSensorStatus(InitialEvent event, Emitter<WallSensorState> emit) async { void _fetchCeilingSensorStatus(InitialEvent event, Emitter<WallSensorState> emit) async {
@ -91,4 +92,17 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
} catch (_) {} } catch (_) {}
emit(UpdateState(wallSensorModel: deviceStatus)); emit(UpdateState(wallSensorModel: deviceStatus));
} }
void _getDeviceReports(GetDeviceReportsEvent event, Emitter<WallSensorState> emit) async {
emit(LoadingInitialState());
try {
await DevicesAPI.getDeviceReports(deviceId, event.code).then((value) {
emit(DeviceReportsState(deviceReport: value, code: event.code));
});
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
} }

View File

@ -29,3 +29,15 @@ class ChangeValueEvent extends WallSensorEvent {
@override @override
List<Object> get props => [value, code]; List<Object> get props => [value, code];
} }
class GetDeviceReportsEvent extends WallSensorEvent {
final String deviceUuid;
final String code;
const GetDeviceReportsEvent({
required this.deviceUuid,
required this.code,
});
@override
List<Object> get props => [deviceUuid, code];
}

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_report_model.dart';
import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart'; import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart';
class WallSensorState extends Equatable { class WallSensorState extends Equatable {
@ -36,3 +37,9 @@ class FailedState extends WallSensorState {
@override @override
List<Object> get props => [error]; List<Object> get props => [error];
} }
class DeviceReportsState extends WallSensorState {
final DeviceReport deviceReport;
final String code;
const DeviceReportsState({required this.deviceReport, required this.code});
}

View File

@ -9,17 +9,18 @@ class WallSensorModel {
int currentDistance; int currentDistance;
int illuminance; int illuminance;
bool indicator; bool indicator;
int noOneTime;
WallSensorModel({ WallSensorModel(
required this.presenceState, {required this.presenceState,
required this.farDetection, required this.farDetection,
required this.presenceTime, required this.presenceTime,
required this.motionSensitivity, required this.motionSensitivity,
required this.motionlessSensitivity, required this.motionlessSensitivity,
required this.currentDistance, required this.currentDistance,
required this.illuminance, required this.illuminance,
required this.indicator, required this.indicator,
}); required this.noOneTime});
factory WallSensorModel.fromJson(List<StatusModel> jsonList) { factory WallSensorModel.fromJson(List<StatusModel> jsonList) {
late String _presenceState; late String _presenceState;
@ -30,6 +31,7 @@ class WallSensorModel {
late int _currentDistance; late int _currentDistance;
late int _illuminance; late int _illuminance;
late bool _indicator; late bool _indicator;
late int _noOneTime;
for (int i = 0; i < jsonList.length; i++) { for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'presence_state') { if (jsonList[i].code == 'presence_state') {
@ -48,6 +50,8 @@ class WallSensorModel {
_illuminance = jsonList[i].value ?? 0; _illuminance = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'indicator') { } else if (jsonList[i].code == 'indicator') {
_indicator = jsonList[i].value ?? false; _indicator = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'no_one_time') {
_noOneTime = jsonList[i].value ?? 0;
} }
} }
return WallSensorModel( return WallSensorModel(
@ -58,6 +62,7 @@ class WallSensorModel {
motionlessSensitivity: _motionlessSensitivity, motionlessSensitivity: _motionlessSensitivity,
currentDistance: _currentDistance, currentDistance: _currentDistance,
illuminance: _illuminance, illuminance: _illuminance,
indicator: _indicator); indicator: _indicator,
noOneTime: _noOneTime);
} }
} }

View File

@ -215,8 +215,7 @@ class ParametersList extends StatelessWidget {
{ {
'icon': Assets.assetsIconsPresenceSensorAssetsEmpty, 'icon': Assets.assetsIconsPresenceSensorAssetsEmpty,
'title': 'Nobody Time', 'title': 'Nobody Time',
'code': null, 'code': 'no_one_time',
//TODO: Implement the nobody time
}, },
{ {
'icon': Assets.assetsIconsPresenceSensorAssetsIndicator, 'icon': Assets.assetsIconsPresenceSensorAssetsIndicator,
@ -231,7 +230,7 @@ class ParametersList extends StatelessWidget {
{ {
'icon': Assets.assetsIconsPresenceSensorAssetsIlluminanceRecord, 'icon': Assets.assetsIconsPresenceSensorAssetsIlluminanceRecord,
'title': 'Illuminance Record', 'title': 'Illuminance Record',
'code': null 'code': 'illuminance_value'
}, },
]; ];
} }
@ -240,6 +239,7 @@ Widget listItem(Map<String, Object?> wallSensorButton, BuildContext context, Dev
WallSensorModel wallSensorStatus) { WallSensorModel wallSensorStatus) {
String? unit; String? unit;
dynamic value; dynamic value;
int noBodyTimeValue;
if (wallSensorButton['code'] != null) { if (wallSensorButton['code'] != null) {
// if (wallSensor.status.any((element) => element.code == wallSensorButton['code'] as String)) { // if (wallSensor.status.any((element) => element.code == wallSensorButton['code'] as String)) {
// unit = unitsMap[wallSensorButton['code'] as String]; // unit = unitsMap[wallSensorButton['code'] as String];
@ -256,12 +256,15 @@ Widget listItem(Map<String, Object?> wallSensorButton, BuildContext context, Dev
} else if (wallSensorButton['code'] == 'illuminance_value') { } else if (wallSensorButton['code'] == 'illuminance_value') {
unit = unitsMap[wallSensorButton['code'] as String]; unit = unitsMap[wallSensorButton['code'] as String];
value = wallSensorStatus.illuminance; value = wallSensorStatus.illuminance;
} else if (wallSensorButton['code'] == 'no_one_time') {
unit = unitsMap[wallSensorButton['code'] as String];
value = wallSensorStatus.noOneTime;
} }
} }
return DefaultContainer( return DefaultContainer(
margin: const EdgeInsets.only(bottom: 5), margin: const EdgeInsets.only(bottom: 5),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
onTap: () { onTap: () async {
if (wallSensorButton['page'] != null) { if (wallSensorButton['page'] != null) {
Navigator.push( Navigator.push(
context, context,
@ -270,6 +273,42 @@ Widget listItem(Map<String, Object?> wallSensorButton, BuildContext context, Dev
), ),
); );
} }
if (wallSensorButton['title'] == 'Presence Record') {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PresenceRecords(
deviceId: wallSensor.uuid!,
code: 'presence_state',
title: 'Presence Record',
)),
);
}
if (wallSensorButton['title'] == 'Illuminance Record') {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PresenceRecords(
deviceId: wallSensor.uuid!,
code: 'illuminance_value',
title: 'Illuminance Record',
)),
);
}
if (wallSensorButton['title'] == 'Nobody Time') {
int noBodyTimeValue = value as int;
String controlCode = 'no_one_time';
final result = await showDialog(
context: context,
builder: (context) => ParameterControlDialog(
title: 'Nobody Time', sensor: wallSensor, value: noBodyTimeValue, min: 0, max: 10000),
);
if (result != null) {
BlocProvider.of<WallSensorBloc>(context)
.add(ChangeValueEvent(value: result, code: controlCode));
}
}
}, },
child: Row( child: Row(
children: [ children: [

View File

@ -1,3 +1,5 @@
import 'dart:ffi';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -9,6 +11,8 @@ import 'package:syncrow_app/features/devices/bloc/wall_sensor_bloc/wall_sensor_e
import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart'; import 'package:syncrow_app/features/devices/model/wall_sensor_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart'; import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/garage_door/garage_records_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/persence_records.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
@ -41,7 +45,8 @@ class WallMountedInterface extends StatelessWidget {
motionlessSensitivity: 0, motionlessSensitivity: 0,
currentDistance: 0, currentDistance: 0,
illuminance: 0, illuminance: 0,
indicator: false); indicator: false,
noOneTime: 0);
if (state is UpdateState) { if (state is UpdateState) {
wallSensorModel = state.wallSensorModel; wallSensorModel = state.wallSensorModel;

View File

@ -209,4 +209,5 @@ abstract class ApiEndpoints {
static const String resetDevice = '/factory/reset/{deviceUuid}'; static const String resetDevice = '/factory/reset/{deviceUuid}';
static const String unAssignScenesDevice = '/device/{deviceUuid}/scenes?switchName={switchName}'; static const String unAssignScenesDevice = '/device/{deviceUuid}/scenes?switchName={switchName}';
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
} }

View File

@ -88,8 +88,7 @@ class DevicesAPI {
static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async { static Future<Map<String, dynamic>> getDeviceStatus(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.deviceFunctionsStatus path: ApiEndpoints.deviceFunctionsStatus.replaceAll('{deviceUuid}', deviceId),
.replaceAll('{deviceUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -98,8 +97,7 @@ class DevicesAPI {
return response; return response;
} }
static Future<Map<String, dynamic>> getPowerClampStatus( static Future<Map<String, dynamic>> getPowerClampStatus(String deviceId) async {
String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.powerClamp.replaceAll('{powerClampUuid}', deviceId), path: ApiEndpoints.powerClamp.replaceAll('{powerClampUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
@ -111,9 +109,7 @@ class DevicesAPI {
} }
static Future<Map<String, dynamic>> renamePass( static Future<Map<String, dynamic>> renamePass(
{required String name, {required String name, required String doorLockUuid, required String passwordId}) async {
required String doorLockUuid,
required String passwordId}) async {
final response = await _httpService.put( final response = await _httpService.put(
path: ApiEndpoints.renamePassword path: ApiEndpoints.renamePassword
.replaceAll('{doorLockUuid}', doorLockUuid) .replaceAll('{doorLockUuid}', doorLockUuid)
@ -148,8 +144,7 @@ class DevicesAPI {
return response; return response;
} }
static Future getSceneBySwitchName( static Future getSceneBySwitchName({String? deviceId, String? switchName}) async {
{String? deviceId, String? switchName}) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.fourSceneByName path: ApiEndpoints.fourSceneByName
.replaceAll('{deviceUuid}', deviceId!) .replaceAll('{deviceUuid}', deviceId!)
@ -170,11 +165,7 @@ class DevicesAPI {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.deviceScene.replaceAll('{deviceUuid}', deviceId!), path: ApiEndpoints.deviceScene.replaceAll('{deviceUuid}', deviceId!),
body: jsonEncode( body: jsonEncode(
{ {"switchName": switchName, "sceneUuid": sceneUuid, "spaceUuid": spaceUuid},
"switchName": switchName,
"sceneUuid": sceneUuid,
"spaceUuid": spaceUuid
},
), ),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
@ -194,8 +185,7 @@ class DevicesAPI {
return response; return response;
} }
static Future<List<DeviceModel>> getDeviceByGroupName( static Future<List<DeviceModel>> getDeviceByGroupName(String unitId, String groupName) async {
String unitId, String groupName) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.devicesByGroupName path: ApiEndpoints.devicesByGroupName
.replaceAll('{unitUuid}', unitId) .replaceAll('{unitUuid}', unitId)
@ -240,9 +230,7 @@ class DevicesAPI {
if (json == null || json.isEmpty || json == []) { if (json == null || json.isEmpty || json == []) {
return <DeviceModel>[]; return <DeviceModel>[];
} }
return data return data.map<DeviceModel>((device) => DeviceModel.fromJson(device)).toList();
.map<DeviceModel>((device) => DeviceModel.fromJson(device))
.toList();
}, },
); );
@ -254,8 +242,7 @@ class DevicesAPI {
} }
} }
static Future<List<DeviceModel>> getDevicesByGatewayId( static Future<List<DeviceModel>> getDevicesByGatewayId(String gatewayId) async {
String gatewayId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId),
showServerMessage: false, showServerMessage: false,
@ -277,8 +264,7 @@ class DevicesAPI {
String deviceId, String deviceId,
) async { ) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getTemporaryPassword path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -289,8 +275,7 @@ class DevicesAPI {
static Future getOneTimePasswords(String deviceId) async { static Future getOneTimePasswords(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getOneTimeTemporaryPassword path: ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -301,8 +286,7 @@ class DevicesAPI {
static Future getTimeLimitPasswords(String deviceId) async { static Future getTimeLimitPasswords(String deviceId) async {
final response = await _httpService.get( final response = await _httpService.get(
path: ApiEndpoints.getMultipleTimeTemporaryPassword path: ApiEndpoints.getMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -327,12 +311,10 @@ class DevicesAPI {
"invalidTime": invalidTime, "invalidTime": invalidTime,
}; };
if (scheduleList != null) { if (scheduleList != null) {
body["scheduleList"] = body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
scheduleList.map((schedule) => schedule.toJson()).toList();
} }
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addTemporaryPassword path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
.replaceAll('{doorLockUuid}', deviceId),
body: body, body: body,
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) => json, expectedResponseModel: (json) => json,
@ -343,8 +325,7 @@ class DevicesAPI {
static Future generateOneTimePassword({deviceId}) async { static Future generateOneTimePassword({deviceId}) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addOneTimeTemporaryPassword path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: false, showServerMessage: false,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return json; return json;
@ -356,12 +337,10 @@ class DevicesAPI {
} }
} }
static Future generateMultiTimePassword( static Future generateMultiTimePassword({deviceId, effectiveTime, invalidTime}) async {
{deviceId, effectiveTime, invalidTime}) async {
try { try {
final response = await _httpService.post( final response = await _httpService.post(
path: ApiEndpoints.addMultipleTimeTemporaryPassword path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId),
.replaceAll('{doorLockUuid}', deviceId),
showServerMessage: true, showServerMessage: true,
body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime}, body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime},
expectedResponseModel: (json) { expectedResponseModel: (json) {
@ -545,4 +524,18 @@ class DevicesAPI {
); );
return response; return response;
} }
static Future<DeviceReport> getDeviceReports(
String uuid,
String code,
) async {
final response = await HTTPService().get(
path: ApiEndpoints.getDeviceLogs.replaceAll('{uuid}', uuid).replaceAll('{code}', code),
showServerMessage: false,
expectedResponseModel: (json) {
return DeviceReport.fromJson(json);
},
);
return response;
}
} }

View File

@ -5,7 +5,7 @@ description: This is the mobile application project, developed with Flutter for
# pub.dev using `flutter pub publish`. This is preferred for private packages. # pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev publish_to: "none" # Remove this line if you wish to publish to pub.dev
version: 1.0.9+45 version: 1.0.10+46
environment: environment:
sdk: ">=3.0.6 <4.0.0" sdk: ">=3.0.6 <4.0.0"