Compare commits

...

10 Commits
1.0.0 ... 1.0.1

Author SHA1 Message Date
9c1d240962 1013 2020-05-06 19:05:11 +00:00
a76652b552 1012 2020-05-06 18:46:05 +00:00
a140f993d0 1011 2020-05-06 18:23:01 +00:00
ded60a2867 not null 2020-05-06 18:22:17 +00:00
b86602bcdb app version and whats new 2020-05-06 18:19:41 +00:00
02ea45469f 1.0.1 2020-05-06 17:52:31 +00:00
90105c3b09 Cache reading issues fix 2020-05-06 17:51:06 +00:00
3d828914cc Fix error handling 2020-05-06 17:24:13 +00:00
8cd5776bc6 Make integration work with HA < 0.104 2020-05-06 16:40:19 +00:00
17ec73b176 Report foreground location errors 2020-05-06 16:19:42 +00:00
11 changed files with 90 additions and 61 deletions

View File

@ -140,9 +140,9 @@ class HomeAssistant {
Future _getConfig(SharedPreferences sharedPrefs) async { Future _getConfig(SharedPreferences sharedPrefs) async {
_instanceConfig?.clear(); _instanceConfig?.clear();
if (sharedPrefs != null) { if (sharedPrefs != null && sharedPrefs.containsKey('cached_config')) {
try { try {
var data = json.decode(sharedPrefs.getString('cached_config') ?? '{}'); var data = json.decode(sharedPrefs.getString('cached_config'));
_parseConfig(data); _parseConfig(data);
} catch (e, stacktrace) { } catch (e, stacktrace) {
Logger.e('Error gettong config from cache: $e', stacktrace: stacktrace); Logger.e('Error gettong config from cache: $e', stacktrace: stacktrace);
@ -160,9 +160,9 @@ class HomeAssistant {
} }
Future _getStates(SharedPreferences sharedPrefs) async { Future _getStates(SharedPreferences sharedPrefs) async {
if (sharedPrefs != null) { if (sharedPrefs != null && sharedPrefs.containsKey('cached_states')) {
try { try {
var data = json.decode(sharedPrefs.getString('cached_states') ?? '[]'); var data = json.decode(sharedPrefs.getString('cached_states'));
_parseStates(data); _parseStates(data);
} catch (e, stacktrace) { } catch (e, stacktrace) {
Logger.e('Error getting cached states: $e', stacktrace: stacktrace); Logger.e('Error getting cached states: $e', stacktrace: stacktrace);
@ -171,7 +171,7 @@ class HomeAssistant {
await ConnectionManager().sendSocketMessage(type: "get_states").then( await ConnectionManager().sendSocketMessage(type: "get_states").then(
(data) => _parseStates(data) (data) => _parseStates(data)
).catchError((e) { ).catchError((e) {
Logger.e('get_states error: $e'); Logger.e('get_states error: $e');
throw HACException("Error getting states: $e"); throw HACException("Error getting states: $e");
}); });
} }
@ -183,9 +183,9 @@ class HomeAssistant {
} }
Future _getLovelace(SharedPreferences sharedPrefs) { Future _getLovelace(SharedPreferences sharedPrefs) {
if (sharedPrefs != null) { if (sharedPrefs != null && sharedPrefs.containsKey('cached_lovelace')) {
try { try {
var data = json.decode(sharedPrefs.getString('cached_lovelace') ?? '{}'); var data = json.decode(sharedPrefs.getString('cached_lovelace'));
_rawLovelaceData = data; _rawLovelaceData = data;
} catch (e) { } catch (e) {
autoUi = true; autoUi = true;
@ -221,9 +221,9 @@ class HomeAssistant {
Future _getServices(SharedPreferences prefs) async { Future _getServices(SharedPreferences prefs) async {
services?.clear(); services?.clear();
if (prefs != null) { if (prefs != null && prefs.containsKey('cached_services')) {
try { try {
var data = json.decode(prefs.getString('cached_services') ?? '{}'); var data = json.decode(prefs.getString('cached_services'));
_parseServices(data); _parseServices(data);
} catch (e, stacktrace) { } catch (e, stacktrace) {
Logger.e(e, stacktrace: stacktrace); Logger.e(e, stacktrace: stacktrace);
@ -240,9 +240,19 @@ class HomeAssistant {
Future _getUserInfo(SharedPreferences sharedPrefs) async { Future _getUserInfo(SharedPreferences sharedPrefs) async {
_userName = null; _userName = null;
await ConnectionManager().sendSocketMessage(type: "auth/current_user").then((data) => _parseUserInfo(data)).catchError((e) { if (sharedPrefs != null && sharedPrefs.containsKey('cached_user')) {
Logger.e('auth/current_user error: $e'); try {
}); var data = json.decode(sharedPrefs.getString('cached_user'));
_parseUserInfo(data);
} catch (e, stacktrace) {
Logger.e('Error getting cached user info: $e', stacktrace: stacktrace);
}
return Future.value();
} else {
await ConnectionManager().sendSocketMessage(type: "auth/current_user").then((data) => _parseUserInfo(data)).catchError((e) {
Logger.e('auth/current_user error: $e');
});
}
} }
void _parseUserInfo(data) { void _parseUserInfo(data) {
@ -251,9 +261,9 @@ class HomeAssistant {
} }
Future _getPanels(SharedPreferences sharedPrefs) async { Future _getPanels(SharedPreferences sharedPrefs) async {
if (sharedPrefs != null) { if (sharedPrefs != null && sharedPrefs.containsKey('cached_panels')) {
try { try {
var data = json.decode(sharedPrefs.getString('cached_panels') ?? '{}'); var data = json.decode(sharedPrefs.getString('cached_panels'));
_parsePanels(data); _parsePanels(data);
} catch (e, stacktrace) { } catch (e, stacktrace) {
Logger.e(e, stacktrace: stacktrace); Logger.e(e, stacktrace: stacktrace);

View File

@ -157,10 +157,11 @@ part 'popups.dart';
EventBus eventBus = new EventBus(); EventBus eventBus = new EventBus();
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin(); FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
const String appName = "HA Client"; const String appName = 'HA Client';
const appVersionNumber = "1.0.0"; const appVersionNumber = '1.0.1';
const appVersionAdd = ""; final String appVersionAdd = secrets['version_type'] ?? '';
const appVersion = "$appVersionNumber$appVersionAdd"; final String appVersion = '$appVersionNumber${appVersionAdd.isNotEmpty ? '-' : ''}$appVersionAdd';
const whatsNewUrl = 'http://ha-client.app/service/whats_new_1.0.1.md';
Future<void> _reportError(dynamic error, dynamic stackTrace) async { Future<void> _reportError(dynamic error, dynamic stackTrace) async {
// Print the exception to the console. // Print the exception to the console.

View File

@ -19,6 +19,7 @@ class ConnectionManager {
String _tempToken; String _tempToken;
String oauthUrl; String oauthUrl;
String webhookId; String webhookId;
double haVersion;
String mobileAppDeviceName; String mobileAppDeviceName;
bool settingsLoaded = false; bool settingsLoaded = false;
int appIntegrationVersion; int appIntegrationVersion;
@ -154,7 +155,12 @@ class ConnectionManager {
if (!connecting.isCompleted) connecting.completeError(e); if (!connecting.isCompleted) connecting.completeError(e);
}); });
} else if (data["type"] == "auth_ok") { } else if (data["type"] == "auth_ok") {
Logger.d("[Received] <== ${data.toString()}"); String v = data["ha_version"];
if (v != null && v.isNotEmpty) {
haVersion = double.tryParse(v.replaceFirst('0.','')) ?? 0;
}
Logger.d("Home assistant version: $v ($haVersion)");
Crashlytics.instance.setString('ha_version', v);
Logger.d("[Connection] Subscribing to events"); Logger.d("[Connection] Subscribing to events");
sendSocketMessage( sendSocketMessage(
type: "subscribe_events", type: "subscribe_events",

View File

@ -108,40 +108,47 @@ class LocationManager {
} }
updateDeviceLocation() async { updateDeviceLocation() async {
Logger.d("[Foreground location] Started"); try {
Geolocator geolocator = Geolocator(); Logger.d("[Foreground location] Started");
var battery = Battery(); Geolocator geolocator = Geolocator();
String webhookId = ConnectionManager().webhookId; var battery = Battery();
String httpWebHost = ConnectionManager().httpWebHost; String webhookId = ConnectionManager().webhookId;
if (webhookId != null && webhookId.isNotEmpty) { String httpWebHost = ConnectionManager().httpWebHost;
Logger.d("[Foreground location] Getting battery level..."); if (webhookId != null && webhookId.isNotEmpty) {
int batteryLevel = await battery.batteryLevel; Logger.d("[Foreground location] Getting battery level...");
Logger.d("[Foreground location] Getting device location..."); int batteryLevel = await battery.batteryLevel;
Position position = await geolocator.getCurrentPosition( Logger.d("[Foreground location] Getting device location...");
desiredAccuracy: LocationAccuracy.high, Position position = await geolocator.getCurrentPosition(
locationPermissionLevel: GeolocationPermission.locationAlways desiredAccuracy: LocationAccuracy.high,
); locationPermissionLevel: GeolocationPermission.locationAlways
if (position != null) { );
Logger.d("[Foreground location] Location: ${position.latitude} ${position.longitude}. Accuracy: ${position.accuracy}. (${position.timestamp})"); if (position != null) {
String url = "$httpWebHost/api/webhook/$webhookId"; Logger.d("[Foreground location] Location: ${position.latitude} ${position.longitude}. Accuracy: ${position.accuracy}. (${position.timestamp})");
Map data = { String url = "$httpWebHost/api/webhook/$webhookId";
"type": "update_location", Map data = {
"data": { "type": "update_location",
"gps": [position.latitude, position.longitude], "data": {
"gps_accuracy": position.accuracy, "gps": [position.latitude, position.longitude],
"battery": batteryLevel ?? 100 "gps_accuracy": position.accuracy,
"battery": batteryLevel ?? 100
}
};
Logger.d("[Foreground location] Sending data home...");
http.Response response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: json.encode(data)
);
if (response.statusCode >= 300) {
Logger.e('Foreground location update error: ${response.body}');
} }
}; Logger.d("[Foreground location] Got HTTP ${response.statusCode}");
Logger.d("[Foreground location] Sending data home..."); } else {
var response = await http.post( Logger.d("[Foreground location] No location. Aborting.");
url, }
headers: {"Content-Type": "application/json"}, }
body: json.encode(data) } catch (e, stack) {
); Logger.e('Foreground location error: ${e.toSTring()}', stacktrace: stack);
Logger.d("[Foreground location] Got HTTP ${response.statusCode}");
} else {
Logger.d("[Foreground location] No location. Aborting.");
}
} }
} }

View File

@ -31,12 +31,16 @@ class MobileAppIntegrationManager {
Logger.d("Mobile app was not registered yet. Registering..."); Logger.d("Mobile app was not registered yet. Registering...");
var registrationData = Map.from(_appRegistrationData); var registrationData = Map.from(_appRegistrationData);
registrationData.addAll({ registrationData.addAll({
"device_id": "${DeviceInfoManager().unicDeviceId}",
"app_id": "ha_client", "app_id": "ha_client",
"app_name": "$appName", "app_name": "$appName",
"os_name": DeviceInfoManager().osName, "os_name": DeviceInfoManager().osName,
"supports_encryption": false, "supports_encryption": false,
}); });
if (ConnectionManager().haVersion >= 104) {
registrationData.addAll({
"device_id": "${DeviceInfoManager().unicDeviceId}"
});
}
ConnectionManager().sendHTTPPost( ConnectionManager().sendHTTPPost(
endPoint: "/api/mobile_app/registrations", endPoint: "/api/mobile_app/registrations",
includeAuthHeader: true, includeAuthHeader: true,

View File

@ -14,13 +14,13 @@ class StartupUserMessagesManager {
bool _supportAppDevelopmentMessageShown; bool _supportAppDevelopmentMessageShown;
bool _whatsNewMessageShown; bool _whatsNewMessageShown;
static final _supportAppDevelopmentMessageKey = "user-message-shown-support-development_3"; static final _supportAppDevelopmentMessageKey = "user-message-shown-support-development_3";
static final _whatsNewMessageKey = "user-message-shown-whats-new-1006"; static final _whatsNewMessageKey = "user-msg-whats-new-url";
void checkMessagesToShow() async { void checkMessagesToShow() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.reload(); await prefs.reload();
_supportAppDevelopmentMessageShown = prefs.getBool(_supportAppDevelopmentMessageKey) ?? false; _supportAppDevelopmentMessageShown = prefs.getBool(_supportAppDevelopmentMessageKey) ?? false;
_whatsNewMessageShown = prefs.getBool(_whatsNewMessageKey) ?? false; _whatsNewMessageShown = '${prefs.getString(_whatsNewMessageKey)}' == whatsNewUrl;
if (!_whatsNewMessageShown) { if (!_whatsNewMessageShown) {
_showWhatsNewMessage(); _showWhatsNewMessage();
} else if (!_supportAppDevelopmentMessageShown) { } else if (!_supportAppDevelopmentMessageShown) {
@ -52,7 +52,7 @@ class StartupUserMessagesManager {
void _showWhatsNewMessage() { void _showWhatsNewMessage() {
SharedPreferences.getInstance().then((prefs) { SharedPreferences.getInstance().then((prefs) {
prefs.setBool(_whatsNewMessageKey, true); prefs.setString(_whatsNewMessageKey, whatsNewUrl);
eventBus.fire(ShowPageEvent(path: "/whats-new")); eventBus.fire(ShowPageEvent(path: "/whats-new"));
}); });
} }

View File

@ -24,7 +24,7 @@ class _WhatsNewPageState extends State<WhatsNewPage> {
error = ""; error = "";
}); });
http.Response response; http.Response response;
response = await http.get("http://ha-client.app/service/whats_new_1.0.0_stable.md"); response = await http.get(whatsNewUrl);
if (response.statusCode == 200) { if (response.statusCode == 200) {
setState(() { setState(() {
data = response.body; data = response.body;

View File

@ -54,7 +54,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
}); });
} }
}).catchError((e) { }).catchError((e) {
Logger.e("Error loading $entityId history: $e"); Logger.e("Error loading $entityId history: $e", skipCrashlytics: true);
if (!_disposed) { if (!_disposed) {
setState(() { setState(() {
_history = []; _history = [];

View File

@ -18,8 +18,8 @@ class Logger {
print(data); print(data);
} }
static void e(String message, {dynamic stacktrace, bool skipCrashlytics: false}) { static void e(dynamic message, {dynamic stacktrace, bool skipCrashlytics: false}) {
_writeToLog(ErrorLevel.ERROR, message, stacktrace, skipCrashlytics); _writeToLog(ErrorLevel.ERROR, message.toString(), stacktrace, skipCrashlytics);
} }
static void w(String message) { static void w(String message) {

View File

@ -1,7 +1,7 @@
name: hass_client name: hass_client
description: Home Assistant Android Client description: Home Assistant Android Client
version: 1.0.0+1008 version: 1.0.1+1013
environment: environment:

View File

@ -4,6 +4,7 @@ import 'dart:io';
Future<void> main() async { Future<void> main() async {
final config = { final config = {
'syncfusion_license_key': Platform.environment['SYNCFUSION_LICENSE_KEY'], 'syncfusion_license_key': Platform.environment['SYNCFUSION_LICENSE_KEY'],
'version_type': Platform.environment['HA_CLIENT_VERSION_TYPE'] ?? ''
}; };
final filename = 'lib/.secrets.dart'; final filename = 'lib/.secrets.dart';