Submarine
잠수함 만들기 

Start, Stop Shell
start shell  
 #!/bin/bash

echo
echo '##### START Submarine #####'
echo

wpa_cli -i wlan0 status
echo
echo

FILENAME=/home/hyunsu/submarine/nohup.out
if [ -f "$FILENAME" ] ; then
 echo "nohup.out delete !"
 rm /home/hyunsu/submarine/nohup.out
else
 echo "file not exist"
fi

echo '##### START CCTV #####'
cd /home/hyunsu/submarine
nohup python3 /home/hyunsu/submarine/SubMarine.py &
sleep 3

echo '##### START BROD SOUND #####'
hwString=`pactl list | grep -A 40 'Source' | grep -A 20 'device.bus = "usb"' | grep 'device.string' | grep -o '[0-9]'`
echo -e "\n Mic HW = [$hwString]"

nohup cvlc -vvv alsa://plughw:$hwString --sout '#transcode{acodec=mp3,ab=64,channels=1}:standard{access=http,dst=0.0.0.0:8080/out.mp3}' 1> /dev/null 2>&1 &

echo
echo '##### STARTed Submarine #####'
echo

 
 Stop shell 
 #!/bin/bash

echo
echo '##### STOP Submarine #####'
echo

ps -ef | grep SubMarine.py | grep -v grep
KILLPID=`ps -ef | grep SubMarine.py | grep -v grep | awk '{print($2)}'`
echo "Stop Submarine Process = " $KILLPID
kill -9 $KILLPID
sleep 3

ps -ef | grep vlc | grep -v grep
KILLPID=`ps -ef | grep vlc | grep -v grep | awk '{print($2)}'`
echo "Stop Brod Sound Process = " $KILLPID
kill -9 $KILLPID
sleep 3

echo
echo '##### STOPed Submarine #####'
echo
 
  

메인프로그램 SubMarine.py
SubMarine.py 
 메인 프로그램  
 from flask import Flask, render_template, send_from_directory, Response, send_file, request, redirect, url_for
from flask_socketio import SocketIO
import argparse, logging, logging.config, conf
import os
from power import PowerStatus
from datetime import datetime
from commChecker import CommChecker
from gpioControl import GpioControl
from usbwebcamera import UsbWebCamera
from piwebcamera import PiWebCamera

app = Flask(__name__)
app.config['SECRET_KEY'] = '1764121q'
socketio = SocketIO(app)

logging.config.dictConfig(conf.dictConfig)
logger = logging.getLogger(__name__)

power = PowerStatus()
commChecker = CommChecker()
gpio = GpioControl()

usbcamera = UsbWebCamera(20,1)
usbcamera.run()

piwebcamera = PiWebCamera()
piwebcamera.run()

@app.after_request
def add_header(r):
 """
 Add headers to both force latest IE rendering or Chrome Frame,
 and also to cache the rendered page for 10 minutes
 """
 r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
 r.headers["Pragma"] = "no-cache"
 r.headers["Expires"] = "0"
 r.headers["Cache-Control"] = "public, max-age=0"
 return r

@app.route("/")
@app.route("/index.html")
def index():
 logger.debug("Requested /")
 return render_template("index.html")

@app.route("/favorit.ico")
def favorit_ico():
 logger.debug("Requested favorit.ico image")
 filename = "favorit.ico"
 return send_file(filename)

@app.route("/VideoStatus")
def videostatus():
 logger.debug("Video Status change ")
 content = usbcamera.status()
 return Response(content, mimetype='text/xml')

@app.route("/SubmStatus")
def submStatus():
 logger.debug("Submarine Status change ")
 content = piwebcamera.status()
 return Response(content, mimetype='text/xml')
 
@app.route("/temperature")
def temperature():
 content = os.popen("vcgencmd measure_temp").readline()
 content = content.replace("temp=", "")
 powerstatus = power.getPowerStatus()
 return Response("내부온도:" + content+" , 전원:"+powerstatus+" , 측정시간:"+str(datetime.now()), mimetype='text/xml')

