Repository navigation
Move to btleplug 0.13.5 - #14
Merged
Merged
Conversation
…both library defects aranet works around aranet works around two defects of btleplug 0.11.8. On macOS its CoreBluetooth thread never drained an autorelease pool, so memory grew while scanning (btleplug's issue 494). On Linux a connect failed with "Service discovery timed out" when BlueZ needed more than 5 s to resolve a sensor's services (btleplug's issue 496). By its changelog, btleplug 0.13.5 fixes both: it drains a pool for every message, and through bluez-async 0.9.0 it waits 30 s. Neither effect has been measured here yet. This commit moves the dependency and changes nothing else. Both workarounds stay as they are. The BlueZ test double still waits 5 s; the double, the tests, the comments and the changelog follow in later commits of this pull request. The requirement is `"0.13.5"`, a floor and not a pin: it accepts 0.13.6. `"0.13"` would let a project that already has 0.13.1 to 0.13.4 in its lock file build aranet-core against a release with neither fix. 0.13.0 is yanked. `Cargo.lock` comes from `cargo update -p btleplug --precise 0.13.5`. btleplug, bluez-async (0.8.2 to 0.9.0) and objc2-core-bluetooth (0.2.2 to 0.3.2) move. itertools 0.15.0, which bluez-async 0.9.0 uses on Linux, is added, and so are eight `windows` crates, which only btleplug's Windows backend uses. cesu8, dashmap 5.5.3, jni 0.19.0 and jni-utils go. No other package moves, `cargo update --workspace` changes nothing more, and the lock goes from 763 to 768 packages. `ValueNotification` has a new field, `service_uuid`. The one literal in the tree is in the test double `link/fake.rs`, which now names the service that its characteristics already use. With the new lock and without that line, the test build of aranet-core stops at E0063; no other code needs a change. Checked on macOS arm64: rustfmt 1.90; clippy with `-D warnings` on Rust 1.99, with and without `--all-features`, and on 1.90; `cargo test --locked --workspace` (1,591 passed, 83 ignored); aranet-core's own tests, which give 423 passed and 59 ignored before and after the change; each feature of aranet-core with cargo-hack; the docs build with `-D warnings`; and `cargo audit`. In a Linux arm64 container with Rust 1.90: clippy with `--all-features` and aranet-core's tests (431 passed, 60 ignored). Nothing Windows-specific has been compiled yet: this pull request's Windows jobs are the first to do that.
…alias never replaces it btleplug 0.13.5 gives `PeripheralProperties::local_name` a different meaning on each operating system. On Linux it is BlueZ's `Alias`: a sensor that the user renamed in a Bluetooth settings dialog would lose its Aranet name and with it its detected type, and a sensor without a type is read and parsed as an Aranet4. A device that BlueZ has no name for would be listed under its address with dashes. On Windows a connect replaces the field with the system's name for the device. On both, the new field `advertisement_name` holds what `local_name` held in 0.11.8. `aranet_core::peripheral_name` is now the one rule for a name: `advertisement_name`, and on macOS only, `local_name` when no name was advertised, which there is CoreBluetooth's own name for the peripheral. The scan, the device lookup, the connect, the passive monitor, the `discover_services` example and the hardware tests' peripheral lookup all take the name from it. It is public because the example and the hardware tests are separate crates, and because a program that calls `properties()` on a peripheral it got from aranet needs the same rule. On macOS it returns what `local_name` holds, so nothing changes there. The test double of a peripheral reports the name in both fields, as the backends do for a named sensor, and the link test reads it through `peripheral_name`: with `local_name` alone it would fail on Linux. Tests: the rule for each backend, through a private function that takes the choice per OS as a flag; one test of the constant that makes the choice, which expects the fallback on macOS and nowhere else; `is_aranet_device`, which had no test; and a guard that reads the sources under `crates/aranet-core/src` and fails if any file but `util.rs` reads `local_name` or `advertisement_name`. Five of the six places that need a name take a real peripheral and cannot be unit-tested, and a read of `advertisement_name` would pass every other test and lose the system's name on macOS for a sensor that has not advertised one. The example and the hardware tests are outside `src`, so the guard does not cover them. Eight hand mutants of the constant, the rule and two read sites, one reading `local_name` again and one reading `advertisement_name`, each failed a test. The mutant that sets the fallback on every OS is the same program on macOS and was run in the Linux container.
…, which btleplug 0.13.5 never builds btleplug 0.11.8 named a macOS peripheral `"<system name> [<advertised name>]"` when CoreBluetooth's name for it differed from the name it advertised, and since f04ade7 a device lookup also matched either half of such a name. 0.13.5 never builds that form: the name is the advertised one. The rule could only still match a device whose own name ends in `]`, and no release has had it: f04ade7 is later than v0.2.1. `name_matches` now compares the whole name and nothing else, ignoring case and the spaces around it as before. Its two copies go too, in the `lifecycle_soak` example and in the hardware tests' peripheral lookup. The rustdoc of `find_device` loses the sentence that described the rule and points to `peripheral_name` for what a device's name is. Tests: a name with a bracketed part is found by the whole name and by neither half, in `lookup` and in the example, and both tests failed against the old code. A name with spaces around it is still found. With the branch put back, the trim removed, the comparison made case-sensitive or `==` turned into `contains`, a lookup test fails each time. The copy in the hardware tests needs a sensor and was only compiled. Nothing else in the upgrade depends on this commit: without it the branch is dead code for every name btleplug 0.13.5 reports.
btleplug 0.13.5 brings bluez-async 0.9.0, whose `connect` waits 30 s for BlueZ's `ServicesResolved` where 0.8.2 waited 5 s. The test double still modelled 5 s, so the tests described a library that aranet no longer uses. `BLUEZ_ASYNC_WAIT` is now 30 s, and its doc says how a first connect must be scripted at a 30 s connect limit. With the constant alone at 30 s, seven tests of `link::bluez_discovery_tests` fail: each scripts a library timeout that aranet's own 15 s connect limit or 20 s wait now ends first. They are restated: - Five keep their path, which starts with the library's timeout, by setting a 45 s connect limit (`LONG_CONNECT_LIMIT`). One of them now sees exactly two connects where it saw at least five. - Two start at aranet's connect limit. They script the one re-ask that the wait makes there now, in place of 5 s rounds. `a_longer_discovery_timeout_waits_longer` passed on a tie: the end of the wait and the end of a library round fell on the same instant. It now uses a 40 s `discovery_timeout`, so the wait ends between two rounds. `a_connect_timeout_with_the_link_up_gives_up_after_the_wait` asserts its exact calls. Two tests are new, the default-limit twins of `another_error_ends_the_wait` and `the_zero_services_retry_waits_too`. No production code changes: everything above `mod tests` in `link.rs` is unchanged. The module's 18 tests pass, the crate's tests pass, and the format check and clippy on stable and on 1.90 are clean.
…e usual ones With a 30 s wait in the library, a slow service discovery at the default limits ends at aranet's own 15 s connect limit with the link up, and the wait after it makes one re-ask. No test scripted that as its own case. Eight tests are added, on the 30 s double: - the usual slow first connect, and the same after a pairing step that used its whole budget; - `aranet watch`'s 30 s limit: a 20 s discovery needs no wait, and a link that is down at the limit is not asked again inside the connect; - a 90 s limit: the library gives up first and the re-ask connects; - the library's 30 s limit on the D-Bus call, through a new outcome of the double, `DbusTimeout`: the connect fails with "Timeout waiting for reply", without a connection check or a wait; - a discovery that BlueZ ends itself with no services goes into the zero-services retry; - a guard that fails if the double's wait is ever set to the default connect limit or below. No production code changes: everything above `mod tests` in `link.rs` is unchanged. `link::bluez_discovery_tests` has 25 tests and `link::pairing_tests` 6; they and the crate's other tests pass, and the format check and clippy on stable, on 1.90 and for each feature of aranet-core are clean.
…not 5 s The comments on the BlueZ wait in `link.rs` and on its test double gave bluez-async's wait for `ServicesResolved` as 5 s, and cited bluez-async 0.8.2 and btleplug 0.11.8 by line. With btleplug 0.13.5 the wait is 30 s (bluez-async 0.9.0 `src/lib.rs:61`), and that turns around which limit ends a slow connect: under a `connection_timeout` of 30 s or less, the 15 s default included, aranet's own limit ends it first, and the library's "Service discovery timed out" needs a longer limit. The comments now say so, with the upstream lines of the new versions. The reason given for the 20 s minimum wait is rewritten around what BlueZ's discovery gets in all, 35 s less the time BlueZ takes to answer at the default limits; the value does not change. The docs of the wait also say what follows from one 30 s re-ask inside a 20 s wait: a link that drops during the wait is not reopened, and an `In Progress` from another client is asked again. The double's `Hang`, `DiscoveryTimedOut` and `After` say what each stands for now. btleplug's issue 496, about the 5 s wait, is cited where the wait is explained. Comments and rustdoc only: with comment lines left out, the three files are unchanged. The task gate is clean: the format check, clippy on stable, on 1.90 and for each feature of aranet-core, the crate's tests, the docs build, and clippy and the tests in the Linux container.
…used On macOS with btleplug 0.13.5 a service discovery can succeed with no services. 0.11.8 could not report that: its connect never returned then. aranet's retry for an empty discovery disconnects, waits 2 s and connects again on the same handle. The disconnect makes btleplug's CoreBluetooth backend forget the peripheral, so 0.13.5 refuses that reconnect at once with "Peripheral no longer available" (src/corebluetooth/internal.rs:1300-1304). The new test scripts that sequence on the test double: a connect that succeeds, one empty discovery, then a connect that fails at once. It expects the Bluetooth error 2 s after the start and the calls connect, discover, disconnect, connect, disconnect. Until now only a reconnect that never answers was covered. No production code changes, and the test passed as soon as it was written. With the pause in `connect_and_discover` set to 3 s it fails on the elapsed time (left: 3s, right: 2s); that edit was undone.
…s it Comments and rustdoc in aranet-core still described btleplug 0.11.8 on macOS, where a call on a peripheral the backend had forgotten was never answered and `connect()` included the service discovery. Only comments change; no code, constant or test does. - `GattLink::is_connected`, `Device::is_connected`, the hardware tests and the lifecycle soak: 0.13.5 answers "not connected" at once for a forgotten peripheral, and the time limits stay as guards. - `connect_and_discover`: on macOS the zero-services retry can now be reached, by an empty discovery or by a "services changed" callback during one, and its reconnect on the same handle is refused at once. - `CLOSES_TIME_OUT_AFTER_DROP`: what the constant does, that 0.13.5 answers the disconnect it was written for, the one case its source does not settle, and the state of the hardware check of that case. The link to issue 494 is gone: that issue is about memory. The value is unchanged. - `DeviceManager`: a close can fail by running out of time. The macOS example given for it was no longer true. - `ConnectionConfig::discovery_timeout`: it now limits the service discovery on macOS. - `scan.rs`: the adapter-thread check loses its example of a panic that 0.13.5 no longer has. The search filter's comment says which of its reasons still holds: every scanned device is still kept, the growth per advertisement is fixed by source and not yet measured, and its figures are from 0.11.8. Each statement about 0.13.5 was read from its source and names the file and line. A diff check shows that every changed line is a comment line, and the docs build with `-D warnings` passes.
…disconnect on macOS On macOS, btleplug 0.13.5 logs `Shouldn't get anything but Ok!` at error level for every disconnect that CoreBluetooth confirms, and then returns Ok (src/corebluetooth/peripheral.rs:468-476): the disconnect's own reply is answered with "Device disconnected", like every other pending operation (src/corebluetooth/internal.rs:678-698). 0.11.8 had the same statement and never reached it. A hardware run on the commit that only moves to 0.13.5 showed the line. Every `aranet` command that connects ends with a disconnect, and the service disconnects after every poll. So each successful `aranet read` would print an error on stderr, `--quiet` included, and the service would log one per poll per device. The directive `btleplug::corebluetooth::peripheral=off` joins three default filters: - the CLI's default and `--quiet`. `-v` and a `RUST_LOG` of the user's own are used as before and still show the line; - the GUI's default, which stays at errors only. `fmt::init()` becomes the same filter written out, so that the directive can be added when `RUST_LOG` is unset or empty; - the service's `DEFAULT_LOG_DIRECTIVES`. There a default directive replaces a `RUST_LOG` directive for the same target, so no `RUST_LOG` directive for that target, or for a shorter one such as `btleplug=trace`, can show the module's lines. The line is that module's only warning or error, and the target is not widened: btleplug's warnings about Bluetooth being off, a missing permission and a failed characteristic discovery come from other modules and stay visible. A program that uses aranet-core with its own logger still gets the line. Each site says when the directive goes: with the btleplug release that no longer logs the line. The CLI and the GUI take their default from one function, `log_filter::default_directives`. Its file is a module of the library, for the GUI, and of the `aranet` binary, for the CLI, because the binary cannot call a private function of the library and the filter is not public API. New tests log one line per btleplug module under each filter and compare what is shown: the default shows what its level shows minus that one line, `--quiet` equals the default, `-v` and `RUST_LOG` are untouched, and the service drops the line under four `RUST_LOG` values. Each test of a changed filter failed before its change. Eight hand-made mutants (the target widened to `btleplug`, `=off` as `=error`, the directive dropped from a site or added to `-v`, the GUI's condition inverted) each fail a test.
Comments in three test modules (four comment sites) gave reasons for not making a `PeripheralId` that the source of btleplug and of bluez-async does not bear out. The Windows reasons were wrong on 0.11.8 too; the Linux reason in format.rs stopped being true with bluez-async 0.9.0. - scan.rs said that the Windows `PeripheralId` wraps a u64. It wraps a `BDAddr`. - format.rs said that the tests which build a `DiscoveredDevice` run on macOS only because the constructors on Linux and Windows are private. On Windows `PeripheralId` has a public `From<BDAddr>`; no helper was written for it. On Linux it is made from a `bluez_async::DeviceId`, a type aranet-cli can't name: btleplug doesn't re-export bluez-async and aranet-cli doesn't depend on it. - util.rs said, in two places, that a test can't easily create a `PeripheralId`. Only Linux lacks a conversion that aranet-core can reach. Each module's note now gives its reason with the btleplug 0.13.5 source line; the second comment in util.rs refers to the note above it. Comments only: every changed line is a `//` comment, and the tests of aranet-core and aranet-cli pass as before.
…CHITECTURE.md The dependency policy said to pin to major versions only, with `btleplug = "0.11"` as its example. The workspace now asks for `btleplug = "0.13.5"`, the first release with two fixes aranet relies on, so the example named the old version and the rule contradicted the manifest. The policy now states the rule the btleplug requirement follows and new requirements should: ask for the major version, or the minor version of a 0.x crate, and for a later release only when the code needs something that release added, with a comment that says why. Its examples are lines of the root Cargo.toml. `tempfile = "3.10"` and the other requirements with a minor or patch version predate it and carry no comment. "What's Working Now" names btleplug 0.13, and the minimum version in the requirements table is 0.13.5. The two "(current)" labels in the survey of other Aranet crates are gone: they compared those crates with btleplug's newest release at the time the table was written. Checked in the rendered file: the block quote is one paragraph, and both tables keep their four columns.
The unreleased section said nothing about the move from btleplug 0.11 to 0.13. It gains seven bullets, written against 0.2.1. Added: `aranet_core::peripheral_name`. Changed: on macOS, `discovery_timeout` now limits service discovery, errors that macOS reports for a read, a write or a subscribe are returned, and two failure texts are new; the combined macOS device name is gone; on Linux, adapters with a `bluetooth:` modalias are listed. One bullet marked "Breaking (library)" says that aranet-core's public API now carries btleplug 0.13 types, that `btleplug::Error` has a new variant, and that `local_name` means something different on each platform. The three bullets about macOS behaviour and the Linux adapters bullet carry the words "by the library's source": no hardware check has seen that behaviour yet. The early hardware check saw btleplug's error log line on a macOS disconnect, so the library bullet names the line and the log target that aranet's binaries leave out of their default output. The Linux connect path gets no new bullet: the entry about first connections to an Aranet4 is the statement against 0.2.1 and is still true. No existing line changed (7 lines added, none removed), and the file still has exactly one "Unreleased" heading.
…retries A review of the branch found no defect in the connect path, but comments in link.rs and in its test double that say something false or leave a case out. Two of them are about a link that drops while bluez-async waits for the services. - The doc of the test that pins a 30 s connect timeout with the link down said the caller's own retry dials again. `aranet watch` and the service retry. `aranet read` and the other one-shot commands connect once, so for them the command fails. - The doc of `wait_for_bluez_discovery` said that at the default limits a link that drops during the wait is not reopened. That holds once BlueZ has accepted a call of the wait. While BlueZ still refuses with `In Progress`, the next call it accepts opens a new link. - The doc of `BLUEZ_DISCOVERY_TIMED_OUT` named only the first call of a connect. A call made again during the wait gets the text too, under a `discovery_timeout` above 30 s. - The two comments at the zero-services retry said a caller that retries searches for the sensor again. aranet's own callers that retry connect by identifier and do; a retry on a kept handle is refused until a scan has found the sensor. The inline comment also counted two ways in which btleplug 0.13.5 returns an empty service set on macOS. There are three: a "services changed" callback also empties the set that the handle keeps. - The doc of `LONG_CONNECT_LIMIT` said the tests of the paths that start with the library's timeout use that limit. Five do; the others set 90 s, `challenging_environment()` or no limit. The module doc now names the 90 s as well. - A test comment gave the wait's limit (100 s) as the time the wait lasts; the test asserts 60 s. - The fake's scripting rule named only a first connect under a 30 s limit. The same order that cannot happen arises for the retry's reconnect and for a call made again in a wait with exactly 30 s left. - Three test docs stated facts about bluez-async with no version or line, and two comments said bluez-async waits 30 s for the services where it waits up to 30 s. Comments only: every changed line is a `//` comment, and the functions and constants of the wait are as they were. Each statement was read against the source it names: btleplug 0.13.5 (the CoreBluetooth `internal.rs` and `peripheral.rs`), bluez-async 0.9.0 `src/lib.rs` (lines 57, 711-726, 748-751 and 759-760), BlueZ 5.82 `src/device.c`, tokio's `Timeout`, and the callers in aranet-cli and aranet-service. rustfmt (Rust 1.90), clippy on stable and on 1.90, the tests of aranet-core (410 unit tests) and the workspace docs pass.
Three comments about device names were incomplete or gave a reason that does not hold. - A test comment in scan.rs said both name fields hold the name "as every backend reports a named sensor that has no BlueZ alias". By btleplug 0.13.5's source WinRT puts the system's name in `local_name` after a connect, and CoreBluetooth holds a name in `local_name` alone until one is advertised. The comment now names the three cases in which both fields hold the name, and the btleplug version. - The doc of the guard test in util.rs did not say what gets past it. A pattern that takes a field out of the struct has no dot before the name, and util.rs is skipped as a whole, so a second read in it would pass. Neither exists today. - The comment on the split search texts said the split keeps the test from finding itself. The test skips its own file. What the split does is keep a text search of the crate down to the two reads in `name_from`. Comments only: every changed line is a `//` comment. Checked against btleplug 0.13.5 (`src/winrtble/peripheral.rs:523-531`, `src/corebluetooth/internal.rs:1003-1008`, `src/bluez/peripheral.rs:155-156`) and by a search of aranet-core for the two field names: the only reads are the two in `name_from`, and no pattern takes a field out of the struct. rustfmt (Rust 1.90), clippy on stable and on 1.90, the tests of aranet-core and the workspace docs pass.
The example's name test checked that a bracketed name matches as a
whole and that its first half ("hall") does not. The second half was
not checked, although the commit that removed the bracket matching
says the name is matched by neither half in the example.
One assertion adds the second half ("aranet2 2751b").
Checked: the example's 20 tests pass. With the query changed to the
whole name in lower case the new assertion failed, so it can fail;
that change was undone before this commit. rustfmt (Rust 1.90), clippy
on stable and on 1.90 with --all-targets, the tests of aranet-core and
the workspace docs pass.
The module doc of log_filter.rs said the filter is the one the commands and the GUI use "when the user has chosen none", and the doc of `default_directives` said it is for "when neither a flag nor `RUST_LOG` chooses the filter". `--quiet` is a flag that chooses the filter, and it builds it from these directives. Someone who reads the file alone would conclude that `--quiet` shows btleplug's disconnect error. Both docs now name who uses the directives: the CLI under `--quiet` and when neither `--verbose` nor `RUST_LOG` chooses a filter, and the GUI when `RUST_LOG` is unset or empty. The doc of `lines_shown_by` says the `log` bridge asks the subscriber about each record with the record's own target, and cited only the conversion that builds the metadata (tracing-log 0.2.0 `src/lib.rs:227-242`). It now cites the place that asks, `src/log_tracer.rs:170-201`, and keeps the conversion as what that call is made with. Comments only: every changed line is a `//` comment. Checked against `cli_log_filter` in main.rs (the `--quiet` branch and the default both call `default_directives`), `gui_log_filter` and `init_logging` in gui/mod.rs (an unset `RUST_LOG` is read as an empty one), and the two ranges in tracing-log 0.2.0, the version in Cargo.lock. rustfmt (Rust 1.90), clippy on stable and on 1.90, the tests of aranet-cli with default and with all features (335 and 363) and the workspace docs pass.
…o valid directive `gui_log_filter` adds the directive that hides btleplug's disconnect error only when `RUST_LOG` is unset or empty. A value that is not empty but holds no valid directive, such as `aranet_core=loud`, goes to `EnvFilter::new`, which drops what it cannot parse and falls back to errors only by itself (tracing-subscriber 0.3.23 `src/filter/env/builder.rs:146-159` and `334-338`). The GUI then logs errors with the line, as it did when it called `fmt::init()`. The CLI treats the same value as unset and hides the line, and has a test for it. Neither the doc nor a test said which of the two the GUI does, so a reader could not tell whether the difference is meant. The behaviour stays as it is. The doc of `gui_log_filter` now states it, and `rust_log_replaces_the_default_gui_log_filter` pins it: with such a value the filter shows the line and exactly what `error` alone shows. No line of the function's code changes. The new assertions passed on the first run, since they pin what the code already does. To see that they can fail, the test ran twice more with one temporary change each, edited back afterwards: with the value replaced by the empty string, and with a `gui_log_filter` that gives a value that does not parse the default directives. Both runs failed on the first new assertion. rustfmt (Rust 1.90), clippy on stable and on 1.90, the tests of aranet-cli with default and with all features (335 and 363, as before) and the workspace docs pass.
The whole-branch review found two false sentences and three incomplete
ones in the Unreleased bullets that this branch added.
Linux adapters: the bullet said that on a host with more than one
adapter the one aranet uses can change. It cannot. BlueZ builds every
adapter's modalias from the daemon-wide `DeviceID` setting, so all
adapters of a host carry the same one. What changes is a host that
sets `DeviceID = bluetooth:…`: 0.2.1 found no adapter there, and its
adapters are now found. The bullet says that instead.
Bluetooth errors on macOS: the bullet said that a failed subscribe ran
into its time limit before. In 0.2.1 a subscribe had none, so the
sentence about 0.2.1 now speaks of reads and writes only. The review's
text went on to say that such a subscribe never returned. That clause
is left out: btleplug 0.11.8 answers a pending subscribe with "Device
disconnected" when the link ends, so "never" is too wide.
Two new failures on macOS: the bullet now names the second error text
("Service invalidated; rediscovery required"), says that writes fail
as reads do, and says who does not retry a missing characteristic:
`ReconnectingDevice`, while `aranet watch` and the service connect
again at their next poll.
`discovery_timeout` on macOS: the bullet now says that no option or
config key sets it, and that `--timeout` and the `timeout` key of
`aranet watch` limit only the time the link takes to come up.
The disconnect log line: the bullet now says that the disconnect has
succeeded, that `aranet --verbose` and a `RUST_LOG` of the user's own
can still show the line, and that `aranet-service` and `aranet server`
keep the target off whatever `RUST_LOG` says.
The four bullets that state behaviour read from code said "by the
library's source". Everywhere else in that section "library" means
aranet's own crates, so they now say "by btleplug's source code".
Each sentence was checked before it was written: against btleplug
0.13.5 and 0.11.8 (`src/corebluetooth`), bluez-async 0.9.0 and 0.8.2
(`src/modalias.rs`, `src/lib.rs`, `src/adapter.rs`), BlueZ 5.82
(`src/adapter.c`, `src/main.c`), aranet 0.2.1 (`device.rs`, `scan.rs`,
`error.rs`) and the code at this commit (`watch.rs`, `collector.rs`,
`error.rs`, `reconnect.rs` and the three log filters). Five lines
change, all above the first released section, and the file keeps one
Unreleased heading. No Rust file changes; rustfmt (Rust 1.90) passes.
…thing The rule said to ask for a later release only when the code needs something that release added. Its one example, btleplug 0.13.5, is a release that fixed something, so the rule did not cover its own example. It now says "added or fixed". The rule also read as if every manifest followed it. Some requirement lines name a later release without a comment, and they are older than the rule. A maintainer who compared the rule with the manifests could not tell which side is right, and might copy the form without a comment. The rule now names two such lines, `tempfile = "3.10"` in the workspace manifest and `proptest = "1.9.0"` in aranet-core and aranet-types, and says to give each its reason when it is next changed. The review proposed `indicatif = "0.18.3"` as the second example. In aranet-cli's manifest that requirement is an inline table with `version = "0.18.3"` and `optional = true`, so a search for the quoted text would find nothing. `proptest = "1.9.0"` stands in two manifests exactly so. Checked against the manifests: both example lines stand as quoted, with no comment above them, and `btleplug = "0.13.5"` has its comment. On this branch the only requirement line that changed is btleplug's, so the two examples are older than the rule. No manifest changes, and no other line of the document.
The entry on `discovery_timeout` said that `--timeout` and the `timeout` key of `aranet watch` limit only the time the link takes to come up. That holds for a connect. `watch --passive` uses the same value as the length of each scan, and `timeout` is the general key of config.toml, not a key of `watch`. The entry on the two new macOS failures said that reads and writes "on that connection" fail once macOS reports that services changed. btleplug 0.13.5 removes only the services macOS names (src/corebluetooth/internal.rs:977-981), and a read or a write fails only when its own service is gone. Both were found by the re-read of the changelog against the sources. The file keeps one Unreleased heading and four entries marked as read from btleplug's source code.
…stops, in the shared-scan hardware test The doc comment of `test_concurrent_finds_share_one_scan` explained the test's rare double `CacheHit`, and its rare failure, by CoreBluetooth reporting the sensor just after the scan had stopped. That describes btleplug 0.11.8. btleplug 0.13.5 drops a scan report that its CoreBluetooth thread takes up after the stop (`src/corebluetooth/internal.rs:1776-1784`). A report taken up just before the stop can still reach the adapter's list after `stop_scan` has returned: `stop_scan` only queues the stop (`src/corebluetooth/adapter.rs:176-182`), and a second task fills the list (`adapter.rs:59-82`). So the comment keeps the rare case and the advice to rerun the test once, and says where each fact is in the library's source. The comment was left until the hardware tests had run on the new library; the test passed when run on its own against an Aranet2. A comment only: the test and its assertion are unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This moves aranet from btleplug 0.11.8 to 0.13.5 (on Linux, bluez-async 0.8.2 to 0.9.0). The aim is that users see no change. Every difference the new library makes unavoidable on macOS or Linux is listed under "What users may notice", each with what it is measured against. Those that differ from the last release, 0.2.1, are in two lists there: the ones that
CHANGELOG.mdhas an entry for, and the ones that are described only here. The second list holds differences that are neutral, rare or negligible, the Windows ones, which were never run, and btleplug's two warnings in the CLI, for which a changelog entry is offered to the owner. Differences from today's unreleasedmainare only here, because no release had the behaviour they are measured against.btleplug 0.13.5 is the first release with upstream's fixes for the two library defects that aranet works around: memory that grows while scanning on macOS (btleplug's issue 494), and a BlueZ connect that fails 5 s after BlueZ has answered it, while BlueZ is still discovering the services (btleplug's issue 496; the library now waits 30 s). Both workarounds stay in this pull request: the filter that makes a search for a sensor on macOS ask only for Aranet sensors, and the wait for BlueZ's service discovery on Linux. Whether either can be simplified is a later change, decided from measurements on the new library.
Everything said here about the library's behaviour comes from reading its source, unless a line says it was seen on hardware.
Where it stands
mainat688974d; head72ae11e(23 files changed, 1742 insertions(+), 310 deletions(-)). Every commit builds, and each passed the per-commit gate when it was made; the first three commits of the review's fixes (a6be5df,629a73eandbd1999f: two of comments only, one test assertion) passed it in one run on their combined tree. The branch is merged by rebase, so each commit lands onmainas itself.docs/ARCHITECTURE.mdand commit messages. The rest asked for test lines, which were added, and for a log directive in two examples, which is a follow-up.a6be5dfto25d9b0e): comments, the changelog anddocs/ARCHITECTURE.md, and five test lines (one assertion in the soak example, four lines for the GUI's log filter). A second review read the first seven and found nothing serious left. The eighth narrows two changelog phrases with that review's own words.aranetprograms sets it. If an Aranet4 needs longer than that on a Mac, every read of one there fails with "Operation 'discover services' timed out". No check saw that: the two sensor types that were measured took 1.015 to 1.287 s in the head's 34 discoveries on the Mac. But the project's only figure for an Aranet4 is 9 to 22 s, computed from a request rate measured on Linux, and the review names the Aranet4 as the most common sensor. M9, the one read of an Aranet4 from the Mac that the review asked for, was not run, because no Mac run may connect to that sensor without the owner's word. The choice is to run M9 before the merge, or to merge with the limit unmeasured for that sensor. The facts on both sides are under "Not run, and why". The owner merged the pull request on 2026-10-12 without M9. So the limit is unmeasured for the Aranet4 on macOS, and the rule that no Mac run connects to that sensor stands. This text was written before the merge and put on the pull request after it.What changes in the code
btleplug = "0.13.5"in the workspace manifest. It is a floor, not a pin:"0.13"would let a project that already has 0.13.1 to 0.13.4 in its lock file build aranet-core against a release with neither fix.Cargo.lockis regenerated for btleplug alone: 3 packages updated, 9 added, 4 removed, 763 to 768 in all. One test-only struct literal gains the newservice_uuidfield. The manifest changes in that one line and in the comment above it, and nowhere else.PeripheralProperties::local_namea different meaning on each OS; on Linux it is now BlueZ's alias. The new public functionaranet_core::peripheral_namekeeps a sensor's name what it was: the advertised name, and on macOS the system's name when none was advertised. Every place in aranet-core that needs a name goes through it, and a test fails if any file undercrates/aranet-core/srcbututil.rsreadslocal_nameoradvertisement_nameitself.mainafter 0.2.1, unreleasedmainalso matched either half of a macOS combined name such asKitchen [Aranet4 1A2B3]. btleplug 0.13 never builds such a name, so the rule could match nothing. It is removed in a commit of its own and was never in a release.CLOSES_TIME_OUT_AFTER_DROPkeeps its value (true on macOS, false elsewhere), and its comment says what 0.13.5 does. A hardware check on the first commit (H2) saw a close through a handle from before a drop run into its time limit, so the classifier that this constant feeds still has one real case. M6 saw that case once more on the head (difference 5 below).Shouldn't get anything but Ok!at error level after every disconnect that macOS confirms; check M4 saw it on the first commit. ThearanetCLI,aranet-serviceand the GUI now switch off that one log target,btleplug::corebluetooth::peripheral, at their default log settings.-vand a user's ownRUST_LOGstill show the line. In the GUI aRUST_LOGof the user's own does too.RUST_LOGdirective for that target, or forbtleplugas a whole, brings that module's lines back. That is the cost of hiding it there. A directive that names a span is not covered by this: see "For reviewers".read_sensoranddownload_history: each installs its own logger and ends with a disconnect, so on macOS each prints the line after a successful run. They are not changed here; a directive for them is offered to the owner under Follow-ups.RUST_LOGthat holds no valid directive makes the GUI print tracing-subscriber's own "ignoring …" line to stderr, as before this branch, and fall back to errors only, with btleplug's line; a unit test pins that fallback. The CLI treats the same value as unset.docs/ARCHITECTURE.mdandCHANGELOG.mddescribe the new library. A comment states the library's behaviour with its version and a source line; none claims a measured effect on 0.13.5, except the comment ofCLOSES_TIME_OUT_AFTER_DROP, which cites hardware check H2.No value in
ConnectionConfig, no timeout constant and no budget derived from them changes.What users may notice
Differences from today's
main. These are not in the changelog, because no release had the behaviour they are measured against. The Linux numbers come from the code and from the paused-clock tests; none was measured on a radio.main), and until 50 s inaranet watch. On a link that takes more than 10 s to come up nothing changes. Not in the GUI: its own 30 s limit wraps the whole attempt.watch, 62 s withConnectionConfig::challenging_environment()(main: about 27, 27 and 37 s). No change at default limits when the answer takes 10 s or more. BlueZ's own 30 s timeout now falls inside aranet's wait, so the attempt can instead end as "the device reported no GATT services" after up to about 77 s at default limits, inside the documented 122 s bound, or about 107 s inwatch. That ending was already seen once onmain.watch's 30 s).mainthe library gives up 5 s after the answer, aranet asks again, and BlueZ opens a new link inside the same connect. That re-ask was added in Phase 3a and has never been released.main. With adiscovery_timeoutabove 30 s the wait's next call reopens a link that dropped during the wait.aranet watchand the service do, dials again with its next attempt.aranet readand the other one-shot commands do not retry: for them the command fails with the timeout.ReconnectingDevice), after macOS had ended that link by itself: the close got no answer within 5 s, and the reconnect went on at once and succeeded 3 s later. The other 21 closes of an already ended link in that run returned within a millisecond. It is the case H2 saw on the first commit, a close through a handle from before a drop once a scan has found the sensor again, and it is whyCLOSES_TIME_OUT_AFTER_DROPstays.Differences from 0.2.1 that are in the changelog.
btleplug::Errorhas a new variant,NoAdapterAvailable; code that readslocal_nameitself gets a different value on each OS.<system name> [<advertised name>]is gone. Lookup by the system's name, or by the whole old string, stops working; use the advertised name or the identifier thataranet scanprints. No record shows a combined name on any sensor here.discovery_timeout. In total that is more time: 25 s where it was 15 s by default, 40 s for 30 s inwatch, 18 s for 10 s in the TUI. It is stricter for discovery alone: 10 s, and 8 s in the TUI.ReconnectingDevicereturns without reconnecting.bluetooth:modalias are now listed. BlueZ gives every adapter of a host the same modalias, fromDeviceIDin its main.conf (usb:…by default), so only a host that setsDeviceID = bluetooth:…is affected: 0.2.1 found no adapter there and its adapters are now found. The design for this upgrade first said that the adapter aranet uses could change on a host with several. BlueZ 5.82's source rules that out, and the design and the changelog entry were corrected after the review. On a host with the defaultDeviceIDthe upgrade does not change which adapters are listed. Which of several adapters aranet takes was arbitrary before (bluez-async collects them from a hash map) and still is. Not testable here: the test host has the default (L1 records its line,Modalias: usb:v1D6Bp0246d0552).btleplug::corebluetooth::peripheralitself.Differences from 0.2.1 that are described only here.
Adapter powered off, canceling all pending operationswhen Bluetooth is off (also at start), andError discovering characteristics for service …when a characteristic discovery fails. Each is one more line beside aranet's own message. The changelog does not mention them; an entry is offered to the owner under Follow-ups.Device::from_peripheraland its variants) is refused in the same way until btleplug knows the sensor again. By source there are two ways to that: a scan that finds the sensor, and a call ofCentral::retrieve_peripherals, which a library user can make and aranet never does. The comments inlink.rsname the scan alone.Related Issue
None in this repository.
Type of Change
A dependency upgrade. It is breaking for programs that pass their own btleplug types to aranet-core. For users of the
aranetprograms, the differences are the ones listed above.Checklist
cargo fmtandcargo clippycargo test --workspace)Testing
Test Environment
ocean(the Linux hardware checks)Aranet2 2751BandAranetRn+ 306B8, both unpaired, from the Mac; the AranetRn+, paired, fromoceanTest Results
Local gate, on
25d9b0e. The one commit after it,72ae11e, changes only a doc comment in the hardware tests; for it the format check, clippy and aranet-core's tests were run again.git diff --numstat origin/main -- Cargo.lockprints116 74 Cargo.lock, and the lock equals the one a trial build compiled before the work started.cargo fmt --all --checkwith Rust 1.90's rustfmt, the one CI uses.-D warnings, with and without--all-features: on 1.90 and on 1.99 on the Mac, on 1.90 in the Linux container.-D warnings, on the Mac and in the container.cargo audit: exit=0.Tests whose values were computed by hand. The restated and the new BlueZ connect tests carry elapsed times and call sequences that were computed from the code before any of them ran. Every one matched when run.
Mutation checks. Each task that added or changed a decision point in non-test code ended with a hand mutation check of at most eight mutants. Every mutant was caught by a test: eight in the name helper and its guard, five in the name matching, eight in the Linux connect path and its test double, eight in the log filters. One copy of the name matching, in the hardware tests, was not mutated: it needs a sensor, and M5 runs it.
CI. All 18 jobs are green on
72ae11e: the 13 of the CI workflow,Security Audit, the three ofDeployment files, and the Release workflow'splan. The three Windows jobs first ran on the draft with only the first commit: Clippy (windows-latest, stable): pass, 2 min; Clippy (windows-latest, msrv): pass, 2 min; Build and Test (windows-latest): pass, 5 min.Hardware checks
Pass lines were fixed before any run. "First commit" is the commit that only moves the dependency,
c9e5f27; its results chose between alternatives the design had named in advance. The pass lines call it the bump-only commit, and the checks that ran on it the smoke. "Head" is the head after the review and its fixes,25d9b0e, the same commit the local gate ran on. The branch's last commit,72ae11e, came after the hardware checks and changes only a doc comment in the hardware tests. The two result columns hold each check's result line as the hardware record has it.aranet scanon the Mac, old and new binaryAranet2 2751BandAranetRn+ 306B8, no[in any name, same identifiers as the old binaryaranet readruns, five per sensor. A span runs fromDiscovering services...toFound N services. On the head the spans in M6's log are added, and the number of spans is recorded.aranet read, and a 200 s service run, withRUST_LOGunset/api/statusshows asuccess_countof at least 2 for the sensor (the log has no line per successful poll at this level). Bump-only commit: the count in each output is recorded; the line "appears" if either count is at least 1 (expected: 1 for the read,success_countfor the service). Head, with the directive: 0 in both under the same preconditions, and at least 1 inaranet read -v. Head, without it because the smoke showed no line: 0 in both.ARANET4_DEVICE not setand the one oftest_concurrent_finds_share_one_scan. Then that test alone passes and prints no SKIP line. One rerun is allowed for a test that fails at its own search.timed out after 5s,Failed to query connection stateandShouldn't get anything but Ok.RESULT: PASS; at most 2 failed polls; slope at most 0.5 MB/h; growth from warm-up to end at most 5% (0.11.8: 0.21 MB/h, 2.4%). On a miss, one repeat at 2 h.aranet readofAranet4 17C3Cfrom the Mac, a sensor type that M3 does not measure. It needs the owner's word, because the Aranet4 isocean's sensor.Discovering services...toFound N services, not the exit code. FAIL: a "discover services" timeout, or a span over 8 s. REVIEW: a span over 5 s.is_connected()anddisconnect()on the old handle, each under a 10 s limit.Shouldn't get anything but Ok!was logged; whether the adapter still lists the sensor afterwards.ocean, read-onlyaranet scanonoceanName, with the right type. This shows that names are unchanged when no alias is set; it does not test the name rule. L7 does.dbus-monitorBlueZ is still discovering services(link.rs:722, the line that does not go on with; waiting up to) appears 0 times; the INFO line that endswaiting up to 20s in allmay appear, at most once per connect attempt, and is recorded.Connected: nofive times after every run. Recorded: which path ran, and the times.okand no SKIP line;Connected: nofive times; no HCI linkDiscovering: noaranet watch -n 1at its default 30 sConnected: noafterwardsAranetRn+ 306B8with its type, andaranet read -d "AranetRn+ 306B8"exits 0 with a radon value. Afterwardsbluetoothctl infoshowsAliasequal toNameagain.aranet history --count 5for the bonded AranetRn+ onoceanThree notes on reading the results. In L3's result,
lib_timeout,debug_stillandinfo_waitcount, for each of the three reads, the lines its pass line names: the library's "Service discovery timed out", the DEBUG line and the INFO line. L3's pass line citeslink.rs:722, where the DEBUG line stood when the pass line was written; at the head it is line 796.M4_LINE_SEEN=yesandH2_OLD_HANDLE=timed-outare the two answers that the first commit's checks handed to the later work: the error line is real, and the close through the old handle ran into its limit.Two read-only audits re-judged every check of the head from the raw files and agreed with every result. For both blocks of the head's checks, the Mac's and
ocean's, the raw output of the idle check and of the Mac's list of paired devices was saved: no aranet process was running on either host, and no Aranet sensor was paired with the Mac before the Mac's checks, after them, or beforeocean's.Seen on hardware, outside the pass lines.
oceanfailed at its connect with BlueZ'sle-connection-abort-by-local, 0.7 s after the link came up; the records of this host hold the same failure with btleplug 0.11.8, the pass line allows one failed read in three, and every later connect of the checks worked at once.Pairedsignal in L3's second read: BlueZ sent one change signal for the AranetRn+ withServicesResolvedtrue andPairedtrue. By the records it is not a new pairing:Pairedread true at L1 and before each connect, no recording holdsPairedfalse, and no log holds a pairing line or a line of aranet's BlueZ pairing agent.rssicolumn ofaranet scanis empty onoceanin every row (L2, L7); the released 0.2.1 binary and the head's binary then each scanned twice there, and the column was empty in all 16 rows, so it is not from this change, and it is a follow-up.Aranet4 17C3C, which the old binary's scan 16 s earlier did; the head's scan test listed it later (M5), everyaranet scanonoceanlisted it (L2, L7 and the four scans of therssicheck), and the pass line names the Mac's two sensors only.Watch list. Every hardware log was searched for
Service no longer available,Service invalidated,Characteristic not found,Error discovering characteristicsandreturned 0 services. No log had a hit.Changelog against hardware. The four changelog entries about run-time behaviour (three for macOS, one for Linux adapters) say "by btleplug's source code". Each was compared with these results. No result contradicts any of them, and they keep those words in this pull request. What the checks did see of them is one thing: the separate discovery step on macOS, 1.07 to 1.26 s in the ten reads on the first commit and 1.015 to 1.287 s in the 34 discoveries on the head. They did not see the discovery limit applied, an error that macOS reported for a read, a write or a subscribe, either of the two new failure texts, or a host with a
bluetooth:modalias. The changelog's older entry on macOS memory (under Fixed: long-running programs "no longer grow by about 1-2 MB an hour") was measured on 0.11.8 and will ship with 0.13.5; M7 (0.10 MB/h and 0.6% in its hour, with the search filter on as committed) does not contradict it, so it stands as it is.Not run, and why
ocean's sensor, and the rules for the hardware checks let no Mac run connect to it without the owner's word. The review asked for one read of it from the Mac (M9); the owner was asked on 2026-10-11 and had not answered when the checks ran, so it was not run. The pull request was merged without it. No record shows the Mac ever connecting to it.Aranet☢ 30ED1).aranetprograms sets the limit. The review names the Aranet4 as the most common sensor. In 0.2.1 link-up and discovery shared 15 s. This is a risk that no check measured, not a failure that a check saw.ocean's BlueZ, not measured as a discovery. The 10 s limit lies at the low end of that range, and the TUI's 8 s lies below it.ocean's BlueZ; on the Mac its discovery took 1.07 to 1.14 s in the first commit's five reads and 1.015 to 1.226 s in the head's 17 discoveries, so the Mac is not shown to be faster. The Aranet4's table is about the same size as the Aranet2's (25 characteristics against 23), so the table does not explain its slowness onocean, and whether that slowness carries over to a Mac is unknown. And the notes that planned the hardware checks call the Aranet4 "the worst case for the new discovery limits".DeviceID = bluetooth:…in BlueZ's main.conf, the only kind the adapters change affects.oceanhas the default.scan.rssays that upstream's fix has not been measured, and nothing new about memory is claimed until then.oceanand both 24 h soaks. They run once, on this stack, after the follow-up pull request.dist planare checked by CI only.Screenshots (if applicable)
None.
Additional Notes
Decisions a reader may not expect
CLOSES_TIME_OUT_AFTER_DROP, and changing the Linux wait are later changes, each backed by a measurement on the new library.-d "Kitchen [Aranet4 1A2B3]", gets no special rule.mainand presents 0.2.1.Follow-ups
rssicolumn ofaranet scan: aranet reads a device's properties after the scan has stopped, and BlueZ dropsRSSIthen. 0.2.1 has the fault too. It is not fixed here, because this pull request changes no scan logic.read_sensoranddownload_history, so that they stop printing btleplug's error line after a successful run on macOS. The design named three places for the directive (the CLI, the service and the GUI), and this pull request keeps to them.Corrections to commit messages. The messages cannot be changed, so the corrections stand here. The first message leaves something out; the other four say something wider than the code or the records bear out.
c9e5f27, the first commit, builds and passes its checks, but it is not a state to ship or to bisect behaviour on. Its message does not say two things that hold at that commit. A sensor's name on Linux is BlueZ's alias, and on Windows it can change after a connect;8b04ec3puts that right. And thearanetprograms print btleplug's error line after a disconnect on macOS;3c8e075hides it.b7142e4says "a link that drops during the wait is not reopened". That is wider than the code. It holds once BlueZ has answered the connect, at limits of 30 s or less (difference 3 above).24e3e01says that the macOS example inDeviceManager's comment for a close that runs out of time "was no longer true". It is still true in one case, the one H2 and M6 saw: a close through an old handle after a scan has found the sensor again. The message also says that each statement about 0.13.5 was read from its source; the sentence about H2 inconnector.rsis a hardware observation.064a3c1says of the four source-based changelog entries that "no hardware check has seen that behaviour yet". For thediscovery_timeoutentry that is too wide: the checks on the first commit had already measured the separate discovery step on macOS (1.07 to 1.26 s in ten reads). They had not seen the limit applied, nor anything of the other three entries. The words it quotes for those entries, "by the library's source", became "by btleplug's source code" inc11c27e.c11c27esays of the adapter aranet uses on a host with several: "It cannot" change. That is meant of this upgrade only. The upgrade does not change which adapters are listed on a host with the defaultDeviceID. Which of several adapters aranet uses was arbitrary before and still is.For reviewers. The first commit is the dependency alone. The removal of the bracket matching is one commit,
0e7c352. It can no longer be reverted on its own:bd1999f, which the review added, puts one assertion into the soak example's name test that holds only with the removal, so a revert has to take both. The commit that sets the test double to 30 s also restates the tests, because they fail without each other. Four wordings were left as they are after the second review, because none is false to a user: inlink.rs, "every such callback … empties the set that this handle keeps" is wider than the source for a handle that btleplug has replaced; inutil.rs, "Two kinds of read get past it" is not a complete list of what the name guard misses; ingui/mod.rs, "the directive" does not say which one; and the changelog's "whateverRUST_LOGsays" does not cover a span directive, which could still show the line inside a connect span.