Slow OneWire Bulk-Read Polling =============================== This applies to :py:class:`herosdevices.core.bus.onewire.OneWireBusMaster` and :py:class:`herosdevices.core.bus.onewire.W1ThermBusMaster`, which poll a onewire bus by triggering one bulk conversion for every sensor at once (``therm_bulk_read``) instead of reading each sensor individually. On a working bus, one poll cycle takes roughly one conversion time (about 750 ms at 12-bit resolution), no matter how many sensors are attached. If the kernel refuses the bulk trigger, ``OneWireBusMaster`` falls back to reading each sensor individually so a poll cycle still completes, but every sensor then pays its own conversion time. Symptoms -------- The ``poll_time`` observable (or the time a manual ``poll_once()`` takes) is close to:: number_of_sensors * ~750 ms For example, 13 sensors on one bus reporting a poll time around 9.5-10.5 s instead of roughly 1 s. Diagnosis --------- Check the kernel log for the bulk-read trigger being refused: .. code-block:: bash dmesg | grep -iE "not registered|therm_bulk_read" Two messages point at this problem: ``Family 28 for is not registered`` Logged once per sensor, right when the bus master's first search runs. ``therm_bulk_read_store: unable to trigger a bulk read on the bus. err=-22`` Logged every time a poll cycle tries to trigger a bulk conversion and the kernel rejects it. ``err=-22`` is ``EINVAL``. If you see the first message on its own (only near boot) followed by the second message persisting afterwards, this is a boot-ordering problem, described below. Also worth ruling out before digging further: .. code-block:: bash # do all sensors use the same power mode? a mix of parasite- and externally-powered # sensors on one bus also makes the kernel refuse the bulk trigger for d in $(cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves); do echo -n "$d: "; cat /sys/bus/w1/devices/$d/ext_power done Cause ----- ``w1-gpio``'s master driver runs its first bus search as soon as it comes up. If ``w1-therm``, the driver that recognizes DS18B20-family sensors, has not registered yet at that exact moment, every sensor found in that first search is added to the bus as an unrecognized ("not registered") device. Once a sensor gets added this way, it stays ineligible for bulk-read for the rest of that boot, even after ``w1-therm`` loads a moment later - the kernel does not retroactively upgrade it. On a typical setup, ``w1-gpio`` and its dependency ``wire`` load early via the ``dtoverlay=w1-gpio`` device tree overlay, while ``w1-therm`` is only pulled in reactively once a matching device is found. That ordering is exactly backwards for bulk-read: ``w1-therm`` needs to already be loaded before the first search runs, not after. .. tip:: You can reproduce and confirm this by hand. Force a clean reload with the modules in the correct order and watch for the "not registered" message to disappear: .. code-block:: bash rmmod w1_therm 2>/dev/null rmmod w1_gpio rmmod wire modprobe wire modprobe w1_therm modprobe w1_gpio sleep 3 dmesg | tail -50 cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count Fix --- Make module loading order explicit instead of relying on the device tree overlay's reactive autoloading. Add the following to ``/etc/modules`` (Raspberry Pi OS reads this via ``systemd-modules-load.service`` early in boot, before the overlay-triggered probe): .. code-block:: text :caption: /etc/modules wire w1-therm w1-gpio Leave ``dtoverlay=w1-gpio`` in ``config.txt`` as is - it is still needed for the GPIO pin configuration itself. This change only makes sure ``w1-therm`` is ready before ``w1-gpio`` probes. Verifying the fix ------------------ Reboot, then check that no sensor was added before ``w1-therm`` was ready: .. code-block:: bash dmesg | grep -iE "not registered|therm_bulk_read" cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slave_count Both commands should come back clean: no matching log lines, and a slave count matching the number of sensors you expect. A manual trigger should now settle quickly instead of erroring: .. code-block:: bash echo trigger > /sys/bus/w1/devices/w1_bus_master1/therm_bulk_read sleep 1 cat /sys/bus/w1/devices/w1_bus_master1/therm_bulk_read # expect 1, not an error for d in $(cat /sys/bus/w1/devices/w1_bus_master1/w1_master_slaves); do echo -n "$d: "; cat /sys/bus/w1/devices/$d/temperature done cat /sys/bus/w1/devices/w1_bus_master1/therm_bulk_read # expect 0 (drained) .. note:: ``OneWireBusMaster`` writes the trigger command with a trailing newline (``f"{action.trigger_value}\\n"`` in ``_drain_action``). On some kernel versions, ``w1-therm`` rejects a trigger write missing that newline - same ``err=-22`` symptom, unrelated to boot order. If the fix above does not resolve the symptom, make sure you are running a ``herosdevices`` version that includes this trailing newline.