
Running a marathon is a monumental undertaking. Even though I had been preparing for 1.8 years, it wasn’t until a few weeks ago that I truly grasped the significance of this feat. The turning point came when I made the decision to run for a charity organization in Brazil, specifically Casa da Crianca Paralítica de Campinas (https://www.ccp.org.br/web/). This organization provides vital medical, dental, and pedagogical support to children with physical and mental disabilities in Campinas, Sao Paulo State, Brazil.
Moreover, during my preparations, I delved into the origin of the marathon. It is rooted in the inspiring story of Phidippides, a herald who ran the grueling 26 miles from Marathon to Athens to deliver the news of Greek victory and tragically perished on the spot.
This newfound understanding has deepened my appreciation for the immense challenge and purpose behind running a marathon. It has brought me closer to the cause I am running for and has made the journey even more meaningful.
In addition to the incredible experience itself, I leveraged IoT devices to stay updated on various aspects of my body and speed. These insights were invaluable, and I diligently recorded them in the Strava application. Here are a few highlights of the information I captured:



By capturing the running information, I had the opportunity to download the GPX (Global Positioning XML) files that meticulously recorded GPS waypoints throughout my marathon journey. Leveraging this valuable data, I developed an application capable of visualizing the route on a map, plotting the elevation variation over distance, and providing detailed information at each kilometer. This included data such as latitude, longitude, elevation, and the corresponding time reached. With these features, I was able to gain comprehensive insights into my performance and accurately track my progress throughout the marathon:


One kilometer reached - Kilometer 1 Latitude: 59.346874 Longitude: 18.06763 Elevation: 36.4 Time: 2023-06-03 10:17:09+00:00 <<<-- the marathon starts at 12:00 pm not 10:00 am. One kilometer reached - Kilometer 2 Latitude: 59.342318 Longitude: 18.057401 Elevation: 23.4 Time: 2023-06-03 10:23:22+00:00 One kilometer reached - Kilometer 3 Latitude: 59.334876 Longitude: 18.060889 Elevation: 24.4 Time: 2023-06-03 10:29:20+00:00 One kilometer reached - Kilometer 4 Latitude: 59.336397 Longitude: 18.046855 Elevation: 18.8 Time: 2023-06-03 10:35:31+00:00 One kilometer reached - Kilometer 5 Latitude: 59.337395 Longitude: 18.035086 Elevation: 31.4 Time: 2023-06-03 10:41:54+00:00 One kilometer reached - Kilometer 6 Latitude: 59.333199 Longitude: 18.043528 Elevation: 24.3 Time: 2023-06-03 10:48:04+00:00 One kilometer reached - Kilometer 7 Latitude: 59.326784 Longitude: 18.045059 Elevation: 15.0 Time: 2023-06-03 10:53:49+00:00 One kilometer reached - Kilometer 8 Latitude: 59.328353 Longitude: 18.06119 Elevation: 12.9 Time: 2023-06-03 11:00:01+00:00 One kilometer reached - Kilometer 9 Latitude: 59.322674 Longitude: 18.070649 Elevation: 12.9 Time: 2023-06-03 11:06:16+00:00 One kilometer reached - Kilometer 10 Latitude: 59.328373 Longitude: 18.072838 Elevation: 16.5 Time: 2023-06-03 11:12:27+00:00 One kilometer reached - Kilometer 11 Latitude: 59.331817 Longitude: 18.083543 Elevation: 15.9 Time: 2023-06-03 11:18:42+00:00 One kilometer reached - Kilometer 12 Latitude: 59.336051 Longitude: 18.090822 Elevation: 25.4 Time: 2023-06-03 11:25:09+00:00 One kilometer reached - Kilometer 13 Latitude: 59.340122 Longitude: 18.078659 Elevation: 29.2 Time: 2023-06-03 11:31:55+00:00 One kilometer reached - Kilometer 14 Latitude: 59.341578 Longitude: 18.086899 Elevation: 29.6 Time: 2023-06-03 11:38:38+00:00 One kilometer reached - Kilometer 15 Latitude: 59.337827 Longitude: 18.102701 Elevation: 21.2 Time: 2023-06-03 11:44:44+00:00 One kilometer reached - Kilometer 16 Latitude: 59.33263 Longitude: 18.105322 Elevation: 12.8 Time: 2023-06-03 11:50:54+00:00 One kilometer reached - Kilometer 17 Latitude: 59.333129 Longitude: 18.122436 Elevation: 18.4 Time: 2023-06-03 11:57:20+00:00 One kilometer reached - Kilometer 18 Latitude: 59.328229 Longitude: 18.132758 Elevation: 13.6 Time: 2023-06-03 12:03:34+00:00 One kilometer reached - Kilometer 19 Latitude: 59.323245 Longitude: 18.127401 Elevation: 17.5 Time: 2023-06-03 12:10:17+00:00 One kilometer reached - Kilometer 20 Latitude: 59.322588 Longitude: 18.111348 Elevation: 13.1 Time: 2023-06-03 12:16:22+00:00 One kilometer reached - Kilometer 21 Latitude: 59.325796 Longitude: 18.096353 Elevation: 14.9 Time: 2023-06-03 12:22:42+00:00 One kilometer reached - Kilometer 22 Latitude: 59.331535 Longitude: 18.088168 Elevation: 14.2 Time: 2023-06-03 12:29:39+00:00 One kilometer reached - Kilometer 23 Latitude: 59.330183 Longitude: 18.078932 Elevation: 14.1 Time: 2023-06-03 12:35:48+00:00 One kilometer reached - Kilometer 24 Latitude: 59.324627 Longitude: 18.075818 Elevation: 14.2 Time: 2023-06-03 12:42:14+00:00 One kilometer reached - Kilometer 25 Latitude: 59.318594 Longitude: 18.078732 Elevation: 34.5 Time: 2023-06-03 12:48:42+00:00 One kilometer reached - Kilometer 26 Latitude: 59.314479 Longitude: 18.07504 Elevation: 38.1 Time: 2023-06-03 12:55:00+00:00 One kilometer reached - Kilometer 27 Latitude: 59.312194 Longitude: 18.062026 Elevation: 33.9 Time: 2023-06-03 13:01:16+00:00 One kilometer reached - Kilometer 28 Latitude: 59.31788 Longitude: 18.05432 Elevation: 34.3 Time: 2023-06-03 13:07:36+00:00 One kilometer reached - Kilometer 29 Latitude: 59.318504 Longitude: 18.039661 Elevation: 37.1 Time: 2023-06-03 13:14:52+00:00 One kilometer reached - Kilometer 30 Latitude: 59.323143 Longitude: 18.028996 Elevation: 37.5 Time: 2023-06-03 13:21:26+00:00 One kilometer reached - Kilometer 31 Latitude: 59.330603 Longitude: 18.021492 Elevation: 18.1 Time: 2023-06-03 13:28:05+00:00 One kilometer reached - Kilometer 32 Latitude: 59.327308 Longitude: 18.037927 Elevation: 14.6 Time: 2023-06-03 13:34:36+00:00 One kilometer reached - Kilometer 33 Latitude: 59.332945 Longitude: 18.043762 Elevation: 23.5 Time: 2023-06-03 13:41:15+00:00 One kilometer reached - Kilometer 34 Latitude: 59.337331 Longitude: 18.034871 Elevation: 30.4 Time: 2023-06-03 13:48:42+00:00 One kilometer reached - Kilometer 35 Latitude: 59.336522 Longitude: 18.046515 Elevation: 19.4 Time: 2023-06-03 13:55:52+00:00 One kilometer reached - Kilometer 36 Latitude: 59.331736 Longitude: 18.058298 Elevation: 16.7 Time: 2023-06-03 14:02:25+00:00 One kilometer reached - Kilometer 37 Latitude: 59.324959 Longitude: 18.066619 Elevation: 14.4 Time: 2023-06-03 14:09:49+00:00 One kilometer reached - Kilometer 38 Latitude: 59.325161 Longitude: 18.075494 Elevation: 15.4 Time: 2023-06-03 14:17:22+00:00 One kilometer reached - Kilometer 39 Latitude: 59.332495 Longitude: 18.076794 Elevation: 14.8 Time: 2023-06-03 14:25:01+00:00 One kilometer reached - Kilometer 40 Latitude: 59.332289 Longitude: 18.092964 Elevation: 16.9 Time: 2023-06-03 14:32:28+00:00 One kilometer reached - Kilometer 41 Latitude: 59.338685 Longitude: 18.086357 Elevation: 29.6 Time: 2023-06-03 14:40:18+00:00 One kilometer reached - Kilometer 42 Latitude: 59.343693 Longitude: 18.077884 Elevation: 34.4 Time: 2023-06-03 14:47:47+00:00
The code that generated the aforementioned information and visualizations can be found in its entirety on my GitHub repository. You can access it at the following link: GitHub – Stockholm Marathon 2023. Feel free to explore the code and use it as a reference for your own projects or further analysis of marathon data.
But how can these details be implemented in cloud computing? To address this question, I made the decision to store the data in databases provided by different cloud providers. Specifically, I chose to utilize Oracle Database (or MySQL) on Oracle Cloud Infrastructure (OCI), Amazon RDS (Relational Database Service) on Amazon Web Services (AWS), Cloud SQL (MySQL) on Google Cloud Platform (GCP), and Azure SQL Database on Microsoft Azure.
By leveraging these cloud database solutions, I ensured efficient data storage and management for my marathon-related information. Oracle Database and MySQL, both offering robust capabilities, served as excellent choices for OCI, including Arm Ampere A1 Compute. Additionally, Amazon RDS provided a wide range of database engine options on AWS, GCP’s Cloud SQL supported MySQL and PostgreSQL, and Azure SQL Database emerged as a fully managed service on Microsoft Azure. With these diverse offerings, I could effectively meet my data storage needs across multiple cloud platforms.
With the database services offered by each cloud provider, I was able to securely store and access my marathon data in a scalable and reliable manner. This approach allowed me to fully leverage the unique features and benefits provided by each cloud provider. Below, you can see a visual representation of the usage of OCI through the Autonomous Database Service, as well as the information required to establish connections to the other providers in the code.







To connect to Oracle Cloud Infrastructure (OCI) and create a table named marathon_data2023, I used the following code, which is also available on my GitHub:
# Establish a connection
import cx_Oracle
import os
# Set the environment variable for the wallet location
os.environ["TNS_ADMIN"] = "/Users/brunotechdatabasket/Downloads/Wallet_marathondb"
# Set the TNS entry in tnsnames.ora
with open(os.path.join(os.environ["TNS_ADMIN"], "tnsnames.ora"), "w") as tns_file:
tns_file.write("ORACLEDB =\n"
"(DESCRIPTION =\n"
" (ADDRESS = (PROTOCOL = TCPS)(HOST = adb.eu-stockholm-1.oraclecloud.com)(PORT = 1522))\n"
" (CONNECT_DATA =\n"
" (SERVER = DEDICATED)\n"
" (SERVICE_NAME = g114b7e420dfb56_marathondb_tpurgent.adb.oraclecloud.com)\n"
" )\n"
" (SECURITY =\n"
" (SSL_SERVER_DN_MATCH = YES)\n"
" )\n"
")\n")
# Set the SSL options in sqlnet.ora
with open(os.path.join(os.environ["TNS_ADMIN"], "sqlnet.ora"), "w") as sqlnet_file:
sqlnet_file.write("WALLET_LOCATION =\n"
" (SOURCE =\n"
" (METHOD = FILE)\n"
" (METHOD_DATA =\n"
" (DIRECTORY = /Users/brunotechdatabasket/Downloads/Wallet_marathondb)\n"
" )\n"
" )\n")
# Test the connection using Oracle Wallet Manager
try:
cx_Oracle.connect("/", mode=cx_Oracle.SYSDBA)
print("Wallet connection test successful.")
except cx_Oracle.DatabaseError as e:
print("Error occurred while testing wallet connection:", e)
# Establish a connection
connection = cx_Oracle.connect(
"ADMIN",
"yourpasswordhere",
"ORACLEDB"
)
# Create a cursor
cursor = connection.cursor()
# Create a table (if necessary)
cursor.execute("CREATE TABLE marathon_data2023 (latitude NUMBER, longitude NUMBER, elevation NUMBER, time TIMESTAMP)")
# Insert data into the table
for point in points:
cursor.execute("INSERT INTO marathon_data2023 VALUES (:1, :2, :3, :4)",
(point.latitude, point.longitude, point.elevation, point.time))
# Commit the changes
connection.commit()
# Select data from the table
cursor.execute("SELECT * FROM marathon_data2023")
result = cursor.fetchall()
# Print the selected data
for row in result:
print(row)
# Close the cursor and connection
cursor.close()
connection.close()
As expected, the message ‘Error occurred while testing wallet connection: ORA-12162: TNS:net service name is incorrectly specified’ was displayed. I included this verification step solely for educational purposes to check the utilization of the wallet. In this implementation, I have been connecting via Transport Layer Security (TLS) connections. The output is shown below:

The same implementation is also available for Amazon Web Services (AWS) using Amazon RDS (Relational Database Service), Google Cloud Platform (GCP) using Cloud SQL (MySQL), and Microsoft Azure using Azure SQL Database in the Python file included in the repository. Adopting a multi-cloud strategy offers increased flexibility, scalability, and reliability, enabling organizations to leverage the unique strengths of multiple cloud providers. As mentioned earlier, you can find the implementation codes for each cloud platform in the GitHub repository [2]. I hope this blog post has provided valuable insights into the journey from Stockholm Marathon to a multi-cloud strategy, demonstrating the potential of storing IoT data in cloud computing environments.
References:
[1] Oracle Documentation: “Preparing to Connect to Autonomous Database” – Available at: https://aws.amazon.com/rds/
[2] GitHub Repository: “stockholm_marathon2023” – Available at: https://github.com/brunorsreis/stockholm_marathon2023

The full code content in the file Stockholm_marathon_2023.py follows below:
import gpxpy
import matplotlib.pyplot as plt
# Read the GPX file
gpx_file = open('Stockholm_Marathon_2023.gpx', 'r')
gpx = gpxpy.parse(gpx_file)
# Extract track data
tracks = gpx.tracks
if len(tracks) > 0:
track = tracks[0] # Assuming only one track in the GPX file
segments = track.segments
if len(segments) > 0:
segment = segments[0] # Assuming only one segment in the track
points = segment.points
# Extract latitude, longitude, elevation, and time data
lats = [point.latitude for point in points]
lngs = [point.longitude for point in points]
elevations = [point.elevation for point in points]
times = [point.time for point in points]
# Visualize the data in different ways
# Plotting the elevation profile
#plt.figure(figsize=(10, 5))
#plt.plot(times, elevations)
#plt.xlabel('Time')
#plt.ylabel('Elevation (m)')
#plt.title('Elevation Profile')
#plt.show()
# Plotting the route on a map
plt.figure(figsize=(8, 8))
plt.plot(lngs, lats, color='blue')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.title('Route on Map')
plt.axis('equal')
plt.show()
# Scatter plot of elevation over distance
distances = [point.distance_2d(points[i-1]) if i > 0 else 0 for i, point in enumerate(points)]
plt.figure(figsize=(10, 5))
plt.scatter(distances, elevations, s=5)
plt.xlabel('Distance (m)')
plt.ylabel('Elevation (m)')
plt.title('Elevation Variation over Distance')
plt.show()
else:
print('No segments found in the GPX file.')
else:
print('No tracks found in the GPX file.')
# Display information at each kilometer
total_distance = 0
prev_point = None
kilometer_count = 1
for point in points:
if prev_point is not None:
distance = point.distance_2d(prev_point)
total_distance += distance
if total_distance >= 1000: # Check if the total distance is equal to or greater than 1 kilometer
print("One kilometer reached - Kilometer", kilometer_count)
print("Latitude:", point.latitude)
print("Longitude:", point.longitude)
print("Elevation:", point.elevation)
print("Time:", point.time)
print() # Empty line for separation
total_distance = 0 # Reset the total distance
kilometer_count += 1 # Increment the kilometer count
prev_point = point
import gpxpy
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
# Plot the GPS points
plt.scatter(lngs, lats, c='blue', alpha=0.5)
# Perform clustering for visualization
kmeans = KMeans(n_clusters=5) # Adjust the number of clusters as desired
kmeans.fit(list(zip(lats, lngs)))
# Plot the cluster centers
plt.scatter(kmeans.cluster_centers_[:, 1], kmeans.cluster_centers_[:, 0], c='red', marker='x')
# Display the plot
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.title('Visualization of GPS Points with Cluster Centers')
plt.show()
Establish a connection
import cx_Oracle
import os
# Set the environment variable for the wallet location
os.environ["TNS_ADMIN"] = "/Users/brunotechdatabasket/Downloads/Wallet_marathondb"
# Set the TNS entry in tnsnames.ora
with open(os.path.join(os.environ["TNS_ADMIN"], "tnsnames.ora"), "w") as tns_file:
tns_file.write("ORACLEDB =\n"
"(DESCRIPTION =\n"
" (ADDRESS = (PROTOCOL = TCPS)(HOST = adb.eu-stockholm-1.oraclecloud.com)(PORT = 1522))\n"
" (CONNECT_DATA =\n"
" (SERVER = DEDICATED)\n"
" (SERVICE_NAME = g114b7e420dfb56_marathondb_tpurgent.adb.oraclecloud.com)\n"
" )\n"
" (SECURITY =\n"
" (SSL_SERVER_DN_MATCH = YES)\n"
" )\n"
")\n")
# Set the SSL options in sqlnet.ora
with open(os.path.join(os.environ["TNS_ADMIN"], "sqlnet.ora"), "w") as sqlnet_file:
sqlnet_file.write("WALLET_LOCATION =\n"
" (SOURCE =\n"
" (METHOD = FILE)\n"
" (METHOD_DATA =\n"
" (DIRECTORY = /Users/brunotechdatabasket/Downloads/Wallet_marathondb)\n"
" )\n"
" )\n")
# Test the connection using Oracle Wallet Manager
try:
cx_Oracle.connect("/", mode=cx_Oracle.SYSDBA)
print("Wallet connection test successful.")
except cx_Oracle.DatabaseError as e:
print("Error occurred while testing wallet connection:", e)
# Establish a connection
connection = cx_Oracle.connect(
"ADMIN",
"yourpasswordhere",
"ORACLEDB"
)
# Create a cursor
cursor = connection.cursor()
# Create a table (if necessary)
cursor.execute("CREATE TABLE marathon_data2023 (latitude NUMBER, longitude NUMBER, elevation NUMBER, time TIMESTAMP)")
# Insert data into the table
for point in points:
cursor.execute("INSERT INTO marathon_data2023 VALUES (:1, :2, :3, :4)",
(point.latitude, point.longitude, point.elevation, point.time))
# Commit the changes
connection.commit()
# Select data from the table
cursor.execute("SELECT * FROM marathon_data2023")
result = cursor.fetchall()
# Print the selected data
for row in result:
print(row)
# Close the cursor and connection
cursor.close()
connection.close()
#Connection to Amazon Web Services (AWS) using Amazon RDS (Relational Database Service):
import pymysql
# Establish a connection
connection = pymysql.connect(host='your_host', user='your_user', password='your_password', db='your_database')
# Create a cursor
cursor = connection.cursor()
# Create a table (if necessary)
cursor.execute("CREATE TABLE marathon_data (latitude FLOAT, longitude FLOAT, elevation FLOAT, time TIMESTAMP)")
# Insert data into the table
for point in points:
cursor.execute("INSERT INTO marathon_data VALUES (%s, %s, %s, %s)",
(point.latitude, point.longitude, point.elevation, point.time))
# Commit the changes
connection.commit()
# Close the cursor and connection
cursor.close()
connection.close()
#Connecting to Google Cloud Platform (GCP) using Cloud SQL (MySQL):
from google.cloud import bigquery
# Set up authentication credentials (if required)
# ...
# Establish a connection
client = bigquery.Client()
# Create a dataset (if necessary)
dataset_ref = client.create_dataset('my_dataset')
# Create a table
table_ref = dataset_ref.table('marathon_data')
schema = [
bigquery.SchemaField('latitude', 'FLOAT'),
bigquery.SchemaField('longitude', 'FLOAT'),
bigquery.SchemaField('elevation', 'FLOAT'),
bigquery.SchemaField('time', 'TIMESTAMP'),
]
table = bigquery.Table(table_ref, schema=schema)
table = client.create_table(table)
# Insert data into the table
rows_to_insert = []
for point in points:
rows_to_insert.append({'latitude': point.latitude, 'longitude': point.longitude,
'elevation': point.elevation, 'time': point.time})
client.insert_rows(table, rows_to_insert)
#Microsoft Azure using Azure SQL Database:
import pyodbc
# Establish a connection
connection = pyodbc.connect('Driver={ODBC Driver 17 for SQL Server};Server=your_server;Database=your_database;UID=your_username;PWD=your_password')
# Create a cursor
cursor = connection.cursor()
# Create a table (if necessary)
cursor.execute("CREATE TABLE marathon_data (latitude FLOAT, longitude FLOAT, elevation FLOAT, time DATETIME)")
# Insert data into the table
for point in points:
cursor.execute("INSERT INTO marathon_data VALUES (?, ?, ?, ?)",
(point.latitude, point.longitude, point.elevation, point.time))
# Commit the changes
connection.commit()
# Close the cursor and connection
cursor.close()
connection.close()
[3] Amazon Web Services (AWS) Documentation: “Amazon RDS” – Available at: https://aws.amazon.com/rds/
[4] Microsoft Azure Documentation: “Azure SQL Database” – Available at: https://azure.microsoft.com/services/sql-database/
[5] Google Cloud Platform (GCP) Documentation: “Cloud SQL” – Available at: https://cloud.google.com/sql/
[6] Oracle Cloud Infrastructure (OCI) Sign-In – Available at: https://www.oracle.com/cloud/sign-in.html


*The views expressed here are my own and do not represent those of my employer.*
Hello, I’m Bruno — a dual citizen of Brazil and Sweden. I bring a global perspective shaped by experiences in both South America and Europe, with a strong focus on collaboration and innovation across cultures. I am a Computer Scientist, PhD Candidate in Information and Communication Technologies, focusing on Data Science and Artificial Intelligence, and hold dual Master’s degrees in Data Science and Cybersecurity. With over fifteen years of international experience spanning Brazil, Hungary, and Sweden, I have collaborated with global organizations such as IBM, Playtech, and Oracle, as well as contributed remotely to projects across multiple regions. My professional interests include Databases, Cybersecurity, Cloud Computing, Data Science, Data Engineering, Big Data, Artificial Intelligence, Programming, and Software Engineering, all driven by a deep passion for transforming data into strategic business value.