<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BreakFinderSurf</title>
    <description>The latest articles on DEV Community by BreakFinderSurf (@breakfindersurf).</description>
    <link>https://dev.to/breakfindersurf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4188836%2Fb6b18c01-af1d-4b98-9edc-1f250fa7486c.png</url>
      <title>DEV Community: BreakFinderSurf</title>
      <link>https://dev.to/breakfindersurf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/breakfindersurf"/>
    <language>en</language>
    <item>
      <title>Surf File Imports Now Detect Waves Properly</title>
      <dc:creator>BreakFinderSurf</dc:creator>
      <pubDate>Sat, 17 Oct 2026 13:05:53 +0000</pubDate>
      <link>https://dev.to/breakfindersurf/surf-file-imports-now-detect-waves-properly-51pp</link>
      <guid>https://dev.to/breakfindersurf/surf-file-imports-now-detect-waves-properly-51pp</guid>
      <description>&lt;p&gt;I'm the dev of BreakFinder, and this is the write-up of the file import work I finished in July. The import is no longer a dump-and-pray tool. You upload a raw file, the wave detector runs on its GPS and motion data, and you get an interactive map where you choose which detected waves count. Tuning sliders persist between uploads. The result saves as a real surf session that sits next to your watch-synced sessions in the logbook.&lt;/p&gt;

&lt;p&gt;For a long time, the import path was the weak link. Watches worked. Manual entry worked. But the moment you handed BreakFinder a raw file from a watch export, a third-party app, or a friend's Strava download, the experience fell apart. It doesn't anymore.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the import used to be the weak link
&lt;/h2&gt;

&lt;p&gt;Here is what happened before. You finished a session. Your watch recorded it. You exported the file because you wanted to keep the raw data, or because you switched apps, or because the live sync failed and all you had left was the FIT file in Garmin Connect's export folder.&lt;/p&gt;

&lt;p&gt;You uploaded it to BreakFinder, and what came back was a flat list of GPS points. No waves. No ride segments. No speed breakdown. Just a track on a map and a total distance number.&lt;/p&gt;

&lt;p&gt;That's a breadcrumb trail, and it tells you nothing about the surf.&lt;/p&gt;

&lt;p&gt;The file itself was fine. FIT, GPX, and TCX files from modern sports watches all carry the raw material: timestamped latitude and longitude, speed, and often heart rate. The problem was that the import pipeline stopped at parsing. It never ran the data through the same wave detection that powers the wearable sync.&lt;/p&gt;

&lt;p&gt;So you had two kinds of session in one logbook. Watch-synced sessions, with full wave-by-wave breakdowns. File-imported sessions with nothing in them.&lt;/p&gt;

&lt;p&gt;That gap is closed now.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the new import actually does
&lt;/h2&gt;

&lt;p&gt;Three file formats are supported. FIT is Garmin's binary format and the most common export from surf-capable watches. GPX is the open XML standard that nearly every platform can produce. TCX is the older Training Center XML format that Strava, Garmin Connect, and a few other tools still emit.&lt;/p&gt;

&lt;p&gt;All three go through the same path.&lt;/p&gt;

&lt;p&gt;First, the parser extracts the sample stream: timestamp, latitude, longitude, speed where available, and heart rate where present. FIT files carry the richest data because Garmin's schema includes sport-specific messages. GPX and TCX are lighter, but the GPS track is usually complete enough for detection.&lt;/p&gt;

&lt;p&gt;Second, the sample stream goes into the existing wave detection pipeline, the same detector that processes live watch data. It smooths the speed signal, finds riding-speed bursts that stand out from paddling, validates each candidate by duration and distance, and produces wave rides with a start point, an end point, max speed, and ride length.&lt;/p&gt;

&lt;p&gt;Third, instead of just dumping the result, the import shows you an interactive map.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interactive wave selection on the map
&lt;/h2&gt;

&lt;p&gt;This is the part that changed the import from passive to active.&lt;/p&gt;

&lt;p&gt;When detection finishes, you see your full GPS track with every detected wave highlighted. Each wave has a coloured segment along the track and a number. Click a wave and you get its details: duration, distance, max speed, and start and end coordinates.&lt;/p&gt;