@app.route("/commCheck")
def commcheck():
 connstatus = str(commChecker.checkQuality())
 return Response(connstatus+" , "+str(datetime.now()), mimetype='text/xml')

@app.route('/lightOnOff', methods=['GET', 'POST'])
def lightOnOff():
 gpio.light()
 logger.debug('message KK Fired !!!')
 return Response('Light ON', mimetype='text/html')

''' ############# MOVE ############# '''

@app.route("/floating", methods=['GET', 'POST'])
def floating():
 if request.method == 'POST':
 moveOrder = request.form['moveCnt']
 if not moveOrder :
 reString = "Do not move"
 else :
 reString = gpio.Floating(int(moveOrder))
 print("Move floating ..." + moveOrder)
 return Response(reString, mimetype='text/html')

@app.route("/diving", methods=['GET', 'POST'])
def diving():
 if request.method == 'POST':
 moveOrder = request.form['moveCnt']
 if not moveOrder :
 reString = "Do not move"
 else :
 reString = gpio.Diving(int(moveOrder))
 print("Move diving ..." + moveOrder)
 return Response(reString, mimetype='text/html')
 
 
 
@app.route("/forward", methods=['GET', 'POST'])
def forward():
 if request.method == 'POST':
 moveOrder = request.form['moveFBLFCnt']
 if not moveOrder :
 reString = "Do not move"
 else :
 reString = gpio.Forward(int(moveOrder))
 print("Move Forward ..." + moveOrder)
 return Response(reString, mimetype='text/html')

@app.route("/backward", methods=['GET', 'POST'])
def backward():
 if request.method == 'POST':
 moveOrder = request.form['moveFBLFCnt']
 if not moveOrder :
 reString = "Do not move"
 else :
 reString = gpio.Backward(int(moveOrder))
 print("Move Backward ..." + moveOrder)
 return Response(reString, mimetype='text/html')
 
@app.route("/right", methods=['GET', 'POST'])
def right():
 if request.method == 'POST':
 moveOrder = request.form['moveFBLFCnt']
 if not moveOrder :
 reString = "Do not move"
 else :
 reString = gpio.TurnLeftF(int(moveOrder))
 print("Move Right ..." + moveOrder)
 return Response(reString, mimetype='text/html')
 
@app.route("/left", methods=['GET', 'POST'])
def left():
 if request.method == 'POST':
 moveOrder = request.form['moveFBLFCnt']
 if not moveOrder :
 reString = "Do not move"
 else :
 reString = gpio.TurnRightF(int(moveOrder))
 print("Move Left ..." + moveOrder)
 return Response(reString, mimetype='text/html')

@app.route("/video_usb_feed")
def video_usb_feed():
 return Response(genusb(usbcamera),
 mimetype="multipart/x-mixed-replace; boundary=frame")

def genusb(usbcamera):
 logger.debug("Starting USB stream")
 while True:
 frame = usbcamera.get_frame()
 yield (b'--frame\r\n'
 b'Content-Type: image/png\r\n\r\n' + frame + b'\r\n')

@app.route("/video_pi_snapshot")
def video_pi_snapshot():
 return Response(genpi(piwebcamera),
 mimetype="multipart/x-mixed-replace; boundary=frame")
 
def genpi(piwebcamera):
 logger.debug("Starting PI capchure")
 while True:
 frame = piwebcamera.get_frame()
 yield (b'--frame\r\n'
 b'Content-Type: image/png\r\n\r\n' + frame + b'\r\n')
 
 
if __name__=="__main__":
 logger.debug("Starting Submarine start")
# socketio.run(app, log_output=True, host='0.0.0.0', port=8081, debug=True, use_reloader=False, allow_unsafe_werkzeug=True)
 socketio.run(app, log_output=True, host='0.0.0.0', port=8081, allow_unsafe_werkzeug=True)

