From 9e739f6cd75e84208e9cac9ef3590511ecae3e33 Mon Sep 17 00:00:00 2001 From: Stratos Thivaios <stratosthivaios@outlook.com.gr> Date: Sun, 21 Apr 2024 19:09:27 +0300 Subject: [PATCH] initial commit --- Docker/api.py | 2 +- Docker/docker-compose.yaml | 2 +- {API => backend}/api.py | 195 +++++++++---------- {API => backend}/requirements.txt | 2 +- backend/static/templates/air_quality.xml | 11 ++ backend/static/templates/cisco.xml | 20 ++ backend/static/templates/environmental.xml | 12 ++ backend/static/templates/games.xml | 8 + backend/static/templates/geocode_aqi.xml | 10 + backend/static/templates/geocode_weather.xml | 10 + backend/static/templates/get_stock.xml | 10 + backend/static/templates/info.xml | 34 ++++ backend/static/templates/no_results.xml | 7 + backend/static/templates/rps.xml | 25 +++ backend/static/templates/rps_out.xml | 13 ++ backend/static/templates/scr-off.xml | 4 + backend/static/templates/stock_value.xml | 9 + backend/static/templates/weather.xml | 14 ++ 18 files changed, 277 insertions(+), 111 deletions(-) rename {API => backend}/api.py (62%) rename {API => backend}/requirements.txt (89%) create mode 100644 backend/static/templates/air_quality.xml create mode 100644 backend/static/templates/cisco.xml create mode 100644 backend/static/templates/environmental.xml create mode 100644 backend/static/templates/games.xml create mode 100644 backend/static/templates/geocode_aqi.xml create mode 100644 backend/static/templates/geocode_weather.xml create mode 100644 backend/static/templates/get_stock.xml create mode 100644 backend/static/templates/info.xml create mode 100644 backend/static/templates/no_results.xml create mode 100644 backend/static/templates/rps.xml create mode 100644 backend/static/templates/rps_out.xml create mode 100644 backend/static/templates/scr-off.xml create mode 100644 backend/static/templates/stock_value.xml create mode 100644 backend/static/templates/weather.xml diff --git a/Docker/api.py b/Docker/api.py index c8e86e2..74ea69d 100644 --- a/Docker/api.py +++ b/Docker/api.py @@ -172,7 +172,7 @@ def weather(): region = request.args.get("region").replace("_", " ") country = request.args.get("country") - # Setup the Open-Meteo API client with cache and retry on error + # Setup the Open-Meteo backend client with cache and retry on error cache_session = requests_cache.CachedSession('.cache', expire_after = 3600) retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2) openmeteo = openmeteo_requests.Client(session = retry_session) diff --git a/Docker/docker-compose.yaml b/Docker/docker-compose.yaml index 64f2808..5219926 100644 --- a/Docker/docker-compose.yaml +++ b/Docker/docker-compose.yaml @@ -8,4 +8,4 @@ services: environment: - stocks_api_key="YOUR_ALPHAVANTAGE_API_KEY_HERE" - api_hostname="YOUR_IP_OR_DOMAIN_THAT_THE_API_IS_HOSTED_ON" - # the variable above can either be an IP or a domain. it CANNOT be changed later. Keep in mind that the API listens on port 80. \ No newline at end of file + # the variable above can either be an IP or a domain. it CANNOT be changed later. Keep in mind that the backend listens on port 80. \ No newline at end of file diff --git a/API/api.py b/backend/api.py similarity index 62% rename from API/api.py rename to backend/api.py index c8e86e2..81aabe9 100644 --- a/API/api.py +++ b/backend/api.py @@ -1,53 +1,82 @@ -from flask import Flask, request, jsonify, Response +from datetime import datetime +from flask import Flask, request, Response, render_template import requests import random -# import ast import openmeteo_requests import requests_cache -import pandas as pd -import time from retry_requests import retry from unidecode import unidecode -import os -app = Flask(__name__) +app = Flask(__name__, template_folder="./static/templates/") -apisrv = 236 -stock_apikey = os.environ.get("stocks_api_key") -api_hostname = os.environ.get("api_hostname") +stock_apikey = "Your Alphavantage backend key here" +api_hostname = "192.168.1.156" # the ip address or domain of the server +fullHostname = "http://192.168.1.156" # the full hostname, with the http:// or https:// in front + +@app.route("/homepage/") +def homepage(): + code = render_template("cisco.xml", hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/scrOff/") +def scrOff(): + code = render_template("scr-off.xml") + return Response(code, mimetype='text/xml') + +@app.route("/getStock/") +def getStock(): + code = render_template("get_stock.xml", hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getWeather/") +def getWeather(): + code = render_template("geocode_weather.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/info/") +def getInfo(): + code = render_template("info.xml") + return Response(code, mimetype='text/xml') + +@app.route("/playRps/") +def playRps(): + code = render_template("rps.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getAqi/") +def getAqi(): + code = render_template("geocode_aqi.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getGamesList/") +def getGamesList(): + code = render_template("games.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getEnvApps/") +def getEnvApps(): + code = render_template("environmental.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +# backend calls @app.route("/stock-price/") def get_stock(): nsymb = request.args.get("symbol") out = requests.get(f"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={nsymb}&apikey={stock_apikey}") out = out.json() - # out = "{'Global Quote': {'01. symbol': 'MSFT', '02. open': '371.0400', '03. high': '371.9500', '04. low': '367.3454', '05. price': '370.2700', '06. volume': '26816841', '07. latest trading day': '2023-11-14', '08. previous close': '366.6800', '09. change': '-3.5900', '10. change percent': '0.9791%'}}" - # out = ast.literal_eval(out) - # print(out) - price = round(float(out['Global Quote']['05. price']),2) - change = round(float(out['Global Quote']['09. change']),2) + price = round(float(out['Global Quote']['05. price']), 2) + change = round(float(out['Global Quote']['09. change']), 2) change_percent = out['Global Quote']['10. change percent'] - # print(type(price)) - - # print(price) if change > 0: up_or_down = "UP ^" else: up_or_down = "DOWN" - output = f"<CiscoIPPhoneText>\n" - output += f"<Title>Stock value for {nsymb.upper()}</Title>\n" - output += f"<Text>\n" - output += f"Symbol : {nsymb.upper()}\n" - output += f"Value : {price}$\n" - output += f"Change : {change}$ ({up_or_down})\n" - output += f"Change (%) : {change_percent}\n" - output += f"</Text>\n" - output += f"</CiscoIPPhoneText>" - - return Response(output, mimetype='text/xml') - + sResp = render_template("stock_value.xml", symbol=nsymb.upper(), price=price, + change=change, up_or_down=up_or_down, change_percent=change_percent) + return Response(sResp, mimetype='text/xml') @app.route("/geocode-aqi/") def geocode_aqi(): @@ -58,8 +87,7 @@ def geocode_aqi(): print(out) cities_data = out['results'] city_info_list = [{'name': city['name'], 'admin1': city.get('admin1', ''), 'latitude': city['latitude'], - 'longitude': city['longitude'], 'country_code': city['country_code']} for city in cities_data] - + 'longitude': city['longitude'], 'country_code': city['country_code']} for city in cities_data] # Print the result for city_info in city_info_list: @@ -82,15 +110,9 @@ def geocode_aqi(): return Response(output, mimetype='text/xml') except: - output = f"<CiscoIPPhoneText>\n" - output += f"<Title>No results were found</Title>\n" - output += f"<Text>\n" - output += f"No results could be returned for your search.\nPerhaps you made a typo?</Text>\n" - output += f"</CiscoIPPhoneText>\n" - return Response(output, mimetype='text/xml') + return Response(render_template("no_results.xml"), mimetype='text/xml') # return out, 200 - @app.route("/geocode-weather/") def geocode_weather(): try: @@ -123,15 +145,9 @@ def geocode_weather(): return Response(output, mimetype='text/xml') except: - output = f"<CiscoIPPhoneText>\n" - output += f"<Title>No results were found</Title>\n" - output += f"<Text>\n" - output += f"No results could be returned for your search.\nPerhaps you made a typo?</Text>\n" - output += f"</CiscoIPPhoneText>\n" - return Response(output, mimetype='text/xml') + return Response(render_template("no_results.xml"), mimetype='text/xml') # return out, 200 - @app.route("/air-quality/") def get_air_quality(): latitude = float(request.args.get("latitude")) @@ -143,27 +159,17 @@ def get_air_quality(): out = out.json() print(out) current = out['current'] - dust = current['dust'] air_quality = current['us_aqi'] + date = (f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day} ' + + f'{datetime.now().hour}:{datetime.now().minute}:{datetime.now().second}') - print(dust) - print(air_quality) - - output = f"<CiscoIPPhoneText>\n" - output += f"<Title>Air Quality</Title>\n" - output += f"<Text>\n" - output += f"{name}, {region}, {country}\n\n" - output += f"Dust : {dust}\n" - output += f"Air Quality (US AQI) : {air_quality}" - output += f"</Text>\n" - output += f"</CiscoIPPhoneText>" + aqResp = render_template("air_quality.xml", city=name, region=region, country=country, + dust=dust, air_quality=air_quality, last_update=date) - - return Response(output, mimetype='text/xml') + return Response(aqResp, mimetype='text/xml') # return out, 200 - @app.route("/weather/") def weather(): latitude = float(request.args.get("latitude")) @@ -171,13 +177,11 @@ def weather(): name = request.args.get("name").replace("_", " ") region = request.args.get("region").replace("_", " ") country = request.args.get("country") - - # Setup the Open-Meteo API client with cache and retry on error + # Setup the Open-Meteo backend client with cache and retry on error cache_session = requests_cache.CachedSession('.cache', expire_after = 3600) retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2) openmeteo = openmeteo_requests.Client(session = retry_session) - - # Make sure all required weather variables are listed here + # Make sure all required weather variables are listed here # The order of variables in hourly or daily is important to assign them correctly below url = "https://api.open-meteo.com/v1/forecast" params = { @@ -197,70 +201,45 @@ def weather(): current_wind_speed_10m = current.Variables(2).Value() current_wind_gusts_10m = current.Variables(3).Value() current_relative_humidity_2m = current.Variables(4).Value() + date = (f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day} '+ + f'{datetime.now().hour}:{datetime.now().minute}:{datetime.now().second}') + wResp = render_template("weather.xml", city=name, region=region, country=country, + temperature=round(current_temperature_2m, 2), precipitation=current_precipitation, + w_speed=round(current_wind_speed_10m, 2), wg_speed=round(current_wind_gusts_10m, 2), + humidity=round(current_relative_humidity_2m, 2), last_update=date) - xml = f"<CiscoIPPhoneText>\n" - xml += "<Title>Current Weather</Title>\n" - xml += "<Text>\n" - xml += f"{name}, {region}, {country}\n\n" - xml += f"Temperature : {round(current_temperature_2m, 2)}C\n" - xml += f"Precipitation : {current_precipitation}mm\n" - xml += f"Wind speed : {round(current_wind_speed_10m, 2)}m/s\n" - xml += f"Wind gusts : {round(current_wind_gusts_10m, 2)}m/s\n" - xml += f"Humidity : {round(current_relative_humidity_2m, 2)}%" - xml += f"</Text>\n" - xml += f"</CiscoIPPhoneText>" - - return Response(xml, mimetype='text/xml') - + return Response(wResp, mimetype='text/xml') @app.route("/rps/") def rock_paper_scissors(): user_input = request.args.get("user_input") global computer - possible = ['rock','paper','scissors'] computer = random.choice(possible) - print(computer) if user_input == 'rock' and computer == 'paper': - output = f"{computer}\n" - output += "You loose!" - return output, 200 + lWin = "You loose!" elif user_input == 'rock' and computer == 'scissors': - output = f"{computer}\n" - output += "You win!" - return output, 200 + lWin = "You win!" elif user_input == 'rock' and computer == 'rock': - output = f"{computer}\n" - output += "Tie" - return output, 200 + lWin = "Tie" elif user_input == 'paper' and computer == 'rock': - output = f"{computer}\n" - output += "You win!" - return output, 200 + lWin = "You win!" elif user_input == 'paper' and computer == 'scissors': - output = f"{computer}\n" - output += "You loose!" - return output, 200 + lWin = "You loose!" elif user_input == 'paper' and computer == 'paper': - output = f"{computer}\n" - output += "Tie" - return output, 200 + lWin = "Tie" elif user_input == 'scissors' and computer == 'rock': - output = f"{computer}\n" - output += "You loose!" - return output, 200 + lWin = "You loose!" elif user_input == 'scissors' and computer == 'paper': - output = f"{computer}\n" - output += "You win" - return output, 200 + lWin = "You win" if user_input == 'scissors' and computer == 'scissors': - output = f"{computer}\n" - output += "Tie" - return output, 200 + lWin = "Tie" + + rpsResp = render_template("rps_out.xml", computer=computer.capitalize(), result=lWin, hostname=fullHostname) - return 'knag', 200 + return Response(rpsResp, mimetype='text/xml') diff --git a/API/requirements.txt b/backend/requirements.txt similarity index 89% rename from API/requirements.txt rename to backend/requirements.txt index ef4548a..a5f32b6 100644 --- a/API/requirements.txt +++ b/backend/requirements.txt @@ -1,7 +1,7 @@ flask +datetime requests openmeteo_requests requests_cache -pandas retry_requests unidecode \ No newline at end of file diff --git a/backend/static/templates/air_quality.xml b/backend/static/templates/air_quality.xml new file mode 100644 index 0000000..963a9ae --- /dev/null +++ b/backend/static/templates/air_quality.xml @@ -0,0 +1,11 @@ +<CiscoIPPhoneText> +<Title>Current Air Quality</Title> +<Text> +{{city}}, {{region}}, {{country}} + +Dust : {{dust}} +Air Quality (US AQI) : {{air_quality}} + +Last Updated : {{last_update}} +</Text> +</CiscoIPPhoneText> \ No newline at end of file diff --git a/backend/static/templates/cisco.xml b/backend/static/templates/cisco.xml new file mode 100644 index 0000000..5c51820 --- /dev/null +++ b/backend/static/templates/cisco.xml @@ -0,0 +1,20 @@ +<CiscoIPPhoneMenu> + <Title>CISCAPPS Suite</Title> + <Prompt>Welcome! Select an application :</Prompt> + <MenuItem> + <Name>Environmental</Name> + <URL>{{hostname}}/getEnvApps/</URL> + </MenuItem> + <MenuItem> + <Name>Stock</Name> + <URL>{{hostname}}/getStock/</URL> + </MenuItem> + <MenuItem> + <Name>Games</Name> + <URL>{{hostname}}/getGamesList/</URL> + </MenuItem> + <MenuItem> + <Name>Turn screen off</Name> + <URL>{{hostname}}/scrOff/</URL> + </MenuItem> +</CiscoIPPhoneMenu> \ No newline at end of file diff --git a/backend/static/templates/environmental.xml b/backend/static/templates/environmental.xml new file mode 100644 index 0000000..6b93302 --- /dev/null +++ b/backend/static/templates/environmental.xml @@ -0,0 +1,12 @@ +<CiscoIPPhoneMenu> + <Title>CISCAPPS Weather Apps</Title> + <Prompt>Select an app :</Prompt> + <MenuItem> + <Name>Weather</Name> + <URL>{{hostname}}/getWeather/</URL> + </MenuItem> + <MenuItem> + <Name>Air Quality</Name> + <URL>{{hostname}}/getAqi/</URL> + </MenuItem> +</CiscoIPPhoneMenu> \ No newline at end of file diff --git a/backend/static/templates/games.xml b/backend/static/templates/games.xml new file mode 100644 index 0000000..0831b71 --- /dev/null +++ b/backend/static/templates/games.xml @@ -0,0 +1,8 @@ +<CiscoIPPhoneMenu> + <Title>CISCAPPS Games</Title> + <Prompt>Select a game :</Prompt> + <MenuItem> + <Name>Rock, Paper, Scissors</Name> + <URL>{{hostname}}/playRps/</URL> + </MenuItem> +</CiscoIPPhoneMenu> \ No newline at end of file diff --git a/backend/static/templates/geocode_aqi.xml b/backend/static/templates/geocode_aqi.xml new file mode 100644 index 0000000..c5495fb --- /dev/null +++ b/backend/static/templates/geocode_aqi.xml @@ -0,0 +1,10 @@ +<CiscoIPPhoneInput> + <Title>CISCAPPS Air Quality</Title> + <Prompt>Search for a city/area :</Prompt> + <URL>{{hostname}}/geocode-aqi/</URL> + <InputItem> + <DisplayName>Search </DisplayName> + <QueryStringParam>name</QueryStringParam> + <InputFlags>A</InputFlags> + </InputItem> +</CiscoIPPhoneInput> \ No newline at end of file diff --git a/backend/static/templates/geocode_weather.xml b/backend/static/templates/geocode_weather.xml new file mode 100644 index 0000000..5b84fb1 --- /dev/null +++ b/backend/static/templates/geocode_weather.xml @@ -0,0 +1,10 @@ +<CiscoIPPhoneInput> + <Title>CISCAPPS Weather</Title> + <Prompt>Search for a city/area :</Prompt> + <URL>{{hostname}}/geocode-weather/</URL> + <InputItem> + <DisplayName>Search </DisplayName> + <QueryStringParam>name</QueryStringParam> + <InputFlags>A</InputFlags> + </InputItem> +</CiscoIPPhoneInput> \ No newline at end of file diff --git a/backend/static/templates/get_stock.xml b/backend/static/templates/get_stock.xml new file mode 100644 index 0000000..32f9f4f --- /dev/null +++ b/backend/static/templates/get_stock.xml @@ -0,0 +1,10 @@ +<CiscoIPPhoneInput> + <Title>Get stock value</Title> + <Prompt>Enter the stock symbol :</Prompt> + <URL>{{hostname}}/stock-price/</URL> + <InputItem> + <DisplayName>Symbol (eg. MSFT)</DisplayName> + <QueryStringParam>symbol</QueryStringParam> + <InputFlags>A</InputFlags> + </InputItem> +</CiscoIPPhoneInput> \ No newline at end of file diff --git a/backend/static/templates/info.xml b/backend/static/templates/info.xml new file mode 100644 index 0000000..6ca5b03 --- /dev/null +++ b/backend/static/templates/info.xml @@ -0,0 +1,34 @@ +<CiscoIPPhoneText> + <Title>Cisco Help - KIOYDIOLABS.ORG</Title> + <Text> +Service Help +---------------- +The "School Schedule" service allows users to view the school schedule for the next day. + +The "CCTV" service allows users to view the latest frame of all CCTV cameras. + +The "Phonebooks" service provides multiple phonebooks each helpful for something specific. + + +For technical support with your Cisco IP Phone please dial the internal Cisco Support Hotline at 2075 or press "Support" below. + + +Press "Exit" to get to your home screen. + </Text> + + <SoftKeyItem> + <Name>Update</Name> + <URL>SoftKey:Update</URL> + <Position>4</Position> + </SoftKeyItem> + <SoftKeyItem> + <Name>Exit</Name> + <URL>SoftKey:Exit</URL> + <Position>3</Position> + </SoftKeyItem> + <SoftKeyItem> + <Name>Support</Name> + <URL>Dial:2075</URL> + <Position>1</Position> + </SoftKeyItem> +</CiscoIPPhoneText> \ No newline at end of file diff --git a/backend/static/templates/no_results.xml b/backend/static/templates/no_results.xml new file mode 100644 index 0000000..27b60f2 --- /dev/null +++ b/backend/static/templates/no_results.xml @@ -0,0 +1,7 @@ +<CiscoIPPhoneText> +<Title>No results were found</Title> +<Text> +No results could be returned for your search. +Perhaps you made a typo? +</Text> +</CiscoIPPhoneText> \ No newline at end of file diff --git a/backend/static/templates/rps.xml b/backend/static/templates/rps.xml new file mode 100644 index 0000000..bb604bc --- /dev/null +++ b/backend/static/templates/rps.xml @@ -0,0 +1,25 @@ +<CiscoIPPhoneText> +<Title>Rock Paper Scissors</Title> +<Prompt>Rock, paper, scissors, shoot!</Prompt> +<Text></Text> +<SoftKeyItem> + <Name>Rock</Name> + <URL>{{hostname}}/rps/?user_input=rock</URL> + <Position>1</Position> +</SoftKeyItem> +<SoftKeyItem> + <Name>Paper</Name> + <URL>{{hostname}}/rps/?user_input=paper</URL> + <Position>2</Position> +</SoftKeyItem> +<SoftKeyItem> + <Name>Scissors</Name> + <URL>{{hostname}}/rps/?user_input=scissors</URL> + <Position>3</Position> +</SoftKeyItem> +<SoftKeyItem> + <Name>Exit :(</Name> + <URL>Init:Services</URL> + <Position>4</Position> +</SoftKeyItem> +</CiscoIPPhoneText> \ No newline at end of file diff --git a/backend/static/templates/rps_out.xml b/backend/static/templates/rps_out.xml new file mode 100644 index 0000000..854a3c3 --- /dev/null +++ b/backend/static/templates/rps_out.xml @@ -0,0 +1,13 @@ +<CiscoIPPhoneText> +<Title>Rock, Paper, Scissors</Title> +<Text> +Phone's Choice : {{computer}} + +{{result}} +</Text> +<SoftKeyItem> + <Name>Play again</Name> + <URL>{{hostname}}/playRps/</URL> + <Position>1</Position> +</SoftKeyItem> +</CiscoIPPhoneText> \ No newline at end of file diff --git a/backend/static/templates/scr-off.xml b/backend/static/templates/scr-off.xml new file mode 100644 index 0000000..c506f31 --- /dev/null +++ b/backend/static/templates/scr-off.xml @@ -0,0 +1,4 @@ +<CiscoIPPhoneExecute> +<ExecuteItem URL="Display:Off:0"/> +<ExecuteItem URL="Init:Services"/> +</CiscoIPPhoneExecute> \ No newline at end of file diff --git a/backend/static/templates/stock_value.xml b/backend/static/templates/stock_value.xml new file mode 100644 index 0000000..35e6bb2 --- /dev/null +++ b/backend/static/templates/stock_value.xml @@ -0,0 +1,9 @@ +<CiscoIPPhoneText> +<Title>Stock value for {{symbol}}</Title> +<Text> +Symbol : {{symbol}} +Value : {{price}}$ +Change : {{change}}$ ({{up_or_down}}) +Change (%) : {{change_percent}} +</Text> +</CiscoIPPhoneText> \ No newline at end of file diff --git a/backend/static/templates/weather.xml b/backend/static/templates/weather.xml new file mode 100644 index 0000000..e857140 --- /dev/null +++ b/backend/static/templates/weather.xml @@ -0,0 +1,14 @@ +<CiscoIPPhoneText> +<Title>Current Weather</Title> +<Text> +{{city}}, {{region}}, {{country}} + +Temperature : {{temperature}}C +Precipitation : {{precipitation}}mm +Wind speed : {{w_speed}}m/s +Wind gusts : {{wg_speed}}m/s +Humidity : {{humidity}}% + +Last Updated : {{last_update}} +</Text> +</CiscoIPPhoneText> \ No newline at end of file