&lt;p&gt;Then you decide what counts.&lt;/p&gt;

&lt;p&gt;Some detected waves are real. You remember them. The speed looks right, the segment sits along the peak, and the duration matches what you rode. Keep those.&lt;/p&gt;

&lt;p&gt;Some are false positives. The detector caught a fast paddle into the impact zone, or a current-assisted drift that briefly hit riding speed. Unselect those and they disappear from the session.&lt;/p&gt;

&lt;p&gt;Some waves were missed. Maybe you caught a small inside wave that never hit the speed threshold. You can add it by selecting the segment on the track.&lt;/p&gt;

&lt;p&gt;The session totals update live as you select and deselect: wave count, riding time, distance ridden, and average speed. They reflect only what you confirm.&lt;/p&gt;

&lt;p&gt;No wave detector gets every wave right. The honest approach is to run the detector, show the result, and let the surfer who was actually in the water make the final call. That's how every file import works now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Presets and sliders that remember your settings
&lt;/h2&gt;

&lt;p&gt;Every surfer is different. A longboarder at a mellow beach break rides at lower speed than a shortboarder at a hollow reef, so the same detection thresholds don't fit both.&lt;/p&gt;

&lt;p&gt;The import now exposes tuning sliders: minimum riding speed, minimum ride duration, and minimum ride distance. Adjust one and the detection re-runs on the map straight away. Push the speed threshold up and the marginal waves drop away. Lower the duration threshold and the short inside waves come back.&lt;/p&gt;

&lt;p&gt;Here is the part that took real work: the sliders persist.&lt;/p&gt;

&lt;p&gt;You tune your settings on one import and save the session. Two weeks later you upload another file, and your slider values are right where you left them. You don't re-tune from scratch every time.&lt;/p&gt;

&lt;p&gt;The persistence is per user, not per session. Your preset travels with your account. If you surf mostly the same spot on the same board, your detection settings are already dialed in by the second import. If you switch between a longboard spot and a shortboard spot, you can save several presets and switch between them.&lt;/p&gt;

&lt;p&gt;People who import regularly were tired of re-adjusting the same sliders every session, so this was a common request.&lt;/p&gt;




&lt;h2&gt;
  
  
  The result is a real surf session
&lt;/h2&gt;

&lt;p&gt;This is the change that ties everything together.&lt;/p&gt;

&lt;p&gt;When you confirm your wave selection and save, the import doesn't create a special file-import record or a second-class session object. It creates a standard &lt;code&gt;SurfSessions::Session&lt;/code&gt;, with the same model, the same associations, and the same wave ride structure as a session that came in from a Garmin, Apple Watch, Wear OS, Amazfit, HarmonyOS, Suunto, or Strava sync.&lt;/p&gt;

&lt;p&gt;In practice, the imported session shows up in your logbook next to your watch sessions. It counts toward your session totals and your progression stats. If you have a board or wetsuit attached, it shows up in your equipment history. The wave map and the wave-by-wave breakdown look identical to a watch-synced session, because the data shape and the rendering pipeline are the same.&lt;/p&gt;

&lt;p&gt;If you connect a watch later and start syncing live, your old imported sessions stay where they are. One continuous history.&lt;/p&gt;

&lt;p&gt;The source is recorded, so you can always tell a session came from a FIT import, a live Garmin sync, or a manual entry. Functionally, they are peers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;A few groups get the most out of it.&lt;/p&gt;

&lt;p&gt;Surfers who switched watches. You had a Garmin, moved to a Huawei Watch, and your old sessions are FIT files in a folder. Import them and they become real sessions with real wave data.&lt;/p&gt;

&lt;p&gt;Surfers whose live sync failed. Saltwater kills Bluetooth connections. The phone got wet, the watch lost its pairing, and the session never synced. Pull the file off the watch, drop it in, and recover the session with full detection.&lt;/p&gt;

&lt;p&gt;Surfers using third-party apps. Some people record with the watch's native sport mode or with another app, and want the BreakFinder wave analysis afterwards. GPX and TCX exports from those tools import cleanly now.&lt;/p&gt;

