Un ghid DIY complet pentru a vă construi propriul bot de alertă meteo.

Rutina de dimineață este întotdeauna stresantă. Nu ar fi minunat dacă ați avea un lucru mai puțin de care să vă faceți griji dimineața?

Ce se întâmplă dacă ai avea un bot de alertă meteo personalizabil care ți-ar fi trimis un mesaj scurt DOAR atunci când există șanse de ploaie peste pragul tău predefinit?

Nu vă pierdeți timpul verificând vremea într-o aplicație separată. Poate fi live pe chat-ul tău de chat Facebook Messenger!

De ce ai nevoie?

  • Python 3.6 (sau anterior) cu panda și fbchat pachetele instalate
pip install fbchat
Cum sa faci Facebook Messenger sa te anunte despre vreme
Cont gratuit AccuWeather

Să începem!

La sfârșitul acestei instrucțiuni, veți avea 3 fișiere în folderul de scripturi:

keys.py : pentru a stoca adresa dvs. de e-mail de pe facebook, parola și cheia API Accuweather

params.py : pentru a stoca pragul și identificarea locației prognozei meteo

main.py : acesta este scriptul principal, va apela keys.py și params.py

1. Configurați contul Facebook și cheia API AccuWeather

Mai întâi, să introducem detaliile contului dvs. în keys.py fişier.

# Your Facebook usersname (email)
FB_USERNAME= "" 

# Your Facebook password
FB_PASSWORD= "" 

# Your AccuWeather API key
ACCUWEATHER_API_KEY= ""

2. Parametrii de configurare

În acest pas, vom defini pragul pentru probabilitatea de ploaie sau zăpadă, timpul de întârziere între fiecare solicitare și mesaj, precum și locația.

În prezent, am stabilit pragul la 25% atât pentru ploaie, cât și pentru zăpadă. Vom primi mesajul de alertă numai dacă datele AccuWeather arată probabilitatea ≥ 25%.

Scripturile de mai jos vor solicita date de la AccuWeather la fiecare 1 oră (UPDATE_INTERVAL_HR = 1) și vor trimite un mesaj la fiecare 4 ore (DELAY_TIME_HR = 4).

Acești parametri vor fi stocați în params.py fişier.

# Define % threshold for probability of rain and snow. 
# The msg will be sent out if the % chance exceed the value
RAIN_THRESHOLD = 25
SNOW_THRESHOLD = 25

# time between Accuweather request (in hour)
UPDATE_INTERVAL_HR = 1 

# delay time between msg (in hour)
DELAY_TIME_HR = 4 

# location id
# for example, https://www.accuweather.com/en/fr/lille/135564/weather-forecast/135564
# location id is 135564
LOCATION_ID = "135564" 

3. Preluarea datelor din AccuWeather

Acum vine partea distractivă. Acum vom lucra la scenariul principal.

Dacă intenționați să îl rulați local, configurați directorul și importați cheile și parametrii. Asigurați-vă că ați pus keys.py și params.py în același dosar ca acesta main.py scenariu.

#set the current directory
import os
os.chdir(r".YOUR_PATH")
###############################################################################
#import keys and parameters other scripts in the same folder
from keys import FB_USERNAME,FB_PASSWORD,ACCUWEATHER_API_KEY
from params import RAIN_THRESHOLD,SNOW_THRESHOLD,UPDATE_INTERVAL_HR,DELAY_TIME_HR,LOCATION_ID

Importați modulele necesare.

#import required modules
import urllib
import urllib.parse
import json
import time
import requests
import pandas as pd
import logging
import sys
from fbchat import Client
from fbchat.models import *
from datetime import datetime

Definiți „url_page” care urmează să fie solicitată, în acest exemplu, vom prelua prognoza orară de 12 ore. Convertiți timpul nostru de actualizare / întârziere în secunde.

