BangleApps/apps/sleeplog
Anton 34a9d86f20 Fix lint warnings 2024-04-01 17:27:15 +02:00
..
ChangeLog Fix lint warnings 2024-04-01 17:27:15 +02:00
README.md Update README.md 2024-03-22 16:32:49 +01:00
app-icon.js sleeplog: Add Sleep Log App 2022-02-11 09:29:02 +01:00
app.js Fix lint warnings 2024-04-01 17:27:15 +02:00
app.png sleeplog: Add Sleep Log App 2022-02-11 09:29:02 +01:00
boot.js Fix lint warnings 2024-04-01 17:27:15 +02:00
conf_20x20.png [sleeplog] Replace old icons 2022-05-20 20:14:05 +02:00
debug_20x20.png [sleeplog] Replace old icons 2022-05-20 20:14:05 +02:00
file_20x20.png [sleeplog] Replace old icons 2022-05-20 20:14:05 +02:00
interface.html [sleeplog] Correct deleteBefore function ... last 2023-04-05 23:13:34 +02:00
lib.js Fix lint warnings 2024-04-01 17:27:15 +02:00
metadata.json Fix lint warnings 2024-04-01 17:27:15 +02:00
off_20x20.png [sleeplog] Replace old icons 2022-05-20 20:14:05 +02:00
screenshot-1_app_light.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-2_day_light.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-3_graph_light.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-4_graph2_light.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-5_app_dark.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-6_day_dark.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-7_graph_dark.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
screenshot-8_graph2_dark.png [sleeplog] Update README.md + screenshots 2022-08-29 23:11:49 +02:00
settings.js Fix lint warnings 2024-04-01 17:27:15 +02:00

README.md

Sleep Log

This app logs and displays the following states:

  • sleepling status: unknown, not worn, awake, light sleep, deep sleep
  • consecutive sleep status: unknown, not consecutive, consecutive

It is using the built in movement calculation to decide your sleeping state. While charging it is assumed that you are not wearing the watch and if the status changes to deep sleep the internal heartrate sensor is used to detect if you are wearing the watch.

Explanations

  • Detection of Sleep The movement value of bangle's build in health event that is triggered every 10 minutes is checked against the thresholds for light and deep sleep. If the measured movement is lower or equal to the Deep Sleep-threshold a deep sleep phase is detected for the last 10 minutes. If the threshold is exceeded but not the Light Sleep-threshold than the last timeperiod is detected as light sleep phase. On exceeding even this threshold it is assumed that you were awake.
  • True Sleep The true sleep value is a simple addition of all registered sleeping periods.
  • Consecutive Sleep In addition the consecutive sleep value tries to predict the complete time you were asleep, even the very light sleeping periods when an awake period is detected based on the registered movements. All periods after a sleeping period will be summarized until the first following non sleeping period that is longer then the maximal awake duration (Max Awake). If this sum is lower than the minimal consecutive sleep duration (Min Consecutive) it is not considered, otherwise it will be added to the consecutive sleep value.

Logfiles are not removed on un-/reinstall to prevent data loss.

Filename (* example) Content Removeable in
sleeplog.log (StorageFile) recent logfile App Web Interface
sleeplog_1234.log* past logfiles App Web Interface
sleeplog_123456.csv* debugging files Web IDE

Main App Usage


Controls:

  • swipe left & right to change the displayed day
  • touch the "title" (e.g. Night to Fri 20/05/2022) to enter day selection prompt
  • touch the info area to change the displayed information (by default: consecutive & true sleeping)
  • touch the wrench (upper right corner) to enter the settings
  • use back button widget (upper left corner) exit the app

View:

Status Color Height
unknown black 0%
not worn red 40%
awake green 60%
light sleep cyan 80%
deep sleep blue 100%
consecutive violet as status

Settings Usage


  • Thresholds submenu Changes take effect from now on, not retrospective!
    • Max Awake | maximal awake duration 10min / 20min / ... / 60min / ... / 120min
    • Min Consecutive | minimal consecutive sleep duration 10min / 20min / ... / 30min / ... / 120min
    • Deep Sleep | deep sleep threshold 30 / 31 / ... / 100 / ... / 200
    • Light Sleep | light sleep threshold 100 / 110 / ... / 200 / ... / 400
    • Wear Temperature | Set the minimum measured temperature of the wearable to consider it being worn. Can be disabled to use the HRM instead to detect if it's being worn. Disabled / 20.0°C / 20.5°C / ... / 40.0°C
    • Reset to Default | reset to bold values above
  • BreakToD | time of day to break view 0:00 / 1:00 / ... / 12:00 / ... / 23:00
  • App Timeout | app specific lock timeout 0s / 10s / ... / 120s
  • Enabled | completely en-/disables the background service on / off
  • Debugging submenu
    • View log | display logfile data Select the logfile by its starting time. Thresholds are shown as line with its value.
      • swipe left & right to change displayed duration
      • swipe up & down to change displayed value range
      • touch the graph to change between light & dark colors
      • use back button widget (upper left corner) to go back to the logfile selection
    • Enabled | en-/disables debugging on / off
    • write File | toggles if a logfile is written on / off
    • Duration | duration for writing into logfile 1h / 2h / ... / 12h / 96
    • The following data is logged to a csv-file: timestamp (in days since 1900-01-01 00:00 UTC used by office software) , movement, status, consecutive, asleepSince, awakeSince, bpm, bpmConfidence

Web Interface Usage