&lt;p&gt;Surfers who want more control. The sliders and manual wave selection let you shape the final session more than the live watch path, where detection runs on the device and you accept what it gives you.&lt;/p&gt;




&lt;h2&gt;
  
  
  What still needs work
&lt;/h2&gt;

&lt;p&gt;The import is better. It isn't finished.&lt;/p&gt;

&lt;p&gt;FIT parsing is solid across Garmin surf exports and most fitness-watch open-water swim files. GPX handles standard tracks from Strava, Komoot, and similar tools. TCX is the roughest of the three because the format is loose and every tool writes it slightly differently. Some TCX files with unusual namespace declarations or missing timestamps can still produce incomplete sample streams. Those cases fail gracefully now instead of crashing, but the detection gets worse.&lt;/p&gt;

&lt;p&gt;Heart rate parsing works when the file includes it. Many GPX exports from third-party tools strip heart rate, and nothing can recover data that was never written to the file.&lt;/p&gt;

&lt;p&gt;Manual wave addition on the map works, but it's fiddly on touchscreens. Selecting a precise segment with a finger is harder than with a mouse. A touch-friendly selection mode is on the list.&lt;/p&gt;

&lt;p&gt;The presets system currently allows unlimited saved presets per account, which sounds generous but gets messy fast. A sensible default limit and a preset management view are coming.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The import tool is at &lt;a href="https://breakfinder.surf/en/surf_sessions/file-import" rel="noopener noreferrer"&gt;breakfinder.surf/en/surf_sessions/file-import&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can upload and preview without an account. Saving the session requires a login, same as the board sensor import.&lt;/p&gt;

&lt;p&gt;If something parses wrong or the detection looks off on a specific file, send the file to &lt;code&gt;philipp.winkler@breakfinder.surf&lt;/code&gt;. Real files from real sessions are what make the parser and detector better.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm the dev of BreakFinder. This article was first published on breakfinder.surf, where the import tool linked above is part of the app.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>surfing</category>
      <category>garmin</category>
      <category>gpx</category>
      <category>sports</category>
    </item>
    <item>
      <title>Fourteen Days at La Pared, Building Wave Detection in the Water</title>
      <dc:creator>BreakFinderSurf</dc:creator>
      <pubDate>Fri, 16 Oct 2026 12:34:03 +0000</pubDate>
      <link>https://dev.to/breakfindersurf/fourteen-days-at-la-pared-building-wave-detection-in-the-water-3kpl</link>
      <guid>https://dev.to/breakfindersurf/fourteen-days-at-la-pared-building-wave-detection-in-the-water-3kpl</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://breakfinder.surf/en/blog/14-days-la-pared-building-wave-detection" rel="noopener noreferrer"&gt;breakfinder.surf&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I'm Philipp, I surf the Baltic out of Flensburg and I'm the dev behind BreakFinder, a surf tracker for smartwatches. I recently spent 14 days at La Pared on the west coast of Fuerteventura. Most mornings I surfed. Most evenings I sat with the data from that session and tried to work out why my own app had counted what it counted.&lt;/p&gt;

&lt;p&gt;The short version of this trip has come up in a few places already. This is the long one, session by session, with the bugs in the order they showed up. I'll explain them the way I'd explain them in the car park, without code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three watches on me at once
&lt;/h2&gt;

&lt;p&gt;The setup looked a bit silly. A Garmin Instinct 2S on my left wrist, close to the hand. A Galaxy Watch running Wear OS higher up on the forearm. An Amazfit T-Rex Ultra on Zepp OS on my right wrist. Each one ran its own port of the same detection rules.&lt;/p&gt;

&lt;p&gt;The idea behind it was simple. If all three follow the same rules and I'm the only one riding, they should agree. Whenever they didn't, at least one of them was wrong, and the other two usually pointed at which one.&lt;/p&gt;

&lt;p&gt;There was no Apple Watch on my arm. The Apple Watch version got the same fixes as the others, but I didn't test it in the water at La Pared, so I won't pretend I did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first session told three different stories
&lt;/h2&gt;

