bluer 0.17.4

BlueR: official Rust interface to the Linux Bluetooth protocol stack (BlueZ)
Documentation
//! 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<String>,
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    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::<SensorModel, 1, 1>::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<const N: usize>(
        &self, _: PropertyId, xmit: &mut heapless::Vec<u8, N>,
    ) -> 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<Option<Self::Message>, 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<const N: usize>(
        &self, _xmit: &mut heapless::Vec<u8, N>,
    ) -> Result<(), InsufficientBuffer> {
        unimplemented!();
    }
}