Merge pull request #5 from skinnyrad/feat/two_gateways

Feat/two gateways
This commit is contained in:
Halcy0nic
2024-03-29 14:25:42 -06:00
committed by GitHub
13 changed files with 11328 additions and 109 deletions

119
app.py
View File

@@ -9,6 +9,7 @@ from collections import deque
import re
import requests
from bs4 import BeautifulSoup
import ipaddress
app = Flask(__name__)
socketio = SocketIO(app)
@@ -20,6 +21,9 @@ port3_status = True
global ser1
global ser2
global ser3
gateway_ips = {'gateway1': '192.168.0.101',
'gateway2': '192.168.0.102',
'gateway3': '192.168.0.103'}
frequency = lambda port: {'port1': 433, 'port2': 868,'port3': 915}.get(port, None)
surveydata = {}
parsed_entries = set()
@@ -79,61 +83,104 @@ def read_serial_data(port, ser, buffer):
#print(f"Error: {e}")
pass
@app.route('/set_gateways', methods=['POST'])
def set_gateways():
global gateway_ips
data = request.form
for key in ['gateway1', 'gateway2', 'gateway3']:
input_ip = data.get(key, '').strip()
if input_ip: # Proceed only if the input is not empty
try:
# Validate the IP address
ipaddress.ip_address(input_ip)
# Update the IP address if valid
gateway_ips[key] = input_ip
except ValueError:
# Return an error if the IP address is invalid
return jsonify({"error": f"Invalid IP address provided for {key}"}), 400
for gateway, ip_address in gateway_ips.items():
print(f"Gateway {gateway} has IP address: {ip_address}")
return jsonify({"message": "Gateway IPs updated successfully"}), 200
def parse_and_store_data():
global surveydata
url = "http://10.130.1.1/cgi-bin/log-traffic.has" # Your target URL
global parsed_entries
global gateway_ips
# Include the port number (8000) in your gateway URLs
gateway_urls = [
f"http://{gateway_ips['gateway1']}:8000/cgi-bin/log-traffic.has", # Gateway 1
f"http://{gateway_ips['gateway2']}:8000/cgi-bin/log-traffic.has", # Gateway 2
f"http://{gateway_ips['gateway3']}:8000/cgi-bin/log-traffic.has" # Gateway 3
]
headers = {
"Host": "10.130.1.1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
"DNT": "1",
"Sec-GPC": "1",
"Authorization": "Basic cm9vdDpkcmFnaW5v",
"Authorization": "Basic cm9vdDpkcmFnaW5v", # Assumes the same credentials for both gateways
"Connection": "keep-alive",
"Referer": "http://10.130.1.1/cgi-bin/log-lora.has",
"Upgrade-Insecure-Requests": "1"
}
response = requests.get(url, headers=headers)
for url in gateway_urls:
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table')
if table:
rows = table.find_all('tr')[1:] # Skip the header row
for row in rows:
# Skip hidden rows in this iteration
if row.get('style') == 'display: none;':
continue
cells = row.find_all('td')
if not cells:
continue
# Prepare formatted_row from visible cells, skipping the first cell for Chevron icon
formatted_row = ' | '.join(cell.text.strip() for cell in cells[1:])
# Extract dev_id and freq from the visible row
dev_id = extract_dev_id(formatted_row)
freq = extract_freq(formatted_row)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table')
rows = table.find_all('tr')
headers = [header.text.strip() for header in rows[0].find_all('th')][1:]
# Extract RSSI from the next hidden row
hidden_row = row.find_next_sibling('tr')
if hidden_row and 'display: none;' in hidden_row.get('style', ''):
hidden_data = hidden_row.td.text.strip()
rssi_match = re.search(r'"Rssi":(-?\d+)', hidden_data)
if rssi_match:
rssi = int(rssi_match.group(1))
else:
rssi = None
else:
rssi = None
for row in rows[1:]:
cells = row.find_all('td')
cell_data = [cell.text.strip() for cell in cells[1:] if cells.index(cell) < len(headers) + 1]
formatted_row = ' | '.join(cell_data)
# Save data into the surveydata structure
if dev_id and freq is not None:
entry_identifier = f"{dev_id}_{freq}_{formatted_row}"
if entry_identifier not in parsed_entries:
parsed_entries.add(entry_identifier)
if dev_id not in surveydata:
surveydata[dev_id] = []
surveydata[dev_id].append([freq, rssi, formatted_row])
dev_id = extract_dev_id(formatted_row) # Your existing function to extract DevEui or DevAddr
freq = extract_freq(formatted_row) # Your existing function to extract frequency
if dev_id and freq:
entry_identifier = f"{dev_id}_{formatted_row}" # Create a unique identifier for the entry
# Only process the entry if we haven't seen this identifier before
if entry_identifier not in parsed_entries:
parsed_entries.add(entry_identifier) # Add the identifier to the set
# Initialize dictionary for dev_id if not present
if dev_id not in surveydata:
surveydata[dev_id] = []
# Append new data to the list associated with the DevEui or DevAddr
surveydata[dev_id].append([freq, 0, formatted_row])
print("Data parsed and stored.")
else:
print(f"Request failed with status code: {response.status_code}")
print(f"Data parsed and stored from {url}.")
else:
print(f"Request to {url} failed with status code: {response.status_code}")
except Exception as e:
print(f"An error occurred while processing {url}: {e}")
# Schedule the next call to this function
Timer(60, parse_and_store_data).start() # Call this function every 60 seconds
Timer(30, parse_and_store_data).start() # Call this function every 30 seconds
def extract_dev_id(formatted_row):
@@ -346,5 +393,5 @@ def get_table_data():
if __name__ == '__main__':
Timer(60, parse_and_store_data).start()
Timer(30, parse_and_store_data).start()
socketio.run(app, debug=True)