url_page = "http://dataservice.accuweather.com/forecasts/v1/hourly/12hour/"+str(LOCATION_ID)+"?apikey="+ACCUWEATHER_API_KEY+"&details=true&metric=true"
#convert hours to seconds
update_interval_sec = 60*60*UPDATE_INTERVAL_HR 
delay_time_sec = 60*60*DELAY_TIME_HR 

Apoi, solicitați datele și puneți panda DataFrame numit „json_df”.

În acest moment, putem inspecta tabelul recuperat. Extrageți și redenumiți elementele de care avem nevoie. În acest exemplu, vom avea nevoie de link-ul AccuWeather,% ploaie,% zăpadă, dată și oră în formatul dorit.

    json_page = urllib.request.urlopen(url_page)
    json_data = json.loads(json_page.read().decode())
    json_df = pd.DataFrame(json_data)
    
    # set maximum width, so the links are fully shown and clickable
    pd.set_option('display.max_colwidth', -1)
    json_df['Links'] = json_df['MobileLink'].apply(lambda x: '<a href="https://www.freecodecamp.org/news/how-to-get-facebook-messenger-to-notify-you-about-the-weather-8b5e87a64540/+x+">Link</a>')
    
    json_df['Real Feel (degC)'] = json_df['RealFeelTemperature'].apply(lambda x: x.get('Value'))
    json_df['Weather'] = json_df['IconPhrase'] 
    json_df['Percent_Rain'] = json_df['RainProbability'] 
    json_df['Percent_Snow'] = json_df['SnowProbability'] 

Dacă ne uităm atent, coloana „DateTime” este puțin dificil de extras și are nevoie de ceva lucru. După curățare, salvați-o în variabila „current_retrieved_datetime”.

json_df[['Date','Time']] = json_df['DateTime'].str.split('T', expand=True)
# trim the time to hh:mm format, change to str
json_df[['Time']] = json_df['Time'].str.split('+', expand=True)[0].astype(str).str[:5]

current_retrieved_datetime = str(json_df['Date'][0])+' '+str(json_df['Time'][0])

Apoi, scrieți o condiție if-else pentru a personaliza mesajul de alertă. Tabelul recuperat ne oferă o prognoză de 12 ore. Vom verifica fiecare element atât al coloanelor de ploaie, cât și de zăpadă și vom returna un mesaj dacă probabilitatea este peste prag.

Mai întâi, inițializați mesajul de alertă pentru fiecare caz.

rain_msg=""
snow_msg=""

Verificați coloanele „Procent_ploaie” și „Procent_zăpadă”, semnalizați cu 1 dacă probabilitatea% este peste prag (sau 0 altfel).

Sumați coloanele și modificați „rain_msg” și „snow_msg”.

    # check % Rain column, return rain_msg
    json_df.loc[json_df['Percent_Rain'] >= RAIN_THRESHOLD, 'Rain_Alert'] = 1  
    json_df.loc[json_df['Percent_Rain'] < RAIN_THRESHOLD, 'Rain_Alert'] = 0
    if (sum(json_df['Rain_Alert']) > 0):
        rain_msg = 'There is ' 
                    +str(json_df['Percent_Rain'][json_df['Rain_Alert']==1][0]) 
                    +' % chance of rain' 
                    +' at ' 
                    +str(json_df['Time'][json_df['Rain_Alert']==1][0])
    
    # check % Snow column
    json_df.loc[json_df['Percent_Snow'] >= SNOW_THRESHOLD, 'Snow_Alert'] = 1  
    json_df.loc[json_df['Percent_Snow'] < SNOW_THRESHOLD, 'Snow_Alert'] = 0
    if (sum(json_df['Snow_Alert']) > 0):
        snow_msg = 'There is ' 
                    +str(json_df['Percent_Snow'][json_df['Percent_Snow']==1][0]) 
                    +' % chance of snow' 
                    +' at ' 
                    +str(json_df['Time'][json_df['Percent_Snow']==1][0])

Inițializați „alert_msg”, modificați mesajele dacă există „rain_msg” sau „snow_msg”.

alert_msg =""
if(len(rain_msg)|len(snow_msg)!=0):
     alert_msg = rain_msg +" "+snow_msg