&lt;p&gt;After the first session with all three watches, they disagreed badly. The Galaxy Watch mostly counted my paddling as waves. The Garmin counted almost nothing but things that weren't waves. The Amazfit counted too few. None of them matched what I had actually ridden.&lt;/p&gt;

&lt;p&gt;Going through the tracks that evening, I found three causes. When you paddle, your arm swings, and on the wrist that creates short spikes in speed. To the watch, a spike looked like the start of a ride. Then a clean, even ride sometimes got thrown out for being "too flat", because the rules expected a ride to be bumpier. And a hard paddle into a wave could switch the watch into riding mode and never properly switch it back. The cooldown after that swallowed the real take-off.&lt;/p&gt;

&lt;p&gt;The fix became the heart of the new detection. A wave only counts if you actually glide towards the beach for a short stretch. Paddling out to sea doesn't count, and a speed spike on its own isn't enough. I call that part the ride core.&lt;/p&gt;

&lt;p&gt;Honestly, that was the biggest lesson of the whole trip. To a watch, paddling looks a lot like surfing. Speed alone can't tell them apart. Direction plus a bit of distance can. I wrote about how wave counts go wrong on watches in general in an older post on &lt;a href="https://breakfinder.surf/en/blog/why-garmin-counts-47-waves" rel="noopener noreferrer"&gt;why Garmin counts 47 waves&lt;/a&gt;, but sitting in the line-up with three of them on me made it a lot more concrete.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the GPS shows up late
&lt;/h2&gt;

&lt;p&gt;The next session had a different problem. The Galaxy Watch missed most of the rides I could clearly see in the other two tracks. Its GPS points came in bundles and late. By the time the watch knew I was moving fast, the moment to decide was already over. The Garmin had its own trouble that day, it hardly got a GPS fix at all while my arm was under water.&lt;/p&gt;

&lt;p&gt;So the watch now looks further back before the start of a wave, and it accepts GPS points that arrive late. On Wear OS I also asked the system for location updates that don't get batched. While I was at it, I loosened the thresholds a little for slower, smaller waves. Those are the waves beginners ride, and the ones I get at home on the Baltic. They were falling through before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The day of small, mean bugs
&lt;/h2&gt;

&lt;p&gt;The third session was the one where everything weird came out at once.&lt;/p&gt;

&lt;p&gt;A paddle attempt that the watch rightly rejected kept it locked for a while afterwards. The real wave came exactly in that window and wasn't counted. Now the lock after a rejected attempt is short.&lt;/p&gt;

&lt;p&gt;The Garmin counted one paddle-out twice, because its second "wave" reused the GPS points of the first. Now the watch can't look back past the end of the previous candidate, and paddling back out is recognised more strictly as going the wrong way.&lt;/p&gt;

&lt;p&gt;The Galaxy Watch kept losing GPS under water for minutes at a time. Its GPS quality check then blocked rides it should have counted. Now that check only steps in when reception stays bad for a long time, and it lets go faster.&lt;/p&gt;

&lt;p&gt;The Amazfit had two of its own. Gaps of several seconds in the GPS broke the check at the start of a ride. And the session got split in two, most likely because the wet screen registered phantom touches. One surf now stays one session, the water lock holds in the sea, and you unlock by tapping a dot, so no buttons are needed.&lt;/p&gt;

&lt;p&gt;And the Garmin had been treating old or missing speed values as if they were live. Now only fresh GPS fixes count, and a missing speed value is neutral.&lt;/p&gt;

&lt;p&gt;Each of these came out of one session and was fixed before the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tool for the evenings
&lt;/h2&gt;

&lt;p&gt;That same day I built a small tool that I've kept around since. It takes the tracks from all three watches and works out, by consensus, when the real rides happened. I checked it against the waves I remembered from that session, and every one of them was on its list. It also found rides I hadn't remembered at all.&lt;/p&gt;

&lt;p&gt;That changed the evening loop. Before, I was comparing three watches with my memory. After, I compared each watch with the other two plus my memory, which is much harder to fool. I could see which watch had missed a wave and which one had made one up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Late triggers, jumping GPS and split waves
&lt;/h2&gt;

