Skip to content

Commit 727551b

Browse files
Merge pull request #2 from SentryCoderDev/develop
Switched to Fastapi instead of Flask
2 parents 6195e59 + b1a7566 commit 727551b

File tree

3 files changed

+200
-82
lines changed

3 files changed

+200
-82
lines changed

app.py

Lines changed: 53 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
from flask import Flask, render_template, Response, request, jsonify
1+
from fastapi import FastAPI, WebSocket, Request
2+
from fastapi.responses import HTMLResponse, StreamingResponse
3+
from fastapi.templating import Jinja2Templates
24
import cv2
35
import pytesseract
4-
import time
56
import threading
67
import serial
8+
import asyncio
79

8-
app = Flask(__name__)
10+
app = FastAPI()
11+
templates = Jinja2Templates(directory="templates")
912

1013
# All Cameras
11-
outside_garage_cam = cv2.VideoCapture(0)
12-
inside_garage_cam = cv2.VideoCapture(1)
13-
entrance_cam = cv2.VideoCapture(2)
14-
14+
cameras = [cv2.VideoCapture(i) for i in range(3)]
1515
ser = serial.Serial('/dev/ttyUSB0', 115200) # Arduino's serial port
1616
result_message = ""
1717

@@ -24,8 +24,11 @@
2424
# Pytesseract configuration
2525
pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract' # Path to Tesseract OCR executable
2626

