Making Ski Trips Safer With Real-Time Data โ›ท

Making Ski Trips Safer With Real-Time Data โ›ท

ยท

8 min read

Introduction ๐ŸŽฟ

As with the rest of the avid outdoors-lovers of the greater Seattle, Washington area, the winter months are always full of excitement towards the next foot of snow in the mountains. With resorts less than an hour from the city, skiers and snowboarders have been able to go virtually whenever they please, oftentimes only needing to commit a few hours out of the day to make the trek and enjoy themselves. Unfortunately, the decision to go isn't always as simple as it seems. From road collisions to snowy weather and pass closures, the 'no-brainer' can quickly turn into an endless spiral of nervousness and questions as soon as the forecast changes from sunny. As someone who has gone through this myself, this overly-common dilemma initiated an idea to simplify this decision as much as possible, and I wanted to see if I had what it took to solve it. Feel free to visit the site here, or keep reading to see how I made it.

This Is Where Data Comes In ๐Ÿ“„

The problem quickly initiated a search for data on everything safety. Beyond weather, I'd need to know about closures, road conditions, driving restrictions, and even the upcoming forecasts. To begin as a concept, I decided to focus on the most popular resort in my area. I found an API that gave me data on road conditions, weather, and even restrictions- and after mixing that with the Weather.Gov forecast API, I was ready to leverage it for my project.

The Safety Score โœ…

At this point, I had my data issue situated, though now I just had to formulate it. When thinking from the user-experience side, I knew simply displaying the data wouldn't be enough. It wouldn't simplify the decision-making process adequately, and there was a chance of confusing a user even more. My target audience was not only the skiers, but also anyone who cares about those who are going to the mountain (parents, significant others, etc). I thought to myself: "How can I easily portray the travel-risk without overcomplicating the decision?". Then it hit me: Sum it up into a total score so it can be easily read and understood in an instant. Through an analysis of previous conditions, closures, and collisions (provided by WSDOT data and some of my own intuition), I came up with a list of perfect or ideal conditions that would equate to a Safety Score of 100. From here, it was only a matter of working backward. I assigned point deductions to different conditions and arranged them into three different potential ranges to give the score more context. The range is similar to a stoplight, green being good to go, yellow being proceed with caution, and red being a recommendation not to go.

Let's Talk About the Development โŒจ๏ธ

Without even thinking about it, I knew Next.js would be the perfect supplement for this project. Its great use of incremental static generation (ISG) and React implementation made the development easy and the speed and efficiency extremely fast and lightweight.

export async function getStaticProps() {
    let SafetyScore = 100
    const currentConditionsRes = await fetch('https://www.wsdot.com/Traffic/api/MountainPassConditions/MountainPassConditionsREST.svc/GetMountainPassConditionAsJon?AccessCode={Code}&PassConditionID=11')
    const currentConditions = await currentConditionsRes.json()
    const weeklyForecastRes = await fetch('https://api.weather.gov/gridpoints/PDT/61,195/forecast', {
        headers: {
            "user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"
        }
    })
    const weeklyForecast = await weeklyForecastRes.json();
    const lastUpdated = moment().format();
    return {
        props: {
            currentConditions,lastUpdated, weeklyForecast:weeklyForecast.properties.periods, SafetyScore, notes
        },
        revalidate:30
    }
}

Using getStaticProps, I can set up the ISG, and when hosted with Vercel , a perfect combination is made. The above requests showcase how each element of the API is fetched. Once the requests are awaited- they are turned into a JSON object, ready for scoring. The approach I decided to take for scoring is relatively simple. After observing many of the potential conditions for weather, road, and restrictions, I created a setup of multiple if statements to reduce the score based on the weights I previously decided from my perfect conditions. I also set up a Cron Job to run every two minutes, just in case, to keep the data fresh assuming there isn't always a constant source of traffic to initiate the revalidation.

if(weeklyForecast.properties.periods[0].shortForecast.toLowerCase().includes("snow")) {
        SafetyScore-=15;
        if(weeklyForecast.properties.periods[0].shortForecast.toLowerCase().includes("light")) {
            SafetyScore+=10;
        }
        notes.push({
            positive:false,
            note:`Snow is forecasted for later ${weeklyForecast.properties.periods[0].name.toLowerCase()}`
        })
    } else {
        notes.push({
            positive:true,
            note:"The weather forecast doesn't call for snow in the near future"
        })
    }

Below is an example of the forecast if statement. Notice how each element also calls notes.push- through adding notes, more context is given on the UX about why exactly the score is decreased.

Now, the UI โœจ

For this project, I decided to keep the UI simple and straightforward. I took advantage of TailwindCSS for this project and created components for my most used elements. For example, there is a component for <ForecastCard/>, <FeatureCard/>, <Note/>, <Score/>, and more! If you are unaware, Tailwind is a utility-first CSS framework packed with classes like flex, pt-4, text-center, and rotate-90 that can be composed to build any design directly in your markup (Tailwind Website). As someone who hates managing CSS files, it has been a lifesaver. image.png

Conclusion ๐Ÿ‚

Overall, I'm super stoked with how the website came out, and I'm glad to have the opportunity to freshen up my Next.JS skills and learn some data science and React tricks along the way. If there's any interest in adding more ski areas, please let me know in the comments and I'm excited to hear any feedback or tips.

Visit The Site Check Out The Code

This site is for educational purposes only, please do your own due-diligence before heading to the mountain