Skip to content

Releases: Necrosiak/bc250-toolkit-decky

v0.6.2 — a successful update now says so

Choose a tag to compare

@github-actions github-actions released this 27 Sep 09:05

A successful update now says so

After installing an update, the button went back to "Up to date", which looked exactly like a click that did nothing. It now reads "Updated to X ✓", with a note to close and reopen the Quick Access menu to load the new version. You will see it from the next update on.

Same fix as Steamcord #52, reported by @bastiHST90.

v0.6.1 — updates that install and actually load

Choose a tag to compare

@github-actions github-actions released this 22 Sep 18:35

Updates were being written and never loaded

Pressing Install wrote the new version to disk, and the plugin reload that should follow could never happen. The update only took effect at the next boot, and nothing said so either way.

This plugin runs as root, so it looked immune to this. It was not:

  • Decky's loader is a PyInstaller bundle and exports its extraction directory on LD_LIBRARY_PATH. Every plugin backend inherits it, so systemctl resolves the bundled libcrypto and does not even start — root or otherwise.
  • Being refused by polkit is only the second gate, and the one that stops the plugins that do not run as root.

Nothing read the result of that call, so the failure was completely silent.

What changed

The update button now asks Decky's loader to reload this plugin alone, and reports the new version when it is done. That also stops an update to one plugin from restarting all of them. If the loader is too old to offer that, the button says so instead of sitting on Installing….

Automatic updates keep restarting the loader — this plugin is allowed to, once its environment is repaired — and now say plainly when that restart was refused.

Credit

Found through Steamcord #52, reported by @bastiHST90 — his follow-up edit, noting he was on the latest build after a reboot, is what turned the report into a diagnosis. The same defect was in this plugin.

Also

This release adds no new top-level files, so the built-in updater can install it.

v0.6.0 — hardware integrations, read-only

Choose a tag to compare

@github-actions github-actions released this 20 Sep 07:39

Hardware integrations, read-only

The System tab gained a panel that reports what this machine actually has, and changes nothing:

  • Wi-Fi — the adapter NetworkManager knows about, its state and the driver behind it.
  • DualSense — whether the hid_playstation driver is loaded, and how many controllers are connected right now.
  • Display — the DRM connectors currently active.
  • Audio output — the PipeWire sink in use.
  • HDMI-CEC — shown only when a /dev/cec* bus exists.

Nothing here enables cecd, CEC or any TV setting on its own. The point is the opposite: knowing what the hardware really offers is what keeps a TV, controller or wireless feature from being proposed on a machine that cannot do it.

Every read-only line in the System tab is now a D-pad stop, with a visible highlight. Without it, Decky's focus router skips the whole section and the Quick Access Menu never scrolls down to the rows at the bottom.

The same probes are available from the terminal with bc250-status, in bc250-tweaks (git pull to get it).


Install: download BC250-Toolkit.zip below and install it from Decky (gear icon → Install from ZIP), or let the plugin update itself if auto-update is on.

v0.5.9 — notifications wait until you stop streaming

Choose a tag to compare

@github-actions github-actions released this 15 Sep 17:55

🎥 Notifications wait until you stop streaming

A Steam notification that pops up while you are live ends up in the video. BC250 Toolkit's notifications are now held while you are live and shown once the stream ends.

It follows the Streamer mode setting in Steamcord (Automatic, Always on, Off): Automatic holds them during a Discord Go Live or a BoneCast stream or recording; Always on covers OBS and any other streaming software.

Full details in the changelog.

v0.5.8 — the 8-core restore survives a refused reboot

Choose a tag to compare

@github-actions github-actions released this 13 Sep 18:20

The 8-core restore could be refused at boot

After a power cut the BIOS puts the core mask back to 6 cores, and the Restore at boot service rewrites it and reboots. The first time this happened for real, the mask was written but the reboot was refused (Operation denied due to active block inhibitor). The machine stayed on 6 cores / 12 threads, and the attempt was counted anyway, leaving one try out of two.

