Skip to main content

camply, the campsite finder ⛺️

Project description

camply

camply, the campsite finder ⛺️, is a tool to help you book a campground online. Finding reservations at sold out campgrounds can be tough. That's where camply comes in. It searches the APIs of booking services like https://recreation.gov (which indexes thousands of campgrounds across the USA) to continuously check for cancellations and availabilities to pop up. Once a campsite becomes available, camply sends you a notification to book your spot!



Version Python Versions Docker Version Testing Status License

Table of Contents

Installation

PyPI

pip install camply

Docker

docker pull juftin/camply

**see Running in Docker below.

Building Locally

git clone https://github.com/juftin/camply.git
cd camply
python setup.py install

Command Line Usage

When installed, camply's command line utility can be invoked with the command, camply. The CLI tool accepts one of four sub-arguments: campsites, recreation-areas, campgrounds, and configure.

❯ camply --help

2021-05-17 19:11:59,858 [  CAMPLY]: camply, the campsite finder ⛺️
usage: camply [-h] [--version]
              {campsites,recreation-areas,campgrounds,configure} ...

Welcome to camply, the campsite finder. Finding reservations at sold out
campgrounds can be tough. That's where camply comes in. It searches the APIs
of booking services like https://recreation.gov (which indexes thousands of
campgrounds across the USA) to continuously check for cancellations and
availabilities to pop up. Once a campsite becomes available, camply sends you
a notification to book your spot!

positional arguments:
  {campsites,recreation-areas,campgrounds,configure}
    campsites           Find available Campsites using search criteria
    recreation-areas    Search for Recreation Areas and list them
    campgrounds         Search for Campgrounds (inside of Recreation Areas)
                        and list them
    configure           Set up camply configuration file with an interactive
                        console

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit

visit the camply documentation at https://github.com/juftin/camply

2021-05-17 19:11:59,863 [  CAMPLY]: Exiting camply 👋

campsites

Search for a campsite within camply. Campsites are returned based on the search criteria provided. Campsites contain properties like booking date, site type (tent, RV, cabin, etc), capacity, price, and a link to make the booking. Required parameters include --start-date, --end-date, --rec-area / --campground. Constant searching functionality can be enabled with --continuous and notifications via Email and Pushover can be enabled using --notifications.

Arguments:

  • --rec-area: RECREATION_AREA_ID
    • Add Recreation Areas (comprised of campgrounds) by ID. **example
  • --campground: CAMPGROUND_ID
    • Add individual Campgrounds by ID. **example
  • --start-date: START_DATE
    • YYYY-MM-DD: Start of Search window. You will be arriving this day. **example
  • --end-date: END_DATE
    • YYYY-MM-DD: End of Search window. You will be leaving the following day. **example
  • --weekends
    • Only search for weekend bookings (Fri/Sat nights). **example
  • --provider: PROVIDER
    • Camping Search Provider. Options available are 'Yellowstone' and 'RecreationDotGov'. Defaults to 'RecreationDotGov', not case-sensitive. **example
  • --continuous
    • Continuously check for a campsite to become available, and quit once at least one campsite is found. **example
  • --polling-interval: POLLING_INTERVAL
    • If --continuous is activated, how often to wait in between checks (in minutes). Defaults to 10, cannot be less than 5. **example
  • --notifications: NOTIFICATIONS
    • If --continuous is activated, types of notifications to receive. Options available are email, pushover, or silent. Defaults to silent - which just logs messages to console. **example
  • --notify-first-try
    • If --continuous is activated, whether to send all non-silent notifications if more than 5 matching campsites are found on the first try. Defaults to false which only sends the first 5. **example
  • --search-forever
    • If --continuous is activated, this method continues to search after the first availability has been found. The one caveat is that it will never notify about the same identical campsite for the same booking date. **example
camply campsites \
    --rec-area 2725 \
    --start-date 2021-07-10 \
    --end-date 2021-07-17

recreation-areas

Search for Recreation Areas and their IDs. Recreation Areas are places like National Parks and National Forests that can contain one or many campgrounds.

Arguments:

  • --search SEARCH
    • Search for Campgrounds or Recreation Areas by search string.
  • --state STATE
    • Filter by US state code.
camply recreation-areas --search "Yosemite National Park"

**see the examples for more information

campgrounds

Search for Campgrounds and their IDs. Campgrounds are facilities inside of Recreation Areas that contain campsites. Most 'campgrounds' are areas made up of multiple campsites, others are facilities like fire towers or cabins that might only contain a single 'campsite' to book.

Arguments:

  • --search SEARCH
    • Search for Campgrounds or Recreation Areas by search string.
  • --state STATE
    • Filter by US state code.
  • --rec-area: RECREATION_AREA_ID
    • Add Recreation Areas (comprised of campgrounds) by ID.
  • --campground: CAMPGROUND_ID
    • Add individual Campgrounds by ID.
camply campgrounds --search "Fire Tower Lookout" --state CA

**see the examples for more information

configure

Set up camply configuration file with an interactive console

