Your data
bottomtime keeps two things: an untouched copy of every file it reads, and a
SQLite database decoded from those copies. The copies are the record. The
database can be thrown away and rebuilt from them at any time, which is what
bottomtime rebuild and the app’s Rebuild from saved files do.
Where it lives
The app keeps everything in ~/Library/Application Support/bottomtime on a
Mac, and in %APPDATA%\bottomtime on Windows:
| Path | What it is |
|---|---|
dives.db |
The database. |
archive/fit/ |
Every Garmin FIT file, as Garmin sent it. |
archive/shearwater_db/ |
Every copy of Shearwater Cloud’s database that bottomtime read. |
archive/garmin_index/ |
Garmin Connect’s list of your dive activities, with their names and locations. |
garmin/ |
Your Garmin Connect sign-in, if you signed in. |
settings.json |
The app’s settings. |
Each archived file is named by the SHA-256 hash of its contents, so the same
file is never stored twice and a file’s name proves its contents haven’t
changed. The command line uses data/dives.db and archive/ in the current
folder unless you pass --db and --archive.
Exported files
Export this dive in the app, and bottomtime export N, write one CSV row
per sample per computer. The first four columns are:
| Column | Meaning |
|---|---|
source |
garmin or shearwater. |
source_dive_id |
Which log the row came from. |
computer |
The computer’s model, such as Perdix 2. |
dive_time_s |
Seconds from the start of the dive, on the timeline every computer shares. |
The sample columns from the tables below follow. A Garmin row leaves the Shearwater-only columns empty, and the other way round. Values are always metric.
Export all writes a zip file with one such CSV per dive in a dives
folder, and a dives.csv with one row per dive: the file name, dive number,
start time in UTC, UTC offset, runtime, max depth, whether it’s a pool or test
dive, the computers, the name, the mode, max GF99, GF99 at surfacing, CNS,
and minutes of deco.
Sample columns
Every sample has t_s, the seconds since that computer’s log started.
Shearwater
Decoded from Shearwater’s native log format by pnf, whose SPEC.md gives the byte each value comes from. Shearwater computers record a sample every 10 seconds by default.
| Column | Meaning |
|---|---|
depth_m |
Depth in metres. |
temp_c |
Water temperature in °C. |
gf99 |
GF99, in percent. Empty when the computer used DCIEM. |
ceiling_m |
The deco ceiling in metres. Empty under DCIEM. |
at_plus_five_min |
@+5: time to surface if you stayed five more minutes. |
tts_min |
Time to surface, in minutes. |
ndl_min |
No-decompression limit in minutes. Empty while in deco. |
stop_depth_m, stop_time_min |
The next required stop. 0 m means none. |
in_deco |
1 while the computer showed a required stop. |
cns_pct |
CNS oxygen toxicity, in percent. |
avg_ppo2 |
The ppO2 the computer used, in bar. |
sensor1_ppo2, sensor2_ppo2, sensor3_ppo2 |
Each oxygen sensor’s ppO2, on a CCR. |
sensor1_raw, sensor2_raw, sensor3_raw |
The sensors’ raw readings, as the computer stored them. |
setpoint |
The CCR setpoint, in bar. |
o2_pct, he_pct |
The gas in use. |
safe_ascent_depth_m |
The safe ascent depth, under DCIEM only. |
battery_v, battery_pct |
The computer’s battery voltage and percentage. |
tank0_psi, tank1_psi, gas_time_min, sac |
Air integration, when a transmitter is paired. |
status_flags, solenoid_fired_count |
The raw status byte, and the CCR oxygen solenoid count it carries. |
extra_json |
Anything else pnf decoded for the sample, such as extra transmitters. |
Garmin
Read with Garmin’s official FIT SDK. A Descent usually records a sample every second.
| Column | Meaning |
|---|---|
depth_m |
Depth in metres. |
temp_c |
Temperature in °C. |
heart_rate |
Heart rate in beats per minute. |
absolute_pressure |
Pressure in pascals. |
lat, lon |
Position, when Garmin puts one in a sample. Usually empty, since a watch has no GPS underwater. |
next_stop_depth_m, next_stop_time_s |
The next required stop. |
tts_s, ndl_s |
Time to surface and no-decompression limit, in seconds. |
cns_pct |
CNS oxygen toxicity, in percent. |
n2_load |
Nitrogen tissue loading, as Garmin reports it. |
po2 |
ppO2 in bar. |
ascent_rate |
Ascent rate in metres per second. |
air_time_remaining_s, pressure_sac, volume_sac, rmv |
Air integration, when a transmitter is paired. |
extra_json |
Every other field Garmin recorded in the sample, by name or number. |
Tables
| Table | One row per |
|---|---|
raw_artifacts |
Archived file: its kind, SHA-256, size, where it came from, and where it’s archived. |
source_dives |
Log from one computer: source, serial, model, name, start time on its own clock and in UTC, runtime, max depth, mode, the decoded header verbatim, and for Shearwater the original log bytes. |
garmin_samples, shearwater_samples |
Sample, with the columns above. Never resampled. |
gases |
Gas a computer had set up. |
gas_segments |
Stretch of a dive on one gas. |
events |
Event a computer logged, such as a Garmin dive alarm, with its full payload. |
undecoded_payloads |
Record or message bottomtime doesn’t understand yet, kept raw so a later version can decode it. |
matches |
Link between two logs of the same dive: clock offset, residual skew, cross-correlation score, and status (auto, confirmed, or rejected). |
dives |
Dive: number, start time, UTC offset, runtime, max depth, and whether it’s a pool or test dive. |
dive_members |
Log in a dive, with offset_s, the seconds from the dive’s start to the log’s first sample. |
Two views cover common questions. v_dive_summary is one row per dive with
its sources, and v_samples_unified puts the columns both makers record
(depth, temperature, time to surface, stop depth, CNS) from every log into
one table.
meta holds the schema version. When a new version of bottomtime changes the
schema, it asks for a rebuild from the archive.