The service now:

  • retries for 30 seconds, logging which programs hold an inhibitor;
  • then reboots ignoring them, since nothing irreversible is written at that point of the boot;
  • and does not count the attempt if the reboot still cannot happen.

Machines that already enabled the switch get the new script automatically the next time the plugin loads.

A reboot button when the 8 cores are one restart away

Once the core mask was written, the CPU section only showed the Restore at boot switch, with nothing saying a restart was still needed. It now says so and offers a Reboot now button until the 8 cores are up.

v0.5.7 — a Tuning tab for BC250 Control Center

Choose a tag to compare

@github-actions github-actions released this 13 Sep 14:32

A Tuning tab for BC250 Control Center — and a button to install it

BC250 Control Center by @movacx is the desktop app that tunes the BC-250: GPU governor, Compute Units, CPU overclock, fans. From this release, the Toolkit is its Game Mode interface.

New Tuning tab

When the Control Center is installed, a new Tuning tab drives the same protected helper as the Control Center itself:

  • GPU — governor profiles (Balanced, Gaming, Benchmark) and validated safe points;
  • Compute Units — a live 4×5 grid, the saved boot table and its boot service;
  • CPU — overclock through the Control Center's detector, manual scale and boot service;
  • Fans — manual speed per channel, and back to automatic.

The Toolkit stores nothing of its own there. Both interfaces read and write the same files, so a change made on the desktop shows up in Game Mode, and the other way round. The CU tab goes through the Control Center too while it is present, and the Toolkit's own CU boot service steps aside once the Control Center restores CUs at boot, so the table is never applied twice.

The helper is only run when it is a root-owned, non-writable file, its protocol version is checked before every write, and no value outside the lists it accepts is ever forwarded.

Install it from Game Mode

On Bazzite (and other rpm-ostree systems), when the Control Center is missing the tab now shows Install BC250 Control Center. It downloads the official v1.19.0 RPM, refuses it unless its SHA-256 matches, adds it with rpm-ostree install, then offers to reboot. The version is pinned to the one whose helper protocol the Toolkit speaks. After the reboot, run Prepare dependencies once in the app from Desktop Mode.

Once the Control Center is detected, the button is gone. On other systems, the tab links to the project page as before.

The real GPU clock

The GPU "Current" line read pp_dpm_sclk, which stays stuck between 14 and 100 MHz on the BC-250 even while the GPU runs at 1850 MHz. It now reads the amdgpu freq1_input sensor — the same source MangoHud uses.

The CU tab no longer shows a stale count

The live CU count came from a cache that was only refreshed when empty, so a change made by another tool never appeared. It is now re-read once the cache is more than a minute old.

Also

  • The release zip ships the plugin's own LICENSE again (it was missing from v0.5.5 and v0.5.6), and the build now fails if it is ever left out.

Credits

  • @movacx — BC250 Control Center (MIT): the helper this tab drives, its protocol and its GPU profile bounds.
  • Old Lamer — the video that showed the Control Center to a wider audience.

v0.5.6

Choose a tag to compare

@github-actions github-actions released this 13 Sep 12:50

Updates no longer stop halfway, or die on DNS

Two silent faults in the built-in updater, both found while looking at something else.

A release was applied file by file, and the updater gave up on the first file it could not write — leaving the plugin half updated, part old code and part new. That is worse than no update at all, and nothing said so beyond one line in a log.

Decky keeps a plugin's top-level directory and its plugin.json owned by root and chowns everything else to you, so overwriting an existing file works while creating a new top-level entry does not. The updater now surveys the whole release before writing anything: a code file it cannot write cancels the update without touching a thing, and names the files; documentation, licences and plugin.json are skipped and the update goes through.

The release check ran once, a few seconds after the plugin starts — which is often before the network is up. Nothing retried, so the plugin stayed on its version until a boot that happened to be luckier. On the machine this was found on, three boots out of four were dying on Temporary failure in name resolution. It now retries while the failure is the network.

And when an update genuinely cannot be applied, the plugin tells you, instead of leaving you on a stale version without knowing it.

Not done, deliberately

