Skip to content

Commit

Permalink
database wip
Browse files Browse the repository at this point in the history
  • Loading branch information
elblogbruno committed Jul 28, 2021
1 parent 14499f6 commit 91cf3ac
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 48 deletions.
5 changes: 4 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from controller import create_app
from flask_sqlalchemy import SQLAlchemy

app = create_app('dev')
db = SQLAlchemy(app)

if __name__ == '__main__':
app.run(threaded=True, host="0.0.0.0")
#app.run(threaded=True, host="0.0.0.0")
app.run(threaded=True, host="0.0.0.0", ssl_context='adhoc')

2 changes: 2 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class DevelopmentConfig(Config):
DEBUG = True
LOG_LEVEL = logging.DEBUG
UPLOAD_FOLDER = UPLOAD_FOLDER
SQLALCHEMY_DATABASE_URI = 'postgresql://postgres:manresa21@localhost:5432/wanderpi_db_test'
SQLALCHEMY_TRACK_MODIFICATIONS = False

class ProductionConfig(Config):
# 上线配置
Expand Down
6 changes: 5 additions & 1 deletion controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from logging.handlers import RotatingFileHandler
from flask import Flask
from config import config_dict, STATIC_FOLDER
from flask_sqlalchemy import SQLAlchemy


# 设置日志(目的是将flask默认的日志和自定义的日志保存到文件中)
Expand All @@ -23,9 +24,12 @@ def setup_log(log_level):
def create_app(config_type): # 封装web应用的创建过程
# 根据类型取出对应的配置子类
config_class = config_dict[config_type]

app = Flask(__name__, static_folder=STATIC_FOLDER)
app.config.from_object(config_class)


app.config.from_object(config_class)

# 注册蓝图对象 如果内容只在文件中使用一次, 最好在使用前才导入, 可以有效避免导入错误
from controller.modules.home import home_blu
app.register_blueprint(home_blu)
Expand Down
28 changes: 28 additions & 0 deletions controller/models/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from werkzeug.security import generate_password_hash, check_password_hash

class Wanderpi(db.Model):
__tablename__ = 'video'
id = db.Column(db.String(256), primary_key=True)
name = db.Column(db.String(256), nullable=False)
lat = db.Column(db.String(256), nullable=False)
long = db.Column(db.String(256), nullable=False)



def __repr__(self):
return f'<User {self.id}>'
def set_id(self, id):
self.id = id

def save(self):
if not self.id:
db.session.add(self)
db.session.commit()

@staticmethod
def get_by_id(id):
return Wanderpi.query.get(id)

@staticmethod
def get_all():
return Wanderpi.query.all()
62 changes: 45 additions & 17 deletions controller/modules/home/views.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,61 @@
from app import Wanderpi
from os import name
from config import UPLOAD_FOLDER
from flask import session, render_template, redirect, url_for, Response,request, jsonify,send_from_directory
from flask import json, session, render_template, redirect, url_for, Response,request, jsonify,send_from_directory
from controller.modules.home import home_blu
from controller.utils.camera import VideoCamera

video_camera_ids = [{"deviceId" : 0, "deviceLabel" : "Webcam"}, {"deviceId" : 1, "deviceLabel" : "Webcam1"}]

video_camera = None
global_frame = None

@home_blu.route('/test')
def test():
# 模板渲染
return render_template("test.html")
# 主页
@home_blu.route('/')
def index():
# 模板渲染
username = session.get("username")
if not username:
session["initialized"] = False
return redirect(url_for("user.login"))

wanderpis = Wanderpi.get_all()
return render_template("test.html", wanderpis=wanderpis)

# 主页
@home_blu.route('/record')
def record():
# 模板渲染
username = session.get("username")
if not username:
session["initialized"] = False
return redirect(url_for("user.login"))
return render_template("record.html")

def init_camera():
def init_camera(camera_id):
global video_camera
if video_camera is None:
print("Camera has not been initialized. Initializing...")
print("Camera {0} has not been initialized. Initializing...".format(camera_id))
print("Initialized video camera")
a = "rtsp://192.168.1.10:554/user=admin_password=VyJdSdKg_channel=0_stream=1.sdp?real_stream"
return VideoCamera(1)