Adăugați linkul la variabila „link_for_click”, aceasta va fi atașată la mesaj atunci când vom trimite mai târziu

link_for_click = json_df['MobileLink'][0]

Până în acest moment, le putem înfășura într-o funcție. Nu vă faceți griji dacă vă pierdeți, le-am pus împreună mai jos.

def func_get_weather(url_page):

    json_page = urllib.request.urlopen(url_page)
    json_data = json.loads(json_page.read().decode())
    json_df = pd.DataFrame(json_data)
    
    # set maximum width, so the links are fully shown and clickable
    pd.set_option('display.max_colwidth', -1)
    json_df['Links'] = json_df['MobileLink'].apply(lambda x: '<a href="https://www.freecodecamp.org/news/how-to-get-facebook-messenger-to-notify-you-about-the-weather-8b5e87a64540/+x+">Link</a>')
    
    json_df['Real Feel (degC)'] = json_df['RealFeelTemperature'].apply(lambda x: x.get('Value'))
    json_df['Weather'] = json_df['IconPhrase'] 
    json_df['Percent_Rain'] = json_df['RainProbability'] 
    json_df['Percent_Snow'] = json_df['SnowProbability'] 
    json_df[['Date','Time']] = json_df['DateTime'].str.split('T', expand=True)
    # trim the time to hh:mm format, change to str
    json_df[['Time']] = json_df['Time'].str.split('+', expand=True)[0].astype(str).str[:5]
    
    current_retrieved_datetime = str(json_df['Date'][0])+' '+str(json_df['Time'][0])
    
    rain_msg=""
    snow_msg=""
    
    # check % Rain column, return rain_msg
    json_df.loc[json_df['Percent_Rain'] >= RAIN_THRESHOLD, 'Rain_Alert'] = 1  
    json_df.loc[json_df['Percent_Rain'] < RAIN_THRESHOLD, 'Rain_Alert'] = 0
    if (sum(json_df['Rain_Alert']) > 0):
        rain_msg = 'There is ' 
                    +str(json_df['Percent_Rain'][json_df['Rain_Alert']==1][0]) 
                    +' % chance of rain' 
                    +' at ' 
                    +str(json_df['Time'][json_df['Rain_Alert']==1][0])
    
    # check % Snow column
    json_df.loc[json_df['Percent_Snow'] >= SNOW_THRESHOLD, 'Snow_Alert'] = 1  
    json_df.loc[json_df['Percent_Snow'] < SNOW_THRESHOLD, 'Snow_Alert'] = 0
    if (sum(json_df['Snow_Alert']) > 0):
        snow_msg = 'There is ' 
                    +str(json_df['Percent_Snow'][json_df['Percent_Snow']==1][0]) 
                    +' % chance of snow' 
                    +' at ' 
                    +str(json_df['Time'][json_df['Percent_Snow']==1][0])

    alert_msg =""
    if(len(rain_msg)|len(snow_msg)!=0):
         alert_msg = rain_msg +" "+snow_msg
    
    link_for_click = json_df['MobileLink'][0]
    
    return(current_retrieved_datetime,alert_msg,link_for_click)

4. Buclă automată

În cele din urmă, pentru ultima parte, vom automatiza procesul folosind bucle. Scripturile de mai jos pun numărul de bucle ca „num_repeat = 999”.

num_repeat = 999 # number of loops to repeat
previous_alert_msg = "" # initialize alert msg

Folosiți try and except pentru a depăși erorile (doar în cazul în care ceva nu merge bine la conexiuni). Apelați funcția „func_get_weather” și atribuiți variabilelor.

for i in range(num_repeat):
    try:
        current_retrieved_datetime,alert_msg,link_for_click = func_get_weather(url_page)
    except (RuntimeError, TypeError, NameError, ValueError, urllib.error.URLError):
        print('error catched')

