Comments (20)
@jhartzell42 done
from bluer.
You are right, and you made me see things from a different perspective.
Looking at the API documentation, we must register the root endpoint once and add the AdvertisementMonitor1 interface underneath it multiple times.
Instead, we are adding the root endpoint for every monitor we register.
And this is also the problem with the crossroad. Every time we add the same path again, it replaces the old one and loses the previous child structure. In the end, it will have only the last monitor as a child, and the previous ones will stop working.
With that in mind, I made another proposal, one where we register the monitor once and then add as many rules as we want.
I created a new branch for it:
https://github.com/otaviojr/bluer/tree/monitor1
And here is the code I used to try it out.
if let Ok(mut monitor_handle) = adapter.register_monitor().await {
monitor_handle.add_monitor(Monitor {
activate: Some(Box::new(move || {
Box::pin(async {
println!("Monitor 1: Activate funcion called");
Ok(())
})
})),
release: Some(Box::new(move || {
Box::pin(async {
println!("Monitor 1: Release funcion called");
Ok(())
})
})),
device_found: Some(Box::new(move |device| {
Box::pin(async move {
println!("Monitor 1: DeviceFound funcion called: {}",device.addr);
Ok(())
})
})),
patterns: Some(vec!(Pattern {
start_position: 2,
ad_data_type: 0xff,
content_of_pattern: vec!(190, 172, 57, 237, 152, 255, 41, 0, 68, 26, 128, 47, 156, 57, 143, 193, 153, 210, 0, 1, 0, 100, 197, 100)
})),
rssi_low_threshold: Some(127),
rssi_high_threshold: Some(127),
rssi_low_timeout: Some(0),
rssi_high_timeout: Some(0),
..Default::default()
}).await;
monitor_handle.add_monitor(Monitor {
activate: Some(Box::new( move || {
Box::pin(async {
println!("Monitor 2: Activate funcion called");
Ok(())
})
})),
release: Some(Box::new( move || {
Box::pin(async {
println!("Monitor 2: Release funcion called");
Ok(())
})
})),
device_found: Some(Box::new(move |device| {
Box::pin(async move {
println!("Monitor 2: DeviceFound funcion called: {}",device.addr);
Ok(())
})
})),
patterns: Some(vec!(Pattern {
start_position: 2,
ad_data_type: 0xff,
content_of_pattern: vec!(190, 172, 57, 237, 152, 255, 41, 0, 68, 26, 128, 47, 156, 57, 143, 193, 153, 210, 0, 1, 0, 100, 197, 100)
})),
rssi_low_threshold: Some(127),
rssi_high_threshold: Some(127),
rssi_low_timeout: Some(0),
rssi_high_timeout: Some(0),
..Default::default()
}).await;
}
With this code, I have been able to receive events for both monitors.
Monitor 1: DeviceFound funcion called: 60:68:4E:15:18:25
Monitor 2: DeviceFound funcion called: 60:68:4E:15:18:25
And the dbus objects's paths are now following what has been suggested in the API documentation.
PS: I borrowed some pieces of your code, especially the one that handles the or_patterns, which are much better than mine. Thanks for that.
regards,
Otávio Ribeiro
from bluer.
This would probably be provided by the advertisement monitoring api which is indeed not yet implemented in BlueR.
from bluer.
I'm working on this for a few days now, it's not working yet. It should, but bluez is not calling the callback functions.
Maybe something with bluez?
I compiled the latest version manually since monitoring API is something new.
I forked bluer:
https://github.com/otaviojr/bluer/tree/monitor
The code is simple:
callbacks:
pub fn activate_fn() -> Pin<Box<dyn Future<Output = bluer::monitor::ReqResult<()>> + Send>> {
println!("Activate funcion called(1)");
Box::pin(async {
println!("Activate funcion called(2)");
Ok(())
})
}
pub fn release_fn() -> Pin<Box<dyn Future<Output = bluer::monitor::ReqResult<()>> + Send>> {
println!("Release funcion called(1)");
Box::pin(async {
println!("Release funcion called(2)");
Ok(())
})
}
pub fn device_found_fn(device: DeviceFound) -> Pin<Box<dyn Future<Output = bluer::monitor::ReqResult<()>> + Send>> {
println!("DeviceFound funcion called(1)");
Box::pin(async {
println!("DeviceFound funcion called(2)");
Ok(())
})
}
code:
if let Ok(monitor_handle) = adapter.register_monitor(Monitor {
activate: Some(Box::new(BlueZ::activate_fn)),
release: Some(Box::new(BlueZ::release_fn)),
device_found: Some(Box::new(BlueZ::device_found_fn)),
patterns: Some((0x00, 0xff,vec![0xbe,0xac])),
..Default::default()
}).await { ...
Now, a few things on bluer may complicate things further.
BlueR changes some filters on discover_devices on the user's behalf, it doesn't allow duplicates, which could be a problem with beacons, and it does not allow us to choose a LE scan only.
I think discover_devices is not necessary with passive scan, but if they work simultaneously, it could be a problem with beacons. I don't know.
And sorry if my Rust code is not state of the art. I'm relatively new to Rust.. just trying to do my best here.
regards,
Otávio Ribeiro
from bluer.
Oh, and I'm having a hard time with those or_patterns as well... but I will figure them out eventually.
from bluer.
I also started a prototype a while ago, but forgot to post it here: lopsided98/bluer@master...adv-mon
It works, but currently only supports one monitor at a time. The monitor root can only contain a single monitor right now because dbus-crossroads seems to only support sending added/removed signals for the root ObjectManager, so I can't tell BlueZ when a new monitor was added.
I also found that adjusting any of the RSSI settings broke the monitor (I forget the exact details, but most of the time I would just get no notifications), and I was never able to get the DeviceLost callback to work reliably. These both appear to be BlueZ issues.
Despite these issues, I was to get it working well for my application. To reliably get notifications when a device starts reappears after disappearing for a while, I have to re-register the monitor. My application code can be found here: https://github.com/lopsided98/WaterLevelMonitor/blob/54e8bc2219d0ef33d84bb9c4fb57ed287cb848a3/base_station/src/sensor.rs#L185
from bluer.
I managed to make it to work. At least receiving the Activate/Release callbacks.
It was the object manager indeed. Once I implemented it on the monitor interface things started to work.
I managed to implement object manager at the monitor path, so, in my version, you can have more than one monitor, as many as bluez allows. At least, in theory, I will make more tests on it. If you want to get a look at it, maybe you could allow more than one monitor on your version as well.
Now, I need to finish the DeviceFound and DeviceLost endpoints and I think it will be good to go.
regards,
Otávio Ribeiro
from bluer.
It looks like you are still calling RegisterMonitor
and UnregisterMonitor
for each monitor, right? If the object manager signals are working, you should be able to register the root once (with RegisterMonitor
) and then just add monitors under that root through the object manager.
from bluer.
I made the last commit with those changes....
I'm implementing the object manager at the root level, but my root level is the uuid. The AdvertisementMonitor1 interface is one level above the uuid...
that allows you to have multiple monitors.
object manager -> /org/bluez/bluer/monitor/4e7adc5601864010bf393486740bbe92
AdvertisementMonitor1 -> /org/bluez/bluer/monitor/4e7adc5601864010bf393486740bbe92/app
pub(crate) async fn register(self, inner: Arc<SessionInner>, adapter_name: &str) -> Result<MonitorHandle> {
let manager_path = dbus::Path::new(format!("{}/{}", MANAGER_PATH, adapter_name)).unwrap();
let uuid = Uuid::new_v4().as_simple().to_string();
let root = dbus::Path::new(format!("{}/{}",MONITOR_PREFIX,uuid)).unwrap();
let name = dbus::Path::new(format!("{}/{}/app",MONITOR_PREFIX,uuid)).unwrap();
log::trace!("Publishing monitor at {}", &name);
{
let mut cr = inner.crossroads.lock().await;
let object_manager_token = cr.object_manager();
let introspectable_token = cr.introspectable();
let properties_token = cr.properties();
cr.insert(root.clone(), [&object_manager_token, &introspectable_token, &properties_token], {});
cr.insert(name.clone(), [&inner.monitor_token], Arc::new(self));
}
log::trace!("Registering monitor at {}", &name);
let proxy = Proxy::new(SERVICE_NAME, manager_path, TIMEOUT, inner.connection.clone());
proxy.method_call(MANAGER_INTERFACE, "RegisterMonitor", (root.clone(),)).await?;
let (drop_tx, drop_rx) = oneshot::channel();
let unreg_name = root.clone();
tokio::spawn(async move {
let _ = drop_rx.await;
log::trace!("Unregistering monitor at {}", &unreg_name);
let _: std::result::Result<(), dbus::Error> =
proxy.method_call(MANAGER_INTERFACE, "UnregisterMonitor", (unreg_name.clone(),)).await;
log::trace!("Unpublishing monitor at {}", &unreg_name);
let mut cr = inner.crossroads.lock().await;
let _: Option<Self> = cr.remove(&unreg_name);
});
Ok(MonitorHandle { name, _drop_tx: drop_tx })
}
regards,
Otávio Ribeiro
from bluer.
Yeah, I guess that works, but it doesn't seem to be the how the advertisement monitor API is intended to be used. The documentation implies that you are supposed to create a single root object manager per application and then create multiple monitors underneath that, using the object manager signals to tell BlueZ that they were added/removed.
from bluer.
Is this issue still open? I'm hoping to use this lib for essentially beacon advertisements, so it seems like this issue might be impactful for me?
from bluer.
I believe it is still open.
I am still waiting for feedback.
You could get my branch, update it and use it.
I've been using it for a while now, and it works well.
Regards
from bluer.
@otaviojr I got feedback pretty quickly for my (unrelated) change once I actually made a MR. Would you be willing to make a MR of your branch? If not, I can make an MR from a copy of your branch on my fork, so I can handle the feedback and make appropriate updates.
from bluer.
Could you please send a PR if you would like a review? This makes it easier for everyone.
from bluer.
OK, I made an MR on @otaviojr 's behalf...
from bluer.
If @surban would be interested, I can move this MR to my own fork and clean up the commit log as well :-)
from bluer.
OK, I made an MR on @otaviojr 's behalf...
Sorry for the delay, but thanks. If you need something, let me know...
About the commit logs, I developed them on a remote host and used git to sync code... :-(
Can be cleaned
from bluer.
@jhartzell42 I've cleaned all commit logs at https://github.com/otaviojr/bluer/tree/monitor1 branch
Can you change your pull request?
from bluer.
I can't retarget it to a different branch, and I can't modify the branch I'm using, as it's a pull request literally from your fork. Could you possibly make your own pull request from monitor1?? If not, I'll delete the one I have, make my own fork, migrate your new branch over, and make a new pull request.
from bluer.
PR merged.
from bluer.
Related Issues (20)
- BlueZ version is not verified to be compatible HOT 5
- `connect_device` fails with D-Bus error UnknownMethod HOT 1
- feature: builder pattern for application HOT 3
- agent doesn't work? HOT 2
- Can't get monitor HOT 21
- Is setting the L2CAP LE LL PDU possible? If so, how would this be done in BlueR? HOT 15
- Can setting the connection interval parameter be added? HOT 10
- Get paired/connected devices
- Peer to Peer communication HOT 1
- le_passive_scan example not working HOT 1
- Add ability to save LE Advertising Reports with bluer-tools HOT 6
- Pairing fail due to missing key distribution
- License HOT 4
- Build failure due to git clone without submodules HOT 1
- gatt_echo example: does not work HOT 6
- next release ?
- Minimal RFCOMM client example
- Unexpected Pairing Request Dialog When Connecting to GATT Server with BlueR HOT 7
- Add a command line tool for device advertising HOT 9
- advertising max/min interval being ignored HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bluer.