if camera_id.isnumeric():
camera_id = int(camera_id)

return VideoCamera(camera_id)
else:
print("Video Camera Object exists")

if video_camera.cap.isOpened():
video_camera.cap.release()
# if video_camera.cap.isOpened():
# video_camera.cap.release()
# video_camera.stop_record()

return video_camera


# 获取视频流
def video_stream():
def video_stream(camera_id):
global video_camera
global global_frame
video_camera = init_camera()
video_camera = init_camera(camera_id)


while video_camera.cap.isOpened():
Expand All @@ -58,13 +71,13 @@ def video_stream():


# 视频流
@home_blu.route('/video_viewer')
def video_viewer():
@home_blu.route('/video_feed/<string:camera_id>/')
def video_feed(camera_id):
# 模板渲染
username = session.get("username")
if not username:
return redirect(url_for("user.login"))
return Response(video_stream(),
return Response(video_stream(camera_id),
mimetype='multipart/x-mixed-replace; boundary=frame')

# 录制状态
Expand Down Expand Up @@ -92,3 +105,18 @@ def record_status():
def download_file(filename):
return send_from_directory(directory=UPLOAD_FOLDER, path=filename, as_attachment=True)


@home_blu.route('/get_available_video_sources', methods=['GET', 'POST'])
def get_available_video_sources(): #todo get available video sources from database
return jsonify(devices = video_camera_ids)

@home_blu.route('/save_video/<string:video_id>/', methods=['GET', 'POST'])
def save_video(video_id): #todo get available video sources from database
print("Saving video {0}".format(video_id))

wanderpi = Wanderpi(id=video_id, name="a", lat="a", long="a")
wanderpi.save()

return jsonify(devices = video_camera_ids)


48 changes: 47 additions & 1 deletion controller/static/recorder.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var statusBadgeContainer = document.getElementById("recording_status_container")
var statusBadge = document.getElementById("recording_status");
var downloadLink = document.getElementById("download_video");
var saveButton = document.getElementById("save_video");
var saveButtonModal = document.getElementById("save_request_button");


var gps = document.getElementById("gps_text");
Expand All @@ -15,12 +16,42 @@ buttonStop.disabled = true;
statusBadgeContainer.style.display = "none";


function initializeDropdown() {

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
obj = JSON.parse(xhr.responseText);
var devices = obj.devices;
for(var i = 0; i < devices.length; i ++){
var device = devices[i];
var option = document.createElement('option');
option.value = device.deviceId;
option.text = device.deviceLabel || 'camera ' + (i + 1);
document.querySelector('select#videoSource').appendChild(option);
};
}
}

xhr.open("POST", "/get_available_video_sources");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send();


}

window.addEventListener('DOMContentLoaded', (event) => {
initializeDropdown();
});


buttonRecord.onclick = function () {
// var url = window.location.href + "record_status";
buttonRecord.disabled = true;
buttonStop.disabled = false;

saveButton.style.display = "none";
downloadLink.style.display = "none";
// XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
Expand All @@ -42,6 +73,20 @@ buttonRecord.onclick = function () {
initializeMapAndLocator();
};

saveButtonModal.onclick = function () {
//makes a request to save the video and when it is done, it will redirect to the home page where the video is saved
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
window.location.href = "/";
}
}
xhr.open("POST", "/save_video/" + saveButton.value + "/");
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send();
};

