def news(): '''This function does the api call to the news website and it gets the api key from the config json file, then it returns the json file from the api call''' length = len(current_time_hhmm()) #looping through the time to find the middle (:) for i in range(length): if current_time_hhmm()[i] == ":": start = i + 1 #only getting the news from the api every 15 mins, or when the function is first called if int(current_time_hhmm()[start:]) % 15 == 0 or current_time_hhmm( )[start:] == '' or len(lst) == 0: if len(lst) == 0: lst.append('1') #setting the base url base_url = "https://newsapi.org/v2/top-headlines?" #getting the user key from the config json file with open("./json_files/config.json", "r") as jfile: key = json.load(jfile) key = key["config"] api_key = key[1]['newskey'] #adding these (key an country) to the base url to get the url for an api call complete_url = base_url + "country=gb&apiKey=" + api_key #trying to get the data from the api call, if it can't #it will return failed so that the program can continue try: #making an api call with the requests module and the complete url response = requests.get(complete_url) articles = response.json() #getting the articles from the api call response articles = articles["articles"] #logging that the articles have been retrieved log("articles retrieved -- " + str(requests.get(complete_url))) #returning the list of articles return articles except: #logging and returning that the api calling has errored log('FAILED to get news data from api' + str(requests.get(complete_url))) return [{'title': 'FAILED', 'content': "couldn't get news data"}] else: #opening the json file to read from it with open('./json_files/notifications.json') as jfile: data = json.load(jfile) #getting the notifications from the json file data = data['notifications'][0] log('notifications got from the json file') return data[2:]
def controller(): """Controlls what happens, returns the alarm and the news notifications and so forth.""" alarm_item = request.args.get("alarm_item") if alarm_item != None: for alarm in alarms: if alarm['title'] == alarm_item: alarms.remove(alarm) s.run(blocking=False) alarm_time = request.args.get("alarm") news = get_top_headlines() if alarm_time: #convert alarm_time to a delay alarm_hhmm = alarm_time[-5:-3] + ':' + alarm_time[-2:] delay = hhmm_to_seconds(alarm_hhmm) - hhmm_to_seconds(current_time_hhmm()) weather_input = "" news_input = "" if request.args.get("weather") != None and request.args.get("news") != None: weather_input = get_weather() news_input = get_news_briefing() setalarm("It is: " + alarm_time + " and the weather is: " + weather_input + " Here are your covid news updates: " + news_input) elif request.args.get("weather") != None: weather_input = get_weather() setalarm("It is: " + alarm_time + " and the weather is " + weather_input + " Here are your covid news updates: " + news_input) elif request.args.get("news") != None: news_input = get_news_briefing() setalarm(alarm_time + " " + weather_input + news_input) else: setalarm(alarm_time) s.enter(int(delay), 1, announce, (alarms[-1]['content'],)) return render_template('index.html', title='Daily update', notifications=news, image='alarm-meme.jpg', alarms= alarms)
def controller(): """ Function runs the alarm This function is what is called every time the page refreshes and is the homepage It holds the majority of the functionality of the alarm, with most larger modules running here. Function contains functions that schedules todays alarms and notifications. Sets alarms and removes notifications and alarms """ alarm_time = request.args.get("alarm") s.run( blocking=False ) #allows alarms to be scheduled without freezing the interface if a scheduled event is running logging.info('Page refreshed, running on controller') if current_time_hhmm( ) == '00:00': #set new alarms and notifications at midnight set_todays_alarms() automatic_notifications_remover_appender() if alarm_time: #if an alarm is scheduled set_alarm() if request.args.get( "alarm_item" ): #if an alarm is removed by the user (x in the corner clicked) remove_alarm() if request.args.get( "notif" ): #if a notification is removed by the user (x in the corner clicked) remove_notification() return render_template('index.html', title='Daily update', alarms=alarms, notifications=notifications, image='meme.jpg') #requires
def regular_actions(hour: bool =False, day: bool =False, first_time: bool =False) -> None: ''' Parameters ---------- hour : bool, optional Triggers the make_notifications function and schedules it to be done again in an hour. The default is False. day : bool, optional Triggers the load_alarms_from_log function and schedules it to be done again in a day. The default is False. first_time : bool, optional Trigers both load_alarms_from_log and make_notifications to be run. It schedueles them to be run again at 00:02 and the begining of the hour respectively. The default is False. Returns ------- None This module is for ensuring that the notifications are kept upto date regularly and that every day the relevant alarms are loaded from the log file. It also has a first time flag to complete both these methods on startup.''' if first_time: make_notifications() load_alarms_from_log() delay = time_conversions.hhmm_to_seconds(str(int(time.strftime('%H'))+1) + ':01') - \ time_conversions.hhmm_to_seconds(time_conversions.current_time_hhmm()) - \ int(time.strftime('%S')) scheduler.enter(float(delay), 1, regular_actions, (True,)) delay = (time_conversions.hhmm_to_seconds('23:59') - \ time_conversions.hhmm_to_seconds(time_conversions.current_time_hhmm()) - \ int(time.strftime('%S'))) + 180 scheduler.enter(float(delay), 1, regular_actions, (False, True,)) logging.info( 'make_notifications and load_alarms_from_log have been run for the first time and rescheduled.') elif hour: make_notifications() scheduler.enter(float(reload_notifications), 1, regular_actions, (True,)) logging.info('make_notifications has been run and rescheduled') elif day: load_alarms_from_log() scheduler.enter(float(86400), 1, regular_actions, (False, True)) logging.info('load_alarms_from_log has been run and rescheduled')
def set_an_alarm(alarm_time: str, alarm_title: str, read_news: str, read_weather: str) -> None: ''' Parameters ---------- alarm_time : str The time the alarm should go off. FORMAT: "HH:MM". alarm_title : str The title of the alarm passed through from the HTML form. read_news : str Is equal to 'news' if the news should be read with the alarm. read_weather : str Is equal to 'weather' if the weather should be read with the alarm. Returns ------- None This function creates the user-friendly tile that is displayed in the browser and adds it to the ALARMS list. It checks if the alarm is in the past and if it is ignors the request. If the alarm is the same day in the future it schedules and logs it. If the alarm is in the future and not on the current day it only logs it so that it can be loaded in and scheduled after midnight on the relevant day. ''' global ALARMS global NOTIFICATIONS content = 'This alarm will:<br />Make an announcement' title = alarm_time[:10] + ' - ' + alarm_time[-5:] + ' - ' + alarm_title # Check alarm is today and in the future if date(int(alarm_time[:4]), int(alarm_time[5:7]), int(alarm_time[8:10])) > date.today(): logging.critical([alarm_time, alarm_title, read_news, read_weather]) if read_news: content += '<br />Read the headlines' if read_weather: content += '<br />Read the weather' ALARMS.append({'title':title, \ 'content':Markup(content), \ 'news':read_news, \ 'weather':read_weather, \ 'event':None }) logging.info( 'Alarm %s has been logged for the future and added to ALARMS.', title) elif datetime.datetime(int(alarm_time[:4]), int(alarm_time[5:7]), \ int(alarm_time[8:10]), int(alarm_time[11:13]), \ int(alarm_time[14:])) > datetime.datetime.now(): # Convert alarm_time to a delay alarm_hhmm = alarm_time[-5:-3] + ':' + alarm_time[-2:] delay = time_conversions.hhmm_to_seconds(alarm_hhmm) - \ time_conversions.hhmm_to_seconds(time_conversions.current_time_hhmm()) - \ int(time.strftime('%S')) if read_news: content += '<br />Read the headlines' if read_weather: content += '<br />Read the weather' logging.critical([alarm_time, alarm_title, read_news, read_weather]) ALARMS.append({'title':title, \ 'content':Markup(content), \ 'news':read_news, \ 'weather':read_weather, \ 'event':scheduler.enter(float(delay), 1, \ say_and_remove, \ (title, alarm_title)) }) logging.info( 'Alarm %s has been logged, scheduled and added to ALARMS.', title) else: NOTIFICATIONS.insert(0, {'title':'ALARM TIME NOT POSSIBLE', \ 'content': 'The date and time you choese must be in the future.'}) logging.debug('The user tried to set an alarm in the future %s', title)
def add_alarm(alarm, name, weather, article, covid, pick_news, pick_weather): '''This function adds the alarms inputed to the function to the json file of alarms and or adds it to the scheduler depends on conditions''' #running the scheduler s.run(blocking=False) #setting alarm1 to be the time part of the alarm title alarm1 = alarm[11:] if alarm1: #convert alarm_time to a delay current_time = current_time_hhmm() #working out the delay by subtracting the current time (in seconds)\ #from the time on the alarm (in seconds) delay = hhmm_to_seconds(alarm1) - hhmm_to_seconds(current_time) #setting a new name variable to append to what is in the input\ #and still keep the input var new_name = name #The conditions on whether to manipulate the weather,news & covid\ #depending on whether they were inputted if weather != '' and weather["cod"] == 200: #setting weath to the main attributes of the weather input weath = weather["main"] #getting the tempurature current_temp = weath["temp"] #getting the pressure current_press = weath["pressure"] #getting the humidity current_humid = weath["humidity"] #setting weath to the weather attribute of the weather input weath = weather["weather"] #getting the description from the weather input (from weath) weather_desc = weath[0]["description"] #gettign the wind speed weath = weather["wind"] #concatonating all the variables gathered on weather into one string with\ #more descriptions of them weather = "The temperature outside is "+str(int(current_temp - 273.15))\ + "degrees centigrade; The atmospheric pressure is "\ + str(current_press) + "hectopascals; The humidity is " + str(current_humid) +\ "percent; The wind speed is "+str(weath['speed'])+\ "metres per second; And it is "+str(weather_desc) #adding this to the newname variable new_name = str(new_name) + ". '''''''' " + str(weather) #inputting to the alarm that there is an error if false weather data is added to an alarm elif weather != '' and weather["cod"] != 200: wdic = {'title': weather["cod"], 'content': weather['message']} new_name = str(new_name) + ". '''''''' " + str(wdic) if article != '': #getting the title from the news input article = article[0]['title'] article = str('The top news story is: ') + str(article) #adding this information plus a description to the newname variable new_name = str(new_name) + ". '''''''' " + str(article) if covid != '': covid = 'The local coronavirus infection rates are: ' + str(covid) #adding the information on covid to the newname variable new_name = str(new_name) + ". ''''''' " + str(covid) #setting the details abotu the news alarm from the inputs new_alarm = {"title": alarm, "content": new_name, "pick_news": pick_news,\ "pick_weather": pick_weather} #opening the alarm json file and getting all the alarms from it with open('./json_files/alarms.json') as jfile: data = json.load(jfile) temp = data['alarms'] in_alarms = False if len(temp) != 0: #looping though the alarms json if it isnt empty for i in temp: if i['title'] == alarm: #if the alarm exists that is being added then in alarms is true if not its false in_alarms = True break #appending the json file if that alarm doesnt exist if not in_alarms: # appending data to alarms temp.append(new_alarm) #calling the write function to add the new alarms to the json file write_json(data, alarm) else: log('cannot make alarm as there is already an alarm for this time') return end() #saying the event if it is set for the time now\ #and if the date on the alarm is the same as todays date if alarm[:10] == current_date() and int(delay) == 0: print_job_name(alarm, name, weather, article, covid) #Not adding the alarm if it is set in the past elif alarm[:10] == current_date() and int(delay) < 0: log("alarm " + alarm + " is set in the past") remove_alarm(alarm, True) #only adding an item to the scheduler if it has less than 60 seconds\ #and if the date on the alarm is the same as todays date elif alarm[:10] == current_date() and 0 < int(delay) < 61: lst.append( s.enter(int(delay), 1, print_job_name, [ alarm, name, weather, article, covid, ])) #logging that the alarm has been added to the scheduler log("alarm " + alarm + " added to the scheduler") return end() #returning end if there is nothing to do return end()
def org_func(covid, weather, articles): '''This function takes in the 3 dictionsaries covid, weather & articles and then it formats them and returns them in one list''' length = len(current_time_hhmm()) for i in range(length): if current_time_hhmm()[i] == ":": start = i + 1 #refreshing the seen file so it doesn't contain irrelevent info, and because by ever hour\ #normally all of the nes has been updated and the data in the seen file is different to the\ #new nes anyway if current_time_hhmm()[start:] == '': with open('./json_files/seen.json', 'w') as jfile: json.dump({'notifications': []}, jfile, indent=4) #this wil update the notifications collumn every 15 mins or when the function is first called if int(current_time_hhmm()[start:]) % 15 == 0 or current_time_hhmm( )[start:] == '' or len(lst) == 0: #updating the list if it is the first time the function is called if len(lst) == 0: lst.append('1') length = len(articles) i = 0 #this will loop through every item (article) in articles #if the api call didn't fail if articles[0]['title'] != 'FAILED': while i < length: #adding the url of the website in the article to the content variable as\ #markup so it can be displayed on the website (with html) content = Markup( ("<a href='%s'target='_blank'>click_here</a>" % (articles[i]['url']))) #then adding this to the content of the spcific article articles[i]['content'] = str( articles[i]['description']) + ' ------ ' + content i += 1 #setting the covid input to be added as a dictionary dic = { 'title': 'Daily local covid infection rates', 'content': str(covid), 'url': '' } #adding this dictionary to articles articles.insert(0, dic) #chekcing if there has been weather data inputted and that there hasn't been an error if weather != [] and weather["cod"] == 200: #setting weath to the main attributes of the weather input weath = weather["main"] #getting the tempurature current_temp = weath["temp"] #getting the pressure current_press = weath["pressure"] #getting the humidity current_humid = weath["humidity"] #setting weath to the weather attribute of the weather input weath = weather["weather"] #getting the description from the weather input (from weath) weather_desc = weath[0]["description"] #getting the wind speed weath = weather["wind"] #concatonating all the variables gathered on weather into one string with\ #more descriptions of them description = "The temperature outside is "+str(int(current_temp - 273.15))\ + " degrees centigrade; The atmospheric pressure is "\ + str(current_press) + "hPa; The humidity is " + str(current_humid) +\ "%; The wind speed is "+str(weath['speed'])+"m/s; And it is "+\ str(weather_desc) #putting this description into a dictionary with the other informaiont about weather wdic = { 'title': 'Weather in Exeter', 'content': description, 'url': '' } #adding this dictionary to articles articles.insert(1, wdic) #adding to articles that there has been an error with the api call elif weather != [] and weather["cod"] != 200: wdic = { 'title': weather["cod"], 'content': weather['message'], 'url': '' } articles.insert(1, wdic) #logging that the inputs have been organised into notifications log("notifications organised") data = {'notifications': [articles]} #calling the write function to add the new notifications to the json file write_json(data) #opening the json file to read from it with open('./json_files/notifications.json') as jfile: data = json.load(jfile) #getting the notifications from the json file data = data['notifications'][0] log('notifications from json file returned') #looping through the json file and adding the urls as links length = len(data) if data[2]['title'] != 'FAILED': for i in range(length): if data[i]['url']: #adding the url of the website in the article to the content variable as\ #markup so it can be displayed on the website (with html) content = Markup( ("<a href='%s'target='_blank'>click_here</a>" % (data[i]['url']))) #then adding this to the content of the spcific article data[i]['content'] = str( data[i]['description']) + ' ------ ' + content notifications = [] #getting the seen notifications file with open('./json_files/seen.json') as jfil: seen = json.load(jfil) #getting the notificatios from the json file seen = seen['notifications'] for i in data: if i not in seen: notifications.append(i) #returning the notifications in the json file return notifications
def set_alarm(): """This function sets alarms It first checks whether the alarm has been set in the past. Which will cause it to log the alarm as in the past but will not append it. It then sets the alarm if it is set for today and if it is not it will add it to a list. Each day this list is checked and if the date on the alarm matches the date of the current day the alarm will be set for that day. When an alarm is set for today or added to a list to be set in the future, it will add an alarm on the left hand side of the interface with the title and the time that it will trigger. """ alarm_time = request.args.get("alarm") alarm_hhmm = alarm_time[-5:-3] + ':' + alarm_time[-2:] if full_date.year > int(alarm_time[0:4]) or full_date.month > int( alarm_time[5:7]) or full_date.day > int(alarm_time[8:10]): return logging.info('Alarm is in the past') if full_date.year == int(alarm_time[0:4]) and full_date.month == int( alarm_time[5:7]) and full_date.day == int(alarm_time[8:10]): if hhmm_to_seconds(alarm_hhmm) < hhmm_to_seconds(current_time_hhmm()): logging.info('Alarm is in the past') return render_template('index.html', title='Daily update', alarms=alarms, notifications=notifications, image='meme.jpg') delay = hhmm_to_seconds(alarm_hhmm) - hhmm_to_seconds( current_time_hhmm()) date = alarm_time[0:10] events.append({ "date": date, "delay": delay, "event_title": request.args.get("two"), "time": alarm_hhmm }) alarms.append({ "title": request.args.get("two"), "content": 'Will be updated on announcement ( ' + alarm_time[0:10] + ' ' + alarm_time[12:] + ' )in order to provide relevant information' }) #changed from alarm content events_list.append({ "title": request.args.get("two"), "content": s.enter(int(delay), 1, alarm_runner, (alarm_content(), request.args.get("two"))) }) logging.info('Alarm set for today at ' + alarm_time) return render_template('index.html', title='Daily update', alarms=alarms, notifications=notifications, image='meme.jpg') delay = hhmm_to_seconds(alarm_hhmm) - hhmm_to_seconds(current_time_hhmm()) date = alarm_time[0:10] events.append({ "date": date, "delay": delay, "title": request.args.get("two"), "time": alarm_hhmm }) alarms.append({ "title": request.args.get("two"), "content": 'Will be updated on announcement ( ' + alarm_time[0:10] + ' ' + alarm_time[12:] + ' )in order to provide relevant information' }) logging.info('Alarm set for ' + alarm_time + 'future date, will be scheduled on the date') return render_template('index.html', title='Daily update', alarms=alarms, notifications=notifications, image='meme.jpg')