Breeze Core packages

Signed packages for Breeze Core — self-hosted, LAN-first control for Midea air conditioners. v@VERSION@

How this works: add the repository once with the snippet for your system, then install and update through your normal package manager. Everything is built and signed offline — this server serves static files and holds no keys, so verify against the published keys. Linux amd64/arm64; amd64 for the BSDs.
Documentation lives in the wiki — installing, pairing, the REST API, and how to expose it safely. This page is just the packages.
Some platforms can lag a release behind. Linux amd64/arm64 is built and signed every release; the BSDs, OpenWrt and RISC-V need real hardware, cross-builds or emulation, so check the package version against v@VERSION@ above. The source tarball always matches this page.

Debian family

Debian · Ubuntu · Mint · Pop!_OS · Raspberry Pi OS · Devuan — apt
# the key gets its own keyring, referenced by the sources entry
curl -fsSL https://bolero.salataputarica.hr.eu.org/breeze-core.asc \
  | sudo gpg --dearmor -o /usr/share/keyrings/breeze-core.gpg
echo "deb [signed-by=/usr/share/keyrings/breeze-core.gpg] https://bolero.salataputarica.hr.eu.org/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/breeze-core.list
sudo apt update && sudo apt install breeze-core

Fedora / RHEL family

Fedora · RHEL · AlmaLinux · Rocky · CentOS Stream — dnf
# import the key first: dnf 5 will not fetch it from gpgkey= on its own
sudo rpm --import https://bolero.salataputarica.hr.eu.org/breeze-core.asc
sudo tee /etc/yum.repos.d/breeze-core.repo <<'EOF'
[breeze-core]
name=Breeze Core
baseurl=https://bolero.salataputarica.hr.eu.org/rpm/$basearch/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://bolero.salataputarica.hr.eu.org/breeze-core.asc
EOF
sudo dnf install breeze-core
dnf 4 vs dnf 5. The .repo file works on both. On dnf 4 (RHEL 8/9, Fedora ≤ 40) the key would be imported interactively on first install — the rpm --import above just avoids the prompt. On dnf 5 (Fedora 41+, RHEL 10) that pre-import is required: dnf 5 no longer pulls the key from gpgkey= itself. Prefer dnf config-manager? The verb changed too — dnf 5 wants dnf config-manager addrepo --from-repofile=<url> where dnf 4 used --add-repo.

openSUSE / SLE

Leap · Tumbleweed · SLES / SLED — zypper
sudo rpm --import https://bolero.salataputarica.hr.eu.org/breeze-core.asc
# swap x86_64 for aarch64 on ARM
sudo zypper addrepo --refresh --gpgcheck \
  https://bolero.salataputarica.hr.eu.org/rpm/x86_64/ breeze-core
sudo zypper --gpg-auto-import-keys refresh
sudo zypper install breeze-core

The same rpms as the Fedora/RHEL section — zypper just adds and refreshes repos its own way. --gpg-auto-import-keys accepts the repo signature without prompting.

Arch family

Arch · Manjaro · Artix · EndeavourOS — pacman
# fetch once, then add + locally sign the key by its fingerprint
curl -fsSL -o /tmp/breeze-core.asc https://bolero.salataputarica.hr.eu.org/breeze-core.asc
sudo pacman-key --add /tmp/breeze-core.asc
sudo pacman-key --lsign-key "$(gpg --show-keys --with-colons /tmp/breeze-core.asc \
  | awk -F: '/^fpr/{print $10; exit}')"
sudo tee -a /etc/pacman.conf <<'EOF'

[breeze-core]
SigLevel = Required
Server = https://bolero.salataputarica.hr.eu.org/arch/$arch
EOF
sudo pacman -Sy breeze-core

Alpine

Alpine Linux — apk · x86_64 · aarch64 · riscv64 · run as root (Alpine ships doas, not sudo)
# as root — prefix with `doas` if you use it
apk add --no-cache curl
curl -fsSL -o /etc/apk/keys/breeze-core@bolero.rsa.pub \
  https://bolero.salataputarica.hr.eu.org/alpine/breeze-core@bolero.rsa.pub
echo "https://bolero.salataputarica.hr.eu.org/alpine" >> /etc/apk/repositories
apk update && apk add breeze-core

