//! Attach and send/receive BT Mesh messages //! //! Example meshd //! [bluer/bluer]$ sudo /usr/libexec/bluetooth/bluetooth-meshd --config ${PWD}/examples/meshd/config --storage ${PWD}/examples/meshd/lib --debug //! //! Example receive //! [bluer/bluer]$ RUST_LOG=TRACE cargo +nightly run --features=mesh --example mesh_sensor_client -- --token 7eb48c91911361da //! //! Example send //! [bluer/bluer]$ RUST_LOG=TRACE cargo +nightly run --features=mesh --example mesh_sensor_server -- --token dae519a06e504bd3 use bluer::mesh::{ application::{Application, ApplicationMessage}, element::*, }; use btmesh_common::{opcode::Opcode, CompanyIdentifier, InsufficientBuffer, ModelIdentifier, ParseError}; use btmesh_models::{ sensor::{ PropertyId, SensorClient, SensorConfig, SensorData, SensorDescriptor, SensorMessage, SENSOR_CLIENT, }, Message, Model, }; use clap::Parser; use futures::{pin_mut, StreamExt}; use std::time::Duration; use tokio::{signal, sync::mpsc, time::sleep}; use tokio_stream::wrappers::ReceiverStream; use uuid::Uuid; #[derive(Parser)] #[clap(author, version, about, long_about = None)] struct Args { #[clap(short, long)] token: Option, } #[tokio::main(flavor = "current_thread")] async fn main() -> Result<(), Box> { env_logger::init(); let args = Args::parse(); let session = bluer::Session::new().await?; let mesh = session.mesh().await?; let (element_control, element_handle) = element_control(5); let (app_tx, app_rx) = mpsc::channel(1); let sim = Application { device_id: Uuid::new_v4(), elements: vec![Element { location: None, models: vec![SENSOR_CLIENT], control_handle: Some(element_handle), }], events_tx: app_tx, provisioner: None, agent: Default::default(), properties: Default::default(), }; let registered = mesh.application(sim.clone()).await?; match args.token { Some(token) => { println!("Attaching with {}", token); Some(mesh.attach(sim.clone(), &token).await?); } None => { println!("Joining device: {}", sim.device_id.as_simple()); mesh.join(sim.clone()).await?; } }; println!("Sensor client ready. Press Ctrl+C to quit."); pin_mut!(element_control); let mut app_stream = ReceiverStream::new(app_rx); loop { tokio::select! { _ = signal::ctrl_c() => break, evt = element_control.next() => { match evt { Some(msg) => { match msg { ElementEvent::MessageReceived(received) => { match SensorClient::::parse(&received.opcode, &received.parameters).map_err(|_| std::fmt::Error)? { Some(message) => { match message { SensorMessage::Status(status) => { println!("Received {:?}", status.data); }, _ => todo!(), } }, None => todo!() } }, ElementEvent::DevKeyMessageReceived(_) => { todo!() } } }, None => break, } }, app_evt = app_stream.next() => { match app_evt { Some(msg) => { match msg { ApplicationMessage::JoinComplete(token) => { println!("Joined with token {:016x}", token); println!("Attaching"); let _node = mesh.attach(sim.clone(), &format!("{:016x}", token)).await?; }, ApplicationMessage::JoinFailed(reason) => { println!("Failed to join: {}", reason); break; }, } }, None => break, } } } } drop(registered); sleep(Duration::from_secs(1)).await; Ok(()) } #[derive(Clone, Debug)] pub struct SensorModel; #[derive(Clone, Debug, Default)] pub struct Temperature(f32); impl SensorConfig for SensorModel { type Data = Temperature; const DESCRIPTORS: &'static [SensorDescriptor] = &[SensorDescriptor::new(PropertyId(0x4F), 1)]; } impl SensorData for Temperature { fn decode(&mut self, id: PropertyId, params: &[u8]) -> Result<(), ParseError> { if id.0 == 0x4F { self.0 = params[0] as f32 / 2.0; Ok(()) } else { Err(ParseError::InvalidValue) } } fn encode( &self, _: PropertyId, xmit: &mut heapless::Vec, ) -> Result<(), InsufficientBuffer> { xmit.extend_from_slice(&self.0.to_le_bytes()).map_err(|_| InsufficientBuffer)?; Ok(()) } } const COMPANY_IDENTIFIER: CompanyIdentifier = CompanyIdentifier(0x05F1); const COMPANY_MODEL: ModelIdentifier = ModelIdentifier::Vendor(COMPANY_IDENTIFIER, 0x0001); #[derive(Clone, Debug)] pub struct VendorModel; impl Model for VendorModel { const IDENTIFIER: ModelIdentifier = COMPANY_MODEL; type Message = VendorMessage; fn parse(_opcode: &Opcode, _parameters: &[u8]) -> Result, ParseError> { unimplemented!(); } } #[derive(Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum VendorMessage {} impl Message for VendorMessage { fn opcode(&self) -> Opcode { unimplemented!(); } fn emit_parameters( &self, _xmit: &mut heapless::Vec, ) -> Result<(), InsufficientBuffer> { unimplemented!(); } }