Available through the App Loader when your watch is connected.

  • A list of all found logfiles with following options for each file:
    • view data Display the data to each timestamp in a table.
    • save csv-file Download a csv-file with the data to each timestamp. The time format is chooseable beneath the file list.
    • delete file Deletes the logfile from the watch. Please backup your data first!
  • csv time format JavaScript (milliseconds since 1970) / UNIX (seconds since 1970) / Office (days since 1900)
  • delete all logfiles before Deletes all logfile before the given date from the watch. Please backup your data first!

Timestamps and Files


  1. externally visible/usable timestamps (in global.sleeplog) are formatted as Bangle timestamps: seconds since 1970-01-01 00:00 UTC
  2. internally used and logged (to sleeplog.log (StorageFile)) is within the highest available resolution: 10 minutes since 1970-01-01 00:00 UTC (Bangle / (10 * 60 * 1000))
  3. debug .csv file ID (sleeplog_123456.csv) has a hourly resolution: hours since 1970-01-01 00:00 UTC (Bangle / (60 * 60 * 1000))
  4. logged timestamps inside the debug .csv file are formatted for office calculation software: days since 1900-01-01 00:00 UTC (Bangle / (24 * 60 * 60 * 1000) + 25569)
  5. every 14 days the sleeplog.log (StorageFile) is reduced and old entries are moved into separat files for each fortnight (sleeplog_1234.log) but still accessible though the app: fortnights since 1970-01-04 12:00 UTC (converted with require("sleeplog").msToFn(Bangle) and require("sleeplog").fnToMs(fortnight))
  • Logfiles from before 0.10: timestamps and sleeping status of old logfiles are automatically converted on your first consecutive sleep or manually by require("sleeplog").convertOldLog()

  • View logged data: if you'd like to view your logged data in the IDE, you can access it with require("sleeplog").printLog(since, until) or require("sleeplog").readLog(since, until) to view the raw data since & until in Bangle timestamp, e.g. require("sleeplog").printLog(Date()-24*60*60*1000, Date()) for the last 24h


Developer Information


Access statistics

  • Last Asleep Time [Date]: Date(sleeplog.awakeSince)
  • Last Awake Duration [ms]: Date() - sleeplog.awakeSince
  • Last Statistics [object]:
    // get stats of the last night (period as displayed inside the app)
    //  as this might be the mostly used function the data is cached inside the global object
    sleeplog.getStats();
    
    // get stats of the last 24h
    require("sleeplog").getStats(0, 24*60*60*1000);
    // same as
    require("sleeplog").getStats(Date.now(), 24*60*60*1000);
    // output as object, timestamps as UNIX timestamp, durations in minutes
    ={ calculatedAt: 1653123553810, deepSleep: 250, lightSleep: 150, awakeSleep: 10,
      consecSleep: 320, awakeTime: 1030, notWornTime: 0, unknownTime: 0, logDuration: 1440,
      firstDate: 1653036600000, lastDate: 1653111600000 }
    
    // to get the start of a period defined by "Break TOD" of any date
    var startOfBreak = require("sleeplog").getLastBreak();
    // same as
    var startOfBreak = require("sleeplog").getLastBreak(Date.now());
    // output as date
    =Date: Sat May 21 2022 12:00:00 GMT+0200
    
    // get stats of this period as displayed inside the app
    require("sleeplog").getStats(require("sleeplog").getLastBreak(), 24*60*60*1000);
    // or any other day
    require("sleeplog").getStats(require("sleeplog").getLastBreak(Date(2022,4,10)), 24*60*60*1000);
    
  • Total Statistics [object]:
    // use with caution, may take a long time !
    require("sleeplog").getStats(0, 0, require("sleeplog").readLog());
    

Add functions triggered by status changes or inside a specified time period

With the following code it is possible to add functions that will be called every 10 minutes after new movement data when meeting the specified parameters on each :

// first ensure that the sleeplog trigger object is available (sleeplog is enabled)
if (typeof (global.sleeplog || {}).trigger === "object") {
  // then add your parameters with the function to call as object into the trigger object
  sleeplog.trigger["my app name"] = {
    onChange: false,   // false as default, if true call fn only on a status change
    from: 0,           // 0 as default, in ms, first time fn will be called
    to: 24*60*60*1000, // 24h as default, in ms, last time fn will be called
      // reference time to from & to is rounded to full minutes
    fn: function(data, thisTriggerEntry) { print(data); } // function to be executed
  };
}

The passed data object has the following properties:

  • timestamp: of the status change as date object, (should be around 10min. before "now", the actual call of the function)
  • status: value of the new status (0-4), (0 = unknown, 1 = not worn, 2 = awake, 3 = light sleep, 4 = deep sleep)
  • consecutive: value of the new status (0-2), (0 = unknown, 1 = no consecutive sleep, 2 = consecutive sleep)
  • prevStatus: if changed the value of the previous status (0-4) else undefined,
  • prevConsecutive: if changed the value of the previous status (0-2) else undefined

If you want to use other variables or functions from the trigger object inside the trigger fn function, you will find them inside the thisTriggerEntry object, as the this keyword is not working in this scenario. The function itself (the fn property) is not passed inside the thisTriggerEntry object.


Worth Mentioning


To do list

  • Optimize interface.html:
    • Open logfile through require("Storage") instead of require("sleeplog").
    • Give feedback how much files have been deleted on "delete all logfiles before".
  • Check translations.
  • Add more functionallities to interface.html.
  • Enable receiving data on the Gadgetbridge side + testing. Help appreciated!

Requests, Bugs and Feedback

Please leave requests and bug reports by raising an issue at github.com/storm64/BangleApps (or send me a mail).

Creator

Storm64 (mail, github)

Contributors

myxor (github)

Attributions

The app icon is downloaded from https://icons8.com.

License

MIT License