Handing the install to Decky's own installer was tried and rejected. That route reports the install to the Decky Store, which does not know a self-distributed plugin, and the request fails with a 404 — after which the flow stops: files written, plugin never reloaded, and a confirmation dialog frozen over the Steam UI. It also leaves the whole plugin directory root-owned, which would stop the plugin updating itself ever again.

v0.5.5 — keep the 8-core unlock across power cuts

Choose a tag to compare

@github-actions github-actions released this 30 Aug 07:01

Added

  • Keep the 8-core unlock across power cuts. A new Restore at boot toggle in the CPU unlock section.

    The CU profile can simply be re-poked at boot, because compute units are written live. Cores cannot: the presence mask is only read when the CPU initialises, so the two extra cores appear at the next boot, never the current one. The service therefore checks the mask at startup and, only when the cores are missing, rewrites it and reboots the machine once. Since the mask survives warm reboots, that extra reboot happens only after a genuine power-off — a warm reboot finds 8 cores already up and does nothing.

  • The unlock status now reports whether that service is enabled, so the toggle reflects the real state of the system rather than a remembered preference.

Notes

  • A service that reboots the machine at boot is the most dangerous thing this plugin can install, so it is capped: two attempts, then it gives up for good and leaves the board at 6C/12T rather than looping. To disarm it without a working system, add bc250.nocoreunlock to the kernel command line.
  • Its scripts are copied to /usr/local/lib/bc250-core-unlock/, outside the plugin directory that Decky rewrites on every update.
  • The toggle needs the bc250-core-boot sudoers rules from bc250-tweaks — run sudo ./apply.sh there first, otherwise the plugin cannot install the service and will say so.
  • Permanent unlock without that extra reboot remains a BIOS matter: see the README.

Full Changelog: v0.5.4...v0.5.5

v0.5.4

Choose a tag to compare

@github-actions github-actions released this 25 Aug 17:23

Added

A GPU load that is actually measured.

The BC-250's firmware does not report GPU activity at all. gpu_busy_percent
answers operation not supported, and average_gfx_activity in the driver's
metrics table holds 0xFFFF — the "unsupported" sentinel. Overlays divide that
by 100 and show 655 %, a figure that never moves no matter what the machine
is doing.

The Resources tab now derives the load from the kernel's own per-engine
accounting (drm-engine-gfx in fdinfo), the same source nvtop uses.

Measured on a BC-250: about 58 % with only the Steam interface on screen,
68-75 % in a game — tracking the GPU temperature as it climbs from 40 to
46 °C. The row says plainly that the figure comes from the Toolkit rather than
from the chip.

Fixed

The SoC temperature is now read from the metrics table alongside the GPU
temperature, instead of being unavailable.

Not shown, deliberately

Power draw. The same metrics table carries GPU and package wattage, and both
are unusable on this chip: under a constant load the GPU figure swings between
0.9 W and 62 W within seconds.

The decoding is sound — the temperature beside it stays steady, and the CPU
power field holds its sentinel — so the firmware itself is at fault. Overlays
read that same field, which is where their wattages come from.

No number is better than an invented one.

v0.5.3

Choose a tag to compare

@github-actions github-actions released this 25 Aug 16:59

Fixed

The active Steam account could no longer be identified, because Steam
changed the two files it was read from.

registry.vdf stopped publishing a numeric ActiveUser — it now publishes
AutoLoginUser, which holds the account name rather than an id. And
loginusers.vdf dropped MostRecent in favour of AutoLogin and Timestamp.

Both probes therefore came back empty, and everything fell back to a generic
profile that belongs to nobody.

The account is now resolved from AutoLoginUser, matched by account name, then
from AutoLogin, then from the most recent Timestamp. The older ActiveUser
and MostRecent keys are still tried first, so an older Steam behaves exactly
as it did before.

This was found while fixing the same failure in
SkullKey, where it
made Epic, GOG and Amazon all report themselves as logged out. Every plugin that
keeps per-account state was written against the same two keys, so they all
stopped working on the same day.