SP-1594-device-location-api-integration.

This commit is contained in:
Faris Armoush
2025-06-04 13:06:27 +03:00
parent 79b974ee6c
commit 24a7f3ac2a
7 changed files with 65 additions and 51 deletions

View File

@ -8,6 +8,8 @@ class AnalyticsDevice {
this.isActive, this.isActive,
this.productDevice, this.productDevice,
this.spaceUuid, this.spaceUuid,
this.latitude,
this.longitude,
}); });
final String uuid; final String uuid;
@ -18,6 +20,8 @@ class AnalyticsDevice {
final bool? isActive; final bool? isActive;
final ProductDevice? productDevice; final ProductDevice? productDevice;
final String? spaceUuid; final String? spaceUuid;
final double? latitude;
final double? longitude;
factory AnalyticsDevice.fromJson(Map<String, dynamic> json) { factory AnalyticsDevice.fromJson(Map<String, dynamic> json) {
return AnalyticsDevice( return AnalyticsDevice(
@ -35,6 +39,8 @@ class AnalyticsDevice {
? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>) ? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>)
: null, : null,
spaceUuid: json['spaceUuid'] as String?, spaceUuid: json['spaceUuid'] as String?,
latitude: json['lat'] != null ? double.parse(json['lat'] as String) : null,
longitude: json['lon'] != null ? double.parse(json['lon'] as String) : null,
); );
} }
} }

View File

