weather_service.dart 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. import 'dart:convert';
  2. import 'dart:io';
  3. /// Keyless current-temperature lookup for the dashboard fallback.
  4. ///
  5. /// Open-Meteo is used deliberately: no API key, no account and a tiny JSON
  6. /// response. Any failure returns null so the UI simply hides the row.
  7. class WeatherService {
  8. Future<double?> temperatureCelsius({
  9. required double latitude,
  10. required double longitude,
  11. }) async {
  12. final uri = Uri.https('api.open-meteo.com', '/v1/forecast', {
  13. 'latitude': latitude.toStringAsFixed(4),
  14. 'longitude': longitude.toStringAsFixed(4),
  15. 'current': 'temperature_2m',
  16. 'timezone': 'auto',
  17. });
  18. final client = HttpClient()..connectionTimeout = const Duration(seconds: 8);
  19. try {
  20. final request = await client.getUrl(uri);
  21. request.headers.set(HttpHeaders.userAgentHeader, 'CarDash/0.6');
  22. final response = await request.close().timeout(
  23. const Duration(seconds: 10),
  24. );
  25. if (response.statusCode != HttpStatus.ok) return null;
  26. final body = await response.transform(utf8.decoder).join();
  27. final decoded = jsonDecode(body);
  28. if (decoded is! Map) return null;
  29. final current = decoded['current'];
  30. if (current is! Map) return null;
  31. final temperature = current['temperature_2m'];
  32. if (temperature is! num) return null;
  33. if (temperature < -90 || temperature > 60) return null;
  34. return temperature.toDouble();
  35. } catch (_) {
  36. return null;
  37. } finally {
  38. client.close(force: true);
  39. }
  40. }
  41. }