Merge pull request #1 from skinnyrad/survey-mode

Survey mode
This commit is contained in:
Halcy0nic
2024-01-08 18:31:30 -07:00
committed by GitHub
7 changed files with 307 additions and 108 deletions

54
app.py
View File

@@ -6,6 +6,7 @@ import threading
import time
from collections import deque
import pandas as pd
import re
app = Flask(__name__)
socketio = SocketIO(app)
@@ -19,25 +20,44 @@ 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)
surveydata = {}
def read_serial_data(port, ser, buffer):
global global_dataframe
global surveydata
rssi_pattern = r"RSSI: (-?\d+)"
rssi = ''
while True:
try:
if ser.in_waiting > 0:
data = ser.readline().decode('utf-8').strip()
match = re.search(rssi_pattern, data)
# Check if a RSSI was found
if match:
if port =='port1':
rssi = int(match.group(1))
surveydata['Raw LoRa Device 443 MHz'] = [433,rssi,'']
elif port =='port2':
rssi = int(match.group(1))
surveydata['Raw LoRa Device 868 MHz'] = [868,rssi,'']
elif port =='port3':
rssi = int(match.group(1))
surveydata['Raw LoRa Device 915 MHz'] = [915,rssi,'']
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())'''
socketio.emit(f'serial_data_{port}', {'data': data})
if frequency(port) == 433 and surveydata.get('Raw LoRa Device 443 MHz') is None:
surveydata['Raw LoRa Device 443 MHz'] = [433,0,rssi]
elif frequency(port) == 868 and surveydata.get('Raw LoRa Device 868 MHz') is None:
surveydata['Raw LoRa Device 868 MHz'] = [868,0,rssi]
elif frequency(port) == 915 and surveydata.get('Raw LoRa Device 915 MHz') is None:
surveydata['Raw LoRa Device 915 MHz'] = [915,0,rssi]
if (port == 'port1' and port1_status == False):
return
if (port == 'port2' and port2_status == False):
@@ -47,7 +67,7 @@ def read_serial_data(port, ser, buffer):
time.sleep(0.1)
except:
pass
def connect_serial(port,frequency):
global ser1
@@ -114,7 +134,7 @@ def analysis():
@app.route('/survey')
def survey():
return render_template('survey.html', initial_data={port: list(buffer) for port, buffer in serial_buffers.items()})
return render_template('survey.html', data=global_dataframe)
@app.route('/tracking')
def tracking():
@@ -221,8 +241,12 @@ def checkSer():
except:
pass
return jsonify(result="False")
@app.route('/get_table_data')
def get_table_data():
global surveydata
print(surveydata)
return jsonify(surveydata)
if __name__ == '__main__':
socketio.run(app, debug=True)

5
requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
Flask==2.3.2
Flask_SocketIO==5.3.6
MarkupSafe==2.1.3
pandas==2.0.3
pyserial==3.5

View File

@@ -11062,4 +11062,38 @@ section.resume-section .resume-section-content {
.red {
background-color: red;
}
/* Styling for the table */
.scrollable-table {
max-height: 300px;
overflow-y: auto;
display: block;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
.selected-row {
background-color: #FFFF99; /* Highlight color */
font-weight: bold; /* Enlarge the font */
}
.hidden-row {
display: none; /* Hide the non-selected rows */
}
.center-button {
display: block;
margin: 0 auto;
text-align: center;
}

View File

@@ -52,25 +52,18 @@
<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" />
<hr class="m-0" />
<br><br>
<!-- 433 -->
<section class="resume-section" id="433">
<div class="resume-section-content">
<h2 class="mb-5">433 MHz</h2>
<!-- Collapsible content -->
<div class="collapse" id="collapse433">
<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>
<h3 class="mb-0">433 MHz 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>
@@ -235,18 +228,20 @@
});
}
</script>
</section>
<hr class="m-0" />
<!-- 868 -->
<section class="resume-section" id="868">
</div>
</div>
</div>
<!-- Collapsible button -->
<a class="btn btn-primary" data-bs-toggle="collapse" href="#collapse433" role="button" aria-expanded="false" aria-controls="collapse433">
Toggle 433 MHz Section
</a>
</div>
<br><br>
<div class="resume-section-content">
<h2 class="mb-5">868 MHz</h2>
<div class="collapse" id="collapse868">
<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>
<h3 class="mb-0">868 MHz LoRa Transceiver</h3><br>
<div class="serial-data" id="serial-data-port2">
</div>
<div style="text-align:center;">
@@ -296,22 +291,17 @@
<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');
socket.on('serial_data_port1', function(data) {
var serialDataDiv = document.getElementById('serial-data-port1');
if (data.data instanceof Array) {
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;
});
}
// Scroll to the bottom for new data
//serialDataDiv.scrollTop = serialDataDiv.scrollHeight;
});
</script>
<script>
@@ -433,15 +423,20 @@
});
}
</script>
</section>
<hr class="m-0" />
<!-- 915-->
<section class="resume-section" id="915">
</div>
</div>
<!-- Collapsible button -->
<a class="btn btn-primary" data-bs-toggle="collapse" href="#collapse868" role="button" aria-expanded="false" aria-controls="collapse868">
Toggle 868 MHz Section
</a>
</div>
<br><br>
<div class="resume-section-content">
<h2 class="mb-5">915 MHz</h2><br>
<div class="collapse" id="collapse915">
<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>
<h3 class="mb-0">915 MHZ LoRa Transceiver</h3><br>
<div class="serial-data" id="serial-data-port3">
</div>
<div style="text-align:center;">
@@ -606,8 +601,17 @@
});
}
</script>
</div>
</div>
<!-- Collapsible button -->
<a class="btn btn-primary" data-bs-toggle="collapse" href="#collapse915" role="button" aria-expanded="false" aria-controls="collapse915">
Toggle 915 MHz Section
</a>
</div>
</div>
</section>
</div>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>

View File

@@ -36,7 +36,7 @@
<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>
<li class="nav-item"><a class="nav-link js-scroll-trigger" href="/tracking">Tracking Mode</a></li>
</ul>
</div>
</nav>

View File

@@ -20,7 +20,7 @@
<!-- 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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body id="page-top">
@@ -45,52 +45,55 @@
<!-- About-->
<section class="resume-section" id="about">
<div class="resume-section-content">
<h1 class="mb-0">
<h1 class="mb-0" style="text-align: center;">
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>
<br>
<div class="scrollable-table">
<table id="data-table">
<thead>
<tr>
<th>Device Name</th>
<th>Frequency</th>
<th>Signal Strength</th>
<th>Recovered Plaintext</th>
</tr>
</thead>
<tbody>
<!-- Rows will be inserted here -->
</tbody>
</table>
</div>
<script>
function updateTableData() {
fetch('/get_table_data')
.then(response => response.json())
.then(data => {
const tableBody = document.getElementById('data-table').getElementsByTagName('tbody')[0];
tableBody.innerHTML = ''; // Clear existing table rows
for (let key in data) {
let row = tableBody.insertRow();
let cell1 = row.insertCell();
let cell2 = row.insertCell();
let cell3 = row.insertCell();
let cell4 = row.insertCell();
cell1.innerHTML = key;
cell2.innerHTML = data[key][0];
cell3.innerHTML = data[key][1];
cell4.innerHTML = data[key][2];
}
})
.catch(error => console.error('Error:', error));
}
// Initial update of the table
updateTableData();
// Periodically update the table every 30 seconds (30000 milliseconds)
setInterval(updateTableData, 30000);
</script>
</section>
<hr class="m-0" />

View File

@@ -20,8 +20,7 @@
<!-- 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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body id="page-top">
<!-- Navigation-->
@@ -45,11 +44,141 @@
<!-- About-->
<section class="resume-section" id="about">
<div class="resume-section-content">
<h1 class="mb-0">
<h1 class="mb-0" style="text-align: center;">
Tracking Mode
</h1>
<h2 class="lead mb-5">Skinny Research and Development</h2>
</div>
<br>
<h2 class="lead mb-5" style="text-align: center;">Select A Device You Would Like To Track</h2>
<br>
<div class="scrollable-table">
<table id="data-table">
<thead>
<tr>
<th>Device Name</th>
<th>Frequency</th>
<th>Signal Strength</th>
</tr>
</thead>
<tbody>
<!-- Rows will be inserted here -->
</tbody>
</table>
</div>
<br>
<!-- Add a Clear Selection button with a CSS class -->
<button id="clear-selection-button" class="center-button" style="display: none;">Clear Filter</button>
<style>
/* CSS styles for centering the button */
.center-button {
display: block;
margin: 0 auto;
text-align: center;
}
/* CSS styles to hide rows */
.hidden-row {
display: none;
}
</style>
<script>
let selectedDeviceName = null; // Global variable to store the selected device name
let dataCache = {}; // Cache for storing fetched data
function updateTableData() {
fetch('/get_table_data')
.then(response => response.json())
.then(data => {
dataCache = data; // Update the data cache
const tableBody = document.getElementById('data-table').getElementsByTagName('tbody')[0];
tableBody.innerHTML = ''; // Clear existing table rows
for (let key in data) {
let row = tableBody.insertRow();
row.addEventListener('click', function () {
// Hide all rows
const allRows = tableBody.getElementsByTagName('tr');
for (let i = 0; i < allRows.length; i++) {
allRows[i].classList.add('hidden-row');
}
// Show the clicked row
row.classList.remove('hidden-row');
row.classList.add('selected-row');
// Display the "Clear Filter" button
const clearButton = document.getElementById('clear-selection-button');
clearButton.style.display = 'block';
selectedDeviceName = key; // Update the global variable with the selected device name
updateSelectedDataDisplay(); // Update the selected data display
});
if (Object.keys(data).indexOf(key) > 0) {
row.classList.add('hidden-row');
}
let cell1 = row.insertCell();
let cell2 = row.insertCell();
let cell3 = row.insertCell();
cell1.innerHTML = key;
cell2.innerHTML = data[key][0];
cell3.innerHTML = data[key][1];
}
updateSelectedDataDisplay(); // Update the selected data display after refreshing the table
})
.catch(error => console.error('Error:', error));
}
function updateSelectedDataDisplay() {
const selectedDataDiv = document.getElementById('selected-data');
if (selectedDeviceName !== null && selectedDeviceName in dataCache) {
const frequency = dataCache[selectedDeviceName][0];
const signalStrength = dataCache[selectedDeviceName][1];
selectedDataDiv.innerHTML = `
Device Name: ${selectedDeviceName}<br>
Frequency: ${frequency}<br>
Signal Strength: ${signalStrength}<br>
`;
} else {
selectedDataDiv.innerHTML = '';
}
}
const clearButton = document.getElementById('clear-selection-button');
clearButton.addEventListener('click', function () {
const tableBody = document.getElementById('data-table').getElementsByTagName('tbody')[0];
const selectedRow = tableBody.getElementsByClassName('selected-row')[0];
if (selectedRow) {
selectedRow.classList.remove('selected-row');
}
// Show all rows
const allRows = tableBody.getElementsByTagName('tr');
for (let i = 0; i < allRows.length; i++) {
allRows[i].classList.remove('hidden-row');
}
// Hide the "Clear Filter" button
clearButton.style.display = 'none';
selectedDeviceName = null; // Reset the global variable when selection is cleared
updateSelectedDataDisplay(); // Clear the selected data display
});
// Initial update of the table
updateTableData();
// Periodically update the table every second
setInterval(updateTableData, 1000);
</script>
<!-- Add a section to display selected data -->
<div id="selected-data"></div>
</section>
<hr class="m-0" />