Resloves #570 Next Android alarm as sensor
This commit is contained in:
parent
d09afc37b5
commit
7683d18e81
@ -13,6 +13,6 @@ Discuss it on [Discord](https://discord.gg/u9vq7QE) or at [Home Assistant commun
|
|||||||
#### Last release build status
|
#### Last release build status
|
||||||
[](https://codemagic.io/apps/5da8bdab9f20ef798f7c2c65/5db1862025dc3f0b0288a57a/latest_build)
|
[](https://codemagic.io/apps/5da8bdab9f20ef798f7c2c65/5db1862025dc3f0b0288a57a/latest_build)
|
||||||
|
|
||||||
#### Special thanks to
|
#### Projects used
|
||||||
- [Crewski](https://github.com/Crewski) for his [HANotify](https://github.com/Crewski/HANotify)
|
- [HANotify](https://github.com/Crewski/HANotify) by [Crewski](https://github.com/Crewski)
|
||||||
- [Home Assistant](https://github.com/home-assistant) for some support and [Home Assistant](https://www.home-assistant.io/)
|
- [hassalarm](https://github.com/Johboh/hassalarm) by [Johboh](https://github.com/Johboh)
|
||||||
|
@ -62,7 +62,12 @@
|
|||||||
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
|
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
<receiver android:name=".NextAlarmBroadcastReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
<service
|
<service
|
||||||
android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
|
android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.keyboardcrumbs.hassclient;
|
||||||
|
|
||||||
|
import android.app.AlarmManager;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import android.webkit.URLUtil;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
|
||||||
|
public class NextAlarmBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
private static final String TAG = "NextAlarmReceiver";
|
||||||
|
private static final SimpleDateFormat DATE_FORMAT_LEGACY = new SimpleDateFormat("yyyy-MM-dd HH:mm:00", Locale.ENGLISH);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (intent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean isBootIntent = Intent.ACTION_BOOT_COMPLETED.equalsIgnoreCase(intent.getAction());
|
||||||
|
final boolean isNextAlarmIntent = AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equalsIgnoreCase(intent.getAction());
|
||||||
|
if (!isBootIntent && !isNextAlarmIntent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final AlarmManager alarmManager;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= 23) {
|
||||||
|
alarmManager = context.getSystemService(AlarmManager.class);
|
||||||
|
} else {
|
||||||
|
alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
final AlarmManager.AlarmClockInfo alarmClockInfo = alarmManager.getNextAlarmClock();
|
||||||
|
|
||||||
|
SharedPreferences prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
|
||||||
|
String webhookId = prefs.getString("flutter.app-webhook-id", null);
|
||||||
|
if (webhookId != null) {
|
||||||
|
try {
|
||||||
|
String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
|
||||||
|
"://" +
|
||||||
|
prefs.getString("flutter.hassio-domain", "") +
|
||||||
|
":" +
|
||||||
|
prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
|
||||||
|
JSONObject dataToSend = new JSONObject();
|
||||||
|
if (URLUtil.isValidUrl(requestUrl)) {
|
||||||
|
final String state;
|
||||||
|
final long triggerTimestamp;
|
||||||
|
if (alarmClockInfo != null) {
|
||||||
|
triggerTimestamp = alarmClockInfo.getTriggerTime();
|
||||||
|
final Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(triggerTimestamp);
|
||||||
|
state = DATE_FORMAT_LEGACY.format(calendar.getTime());
|
||||||
|
} else {
|
||||||
|
state = "";
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Setting time to " + state);
|
||||||
|
dataToSend.put("type", "update_sensor_states");
|
||||||
|
JSONArray dataArray = new JSONArray();
|
||||||
|
JSONObject sensorData = new JSONObject();
|
||||||
|
sensorData.put("unique_id", "next_alarm");
|
||||||
|
sensorData.put("type", "sensor");
|
||||||
|
sensorData.put("state", state); //TEST DATA
|
||||||
|
dataArray.put(0, sensorData);
|
||||||
|
dataToSend.put("data", dataArray);
|
||||||
|
|
||||||
|
String stringRequest = dataToSend.toString();
|
||||||
|
SendTask sendTask = new SendTask();
|
||||||
|
sendTask.execute(requestUrl, stringRequest);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Invalid HA url");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error setting next alarm", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Webhook id not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package com.keyboardcrumbs.hassclient;
|
package com.keyboardcrumbs.hassclient;
|
||||||
|
|
||||||
|
import android.app.AlarmManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -19,6 +19,10 @@ public class NotificationActionReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (intent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String rawActionData = intent.getStringExtra("actionData");
|
String rawActionData = intent.getStringExtra("actionData");
|
||||||
if (intent.hasExtra("tag")) {
|
if (intent.hasExtra("tag")) {
|
||||||
String notificationTag = intent.getStringExtra("tag");
|
String notificationTag = intent.getStringExtra("tag");
|
||||||
|
@ -28,6 +28,7 @@ class AppSettings {
|
|||||||
String webhookId;
|
String webhookId;
|
||||||
double haVersion;
|
double haVersion;
|
||||||
bool scrollBadges;
|
bool scrollBadges;
|
||||||
|
bool nextAlarmSensorCreated = false;
|
||||||
DisplayMode displayMode;
|
DisplayMode displayMode;
|
||||||
AppTheme appTheme;
|
AppTheme appTheme;
|
||||||
final int defaultLocationUpdateIntervalMinutes = 20;
|
final int defaultLocationUpdateIntervalMinutes = 20;
|
||||||
@ -61,6 +62,7 @@ class AppSettings {
|
|||||||
locationUpdateInterval = Duration(minutes: prefs.getInt("location-interval") ??
|
locationUpdateInterval = Duration(minutes: prefs.getInt("location-interval") ??
|
||||||
defaultLocationUpdateIntervalMinutes);
|
defaultLocationUpdateIntervalMinutes);
|
||||||
locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
||||||
|
nextAlarmSensorCreated = prefs.getBool("next-alarm-sensor-created") ?? false;
|
||||||
longLivedToken = Hive.box(DEFAULT_HIVE_BOX).get(AUTH_TOKEN_KEY);
|
longLivedToken = Hive.box(DEFAULT_HIVE_BOX).get(AUTH_TOKEN_KEY);
|
||||||
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent(
|
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent(
|
||||||
'https://ha-client.app')}&redirect_uri=${Uri
|
'https://ha-client.app')}&redirect_uri=${Uri
|
||||||
|
@ -62,12 +62,13 @@ class MobileAppIntegrationManager {
|
|||||||
includeAuthHeader: true,
|
includeAuthHeader: true,
|
||||||
data: json.encode(registrationData)
|
data: json.encode(registrationData)
|
||||||
).then((response) {
|
).then((response) {
|
||||||
Logger.d("Processing registration responce...");
|
Logger.d("Processing registration response...");
|
||||||
var responseObject = json.decode(response);
|
var responseObject = json.decode(response);
|
||||||
AppSettings().webhookId = responseObject["webhook_id"];
|
AppSettings().webhookId = responseObject["webhook_id"];
|
||||||
AppSettings().save({
|
AppSettings().save({
|
||||||
'app-webhook-id': responseObject["webhook_id"]
|
'app-webhook-id': responseObject["webhook_id"]
|
||||||
}).then((prefs) {
|
}).then((_) {
|
||||||
|
_createNextAlarmSensor(true);
|
||||||
completer.complete();
|
completer.complete();
|
||||||
eventBus.fire(ShowPopupEvent(
|
eventBus.fire(ShowPopupEvent(
|
||||||
popup: Popup(
|
popup: Popup(
|
||||||
@ -112,6 +113,7 @@ class MobileAppIntegrationManager {
|
|||||||
_askToRegisterApp();
|
_askToRegisterApp();
|
||||||
} else {
|
} else {
|
||||||
Logger.d('App registration works fine');
|
Logger.d('App registration works fine');
|
||||||
|
_createNextAlarmSensor(false);
|
||||||
}
|
}
|
||||||
completer.complete();
|
completer.complete();
|
||||||
}).catchError((e) {
|
}).catchError((e) {
|
||||||
@ -131,6 +133,42 @@ class MobileAppIntegrationManager {
|
|||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _createNextAlarmSensor(bool force) {
|
||||||
|
if (AppSettings().nextAlarmSensorCreated && !force) {
|
||||||
|
Logger.d("Next alarm sensor was previously created");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Logger.d("Creating next alarm sensor...");
|
||||||
|
ConnectionManager().sendHTTPPost(
|
||||||
|
endPoint: "/api/webhook/${AppSettings().webhookId}",
|
||||||
|
includeAuthHeader: false,
|
||||||
|
data: json.encode(
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"device_class": "timestamp",
|
||||||
|
"icon": "mdi:alarm",
|
||||||
|
"name": "Next Alarm",
|
||||||
|
"state": "",
|
||||||
|
"type": "sensor",
|
||||||
|
"unique_id": "next_alarm"
|
||||||
|
},
|
||||||
|
"type": "register_sensor"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).then((_){
|
||||||
|
AppSettings().nextAlarmSensorCreated = true;
|
||||||
|
AppSettings().save({
|
||||||
|
'next-alarm-sensor-created': true
|
||||||
|
});
|
||||||
|
}).catchError((e) {
|
||||||
|
if (e is http.Response) {
|
||||||
|
Logger.e("Error creating next alarm sensor: ${e.statusCode}: ${e.body}");
|
||||||
|
} else {
|
||||||
|
Logger.e("Error creating next alarm sensor: ${e?.toString()}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static void _showError() {
|
static void _showError() {
|
||||||
eventBus.fire(ShowPopupEvent(
|
eventBus.fire(ShowPopupEvent(
|
||||||
popup: Popup(
|
popup: Popup(
|
||||||
|
Reference in New Issue
Block a user