USB 카메라 프로그램 (Thread)
USB 카메라 프로그램 (Thread) 
 import cv2
import threading
import time
import logging
import os

logger = logging.getLogger(__name__)
archive_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

thread = None
status = True

class UsbWebCamera:

 def __init__(self,fps=20,video_source=0):
 logger.info("Initializing usb camera class with {fps} " + str(fps) + " and video_source={" + str(video_source) + "}")
 self.fps = fps
 self.video_source = video_source
 self.camera = cv2.VideoCapture(self.video_source)

 self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
 self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
 
 self.max_frames = 5*self.fps
 self.frames = []
 self.isrunning = False
 
 def run(self):
 logging.debug("Perparing Usb Camera thread")
 global thread
 if thread is None:
 logging.debug("Creating thread")
 thread = threading.Thread(target=self._capture_loop,daemon=True)
 logger.debug("Starting thread")
 self.isrunning = True
 thread.start()
 logger.info("Thread started")

 def _capture_loop(self):
 global status
 dt = 1/self.fps
 logger.debug("Observation started")
 while self.isrunning:
 if(status):
 v,im = self.camera.read()
 im = cv2.flip(im, 1)
 #im = cv2.flip(im, 0)
 if v:
 if len(self.frames)==self.max_frames:
 self.frames = self.frames[1:]
 self.frames.append(im)
 time.sleep(dt)
 logger.info("Thread stopped successfully")

 def status(self):
 global status
 logger.debug("Status isrunning" + str(status))
 if(status):
 content = "STOP THREAD !"
 status = False
 else:
 content = "START THREAD !"
 status = True
 return content
 
 def get_frame(self, _bytes=True):
 if len(self.frames)>0:
 if _bytes:
 img = cv2.imencode('.png',self.frames[-1])[1].tobytes()
 else:
 img = self.frames[-1]
 else:
 logger.info("Change cam source 1")
 self.video_source = 1
 self.camera = cv2.VideoCapture(self.video_source)
 self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
 self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
 with open(archive_path+"/not_found.jpeg","rb") as f:
 img = f.read()
 return img
 
 
  

PI 카메라 프로그램 (Thread)
PI 카메라 프로그램 (Thread) 
 # import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
import threading
import time
import logging
import os

logger = logging.getLogger(__name__)
archive_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'archive')

thread = None
status = False

# Set up camera constants
#IM_WIDTH = 1024
#IM_HEIGHT = 768
IM_WIDTH = 640
IM_HEIGHT = 480

class PiWebCamera:
 def __init__(self,fps=20):
 logger.info(f"Initializing pi camera class with {fps} fps ")
 self.fps = fps
 self.camera = PiCamera(framerate=24)
 self.camera.resolution = (IM_WIDTH,IM_HEIGHT)
 # self.camera.rotation = 180 
 self.rawCapture = PiRGBArray(self.camera, size=(IM_WIDTH,IM_HEIGHT))
 self.rawCapture.truncate(0)
 self.max_frames = 5*self.fps
 self.frames = []
 self.isrunning = False
 
 def run(self):
 logging.debug("Perparing Pi Camera thread")
 global thread
 if thread is None:
 logging.debug("Creating PI thread")
 thread = threading.Thread(target=self._capture_loop,daemon=True)
 logger.debug("Starting PI thread")
 self.isrunning = True
 thread.start()
 logger.info("Thread PI started")

 def _capture_loop(self):
 global status
 dt = 1/self.fps
 logger.debug("Observation started")
 while self.isrunning:
 if(status):
 self.camera.capture(self.rawCapture, format="bgr", use_video_port=True)
 self.rawCapture.truncate(0)
 image = self.rawCapture.array
 if len(self.frames)==self.max_frames:
 self.frames = self.frames[1:]
 self.frames.append(image)
 time.sleep(dt)
 logger.info("Thread stopped successfully")

 def status(self):
 global status
 logger.debug("Status isrunning" + str(status))
 if(status):
 content = "STOP THREAD !"
 status = False
 else:
 content = "START THREAD !"
 status = True
 return content

 
 def get_frame(self, _bytes=True):
 if len(self.frames)>0:
 if _bytes:
 img = cv2.imencode('.png',self.frames[-1])[1].tobytes()
 else:
 img = self.frames[-1]
 else:
 with open(archive_path+"/not_found.jpeg","rb") as f:
 img = f.read()
 return img
 

 
  

메인 화면 index.html
메인 화면 index.html 
 {% extends "base.html" %}

{% block content %}
<div class="container">
 <center>
 Submarine 0.1 
 </center>
 <form name="frm">
 <table>
 <tr>
 <td colspan=3>
 Temperature = <span id="temperature"> 내부 온도 </span>
 </td>
 </tr>
 <tr>
 <td colspan=3>
 메시지:<span id="resultmessage">...</span><br><BR>
 <input type="button" value="VideoStatus" id="btnVideoStatus" /> Video Status=<span id="videostatus">STARTING</span>
 <audio autoplay controls> 
 <source src="http://web.kkorack.com:19080/out.mp3" type="audio/mp3"> 
 </audio>
 <BR>
 </td>
 </tr>
 <tr>
 <td>
 <table>
 <tr>
 <td></td>
 <td><input type="button" value=" LIGHT ON " id="btnLightOn" /></td>
 <td><br><br><br></td>
 </tr>
 <tr>
 <td></td>
 <td><input type=text id="moveFBLFCnt" maxlength="5" size="5" value=1 />
 <td><br><br><br></td>
 </tr>
 <tr>
 <td></td>
 <td><center><input type="button" value=" ^ " id="btnForward" /></center></td>
 <td></td>
 </tr>
 <tr>
 <td><input type="button" value=" < " id="btnLeft" /></td>
 <td></td>
 <td><input type="button" value=" > " id="btnRight" /></td>
 </tr>
 <tr>
 <td></td>
 <td><center><input type="button" value=" v " id="btnBackward" /></center></td>
 <td></td>
 </tr>
 </table>
 </td>
 <td>
 <img src="{{ url_for('video_usb_feed') }}" class="border border-dark">
 </td>
 <td>
 <table>
 <tr>
 <td colspan=3>
 <input type="button" value="SubmarineStatus" id="btnSubmStatus" /> Submarine Status=<span id="submstatus">STOPED</span><br>
 <img src="{{ url_for('video_pi_snapshot') }}" width=400 class="border border-dark">
 <br>
 <span id="communicationlevel"> 통신 정보 </span><br>통신이 중지되면 부상
 </td>
 </tr>
 <tr>
 <td colspan=3>
 <input type=text id="moveCnt" maxlength="5" size="5" value=1 />
 </td>
 </tr>
 <tr>
 <td></td>
 <td><input type="button" value=" UP " id="btnFloating" /></td>
 <td></td>
 </tr>
 <tr>
 <td></td>
 <td><input type="button" value=" DOWN " id="btnDiving" /></td>
 <td></td>
 </tr>
 </table>
 </td>
 </tr>
 <tr>
 <td colspan=3>
 <span id="alertmessage"> 알림 메시지 </span><br>
 </td>
 </tr>
 </table>
 </form>
</div> 
<script type="text/javascript">

