A spicy little heatmap tile server.

Overview

hotpot

Render customizable activity heatmap images from GPS tracks extracted from GPX, TCX, and FIT files. There's also a built-in web server to serve up XYZ tiles, and endpoints to add new data via HTTP POST or Strava webhooks.

Designed to be self-hosted. It's lightweight and snappy enough to fit onto the free tier of pretty much anything that can run a Docker container. Even with 100,000 km of activity data, Fly.io's smallest instance can render tiles in ~1 ms.

Quick Start

To get started, use the import command to quickly process an entire directory of activities in parallel.

hotpot import [path/to/files/]

If importing activities from a Strava data export, use --join [path/to/activities.csv] to include metadata about your activities usually not stored in the GPX (title, which bike you used, the weather, ...)

hotpot import \
    strava_export/activities/ \
    --join strava_export/activities.csv

After the initial import, you'll have a sqlite3 database, and can start creating heatmaps.

Now run the tile server:

hotpot serve

Open http://127.0.0.1:8080/ in your browser to see a map view with the tile layer loaded.

See hotpot --help for more.

Customization

Gradients

There are several built in palettes available for converting the raw frequency data into colored pixels, which can be set via the ?color={...} query parameter. A list of these is available in the map view.

In addition to the presets, custom gradients can also be used via the ?gradient={...} parameter.

For example, to smoothly transition from red (least activity) to white (most), we could use 0:f00;1:fff. Pixels with no activity will be left transparent. Color codes are interpreted as hex RGB values in the following formats: RGB, RRGGBB, RRGGBBAA.

If alpha values are not given, they are assumed to be 0xff (fully opaque).

Example Gradients
Gradient Rendered
0:000;0.25:fff
0:f00;0.1:ff0;0.2:ffff22;0.3:ffffff
0:322bb3;0.10:9894e5;0.15:fff

Filters

We can also choose which activities we're interested in visualizing dynamically through the ?filter={...} parameter.

Any properties available when the activity was added (either via webhook or bulk import) can be used in the filter expression, but the exact names will vary based on your data.

For example, we may want to generate different tiles for cycling vs hiking, exclude commutes, which gear we used, a minimum elevation gain, etc.

# Basic numeric comparisons: <, <=, >, >=
{"key": "elev_gain", ">": 1000}

# Match/exclude multiple values
{"key": "activity_gear", "any_of": ["gravel", "mtb"]}
{"key": "activity_gear", "none_of": ["gravel", "mtb"]}

# Substring matches (e.g. match "Gravel Ride" + "Ride")
{"key": "activity_type", "matches": "Ride"}

# Property key exists
{"key", "max_hr", "has_key": true}

Activity Uploads

Hotpot supports two mechanisms for adding new data to the sqlite3 database directly over HTTP:

  1. POST /upload: Manually upload a single GPX, TCX, or FIT file
  2. Strava webhook: Subscribe to new activity uploads automatically

/upload

todo document

Strava Webhook

If you're already uploading activity data to Strava, you can use their activity webhook to import new activities automatically.

To get started, follow the Strava API documentation to create your own application.

NOTE

Strava limits new APIs to only allow the owner of the API to authenticate. You won't be able to share this with multiple people.

Next, we can use oauth to authenticate our account and save the API tokens in the database.

export STRAVA_CLIENT_ID=... \
       STRAVA_CLIENT_SECRET=...\
       STRAVA_WEBHOOK_SECRET=...

hotpot strava-auth

# Grant permission to your app via OAuth
open http://127.0.0.1:8080/strava/auth

Once you've authenticated successfully, you'll need to register the callback URL of your server with Strava's API. Follow the curl commands shown on the success page to complete setup.

Deployment

To simplify things, a basic Dockerfile is included. Mount a volume at /data/ to persist the sqlite database between runs.

Since we're using sqlite as our data store, it's easy to first run the bulk import locally, then copy the database over to a remote host.

Fly Quick Start

Hotpot should comfortably fit within Fly.io's free tier, and handles the scale-to-zero behavior gracefully. Follow their setup instructions first.

Steps below assume you've cloned this repo locally and already created a local database.

# Create the application
fly launch --ha false

# Create a persistent volume for the DB
fly volumes create hotpot_db -a YOUR_APP_NAME --size 1

# Attach the volume
echo '
[mounts]
  source="hotpot_db"
  destination="/data"
' >> fly.toml

# If you're using the Strava webhook
fly secrets set \
    STRAVA_CLIENT_ID=... \
    STRAVA_CLIENT_SECRET=...\
    STRAVA_WEBHOOK_SECRET=...

# Deploy the app
fly deploy

# Copy local DB over to the app
fly proxy 10022:22 &
scp -P 10022 ./hotpot.sqlite3* root@localhost:/data/

# Restart the app, and we're done.
fly app restart

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

You might also like...
A standalone libp2p rendezvous server binary.

Standalone Rendezvous Server A standalone libp2p rendezvous server binary. Usage Run the rendezvous_server: rendezvous_server --secret-file PATH-TO-S

Lightning Optimizing Opening Server

Lightning Optimizing Opening Server (loptoš ~ naughty boy/brat/hooligan/..., not to be confused with lopta == ball) WARNING: ULTRA-EXPERIMENTAL SOFTWA

pam-send-slack-message is a program that publishes messages on slack when a linux server is accessed through ssh.

pam-send-slack-message pam-send-slack-message is a program that publishes messages on slack when the linux server is accessed through ssh. Installatio

A simple tcp server that written in rustlang
A simple tcp server that written in rustlang

rust_tcp A simple tcp server that written in rustlang How to build In the root dir cargo run Then you can do a test by using telnet as a client telne

PubSubRT - an industrial pub/sub server
PubSubRT - an industrial pub/sub server

PubSubRT - an industrial real-time pub/sub server What is PSRT PSRT is a pub/sub real-time telemetry protocol, optimized for industrial needs: providi

Simple project to test grpc between ruby (client) and rust (server)

grpc-example Simple project to test grpc between ruby (client) and rust (server). Usage To simplify a lot this project uses docker and docker compose

Proxy sentry request to a sentry server using a tunnel/proxy endpoint

Sentry Tunnel This is a proxy that forwards tunneled sentry requests to the real sentry server. The implementation is based on the explanation provide

A high performence Socks5 proxy server with bind/reverse support implementation by Rust.

rsocx A high performence Socks5 proxy server with bind/reverse support implementation by Rust Features Async-std No unsafe code Single executable Linu

A tcp proxy server/client which exchange the data in temp files

ftcp A tcp proxy server/client which exchange the data in temp files 通过在临时文件中交换数据来进行TCP代理的一个服务端/客户端 学校内网中有针对教学楼的防火墙导致教室电脑难以上网( 但学校内建有公共ftp服务器,因此就有了这个借

Comments
  • hotpot command not found

    hotpot command not found

    I'm trying to follow the Quick Start docs to test the app locally. After cloning the repository I'm unable to run hotpot import as the command is not recognized.

    $ hotpot --help

    zsh: command not found: hotpot

    Is there a step between cloning the repository and running the quick start that I am missing?

    opened by TylerHext 3
Owner
Erik Price
Erik Price
Jex Compiler Server - Server that runs Jex code

Server that compiles and runs Jex code.

furetur 3 Nov 18, 2021
Dav-server-rs - Rust WebDAV server library. A fork of the webdav-handler crate.

dav-server-rs A fork of the webdav-handler-rs project. Generic async HTTP/Webdav handler Webdav (RFC4918) is defined as HTTP (GET/HEAD/PUT/DELETE) plu

messense 30 Dec 29, 2022
A simple web server(and library) to display server stats over HTTP and Websockets/SSE or stream it to other systems.

x-server-stats A simple web server(and library) to display server stats over HTTP and Websockets/SSE or stream it to other systems. x-server(in x-serv

Pratyaksh 11 Oct 17, 2022
DNS Server written in Rust for fun, see https://dev.to/xfbs/writing-a-dns-server-in-rust-1gpn

DNS Fun Ever wondered how you can write a DNS server in Rust? No? Well, too bad, I'm telling you anyways. But don't worry, this is going to be a fun o

Patrick Elsen 26 Jan 13, 2023
QUIC proxy that allows to use QUIC to connect to an SSH server without needing to patch the client or the server.

quicssh-rs ?? quicssh-rs is a QUIC proxy that allows to use QUIC to connect to an SSH server without needing to patch the client or the server. quicss

Jun Ouyang 18 May 5, 2023
A telnet chat server written in Rust, running on Lunatic.

Lunatic.chat A telnet chat server written in Rust, running on Lunatic. If you just would like to try it out, join the hosted version with: # US server

Lunatic 101 Jan 2, 2023
server security proxy write by Rust

server-security-proxy server security proxy write by Rust how to use config toml file

baoyachi. Aka Rust Hairy crabs 3 May 24, 2021
Imagine your SSH server only listens on an IPv6 address, and where the last 6 digits are changing every 30 seconds as a TOTP code...

tosh Imagine your SSH server only listens on an IPv6 address, and where the last 6 digits are changing every 30 seconds as a TOTP code... Inspired fro

Mark Vainomaa 409 Oct 23, 2022
A working demo of RustDesk server implementation

A working demo of RustDesk server implementation This is a super simple working demo implementation with only one relay connection allowed, without NA

RustDesk 461 Jan 1, 2023
A Matrix Server Stats bot

A bot running trough the matrix network to find all rooms.

Marcel 14 Dec 8, 2021