feature: Sleep as android support #3687
No reviewers
Labels
No labels
device mi band 7
activity post processing
activity/health
Android 12
Android 13
android integrations
architecture
Bangle.js
bug
changes requested
charts
deprecation notice
details not provided
developer documentation
device amazfit band 5
device amazfit bip
device amazfit cor
device Casio
device fossil
device garmin
device gtr 2e
device gts 2 mini
device h30
device hplus
device huami
device Huawei
device liveview
device mi band
device mi band 2
device mi band 3
device mi band 4
device mi band 5
device mi band 6
device no.1 f1
device pace
device pebble
device pebble 2
device pinetime infinitime
device request
device sony
device support
device watch 9
device xiaomi
discussion
documentation
duplicate
enhancement
feature request
Gadgetbridge
good first issue
help wanted
i am developing my own app can you help
icebox
intent api
internationalisation
invalid
needs work
network companion app
new device
no feedback
not a bug
notifications
one of the 1000 issues about disconnection
pairing/connecting
potentially fixed / confirm and close
question
research
security
seems abandoned
Solved, waiting for F-Droid release
suggest to close
task
user interface / UX
wear os
weather
wontfix
Zepp OS
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Freeyourgadget/Gadgetbridge#3687
Loading…
Reference in a new issue
No description provided.
Delete branch "nitanmarcel/Gadgetbridge:sleep_as_android"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Rework of #3188 which seems to not be updated for a long time.
Going to a different approach, instead of implementing support for just a specific device it focuses on general support.
The first commit brings a receiver for sleep as android intents that then trigger the method
onSleepForAndroidAction
on device support classes.TODO:
Implement an option to set a device as the default provider for Sleep As Android.
Implement sending data to Sleep As Android from a device to use as example. Probably a ZeppOS device which I own.
Move configuration to preferences screen
Features toggles
Alarms and alarm slot selector
Pause/Resume tracking from watch7fcf1f5fd4
toa4cecc0c93
Option to set unset a device as the default provider for Sleep For Android
I feel like selecting the default device for sleep as android might fit better in a "Sleep for Android" preferences screen (maybe there are other settings we want, for example enabling the feature).
You can see an example of how we list all available devices in the dashboard preferences.
I'm actually thinking of adding controls on what data to be sent to sleep as android, so I guess that will be a good place to move the configuration.
I tough of this as more of a device specific control since it's not something that every device can support, for example earbuds.
I'll move it to it's own settings if you would like, and handle the provider device, default alarm slot (todo) there. Plus the data controls.
I'd suggest a supportsSleepAsAndroid on the coordinators, so they can declare whether they implement support or not. I haven't checked what's needed, but maybe even we can declare what specific capabilities are supported (accelerometer, SPO2, etc)
I do have that, that's how I'm checking whatever to show the provider option or not. Or to which coordinator to send the intents.
Yeah we could have a getSupportedSleepAsAndroidFeatures (maybe something shorter) on coordinators to return an array or something with some constants.
Something like this?
Done.
Now there are toggle for what data to send. The deactivated switches mean that the current selected device does not support that specific data.
EDIT: I've merged RR interval and SDDN into the heart rate feature since they require the same sensors
ed27c74f8e
toad262e2ceb
WIP: feature: Sleep as android supportto feature: Sleep as android support@joserebelo
I think this is ready for a review as it is. It sends enough data to make Sleep As Android reliable.
feature: Sleep as android supportto WIP: feature: Sleep as android supportWithout looking at the code, is it also possible to provide analyzed sleep data back to Gadgetbridge for charting and archiving?
Based on this yes.
https://docs.sleep.urbandroid.org/devs/content_provider_api.html#sleep-data-content-provider
I used it to track my sleep last night. So far it works pretty good.
The missing heart rate numbers seem to be a bug with Sleep As Android. If I zoom on a timestamp I can see the the numbers flashing.
EDIT: Nope. it was totally my fault I guess xD
a8c877a350
to8a20e5e088
@joserebelo what does -1 means in real time HR bpm? That the data is broken or that there's no data sent from the watch?
EDIT: that looks maybe like a bug? I've tested with Notify app and the HR is constantly sent correctly compares with Gadgetbridge
I've opened an issue since it sometimes works and sometimes it doesn't.
#3695
7817974997
to68540f64a1
c9567a6a5a
Does anyone has any idea how to handle sending tracking actions to sleep as android?
I was thinking notifications that have buttons for increasing the pause time and resuming the tracking but I don't think my mi band 7 supports multiple buttons. Or I just can't figure out how to use them
@nitanmarcel maybe we could hijack the canned responses as buttons?
I suppose we could.
I've took a look at Notify and it seems that it doesn't handle this at all on the watch. Doesn't seem to handle pausing and un pausing the tracking at all
Anyway I wish to remove the WIP today if everything goes fine. Hopefully, I'm currently analyzing the data I have with someone from Sleep As Android support since I've had some issues a couple of days ago and I want to make sure the tracking is on point
bc6c44e892
tod42080111d
WIP: feature: Sleep as android supportto feature: Sleep as android supportThe PR is pretty much done and now it's ready for a review.
There is a small issue with the movement received from my watch with some unusual wild movement but I'm not 100% sure it's caused by my watch, the code or how badly I'm sleeping. Except that everything looks good so far.
My graph:
Average graph:
feature: Sleep as android supportto WIP: feature: Sleep as android supportNah I don't like how this ended so far, I need more time to figure out what's wrong with the movement data.
d42080111d
toc3b6e983ce
WIP: feature: Sleep as android supportto feature: Sleep as android supportReady for review
This is very cool - great effort!
Just a couple of comments here and there, but my main concern would really be to remove the sender from the coordinator, as I believe it should live in the support class, unlike the supported features.
@ -0,0 +42,4 @@
if (!defaultDeviceAddr.isEmpty()) {
GBDevice device = GBApplication.app().getDeviceManager().getDeviceByAddress(defaultDeviceAddr);
if (device != null) {
int maxAlarmSlots = device.getDeviceCoordinator().getAlarmSlotCount(device);
There may be a weird interaction here with the alarms reserved for calendar events on some devices.
You should probably subtract
int reservedSlots = prefs.getInt(DeviceSettingsPreferenceConst.PREF_RESERVER_ALARMS_CALENDAR, 0);
@ -0,0 +204,4 @@
*/
public void confirmConnected() {
if (!isDeviceDefault()) return;
LOG.debug("Confirming connected");
Shouldn't we actually confirmed that we're connected here? Maybe
device.isInitialized
?Yeah. I've implemented the check in isDeviceDefault() method.
The confirmConnected one just sends an intent to sleep as android when it requests it.
@ -84,6 +86,8 @@ public abstract class ZeppOsCoordinator extends HuamiCoordinator {
return Collections.emptyMap();
}
private final SleepAsAndroidSender sleepAsAndroidSender = new SleepAsAndroidSender(new ArrayList<>(List.of(SleepAsAndroidFeature.ACCELEROMETER, SleepAsAndroidFeature.HEART_RATE, SleepAsAndroidFeature.NOTIFICATIONS, SleepAsAndroidFeature.ALARMS)));
Coordinators are supposed to be stateless, and this sender is stateful by design (i needs to know the device).
I would refactor this into a function to get the supported features:
And I would add the device as a parameter on the SleepAsAndroidSender. This would allow us to instantiate it directly in the support class, and make it clear that there should be an instance of the sender for each device.
What do you think?
An EnumSet would be more efficient even.
I've used EnumSet also I moved SleepAsAndroid to Support
@ -480,3 +493,2 @@
developer.add(R.xml.devicesettings_wifi_hotspot);
}
if (supportsFtpServer(device)) {
if (supportsWifiHotspot(device)) {
Any reason to move the wifi hotspot? I think it makes sense to keep separate from ftp server.
@ -0,0 +15,4 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
I think we should just ignore the action here if sleep as android is disabled in preferences.
@ -870,0 +972,4 @@
}
private void setSleepAsAndroidAlarm(int hour, int minute, boolean enabled) {
Alarm alarm = new Alarm() {
Instead of this class, you can use
AlarmUtils.createSingleShot
Is there a way to trigger an alarm without setting one?
I used createSignleShot instead of manually creating the Alarm object
I don't think all devices support it, setting an alarm is probably the most supported way
Yeah I've noticed in AlarmClockReceiver that it sends a notification of type GENERIC_ALARM_CLOCK but it acts as an notification for my device.
Alarms will be a little weird. At least on mi band 7 due to limitations.
On device that supports it, should be better to use START_ALARM and STOP_ALARM to give more control over alarms.
Currently Mi Band 7 will know when an alarm was set but not when was disabled.
I don't understand the problem - do you need to know on the phone when the alarm was stopped, or to notify the band from the phone that it should stop?
@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
This file is not needed, right?
@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
This file is not needed, right?
@ -2792,2 +2792,4 @@
<string name="pref_speak_notifications_aloud_title">Speak Notifications Aloud</string>
<string name="pref_header_calls_and_notifications">Calls and notifications</string>
<string name="sleepasandroid_settings">Sleep As Android</string>
<string name="pref_sleepasandroid_enable_title">Enable</string>
Can you re-use
function_enabled
?@ -0,0 +6,4 @@
android:title="@string/pref_header_general"
app:iconSpaceReserved="false">
<SwitchPreferenceCompat
android:defaultValue="true"
I think this should be disabled by default, as it can leak data without the user being aware otherwise.
@ -0,0 +7,4 @@
app:iconSpaceReserved="false">
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="pref_key_sleepasandroid_enable"
Actually, I don't see this preference being used anywhere 🤔 did I miss it?
@ -589,0 +594,4 @@
@Override
public Set<SleepAsAndroidFeature> getSleepAsAndroidFeatures() {
return null;
nulls are evil, I'd prefer
return Collections.emptySet();
@ -0,0 +16,4 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (GBApplication.getPrefs().getBoolean("pref_key_sleepasandroid_enable", true)) {
The default should be false here.
f350566d4b
to00e45f2737
@ -0,0 +108,4 @@
int maxAlarmSlots = device.getDeviceCoordinator().getAlarmSlotCount(device);
if (maxAlarmSlots > 0) {
List<String> alarmSlots = new ArrayList<>();
int reservedAlarmSlot = GBApplication.getPrefs().getInt(DeviceSettingsPreferenceConst.PREF_RESERVER_ALARMS_CALENDAR, 0);
This preference is the number of slots reserved, not the slot index.
for (int i = reservedAlarmSlot; i < maxAlarmSlots; i++) {
I hope I got it correctly now.
@ -0,0 +77,4 @@
* @return
*/
public boolean isFeatureEnabled(SleepAsAndroidFeature feature) {
boolean enabled = true;
I think we should return false right away here if
pref_key_sleepasandroid_enable
is false - this disables all features / every function here.Apologies - 2 last comments and I believe this should be good to go.
@nitanmarcel What do you think are the minimum requirements for a device to support sleep as android? For instance my device reports only minutely heart rate and steps, but not real-time and no raw movement sensor data. I'd like to know whether it would be worth the effort to try to add support for it.
Raw sensors are a must for Sleep as Android, you can get away without the other ones.
Doesn't support or it's not implemented yet in Gadgetbridge?
Two other things:
Yeah, I did that with the other commits.
The non nightly package might have worked because Gadgetbridge is used by pebble so I assume it's whitelisted now that I look at it
Actually you might be able to get away without realtime raw sensors. I don't think Sleep as Android will detect deep sleep and such but for tracking the HR might work.
00e45f2737
to2190c82ed7
Gave this a quick smoke test, seems to work fine (at least data seems to flow :))
I have also added a small page to the website in
8e6faaa7ca
, feel free to add any more info if you want.Thanks!
Nice that the implementation of Sleep as Android is available.
Does this only work with Zepp devices?
@skdubg yup, this implementation only covers Zepp OS, although it shouldn't be too hard to add support to other devices that can provide the same data.
maybe there is someone who can do this for Xiaomi protobuf devices 🙂