<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ weather - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ weather - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 23 Jun 2026 22:45:33 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/weather/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Yahoo Weather API Alternatives ]]>
                </title>
                <description>
                    <![CDATA[ For beginner developers, the Yahoo Weather API might be enough to build simple weather applications.  Yahoo, however, has a lot of limitations as it only provides location-specific current data and ten-day historical data.  If your application requir... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/yahoo-weather-api-alternatives/</link>
                <guid isPermaLink="false">66bb525a74045df86842bf5f</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ weather ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ry Vee ]]>
                </dc:creator>
                <pubDate>Mon, 04 Jan 2021 22:02:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/lloyd-dirks-kz8pEH4IsUo-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For beginner developers, the <a target="_blank" href="https://developer.yahoo.com/weather/">Yahoo Weather API</a> might be enough to build simple weather applications. </p>
<p>Yahoo, however, has a lot of limitations as it only provides location-specific current data and ten-day historical data. </p>
<p>If your application requires more features and information, using this free API may not be the best option.</p>
<p>What follows is a list of the best alternatives to the Yahoo weather API along with their key benefits and features, most common use cases, and pricing.</p>
<h2 id="heading-climacell-microweather-apihttpswwwclimacellcoweather-api"><a target="_blank" href="https://www.climacell.co/weather-api/">ClimaCell Microweather API</a></h2>
<p><img src="https://lh3.googleusercontent.com/A5lc9386L7Qoo24R1O6hVzwgdduieT1QksavGabQM4LioAIj2fcBnHq3Ggj2ahcZukYUmUa1UaKDmBvFn7KKqQgrmxFvHbFCwBV6YGg_nDBeTmRR6rHPYsSR9ysCQM6Amw" alt="Image" width="991" height="449" loading="lazy"></p>
<p>ClimaCell’s Microweather API provides a wide range of information offered both as numerical data and map layers. It can provide up to four weeks of historical data from partner stations and up to six hours of historical data from its own observations.</p>
<h3 id="heading-key-featuresbenefits-of-the-climacell-microweather-api">Key features/benefits of the ClimaCell Microweather API:</h3>
<ul>
<li>Artificial intelligence-driven data model that processes data from a wide range of sources such as drones and IoT devices</li>
<li>Map layers for more than 20 parameters</li>
<li>Hyper-local and global historical and real-time data</li>
<li>Out of the box templates for easier crafting of request calls</li>
</ul>
<p><strong>Best used for:</strong></p>
<ul>
<li>Most corporate applications. The API is used by companies such as Ford and Uber.</li>
</ul>
<p><strong>Pricing</strong>: Free plan allows for up to 1,000 calls per day. Paid plans start at $87 per month.</p>
<h2 id="heading-openweathermap-apihttpsopenweathermaporgapi"><a target="_blank" href="https://openweathermap.org/api">OpenWeatherMap API</a></h2>
<p><img src="https://lh4.googleusercontent.com/X3V2dcRC9eTfn8v0WeIvghTNu96xKaffyxSQ4Z8U2Gp2I72RPQZ8TLOI-BKBCVUK4KTAslPvyuIOZSGOHCWQ_0mpKSEBNA0z0W_sxEIpmsA8kSFN_w8EHK2chgJLRALhZQ" alt="Image" width="800" height="488" loading="lazy"></p>
<p>OpenWeatherMap is an API inspired by Wikipedia’s crowdsourcing model. It is probably the most popular weather API because of its simplicity.</p>
<h3 id="heading-key-featuresbenefits-of-the-openweathermap-api">Key features/benefits of the OpenWeatherMap API:</h3>
<ul>
<li>Very simple to use</li>
<li>40-year historical weather data for any location</li>
<li>Useful data visualization such as a “this-day-in-history” chart</li>
<li>16-day forecast for several locations</li>
<li>Three-hour and five-day forecasts</li>
<li>Very accurate data as it collects from over 40,000 stations globally</li>
<li>Creative Commons Share-Alike licenses on weather maps which allow developers to easily build map-based applications</li>
</ul>
<p><strong>Best used for</strong>:</p>
<ul>
<li>Personal weather stations and simple projects for developers</li>
<li>Applications geared toward the agricultural sector</li>
</ul>
<p><strong>Pricing</strong>: Its free tier allows for up to 100 calls per day. Paid plans start at $40 per month.</p>
<h2 id="heading-accuweather-apihttpsdeveloperaccuweathercom"><a target="_blank" href="https://developer.accuweather.com/">Accuweather API</a></h2>
<p><img src="https://lh3.googleusercontent.com/wOnvI2RujT_Gul96Ib_zG8nUtCnsrUbTubOMXUabZWjlJDJOEprRGRB_kBaDGn6A1YyIj9DuOkAbp7b2gOCFP3cwZT4hYFxi_so19PhdyFlrzxTVhUjQUBExuaK0Yfy1hg" alt="Image" width="1600" height="900" loading="lazy"></p>
<p>Accuweather is another very popular weather API. It processes over 30 billion requests daily and provides imagery endpoints.</p>
<h3 id="heading-key-featuresbenefits-of-the-accuweather-api">Key features/benefits of the Accuweather API:</h3>
<ul>
<li>Developers can quickly get started with its <a target="_blank" href="https://apigee.com/api-management/">Apigee</a> portal (Accuweather’s project with Google).</li>
<li>Its “Indices API” provides other useful information such as flight delays, mosquito activity, data for stargazers, and a host of daily indices for specific locations.</li>
<li>It provides engaging video presentations along with the minute by minute forecasts.</li>
<li>As its name suggests, it provides super accurate weather data for almost any point on earth.</li>
<li>Weather information can be customized.</li>
</ul>
<p><strong>Best used for</strong>:</p>
<ul>
<li>It’s the best option if the application needs to have video presentations.</li>
<li>Applications geared toward managing disaster risks.</li>
</ul>
<p><strong>Pricing:</strong> It has a limited trial that allows for 50 calls daily. Paid plans start at $25 per month.</p>
<h2 id="heading-stormglass-apihttpsstormglassio"><a target="_blank" href="https://stormglass.io/">Stormglass API</a></h2>
<p><img src="https://lh6.googleusercontent.com/nfcnumdm7ugonJcRH2Z0S0ONzK1KIFzJIKl1XN2GYKOq-5Zw_TwaAoiC6LqHL06uI72_bG9cAvmdOed70kNHjYRWHO4KPgJRGv4yUOc1sTDVbyo1CDqczUKoz9VCROYpfw" alt="Image" width="1024" height="452" loading="lazy"></p>
<p>The Stormglass weather API provides high-resolution forecasts globally from renowned meteorological institutions. It allows developers to fetch data from any coordinate through simple HTTP requests.</p>
<h3 id="heading-key-featuresbenefits-of-the-stormglass-api">Key features/benefits of the Stormglass API:</h3>
<ul>
<li>It provides up to 10-day forecasts with high-resolution.</li>
<li>Provides marine information such as tides, water chemical analysis.</li>
<li>Provides data for renewable energy (wind and solar indices) as well as agricultural information (soil moisture, surface temperature).</li>
</ul>
<p><strong>Best Used For</strong>:</p>
<ul>
<li>Marine-related applications.</li>
<li>Renewable energy monitoring.</li>
<li>Agricultural organizations.</li>
</ul>
<p><strong>Pricing</strong>: It has a free tier that allows up to 50 daily API calls. Paid plans start at 16 euros a month.</p>
<h2 id="heading-weather-company-api-ibmhttpswwwibmcomproductsweather-company-data-packages"><a target="_blank" href="https://www.ibm.com/products/weather-company-data-packages">Weather Company API (IBM)</a></h2>
<p><img src="https://lh6.googleusercontent.com/CgRmpyRclHzJP49XhkwKR1zObkg5X_L8RtWpvlwoFNFqwXqrVOYUtICYMYX7W5g6lOM9DbgCKIrska-Y9E8YYghqqBVfVEutGQm_1x1kfu4Y8slwgF1ZWVlpyBWPNesgbg" alt="Image" width="700" height="394" loading="lazy"></p>
<p>The Weather Company API is owned by IBM and is part of a much more comprehensive data package. Its main value proposition is the provision of highly actionable insights that allows business to optimize their operations and reduce costs while increasing the bottomline.</p>
<h3 id="heading-key-featuresbenefits-of-the-weather-company-api">Key features/benefits of the Weather Company API:</h3>
<ul>
<li>It provides very accurate forecasts of about 500-meter resolution.</li>
<li>It has an extensive number of information sources including high-resolution observations from 250,000 weather stations.</li>
<li>It provides historical data encompassing a 35 kilometer worldwide grid allowing businesses to understand patterns to make better decisions relating to weather.</li>
<li>It provides real-time severe weather forecasting.</li>
<li>It also provides non-weather information such as air-quality, pollen and flu indices.</li>
</ul>
<p><strong>Best Used For</strong>:</p>
<ul>
<li>Business relying heavily on quick forecasts as well as long historical weather data.</li>
</ul>
<p><strong>Pricing</strong>: Free trial that allows for up to 10 calls per minute. The trial then expires once the limit of 10,000 free calls is consumed. Paid plans start at $24.95 per month.</p>
<h2 id="heading-weather-2020-apihttpswwwweather2020comapi"><a target="_blank" href="https://www.weather2020.com/api/">Weather 2020 API</a></h2>
<p><img src="https://lh4.googleusercontent.com/xvEDCc8qVjv1kqEuZemB6ZmELiI_HL0ruNvoeiwI3171A2DQUgfy6pJPZ2Ju53_XWJgfpTmdRrl6xsImE9sEP74KcHy4vrz0qVWoYD1z3MyQXhQAljZs7vQoWm6eg7QsNA" alt="Image" width="360" height="480" loading="lazy"></p>
<p>Weather 2020 prides itself on being a predictive weather modeling platform. Its main proposition is that it can provide for up to nine months forecast just based on the preceding three-month observation. Its statistical model is based on the work of famed meteorologist Gary Lezak.</p>
<h3 id="heading-key-featuresbenefits-of-the-weather-2020-api">Key features/benefits of the Weather 2020 API:</h3>
<ul>
<li>It provides long-term forecasts allowing businesses and organizations to have longer planning horizons.</li>
<li>It offers over 10-million forecasts per day and is best used for mobile applications.</li>
<li>It has a very interactive dashboard that displays key information, analytics and graphs.</li>
</ul>
<p><strong>Best Used For</strong>:</p>
<ul>
<li>Mobile weather applications.</li>
<li>Creating video forecasts (available for paid plans).</li>
</ul>
<p><strong>Pricing</strong>: The free plan allows for up to 1,000 API calls per day. Paid plans start at $ 9.99 per month.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As we’ve seen from the list above, each option has certain use-cases for which it is best suited. This is, by no means, an indication that these are the only uses these APIs have. </p>
<p>What you select will depend on several factors including cost, amount and accuracy of data required, as well your own preferences.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I Built My Own Forecasting Tool Using a Weather API ]]>
                </title>
                <description>
                    <![CDATA[ By Anton Lawrence Abrupt weather and climate change are things that everybody is dealing with. In fact, the vast majority of the global population relies on accurate, real-time weather data and forecasts to make informed decisions.    This has increa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-built-my-own-forecasting-tool-using-a-weather-api/</link>
                <guid isPermaLink="false">66d45d978812486a37369c5d</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ forecasting ]]>
                    </category>
                
                    <category>
                        <![CDATA[ weather ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 11 May 2020 17:50:21 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9b25740569d1a4ca29f2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Anton Lawrence</p>
<p>Abrupt weather and climate change are things that everybody is dealing with. In fact, the vast majority of the global population relies on accurate, real-time <a target="_blank" href="https://www.climate.gov/maps-data/primer/processing-climate-data">weather data and forecasts to make informed decisions</a>.   </p>
<p>This has increased the importance of reliable Android and iOS weather apps. In this article, we will show you how to create a simple forecasting tool using NodeJS and a weather API.  </p>
<p>But before that, let’s go over the importance of weather apps.</p>
<h1 id="heading-why-do-we-need-weather-apps">Why Do We Need Weather Apps?</h1>
<p>A feature-rich <a target="_blank" href="https://en.wikipedia.org/wiki/Weather_forecasting">weather forecasting</a> app can provide great value to various industries. Some noteworthy benefits of weather applications include:</p>
<ul>
<li>Providing immediate access to local weather conditions and upcoming forecast, thus saving you time.</li>
<li>Providing real-time notifications about prevailing and expected weather conditions.</li>
<li>Helping governments and local administrations prepare for natural disasters and save lives.</li>
<li>Helping farmers take preventive measures.</li>
<li>Facilitating the global travel and tourism industry.</li>
<li>Providing clear weather forecasts which are crucial in the aviation and logistics industry.</li>
</ul>
<h1 id="heading-what-you-need-to-build-a-weather-app">What You Need to Build a Weather App</h1>
<p>Here are some of the things you will need to build a weather app successfully:  </p>
<ul>
<li>Familiarity working with JavaScript (Node.js)</li>
<li>A text editor such as Notepad or an IDE. My favorite is Visual Studio.</li>
<li>Access to a reliable weather API such as ClimaCell</li>
<li>Access to a map service</li>
<li>Knowledge of HTML, CSS, and Bootstrap</li>
</ul>
<p>Once you have these ready, you’re good to go.</p>
<h1 id="heading-overview-of-the-climacell-weather-api">Overview of the ClimaCell Weather API</h1>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589167731846_climacell+api+weather.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>ClimaCell is a popular weather provider that offers hyper-accurate <a target="_blank" href="https://www.climate.gov/maps-data/dataset/past-weather-zip-code-data-table">historical weather data</a> as well as forecasts through an easy to consume API.</p>
<h1 id="heading-the-building-process">The Building Process</h1>
<p>In this section, I will show you how I created a forecasting app where a user enters their city or any other location by name and fetches weather data from the ClimaCell API. The API responds to the request by returning data, which is then displayed to the user.</p>
<h2 id="heading-install-nodejs-and-create-a-new-project">Install NodeJS and Create a New Project</h2>
<p>For this project, we will use Node.js — one of the most popular run-time environments for JavaScript. Node.js helps developers create quick web applications. It has a wide range of libraries and modules for creating advanced web applications.  </p>
<p>If you do not have Node.js on your device, you can install it from the <a target="_blank" href="https://nodejs.org/en/">official website</a>.<br>Once installed, we use this command to initialize npm - the default packet manager used by Node.js.  </p>
<p><code>$ npm init</code> </p>
<p>This creates our project, so you will be prompted to enter a few details such as package name, description, Git repository, and more.  </p>
<p>Next, we install the modules required to run our project. To generate a Node.js app skeleton, we use express - a framework for building Node.js web applications.  </p>
<p><code>$ npm install express</code>  </p>
<p>Installing the express framework helps you run the server, handle client requests, and connect the right HTML template with a response.    </p>
<p>Next, we will also install unirest - a simple yet powerful solution that allows you to request a library.   </p>
<p>It will help us make requests to the ClimaCell API and handle the responses.   </p>
<p>Use this command:  </p>
<p><code>npm install unirest</code>  </p>
<p>At this point, we’ve installed the necessary modules, and the project is ready.<br>Next, we generate a weather app using the express generator tool. On the command line, type this:  </p>
<p><code>express --view=pug weather-app-nodejs</code>  </p>
<p>You should now have a view like this on the command line:</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589167675672_create+weather+app.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-get-the-climacell-weather-api">Get the ClimaCell Weather API</h2>
<p>To get access to the ClimaCell API, you will need to sign up for an account on their page. </p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589187768233_CLIMACELL+DASHBOARD.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once you create an account, sign in to their Microweather API dashboard which looks like this:  </p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589188690033_dashboard.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>On the dashboard, click on references to check the API endpoints. As you can see, the ClimaCell API has a number of endpoints including the short term forecast, hourly forecast, real time data, and more.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589191651855_API+endpoints.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Worth a mention is that each endpoint has its own code snippet. For example, here is the Node.js code snippet for getting real time weather data.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589192780403_carbon.png" alt="Image" width="600" height="400" loading="lazy">
<em>[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=javascript&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=router.post(%27%252Fweather%27%252C%2520function(req%252C%2520res%252C%2520next)%257B%250A%250A%2520%2520let%2520city%2520%253D%2520req.body.city%253B%250A%250A%2520%2520url%2520%253D%2520url%252Bcity%252B%2522%2526%2522%252BappId%253B%250A%250A%2520request(url%252C%2520function%2520(error%252C%2520response%252C%2520body)%2520%257B%250A%250A%2520%2520%2520%2520%2520%2520body%2520%253D%2520JSON.parse(body)%253B%250A%250A%2520%2520%2520%2520%2520%2520if(error%2520%2526%2526%2520response.statusCode%2520!%253D%2520200)%257B%250A%250A%2520%2520%2520%2520%2520%2520%2520%2520throw%2520error%253B%250A%250A%2520%2520%2520%2520%2520%2520%257D%250A%250A%2520%2520%2520%2520let%2520country%2520%253D%2520(body.sys.country)%2520%253F%2520body.sys.country%2520%253A%2520%27%27%2520%253B%250A%250A%2520%2520%2520%2520let%2520var%2520request%2520%253D%2520require(%2522request%2522)%253B%250A%250Avar%2520options%2520%253D%2520%257B%250A%2520%2520method%253A%2520%27GET%27%252C%250A%2520%2520url%253A%2520%27https%253A%252F%252Fapi.climacell.co%252Fv3%252Fweather%252Frealtime%27%252C%250A%2520%2520qs%253A%2520%257Bapikey%253A%2520%279efRx8KrGKa6ME0ORWIJz7TaNjuRQAvb%27%257D%250A%257D%253B%250A%250Arequest(options%252C%2520function%2520(error%252C%2520response%252C%2520body)%2520%257B%250A%2520%2520if%2520(error)%2520throw%2520new%2520Error(error)%253B%250A%250A%2520%2520console.log(body)%253B%250A%257D)%253B%2520%253D%2520%2522For%2520city%2520%2522%252Bcity%252B%27%252C%2520country%2520%27%252Bcountry%253B%250A%250A%2520%2520%2520%2520res.render(%27index%27%252C%2520%257Bbody%2520%253A%2520body%252C%2520forecast%253A%2520forecast%257D)%253B%250A%250A%2520%2520%2520%257D)%253B%250A%250A%257D)%253B" rel="noreferrer nofollow noopener)</em></p>
<h2 id="heading-modifying-the-application">Modifying the application</h2>
<p>To call the ClimaCell API, we need to first edit some files. Here, you can use Notepad or open the project directory in your IDE for easier editing. It should appear as shown:</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589180215929_repo.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We start modifying our files by adding bootstrap to layout.pug. Open the views directory and insert this snippet to the file.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589170180082_carbon+1.png" alt="Image" width="600" height="400" loading="lazy">
<em>[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=javascript&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=doctype%2520html%250Ahtml(lang%253D%2522en%2522)%250A%2520%2520head%250A%2520%2520%2520%2520title%2520Weather%2520Forecast%2520Tool%2520using%2520Climacell%2520API%250A%2520%2520%2520%2520meta(charset%253D%2522utf-8%2522)%250A%2520%2520%2520%2520meta(name%253D%2522viewport%2522%2520content%253D%2522width%253Ddevice-width%252C%2520initial-scale%253D1%2522)%250A%2520%2520%2520%2520link(rel%253D%2522stylesheet%2522%2520href%253D%2522https%253A%252F%252Fmaxcdn.bootstrapcdn.com%252Fbootstrap%252F3.3.7%252Fcss%252Fbootstrap.min.css%2522)%250A%2520%2520%2520%2520script(src%253D%2522https%253A%252F%252Fajax.googleapis.com%252Fajax%252Flibs%252Fjquery%252F3.3.1%252Fjquery.min.js%2522)%250A%2520%2520%2520%2520script(src%253D%2522https%253A%252F%252Fmaxcdn.bootstrapcdn.com%252Fbootstrap%252F3.3.7%252Fjs%252Fbootstrap.min.js%2522)%250A%2520%2520body%250A%2520%2520%2520%2520block%2520content" rel="noreferrer nofollow noopener)</em></p>
<p>Next, we create a form by adding the snippet below to index.pug file.  </p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589170264156_carbon.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Notice how we use the <a target="_blank" href="https://en.wikipedia.org/wiki/POST_(HTTP)">HTTP post method</a> to send data to the server. The code above also sets the action parameter to weather route and adds the text input as “city.”<br>An input button to fetch the weather is also added.   </p>
<p>We now create an HTML table just below the form to display fetched weather records.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589171285500_carbon+2.png" alt="Image" width="600" height="400" loading="lazy">
<em>[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=htmlmixed&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=.row%250A%2520%2520%2520%2520%2520%2520%2520.col-md-12%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520p%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520br%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520br%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520strong%2520Weather%2520Forecast%2520%2523%257Bforecast%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520table.table%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520thead%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520tr%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520th%2520Longitude%2520%252F%2520Latitude%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520th%2520Pressure%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520th%2520Temprature%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520th%2520Humidty%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520tbody%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520if%2520body%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520tr%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520td%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2523%257Bbody.coord.lon%257D%2520%252F%2520%2523%257Bbody.coord.lon%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520td%2520%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2523%257Bbody.main.pressure%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520td%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2523%257Bbody.main.temp%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520td%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2523%257Bbody.main.humidity%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520else%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520tr%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520td(colspan%253D%25226%2522)%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257C%2520Enter%2520city%2520name%2520and%2520click%2520Fetch%2520Weather%2520button" rel="noreferrer nofollow noopener)</em></p>
<p>Inserting the code snippet above creates a table that looks like this:</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589196907929_Weather+1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-calling-the-climacell-api">Calling the ClimaCell API</h2>
<p>To send requests to the ClimaCell API, we must install the <a target="_blank" href="https://nodejs.dev/making-http-requests-with-nodejs">request module</a>.  </p>
<p><code>npm i request --save</code>  </p>
<p>Next, we add the ClimaCell API credentials in the index.js file. Open the file in your routes directory and add the API key you obtained on the ClimaCell dashboard:  </p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589171891228_example+key.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here is the code to add API credentials:  </p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589172288863_carbon+4.png" alt="Image" width="600" height="400" loading="lazy">
<em>[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=javascript&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=let%2520url%2520%2520%2520%2520%253D%2520%27https%253A%252F%252Fclimacell-microweather-v1.p.rapidapi.com%252Fweather%252Frealtime%27%250Alet%2520appId%2520%2520%253D%2520%27appid%253DYOUR%2520API%2520KEY%27%253B%250Alet%2520units%2520%2520%253D%2520%27%2526units%253Dmetric%27%253B%2520%250Avar%2520request%2520%253D%2520require(%27request%27)%253B" rel="noreferrer nofollow noopener)</em></p>
<p>After adding the API credentials, we update the index route. This is done by replacing the code section in <strong>‘/’</strong> route in index.js file.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589172437273_carbon+5.png" alt="Image" width="600" height="400" loading="lazy">
<em>[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=javascript&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=%252F<em>%2520GET%2520home%2520page.%2520</em>%252F%250Arouter.get(%27%252F%27%252C%2520function(req%252C%2520res%252C%2520next)%2520%257B%250A%2520res.render(%27index%27%252C%2520%257B%27body%27%253A%27%27%252C%2520forecast%253A%2520%27%27%257D)%253B%250A%257D)%253B" rel="noreferrer nofollow noopener)</em></p>
<p>We finish by creating the weather route in index.js.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589172832852_carbon+6.png" alt="Image" width="600" height="400" loading="lazy">
<em>[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=javascript&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=router.post(%27%252Fweather%27%252C%2520function(req%252C%2520res%252C%2520next)%257B%250A%250A%2520%2520let%2520city%2520%253D%2520req.body.city%253B%250A%250A%2520%2520url%2520%253D%2520url%252Bcity%252B%2522%2526%2522%252BappId%253B%250A%250A%2520request(url%252C%2520function%2520(error%252C%2520response%252C%2520body)%2520%257B%250A%250A%2520%2520%2520%2520%2520%2520body%2520%253D%2520JSON.parse(body)%253B%250A%250A%2520%2520%2520%2520%2520%2520if(error%2520%2526%2526%2520response.statusCode%2520!%253D%2520200)%257B%250A%250A%2520%2520%2520%2520%2520%2520%2520%2520throw%2520error%253B%250A%250A%2520%2520%2520%2520%2520%2520%257D%250A%250A%2520%2520%2520%2520let%2520country%2520%253D%2520(body.sys.country)%2520%253F%2520body.sys.country%2520%253A%2520%27%27%2520%253B%250A%250A%2520%2520%2520%2520let%2520forecast%2520%253D%2520%2522For%2520city%2520%2522%252Bcity%252B%27%252C%2520country%2520%27%252Bcountry%253B%250A%250A%2520%2520%2520%2520res.render(%27index%27%252C%2520%257Bbody%2520%253A%2520body%252C%2520forecast%253A%2520forecast%257D)%253B%250A%250A%2520%2520%2520%257D)%253B%250A%250A%257D)%253B" rel="noreferrer nofollow noopener)</em></p>
<p>This code snippet enables data in the input form to be posted to the index route. Once the user enters a city name, it is assigned to the city variable using the request object.   </p>
<p>The URL is then appended with the city name and ID and the request sent to ClimaCell API.  </p>
<p>The ClimaCell API server response is returned as a JSON file, which is then parsed and fed to the output template.  </p>
<p>For instance, if the user was looking for Boston weather forecasts, the app will return this:</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589196959089_WEATHER+2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Note - The temperature in this example is shown in Kelvin and is equal to 50°F or 10°C.</p>
<h2 id="heading-add-maps-to-visualize-your-data">Add Maps to Visualize Your Data</h2>
<p>You can integrate interactive maps into your forecasting application to enhance user experience. This can be achieved by using a third-party map service provider for web applications.  </p>
<p>Mapbox is one such tool that helps developers create awesome weather maps for their applications. It integrates seamlessly with any weather app.  </p>
<p>To use the Mapbox, sign up on their website and <a target="_blank" href="https://www.mapbox.com/install/">check out their API</a>. There are integrations for Android, iOS, Web, and Unity. In this case, we choose Web integration for our tool.  </p>
<p>We can either install the Mapbox CDN or use the module bundler. Let's use the module bundler.  </p>
<p>The first step would be installing the package  </p>
<p><code>npm install Mapbox-gl –save</code>  </p>
<p>Next, we add the GL JS CSS file in the HTML file by including this snippet in the   </p>
<p><code>&lt;link href='https://api.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.css' rel='stylesheet' /&gt;</code>  </p>
<p>We can now add the map to our application. To do this, use the code snippet below.</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589201956495_carbon+1.png" alt="Image" width="600" height="400" loading="lazy">
_[Raw](https://carbon.now.sh/embed?bg=rgba(0%2C0%2C0%2C1)&amp;t=blackboard&amp;wt=none&amp;l=javascript&amp;ds=true&amp;dsyoff=20px&amp;dsblur=68px&amp;wc=true&amp;wa=true&amp;pv=56px&amp;ph=56px&amp;ln=false&amp;fl=1&amp;fm=Hack&amp;fs=14px&amp;lh=133%25&amp;si=false&amp;es=1x&amp;wm=false&amp;code=var%2520mapboxgl%2520%253D%2520require(%27mapbox-gl%252Fdist%252Fmapbox-gl.js%27)%253B%250A%2520%250Amapboxgl.accessToken%2520%253D%2520%27pk.eyJ1IjoiZGlja3Nvbi1tIiwiYSI6ImNrOXphd3MzZDBlMXYzbHFwM2kwbmlvbmkifQ.VE3RRbb8l78w9kxfmh_9ew%27%253B%250Avar%2520map%2520%253D%2520new%2520mapboxgl.Map(%257B%250Acontainer%253A%2520%27CONTAINER_ELEMENT<em>ID%27%252C%250Astyle%253A%2520%27mapbox%253A%252F%252Fstyles%252Fmapbox%252Fstreets-v11%27%250A%257D)%253B%250A" rel="noreferrer nofollow noopener)</em></p>
<p>You can choose where to place the map by replacing the </p>
<p>“CONTAINER_ELEMENT_ID’ .  </p>
<p>Here is a sample map generated using Mapbox:</p>
<p><img src="https://paper-attachments.dropbox.com/s_09D7754335BDD40A8ECD55F1187847147F5C3FBE3BBD081087C52D1E8CDCDF32_1589202164225_map.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-whats-next">What’s next?</h1>
<p>At this point, much of the work is done, and your app can get weather forecasts for any city using the ClimaCell API. </p>
<p>However, you can consider adding more interactive features to your application or extending its functionality. </p>
<p>Here are some things you might want to do:</p>
<ul>
<li>Add a search function.</li>
<li>Improve the look of your user interface.</li>
<li>Query the application by ID or name.</li>
<li>Display a list of target cities and their respective IDs.</li>
<li>Add parameters to display additional weather data .</li>
<li>Integrate real-time notifications and warning signals.</li>
</ul>
<p>As you can see, the basic app building process is pretty simple and straightforward. By following the above process to leverage the power of a weather API, even beginner-level developers can get their weather application up and running in a matter of minutes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Obtain Historical Weather Forecast data in CSV format using Python ]]>
                </title>
                <description>
                    <![CDATA[ By Ekapope Viriyakovithya Recently, I worked on a machine learning project related to renewable energy, which required historical weather forecast data from multiple cities. Despite intense research, I had a hard time finding the good data source. Mo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/obtain-historical-weather-forecast-data-in-csv-format-using-python/</link>
                <guid isPermaLink="false">66d45e42d14641365a0508ac</guid>
                
                    <category>
                        <![CDATA[ worldweatheronline ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ csv ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dataframe ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ weather ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jul 2019 10:00:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca193740569d1a4ca4f62.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ekapope Viriyakovithya</p>
<p>Recently, I worked on a machine learning project related to renewable energy, which required <strong>historical weather forecast data from multiple cities</strong>.</p>
<p>Despite intense research, I had a hard time finding the good data source. Most websites restrict the access to only past two weeks of historical data. If you need more, you need to pay. In my case, I needed five years of data — hourly historical forecast, which can be costly.</p>
<h3 id="heading-my-requirements-are"><strong>My requirements are...</strong></h3>
<p><strong>1. Free — at least during trial period</strong></p>
<p>No need to provide credit card info.</p>
<p><strong>2. Flexible</strong></p>
<p>Flexible to change forecast interval, time periods, locations.</p>
<p><strong>3. Reproducible</strong></p>
<p>Easy to reproduce and implement in the production phase.</p>
<p>In the end, I decided to use data from <a target="_blank" href="https://www.worldweatheronline.com/developer/api/historical-weather-api.aspx">World Weather Online</a>. This took me less than two minutes to subscribe free trial premium API — without filling credit card info. (500 free requests/key/day for 60 days, as of 30-May-2019).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*kVPI57az2iE7Kjni3AhxOw.png" alt="Image" width="859" height="245" loading="lazy"></p>
<p><a target="_blank" href="https://www.worldweatheronline.com/developer/signup.aspx"><em>https://www.worldweatheronline.com/developer/signup.aspx</em></a></p>
<p>You can try out requests in JSON or XML format <a target="_blank" href="https://www.worldweatheronline.com/developer/premium-api-explorer.aspx">here</a>. The result is nested JSON which needed a bit pre-processing work before feeding into ML models. Therefore, I wrote some <a target="_blank" href="https://github.com/ekapope/WorldWeatherOnline">scripts</a> to parse them into pandas DataFrames and save as CSV for further use.</p>
<h3 id="heading-introducing-wwo-hist-package">Introducing wwo-hist package</h3>
<p>This <a target="_blank" href="https://pypi.org/project/wwo-hist/">wwo-hist package</a> is used to retrieve and parse historical weather data from <a target="_blank" href="https://www.worldweatheronline.com/developer/api/historical-weather-api.aspx">World Weather Online</a> into pandas DataFrame and CSV file.</p>
<p><strong>Input:</strong> api_key, location_list, start_date, end_date, frequency</p>
<p><strong>Output:</strong> location_name.csv</p>
<p><strong>Output column names:</strong> date_time, maxtempC, mintempC, totalSnow_cm, sunHour, uvIndex, uvIndex, moon_illumination, moonrise, moonset, sunrise, sunset, DewPointC, FeelsLikeC, HeatIndexC, WindChillC, WindGustKmph, cloudcover, humidity, precipMM, pressure, tempC, visibility, winddirDegree, windspeedKmph</p>
<h4 id="heading-install-and-import-the-package">Install and import the package:</h4>
<pre><code class="lang-py">pip install wwo-hist
</code></pre>
<pre><code class="lang-py"><span class="hljs-comment"># import the package and function</span>
<span class="hljs-keyword">from</span> wwo_hist <span class="hljs-keyword">import</span> retrieve_hist_data

<span class="hljs-comment"># set working directory to store output csv file(s)</span>
<span class="hljs-keyword">import</span> os
os.chdir(<span class="hljs-string">".\YOUR_PATH"</span>)
</code></pre>
<p><strong>Example code:</strong></p>
<p>Specify input parameters and call <strong><em>retrieve_hist_data()*</em></strong>.* Please visit <a target="_blank" href="https://github.com/ekapope/WorldWeatherOnline">my github repo</a> for more info about parameters setup.</p>
<p>This will retrieve <strong>3-hour interval</strong> historical weather forecast data for <strong>Singapore</strong> and <strong>California</strong> from <strong>11-Dec-2018</strong> to <strong>11-Mar-2019</strong>, save output into hist_weather_data variable and <strong>CSV</strong> files.frequency = 3</p>
<pre><code class="lang-py">FREQUENCY = <span class="hljs-number">3</span>
START_DATE = <span class="hljs-string">'11-DEC-2018'</span>
END_DATE = <span class="hljs-string">'11-MAR-2019'</span>
API_KEY = <span class="hljs-string">'YOUR_API_KEY'</span>
LOCATION_LIST = [<span class="hljs-string">'singapore'</span>,<span class="hljs-string">'california'</span>]

hist_weather_data = retrieve_hist_data(API_KEY,
                                LOCATION_LIST,
                                START_DATE,
                                END_DATE,
                                FREQUENCY,
                                location_label = <span class="hljs-literal">False</span>,
                                export_csv = <span class="hljs-literal">True</span>,
                                store_df = <span class="hljs-literal">True</span>)
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*Ga1fGBrxkoKgfzbu" alt="Image" width="795" height="747" loading="lazy"></p>
<p><em>This is what you will see in your console.</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*0-UJ7XO4ZG76oDlVvHQNVA.png" alt="Image" width="761" height="121" loading="lazy"></p>
<p><em>Result CSV(s) exported to your working directory.</em></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*gdtco3Zi0Kv03uz9" alt="Image" width="1200" height="245" loading="lazy"></p>
<p><em>Check the CSV output.</em></p>
<p>There you have it! The script detailed is also <a target="_blank" href="https://github.com/ekapope/WorldWeatherOnline">documented on GitHub</a>.</p>
<hr>
<p>Thank you for reading. Please give it a try, and let me know your feedback! If you like what I did, consider following me on <a target="_blank" href="https://github.com/ekapope">GitHub</a>, <a target="_blank" href="https://medium.com/@ekapope.v">Medium</a>, and <a target="_blank" href="https://twitter.com/EkapopeV">Twitter</a> to get more articles and tutorials on your feed.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to get Facebook messenger to notify you about the weather ]]>
                </title>
                <description>
                    <![CDATA[ By Ekapope Viriyakovithya A complete DIY guide to build your own weather alert bot. The morning routine is always stressful. Wouldn’t it be wonderful if you had one less thing to worry about in the morning? What if you had a customizable weather aler... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-facebook-messenger-to-notify-you-about-the-weather-8b5e87a64540/</link>
                <guid isPermaLink="false">66d45e3fd14641365a0508a0</guid>
                
                    <category>
                        <![CDATA[ Facebook Messenger ]]>
                    </category>
                
                    <category>
                        <![CDATA[ bots ]]>
                    </category>
                
                    <category>
                        <![CDATA[ how-to ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ weather ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 24 Jan 2019 18:22:42 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*RBHbkOfMOzl7o_crT4Rg7g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ekapope Viriyakovithya</p>
<h3 id="heading-a-complete-diy-guide-to-build-your-own-weather-alert-bot">A complete DIY guide to build your own weather alert bot.</h3>
<p>The morning routine is always stressful. Wouldn’t it be wonderful if you had one less thing to worry about in the morning?</p>
<p>What if you had a customizable weather alert bot that sent you a short message ONLY when there was a chance of rain above your pre-defined threshold?</p>
<p>Don’t waste your time checking the weather in a separate app. It can be live on your Facebook messenger chatbox!</p>
<h3 id="heading-what-do-you-need">What do you need?</h3>
<ul>
<li>Python 3.6 (or earlier) with pandas and <a target="_blank" href="https://github.com/carpedm20/fbchat">fbchat</a> packages installed</li>
</ul>
<pre><code class="lang-bash">pip install fbchat
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*Uy6HxLRFNAOcpu40NDfXSw.png" alt="Image" width="249" height="318" loading="lazy">
<em>AccuWeather Free Account</em></p>
<ul>
<li><a target="_blank" href="https://developer.accuweather.com/packages">AccuWeather developer account</a>, the free package should be enough. It provides 50 calls/day with 1 key/developer account.</li>
</ul>
<h3 id="heading-lets-get-started">Let’s get started!</h3>
<p>At the end of this how-to, you will have 3 files in the scripts folder:</p>
<p><a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/tree/master/scripts">keys.py</a> : to store your facebook email, password, and accuweather API key</p>
<p><a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/params.py">params.py</a> : to store the threshold and weather forecast location id</p>
<p><a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/main.py">main.py</a> : this is the main script, it will call the keys.py and params.py</p>
<h4 id="heading-1-setup-facebook-account-and-accuweather-api-key">1. Setup Facebook account and AccuWeather API key</h4>
<p>First, let’s put your account detail in the <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/keys.py">keys.py</a> file.</p>
<pre><code class="lang-py"><span class="hljs-comment"># Your Facebook usersname (email)</span>
FB_USERNAME= <span class="hljs-string">""</span> 

<span class="hljs-comment"># Your Facebook password</span>
FB_PASSWORD= <span class="hljs-string">""</span> 

<span class="hljs-comment"># Your AccuWeather API key</span>
ACCUWEATHER_API_KEY= <span class="hljs-string">""</span>
</code></pre>
<h4 id="heading-2-setup-parameters"><strong>2. Setup parameters</strong></h4>
<p>In this step, we will define the threshold for the probability of rain or snow, delay time between each request and message, and also location.</p>
<p>Currently, we set the threshold at 25% for both rain and snow. We will get the alert message only if the AccuWeather data shows the probability ≥ 25%.</p>
<p>The scripts below will request data from AccuWeather every 1 hour ( UPDATE_INTERVAL_HR= 1) and will send a message every 4 hours ( DELAY_TIME_HR= 4).</p>
<p>These parameters will be stored in the <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/params.py">params.py</a> file.</p>
<pre><code class="lang-py"><span class="hljs-comment"># Define % threshold for probability of rain and snow. </span>
<span class="hljs-comment"># The msg will be sent out if the % chance exceed the value</span>
RAIN_THRESHOLD = <span class="hljs-number">25</span>
SNOW_THRESHOLD = <span class="hljs-number">25</span>

<span class="hljs-comment"># time between Accuweather request (in hour)</span>
UPDATE_INTERVAL_HR = <span class="hljs-number">1</span> 

<span class="hljs-comment"># delay time between msg (in hour)</span>
DELAY_TIME_HR = <span class="hljs-number">4</span> 

<span class="hljs-comment"># location id</span>
<span class="hljs-comment"># for example, https://www.accuweather.com/en/fr/lille/135564/weather-forecast/135564</span>
<span class="hljs-comment"># location id is 135564</span>
LOCATION_ID = <span class="hljs-string">"135564"</span>
</code></pre>
<h4 id="heading-3-retrieve-data-from-accuweather">3. Retrieve data from AccuWeather</h4>
<p>Now here comes the fun part. We will now work on the main script.</p>
<p>If you plan to run it locally, setup your directory and import keys and params. Make sure you put <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/keys.py">keys.py</a> and <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/params.py">params.py</a> in the same folder as this <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/main.py">main.py</a> script.</p>
<pre><code class="lang-py"><span class="hljs-comment">#set the current directory</span>
<span class="hljs-keyword">import</span> os
os.chdir(<span class="hljs-string">r".\YOUR_PATH"</span>)
<span class="hljs-comment">###############################################################################</span>
<span class="hljs-comment">#import keys and parameters other scripts in the same folder</span>
<span class="hljs-keyword">from</span> keys <span class="hljs-keyword">import</span> FB_USERNAME,FB_PASSWORD,ACCUWEATHER_API_KEY
<span class="hljs-keyword">from</span> params <span class="hljs-keyword">import</span> RAIN_THRESHOLD,SNOW_THRESHOLD,UPDATE_INTERVAL_HR,DELAY_TIME_HR,LOCATION_ID
</code></pre>
<p>Import required modules.</p>
<pre><code class="lang-py"><span class="hljs-comment">#import required modules</span>
<span class="hljs-keyword">import</span> urllib
<span class="hljs-keyword">import</span> urllib.parse
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">import</span> sys
<span class="hljs-keyword">from</span> fbchat <span class="hljs-keyword">import</span> Client
<span class="hljs-keyword">from</span> fbchat.models <span class="hljs-keyword">import</span> *
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime
</code></pre>
<p>Define ‘url_page’ to be requested, in this example, we will retrieve 12-hour hourly forecast. Convert our update/delay time into seconds.</p>
<pre><code class="lang-py">url_page = <span class="hljs-string">"http://dataservice.accuweather.com/forecasts/v1/hourly/12hour/"</span>+str(LOCATION_ID)+<span class="hljs-string">"?apikey="</span>+ACCUWEATHER_API_KEY+<span class="hljs-string">"&amp;details=true&amp;metric=true"</span>
<span class="hljs-comment">#convert hours to seconds</span>
update_interval_sec = <span class="hljs-number">60</span>*<span class="hljs-number">60</span>*UPDATE_INTERVAL_HR 
delay_time_sec = <span class="hljs-number">60</span>*<span class="hljs-number">60</span>*DELAY_TIME_HR
</code></pre>
<p>Then, request the data and put in pandas DataFrame called ‘json_df’.</p>
<p>At this point, we can inspect the retrieved table. Extract and rename the elements that we need. In this example, we will need AccuWeather link, % rain, % snow, date, and time in the desired format.</p>
<pre><code class="lang-py">    json_page = urllib.request.urlopen(url_page)
    json_data = json.loads(json_page.read().decode())
    json_df = pd.DataFrame(json_data)

    <span class="hljs-comment"># set maximum width, so the links are fully shown and clickable</span>
    pd.set_option(<span class="hljs-string">'display.max_colwidth'</span>, <span class="hljs-number">-1</span>)
    json_df[<span class="hljs-string">'Links'</span>] = json_df[<span class="hljs-string">'MobileLink'</span>].apply(<span class="hljs-keyword">lambda</span> x: <span class="hljs-string">'&lt;a href='</span>+x+<span class="hljs-string">'&gt;Link&lt;/a&gt;'</span>)

    json_df[<span class="hljs-string">'Real Feel (degC)'</span>] = json_df[<span class="hljs-string">'RealFeelTemperature'</span>].apply(<span class="hljs-keyword">lambda</span> x: x.get(<span class="hljs-string">'Value'</span>))
    json_df[<span class="hljs-string">'Weather'</span>] = json_df[<span class="hljs-string">'IconPhrase'</span>] 
    json_df[<span class="hljs-string">'Percent_Rain'</span>] = json_df[<span class="hljs-string">'RainProbability'</span>] 
    json_df[<span class="hljs-string">'Percent_Snow'</span>] = json_df[<span class="hljs-string">'SnowProbability'</span>]
</code></pre>
<p>If we look closely, the ‘DateTime’ column is a bit tricky to extract and needs some work. After clean up, save it in ‘current_retrieved_datetime’ variable.</p>
<pre><code class="lang-py">json_df[[<span class="hljs-string">'Date'</span>,<span class="hljs-string">'Time'</span>]] = json_df[<span class="hljs-string">'DateTime'</span>].str.split(<span class="hljs-string">'T'</span>, expand=<span class="hljs-literal">True</span>)
<span class="hljs-comment"># trim the time to hh:mm format, change to str</span>
json_df[[<span class="hljs-string">'Time'</span>]] = json_df[<span class="hljs-string">'Time'</span>].str.split(<span class="hljs-string">'+'</span>, expand=<span class="hljs-literal">True</span>)[<span class="hljs-number">0</span>].astype(str).str[:<span class="hljs-number">5</span>]

current_retrieved_datetime = str(json_df[<span class="hljs-string">'Date'</span>][<span class="hljs-number">0</span>])+<span class="hljs-string">' '</span>+str(json_df[<span class="hljs-string">'Time'</span>][<span class="hljs-number">0</span>])
</code></pre>
<p>Next, write an if-else condition to customize the alert message. The retrieved table provides us a 12-hr forecast. We will check each element of both the rain and snow columns and return a message if the probability is above the threshold.</p>
<p>First, initialize the alert message for each case.</p>
<pre><code class="lang-py">rain_msg=<span class="hljs-string">""</span>
snow_msg=<span class="hljs-string">""</span>
</code></pre>
<p>Check ‘Percent_Rain’ and ‘ Percent_Snow’ columns, flag with 1 if the % probability is above threshold (or 0 otherwise).</p>
<p>Sum the columns and modify the ‘rain_msg’ and ‘snow_msg’.</p>
<pre><code class="lang-py">    <span class="hljs-comment"># check % Rain column, return rain_msg</span>
    json_df.loc[json_df[<span class="hljs-string">'Percent_Rain'</span>] &gt;= RAIN_THRESHOLD, <span class="hljs-string">'Rain_Alert'</span>] = <span class="hljs-number">1</span>  
    json_df.loc[json_df[<span class="hljs-string">'Percent_Rain'</span>] &lt; RAIN_THRESHOLD, <span class="hljs-string">'Rain_Alert'</span>] = <span class="hljs-number">0</span>
    <span class="hljs-keyword">if</span> (sum(json_df[<span class="hljs-string">'Rain_Alert'</span>]) &gt; <span class="hljs-number">0</span>):
        rain_msg = <span class="hljs-string">'There is '</span> \
                    +str(json_df[<span class="hljs-string">'Percent_Rain'</span>][json_df[<span class="hljs-string">'Rain_Alert'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]) \
                    +<span class="hljs-string">' % chance of rain'</span> \
                    +<span class="hljs-string">' at '</span> \
                    +str(json_df[<span class="hljs-string">'Time'</span>][json_df[<span class="hljs-string">'Rain_Alert'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>])

    <span class="hljs-comment"># check % Snow column</span>
    json_df.loc[json_df[<span class="hljs-string">'Percent_Snow'</span>] &gt;= SNOW_THRESHOLD, <span class="hljs-string">'Snow_Alert'</span>] = <span class="hljs-number">1</span>  
    json_df.loc[json_df[<span class="hljs-string">'Percent_Snow'</span>] &lt; SNOW_THRESHOLD, <span class="hljs-string">'Snow_Alert'</span>] = <span class="hljs-number">0</span>
    <span class="hljs-keyword">if</span> (sum(json_df[<span class="hljs-string">'Snow_Alert'</span>]) &gt; <span class="hljs-number">0</span>):
        snow_msg = <span class="hljs-string">'There is '</span> \
                    +str(json_df[<span class="hljs-string">'Percent_Snow'</span>][json_df[<span class="hljs-string">'Percent_Snow'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]) \
                    +<span class="hljs-string">' % chance of snow'</span> \
                    +<span class="hljs-string">' at '</span> \
                    +str(json_df[<span class="hljs-string">'Time'</span>][json_df[<span class="hljs-string">'Percent_Snow'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>])
</code></pre>
<p>Initialize ‘alert_msg’, modify the messages if there is any ‘rain_msg’ or ‘snow_msg’.</p>
<pre><code class="lang-py">alert_msg =<span class="hljs-string">""</span>
<span class="hljs-keyword">if</span>(len(rain_msg)|len(snow_msg)!=<span class="hljs-number">0</span>):
     alert_msg = rain_msg +<span class="hljs-string">" "</span>+snow_msg
</code></pre>
<p>Add the link to variable ‘ link_for_click’ this will be attached to the message when we send later on.</p>
<pre><code class="lang-py">link_for_click = json_df[<span class="hljs-string">'MobileLink'</span>][<span class="hljs-number">0</span>]
</code></pre>
<p>Up until this point, we can now wrap them into a function. Don’t worry if you get lost, I have put them together below.</p>
<pre><code class="lang-py"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">func_get_weather</span>(<span class="hljs-params">url_page</span>):</span>

    json_page = urllib.request.urlopen(url_page)
    json_data = json.loads(json_page.read().decode())
    json_df = pd.DataFrame(json_data)

    <span class="hljs-comment"># set maximum width, so the links are fully shown and clickable</span>
    pd.set_option(<span class="hljs-string">'display.max_colwidth'</span>, <span class="hljs-number">-1</span>)
    json_df[<span class="hljs-string">'Links'</span>] = json_df[<span class="hljs-string">'MobileLink'</span>].apply(<span class="hljs-keyword">lambda</span> x: <span class="hljs-string">'&lt;a href='</span>+x+<span class="hljs-string">'&gt;Link&lt;/a&gt;'</span>)

    json_df[<span class="hljs-string">'Real Feel (degC)'</span>] = json_df[<span class="hljs-string">'RealFeelTemperature'</span>].apply(<span class="hljs-keyword">lambda</span> x: x.get(<span class="hljs-string">'Value'</span>))
    json_df[<span class="hljs-string">'Weather'</span>] = json_df[<span class="hljs-string">'IconPhrase'</span>] 
    json_df[<span class="hljs-string">'Percent_Rain'</span>] = json_df[<span class="hljs-string">'RainProbability'</span>] 
    json_df[<span class="hljs-string">'Percent_Snow'</span>] = json_df[<span class="hljs-string">'SnowProbability'</span>] 
    json_df[[<span class="hljs-string">'Date'</span>,<span class="hljs-string">'Time'</span>]] = json_df[<span class="hljs-string">'DateTime'</span>].str.split(<span class="hljs-string">'T'</span>, expand=<span class="hljs-literal">True</span>)
    <span class="hljs-comment"># trim the time to hh:mm format, change to str</span>
    json_df[[<span class="hljs-string">'Time'</span>]] = json_df[<span class="hljs-string">'Time'</span>].str.split(<span class="hljs-string">'+'</span>, expand=<span class="hljs-literal">True</span>)[<span class="hljs-number">0</span>].astype(str).str[:<span class="hljs-number">5</span>]

    current_retrieved_datetime = str(json_df[<span class="hljs-string">'Date'</span>][<span class="hljs-number">0</span>])+<span class="hljs-string">' '</span>+str(json_df[<span class="hljs-string">'Time'</span>][<span class="hljs-number">0</span>])

    rain_msg=<span class="hljs-string">""</span>
    snow_msg=<span class="hljs-string">""</span>

    <span class="hljs-comment"># check % Rain column, return rain_msg</span>
    json_df.loc[json_df[<span class="hljs-string">'Percent_Rain'</span>] &gt;= RAIN_THRESHOLD, <span class="hljs-string">'Rain_Alert'</span>] = <span class="hljs-number">1</span>  
    json_df.loc[json_df[<span class="hljs-string">'Percent_Rain'</span>] &lt; RAIN_THRESHOLD, <span class="hljs-string">'Rain_Alert'</span>] = <span class="hljs-number">0</span>
    <span class="hljs-keyword">if</span> (sum(json_df[<span class="hljs-string">'Rain_Alert'</span>]) &gt; <span class="hljs-number">0</span>):
        rain_msg = <span class="hljs-string">'There is '</span> \
                    +str(json_df[<span class="hljs-string">'Percent_Rain'</span>][json_df[<span class="hljs-string">'Rain_Alert'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]) \
                    +<span class="hljs-string">' % chance of rain'</span> \
                    +<span class="hljs-string">' at '</span> \
                    +str(json_df[<span class="hljs-string">'Time'</span>][json_df[<span class="hljs-string">'Rain_Alert'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>])

    <span class="hljs-comment"># check % Snow column</span>
    json_df.loc[json_df[<span class="hljs-string">'Percent_Snow'</span>] &gt;= SNOW_THRESHOLD, <span class="hljs-string">'Snow_Alert'</span>] = <span class="hljs-number">1</span>  
    json_df.loc[json_df[<span class="hljs-string">'Percent_Snow'</span>] &lt; SNOW_THRESHOLD, <span class="hljs-string">'Snow_Alert'</span>] = <span class="hljs-number">0</span>
    <span class="hljs-keyword">if</span> (sum(json_df[<span class="hljs-string">'Snow_Alert'</span>]) &gt; <span class="hljs-number">0</span>):
        snow_msg = <span class="hljs-string">'There is '</span> \
                    +str(json_df[<span class="hljs-string">'Percent_Snow'</span>][json_df[<span class="hljs-string">'Percent_Snow'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]) \
                    +<span class="hljs-string">' % chance of snow'</span> \
                    +<span class="hljs-string">' at '</span> \
                    +str(json_df[<span class="hljs-string">'Time'</span>][json_df[<span class="hljs-string">'Percent_Snow'</span>]==<span class="hljs-number">1</span>][<span class="hljs-number">0</span>])

    alert_msg =<span class="hljs-string">""</span>
    <span class="hljs-keyword">if</span>(len(rain_msg)|len(snow_msg)!=<span class="hljs-number">0</span>):
         alert_msg = rain_msg +<span class="hljs-string">" "</span>+snow_msg

    link_for_click = json_df[<span class="hljs-string">'MobileLink'</span>][<span class="hljs-number">0</span>]

    <span class="hljs-keyword">return</span>(current_retrieved_datetime,alert_msg,link_for_click)
</code></pre>
<h4 id="heading-4-automated-loop">4. Automated loop</h4>
<p>Finally, for the last part, we will automate the process by using loops. The scripts below are putting the number of loops as ‘num_repeat = 999’.</p>
<pre><code class="lang-py">num_repeat = <span class="hljs-number">999</span> <span class="hljs-comment"># number of loops to repeat</span>
previous_alert_msg = <span class="hljs-string">""</span> <span class="hljs-comment"># initialize alert msg</span>
</code></pre>
<p>Use try and except to overcome errors (just in case something goes wrong with connections). Call ‘func_get_weather’ function and assign to variables.</p>
<pre><code class="lang-py"><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(num_repeat):
    <span class="hljs-keyword">try</span>:
        current_retrieved_datetime,alert_msg,link_for_click = func_get_weather(url_page)
    <span class="hljs-keyword">except</span> (RuntimeError, TypeError, NameError, ValueError, urllib.error.URLError):
        print(<span class="hljs-string">'error catched'</span>)
</code></pre>
<p>Then, check if there are any changes in the weather. If nothing has changed, print the message to the screen. No chat message will be sent.</p>
<pre><code class="lang-py">    <span class="hljs-comment">#if the weather forecast has not changed, no alert msg will be sent</span>
    <span class="hljs-keyword">if</span> len(alert_msg) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> previous_alert_msg == alert_msg:
        print(i, current_retrieved_datetime, <span class="hljs-string">'no changes in weather forecast'</span>)
</code></pre>
<p>The message will be sent only if there is any change in the weather.</p>
<p>We can finalize our message at this point. Fetch your user id of your friends and store in ‘friend_list’. Loop to send the message to each friend one-by-one. We put sleep time = 2 seconds between each message and logout after finish.</p>
<pre><code class="lang-py">    <span class="hljs-keyword">if</span> len(alert_msg) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> previous_alert_msg != alert_msg:    
        <span class="hljs-comment"># login and send facebook msg </span>
        client = Client(FB_USERNAME,FB_PASSWORD)
        users = client.fetchAllUsers()
        friend_list=[user.uid <span class="hljs-keyword">for</span> user <span class="hljs-keyword">in</span> users <span class="hljs-keyword">if</span> user.uid!=<span class="hljs-string">"0"</span>]
        <span class="hljs-comment"># loop though all friends</span>
        <span class="hljs-keyword">for</span> id <span class="hljs-keyword">in</span> friend_list: 
            client.send(Message(text=current_retrieved_datetime+<span class="hljs-string">' '</span>+<span class="hljs-string">'12-hr Weather Forecast'</span> +<span class="hljs-string">' '</span>+ alert_msg +<span class="hljs-string">' '</span>+link_for_click),thread_id=id, thread_type=ThreadType.USER)
            <span class="hljs-comment">#sleep for 2 secs between each msg</span>
            time.sleep(<span class="hljs-number">2</span>) 
        <span class="hljs-comment">#logout after sent</span>
        client.logout()
</code></pre>
<p>Execute delay time for the next message. Already defined in <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat/blob/master/scripts/params.py">params.py</a> file — in this case, it is 4 hours. And another one for AccuWeather request delay is 1 hour.</p>
<pre><code class="lang-py">    time.sleep(delay_time_sec)                         
time.sleep(update_interval_sec)
</code></pre>
<p>Again, don’t worry if you get lost. I have put the complete loop together below.</p>
<pre><code class="lang-py"><span class="hljs-comment"># Execute functions, retrieve data and send facebook msg</span>
num_repeat = <span class="hljs-number">999</span> <span class="hljs-comment"># number of loops to repeat</span>
previous_alert_msg = <span class="hljs-string">""</span> <span class="hljs-comment"># initialize alert msg</span>
<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(num_repeat):

    <span class="hljs-keyword">try</span>:
        current_retrieved_datetime,alert_msg,link_for_click = func_get_weather(url_page)
    <span class="hljs-keyword">except</span> (RuntimeError, TypeError, NameError, ValueError, urllib.error.URLError):
        print(<span class="hljs-string">'error catched'</span>)

    <span class="hljs-comment">#if the weather forecast has not changed, no alert msg will be sent</span>
    <span class="hljs-keyword">if</span> len(alert_msg) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> previous_alert_msg == alert_msg:
        print(i, current_retrieved_datetime, <span class="hljs-string">'no changes in weather forecast'</span>)
    <span class="hljs-comment">#if there is any changes in weather       </span>
    <span class="hljs-keyword">if</span> len(alert_msg) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">and</span> previous_alert_msg != alert_msg:    
        <span class="hljs-comment"># login and send facebook msg </span>
        client = Client(FB_USERNAME,FB_PASSWORD)
        users = client.fetchAllUsers()
        friend_list=[user.uid <span class="hljs-keyword">for</span> user <span class="hljs-keyword">in</span> users <span class="hljs-keyword">if</span> user.uid!=<span class="hljs-string">"0"</span>]
        <span class="hljs-comment"># loop though all friends</span>
        <span class="hljs-keyword">for</span> id <span class="hljs-keyword">in</span> friend_list: 
            client.send(Message(text=current_retrieved_datetime+<span class="hljs-string">' '</span>+<span class="hljs-string">'12-hr Weather Forecast'</span> +<span class="hljs-string">' '</span>+ alert_msg +<span class="hljs-string">' '</span>+link_for_click),thread_id=id, thread_type=ThreadType.USER)
            <span class="hljs-comment">#sleep for 2 secs between each msg</span>
            time.sleep(<span class="hljs-number">2</span>) 
        <span class="hljs-comment">#logout after sent</span>
        client.logout()    
        time.sleep(delay_time_sec)                         
    time.sleep(update_interval_sec)
print(current_retrieved_datetime,<span class="hljs-string">'Run Completed'</span>)
</code></pre>
<p>Ta-da! After all our hard work, here is a snapshot of the message we will get.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*34jxVzSyVzO86-OKGlzVHw.png" alt="Image" width="431" height="503" loading="lazy">
<em>Facebook chatbox msg. The location id in this example is 135564.</em></p>
<p>In case we need to know more detail, we can directly click on the link. It will navigate to the AccuWeather mobile website.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*sZ6uWgjnGDF1rVBoKy44Ng.png" alt="Image" width="603" height="586" loading="lazy">
<em>AccuWeather Link</em></p>
<p>The completed script for this how-to is also <a target="_blank" href="https://github.com/ekapope/Weather_Alert_Notification_Facebook_Chat">documented on GitHub</a>.</p>
<p>Thank you for reading. Please give it a try, have fun and let me know your feedback!</p>
<p>If you like what I did, consider following me on <a target="_blank" href="https://ekapope.github.io/">GitHub</a>, <a target="_blank" href="https://medium.com/@ekapope.v">Medium</a>, and <a target="_blank" href="https://twitter.com/EkapopeV">Twitter</a>. Make sure <a target="_blank" href="https://github.com/Ekapope">to star it on GitHub</a> :D</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