The index is RSA-signed with the key above, so no --allow-untrusted is needed.

OpenWrt

x86_64 · aarch64_generic · aarch64_cortex-a53 · aarch64_cortex-a72 — opkg · run as root
wget -q -O /tmp/breeze.pub https://bolero.salataputarica.hr.eu.org/openwrt/breeze-core-usign.pub
cp /tmp/breeze.pub "/etc/opkg/keys/$(usign -F -p /tmp/breeze.pub)"
echo "src/gz breeze_core https://bolero.salataputarica.hr.eu.org/openwrt/$(. /etc/openwrt_release; echo $DISTRIB_ARCH)" \
  >> /etc/opkg/customfeeds.conf
opkg update && opkg install breeze-core

Signed with usign, the same signer OpenWrt itself uses, so opkg update verifies the feed. Needs OpenWrt 23.05+. Sizes are per architecture — you only ever download your own: about 24 MB to fetch, ~51–63 MB installed (a private Python runtime and every dependency, so there's nothing else to install). That means x86 boxes, NAS/RPi-class devices, or a router with extroot.

No mips package — but the opportunity is no longer mipsed. 🥁 There is a MIPS wheelhouse for OpenWrt, big- and little-endian, built against OpenWrt's own SDK. Not an .ipk: the packages wrap a frozen Python bundle, PyInstaller cannot cross-compile, and 24 MB does not fit 8–16 MB of flash anyway. The full account.
RISC-V is here. riscv64 ships as a musl build — install it from the Alpine section above. Expect it to land last of any architecture and to lag this page: nothing on PyPI is prebuilt for it, so every dependency compiles from source under emulation. No glibc riscv64 build, and no OpenWrt riscv64 .ipkwhy.

FreeBSD

amd64 — a real, RSA-signed pkg repository · verified on FreeBSD 15.1
sudo mkdir -p /usr/local/etc/pkg/keys /usr/local/etc/pkg/repos
sudo fetch -o /usr/local/etc/pkg/keys/breeze-core.pub \
  https://bolero.salataputarica.hr.eu.org/freebsd/breeze-freebsd-repo.rsa.pub
sudo tee /usr/local/etc/pkg/repos/breeze-core.conf <<'EOF'
breeze-core: {
  url: "https://bolero.salataputarica.hr.eu.org/freebsd",
  signature_type: "pubkey",
  pubkey: "/usr/local/etc/pkg/keys/breeze-core.pub",
  enabled: yes
}
EOF
sudo pkg update && sudo pkg install breeze-core

NetBSD

amd64/x86_64 — a pkgin binary repository · verified on NetBSD 11.0
# needs python312 from pkgsrc (pulled in as a dependency)
echo "https://bolero.salataputarica.hr.eu.org/netbsd/All" \
  | su root -c 'tee -a /usr/pkg/etc/pkgin/repositories.conf'
su root -c 'pkgin update && pkgin -y install breeze-core'

OpenBSD

amd64 — installs from source into a private virtualenv · verified on OpenBSD 7.9
# python3.13 is already in base on 7.9; rust builds pydantic-core
doas pkg_add rust
ftp -o breeze-core-@VERSION@.tar.gz \
  https://bolero.salataputarica.hr.eu.org/src/breeze-core-@VERSION@.tar.gz
tar xzf breeze-core-@VERSION@.tar.gz && cd breeze-core
doas sh packaging/bsd/install.sh
No binary package for OpenBSD. There's no repo to add here: OpenBSD gets the source installer, which builds a self-contained virtualenv under /usr/local/breeze-core and installs an rcctl-managed service. The Linux packages on this page are Linux ELF binaries and cannot run on a BSD kernel; FreeBSD and NetBSD get native packages because their tooling (pkg / pkg_create) makes that practical. A ports submission is welcome — see packaging/bsd/.

OPNsense

amd64 — the os-breeze-core plugin, adds Services → Breeze Core to the GUI
# from a shell on the firewall, as root
fetch https://bolero.salataputarica.hr.eu.org/opnsense/os-breeze-core-latest.pkg
pkg add os-breeze-core-latest.pkg

Then Services → Breeze Core to set the listen address and enable it, breeze-core pair to pair the air conditioners, and breeze-core approve to admit a phone or browser.

Its own package, not the FreeBSD one above: OPNsense is FreeBSD:14:amd64 with python311 and neither rust nor pip, so the whole Python runtime is vendored inside the plugin and nothing is ever compiled on the firewall. Checksums: /opnsense/.

Windows

Windows 10 · 11 · Server — an installer, not a repo · runs as a service

Unlike the Linux packages, this one does not bundle its own Python: the installer detects Python 3.11+ and builds a private virtualenv, then registers a hardened BreezeCore service (via NSSM, running as LOCAL SERVICE, with a LAN-only firewall rule and a locked-down %ProgramData%reeze-core). An optional component sets up Caddy as a reverse proxy.

# download, then double-click — or install silently:
Breeze-Core-Setup.exe /S

# verify it first (PowerShell):
Get-FileHash .\Breeze-Core-Setup.exe -Algorithm SHA256

⬇ Breeze-Core-Setup.exe · sha256 · all versions

winget: manifests for Breeze.BreezeCore live under /winget/. The package isn't in the public winget-pkgs repository yet, so install it from the manifest — which Windows gates behind an admin setting:
# once, in an ADMIN PowerShell — winget refuses local manifests otherwise:
winget settings --enable LocalManifestFiles

# then, as yourself:
mkdir breeze-core-@VERSION@; cd breeze-core-@VERSION@
'Breeze.BreezeCore.yaml','Breeze.BreezeCore.installer.yaml','Breeze.BreezeCore.locale.en-US.yaml' |
  % { iwr "https://bolero.salataputarica.hr.eu.org/winget/@VERSION@/$_" -OutFile $_ }
winget install --manifest .
winget then downloads the installer from GitHub and checks it against the SHA256 in the manifest. A private winget source isn't an option here — sources speak a REST API, and this host deliberately serves static files only.

Breeze for Android

the phone client — not the server · sideload APK · Android 7+

Everything above installs the server. This is the app that talks to it: one AC per screen, home-screen widgets, server-side schedules, and an Android Auto surface. It's signed with the project's own release key and distributed as an APK — there's no Play listing, so your phone will ask you to allow installs from this source.

# download to your phone, or push it over adb
adb install breeze-latest.apk

# verify what you downloaded first (recommended):
sha256sum -c breeze-latest.apk.sha256

⬇ breeze-latest.apk · sha256 · all versions — or grab it from GitHub releases.

App and server version independently. The app talks to any server version and feature-detects what it can use; you don't have to upgrade both together. It needs a Breeze Core server on your network — pair once with the server's API key and an admin approval on the LAN.

After installing

three steps on every platform — then find your init system below
# 1. find your ACs and write the config
breeze-core pair
# 2. set this machine's LAN IP (or keep 127.0.0.1 behind a reverse proxy)
#    Linux    /etc/breeze-core/breeze-core.env             → BREEZE_HOST=...
#    FreeBSD  /usr/local/etc/breeze-core/breeze-core.env
#    NetBSD   /usr/pkg/etc/breeze-core/breeze-core.env
#    OpenBSD  /etc/breeze-core/breeze-core.env
# 3. enable + start the service — pick your init system:

systemd

Debian · Ubuntu · Fedora · RHEL · SUSE · Arch
sudo systemctl enable --now breeze-core
sudo systemctl status breeze-core
journalctl -u breeze-core -f            # follow the log

OpenRC

Alpine · Artix (openrc) · Gentoo · Devuan
rc-update add breeze-core default
rc-service breeze-core start
rc-service breeze-core status

runit

Void · Artix (runit)
# template ships at deploy/init/runit-run
sudo mkdir -p /etc/sv/breeze-core
sudo cp deploy/init/runit-run /etc/sv/breeze-core/run
sudo chmod +x /etc/sv/breeze-core/run
sudo ln -s /etc/sv/breeze-core /var/service/     # /run/runit/service on Void
sudo sv status breeze-core

s6 / s6-rc

Artix (s6) · Obarun
# template ships at deploy/init/s6-run
sudo mkdir -p /etc/s6/sv/breeze-core
sudo cp deploy/init/s6-run /etc/s6/sv/breeze-core/run
sudo chmod +x /etc/s6/sv/breeze-core/run
sudo s6-rc-bundle-update add default breeze-core
sudo s6-rc -u change breeze-core

SysV init

Devuan (sysvinit) · Slackware · older LTS releases
# template ships at deploy/init/sysv-breeze-core
sudo cp deploy/init/sysv-breeze-core /etc/init.d/breeze-core
sudo chmod +x /etc/init.d/breeze-core
sudo update-rc.d breeze-core defaults    # RHEL-ish: chkconfig --add breeze-core
sudo service breeze-core start
sudo service breeze-core status

procd

OpenWrt
/etc/init.d/breeze-core enable
/etc/init.d/breeze-core start
logread -e breeze-core                  # follow the log

rc.d — FreeBSD

FreeBSD 14 · 15
sudo sysrc breeze_core_enable=YES
sudo service breeze_core start
sudo service breeze_core status
tail -f /var/log/breeze_core.log

rc.d — NetBSD

NetBSD 10 · 11
echo 'breeze_core=YES' | su root -c 'tee -a /etc/rc.conf'
su root -c 'service breeze_core start'
su root -c 'service breeze_core status'
tail -f /var/log/breeze_core.log

rcctl — OpenBSD

OpenBSD 7.x
doas rcctl enable breeze_core
doas rcctl start breeze_core
doas rcctl check breeze_core
# host/port live in /etc/breeze-core/breeze-core.env

Windows service

Windows 10 · 11 · Server — installed by the .exe (NSSM)
Get-Service BreezeCore
Restart-Service BreezeCore
# config lives in %ProgramData%\breeze-core

Then open http://<BREEZE_HOST>:8420, enter the API key from your config.json, and pair. The service runs as an unprivileged breeze user, and uninstalling keeps your config and device tokens. The runit/s6/SysV templates live in deploy/init/.

Proof of concept

s390x · ppc64le · Termux · OpenWrt MIPS · Debian mips64el — frozen at v3.0.5, for developers

These are not products. They exist so somebody porting Breeze Core to an unusual machine starts from a working build and a list of the walls, instead of from scratch. Frozen at 3.0.5, outside the signed repositories, no support. Every one was verified by running it on the target under emulation — with one clearly-labelled exception, the Octeon wheelhouse, which has never run.

Termux (Android, no root)termux-aarch64 · termux-x86_64a frozen bundle for Termux's own interpreter path
s390xlinux-musl-s390xmainframes need cooling too
ppc64lelinux-musl-ppc64lesame recipe as s390x
OpenWrt MIPSmips_24kc (BE) · mipsel_24kc (LE)wheelhouses, built against OpenWrt's SDK — the one that matters
Debian mips64ellinux-glibc-mips64elglibc wheelhouse; Loongson 3, Cavium on Debian. Not for routers
Octeonmips64_octeonplusUNVERIFIED — compiles and inspects correctly, never executed
# bundles: download, extract, run
curl -fsSLO https://bolero.salataputarica.hr.eu.org/poc/breeze-core-3.0.5-linux-musl-s390x.tar.gz
tar -xzf breeze-core-3.0.5-linux-musl-s390x.tar.gz
./breeze-core-3.0.5-linux-musl-s390x/breeze-core version

# wheelhouses: pip them into an extroot. --only-binary is not optional --
# without it a tag mismatch quietly starts compiling Rust on a router.
opkg update && opkg install python3 python3-pip python3-cryptodome
curl -fsSLO https://bolero.salataputarica.hr.eu.org/poc/breeze-core-3.0.5-openwrt-mips_24kc-wheelhouse.tar.gz
tar -xzf breeze-core-3.0.5-openwrt-mips_24kc-wheelhouse.tar.gz
cd breeze-core-3.0.5-openwrt-mips_24kc-wheelhouse
pip install --find-links . --only-binary pydantic-core pydantic-core
pip install fastapi uvicorn msmart-ng brotli-asgi
⚠ Do not mix the two 32-bit MIPS wheelhouses. uname -m says mips for both endiannesses, so the filenames are identical and the contents are not. It fails safely — the wrong one raises ImportError rather than executing byte-swapped code — but keep them apart. Octeon owners: running the test in the write-up and reporting the result is genuinely useful, whichever way it goes.

⬇ browse /poc/ · every file has a .sha256 · each tarball carries a NOTES.md · built from the v3.0.5 source · every trap, in detail: Proof-of-concept architectures