buttonStop.onclick = function () {
buttonRecord.disabled = false;
buttonStop.disabled = true;
Expand All @@ -56,6 +101,7 @@ buttonStop.onclick = function () {
console.log(video_id);

saveButton.style.display = "inline";
saveButton.value = video_id;
downloadLink.style.display = "inline";
downloadLink.onclick = function () {
window.location.href = "/uploads/" + video_id;
Expand Down
39 changes: 34 additions & 5 deletions controller/templates/record.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
<title>Wanderpi</title>

<!-- CSS only -->
<link href="../static/css/recording-screen-style.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link href="../static/css/recording-screen-style.css" rel="stylesheet">

<!-- JavaScript Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

Expand All @@ -30,6 +31,30 @@

<body>

<!-- Modal -->
<div class="modal fade" id="saveWanderpiModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Save Wanderpi</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-3">
<label for="recipient-name" class="col-form-label">Name:</label>
<input type="text" class="form-control" id="recipient-name">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button id="save_request_button" type="button" class="btn btn-primary">Save <i class="bi bi-save"></i></button>
</div>
</div>
</div>
</div>

<!-- style="background-color: #B6E4FF;" -->

<!-- Image and text -->
Expand All @@ -40,6 +65,11 @@
<img src="{{url_for('static', filename='wanderpi-icon.svg')}}" width="60" height="60" class="d-inline-block align-top" alt="">
</a>
<ul class="navbar-nav mr-auto mt-1 mt-lg-0">

<li class="nav-item">
<select id="videoSource"></select>
</li>

<li class="nav-item" id="recording_status_container">
<span id="recording_status" class="badge">
Camera loaded
Expand All @@ -56,18 +86,16 @@
<div class="col-md d-flex align-items-stretch">
<div class="card">
<div class="card-body" >
<img class="camera-view-responsive card-img-top" id="video" src="{{ url_for('home.video_viewer') }}">
<img class="camera-view-responsive card-img-top" id="video" src="{{ url_for('home.video_feed', camera_id=0) }}">

<div class="container">
<div class="gap-2 mx-auto">
<button id="record" type="button" class="btn btn-outline-info btn-block btn-responsive ">Record Wanderpi <i class="bi bi-record2"></i></button>
<button id="stop" type="button" class="btn btn-outline-danger btn-block btn-responsive ">Stop Recording <i class="bi bi-stop-fill"></i></button>
<!-- <button type="button" value="Log-out" onclick="javascript:window.location.href='{{ url_for('user.logout') }}'" class="btn btn-secondary">Log out</button> -->
<button id="download_video" type="button" class="btn btn-outline-secondary btn-block btn-responsive">Download Wanderpi <i class="bi bi-file-arrow-down-fill"></i></button>


</div>
<button id="save_video" type="button" class="btn btn-outline-success btn-block">Save Wanderpi <i class="bi bi-save"></i></button>
<button id="save_video" type="button" class="btn btn-outline-success btn-block" data-bs-toggle="modal" data-bs-target="#saveWanderpiModal">Save Wanderpi <i class="bi bi-save"></i></button>
</div>
</div>
</div>
Expand Down Expand Up @@ -96,5 +124,6 @@
</div>
</div>


</body>
</html>
28 changes: 8 additions & 20 deletions controller/templates/test.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
<figure class="md:flex bg-gray-100 rounded-xl p-8 md:p-0">
<img class="w-32 h-32 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1280px-Image_created_with_a_mobile_phone.png" alt="" width="384" height="512">
<div class="pt-6 md:p-8 text-center md:text-left space-y-4">
<blockquote>
<p class="text-lg font-semibold">
Tailwind CSS is the only framework that I've seen scale
on large teams. Its easy to customize, adapts to any design,
and the build size is tiny.”
</p>
</blockquote>
<figcaption class="font-medium">
<div class="text-cyan-600">
Sarah Dayan
</div>
<div class="text-gray-500">
Staff Engineer, Algolia
</div>
</figcaption>
</div>
</figure>
{% block title %}Tutorial Flask: Miniblog{% endblock %}
{% block content %}
<ul>
{% for post in wanderpis %}
<li><a href="{{ post.id }}">{{ post.id }}</a></li>
{% endfor %}
</ul>
{% endblock %}
Empty file added db.py
Empty file.
8 changes: 5 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from controller import create_app

from flask_sqlalchemy import SQLAlchemy
app = create_app('dev')
db = SQLAlchemy(app)

if __name__ == '__main__':
app.run(threaded=True, host="0.0.0.0")
# app.run(threaded=True, host="0.0.0.0", ssl_context='adhoc')
#app.run(threaded=True, host="0.0.0.0")
db.create_all()
app.run(threaded=True, host="0.0.0.0", ssl_context='adhoc')

2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
flask
opencv-python
flask-sqlalchemy
psycopg2

0 comments on commit 91cf3ac

Please sign in to comment.