27-
def gen_frames(cam):
27+
def gen_frames(cam_index):
28+
cam = cameras[cam_index]
2829
while True:
30+
if not cam.isOpened():
31+
cam.open(cam_index)
2932
success, frame = cam.read()
3033
if not success:
3134
break
@@ -35,9 +38,9 @@ def gen_frames(cam):
3538
yield (b'--frame\r\n'
3639
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
3740

38-
def garage_control():
41+
async def garage_control():
3942
while True:
40-
ret, frame = outside_garage_cam.read()
43+
ret, frame = cameras[0].read()
4144
if ret:
4245
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
4346
# Perform OCR using Pytesseract
@@ -46,68 +49,59 @@ def garage_control():
4649
# Check if the target plate number is recognized
4750
if "your_target_plate" in text:
4851
ser.write(b'OPEN_GARAGE\n')
49-
print("Opening garage for plate 'your_target_plate'")
50-
time.sleep(1)
51-
52-
def audio_detection():
53-
while True:
54-
if detect_doorbell():
55-
print("ringtone detected!")
56-
# Start camera streaming at home entrance
57-
# Notify and view the camera as needed
58-
time.sleep(1)
52+
print("Garage opens for plate 'your_target_plate'")
53+
await asyncio.sleep(1)
5954

60-
def detect_doorbell():
61-
return False
62-
63-
def read_from_arduino():
55+
async def read_from_arduino():
6456
global result_message
6557
while True:
6658
if ser.in_waiting > 0:
6759
line = ser.readline().decode('utf-8').strip()
6860
if line.startswith("RESULT:"):
6961
result_message = line.split("RESULT:")[1]
62+
await asyncio.sleep(0.1)
63+
64+
@app.get("/", response_class=HTMLResponse)
65+
async def index(request: Request):
66+
return templates.TemplateResponse("index.html", {"request": request})
67+
68+
@app.get("/video_feed/{cam_id}")
69+
async def video_feed(cam_id: int):
70+
if 0 <= cam_id < len(cameras):
71+
return StreamingResponse(gen_frames(cam_id), media_type="multipart/x-mixed-replace; boundary=frame")
72+
return "Invalid Camera ID", 404
7073

71-
@app.route('/video_feed/<int:cam_id>')
72-
def video_feed(cam_id):
73-
if cam_id == 0:
74-
return Response(gen_frames(outside_garage_cam), mimetype='multipart/x-mixed-replace; boundary=frame')
75-
elif cam_id == 1:
76-
return Response(gen_frames(inside_garage_cam), mimetype='multipart/x-mixed-replace; boundary=frame')
77-
elif cam_id == 2:
78-
return Response(gen_frames(entrance_cam), mimetype='multipart/x-mixed-replace; boundary=frame')
79-
else:
80-
return "Invalid Camera ID", 404
81-
82-
@app.route('/open_door', methods=['POST'])
83-
def open_door():
74+
@app.post("/open_door")
75+
async def open_door():
8476
ser.write(b'OPEN_DOOR\n')
85-
return "Door Opened", 200
86-
87-
@app.route('/validate_password', methods=['POST'])
88-
def validate_password():
89-
data = request.json
90-
user = data.get('user')
91-
password = data.get('password')
92-
77+
return {"message": "Door Opened"}
78+
79+
@app.post("/validate_password")
80+
async def validate_password(user: str, password: str):
9381
if user in user_passwords and user_passwords[user] == password:
9482
ser.write(b'VALID_PASSWORD\n')
95-
return "Password Validated", 200
96-
else:
97-
return "Invalid Password", 401
83+
return {"message": "Password Validated"}
84+
return {"message": "Invalid Password"}, 401
9885

99-
@app.route('/result')
100-
def result():
86+
@app.get("/result")
87+
async def result():
10188
global result_message
102-
return jsonify(result=result_message)
89+
return {"result": result_message}
90+
91+
@app.websocket("/ws")
92+
async def websocket_endpoint(websocket: WebSocket):
93+
await websocket.accept()
94+
while True:
95+
data = await websocket.receive_text()
96+
if data == "result":
97+
await websocket.send_text(result_message)
98+
99+
if __name__ == "__main__":
100+
threading.Thread(target=asyncio.run, args=(garage_control(),)).start()
101+
threading.Thread(target=asyncio.run, args=(read_from_arduino(),)).start()
102+
import uvicorn
103+
uvicorn.run(app, host="0.0.0.0", port=8000)
104+
103105

104-
@app.route('/')
105-
def index():
106-
return render_template('index.html')
107106

108-
if __name__ == '__main__':
109-
threading.Thread(target=garage_control).start()
110-
threading.Thread(target=audio_detection).start()
111-
threading.Thread(target=read_from_arduino).start()
112-
app.run(host='0.0.0.0', port=5000, debug=True)
113107

ra.jpg

94.8 KB
Loading

templates/index.html

Lines changed: 147 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,173 @@
11
<!DOCTYPE html>
22
<html lang="en">
3+
34
<head>
45
<meta charset="UTF-8">
56
<meta name="viewport" content="width=device-width, initial-scale=1.0">
67
<title>H3RU Home Control System</title>
7-
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='styles.css') }}">
8+
<style>
9+
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
10+
11+
body {
12+
font-family: 'Roboto', sans-serif;
13+
background-color: #000000;
14+
color: #333;
15+
margin: 0;
16+
padding: 0;
17+
display: flex;
18+
flex-direction: column;
19+
justify-content: center;
20+
align-items: center;
21+
min-height: 100vh;
22+
}
23+
24+
.header {
25+
background-color: #fffb00be;
26+
padding: 20px;
27+
text-align: center;
28+
color: rgb(0, 0, 0);
29+
width: 100%;
30+
}
31+
32+
h1 {
33+
margin: 0;
34+
font-size: 2em;
35+
font-weight: 700;
36+
}
37+
38+
.logo-container {
39+
text-align: center;
40+
margin: 20px 0;
41+
}
42+
43+
.logo-container img {
44+
width: 200px;
45+
height: auto;
46+
}
47+
48+
.logo-container p {
49+
margin: 10px 0 0 0;
50+
font-size: 1em;
51+
}
52+
53+
.content {
54+
display: flex;
55+
justify-content: center;
56+
align-items: flex-start;
57+
flex-wrap: wrap;
58+
gap: 20px;
59+
width: 100%;
60+
}
61+
62+
.camera-feed {
63+
background-color: #fff;
64+
padding: 20px;
65+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
66+
border-radius: 8px;
67+
text-align: center;
68+
width: 320px;
69+
}
70+
71+
.camera-feed h3 {
72+
margin-top: 0;
73+
font-weight: 700;
74+
}
75+
76+
.camera-box {
77+
position: relative;
78+
width: 100%;
79+
padding-top: 56.25%;
80+
/* 16:9 Aspect Ratio */
81+
overflow: hidden;
82+
border-radius: 8px;
83+
}
84+
85+
.camera-box img {
86+
position: absolute;
87+
top: 0;
88+
left: 0;
89+
width: 100%;
90+
height: 100%;
91+
object-fit: cover;
92+
}
93+
94+
.centered-button {
95+
text-align: center;
96+
padding: 20px;
97+
width: 100%;
98+
}
99+
100+
#open-door {
101+
font-size: 1.2em;
102+
padding: 12px 24px;
103+
background-color: #fffb00c0;
104+
color: #fff;
105+
border: none;
106+
border-radius: 4px;
107+
cursor: pointer;
108+
transition: background-color 0.3s ease;
109+
}
110+
111+
#open-door:hover {
112+
background-color: #1669c1;
113+
}
114+
115+
#result-message {
116+
text-align: center;
117+
margin-top: 20px;
118+
font-size: 1em;
119+
color: #555;
120+
}
121+
</style>
8122
</head>
123+
9124
<body>
10-
<h1>H3RU Home Control System</h1>
11-
<div class="container">
125+
<header class="header">
126+
<h1>H3RU Home Control System</h1>
127+
</header>
128+
<div class="content">
12129
<div class="camera-feed">
13130
<h3>Outside Garage Camera</h3>
14-
<img src="{{ url_for('video_feed', cam_id=0) }}" alt="Outside Garage Camera" width="320" height="240">
131+
<div class="camera-box">
132+
<img src="{{ url_for('video_feed', cam_id=0) }}" alt="Outside Garage Camera">
133+
</div>
15134
</div>
16-
<div class="camera-feed">
17-
<h3>Inside Garage Camera</h3>
18-
<img src="{{ url_for('video_feed', cam_id=1) }}" alt="Inside Garage Camera" width="320" height="240">
135+
<div class="logo-container">
136+
<img src="file:///C:/Users/emohi/Desktop/H3RU-Home_Control_System-main/ra.jpg" alt="H3RU Logo">
137+
<p>To everyone who can't finish what they started<br>- H3RU</p>
19138
</div>
20139
<div class="camera-feed">
21-
<h3>Entrance Camera</h3>
22-
<img src="{{ url_for('video_feed', cam_id=2) }}" alt="Entrance Camera" width="320" height="240">
140+
<h3>Inside Garage Camera</h3>
141+
<div class="camera-box">
142+
<img src="{{ url_for('video_feed', cam_id=1) }}" alt="Inside Garage Camera">
143+
</div>
23144
</div>
24145
</div>
25146
<div class="centered-button">
26147
<button id="open-door">Open Door</button>
27148
</div>
28-
<div id="result-message" style="margin-top: 20px;"></div>
149+
<div class="camera-feed">
150+
<h3>Entrance Camera</h3>
151+
<div class="camera-box">
152+
<img src="{{ url_for('video_feed', cam_id=2) }}" alt="Entrance Camera">
153+
</div>
154+
</div>
155+
<div id="result-message"></div>
29156
<script>
30-
document.getElementById('open-door').addEventListener('click', function() {
157+
const ws = new WebSocket("ws://localhost:8000/ws");
158+
document.getElementById('open-door').addEventListener('click', function () {
31159
fetch('/open_door', { method: 'POST' })
32-
.then(response => response.text())
33-
.then(data => {
34-
document.getElementById('result-message').innerText = data;
35-
});
36-
});
37-
38-
function fetchResult() {
39-
fetch('/result')
40160
.then(response => response.json())
41161
.then(data => {
42-
document.getElementById('result-message').innerText = data.result;
162+
document.getElementById('result-message').innerText = data.message;
43163
});
44-
}
45-
46-
setInterval(fetchResult, 1000); // Her saniye sonuçları kontrol et
164+
});
165+
ws.onmessage = function (event) {
166+
document.getElementById('result-message').innerText = event.data;
167+
};
168+
setInterval(() => ws.send("result"), 1000);
47169
</script>
48170
</body>
171+
49172
</html>
173+

0 commit comments

Comments
 (0)