In order to send notifications through camply you must set up some authorization values. Whether you need to set up pushover notifications (push notifications on your phone, your pushover account can be set up at https://pushover.net) or Email messages, everything can be done through the configure command. The end result is a file called .camply in your home folder. See the Running in Docker section to see how you can use environment variables instead of a config file.

camply configure

Examples

Read through the examples below to get a better understanding of camply, its features, and the functionality of the different arguments provided to the CLI.

Searching for a Campsite

The below search looks for campsites inside of Recreation Area ID #2725 (Glacier National Park) between 2021-07-10 and 2021-07-17. The search will be performed once and any results will be logged to the console. camply searches for campsites inside of search windows in increments of one night. --start-date and --end-date define the bounds of the search window, you will be leaving the day after --end-date.

camply campsites \
    --rec-area 2725 \
    --start-date 2021-07-10 \
    --end-date 2021-07-17

Searching for a Campsite by Campground ID

The below search looks for across three campgrounds (all inside Glacier National Park) between 2021-07-10 and 2021-07-17. Multiple Campgrounds (and Recreation Areas too) can be found by supplying the arguments more than once.

camply campsites \
    --campground 232493 \
    --campground 251869 \
    --campground 232492 \
    --start-date 2021-07-10 \
    --end-date 2021-07-17

Continuously Searching for A Campsite

Sometimes you want to look for campgrounds until an eventual match is found. The below snippet will search for matching campsites until it finds a match. It also sends a notification via pushover once matches are found. Alternate notification methods are email and silent (default).

Important Note: When camply is told to run --continuous with non-silent notifications set up and it finds more than 5 matching campsites on the first try, it will only send notifications for the first 5 campsites. This is to prevent thousands of campsites flooding your notifications. It's always encouraged to perform an initial online search before setting up a camply search. To bypass this behavior and send all notifications, pass the --notify-first-try argument.

camply campsites \
    --rec-area 2725 \
    --start-date 2021-07-12 \
    --end-date 2021-07-12 \
    --continuous \
    --notifications pushover \
    --notify-first-try

Continue Looking After The First Match Is Found

Sometimes you want to search for all possible matches up until your arrival date. No problem. Add the --search-forever and camply won't stop sending notifications after the first match is found. One important note, camply will save and store all previous notifications when --search-forever is enabled, so it won't notify you about the exact same campsite availability twice. This can be problematic when certain campsites become available more than once.

camply campsites \
    --rec-area 2725 \
    --start-date 2021-07-01 \
    --end-date 2021-07-31 \
    --continuous \
    --notifications pushover \
    --search-forever

Look for Weekend Campsite Availabilities

This below search looks across larger periods of time, but only if a campground is available to book on a Friday or Saturday night (--weekends). It also uses the --polling-interval argument which checks every 5 minutes instead of the default 10 minutes.

camply campsites \
    --rec-area 2991 \
    --start-date 2021-05-01 \
    --end-date 2021-07-31 \
    --weekends \
    --continuous \
    --notifications email \
    --polling-interval 5

Look for a Campsite Inside of Yellowstone

Yellowstone doesn't use https://recreation.gov to manage its campgrounds, instead it uses its own proprietary system. In order to search the Yellowstone API for campsites, make sure to pass the --provider "yellowstone" argument. This flag disables --rec-area and --campground arguments.

camply campsites \
    --provider yellowstone \
    --start-date 2021-07-09 \
    --end-date 2021-07-16 \
    --continuous

Look for a Campsite Across Multiple Recreation areas

You don't have to confine your search to a single Recreation or Campground ID. Adding multiple arguments to the command line will search across multiple IDs. Keep in mind that any --campground arguments will overwrite all --rec-area arguments.

camply campsites \
    --rec-area 2991 \
    --rec-area 1074 \
    --start-date 2021-07-09 \
    --end-date 2021-07-16

Search for Recreation Areas by Query String

Just need to find what your local Recreation Area ID number is? This simple command allows you to search and list recreation areas. It accepts --search and --state arguments.

camply recreation-areas --search "Yosemite National Park"

Look for Specific Campgrounds Within a Recreation Area

Need to get even more specific and search for a particular campground? This search lists campgrounds attached to a recreation area id --rec-area. It also accepts --search and --state arguments.

camply campgrounds --rec-area 2991

Look for Specific Campgrounds by Query String

The below search looks for Fire Lookout Towers to stay in inside of California.

camply campgrounds --search "Fire Tower Lookout" --state CA

Finding Recreation Areas IDs and Campground IDs To Search Without Using the Command Line

You can uncover campground and recreation area IDs just by using the https://recreation.gov search functionality. Use the below example for a campground within Glacier National Park.

First, perform your search on https://recreation.gov.

recreation_dot_gov search

The above search will take you to a URL like this: https://www.recreation.gov/search?q=Glacier%20National%20Park&entity_id=2725&entity_type=recarea. Taking a closer look at the URL components you can see that Glacier National Park has the Recreation Area ID #2725.

Searching deeper into campgrounds inside of Glacier National Park you might find Fish Creek Campground at a URL like https://www.recreation.gov/camping/campgrounds/232493. Here, we can see that this campground has a Campground ID of #232493.

Object-Oriented Usage (Python)

Search for a Recreation.gov Campsite

from datetime import datetime
import logging
from typing import List

from camply.containers import AvailableCampsite, SearchWindow
from camply.search import SearchRecreationDotGov

logging.basicConfig(format="%(asctime)s [%(levelname)8s]: %(message)s",
                    level=logging.INFO)

month_of_june = SearchWindow(start_date=datetime(year=2021, month=6, day=1),
                             end_date=datetime(year=2021, month=6, day=30))
camping_finder = SearchRecreationDotGov(search_window=month_of_june,
                                        recreation_area=2725,  # Glacier Ntl Park
                                        weekends_only=False)
matches: List[AvailableCampsite] = camping_finder.get_matching_campsites(log=True, verbose=True,
                                                                         continuous=False)

The above script returns a list of any matching AvailableCampsite namedtuple objects:

[
    AvailableCampsite(campsite_id="5391",
                      booking_date=datetime.datetime(2021, 6, 13, 0, 0),
                      campsite_site_name="B37",
                      campsite_loop_name="Loop B",
                      campsite_type="STANDARD NONELECTRIC",
                      campsite_occupancy=(0, 8),
                      campsite_use_type="Overnight",
                      availability_status="Available",
                      recreation_area="Glacier National Park, MT",
                      recreation_area_id="2725",
                      facility_name="Fish Creek Campground",
                      facility_id="232493",
                      booking_url="https://www.recreation.gov/camping/campsites/5391")
]

Continuously Search for Recreation.gov Campsites

You'll notice that the get_matching_campsites function takes accepts parameter values very similar to the commandline arguments.

from datetime import datetime
import logging

from camply.containers import SearchWindow
from camply.search import SearchRecreationDotGov

logging.basicConfig(format="%(asctime)s [%(levelname)8s]: %(message)s",
                    level=logging.INFO)

month_of_june = SearchWindow(start_date=datetime(year=2021, month=6, day=1),
                             end_date=datetime(year=2021, month=6, day=30))
camping_finder = SearchRecreationDotGov(search_window=month_of_june,
                                        recreation_area=[2991, 1074],  # Multiple Rec Areas
                                        weekends_only=False)
camping_finder.get_matching_campsites(log=True, verbose=True,
                                      continuous=True,
                                      polling_interval=5,
                                      notification_provider="pushover",
                                      search_forever=True,
                                      notify_first_try=False)

Running in Docker

Here's an example of a detached container searching in the background (notice the --rm flag, the container will disappear after camply exits).

docker run -d --rm \
  --name camply \
  --env PUSHOVER_PUSH_TOKEN=${PUSHOVER_PUSH_TOKEN} \
  --env PUSHOVER_PUSH_USER=${PUSHOVER_PUSH_USER} \
  --env TZ="America/Denver" \
  juftin/camply \
  camply campsites \
      --rec-area 2991 \
      --start-date 2021-08-01 \
      --end-date 2021-08-31 \
      --continuous \
      --notifications pushover

The docker image accepts the following environment variables:

  • Pushover Notifications
    • PUSHOVER_PUSH_TOKEN
    • PUSHOVER_PUSH_USER
  • Email Notifications
    • EMAIL_TO_ADDRESS
    • EMAIL_USERNAME
    • EMAIL_PASSWORD
    • EMAIL_FROM_ADDRESS (defaults to "camply@juftin.com")
    • EMAIL_SUBJECT_LINE (defaults to "camply Notification")
    • EMAIL_SMTP_SERVER (defaults to "smtp.gmail.com")
    • EMAIL_SMTP_PORT (defaults to 465)
  • Optional Environment Variables

Alternatively, if you have already run camply configure locally, you can share your .camply file inside the docker container.

docker run -d --rm \
  --name camply \
  --env TZ="America/Denver" \
  --volume ${HOME}/.camply:/home/camply/.camply \
  juftin/camply \
  camply campsites \
      --provider yellowstone \
      --start-date 2021-07-22 \
      --end-date 2021-07-26 \
      --continuous \
      --notifications email

Dependencies

camply is compatible with any Python version >= 3.6. Currently, there are four required dependencies:

  • requests
    • The requests package is used to fetch data from the APIs of Camping Booking Providers.
  • pandas
    • The pandas package is to group and aggregate across large data sets of campsites, campgrounds, and recreation areas.
  • tenacity
    • The tenacity package is used for retrying data searches on the underlying campsite APIs. This retrying methodology handles exceptions allowing for API downtime and facilitating exponential backoff.
  • python-dotenv
    • The python-dotenv package reads key-value pairs from a .env file and can set them as environment variables - this helps with the .camply configuration file.



juftin logo

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

camply-0.1.0.tar.gz (41.9 kB view hashes)

Uploaded Source

Built Distribution

camply-0.1.0-py3-none-any.whl (47.9 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page