Traffic Sentinel: IoT Solution for Intelligent Road Surveillance and Monitoring
In the current era, traffic monitoring has become an increasingly challenging task in our cities. It is in this context that Traffic Sentinel emerges as a project proposing an architecture for efficient information flow management and decision-making. This conceptual project presents a robust architectural approach capable of being implemented in a real solution to address traffic and safety issues on our roads.
Managing traffic in today’s cities is no easy task. This is where Traffic Sentinel steps in — it’s more than just a project; it’s a potential solution to handle traffic smarter and safer. This conceptual plan offers a robust approach that, although a proof-of-concept, holds the potential to evolve into a practical solution addressing traffic and safety issues on our roads.
Traffic Sentinel isn’t merely theoretical; it’s a concept with practical implications. It presents an architectural framework designed to tackle the complexities of traffic management, aiming to revolutionize how we handle traffic challenges. This forward-thinking initiative isn’t just a theory; it’s a blueprint ready to evolve into a real-world solution.
Amidst the complexities of urban traffic, Traffic Sentinel emerges as a practical idea. With its adaptability and potential for practical implementation, Traffic Sentinel aims to pave the way for safer roads.
Are you eager to delve into the design details of Traffic Sentinel? Join me on this fascinating journey to explore how this innovative system has been crafted!
Alternatively, you can directly access the Github repository by following this link.
Empowering Smarter Roads: Essential Functionalities of Traffic Sentinel
Traffic Sentinel is designed with a comprehensive set of features aimed at revolutionizing traffic monitoring and management. These key functionalities ensure efficient data processing, real-time insights, and enhanced decision-making capabilities within the system.
Real-Time Vehicle Detection and Tracking
Using advanced machine learning models like YOLO (You Only Look Once), Traffic Sentinel offers real-time detection and continuous tracking of vehicles from live video streams. This enables instantaneous identification and ongoing monitoring of vehicles on the monitored roads, enhancing situational awareness.
Vehicle Speed Monitoring
The system performs precise speed analysis, allowing identification and logging of vehicles that surpass predetermined speed limits. This functionality contributes significantly to improving road safety by identifying speed limit violations in real time.
Efficient Data Processing with Apache Flink
Leveraging Apache Flink for real-time data processing, Traffic Sentinel captures crucial details such as vehicle speed, enabling swift identification of speed limit violators. This feature is pivotal in promptly addressing speeding incidents and ensuring effective traffic management.
Data Movement Orchestration with Apache NiFi
Apache NiFi orchestrates seamless data movement across different components of the IoT system. It integrates MQTT with Kafka, optimizing the flow of data between Fog nodes, processing layers, and storage systems, ensuring efficient traffic analysis.
Robust and Secure Data Storage
Using MongoDB and Redis, Traffic Sentinel stores processed data, manages IoT cameras, user information, and critical system credentials securely. The use of Vault by HashiCorp further fortifies data security by managing and safeguarding sensitive information.
Flask Services for Management and Authentication
The Flask-based services within the Data Services Layer ensure secure user authentication, camera management, and controlled access provisioning to Fog nodes. These services encapsulate critical business logic, ensuring data integrity, and controlled access to system functionalities.
Navigating the Traffic Sentinel Framework: A Comprehensive Architecture Exploration
Traffic Sentinel operates on a multi-layered framework that merges various technologies for effective and scalable traffic management. Each layer has a specific function, working together seamlessly to ensure efficient traffic monitoring without delving into technical specifics. These layers collectively form the backbone of Traffic Sentinel, enabling its smart and agile functionality:
- Fog Stream Processing Layer: This layer acts as an intermediary between IoT devices, such as IP cameras deployed on roads, and the cloud. It serves as an intermediate layer implementing security protocols and ensuring a continuous and efficient flow of information to the cloud using the MQTT protocol. Each Fog node must securely authenticate via the CHAP protocol to validate the information published by the node. Each node is provisioned with information about the IP camera to which it must connect and manage its video streaming.
- Data Orchestration Layer with Apache NiFi: Apache NiFi is the chosen ETL technology for data movement and orchestration among different layers. It plays a fundamental role in facilitating large-scale data movement. It integrates MQTT with Kafka, thereby optimizing data transfer between different components of the architecture.
- Real-time Processing Layer with Apache Flink: This layer, based on Apache Flink, constitutes the heart of Traffic Sentinel. Real-time analysis of video streams from traffic cameras occurs here. Through the use of vehicle detection algorithms like YOLO (You Only Look Once), vehicles are continuously identified and tracked. This real-time processing is crucial for detecting traffic patterns, speed limit violations, and irregular behaviors on roads.
- Data Storage Layer: Using MongoDB and Redis, this layer handles storing processed data, managing IoT cameras, session information, provisioning, and user data. Furthermore, MinIO plays a crucial role in storing original/processed frames and vehicle images. Additionally, Vault by HashiCorp ensures secure management of credentials and sensitive information.
- Data Services Layer with Flask: These Flask-based services enable user authentication, camera management, and secure provisioning of access to Fog nodes. These functions are vital for maintaining security and controlling access to the vehicle and speed monitoring system.
Advantages of the Proposed Architecture
The architecture of Traffic Sentinel offers several significant advantages that drive its efficiency and effectiveness in traffic management:
Scalability
The modular and layered structure allows optimal scalability. This architecture can easily adapt and expand to handle increased traffic volumes and data as the system grows.
Real-time Agility
The real-time processing capability, especially within the Real-time Processing Layer using Apache Flink, enables immediate identification of traffic patterns, speed limit violations, and anomalies. This facilitates quick responses to traffic situations and enhances road safety.
Efficient Data Management
With dedicated layers for data orchestration and storage using technologies like Apache NiFi, MongoDB, and Redis, the architecture ensures smooth and secure data management. This ensures rapid and reliable access to critical information needed for analysis and decision-making.
Flexibility and Adaptability
The integration of multiple technologies allows for greater flexibility. The architecture is designed to integrate new technologies or adapt to changes in system requirements without disrupting its operations.
Reinforced Security
The use of specific layers for credential management and user authentication, combined with tools like Vault by HashiCorp, ensures robust security. Sensitive data is securely stored and managed, reducing the risks of vulnerabilities or unauthorized access.
These architecture advantages in Traffic Sentinel establish a robust and adaptable framework for intelligent traffic monitoring, promoting efficient and secure road management.
Delving into Traffic Sentinel’s Architecture: Unraveling the Anatomy of Intelligent Traffic Management
Let’s take a closer look at how Traffic Sentinel works. We’ll dive into the different parts that make it tick, like sorting out traffic problems on the roads. By exploring each piece, you’ll see how Traffic Sentinel handles information, figures things out quickly, and keeps everything safe and organized. Get ready to discover how this smart system helps make our roads safer and traffic smoother!
Connecting IoT Devices: The Fog Stream Processing Layer
The Fog Stream Processing Layer is pivotal in Traffic Sentinel, enabling a secure and efficient connection between road-deployed traffic cameras, IoT devices, and the cloud infrastructure, ensuring reliable data transmission for subsequent real-time processing and analysis.
- IoT Device Intermediary: The Fog layer acts as a critical interface between road-deployed IP cameras, IoT devices, and the cloud infrastructure. Its function is to gather, process, and transmit data from these cameras to the cloud processing layer.
The above provided code snippet is a piece of the whole script implemeted for Fog Node componente, it’s aimed at initializing a Fog node within an Internet of Things (IoT) infrastructure. The initialize_fog_node(mac_address)
function orchestrates the Fog node setup by acquiring camera details through provisioning. It verifies and constructs a complete URL for the camera, employing base64 encoding for credentials if available. Subsequently, it initiates frame capture after successful provisioning. Additionally, the script sets up an MQTT (Message Queuing Telemetry Transport) client, configuring its connection to an MQTT broker, subscribing to a specific topic, and defining necessary callback functions. Finally, the main()
function serves as the entry point, fetching the node's MAC address or generating a random UUID if unavailable, then initiating the Fog node setup process.
In essence, establishes a Fog node by gathering camera specifics, configuring MQTT client communication, and initiating essential processes for integrating the node into the IoT system. The initialize_fog_node()
function handles camera setup, while the MQTT setup and the main()
function orchestrate broader system interactions and node initiation.
- MQTT Protocol for Efficient Transmission: The MQTT (Message Queuing Telemetry Transport) protocol is employed for data transmission between IoT devices and the cloud. MQTT is a lightweight and efficient messaging protocol that facilitates agile and optimized data transmission.
The provided code snippet outlines a function, send_frame_over_mqtt()
, dedicated to transmitting captured frames via MQTT. This function takes the timestamp of the frame and the corresponding MAC address as inputs to construct the frame's file path. It reads the binary data of the captured frame, encodes it into base64, and creates a payload containing relevant frame information such as MAC address, camera ID, timestamp, and the encoded frame data. Utilizing an MQTT client, this payload is published to a specified MQTT topic at QoS (Quality of Service) 0, ensuring a best-effort delivery. After successful transmission, details like MAC address, timestamp, and frame size are logged, followed by file removal for system cleanup. The function is robustly designed, featuring error handling mechanisms to manage potential exceptions that may occur during the frame transmission process, ensuring smooth and reliable operation within an IoT traffic monitoring system.
- Secure Authentication of Fog Nodes: The Fog layer requires each Fog node to authenticate securely using the Challenge-Handshake Authentication Protocol (CHAP). This authentication ensures that the information published by each Fog node is valid and reliable, guaranteeing the integrity of the processed and transmitted data.
The get_challenge
function requests a challenge for authentication using the device's MAC address. It sends a POST request to the specified service endpoint to retrieve the challenge. If the request is successful (HTTP status code 200), it extracts and returns the challenge for further authentication.
Next, the code defines the authenticate_chap
function, which implements the CHAP (Challenge-Handshake Authentication Protocol) for device authentication. This function receives the MAC address and the client's response to the challenge. It proceeds by collecting GPS information and constructing a JSON request containing authentication data, such as MAC address, client response, public IP, GPS coordinates, and location address. It sends this authentication request to the Fog service endpoint. If the authentication is successful (HTTP status code 200), it retrieves the session ID from the response and returns it.
Additionally, there are functions authenticate
and authenticate_with_retries
, which orchestrate the device authentication process. authenticate
method attempts to authenticate the device by retrieving a challenge, obtaining a password, and performing the CHAP-based authentication. If successful, it returns the session ID. On the other hand, authenticate_with_retries
allows multiple authentication attempts with retries in case of failure, executing the authenticate
method until the maximum retry count is reached or a successful authentication occurs.
- Video Streaming Management: Each Fog node is provisioned with specific information about the IP it needs to connect to and manage its video streaming. This information allows Fog nodes to interact effectively with IP cameras, ensuring a continuous and reliable transmission of video streams to the cloud processing infrastructure.
The code snippet illustrates a frame_capture_loop()
function that continuously captures frames from a specified camera feed. It begins by logging the attempt to open the provided camera URL using OpenCV. If successful, it initiates a loop to read frames from the camera's video stream. For each captured frame, the function generates a unique timestamp and saves the frame as an image file in a designated directory. Concurrently, it launches the send_frame_over_mqtt
function in a separate thread to transmit the frame data via MQTT, optimizing efficiency by allowing simultaneous processing. In case of errors during frame capture or image saving, appropriate error logs are generated. Additionally, the loop incorporates a mechanism to regulate the capture interval, ensuring a consistent time interval between frame captures by calculating elapsed time and determining the time to sleep before the subsequent capture cycle. Finally, upon completion or when instructed to stop, the video capture object is released to end the frame capture process. This function is essential in an IoT traffic monitoring system, facilitating continuous image acquisition, processing, and transmission for real-time analysis and monitoring.
- Intermediate Layer for Security and Efficiency: This Fog layer not only ensures data transmission security but also acts as an essential component in ensuring a continuous and efficient flow of information between IoT devices and the cloud infrastructure, optimizing data management and real-time responsiveness.
Optimizing Data Flow: The Data Orchestration Layer
The Data Orchestration Layer in Traffic Sentinel, facilitated by Apache NiFi, plays a pivotal role in managing the movement and processing of data across the different components of the system. Here’s a detailed explanation of the Data Orchestration Layer:
- Integration Hub: Apache NiFi acts as an integration hub, orchestrating the flow of data between disparate sources, processing layers, and storage systems within the IoT-based traffic monitoring system. It provides a graphical user interface (GUI) for designing, building, and managing data flows, simplifying complex data pipelines.
- Data Ingestion: NiFi enables seamless ingestion of real-time traffic data from various IoT devices, including traffic cameras and sensors. It integrates connectors for different data sources, such as MQTT, Kafka, and other protocols, allowing the system to collect data streams efficiently.
- Data Transformation and Routing: Once data is ingested, NiFi offers powerful transformation capabilities, allowing for data enrichment, cleansing, and normalization. It provides processors to manipulate data on-the-fly, transforming it into a format suitable for downstream processing. Additionally, NiFi efficiently routes the processed data to designated destinations or processing layers.
- Integration with MQTT and Kafka: Apache NiFi integrates with MQTT and Kafka, facilitating seamless communication and data transfer across different components of the architecture. It supports connectors and processors tailored for MQTT and Kafka, ensuring smooth integration and data flow between Fog nodes, data processing layers, and storage systems.
- Scalability and Reliability: NiFi’s distributed architecture ensures scalability and fault tolerance. It is capable of handling large volumes of data while maintaining system reliability. This scalability ensures optimal performance even as the volume of data and connected IoT devices increases.
- Monitoring and Management: NiFi provides monitoring capabilities through its user interface, allowing operators to visualize data flows, track data provenance, and monitor system performance. It also offers features for data lineage, allowing users to trace the origin and transformation history of data.
- Data Security and Governance: Apache NiFi incorporates security features, including SSL encryption, access controls, and data provenance, ensuring data security and compliance with governance policies. It enables administrators to define access control policies and monitor data access across the system.
In essence, the Data Orchestration Layer powered by Apache NiFi serves as the backbone for efficient data movement, transformation, and management within Traffic Sentinel. It ensures seamless integration, optimizes data flow, and provides robust monitoring and security features critical for an IoT-based traffic monitoring system.
Instant Insights: The Real-time Processing Layer
Explore Traffic Sentinel’s Real-time Processing Layer — a hub of instant insights from live traffic video streams. This core layer swiftly identifies vehicles, tracks patterns, and ensures real-time monitoring for safer roads:
- Apache Flink — Core Processing Engine: Apache Flink serves as the central processing engine of the Real-time Processing Layer. Flink’s stream processing capabilities enable the system to analyze data in motion, specifically video streams from traffic cameras, in real time.
- Live Video Analysis: Flink employs advanced algorithms, such as YOLO (You Only Look Once), for real-time vehicle detection and tracking within the video streams. This layer continuously processes incoming frames, identifying vehicles, capturing details like speed, model, color, and direction.
The provided code snippet orchestrates a PyFlink stream processing engine for handling real-time video frame data. It begins by initializing necessary Kafka configurations and performing a connectivity check to ensure proper Kafka connection. The program then initializes a vehicle detection tracker instance and obtains the Flink execution and table environments. It registers a custom FrameProcessorTableFunction
as a temporary function in the Flink environment, facilitating the processing of frame data utilizing the vehicle tracker. Source and sink tables are created within the environment, setting up the groundwork for the stream processing pipeline.
Within the pipeline, incoming video frames are received and processed using the FrameProcessorTableFunction
, extracting and transforming relevant data attributes. The processed frames are directed to an output sink table called "VideoFramesProcessed". Finally, the Flink program is executed, initializing the stream processing engine to process the video frame data received from the "VideoFramesReceived" source and conducting the defined operations before writing the processed data into the designated sink table. This script exemplifies a structured and orchestrated flow for real-time video frame processing within a PyFlink-based environment, emphasizing modularity and efficiency in handling continuous data streams.
- Efficient Stream Processing: Flink’s framework allows for efficient and parallelized processing of high-speed data streams. It performs operations like transformation, filtering, and aggregation on data streams, enabling instantaneous analysis of traffic data for identifying patterns, congestion, speed limit violations, and irregular behaviors.
- Integration with Kafka: Flink seamlessly integrates with Apache Kafka, which acts as a distributed streaming platform. Kafka facilitates high-throughput, fault-tolerant data ingestion, providing a reliable infrastructure for Flink to consume and process traffic-related information in real time.
The provided code snippet defines a function named create_sink_table
responsible for establishing a sink table within the Flink table environment to handle processed video frames. It employs the t_env.execute_sql
method to execute SQL statements for creating the sink table named "VideoFramesProcessed." This table consists of columns such as 'mac_address,' 'camera_id,' 'frame_timestamp,' and 'processed_frame,' specifying the data types for each column. The sink table is configured with the Kafka connector to handle data transmission to a Kafka topic named '{KAFKA_OUTPUT_TOPIC}' using the specified Kafka bootstrap servers. Additionally, the table format is set to 'json,' indicating the expected data format for the sink table's contents.
Overall, this function serves the purpose of setting up a structured sink table within the Flink table environment, defining its schema and configuring the necessary properties to ensure the proper transmission of processed video frame data to a designated Kafka topic in JSON format.
- Scalability and Fault Tolerance: Flink’s distributed architecture ensures scalability by enabling the system to handle increased data volumes and device connections. Its fault-tolerant design guarantees the system’s reliability, allowing it to maintain smooth operations even during component failures or high loads.
- Real-time Decision Making: The analysis performed by Flink enables real-time decision-making capabilities. For instance, identifying vehicles exceeding speed limits triggers immediate actions or alerts within the system, enhancing road safety measures.
- Performance Optimization: Flink offers optimization features like windowing, which allows data to be processed in discrete time intervals, facilitating better management of streaming data for analysis.
In summary, the Real-time Processing Layer powered by Apache Flink is the engine that drives real-time analysis of traffic data streams. It processes live video feeds, detects and tracks vehicles, facilitates immediate decision-making, and continuously monitors traffic patterns, contributing to enhanced road safety and efficient traffic management within Traffic Sentinel.
Exploring Traffic Sentinel’s Data Storage Layer: Safeguarding Information for Smarter Roads
The Data Storage Layer in Traffic Sentinel is a fundamental architectural component designed to efficiently manage, store, and retrieve traffic-related data generated by IoT devices, such as traffic cameras. Powered primarily by MongoDB, complemented by Redis and Vault by HashiCorp, this layer ensures robustness, scalability, and security in handling large volumes of real-time data.
- MongoDB as a Flexible NoSQL Database: MongoDB serves as the primary database solution, offering a schema-less architecture that accommodates diverse and evolving data structures. It efficiently stores processed data, including vehicle information, IoT camera management, session details, and user data, providing flexibility and adaptability in data storage.
- Scalability and Reliability: MongoDB’s distributed architecture enables horizontal scalability, ensuring the system’s ability to handle increased data volumes generated by IoT devices. Its replication and fault-tolerant design ensure data availability and reliability, essential for uninterrupted traffic monitoring and analysis.
- Redis for Caching and Session Management: Complementing MongoDB, Redis serves as an in-memory data store, enhancing performance through efficient caching of frequently accessed data and managing session information within the system.
- Vault by HashiCorp for Secure Data Management: Vault ensures the secure storage and management of sensitive information within the Data Storage Layer. It provides fine-grained control over credentials and critical data, maintaining the security of Fog node passwords and other sensitive information.
- MinIO Cluster for Enhanced Storage: Additionally, Traffic Sentinel integrates a MinIO cluster, bolstering the layer’s storage capacity to handle vast volumes of original and processed image frames, along with vehicle images from traffic cameras. MinIO acts as a high-performance object storage solution, augmenting the layer’s ability to manage and retrieve visual data crucial for comprehensive traffic surveillance and analysis.
The Data Storage Layer, powered by MongoDB, Redis, Vault by HashiCorp, and the MinIO cluster, forms a robust and scalable foundation within Traffic Sentinel. It efficiently manages, stores, and secures diverse traffic-related data, ensuring reliability and scalability in handling the real-time streaming data generated by IoT devices. These components collectively contribute significantly to the system’s functionality, resilience, and security.
Unveiling Traffic Sentinel’s Data Services Layer: Securing Access for Enhanced Traffic Monitoring
The Data Services Layer encompasses Flask-based services tailored to manage user authentication, camera configurations, and secure provisioning of access to Fog nodes. These services act as an interface between the frontend applications and the backend database, ensuring controlled access and efficient data handling within Traffic Sentinel.
- Flask Services for User Authentication: Flask services manage user authentication and access control within Traffic Sentinel. These services authenticate users securely, granting access to authorized functionalities based on user roles and permissions, ensuring data security and system integrity.
- Camera Management Services: The Data Services Layer includes Flask services for configuring and monitoring IoT cameras deployed on roads. These services facilitate camera settings, status monitoring, and information retrieval, ensuring efficient management and operation of traffic surveillance devices.
- Secure Provisioning of Fog Node Access: Flask-based services provide secure access and authorization mechanisms for Fog nodes within the Traffic Sentinel ecosystem. These services authenticate and manage access for Fog nodes, ensuring only authorized nodes can interact with the system, maintaining system security and integrity.
- Encapsulation of Business Logic: The Flask services encapsulate business logic associated with data management and user interactions. They implement rules, validations, and transformations required for storing or retrieving data from the underlying database, ensuring data consistency and integrity.
- Ensuring Secure Data Access: Services within this layer manage authentication, authorization, and data validation processes. They validate incoming requests, enforce security measures, and control access to sensitive data, safeguarding against potential security threats and unauthorized access.
- Real-time Streaming API: The primary purpose of the Real-time Streaming API is to enable users to establish WebSocket connections, facilitating the reception of live, processed payloads for a designated camera. Through this interface, authorized users can subscribe to specific camera streams, receiving instantaneous updates and data insights extracted by Traffic Sentinel’s analytical processes. By harnessing WebSocket technology, the API ensures a persistent and bidirectional communication channel between the Traffic Sentinel system and the subscribed users. This direct connection allows for the immediate transmission of processed data, including vehicle tracking, speed analysis, and other relevant traffic information, empowering users with real-time insights. The implementation of this API enhances user experience by providing an efficient means to access live processed data without latency, contributing to informed decision-making and enabling responsive actions in traffic management scenarios. It exemplifies Traffic Sentinel’s commitment to leveraging cutting-edge technologies for enhanced real-time monitoring and analysis of traffic patterns.
The Data Services Layer, built upon Flask-based services, plays a pivotal role in managing user authentication, camera configurations, and secure access provisioning within Traffic Sentinel. These services act as a bridge between users and the backend database, ensuring controlled and secure access while encapsulating essential business logic for efficient data handling and system security.
Visualizing Real-time Processed Data: Traffic Monitoring Interface
The culminating output of Traffic Sentinel’s robust architecture is a powerful monitoring interface built using Tkinter, a Python GUI framework. This intuitive interface leverages the real-time streaming services to showcase the processed payloads for individual cameras, providing a comprehensive view of the traffic analysis carried out by the platform.
The Traffic Monitoring Interface serves as a user-friendly dashboard that aggregates and displays the real-time processed data from Traffic Sentinel’s analytical engine. Through this interface, users gain immediate access to insights derived from live video streams captured by IoT cameras deployed on roads.
Utilizing Tkinter’s graphical capabilities, this interface exhibits a user-centric design, presenting a clear and organized layout for visualizing various traffic metrics. Users can select specific cameras and subscribe to their processed data streams through the embedded WebSocket connections.
Features of the Monitoring Interface:
- User Authentication: Access to this monitoring interface is restricted to authorized administrators, ensuring secure and controlled usage.
- Camera Selection: Users, specifically administrators, can choose specific cameras from the available list for detailed monitoring.
- Real-time Data Display: Processed data including vehicle detection, speed analysis, and traffic flow patterns are visualized in real-time.
- Responsive Visualization: The interface dynamically updates with newly processed data, ensuring users receive up-to-the-second traffic insights.
By integrating Tkinter with the streaming services offered by Traffic Sentinel, this monitoring interface provides an interactive and informative platform. Users can effortlessly observe, analyze, and interpret the processed data, enabling informed decision-making for effective traffic management strategies. This final output demonstrates the tangible outcome of Traffic Sentinel’s sophisticated architecture and real-time streaming capabilities in action.
Conclusion: Toward Smarter Traffic Management
In short, Traffic Sentinel represents a significant leap in traffic surveillance. Its smart design and technical layers make traffic management faster and more efficient.
This project uses modern tech to analyze traffic in real-time. From spotting cars to monitoring speed, Traffic Sentinel does it all to help make quick decisions and keep streets safer.
The monitoring interface is simple and displays data clearly. Only admins can see it, ensuring security. With this tool, informed decisions can be made to improve streets and make them safer.
In a nutshell, Traffic Sentinel isn’t just an idea; it’s a real solution that can make our streets safer and improve how we handle traffic!
This is it. I have really enjoyed developing and documenting this little project. Thanks for reading it. I hope this is the first of many. Special thanks to the open-source community and the contributors who have made this project possible.
If you are interested in the complete code, here is the link to the public repository: