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