@ -19,11 +19,8 @@ class DeviceLocationInfo extends Equatable {
factory DeviceLocationInfo.fromJson(Map<String, dynamic> json) { factory DeviceLocationInfo.fromJson(Map<String, dynamic> json) {
return DeviceLocationInfo( return DeviceLocationInfo(
airQuality: json['airQuality'] as double?, airQuality: json['aqi'] as double?,
humidity: json['humidity'] as double?, humidity: json['humidity'] as double?,
city: json['city'] as String?,
country: json['country'] as String?,
address: json['address'] as String?,
temperature: json['temperature'] as double?, temperature: json['temperature'] as double?,
); );
} }

View File

@ -65,7 +65,7 @@ abstract final class FetchAirQualityDataHelper {
communityUuid: communityUuid, communityUuid: communityUuid,
spaceUuid: spaceUuid, spaceUuid: spaceUuid,
deviceTypes: ['AQI'], deviceTypes: ['AQI'],
requestType: AnalyticsDeviceRequestType.energyManagement, requestType: AnalyticsDeviceRequestType.occupancy,
), ),
onSuccess: (device) { onSuccess: (device) {
context.read<RealtimeDeviceChangesBloc>() context.read<RealtimeDeviceChangesBloc>()
@ -73,10 +73,10 @@ abstract final class FetchAirQualityDataHelper {
..add(RealtimeDeviceChangesStarted(device.uuid)); ..add(RealtimeDeviceChangesStarted(device.uuid));
context.read<DeviceLocationBloc>().add( context.read<DeviceLocationBloc>().add(
const LoadDeviceLocationEvent( LoadDeviceLocationEvent(
GetDeviceLocationDataParam( GetDeviceLocationDataParam(
latitude: 35.6895, latitude: device.latitude ?? 0,
longitude: 139.6917, longitude: device.longitude ?? 0,
), ),
), ),
); );

View File

@ -1,3 +1,4 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/air_quality_distribution/air_quality_distribution_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/air_quality_distribution/air_quality_distribution_bloc.dart';
@ -19,8 +20,8 @@ import 'package:syncrow_web/pages/analytics/services/air_quality_distribution/fa
import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service_delagate.dart'; import 'package:syncrow_web/pages/analytics/services/analytics_devices/analytics_devices_service_delagate.dart';
import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_energy_management_analytics_devices_service.dart'; import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_energy_management_analytics_devices_service.dart';
import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_occupancy_analytics_devices_service.dart'; import 'package:syncrow_web/pages/analytics/services/analytics_devices/remote_occupancy_analytics_devices_service.dart';
import 'package:syncrow_web/pages/analytics/services/device_location/device_location_details_service_decorator.dart';
import 'package:syncrow_web/pages/analytics/services/device_location/remote_device_location_service.dart'; import 'package:syncrow_web/pages/analytics/services/device_location/remote_device_location_service.dart';
import 'package:syncrow_web/pages/analytics/services/device_location/reverse_geocode_device_location_service_decorator.dart';
import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/remote_energy_consumption_by_phases_service.dart'; import 'package:syncrow_web/pages/analytics/services/energy_consumption_by_phases/remote_energy_consumption_by_phases_service.dart';
import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/remote_energy_consumption_per_device_service.dart'; import 'package:syncrow_web/pages/analytics/services/energy_consumption_per_device/remote_energy_consumption_per_device_service.dart';
import 'package:syncrow_web/pages/analytics/services/occupacy/remote_occupancy_service.dart'; import 'package:syncrow_web/pages/analytics/services/occupacy/remote_occupancy_service.dart';
@ -113,8 +114,13 @@ class _AnalyticsPageState extends State<AnalyticsPage> {
), ),
BlocProvider( BlocProvider(
create: (context) => DeviceLocationBloc( create: (context) => DeviceLocationBloc(
ReverseGeocodeDeviceLocationServiceDecorator( DeviceLocationDetailsServiceDecorator(
RemoteDeviceLocationService(_httpService), RemoteDeviceLocationService(_httpService),
Dio(
BaseOptions(
baseUrl: 'https://nominatim.openstreetmap.org/',
),
),
), ),
), ),
), ),

View File

@ -0,0 +1,40 @@
import 'package:dio/dio.dart';
import 'package:syncrow_web/pages/analytics/models/device_location_info.dart';
import 'package:syncrow_web/pages/analytics/params/get_device_location_data_param.dart';
import 'package:syncrow_web/pages/analytics/services/device_location/device_location_service.dart';
class DeviceLocationDetailsServiceDecorator implements DeviceLocationService {
const DeviceLocationDetailsServiceDecorator(this._decoratee, this._dio);
final DeviceLocationService _decoratee;
final Dio _dio;
@override
Future<DeviceLocationInfo> get(GetDeviceLocationDataParam param) async {
try {
final deviceLocationInfo = await _decoratee.get(param);
final response = await _dio.get<Map<String, dynamic>>(
'reverse',
queryParameters: {
'format': 'json',
'lat': param.latitude,
'lon': param.longitude,
},
);
final data = response.data;
if (data != null) {
final addressData = data['address'] as Map<String, dynamic>;
return deviceLocationInfo.copyWith(
city: addressData['city'],
country: addressData['country_code'].toString().toUpperCase(),
address: addressData['state'],
);
}
return deviceLocationInfo;
} catch (e) {
throw Exception('Failed to load device location info: ${e.toString()}');
}
}
}

View File

@ -17,7 +17,12 @@ class RemoteDeviceLocationService implements DeviceLocationService {
final response = await _httpService.get( final response = await _httpService.get(
path: '/weather', path: '/weather',
queryParameters: param.toJson(), queryParameters: param.toJson(),
expectedResponseModel: (data) => DeviceLocationInfo.fromJson(data), expectedResponseModel: (data) {
final response = data as Map<String, dynamic>;
final location = response['data'] as Map<String, dynamic>;
return DeviceLocationInfo.fromJson(location);
},
); );
return response; return response;
} on DioException catch (e) { } on DioException catch (e) {

View File

@ -1,40 +0,0 @@
import 'package:geocoding/geocoding.dart';
import 'package:syncrow_web/pages/analytics/models/device_location_info.dart';
import 'package:syncrow_web/pages/analytics/params/get_device_location_data_param.dart';
import 'package:syncrow_web/pages/analytics/services/device_location/device_location_service.dart';
class ReverseGeocodeDeviceLocationServiceDecorator implements DeviceLocationService {
const ReverseGeocodeDeviceLocationServiceDecorator(this._decoratee);
final DeviceLocationService _decoratee;
@override
Future<DeviceLocationInfo> get(GetDeviceLocationDataParam param) async {
try {
final deviceLocationInfo = await _decoratee.get(param);
final placemarks = await placemarkFromCoordinates(
param.latitude,
param.longitude,
);
if (placemarks.isNotEmpty) {
final place = placemarks.first;
final city = place.locality;
final country = place.country;
final address = place.street;
return deviceLocationInfo.copyWith(
city: city,
country: country,
address: address,
);
}
return deviceLocationInfo;
} catch (e) {
throw Exception('Failed to reverse load device location info');
}
}
}