&lt;p&gt;The fourth session brought a new batch, and by now I knew where to look.&lt;/p&gt;

&lt;p&gt;The Galaxy Watch sometimes only noticed a ride well after it had ended, and its look-back was too short to reach the start. The look-back is longer now, on every platform. On the Amazfit, a single GPS jump while paddling out looked like a fast ride. Peak speed now comes from positions over a couple of seconds instead of one reading. The Garmin made false counts on the paddle-out when it had too few GPS points to go on. A ride without enough GPS points no longer counts as a wave. And one wave got cut into two pieces and counted twice. Two pieces right after each other are now merged into one wave.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two ideas I threw out
&lt;/h2&gt;

&lt;p&gt;Not everything I tried that day stayed in.&lt;/p&gt;

&lt;p&gt;The first idea was GPS as an extra trigger. If the motion sensors miss a ride but the GPS clearly shows one, count it anyway. In practice it counted way more waves than I remembered riding. Out.&lt;/p&gt;

&lt;p&gt;The second was a rule that a wave only counts if you paddle back out afterwards. It sounded logical to me, because after a ride you go back out. In the data it cost real waves, so it went too.&lt;/p&gt;

&lt;p&gt;I'll admit I was pretty sure about both before I tried them. Having the three-watch consensus to check against is what made it easy to let them go.&lt;/p&gt;

&lt;h2&gt;
  
  
  The last days
&lt;/h2&gt;

&lt;p&gt;In the days after that the changes got smaller. A track from the Amazfit led to a guard against single big GPS jumps. Around the same time the Garmin had trouble sending sessions with a lot of waves to the phone, which is now fixed by uploading them in pieces. The Instinct 2S now asks for just one satellite setting instead of switching around.&lt;/p&gt;

&lt;p&gt;One of the three-watch sessions became a test case. Every change I make to the detection from now on gets replayed against it, so I'll notice if I break something I already fixed.&lt;/p&gt;

&lt;p&gt;The latest change so far deals with quiet paddling that still looked like a wave. A wave now needs a moment of real movement energy, a push or a burst of acceleration. A very soft wave can fall through because of that. That's a deliberate choice. I'd rather miss that one than count paddling again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What surfing with three watches taught me
&lt;/h2&gt;

&lt;p&gt;GPS under water is normal. Every time your arm goes under, the fix drops, comes back late or jumps. Any rule that only works with a clean GPS signal will break in the first session, so everything has to survive gaps and jumps.&lt;/p&gt;

&lt;p&gt;My memory is a decent reference for the waves I liked and a bad one for the rest. Three watches agreeing with each other filled in the waves I'd forgotten. I wouldn't trust a single watch for that, and I wouldn't trust myself alone either.&lt;/p&gt;

&lt;p&gt;None of these bugs would have shown up at a desk. A wet screen that taps itself, or a rejected paddle that blocks the next wave. Every single one needed a real session at a real beach to appear. If you want to know what La Pared itself is like on a given day, the &lt;a href="https://breakfinder.surf/en/surf_spots/la-pared-spain" rel="noopener noreferrer"&gt;La Pared spot page&lt;/a&gt; has the forecast.&lt;/p&gt;

&lt;p&gt;And throwing things out is part of the work. The two ideas I dropped felt clever and made the counts worse.&lt;/p&gt;

&lt;p&gt;By the end of the 14 days the watches were counting the way the session felt to me. That was the whole point of the trip, and it worked out really well.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plain disclosure
&lt;/h2&gt;

&lt;p&gt;It's my blog, so this is probably obvious, but I'll say it once: I'm the dev of BreakFinder, and everything above is about my own app. It runs on Garmin, Apple Watch, Wear OS, Amazfit and Huawei watches, with one history across all of them. It's free to download with an optional premium tier. Links are at &lt;a href="https://breakfinder.surf" rel="noopener noreferrer"&gt;breakfinder.surf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If your watch counts your paddling as waves, send me the session. That's exactly the kind of data that made this trip useful.&lt;/p&gt;

</description>
      <category>wearables</category>
      <category>buildinpublic</category>
      <category>sideprojects</category>
      <category>android</category>
    </item>
  </channel>
</rss>
