scan wireless networks & publish over ble

does not actually connect yet
This commit is contained in:
2026-02-02 21:19:39 +00:00
parent 938cb4fda0
commit 2cfe436ac9
4 changed files with 110 additions and 42 deletions
+41 -8
View File
@@ -3,26 +3,59 @@ import readline
import rlcompleter
import asyncio
from bleak import BleakClient,BleakScanner
import sys
readline.parse_and_bind("tab: complete")
address = "FF:E4:05:1A:8F:FF"
CURRENT_INDEX_UUID = "76be25c2-0803-44fc-a97c-bcb56c69c926"
UUIDS = {
'connection_state': "76be25c2-0801-44fc-a97c-bcb56c69c926",
'max_index': "76be25c2-0802-44fc-a97c-bcb56c69c926",
'current_index': "76be25c2-0803-44fc-a97c-bcb56c69c926",
'current_network': "76be25c2-0804-44fc-a97c-bcb56c69c926",
'secret': "76be25c2-0805-44fc-a97c-bcb56c69c926",
}
networks = []
max_index = 0
async def show_networks(client):
global max_index
global networks
max_index = ord(await client.read_gatt_char(UUIDS['max_index']))
print(f"{max_index} networks available")
networks = [None]
for i in range(1, max_index + 1):
await client.write_gatt_char(UUIDS['current_index'], bytes([i]))
current_network = await client.read_gatt_char(UUIDS['current_network'])
networks.append(current_network)
print(f"{i}: {current_network}")
async def choose_network(client, name):
for i in range(1, max_index + 1):
if networks[i].find(name) >= 0:
print(f"found {name} in {networks[i]}")
chosen = i
break
if chosen:
await client.write_gatt_char(UUIDS['current_index'], bytes([chosen]))
new_index = await client.read_gatt_char(UUIDS['current_index'])
print(f"set to {new_index[0]}")
async def main(address):
print("go")
preferred = sys.argv[1] if len(sys.argv) > 1 else None
print(f"choose {preferred}")
devices = await BleakScanner.discover()
for d in devices:
print(d)
async with BleakClient(address, timeout=30) as client:
current_index = await client.read_gatt_char(CURRENT_INDEX_UUID)
print(f"Model Number: {current_index}")
current_index = ord(current_index) + 1
await client.write_gatt_char(CURRENT_INDEX_UUID, bytes([current_index]))
current_index = await client.read_gatt_char(CURRENT_INDEX_UUID)
print(f"Model Number: {current_index}")
await show_networks(client)
if preferred != None:
await choose_network(client, preferred.encode(encoding="utf-8"))
asyncio.run(main(address))
+29 -6
View File
@@ -10,6 +10,7 @@ use esp_backtrace as _;
use esp_println as _;
use esp_alloc as _;
use alloc::vec::Vec;
pub mod ecu;
pub mod wifi;
@@ -27,15 +28,19 @@ use embassy_executor::Spawner;
use embassy_futures::join::join3;
use embassy_time::Timer;
use esp_radio::Controller;
use esp_radio::{
Controller,
wifi::{
ClientConfig,
ModeConfig,
}
};
use log::{info};
use crate::ecu::Ecu;
use crate::ota::Flasher;
extern crate alloc;
// This creates a default app-descriptor required by the esp-idf bootloader.
@@ -86,13 +91,31 @@ async fn main(s : Spawner) {
let esp_radio_ctrl = // esp_radio::init().expect("esp_radio init failed");
&*mk_static!(Controller<'static>, esp_radio::init().unwrap());
let (mut wifi_controller, interfaces) =
esp_radio::wifi::new(esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap();
let wifi_interface = interfaces.sta;
let station_config = ModeConfig::Client(ClientConfig::default());
wifi_controller.set_config(&station_config).expect("can't config wifi");
wifi_controller.start_async().await.expect("wifi failed to start");
let wifi_networks : Vec<[u8;40]> =
crate::wifi::scan_networks(&mut wifi_controller).await.into_iter().map(
|ap| {
let mut s : [u8; 40] = [0u8; 40];
s[0] = (ap.signal_strength & 0x7f) as u8;
s[1..7].copy_from_slice(&ap.bssid);
let name = ap.ssid.as_bytes();
s[8..(8+name.len())].copy_from_slice(name);
s
}
).collect();
join3(
crate::wifi::start_wifi(&s,
esp_radio_ctrl,
wifi_controller, wifi_interface,
flasher,
peripherals.WIFI,
&mut ecu),
wibble::run_ble(&esp_radio_ctrl, peripherals.BT),
wibble::run_ble(&esp_radio_ctrl, peripherals.BT, wifi_networks),
async {
loop {
Timer::after_millis(1000).await;
+27 -8
View File
@@ -6,7 +6,7 @@ use log::{warn,info};
use embassy_futures::join::join;
use embassy_futures::select::select;
use alloc::string::String;
use alloc::vec::Vec;
/// Max number of connections
const CONNECTIONS_MAX: usize = 1;
@@ -48,7 +48,8 @@ struct WifiProvisioningService {
pub async fn run_ble(radio_init: &RadioController<'static>,
peripheral: esp_hal::peripherals::BT<'_>) {
peripheral: esp_hal::peripherals::BT<'_>,
networks: Vec<[u8; 40]>) {
// let radio_init = esp_radio::init().expect("Failed to initialize Wi-Fi/BLE controller");
let connector = BleConnector::new(&radio_init, peripheral, Default::default()).expect("connector");
let controller: ExternalController<_, 20> = ExternalController::new(connector);
@@ -78,7 +79,7 @@ pub async fn run_ble(radio_init: &RadioController<'static>,
match advertise("Eculocate", &mut peripheral, &server).await {
Ok(conn) => {
// set up tasks when the connection is established to a central, so they don't run when no one is connected.
let a = gatt_events_task(&server, &conn);
let a = gatt_events_task(&server, &conn, &networks);
let b = custom_task(&server, &conn, &stack);
// run until any task ends (usually because the connection has been closed),
// then return to advertising state.
@@ -107,8 +108,16 @@ async fn ble_task<C: Controller, P: PacketPool>(mut runner: Runner<'_, C, P>) {
///
/// This function will handle the GATT events and process them.
/// This is how we interact with read and write requests.
async fn gatt_events_task<P: PacketPool>(server: &Server<'_>, conn: &GattConnection<'_, '_, P>) -> Result<(), Error> {
let current_index = server.wifi_provisioning_service.current_network_index;
async fn gatt_events_task<P: PacketPool>(server: &Server<'_>,
conn: &GattConnection<'_, '_, P>,
networks: &Vec<[u8; 40]> ) -> Result<(), Error> {
let wps = &server.wifi_provisioning_service;
for ap in networks {
info!("ap {:?}", ap)
};
let max_index : u8 = (networks.len() & 0xff).try_into().unwrap();
server.set(&wps.max_network_index, &max_index);
let current_index = wps.current_network_index;
let reason = loop {
match conn.next().await {
GattConnectionEvent::Disconnected { reason } => break reason,
@@ -123,10 +132,20 @@ async fn gatt_events_task<P: PacketPool>(server: &Server<'_>, conn: &GattConnect
// }
// }
GattEvent::Write(event) => {
info!("[gatt] write handle {:?}", event.handle());
info!("[gatt] write handle {:?} {:?}", event.handle(),
event.data());
if event.handle() == current_index.handle {
info!("[gatt] switch current index: {:?}", event.data());
}
let i = (event.data()[0]) as usize;
info!("[gatt] switch current index: {:?}", i);
if i == 0 {
server.set(&wps.current_network, &[0u8;40]);
} else if i <= networks.len() {
server.set(&wps.current_network,
&(networks[i - 1]));
} else {
warn!("index {:?} out of range", i);
}
}
},
_ => {}
};
+13 -20
View File
@@ -28,7 +28,7 @@ use esp_hal::{
};
use esp_println::println;
use esp_radio::{
Controller,
// Controller,
wifi::{
ClientConfig,
ModeConfig,
@@ -37,6 +37,7 @@ use esp_radio::{
WifiDevice,
WifiEvent,
WifiStaState,
AccessPointInfo
},
};
@@ -130,26 +131,27 @@ impl SessionStore {
}
}
pub async fn scan_networks(controller: &mut WifiController<'_>) -> Vec<AccessPointInfo> {
println!("Scan");
let scan_config = ScanConfig::default().with_max(10);
let result = controller
.scan_with_config_async(scan_config)
.await
.expect("scan failed");
result
}
pub async fn start_wifi(spawner: &Spawner,
esp_radio_ctrl: &'static Controller<'static>,
controller: WifiController<'static>,
wifi_interface: WifiDevice<'static>,
flasher: crate::ota::Flasher<'_>,
wifi_peripheral: esp_hal::peripherals::WIFI<'static>,
ecu: &mut crate::ecu::Ecu<'_>) {
let (controller, interfaces) =
esp_radio::wifi::new(esp_radio_ctrl, wifi_peripheral, Default::default()).unwrap();
let wifi_interface = interfaces.sta;
let config = embassy_net::Config::dhcpv4(Default::default());
let rng = Rng::new();
let seed = (rng.random() as u64) << 32 | rng.random() as u64;
// Init network stack
let (stack, runner) = embassy_net::new(
wifi_interface,
@@ -227,15 +229,6 @@ async fn connection(mut controller: WifiController<'static>) {
controller.set_config(&station_config).unwrap();
controller.start_async().await.expect("wifi controller failed to start");
println!("Scan");
let scan_config = ScanConfig::default().with_max(10);
let result = controller
.scan_with_config_async(scan_config)
.await
.unwrap();
for ap in result {
println!("{:?}", ap);
}
}
println!("About to connect...");
let station_config = ModeConfig::Client(