mirror of
https://github.com/skinnyrad/Lora-Scanner.git
synced 2026-05-14 13:25:59 +02:00
Initial Site
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
from flask import Flask, render_template, request, jsonify
|
||||
from markupsafe import escape
|
||||
from flask_socketio import SocketIO, emit
|
||||
import serial
|
||||
import threading
|
||||
import time
|
||||
from collections import deque
|
||||
import pandas as pd
|
||||
|
||||
app = Flask(__name__)
|
||||
socketio = SocketIO(app)
|
||||
serial_threads = {}
|
||||
serial_buffers = {}
|
||||
port1_status = True
|
||||
port2_status = True
|
||||
port3_status = True
|
||||
global ser1
|
||||
global ser2
|
||||
global ser3
|
||||
global_dataframe = pd.DataFrame(columns=['Device Name', 'Frequency', 'Signal Strength', 'Plaintext'])
|
||||
frequency = lambda port: {'port1': 433, 'port2': 868,'port3': 915}.get(port, None)
|
||||
|
||||
|
||||
def read_serial_data(port, ser, buffer):
|
||||
global global_dataframe
|
||||
while True:
|
||||
try:
|
||||
if ser.in_waiting > 0:
|
||||
data = ser.readline().decode('utf-8').strip()
|
||||
buffer.append(data)
|
||||
socketio.emit(f'serial_data_{port}', {'data': data})
|
||||
|
||||
|
||||
if (global_dataframe['Device Name'] == 'Unknown Raw LoRa Devices').any():
|
||||
pass
|
||||
else:
|
||||
pandasdata = {'Device Name': 'Unknown Raw LoRa Devices', 'Frequency': frequency(port)}
|
||||
global_dataframe = global_dataframe.append(pandasdata, ignore_index=True)
|
||||
'''print(global_dataframe.head())'''
|
||||
|
||||
if (port == 'port1' and port1_status == False):
|
||||
return
|
||||
if (port == 'port2' and port2_status == False):
|
||||
return
|
||||
if (port == 'port3' and port3_status == False):
|
||||
return
|
||||
time.sleep(0.1)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def connect_serial(port,frequency):
|
||||
global ser1
|
||||
global ser2
|
||||
global ser3
|
||||
|
||||
if frequency == 433:
|
||||
try:
|
||||
ser1 = serial.Serial(port, baudrate=9600)
|
||||
serial_buffers['port1'] = deque(maxlen=10)
|
||||
serial_threads['port1'] = threading.Thread(target=read_serial_data, args=('port1', ser1, serial_buffers['port1']))
|
||||
serial_threads['port1'].daemon = True
|
||||
serial_threads['port1'].start()
|
||||
except:
|
||||
print("\n\nPort for 433 MHz not available\n\n")
|
||||
if frequency == 868:
|
||||
try:
|
||||
ser2 = serial.Serial(port, baudrate=9600)
|
||||
serial_buffers['port2'] = deque(maxlen=10)
|
||||
serial_threads['port2'] = threading.Thread(target=read_serial_data, args=('port2', ser2, serial_buffers['port2']))
|
||||
serial_threads['port2'].daemon = True
|
||||
serial_threads['port2'].start()
|
||||
except:
|
||||
print("\n\nPort for 868 MHz not available\n\n")
|
||||
if frequency == 915:
|
||||
try:
|
||||
ser3 = serial.Serial(port, baudrate=9600)
|
||||
serial_buffers['port3'] = deque(maxlen=10)
|
||||
serial_threads['port3'] = threading.Thread(target=read_serial_data, args=('port3', ser3, serial_buffers['port3']))
|
||||
serial_threads['port3'].daemon = True
|
||||
serial_threads['port3'].start()
|
||||
|
||||
except:
|
||||
print('\n\nPort for 915 MHz not available\n\n')
|
||||
|
||||
|
||||
def disconnect_serial(port):
|
||||
global ser1
|
||||
global ser2
|
||||
global ser3
|
||||
try:
|
||||
serial_threads[port].stop()
|
||||
del serial_threads[port]
|
||||
del serial_buffers[port]
|
||||
except:
|
||||
pass
|
||||
if port == "port1":
|
||||
ser1.close()
|
||||
elif port == "port2":
|
||||
ser2.close()
|
||||
elif port == "port3":
|
||||
ser3.close()
|
||||
else:
|
||||
print("Unkown port, something went wrong...")
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/analysis')
|
||||
def analysis():
|
||||
return render_template('analysis.html', initial_data={port: list(buffer) for port, buffer in serial_buffers.items()})
|
||||
|
||||
@app.route('/survey')
|
||||
def survey():
|
||||
return render_template('survey.html', initial_data={port: list(buffer) for port, buffer in serial_buffers.items()})
|
||||
|
||||
@app.route('/tracking')
|
||||
def tracking():
|
||||
return render_template('tracking.html', initial_data={port: list(buffer) for port, buffer in serial_buffers.items()})
|
||||
|
||||
@app.route('/attach_serial_433', methods=['GET'])
|
||||
def attach_serial_433():
|
||||
user_input = escape(request.args.get('user_input'))
|
||||
port1_status = True
|
||||
connect_serial(str(user_input), 433)
|
||||
# Process the input as needed
|
||||
result = f'Serial Port Requested for 433 MHz'
|
||||
return jsonify(result=result)
|
||||
|
||||
@app.route('/delete_serial_433', methods=['GET'])
|
||||
def delete433():
|
||||
# Add your logic here to handle the confirmation
|
||||
disconnect_serial("port1")
|
||||
result = "Port Disconnected!"
|
||||
return jsonify(result=result)
|
||||
|
||||
@app.route('/attach_serial_868', methods=['GET'])
|
||||
def attach_serial_868():
|
||||
user_input = escape(request.args.get('user_input'))
|
||||
port2_status = True
|
||||
connect_serial(str(user_input), 868)
|
||||
# Process the input as needed
|
||||
result = f'Serial Port Requested for 868 MHz'
|
||||
return jsonify(result=result)
|
||||
|
||||
@app.route('/delete_serial_868', methods=['GET'])
|
||||
def delete868():
|
||||
# Add your logic here to handle the confirmation
|
||||
disconnect_serial("port2")
|
||||
result = "Port Disconnected!"
|
||||
return jsonify(result=result)
|
||||
|
||||
@app.route('/attach_serial_915', methods=['GET'])
|
||||
def attach_serial_915():
|
||||
user_input = escape(request.args.get('user_input'))
|
||||
connect_serial(str(user_input), 915)
|
||||
# Process the input as needed
|
||||
result = f'Serial Port Requested for 915 MHz'
|
||||
return jsonify(result=result)
|
||||
|
||||
@app.route('/delete_serial_915', methods=['GET'])
|
||||
def delete915():
|
||||
# Add your logic here to handle the confirmation
|
||||
disconnect_serial("port3")
|
||||
result = "Port Disconnected!"
|
||||
return jsonify(result=result)
|
||||
|
||||
@socketio.on('connect')
|
||||
def handle_connect():
|
||||
for port, buffer in serial_buffers.items():
|
||||
emit(f'initial_serial_data_{port}', {'data': list(buffer)})
|
||||
|
||||
@app.route('/transmit433', methods=['POST'])
|
||||
def transmit433():
|
||||
global ser1
|
||||
data = request.json # Get the data from the POST request
|
||||
user_input = data.get('user_input') # Extract the user input
|
||||
msg = "TX:"+user_input+" "
|
||||
ser1.write(msg.encode())
|
||||
return jsonify(result="Ok")
|
||||
|
||||
@app.route('/transmit868', methods=['POST'])
|
||||
def transmit868():
|
||||
global ser2
|
||||
data = request.json # Get the data from the POST request
|
||||
user_input = data.get('user_input') # Extract the user input
|
||||
msg = "TX:"+user_input+" "
|
||||
ser2.write(msg.encode())
|
||||
return jsonify(result="Ok")
|
||||
|
||||
@app.route('/transmit915', methods=['POST'])
|
||||
def transmit915():
|
||||
global ser3
|
||||
data = request.json # Get the data from the POST request
|
||||
user_input = data.get('user_input') # Extract the user input
|
||||
msg = "TX:"+user_input+" "
|
||||
ser3.write(msg.encode())
|
||||
return jsonify(result="Ok")
|
||||
|
||||
@app.route('/checkSer', methods=['GET'])
|
||||
def checkSer():
|
||||
data = request.args.get('port')
|
||||
if data == 'port1':
|
||||
try:
|
||||
if ser1.is_open:
|
||||
return jsonify(result="True")
|
||||
except:
|
||||
pass
|
||||
elif data == 'port2':
|
||||
try:
|
||||
if ser2.is_open:
|
||||
return jsonify(result="True")
|
||||
except:
|
||||
pass
|
||||
elif data == 'port3':
|
||||
try:
|
||||
if ser3.is_open:
|
||||
return jsonify(result="True")
|
||||
except:
|
||||
pass
|
||||
return jsonify(result="False")
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
socketio.run(app, debug=True)
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import sys
|
||||
import serial
|
||||
import argparse
|
||||
|
||||
from serial.threaded import LineReader, ReaderThread
|
||||
|
||||
parser = argparse.ArgumentParser(description='LoRa Radio mode receiver.')
|
||||
parser.add_argument('port', help="Serial port descriptor")
|
||||
args = parser.parse_args()
|
||||
|
||||
class PrintLines(LineReader):
|
||||
|
||||
def connection_made(self, transport):
|
||||
print("connection made")
|
||||
self.transport = transport
|
||||
self.send_cmd('sys get ver')
|
||||
self.send_cmd('mac pause')
|
||||
self.send_cmd('radio set pwr 10')
|
||||
self.send_cmd('radio rx 0')
|
||||
self.send_cmd("sys set pindig GPIO10 0")
|
||||
|
||||
def handle_line(self, data):
|
||||
if data == "ok" or data == 'busy':
|
||||
return
|
||||
if data == "radio_err":
|
||||
self.send_cmd('radio rx 0')
|
||||
return
|
||||
|
||||
self.send_cmd("sys set pindig GPIO10 1", delay=0)
|
||||
print(data)
|
||||
time.sleep(.1)
|
||||
self.send_cmd("sys set pindig GPIO10 0", delay=1)
|
||||
self.send_cmd('radio rx 0')
|
||||
|
||||
def connection_lost(self, exc):
|
||||
if exc:
|
||||
print(exc)
|
||||
print("port closed")
|
||||
|
||||
def send_cmd(self, cmd, delay=.5):
|
||||
self.transport.write(('%s\r\n' % cmd).encode('UTF-8'))
|
||||
time.sleep(delay)
|
||||
|
||||
ser = serial.Serial(args.port, baudrate=57600)
|
||||
with ReaderThread(ser, PrintLines) as protocol:
|
||||
while(1):
|
||||
pass
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import sys
|
||||
import serial
|
||||
import argparse
|
||||
|
||||
from serial.threaded import LineReader, ReaderThread
|
||||
|
||||
parser = argparse.ArgumentParser(description='LoRa Radio mode sender.')
|
||||
parser.add_argument('port', help="Serial port descriptor")
|
||||
args = parser.parse_args()
|
||||
|
||||
class PrintLines(LineReader):
|
||||
|
||||
def connection_made(self, transport):
|
||||
print("connection made")
|
||||
self.transport = transport
|
||||
self.send_cmd("sys set pindig GPIO11 0")
|
||||
self.send_cmd('sys get ver')
|
||||
self.send_cmd('radio get mod')
|
||||
self.send_cmd('radio get freq')
|
||||
self.send_cmd('radio get sf')
|
||||
self.send_cmd('mac pause')
|
||||
self.send_cmd('radio set pwr 10')
|
||||
self.send_cmd("sys set pindig GPIO11 0")
|
||||
self.frame_count = 0
|
||||
|
||||
def handle_line(self, data):
|
||||
if data == "ok":
|
||||
return
|
||||
print("RECV: %s" % data)
|
||||
|
||||
def connection_lost(self, exc):
|
||||
if exc:
|
||||
print(exc)
|
||||
print("port closed")
|
||||
|
||||
def tx(self):
|
||||
self.send_cmd("sys set pindig GPIO11 1")
|
||||
txmsg = 'radio tx %x%x' % (int(time.time()), self.frame_count)
|
||||
self.send_cmd(txmsg)
|
||||
time.sleep(.3)
|
||||
self.send_cmd("sys set pindig GPIO11 0")
|
||||
self.frame_count = self.frame_count + 1
|
||||
|
||||
def send_cmd(self, cmd, delay=.5):
|
||||
print("SEND: %s" % cmd)
|
||||
self.write_line(cmd)
|
||||
time.sleep(delay)
|
||||
|
||||
|
||||
ser = serial.Serial(args.port, baudrate=57600)
|
||||
with ReaderThread(ser, PrintLines) as protocol:
|
||||
while(1):
|
||||
protocol.tx()
|
||||
time.sleep(10)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
+11065
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Start Bootstrap - Resume v7.0.6 (https://startbootstrap.com/theme/resume)
|
||||
* Copyright 2013-2023 Start Bootstrap
|
||||
* Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-resume/blob/master/LICENSE)
|
||||
*/
|
||||
//
|
||||
// Scripts
|
||||
//
|
||||
|
||||
window.addEventListener('DOMContentLoaded', event => {
|
||||
|
||||
// Activate Bootstrap scrollspy on the main nav element
|
||||
const sideNav = document.body.querySelector('#sideNav');
|
||||
if (sideNav) {
|
||||
new bootstrap.ScrollSpy(document.body, {
|
||||
target: '#sideNav',
|
||||
rootMargin: '0px 0px -40%',
|
||||
});
|
||||
};
|
||||
|
||||
// Collapse responsive navbar when toggler is visible
|
||||
const navbarToggler = document.body.querySelector('.navbar-toggler');
|
||||
const responsiveNavItems = [].slice.call(
|
||||
document.querySelectorAll('#navbarResponsive .nav-link')
|
||||
);
|
||||
responsiveNavItems.map(function (responsiveNavItem) {
|
||||
responsiveNavItem.addEventListener('click', () => {
|
||||
if (window.getComputedStyle(navbarToggler).display !== 'none') {
|
||||
navbarToggler.click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,617 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.js"></script>
|
||||
<title>LoRa Scanner</title>
|
||||
<link rel="icon" type="image/x-icon" href="assets/img/favicon.ico" />
|
||||
<!-- Font Awesome icons (free version)-->
|
||||
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
||||
<!-- Google fonts-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Saira+Extra+Condensed:500,700" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli:400,400i,800,800i" rel="stylesheet" type="text/css" />
|
||||
<!-- Core theme CSS (includes Bootstrap)-->
|
||||
<link href="static/css/styles.css" rel="stylesheet" />
|
||||
<!-- Include SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10">
|
||||
|
||||
<!-- Include SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body id="page-top">
|
||||
<!-- Navigation-->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top" id="sideNav">
|
||||
<a class="navbar-brand js-scroll-trigger" href="#page-top">
|
||||
<span class="d-block d-lg-none">LoRa Scanner</span>
|
||||
<span class="d-none d-lg-block"><img class="img-fluid img-profile rounded-circle mx-auto mb-2" src="static/assets/img/profile.jpg" alt="..." /></span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#">Analysis Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/survey">Survey Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/tracking">Tracking Mode</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- Page Content-->
|
||||
<div class="container-fluid p-0">
|
||||
<!-- About-->
|
||||
<section class="resume-section" id="about">
|
||||
<div class="resume-section-content">
|
||||
<h1 class="mb-0">
|
||||
Analysis Mode
|
||||
</h1>
|
||||
<h2 class="lead mb-5">Skinny Research and Development</h2>
|
||||
<p>
|
||||
Analyze LoRa traffic received at 433, 868, or 915 MHz. Click the desired frequency below to get started. Once you are on the appropriate page, click the 'Connect Serial Port' button to connect to a serial port on your computer. Once connected to your LoRa receiver, traffic will automatically be streamed to the web page for analysis. To disconnect a receiver, click the 'Disconnect Serial Port' button.
|
||||
</p>
|
||||
<h2 class="lead mb-5">
|
||||
<a class="nav-link js-scroll-trigger" href="#433">433 MHz</a>
|
||||
<br>
|
||||
<a class="nav-link js-scroll-trigger" href="#868">868 MHz</a>
|
||||
<br>
|
||||
<a class="nav-link js-scroll-trigger" href="#915">915 MHz</a>
|
||||
</h2>
|
||||
</div>
|
||||
</section>
|
||||
<hr class="m-0" />
|
||||
<!-- 433 -->
|
||||
<section class="resume-section" id="433">
|
||||
<div class="resume-section-content">
|
||||
<h2 class="mb-5">433 MHz</h2>
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between mb-5">
|
||||
<div class="flex-grow-1">
|
||||
<h3 class="mb-0">LoRa Transceiver</h3><br>
|
||||
<div class="serial-data" id="serial-data-port1">
|
||||
</div>
|
||||
<div style="text-align:center;">
|
||||
<button class="styled-button" onclick="promptUser433()">Connect Serial Port</button>
|
||||
<button class="disconnect-button" onclick="deleteSerial433()">Disconnect Serial Port</button>
|
||||
<button class="transmit-button" onclick="transmit433()">Transmit Data</button><br>
|
||||
<p id="status-label433" style="text-align: center">Status: Checking...</p>
|
||||
<div class="indicator-container">
|
||||
<div id="indicator433" class="indicator"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JavaScript for updating the indicator -->
|
||||
<script>
|
||||
function updateIndicator433() {
|
||||
// Fetch the status from the Flask route
|
||||
$.ajax({
|
||||
url: '/checkSer',
|
||||
type: 'GET',
|
||||
data: {
|
||||
port: 'port1',
|
||||
|
||||
},
|
||||
success: function(response) {
|
||||
|
||||
if (response['result'] === 'True') {
|
||||
$('#indicator433').removeClass('red').addClass('green');
|
||||
$('#status-label433').text('Status: Connected');
|
||||
} else {
|
||||
$('#indicator433').removeClass('green').addClass('red');
|
||||
$('#status-label433').text('Serial Port Status: Disconnected');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#indicator433').removeClass('green').addClass('red');
|
||||
$('#status-label433').text('Serial Port Status: Disconnected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initial update of the indicator
|
||||
updateIndicator433();
|
||||
|
||||
// Periodically check and update the indicator (e.g., every 5 seconds)
|
||||
setInterval(updateIndicator433, 5000);
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var socket = io.connect('http://' + document.domain + ':' + location.port);
|
||||
|
||||
// For port1
|
||||
socket.on('initial_serial_data_port1', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port1');
|
||||
data.data.forEach(function(line) {
|
||||
serialDataDiv.innerHTML += line + '<br>';
|
||||
});
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
|
||||
socket.on('serial_data_port1', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port1');
|
||||
serialDataDiv.innerHTML += data.data + '<br>';
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function promptUser433() {
|
||||
Swal.fire({
|
||||
title: 'Serial Port:',
|
||||
input: 'text',
|
||||
inputAttributes: {
|
||||
autocapitalize: 'off'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (value) => {
|
||||
// Make an AJAX request to Flask
|
||||
fetch(`/attach_serial_433?user_input=${encodeURIComponent(value)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire({
|
||||
title: 'Result',
|
||||
text: data.result,
|
||||
icon: 'info'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong.', 'error');
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function deleteSerial433() {
|
||||
Swal.fire({
|
||||
title: 'Are you sure you want to disconnect the 433 MHz port?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
cancelButtonText: 'No',
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
// User clicked "Yes" - Send HTTP GET request to Flask
|
||||
fetch('/delete_serial_433')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire({
|
||||
title: 'Confirmation Result',
|
||||
text: data.result,
|
||||
icon: 'info'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong.', 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function transmit433() {
|
||||
Swal.fire({
|
||||
title: 'Enter data to transmit:',
|
||||
input: 'text',
|
||||
inputAttributes: {
|
||||
autocapitalize: 'off'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (value) => {
|
||||
// Make an HTTP POST request to Flask
|
||||
return fetch('/transmit433', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ user_input: value })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong. Maybe the serial port is disconnected?', 'error');
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
Swal.fire({
|
||||
title: 'Data Transmitted',
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
<hr class="m-0" />
|
||||
<!-- 868 -->
|
||||
<section class="resume-section" id="868">
|
||||
<div class="resume-section-content">
|
||||
<h2 class="mb-5">868 MHz</h2>
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between mb-5">
|
||||
<div class="flex-grow-1">
|
||||
<h3 class="mb-0">LoRa Transceiver</h3><br>
|
||||
<div class="serial-data" id="serial-data-port2">
|
||||
</div>
|
||||
<div style="text-align:center;">
|
||||
<button class="styled-button" onclick="promptUser868()">Connect Serial Port</button>
|
||||
<button class="disconnect-button" onclick="deleteSerial868()">Disconnect Serial Port</button>
|
||||
<button class="transmit-button" onclick="transmit868()">Transmit Data</button><br>
|
||||
<p id="status-label868" style="text-align: center">Status: Checking...</p>
|
||||
<div class="indicator-container">
|
||||
<div id="indicator868" class="indicator"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updateIndicator868() {
|
||||
// Fetch the status from the Flask route
|
||||
$.ajax({
|
||||
url: '/checkSer',
|
||||
type: 'GET',
|
||||
data: {
|
||||
port: 'port2',
|
||||
|
||||
},
|
||||
success: function(response) {
|
||||
|
||||
if (response['result'] === 'True') {
|
||||
$('#indicator868').removeClass('red').addClass('green');
|
||||
$('#status-label868').text('Status: Connected');
|
||||
} else {
|
||||
$('#indicator868').removeClass('green').addClass('red');
|
||||
$('#status-label868').text('Serial Port Status: Disconnected');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#indicator868').removeClass('green').addClass('red');
|
||||
$('#status-label868a').text('Serial Port Status: Disconnected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initial update of the indicator
|
||||
updateIndicator868();
|
||||
|
||||
// Periodically check and update the indicator (e.g., every 5 seconds)
|
||||
setInterval(updateIndicator868, 5000);
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var socket = io.connect('http://' + document.domain + ':' + location.port);
|
||||
|
||||
// For port1
|
||||
socket.on('initial_serial_data_port1', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port1');
|
||||
data.data.forEach(function(line) {
|
||||
serialDataDiv.innerHTML += line + '<br>';
|
||||
});
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
|
||||
socket.on('serial_data_port1', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port1');
|
||||
serialDataDiv.innerHTML += data.data + '<br>';
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// For port2
|
||||
socket.on('initial_serial_data_port2', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port2');
|
||||
data.data.forEach(function(line) {
|
||||
serialDataDiv.innerHTML += line + '<br>';
|
||||
});
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
|
||||
socket.on('serial_data_port2', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port2');
|
||||
serialDataDiv.innerHTML += data.data + '<br>';
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function promptUser868() {
|
||||
Swal.fire({
|
||||
title: 'Serial Port:',
|
||||
input: 'text',
|
||||
inputAttributes: {
|
||||
autocapitalize: 'off'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (value) => {
|
||||
// Make an AJAX request to Flask
|
||||
fetch(`/attach_serial_868?user_input=${encodeURIComponent(value)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire({
|
||||
title: 'Result',
|
||||
text: data.result,
|
||||
icon: 'info'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong.', 'error');
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function deleteSerial868() {
|
||||
Swal.fire({
|
||||
title: 'Are you sure you want to disconnect the 868 MHz port?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
cancelButtonText: 'No',
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
// User clicked "Yes" - Send HTTP GET request to Flask
|
||||
fetch('/delete_serial_868')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire({
|
||||
title: 'Confirmation Result',
|
||||
text: data.result,
|
||||
icon: 'info'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong.', 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function transmit868() {
|
||||
Swal.fire({
|
||||
title: 'Enter data to transmit:',
|
||||
input: 'text',
|
||||
inputAttributes: {
|
||||
autocapitalize: 'off'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (value) => {
|
||||
// Make an HTTP POST request to Flask
|
||||
return fetch('/transmit868', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ user_input: value })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong. Maybe the serial port is disconnected?', 'error');
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
Swal.fire({
|
||||
title: 'Data Transmitted',
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
<hr class="m-0" />
|
||||
<!-- 915-->
|
||||
<section class="resume-section" id="915">
|
||||
<div class="resume-section-content">
|
||||
<h2 class="mb-5">915 MHz</h2><br>
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between mb-5">
|
||||
<div class="flex-grow-1">
|
||||
<h3 class="mb-0">LoRa Transceiver</h3><br>
|
||||
<div class="serial-data" id="serial-data-port3">
|
||||
</div>
|
||||
<div style="text-align:center;">
|
||||
<button class="styled-button" onclick="promptUser915()">Connect Serial Port</button>
|
||||
<button class="disconnect-button" onclick="deleteSerial915()">Disconnect Serial Port</button>
|
||||
<button class="transmit-button" onclick="transmit915()">Transmit Data</button><br>
|
||||
<p id="status-label915" style="text-align: center">Status: Checking...</p>
|
||||
<div class="indicator-container">
|
||||
<div id="indicator915" class="indicator"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updateIndicator915() {
|
||||
// Fetch the status from the Flask route
|
||||
$.ajax({
|
||||
url: '/checkSer',
|
||||
type: 'GET',
|
||||
data: {
|
||||
port: 'port3',
|
||||
|
||||
},
|
||||
success: function(response) {
|
||||
|
||||
if (response['result'] === 'True') {
|
||||
$('#indicator915').removeClass('red').addClass('green');
|
||||
$('#status-label915').text('Status: Connected');
|
||||
} else {
|
||||
$('#indicator915').removeClass('green').addClass('red');
|
||||
$('#status-label915').text('Serial Port Status: Disconnected');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$('#indicator915').removeClass('green').addClass('red');
|
||||
$('#status-label915').text('Serial Port Status: Disconnected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initial update of the indicator
|
||||
updateIndicator915();
|
||||
|
||||
// Periodically check and update the indicator (e.g., every 5 seconds)
|
||||
setInterval(updateIndicator915, 5000);
|
||||
</script>
|
||||
<script>
|
||||
// For port3
|
||||
socket.on('initial_serial_data_port3', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port3');
|
||||
data.data.forEach(function(line) {
|
||||
serialDataDiv.innerHTML += line + '<br>';
|
||||
});
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
|
||||
socket.on('serial_data_port3', function(data) {
|
||||
var serialDataDiv = document.getElementById('serial-data-port3');
|
||||
serialDataDiv.innerHTML += data.data + '<br>';
|
||||
// Scroll to the bottom for new data
|
||||
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function promptUser915() {
|
||||
Swal.fire({
|
||||
title: 'Serial Port:',
|
||||
input: 'text',
|
||||
inputAttributes: {
|
||||
autocapitalize: 'off'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (value) => {
|
||||
// Make an AJAX request to Flask
|
||||
fetch(`/attach_serial_915?user_input=${encodeURIComponent(value)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire({
|
||||
title: 'Result',
|
||||
text: data.result,
|
||||
icon: 'info'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong.', 'error');
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function deleteSerial915() {
|
||||
Swal.fire({
|
||||
title: 'Are you sure you want to disconnect the 915 MHz port?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
cancelButtonText: 'No',
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
// User clicked "Yes" - Send HTTP GET request to Flask
|
||||
fetch('/delete_serial_915')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.fire({
|
||||
title: 'Confirmation Result',
|
||||
text: data.result,
|
||||
icon: 'info'
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong.', 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function transmit915() {
|
||||
Swal.fire({
|
||||
title: 'Enter data to transmit:',
|
||||
input: 'text',
|
||||
inputAttributes: {
|
||||
autocapitalize: 'off'
|
||||
},
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Submit',
|
||||
cancelButtonText: 'Cancel',
|
||||
showLoaderOnConfirm: true,
|
||||
preConfirm: (value) => {
|
||||
// Make an HTTP POST request to Flask
|
||||
return fetch('/transmit915', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ user_input: value })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
Swal.fire('Oops!', 'Something went wrong. Maybe the serial port is disconnected?', 'error');
|
||||
});
|
||||
},
|
||||
allowOutsideClick: () => !Swal.isLoading()
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
Swal.fire({
|
||||
title: 'Data Transmitted',
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</section>
|
||||
</div>
|
||||
<!-- Bootstrap core JS-->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- Core theme JS-->
|
||||
<script src="static/js/scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.js"></script>
|
||||
<title>LoRa Scanner</title>
|
||||
<link rel="icon" type="image/x-icon" href="assets/img/favicon.ico" />
|
||||
<!-- Font Awesome icons (free version)-->
|
||||
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
||||
<!-- Google fonts-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Saira+Extra+Condensed:500,700" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli:400,400i,800,800i" rel="stylesheet" type="text/css" />
|
||||
<!-- Core theme CSS (includes Bootstrap)-->
|
||||
<link href="static/css/styles.css" rel="stylesheet" />
|
||||
<!-- Include SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10">
|
||||
|
||||
<!-- Include SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body id="page-top">
|
||||
<!-- Navigation-->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top" id="sideNav">
|
||||
<a class="navbar-brand js-scroll-trigger" href="#page-top">
|
||||
<span class="d-block d-lg-none">LoRa Scanner</span>
|
||||
<span class="d-none d-lg-block"><img class="img-fluid img-profile rounded-circle mx-auto mb-2" src="static/assets/img/profile.jpg" alt="..." /></span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#about">About</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/analysis">Analysis Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/survey">Survey Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#">Tracking Mode</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- Page Content-->
|
||||
<div class="container-fluid p-0">
|
||||
<!-- About-->
|
||||
<section class="resume-section" id="about">
|
||||
<div class="resume-section-content">
|
||||
<h1 class="mb-0">
|
||||
LoRa Scanner
|
||||
</h1>
|
||||
<h2 class="lead mb-5">Skinny Research and Development</h2>
|
||||
<p>LoRa, short for Long Range, is a wireless communication technology designed for long-range, low-power communication between devices in the Internet of Things (IoT) and machine-to-machine (M2M) applications. Developed to address the specific needs of IoT devices, LoRa technology enables efficient, low-cost, and long-range communication in various scenarios.
|
||||
|
||||
<br><br>LoRa operates on unlicensed radio frequencies, such as those in the Industrial, Scientific, and Medical (ISM) bands, providing the flexibility for deployment without the need for a dedicated spectrum license. It utilizes a modulation technique called Chirp Spread Spectrum (CSS), which allows for long-range communication with minimal power consumption.
|
||||
|
||||
<br><br>One of the key features of LoRa technology is its ability to provide extended communication ranges, often reaching several kilometers in open environments. This makes it suitable for applications where devices need to communicate over long distances while conserving battery life, such as in agriculture, smart cities, asset tracking, and environmental monitoring.
|
||||
|
||||
<br><br>LoRa devices typically consist of two main components: LoRa nodes (sensors or devices) and LoRa gateways. The nodes collect and transmit data, while gateways receive and forward this data to the central server or cloud infrastructure. The open LoRaWAN (Long Range Wide Area Network) protocol standardizes communication between devices and gateways, ensuring interoperability and facilitating the deployment of large-scale IoT networks.
|
||||
|
||||
<br><br>Due to its low power consumption, long-range capabilities, and suitability for diverse IoT applications, LoRa technology has gained popularity as a reliable and cost-effective solution for connecting a wide range of devices and sensors in the evolving landscape of the Internet of Things.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<!-- Bootstrap core JS-->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- Core theme JS-->
|
||||
<script src="static/js/scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.js"></script>
|
||||
<title>LoRa Scanner</title>
|
||||
<link rel="icon" type="image/x-icon" href="assets/img/favicon.ico" />
|
||||
<!-- Font Awesome icons (free version)-->
|
||||
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
||||
<!-- Google fonts-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Saira+Extra+Condensed:500,700" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli:400,400i,800,800i" rel="stylesheet" type="text/css" />
|
||||
<!-- Core theme CSS (includes Bootstrap)-->
|
||||
<link href="static/css/styles.css" rel="stylesheet" />
|
||||
<!-- Include SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10">
|
||||
|
||||
<!-- Include SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body id="page-top">
|
||||
<!-- Navigation-->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top" id="sideNav">
|
||||
<a class="navbar-brand js-scroll-trigger" href="#page-top">
|
||||
<span class="d-block d-lg-none">LoRa Scanner</span>
|
||||
<span class="d-none d-lg-block"><img class="img-fluid img-profile rounded-circle mx-auto mb-2" src="static/assets/img/profile.jpg" alt="..." /></span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/analysis">Analysis Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#">Survey Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/tracking">Tracking Mode</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- Page Content-->
|
||||
<div class="container-fluid p-0">
|
||||
<!-- About-->
|
||||
<section class="resume-section" id="about">
|
||||
<div class="resume-section-content">
|
||||
<h1 class="mb-0">
|
||||
Survey Mode
|
||||
</h1>
|
||||
<h2 class="lead mb-5">Skinny Research and Development</h2>
|
||||
</div>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>DataFrame Table</title>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #dddddd;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
</style>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Device Name</th>
|
||||
<th>Frequency</th>
|
||||
<th>Signal Strength</th>
|
||||
<th>Plaintext</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for index, row in data.iterrows() %}
|
||||
<tr>
|
||||
<td>{{ row['Device Name'] }}</td>
|
||||
<td>{{ row['Frequency'] }}</td>
|
||||
<td>{{ row['Signal Strength'] }}</td>
|
||||
<td>{{ row['Plaintext'] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</section>
|
||||
<hr class="m-0" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.js"></script>
|
||||
<title>LoRa Scanner</title>
|
||||
<link rel="icon" type="image/x-icon" href="assets/img/favicon.ico" />
|
||||
<!-- Font Awesome icons (free version)-->
|
||||
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
||||
<!-- Google fonts-->
|
||||
<link href="https://fonts.googleapis.com/css?family=Saira+Extra+Condensed:500,700" rel="stylesheet" type="text/css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli:400,400i,800,800i" rel="stylesheet" type="text/css" />
|
||||
<!-- Core theme CSS (includes Bootstrap)-->
|
||||
<link href="static/css/styles.css" rel="stylesheet" />
|
||||
<!-- Include SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10">
|
||||
|
||||
<!-- Include SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body id="page-top">
|
||||
<!-- Navigation-->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary fixed-top" id="sideNav">
|
||||
<a class="navbar-brand js-scroll-trigger" href="#page-top">
|
||||
<span class="d-block d-lg-none">LoRa Scanner</span>
|
||||
<span class="d-none d-lg-block"><img class="img-fluid img-profile rounded-circle mx-auto mb-2" src="static/assets/img/profile.jpg" alt="..." /></span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/analysis">Analysis Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/survey">Survey Mode</a></li>
|
||||
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="#">Tracking Mode</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- Page Content-->
|
||||
<div class="container-fluid p-0">
|
||||
<!-- About-->
|
||||
<section class="resume-section" id="about">
|
||||
<div class="resume-section-content">
|
||||
<h1 class="mb-0">
|
||||
Tracking Mode
|
||||
</h1>
|
||||
<h2 class="lead mb-5">Skinny Research and Development</h2>
|
||||
</div>
|
||||
</section>
|
||||
<hr class="m-0" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user