var tempId = null;
tempId = setInterval(getTemperatureFunc, 1000*60);
var commCheck = null;
commCheck = setInterval(getCommStatus, 1000*30);
//clearInterval(timerId);

 function getTemperatureFunc() {
 var fName = "/temperature";
 xhr1 = new XMLHttpRequest();
 xhr1.open("get", fName, true);
 xhr1.onreadystatechange = function() {
 if (xhr1.readyState == 4) {
 if (xhr1.status == 200) {
 document.getElementById("temperature").innerHTML = xhr1.responseText;
 } else {
 document.getElementById("temperature").innerHTML = " temperature ERROR : " + xhr1.status;
 } 
 }
 }
 xhr1.send(null);
 }

 function getCommStatus() {
 var fName = "/commCheck";
 xhr2 = new XMLHttpRequest();
 xhr2.open("get", fName, true);
 xhr2.onreadystatechange = function() {
 if (xhr2.readyState == 4) {
 if (xhr2.status == 200) {
 document.getElementById("communicationlevel").innerHTML = xhr2.responseText;
 } else {
 document.getElementById("communicationlevel").innerHTML = " communicationlevel ERROR : " + xhr2.status;
 } 
 }
 }
 xhr2.send(null);
 }

 /////////////////////////////////////////////////////////////////////////////////////////////

 window.onload = function() {
 document.getElementById("btnLightOn").onclick = setLightOnOff;
 document.getElementById("btnFloating").onclick = getFloatingFunc;
 document.getElementById("btnDiving").onclick = getDivingFunc;
 document.getElementById("btnForward").onclick = getForwardFunc;
 document.getElementById("btnBackward").onclick = getTurnBackwardFunc;
 document.getElementById("btnLeft").onclick = getLeftFunc;
 document.getElementById("btnRight").onclick = getRightFunc;
 document.getElementById("btnVideoStatus").onclick = getVideoStatusFunc;
 document.getElementById("btnSubmStatus").onclick = getSubmStatusFunc;
 }
 
 function setLightOnOff() {
 var fName = "/lightOnOff";
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) {
 document.getElementById("alertmessage").value = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.send(null); 
 } 
 
 function getFloatingFunc() {
 var fName = "/floating"; 
 data=document.getElementById("moveCnt").value;
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("resultmessage").innerHTML = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 xhr.send("moveCnt=" + data);
 }

 function getDivingFunc() {
 var fName = "/diving"; 
 data=document.getElementById("moveCnt").value;
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("resultmessage").innerHTML = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 xhr.send("moveCnt=" + data);
 }

 function getForwardFunc() {
 var fName = "/forward"; 
 data=document.getElementById("moveFBLFCnt").value;
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("resultmessage").innerHTML = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 xhr.send("moveFBLFCnt=" + data);
 }

 function getTurnBackwardFunc() {
 var fName = "/backward"; 
 data=document.getElementById("moveFBLFCnt").value;
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("resultmessage").innerHTML = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 xhr.send("moveFBLFCnt=" + data);
 }
 
 
 
 function getRightFunc() {
 var fName = "/right"; 
 data=document.getElementById("moveFBLFCnt").value;
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("resultmessage").innerHTML = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 xhr.send("moveFBLFCnt=" + data);
 }

 function getLeftFunc() {
 var fName = "/left"; 
 data=document.getElementById("moveFBLFCnt").value;
 xhr = new XMLHttpRequest();
 xhr.open("POST", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("resultmessage").innerHTML = xhr.responseText;
 } else {
 alert("ERROR : " + xhr.status);
 }
 }
 }
 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
 xhr.send("moveFBLFCnt=" + data);
 }

 function getVideoStatusFunc() {
 var fName = "/VideoStatus"; 
 xhr = new XMLHttpRequest();
 xhr.open("get", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("videostatus").innerHTML = xhr.responseText;
 } else {
 alert(" status ERROR : " + xhr.status);
 }
 }
 }
 xhr.send(null); 
 }
 
 function getSubmStatusFunc() {
 var fName = "/SubmStatus"; 
 xhr = new XMLHttpRequest();
 xhr.open("get", fName, true);
 xhr.onreadystatechange = function() { 
 if (xhr.readyState == 4) {
 if (xhr.status == 200) { 
 document.getElementById("submstatus").innerHTML = xhr.responseText;
 } else {
 alert(" status ERROR : " + xhr.status);
 }
 }
 }
 xhr.send(null); 
 }
 
 
 
 
 
 
 
 
 
 

 
</script>

{% endblock %}
 
  