mirror of
https://github.com/liamcottle/reticulum-meshchat.git
synced 2026-04-27 16:10:32 +00:00
Compare commits
5 commits
master
...
feature/bl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6100a3bdff | ||
|
|
3aaebfccba | ||
|
|
4970d5088f | ||
|
|
7c5235845a | ||
|
|
b1c3cc767c |
3 changed files with 75 additions and 1 deletions
41
meshchat.py
41
meshchat.py
|
|
@ -13,11 +13,13 @@ import RNS
|
|||
import RNS.vendor.umsgpack as msgpack
|
||||
import LXMF
|
||||
from LXMF import LXMRouter
|
||||
from RNS.Interfaces.RNodeInterface import BLEConnection
|
||||
from aiohttp import web, WSMessage, WSMsgType, WSCloseCode
|
||||
import asyncio
|
||||
import base64
|
||||
import webbrowser
|
||||
|
||||
from bleak import BleakScanner
|
||||
from peewee import SqliteDatabase
|
||||
from serial.tools import list_ports
|
||||
|
||||
|
|
@ -317,6 +319,45 @@ class ReticulumMeshChat:
|
|||
"comports": comports,
|
||||
})
|
||||
|
||||
# scan for rnodes available via ble
|
||||
@routes.get("/api/v1/rnodes/ble-scan")
|
||||
async def index(request):
|
||||
|
||||
# determine how long we should scan for
|
||||
scan_duration_seconds = int(request.query.get("scan_duration_seconds", 3))
|
||||
|
||||
# discover ble devices
|
||||
ble_scan_results = await BleakScanner.discover(
|
||||
timeout=scan_duration_seconds,
|
||||
return_adv=True,
|
||||
cb=dict(use_bdaddr=True),
|
||||
service_uuids=[
|
||||
BLEConnection.UART_SERVICE_UUID,
|
||||
],
|
||||
)
|
||||
|
||||
# format scan results
|
||||
rnodes = []
|
||||
for ble_address in ble_scan_results:
|
||||
|
||||
# get device and advertisement data from scan result
|
||||
device, advertisement_data = ble_scan_results[ble_address]
|
||||
|
||||
# skip this result if advertisement data is unavailable
|
||||
if advertisement_data is None:
|
||||
continue
|
||||
|
||||
rnodes.append({
|
||||
"name": device.name,
|
||||
"local_name": advertisement_data.local_name,
|
||||
"ble_address": device.address,
|
||||
"port": "ble://" + advertisement_data.local_name,
|
||||
})
|
||||
|
||||
return web.json_response({
|
||||
"rnodes": rnodes,
|
||||
})
|
||||
|
||||
# fetch reticulum interfaces
|
||||
@routes.get("/api/v1/reticulum/interfaces")
|
||||
async def index(request):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
aiohttp>=3.9.5
|
||||
bleak>=0.22.3
|
||||
cx_freeze>=7.0.0
|
||||
lxmf>=0.5.8
|
||||
peewee>=3.17.3
|
||||
|
|
|
|||
|
|
@ -117,8 +117,15 @@
|
|||
<div v-if="newInterfaceType === 'RNodeInterface'" class="mb-2">
|
||||
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-zinc-100">Port</label>
|
||||
<select v-model="newInterfacePort" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-zinc-900 dark:border-zinc-600 dark:text-white dark:focus:ring-blue-600 dark:focus:border-blue-600">
|
||||
<option disabled>Serial Devices ({{ comports.length }})</option>
|
||||
<option v-for="comport of comports" :value="comport.device">{{ comport.device }} (Product: {{ comport.product ?? '?' }}, Serial: {{ comport.serial ?? '?' }})</option>
|
||||
<option disabled>Bluetooth Devices ({{ rnodes.length }})</option>
|
||||
<option v-for="rnode of rnodes" :value="rnode.port">{{ rnode.port }} ({{ rnode.ble_address }})</option>
|
||||
</select>
|
||||
<div class="text-xs text-gray-600">
|
||||
<span v-if="isLoadingRnodes" class="text-gray-500">Discovering Bluetooth RNodes...</span>
|
||||
<span v-else @click="loadRnodes" class="text-blue-500 underline cursor-pointer">Discover Bluetooth RNodes</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- interface frequency -->
|
||||
|
|
@ -184,6 +191,9 @@ export default {
|
|||
config: null,
|
||||
|
||||
comports: [],
|
||||
rnodes: [],
|
||||
|
||||
isLoadingRnodes: false,
|
||||
|
||||
newInterfaceName: null,
|
||||
newInterfaceType: null,
|
||||
|
|
@ -243,6 +253,7 @@ export default {
|
|||
|
||||
this.getConfig();
|
||||
this.loadComports();
|
||||
this.loadRnodes();
|
||||
|
||||
// check if we are editing an interface
|
||||
const interfaceName = this.$route.query.interface_name;
|
||||
|
|
@ -276,9 +287,30 @@ export default {
|
|||
const response = await window.axios.get(`/api/v1/comports`);
|
||||
this.comports = response.data.comports;
|
||||
} catch(e) {
|
||||
// do nothing if failed to load interfaces
|
||||
// do nothing if failed to load comports
|
||||
}
|
||||
},
|
||||
async loadRnodes() {
|
||||
|
||||
// do nothing if already loading
|
||||
if(this.isLoadingRnodes){
|
||||
return;
|
||||
}
|
||||
|
||||
// show loading
|
||||
this.isLoadingRnodes = true;
|
||||
|
||||
try {
|
||||
const response = await window.axios.get(`/api/v1/rnodes/ble-scan`);
|
||||
this.rnodes = response.data.rnodes;
|
||||
} catch(e) {
|
||||
// do nothing if failed to load rnodes
|
||||
} finally {
|
||||
// no longer loading
|
||||
this.isLoadingRnodes = false;
|
||||
}
|
||||
|
||||
},
|
||||
async loadInterfaceToEdit(interfaceName) {
|
||||
try {
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue