mirror of
https://github.com/skinnyrad/Lora-Scanner.git
synced 2026-03-28 17:43:00 +01:00
Feat: Integrating Dragino lps8n
This commit is contained in:
89
app.py
89
app.py
@@ -3,10 +3,12 @@ from markupsafe import escape
|
|||||||
from flask_socketio import SocketIO, emit
|
from flask_socketio import SocketIO, emit
|
||||||
import serial
|
import serial
|
||||||
import threading
|
import threading
|
||||||
|
from threading import Timer
|
||||||
import time
|
import time
|
||||||
from collections import deque
|
from collections import deque
|
||||||
import pandas as pd
|
|
||||||
import re
|
import re
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
socketio = SocketIO(app)
|
socketio = SocketIO(app)
|
||||||
@@ -18,7 +20,6 @@ port3_status = True
|
|||||||
global ser1
|
global ser1
|
||||||
global ser2
|
global ser2
|
||||||
global ser3
|
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)
|
frequency = lambda port: {'port1': 433, 'port2': 868,'port3': 915}.get(port, None)
|
||||||
surveydata = {}
|
surveydata = {}
|
||||||
|
|
||||||
@@ -75,8 +76,78 @@ def read_serial_data(port, ser, buffer):
|
|||||||
print(f"Error: {e}")
|
print(f"Error: {e}")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def parse_and_store_data():
|
||||||
|
global surveydata
|
||||||
|
url = "http://10.130.1.1/cgi-bin/log-traffic.has" # Your target URL
|
||||||
|
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",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Referer": "http://10.130.1.1/cgi-bin/log-lora.has",
|
||||||
|
"Upgrade-Insecure-Requests": "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
|
||||||
|
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:]
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Extract DevEui or DevAddr from the response
|
||||||
|
dev_id = extract_dev_id(formatted_row) # Implement this function based on your data format
|
||||||
|
freq = extract_freq(formatted_row) # Implement this function based on your data format
|
||||||
|
|
||||||
|
# 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])
|
||||||
|
#surveydata[dev_id]['decoded_values'].append(formatted_row)
|
||||||
|
|
||||||
|
print("Data parsed and stored.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f"Request failed with status code: {response.status_code}")
|
||||||
|
|
||||||
|
# Schedule the next call to this function
|
||||||
|
Timer(60, parse_and_store_data).start() # Call this function every 60 seconds
|
||||||
|
|
||||||
|
|
||||||
|
def extract_dev_id(formatted_row):
|
||||||
|
# Assuming DevEui or DevAddr is in the 'Content' part of the formatted_row
|
||||||
|
# and it's formatted like 'Dev Addr: {DevEui}, Size: {Size}'
|
||||||
|
try:
|
||||||
|
content_part = formatted_row.split('|')[-1].strip() # Get the last part of the formatted_row, which is 'Content'
|
||||||
|
dev_id = content_part.split(',')[0].split(':')[-1].strip() # Extract the DevEui or DevAddr
|
||||||
|
return dev_id
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error extracting DevEui/DevAddr: {e}")
|
||||||
|
return None # Return None or some default value if extraction fails
|
||||||
|
|
||||||
|
|
||||||
|
def extract_freq(formatted_row):
|
||||||
|
# Assuming 'Freq' is a standalone field in the formatted_row
|
||||||
|
try:
|
||||||
|
freq_part = formatted_row.split('|')[3].strip() # Get the 'Freq' part (assuming it's the fifth field)
|
||||||
|
freq = float(freq_part) # Convert the frequency to float
|
||||||
|
return freq
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error extracting frequency: {e}")
|
||||||
|
return None # Return None or some default value if extraction fails
|
||||||
|
|
||||||
|
|
||||||
def connect_serial(port,frequency):
|
def connect_serial(port,frequency):
|
||||||
@@ -144,7 +215,7 @@ def analysis():
|
|||||||
|
|
||||||
@app.route('/survey')
|
@app.route('/survey')
|
||||||
def survey():
|
def survey():
|
||||||
return render_template('survey.html', data=global_dataframe)
|
return render_template('survey.html')
|
||||||
|
|
||||||
@app.route('/tracking')
|
@app.route('/tracking')
|
||||||
def tracking():
|
def tracking():
|
||||||
@@ -255,8 +326,16 @@ def checkSer():
|
|||||||
@app.route('/get_table_data')
|
@app.route('/get_table_data')
|
||||||
def get_table_data():
|
def get_table_data():
|
||||||
global surveydata
|
global surveydata
|
||||||
print(surveydata)
|
cleaned_data = {}
|
||||||
return jsonify(surveydata)
|
|
||||||
|
for dev_id, data in surveydata.items():
|
||||||
|
if dev_id: # Check if dev_id is not empty
|
||||||
|
cleaned_data[dev_id] = data
|
||||||
|
|
||||||
|
#print(cleaned_data) # For debugging
|
||||||
|
return jsonify(cleaned_data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Timer(60, parse_and_store_data).start()
|
||||||
socketio.run(app, debug=True)
|
socketio.run(app, debug=True)
|
||||||
|
|||||||
58
draginoReq.py
Normal file
58
draginoReq.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
# Define the URL and headers
|
||||||
|
url = "http://10.130.1.1/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",
|
||||||
|
"Accept-Encoding": "gzip, deflate",
|
||||||
|
"DNT": "1",
|
||||||
|
"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)
|
||||||
|
|
||||||
|
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)
|
||||||
1767
examplereq
Normal file
1767
examplereq
Normal file
File diff suppressed because it is too large
Load Diff
122
lorawan.py
Normal file
122
lorawan.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
##!/usr/bin/env python3
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
import argparse
|
||||||
|
from enum import IntEnum
|
||||||
|
import serial
|
||||||
|
from serial.threaded import LineReader, ReaderThread
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Connect to LoRaWAN network')
|
||||||
|
parser.add_argument('port', help="Serial port of LoStik")
|
||||||
|
parser.add_argument('--joinmode', '-j', help="otaa, abp", default="otaa")
|
||||||
|
|
||||||
|
# ABP credentials
|
||||||
|
parser.add_argument('--appskey', help="App Session Key", default="")
|
||||||
|
parser.add_argument('--nwkskey', help="Network Session Key", default="")
|
||||||
|
parser.add_argument('--devaddr', help="Device Address", default="")
|
||||||
|
|
||||||
|
# OTAA credentials
|
||||||
|
parser.add_argument('--appeui', help="App EUI", default="")
|
||||||
|
parser.add_argument('--appkey', help="App Key", default="")
|
||||||
|
parser.add_argument('--deveui', help="Device EUI", default="")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
OTAA_RETRIES = 5
|
||||||
|
|
||||||
|
class MaxRetriesError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ConnectionState(IntEnum):
|
||||||
|
SUCCESS = 0
|
||||||
|
CONNECTING = 100
|
||||||
|
CONNECTED = 200
|
||||||
|
FAILED = 500
|
||||||
|
TO_MANY_RETRIES = 520
|
||||||
|
|
||||||
|
|
||||||
|
class PrintLines(LineReader):
|
||||||
|
|
||||||
|
retries = 0
|
||||||
|
state = ConnectionState.CONNECTING
|
||||||
|
|
||||||
|
def retry(self, action):
|
||||||
|
if(self.retries >= OTAA_RETRIES):
|
||||||
|
print("Too many retries, exiting")
|
||||||
|
self.state = ConnectionState.TO_MANY_RETRIES
|
||||||
|
return
|
||||||
|
self.retries = self.retries + 1
|
||||||
|
action()
|
||||||
|
|
||||||
|
def get_var(self, cmd):
|
||||||
|
self.send_cmd(cmd)
|
||||||
|
return self.transport.serial.readline()
|
||||||
|
|
||||||
|
def join(self):
|
||||||
|
if args.joinmode == "abp":
|
||||||
|
self.join_abp()
|
||||||
|
else:
|
||||||
|
self.join_otaa()
|
||||||
|
|
||||||
|
def join_otaa(self):
|
||||||
|
if len(args.appeui):
|
||||||
|
self.send_cmd('mac set appeui %s' % args.appeui)
|
||||||
|
if len(args.appkey):
|
||||||
|
self.send_cmd('mac set appkey %s' % args.appkey)
|
||||||
|
if len(args.deveui):
|
||||||
|
self.send_cmd('mac set deveui %s' % args.deveui)
|
||||||
|
self.send_cmd('mac join otaa')
|
||||||
|
|
||||||
|
def join_abp(self):
|
||||||
|
if len(args.devaddr):
|
||||||
|
self.send_cmd('mac set devaddr %s' % args.devaddr)
|
||||||
|
if len(args.appskey):
|
||||||
|
self.send_cmd('mac set appskey %s' % args.appskey)
|
||||||
|
if len(args.nwkskey):
|
||||||
|
self.send_cmd('mac set nwkskey %s' % args.nwkskey)
|
||||||
|
self.send_cmd('mac join abp')
|
||||||
|
|
||||||
|
def connection_made(self, transport):
|
||||||
|
"""
|
||||||
|
Fires when connection is made to serial port device
|
||||||
|
"""
|
||||||
|
print("Connection to LoStik established")
|
||||||
|
self.transport = transport
|
||||||
|
self.retry(self.join)
|
||||||
|
|
||||||
|
def handle_line(self, data):
|
||||||
|
# if data == "ok" or data == 'busy':
|
||||||
|
# return
|
||||||
|
print("STATUS: %s" % data)
|
||||||
|
if data.strip() == "denied" or data.strip() == "no_free_ch":
|
||||||
|
print("Retrying OTAA connection")
|
||||||
|
self.retry(self.join)
|
||||||
|
elif data.strip() == "accepted":
|
||||||
|
print("UPDATING STATE to connected")
|
||||||
|
self.state = ConnectionState.CONNECTED
|
||||||
|
|
||||||
|
def connection_lost(self, exc):
|
||||||
|
"""
|
||||||
|
Called when serial connection is severed to device
|
||||||
|
"""
|
||||||
|
if exc:
|
||||||
|
print(exc)
|
||||||
|
print("Lost connection to serial device")
|
||||||
|
|
||||||
|
def send_cmd(self, cmd, delay=.5):
|
||||||
|
print(cmd)
|
||||||
|
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 protocol.state < ConnectionState.FAILED:
|
||||||
|
if protocol.state != ConnectionState.CONNECTED:
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
protocol.send_cmd("mac tx uncnf 1 %d" % int(time.time()))
|
||||||
|
time.sleep(10)
|
||||||
|
exit(protocol.state)
|
||||||
1
rn2903-lorawan.txt
Normal file
1
rn2903-lorawan.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python3 lorawan.py --joinmode otaa --appkey "814BFA6E589EE49376628B0CDD642E1F" --deveui "70B3D57ED80022D3" --appeui 0000000000000000 /dev/tty.usbserial-1140
|
||||||
@@ -81,8 +81,11 @@
|
|||||||
let cell4 = mainRow.insertCell();
|
let cell4 = mainRow.insertCell();
|
||||||
cell1.innerHTML = key;
|
cell1.innerHTML = key;
|
||||||
cell2.innerHTML = data[key][0][0]; // Frequency (from the first entry)
|
cell2.innerHTML = data[key][0][0]; // Frequency (from the first entry)
|
||||||
cell3.innerHTML = data[key][0][1]; // Signal Strength (from the first entry)
|
|
||||||
|
// Check for RSSI value and display 'unknown' if it is 0
|
||||||
|
let rssiValue = data[key][0][1];
|
||||||
|
cell3.innerHTML = rssiValue === 0 ? 'unknown' : rssiValue; // Signal Strength (from the first entry)
|
||||||
|
|
||||||
// Create a Bootstrap styled button
|
// Create a Bootstrap styled button
|
||||||
let expandBtn = document.createElement('button');
|
let expandBtn = document.createElement('button');
|
||||||
expandBtn.classList.add('btn', 'btn-secondary', 'btn-sm'); // Bootstrap button classes
|
expandBtn.classList.add('btn', 'btn-secondary', 'btn-sm'); // Bootstrap button classes
|
||||||
@@ -90,21 +93,21 @@
|
|||||||
expandBtn.onclick = function() {
|
expandBtn.onclick = function() {
|
||||||
let deviceKey = key; // Capture the current device key
|
let deviceKey = key; // Capture the current device key
|
||||||
let isExpanded = !expandedRows[deviceKey]; // Toggle the expanded state
|
let isExpanded = !expandedRows[deviceKey]; // Toggle the expanded state
|
||||||
|
|
||||||
// Show or hide the expandable rows
|
// Show or hide the expandable rows
|
||||||
let nextRow = mainRow.nextSibling;
|
let nextRow = mainRow.nextSibling;
|
||||||
while (nextRow && nextRow.classList.contains('expandable-row')) {
|
while (nextRow && nextRow.classList.contains('expandable-row')) {
|
||||||
nextRow.style.display = isExpanded ? 'table-row' : 'none';
|
nextRow.style.display = isExpanded ? 'table-row' : 'none';
|
||||||
nextRow = nextRow.nextSibling;
|
nextRow = nextRow.nextSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the button text and expandedRows object
|
// Update the button text and expandedRows object
|
||||||
expandBtn.innerHTML = isExpanded ? 'Hide Values' : 'Show Values';
|
expandBtn.innerHTML = isExpanded ? 'Hide Values' : 'Show Values';
|
||||||
expandedRows[deviceKey] = isExpanded;
|
expandedRows[deviceKey] = isExpanded;
|
||||||
};
|
};
|
||||||
cell4.appendChild(expandBtn);
|
cell4.appendChild(expandBtn);
|
||||||
cell4.style.textAlign = 'center'; // Center align the button
|
cell4.style.textAlign = 'center'; // Center align the button
|
||||||
|
|
||||||
// Add expandable rows for each decoded value
|
// Add expandable rows for each decoded value
|
||||||
data[key].forEach(entry => {
|
data[key].forEach(entry => {
|
||||||
let expandableRow = tableBody.insertRow();
|
let expandableRow = tableBody.insertRow();
|
||||||
@@ -114,7 +117,7 @@
|
|||||||
cell.colSpan = "4";
|
cell.colSpan = "4";
|
||||||
cell.innerHTML = `Decoded Value: ${entry[2]}`;
|
cell.innerHTML = `Decoded Value: ${entry[2]}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (expandedRows[key]) {
|
if (expandedRows[key]) {
|
||||||
let nextRow = mainRow.nextSibling;
|
let nextRow = mainRow.nextSibling;
|
||||||
while (nextRow && nextRow.classList.contains('expandable-row')) {
|
while (nextRow && nextRow.classList.contains('expandable-row')) {
|
||||||
@@ -126,15 +129,15 @@
|
|||||||
})
|
})
|
||||||
.catch(error => console.error('Error:', error));
|
.catch(error => console.error('Error:', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial update of the table
|
// Initial update of the table
|
||||||
updateTableData();
|
updateTableData();
|
||||||
|
|
||||||
// Periodically update the table every 30 seconds (30000 milliseconds)
|
// Periodically update the table every 30 seconds (30000 milliseconds)
|
||||||
setInterval(updateTableData, 30000);
|
setInterval(updateTableData, 30000);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
<hr class="m-0" />
|
<hr class="m-0" />
|
||||||
|
|
||||||
|
|||||||
@@ -79,46 +79,51 @@
|
|||||||
let selectedDeviceName = null; // Global variable to store the selected device name
|
let selectedDeviceName = null; // Global variable to store the selected device name
|
||||||
let dataCache = {}; // Cache for storing fetched data
|
let dataCache = {}; // Cache for storing fetched data
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
let isRowSelected = selectedDeviceName !== null;
|
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 isRowSelected = selectedDeviceName !== null;
|
||||||
let row = tableBody.insertRow();
|
|
||||||
row.addEventListener('click', function() {
|
|
||||||
// Handle row click event for selection
|
|
||||||
handleRowSelection(row, key);
|
|
||||||
});
|
|
||||||
|
|
||||||
let cell1 = row.insertCell();
|
for (let key in data) {
|
||||||
let cell2 = row.insertCell();
|
let row = tableBody.insertRow();
|
||||||
let cell3 = row.insertCell();
|
row.addEventListener('click', function() {
|
||||||
cell1.innerHTML = key; // Device Name
|
// Handle row click event for selection
|
||||||
|
handleRowSelection(row, key);
|
||||||
// Assuming that the latest data is the most relevant
|
});
|
||||||
let latestData = data[key][data[key].length - 1];
|
|
||||||
cell2.innerHTML = latestData[0]; // Frequency
|
|
||||||
cell3.innerHTML = latestData[1]; // Signal Strength
|
|
||||||
|
|
||||||
// Apply hiding logic based on selection
|
let cell1 = row.insertCell();
|
||||||
if (isRowSelected) {
|
let cell2 = row.insertCell();
|
||||||
if (key !== selectedDeviceName) {
|
let cell3 = row.insertCell();
|
||||||
row.classList.add('hidden-row');
|
cell1.innerHTML = key; // Device Name
|
||||||
} else {
|
|
||||||
row.classList.add('selected-row');
|
// Assuming that the latest data is the most relevant
|
||||||
}
|
let latestData = data[key][data[key].length - 1];
|
||||||
|
cell2.innerHTML = latestData[0]; // Frequency
|
||||||
|
|
||||||
|
// Check for RSSI value and display 'unknown' if it is 0
|
||||||
|
let rssiValue = latestData[1];
|
||||||
|
cell3.innerHTML = rssiValue === 0 ? 'unknown' : rssiValue; // Signal Strength
|
||||||
|
|
||||||
|
// Apply hiding logic based on selection
|
||||||
|
if (isRowSelected) {
|
||||||
|
if (key !== selectedDeviceName) {
|
||||||
|
row.classList.add('hidden-row');
|
||||||
|
} else {
|
||||||
|
row.classList.add('selected-row');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateSelectedDataDisplay(); // Update the selected data display after refreshing the table
|
updateSelectedDataDisplay(); // Update the selected data display after refreshing the table
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error:', error));
|
.catch(error => console.error('Error:', error));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRowSelection(row, key) {
|
function handleRowSelection(row, key) {
|
||||||
// Reset all rows
|
// Reset all rows
|
||||||
|
|||||||
22
udp-listener.py
Normal file
22
udp-listener.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import socket
|
||||||
|
|
||||||
|
# Define the IP address and the port number to listen on.
|
||||||
|
# '' means the script will listen on all available IPs.
|
||||||
|
IP = '10.130.1.235'
|
||||||
|
PORT = 1700
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Create a UDP socket
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
||||||
|
# Bind the socket to the address and port
|
||||||
|
s.bind((IP, PORT))
|
||||||
|
print(f"Listening for UDP traffic on port {PORT}...")
|
||||||
|
|
||||||
|
# Continuously listen for UDP packets
|
||||||
|
while True:
|
||||||
|
# Receive data from the client
|
||||||
|
data, addr = s.recvfrom(1024) # buffer size is 1024 bytes
|
||||||
|
print(f"Received message from {addr}: {data}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user