mirror of
https://github.com/colonelpanichacks/flock-you.git
synced 2026-06-21 10:08:24 -07:00
@@ -0,0 +1,6 @@
|
||||
|
||||
.pio/
|
||||
|
||||
.vscode/
|
||||
|
||||
.DS_Store
|
||||
+151
-146
@@ -249,43 +249,44 @@ def flock_reader():
|
||||
"""Background thread for reading Flock device data"""
|
||||
global flock_serial_connection, flock_device_connected, serial_data_buffer
|
||||
|
||||
while flock_device_connected:
|
||||
if flock_serial_connection and flock_serial_connection.is_open:
|
||||
try:
|
||||
line = flock_serial_connection.readline().decode('utf-8', errors='ignore')
|
||||
if line:
|
||||
line = line.strip()
|
||||
with app.app_context():
|
||||
while flock_device_connected:
|
||||
if flock_serial_connection and flock_serial_connection.is_open:
|
||||
try:
|
||||
line = flock_serial_connection.readline().decode('utf-8', errors='ignore')
|
||||
if line:
|
||||
# Store in buffer for terminal
|
||||
serial_data_buffer.append(line)
|
||||
if len(serial_data_buffer) > 1000: # Keep last 1000 lines
|
||||
serial_data_buffer.pop(0)
|
||||
|
||||
# Forward to all serial terminal clients
|
||||
safe_socket_emit('serial_data', line, room='serial_terminal')
|
||||
print(f"Serial data sent to terminal: {line}")
|
||||
|
||||
# Try to parse as detection data
|
||||
try:
|
||||
data = json.loads(line)
|
||||
if 'detection_method' in data:
|
||||
# This is a detection, add it
|
||||
add_detection_from_serial(data)
|
||||
else:
|
||||
print(f"JSON data without detection_method: {data}")
|
||||
except json.JSONDecodeError:
|
||||
# Not JSON, just log it
|
||||
print(f"Flock device (non-JSON): {line}")
|
||||
line = line.strip()
|
||||
if line:
|
||||
# Store in buffer for terminal
|
||||
serial_data_buffer.append(line)
|
||||
if len(serial_data_buffer) > 1000: # Keep last 1000 lines
|
||||
serial_data_buffer.pop(0)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Flock device read error: {e}")
|
||||
with connection_lock:
|
||||
flock_device_connected = False
|
||||
safe_socket_emit('flock_disconnected', {})
|
||||
# Trigger reconnection immediately
|
||||
attempt_reconnect_flock()
|
||||
break
|
||||
time.sleep(0.1)
|
||||
# Forward to all serial terminal clients
|
||||
safe_socket_emit('serial_data', line, room='serial_terminal')
|
||||
print(f"Serial data sent to terminal: {line}")
|
||||
|
||||
# Try to parse as detection data
|
||||
try:
|
||||
data = json.loads(line)
|
||||
if 'detection_method' in data:
|
||||
# This is a detection, add it
|
||||
add_detection_from_serial(data)
|
||||
else:
|
||||
print(f"JSON data without detection_method: {data}")
|
||||
except json.JSONDecodeError:
|
||||
# Not JSON, just log it
|
||||
print(f"Flock device (non-JSON): {line}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Flock device read error: {e}")
|
||||
with connection_lock:
|
||||
flock_device_connected = False
|
||||
safe_socket_emit('flock_disconnected', {})
|
||||
# Trigger reconnection immediately
|
||||
attempt_reconnect_flock()
|
||||
break
|
||||
time.sleep(0.1)
|
||||
|
||||
def find_best_gps_match(detection_timestamp):
|
||||
"""Find the GPS reading closest in time to the detection timestamp"""
|
||||
@@ -487,50 +488,51 @@ def connection_monitor():
|
||||
"""Background thread for monitoring device connections"""
|
||||
global gps_enabled, flock_device_connected, serial_connection, reconnect_attempts
|
||||
|
||||
while True:
|
||||
# Check GPS connection
|
||||
if gps_enabled:
|
||||
try:
|
||||
if not serial_connection or not serial_connection.is_open:
|
||||
with app.app_context():
|
||||
while True:
|
||||
# Check GPS connection
|
||||
if gps_enabled:
|
||||
try:
|
||||
if not serial_connection or not serial_connection.is_open:
|
||||
with connection_lock:
|
||||
gps_enabled = False
|
||||
safe_socket_emit('gps_disconnected', {})
|
||||
print("GPS connection lost")
|
||||
# Start reconnection attempts
|
||||
attempt_reconnect_gps()
|
||||
else:
|
||||
# Test if the connection is still valid
|
||||
serial_connection.in_waiting
|
||||
except Exception as e:
|
||||
print(f"GPS connection test failed: {e}")
|
||||
with connection_lock:
|
||||
gps_enabled = False
|
||||
safe_socket_emit('gps_disconnected', {})
|
||||
print("GPS connection lost")
|
||||
# Start reconnection attempts
|
||||
attempt_reconnect_gps()
|
||||
else:
|
||||
|
||||
# Check Flock You device connection
|
||||
if flock_device_connected:
|
||||
try:
|
||||
# Test if the connection is still valid
|
||||
serial_connection.in_waiting
|
||||
except Exception as e:
|
||||
print(f"GPS connection test failed: {e}")
|
||||
with connection_lock:
|
||||
gps_enabled = False
|
||||
safe_socket_emit('gps_disconnected', {})
|
||||
attempt_reconnect_gps()
|
||||
|
||||
# Check Flock You device connection
|
||||
if flock_device_connected:
|
||||
try:
|
||||
# Test if the connection is still valid
|
||||
if not flock_serial_connection or not flock_serial_connection.is_open:
|
||||
if not flock_serial_connection or not flock_serial_connection.is_open:
|
||||
with connection_lock:
|
||||
flock_device_connected = False
|
||||
safe_socket_emit('flock_disconnected', {})
|
||||
print("Flock You device connection lost")
|
||||
# Start reconnection attempts
|
||||
attempt_reconnect_flock()
|
||||
else:
|
||||
# Try a simple read to test connection
|
||||
flock_serial_connection.in_waiting
|
||||
except Exception as e:
|
||||
print(f"Flock device connection test failed: {e}")
|
||||
with connection_lock:
|
||||
flock_device_connected = False
|
||||
safe_socket_emit('flock_disconnected', {})
|
||||
print("Flock You device connection lost")
|
||||
# Start reconnection attempts
|
||||
attempt_reconnect_flock()
|
||||
else:
|
||||
# Try a simple read to test connection
|
||||
flock_serial_connection.in_waiting
|
||||
except Exception as e:
|
||||
print(f"Flock device connection test failed: {e}")
|
||||
with connection_lock:
|
||||
flock_device_connected = False
|
||||
safe_socket_emit('flock_disconnected', {})
|
||||
# Start reconnection attempts
|
||||
attempt_reconnect_flock()
|
||||
|
||||
time.sleep(2) # Check every 2 seconds
|
||||
|
||||
time.sleep(2) # Check every 2 seconds
|
||||
|
||||
def attempt_reconnect_flock():
|
||||
"""Attempt to reconnect to Flock device"""
|
||||
@@ -539,46 +541,47 @@ def attempt_reconnect_flock():
|
||||
def reconnect_thread():
|
||||
global flock_device_connected, reconnect_attempts, flock_serial_connection
|
||||
|
||||
while not flock_device_connected and reconnect_attempts['flock'] < max_reconnect_attempts:
|
||||
try:
|
||||
print(f"Attempting to reconnect to Flock device (attempt {reconnect_attempts['flock'] + 1}/{max_reconnect_attempts})")
|
||||
|
||||
# Try to reconnect
|
||||
if flock_serial_connection:
|
||||
try:
|
||||
flock_serial_connection.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Wait a moment for the device to be ready
|
||||
time.sleep(1)
|
||||
|
||||
flock_serial_connection = serial.Serial(flock_device_port, 115200, timeout=1)
|
||||
|
||||
# Test the connection
|
||||
test_data = flock_serial_connection.readline()
|
||||
|
||||
# If successful, update status
|
||||
with connection_lock:
|
||||
flock_device_connected = True
|
||||
reconnect_attempts['flock'] = 0
|
||||
print(f"Successfully reconnected to Flock device on {flock_device_port}")
|
||||
safe_socket_emit('flock_reconnected', {'port': flock_device_port})
|
||||
|
||||
# Restart the reading thread
|
||||
flock_thread = threading.Thread(target=flock_reader, daemon=True)
|
||||
flock_thread.start()
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
print(f"Reconnection attempt failed: {e}")
|
||||
reconnect_attempts['flock'] += 1
|
||||
time.sleep(reconnect_delay)
|
||||
|
||||
if reconnect_attempts['flock'] >= max_reconnect_attempts:
|
||||
print("Max reconnection attempts reached for Flock device")
|
||||
safe_socket_emit('reconnect_failed', {'device': 'flock'})
|
||||
reconnect_attempts['flock'] = 0 # Reset for future attempts
|
||||
with app.app_context():
|
||||
while not flock_device_connected and reconnect_attempts['flock'] < max_reconnect_attempts:
|
||||
try:
|
||||
print(f"Attempting to reconnect to Flock device (attempt {reconnect_attempts['flock'] + 1}/{max_reconnect_attempts})")
|
||||
|
||||
# Try to reconnect
|
||||
if flock_serial_connection:
|
||||
try:
|
||||
flock_serial_connection.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
# Wait a moment for the device to be ready
|
||||
time.sleep(1)
|
||||
|
||||
flock_serial_connection = serial.Serial(flock_device_port, 115200, timeout=1)
|
||||
|
||||
# Test the connection
|
||||
test_data = flock_serial_connection.readline()
|
||||
|
||||
# If successful, update status
|
||||
with connection_lock:
|
||||
flock_device_connected = True
|
||||
reconnect_attempts['flock'] = 0
|
||||
print(f"Successfully reconnected to Flock device on {flock_device_port}")
|
||||
safe_socket_emit('flock_reconnected', {'port': flock_device_port})
|
||||
|
||||
# Restart the reading thread
|
||||
flock_thread = threading.Thread(target=flock_reader, daemon=True)
|
||||
flock_thread.start()
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
print(f"Reconnection attempt failed: {e}")
|
||||
reconnect_attempts['flock'] += 1
|
||||
time.sleep(reconnect_delay)
|
||||
|
||||
if reconnect_attempts['flock'] >= max_reconnect_attempts:
|
||||
print("Max reconnection attempts reached for Flock device")
|
||||
safe_socket_emit('reconnect_failed', {'device': 'flock'})
|
||||
reconnect_attempts['flock'] = 0 # Reset for future attempts
|
||||
|
||||
thread = threading.Thread(target=reconnect_thread, daemon=True)
|
||||
thread.start()
|
||||
@@ -589,36 +592,37 @@ def attempt_reconnect_gps():
|
||||
|
||||
def reconnect_thread():
|
||||
global gps_enabled, reconnect_attempts
|
||||
|
||||
while not gps_enabled and reconnect_attempts['gps'] < max_reconnect_attempts:
|
||||
try:
|
||||
print(f"Attempting to reconnect to GPS device (attempt {reconnect_attempts['gps'] + 1}/{max_reconnect_attempts})")
|
||||
|
||||
# Try to reconnect
|
||||
test_ser = serial.Serial(serial_connection.port, GPS_BAUDRATE, timeout=1)
|
||||
test_ser.close()
|
||||
|
||||
# If successful, update status
|
||||
with connection_lock:
|
||||
gps_enabled = True
|
||||
reconnect_attempts['gps'] = 0
|
||||
print(f"Successfully reconnected to GPS device on {serial_connection.port}")
|
||||
safe_socket_emit('gps_reconnected', {'port': serial_connection.port})
|
||||
|
||||
# Restart the reading thread
|
||||
gps_thread = threading.Thread(target=gps_reader, daemon=True)
|
||||
gps_thread.start()
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
print(f"GPS reconnection attempt failed: {e}")
|
||||
reconnect_attempts['gps'] += 1
|
||||
time.sleep(reconnect_delay)
|
||||
|
||||
if reconnect_attempts['gps'] >= max_reconnect_attempts:
|
||||
print("Max reconnection attempts reached for GPS device")
|
||||
safe_socket_emit('reconnect_failed', {'device': 'gps'})
|
||||
reconnect_attempts['gps'] = 0 # Reset for future attempts
|
||||
|
||||
with app.app_context():
|
||||
while not gps_enabled and reconnect_attempts['gps'] < max_reconnect_attempts:
|
||||
try:
|
||||
print(f"Attempting to reconnect to GPS device (attempt {reconnect_attempts['gps'] + 1}/{max_reconnect_attempts})")
|
||||
|
||||
# Try to reconnect
|
||||
test_ser = serial.Serial(serial_connection.port, GPS_BAUDRATE, timeout=1)
|
||||
test_ser.close()
|
||||
|
||||
# If successful, update status
|
||||
with connection_lock:
|
||||
gps_enabled = True
|
||||
reconnect_attempts['gps'] = 0
|
||||
print(f"Successfully reconnected to GPS device on {serial_connection.port}")
|
||||
safe_socket_emit('gps_reconnected', {'port': serial_connection.port})
|
||||
|
||||
# Restart the reading thread
|
||||
gps_thread = threading.Thread(target=gps_reader, daemon=True)
|
||||
gps_thread.start()
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
print(f"GPS reconnection attempt failed: {e}")
|
||||
reconnect_attempts['gps'] += 1
|
||||
time.sleep(reconnect_delay)
|
||||
|
||||
if reconnect_attempts['gps'] >= max_reconnect_attempts:
|
||||
print("Max reconnection attempts reached for GPS device")
|
||||
safe_socket_emit('reconnect_failed', {'device': 'gps'})
|
||||
reconnect_attempts['gps'] = 0 # Reset for future attempts
|
||||
|
||||
thread = threading.Thread(target=reconnect_thread, daemon=True)
|
||||
thread.start()
|
||||
@@ -1208,13 +1212,14 @@ def handle_heartbeat():
|
||||
|
||||
def send_heartbeat():
|
||||
"""Send periodic heartbeat to all clients"""
|
||||
while True:
|
||||
try:
|
||||
safe_socket_emit('heartbeat', {})
|
||||
time.sleep(30) # Send heartbeat every 30 seconds
|
||||
except Exception as e:
|
||||
print(f"Heartbeat error: {e}")
|
||||
time.sleep(5)
|
||||
with app.app_context():
|
||||
while True:
|
||||
try:
|
||||
safe_socket_emit('heartbeat', {})
|
||||
time.sleep(30) # Send heartbeat every 30 seconds
|
||||
except Exception as e:
|
||||
print(f"Heartbeat error: {e}")
|
||||
time.sleep(5)
|
||||
|
||||
@socketio.on('request_serial_terminal')
|
||||
def handle_serial_terminal_request(data):
|
||||
|
||||
@@ -14,3 +14,20 @@ build_flags =
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DCONFIG_BT_NIMBLE_ENABLED=1
|
||||
|
||||
[env:xiao_esp32c3]
|
||||
platform = espressif32
|
||||
board = seeed_xiao_esp32c3
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
board_build.partitions = huge_app.csv
|
||||
board_build.flash_mode = qio
|
||||
board_build.flash_size = 4MB
|
||||
board_build.psram_type = opi
|
||||
lib_deps =
|
||||
h2zero/NimBLE-Arduino@^1.4.0
|
||||
bblanchon/ArduinoJson@^6.21.0
|
||||
build_flags =
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DCONFIG_BT_NIMBLE_ENABLED=1
|
||||
|
||||
+23
-11
@@ -29,7 +29,12 @@
|
||||
|
||||
// WiFi Promiscuous Mode Configuration
|
||||
#define MAX_CHANNEL 13
|
||||
#define CHANNEL_HOP_INTERVAL 2500 // milliseconds
|
||||
#define CHANNEL_HOP_INTERVAL 500 // milliseconds
|
||||
|
||||
// BLE SCANNING CONFIGURATION
|
||||
#define BLE_SCAN_DURATION 1 // Seconds
|
||||
#define BLE_SCAN_INTERVAL 5000 // Milliseconds between scans
|
||||
static unsigned long last_ble_scan = 0;
|
||||
|
||||
// Detection Pattern Limits
|
||||
#define MAX_SSID_PATTERNS 10
|
||||
@@ -58,13 +63,14 @@ static const char* mac_prefixes[] = {
|
||||
|
||||
// Flock WiFi devices
|
||||
"70:c9:4e", "3c:91:80", "d8:f3:bc", "80:30:49", "14:5a:fc",
|
||||
"74:4c:a1", "08:3a:88", "9c:2f:9d",
|
||||
"74:4c:a1", "08:3a:88", "9c:2f:9d", "94:08:53", "e4:aa:ea"
|
||||
|
||||
// Penguin devices
|
||||
"cc:09:24", "ed:c7:63", "e8:ce:56", "ea:0c:ea", "d8:8f:14",
|
||||
"f9:d9:c0", "f1:32:f9", "f6:a0:76", "e4:1c:9e", "e7:f2:43",
|
||||
"e2:71:33", "da:91:a9", "e1:0e:15", "c8:ae:87", "f4:ed:b2",
|
||||
"d8:bf:b5", "ee:8f:3c", "d7:2b:21", "ea:5a:98"
|
||||
// Penguin devices - these are NOT OUI based, so use local ouis
|
||||
// from the wigle.net db relative to your location
|
||||
// "cc:09:24", "ed:c7:63", "e8:ce:56", "ea:0c:ea", "d8:8f:14",
|
||||
// "f9:d9:c0", "f1:32:f9", "f6:a0:76", "e4:1c:9e", "e7:f2:43",
|
||||
// "e2:71:33", "da:91:a9", "e1:0e:15", "c8:ae:87", "f4:ed:b2",
|
||||
// "d8:bf:b5", "ee:8f:3c", "d7:2b:21", "ea:5a:98"
|
||||
};
|
||||
|
||||
// Device name patterns for BLE advertisement detection
|
||||
@@ -468,7 +474,7 @@ void hop_channel()
|
||||
}
|
||||
esp_wifi_set_channel(current_channel, WIFI_SECOND_CHAN_NONE);
|
||||
last_channel_hop = now;
|
||||
printf("Hopped to channel %d\n", current_channel);
|
||||
printf("[WiFi] Hopped to channel %d\n", current_channel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,9 +544,15 @@ void loop()
|
||||
}
|
||||
}
|
||||
|
||||
// Run BLE scan
|
||||
pBLEScan->start(1, false); // Scan for 1 second, don't clear results
|
||||
pBLEScan->clearResults();
|
||||
if (millis() - last_ble_scan >= BLE_SCAN_INTERVAL && !pBLEScan->isScanning()) {
|
||||
printf("[BLE] scan...\n");
|
||||
pBLEScan->start(BLE_SCAN_DURATION, false);
|
||||
last_ble_scan = millis();
|
||||
}
|
||||
|
||||
if (pBLEScan->isScanning() == false && millis() - last_ble_scan > BLE_SCAN_DURATION * 1000) {
|
||||
pBLEScan->clearResults();
|
||||
}
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user