Apoi, verificați dacă există modificări ale vremii. Dacă nu s-a schimbat nimic, imprimați mesajul pe ecran. Nu va fi trimis niciun mesaj de chat.

    #if the weather forecast has not changed, no alert msg will be sent
    if len(alert_msg) > 0 and previous_alert_msg == alert_msg:
        print(i, current_retrieved_datetime, 'no changes in weather forecast')

Mesajul va fi trimis numai dacă există vreo modificare a vremii.

Putem finaliza mesajul nostru în acest moment. Aduceți-vă ID-ul de utilizator al prietenilor dvs. și stocați-l în „lista_amici” Buclați-vă pentru a trimite mesajul fiecărui prieten unul câte unul. Punem timpul de repaus = 2 secunde între fiecare mesaj și deconectare după finalizare.

    if len(alert_msg) > 0 and previous_alert_msg != alert_msg:    
        # login and send facebook msg 
        client = Client(FB_USERNAME,FB_PASSWORD)
        users = client.fetchAllUsers()
        friend_list=[user.uid for user in users if user.uid!="0"]
        # loop though all friends
        for id in friend_list: 
            client.send(Message(text=current_retrieved_datetime+' '+'12-hr Weather Forecast' +' '+ alert_msg +' '+link_for_click),thread_id=id, thread_type=ThreadType.USER)
            #sleep for 2 secs between each msg
            time.sleep(2) 
        #logout after sent
        client.logout()   

Executați timpul de întârziere pentru următorul mesaj. Deja definit în params.py fișier – în acest caz, este de 4 ore. Și încă una pentru întârzierea solicitării AccuWeather este de 1 oră.

    time.sleep(delay_time_sec)                         
time.sleep(update_interval_sec)

Din nou, nu vă faceți griji dacă vă pierdeți. Am pus bucla completă împreună mai jos.

# Execute functions, retrieve data and send facebook msg
num_repeat = 999 # number of loops to repeat
previous_alert_msg = "" # initialize alert msg
for i in range(num_repeat):
    
    try:
        current_retrieved_datetime,alert_msg,link_for_click = func_get_weather(url_page)
    except (RuntimeError, TypeError, NameError, ValueError, urllib.error.URLError):
        print('error catched')

    #if the weather forecast has not changed, no alert msg will be sent
    if len(alert_msg) > 0 and previous_alert_msg == alert_msg:
        print(i, current_retrieved_datetime, 'no changes in weather forecast')
    #if there is any changes in weather       
    if len(alert_msg) > 0 and previous_alert_msg != alert_msg:    
        # login and send facebook msg 
        client = Client(FB_USERNAME,FB_PASSWORD)
        users = client.fetchAllUsers()
        friend_list=[user.uid for user in users if user.uid!="0"]
        # loop though all friends
        for id in friend_list: 
            client.send(Message(text=current_retrieved_datetime+' '+'12-hr Weather Forecast' +' '+ alert_msg +' '+link_for_click),thread_id=id, thread_type=ThreadType.USER)
            #sleep for 2 secs between each msg
            time.sleep(2) 
        #logout after sent
        client.logout()    
        time.sleep(delay_time_sec)                         
    time.sleep(update_interval_sec)
print(current_retrieved_datetime,'Run Completed')

Ta-da! După toată munca noastră grea, iată un instantaneu al mesajului pe care îl vom primi.

1611300607 779 Cum sa faci Facebook Messenger sa te anunte despre vreme
Facebook chatbox msg. ID-ul locației din acest exemplu este 135564.

În cazul în care trebuie să aflăm mai multe detalii, putem face clic direct pe link. Acesta va naviga la site-ul mobil AccuWeather.

1611300607 345 Cum sa faci Facebook Messenger sa te anunte despre vreme
AccuWeather Link

Scriptul completat pentru acest manual este, de asemenea documentat pe GitHub.

Mulțumesc că ai citit. Vă rugăm să încercați, distrați-vă și spuneți-mi feedback-ul dvs.!

Dacă îți place ceea ce am făcut, ia în considerare urmărirea mea GitHub, Mediu, și Stare de nervozitate. A te asigura să o vedem pe GitHub : D