View File

@@ -1,10 +1,35 @@
import requests
from bs4 import BeautifulSoup
# Define the URL and headers
url = "http://10.130.1.1/cgi-bin/log-traffic.has"
def get_gateway_data(url, headers):
"""
Makes a request to the specified gateway URL and parses the HTML table content.
Returns a list of formatted strings for each row in the table.
"""
formatted_rows = []
response = requests.get(url, headers=headers)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table')
if table:
rows = table.find_all('tr')
headers = [header.text.strip() for header in rows[0].find_all('th')][1:]
for row in rows[1:]:
cells = row.find_all('td')
cell_data = [cell.text.strip() for cell in cells[1:] if cells.index(cell) < len(headers) + 1]
formatted_row = ' | '.join(cell_data)
formatted_rows.append(formatted_row)
else:
print(f"Request to {url} failed with status code:", response.status_code)
return formatted_rows
# Define URLs and headers for both gateways
gateway_1 = "http://192.168.1.23/cgi-bin/log-traffic.has"
gateway_2 = "http://192.168.1.24/cgi-bin/log-traffic.has"
headers = {
"Host": "10.130.1.1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
@@ -13,46 +38,20 @@ headers = {
"Sec-GPC": "1",
"Authorization": "Basic cm9vdDpkcmFnaW5v",
"Connection": "keep-alive",
"Referer": "http://10.130.1.1/cgi-bin/log-lora.has",
"Upgrade-Insecure-Requests": "1"
}
# Send the GET request
response = requests.get(url, headers=headers)
# Fetch and print data from both gateways
print("Fetching data from Gateway 1 (192.168.1.23)...")
data_1 = get_gateway_data(gateway_1, headers)
for row in data_1:
print(row)
print("\nFetching data from Gateway 2 (192.168.1.24)...")
# Update the 'Host' header for the second gateway if necessary
headers["Host"] = "192.168.1.24"
data_2 = get_gateway_data(gateway_2, headers)
for row in data_2:
print(row)
if response.status_code == 200:
# Parse the HTML content using BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Find the table
table = soup.find('table')
# Initialize an empty list to store formatted strings for each row
formatted_rows = []
# Find all table rows
rows = table.find_all('tr')
# Get column headers from the first row
# Using .text.strip() to clean the text and [1:] to skip the empty first column
headers = [header.text.strip() for header in rows[0].find_all('th')][1:]
# Iterate through each row (skipping the first row with the headers)
for row in rows[1:]:
# Find all data cells (td tags) in the row
cells = row.find_all('td')
# Extract text from each cell
# Using [1:] to skip the first cell with the arrow icon
cell_data = [cell.text.strip() for cell in cells[1:] if cells.index(cell) < len(headers) + 1]
# Format the row data into a neat line
formatted_row = ' | '.join(cell_data)
# Append the formatted string to the list
formatted_rows.append(formatted_row)
# Print the formatted string to display the row
print(formatted_row)
else:
print("Request failed with status code:", response.status_code)

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

1371
static/css/sweetalert2.css Normal file

File diff suppressed because it is too large Load Diff

6
static/js/all.js Normal file

File diff suppressed because one or more lines are too long

7
static/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
static/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

6064
static/js/socket.io.js Normal file

File diff suppressed because it is too large Load Diff

3659
static/js/sweetalert2.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -5,22 +5,21 @@
<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>
<script type="text/javascript" src="static/js/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>
<script src="static/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">
<link rel="stylesheet" href="static/css/sweetalert2.css">
<!-- 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="static/js/sweetalert2.js"></script>
<script src="static/js/jquery.min.js"></script>
</head>
<body id="page-top">
@@ -637,7 +636,7 @@
</div>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="static/js/scripts.js"></script>
</body>

View File

@@ -5,21 +5,20 @@
<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>
<script type="text/javascript" src="static/js/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>
<script src="static/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">
<link rel="stylesheet" href="static/css/sweetalert2.css">
<!-- Include SweetAlert2 JS -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
<script src="static/js/sweetalert2.js"></script>
</head>
@@ -33,7 +32,7 @@
<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="#about">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">Tracking Mode</a></li>
@@ -61,9 +60,77 @@
</p>
</div>
</section>
<!-- Add this form within the body where it fits best, possibly under the About section -->
<section class="resume-section">
<div class="resume-section-content">
<h2 class="mb-0" style="text-align: center;">LoRaWAN Gateway Configuration</h2><br>
<img src="static/assets/img/lorawan.webp" style="width:100%; "><br><br>
<div style="display: flex; justify-content: center; margin-top: 20px;"><button class="transmit-button" id="configureGatewayBtn">Configure Gateway</button></div>
</div>
</section>
</div>
<script>
document.getElementById('configureGatewayBtn').addEventListener('click', function() {
let gatewayIPs = {};
const ipPrompt = (title) => {
return Swal.fire({
title: title,
input: 'text',
inputPlaceholder: 'Leave empty to keep current IP',
inputValidator: (value) => {
if (value && !value.match(/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/)) {
return 'Please enter a valid IP address or leave it empty';
}
}
});
};
ipPrompt('Enter Gateway 1 IP Address').then((result) => {
if (result.value) gatewayIPs.gateway1 = result.value;
ipPrompt('Enter Gateway 2 IP Address').then((result) => {
if (result.value) gatewayIPs.gateway2 = result.value;
ipPrompt('Enter Gateway 3 IP Address').then((result) => {
if (result.value) gatewayIPs.gateway3 = result.value;
// Now send the IPs to the server only if they are not undefined
let queryString = Object.keys(gatewayIPs).reduce((acc, key) => {
if (gatewayIPs[key] !== undefined) {
acc.push(`${key}=${encodeURIComponent(gatewayIPs[key])}`);
}
return acc;
}, []).join('&');
if (queryString) {
fetch('/set_gateways', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: queryString
})
.then(response => response.json())
.then(data => Swal.fire('Success', 'Gateway IPs updated successfully', 'success'))
.catch(error => Swal.fire('Error', 'There was an issue updating the Gateway IPs', 'error'));
} else {
Swal.fire('No Changes', 'No IP addresses were changed.', 'info');
}
});
});
});
});
</script>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="static/js/scripts.js"></script>
</body>

View File

@@ -5,22 +5,21 @@
<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>
<script type="text/javascript" src="static/js/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>
<script src="static/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">
<link rel="stylesheet" href="static/css/sweetalert2.css">
<!-- Include SweetAlert2 JS -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="static/js/sweetalert2.js"></script>
<script src="static/js/jquery.min.js"></script>
</head>
<body id="page-top">

View File

@@ -5,22 +5,21 @@
<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>
<script type="text/javascript" src="static/js/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>
<script src="static/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">
<link rel="stylesheet" href="static/css/sweetalert2.css">
<!-- 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="static/js/sweetalert2.js"></script>
<script src="static/js/jquery.min.js"></script>
</head>
<body id="page-top">
@@ -946,7 +945,7 @@
</div>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="static/js/scripts.js"></script>
</body>