Skip to content

Releases: monikapurpl3/breeze

Breeze 2.2.7

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 21 Aug 19:45

A sleep timer, and cat facts

The sleep timer

An hourglass beside the power switch on any unit that is on. Tap it, pick how
long the unit should stay on, and the server turns it off — so it happens with
the phone asleep, flat, or in another country. Nothing here depends on the app
still running.

It asks for minutes, not a time of day, and counts down from a figure the
server computes, so a phone in a different timezone — or with a wrong clock — still
gets the right answer. Setting a new timer on a unit that already has one replaces
it, because that means you changed your mind, not that you want two competing
promises about the same unit.

Needs Breeze Core 3.2.0 for the /api/timers endpoints. The app
feature-detects: against an older server the hourglass simply is not there.

The refresh indicator moved

It now sits next to the status dot, in a fixed-width slot. It used to occupy the
spot the hourglass now uses, and appearing mid-command shoved the unit's name
sideways. Long names shrink to fit rather than pushing the controls around.

Cat facts while the server loads

Startup used to be a bare spinner. It now shows a random cat fact — bundled, not
fetched, so it works on a network that is not cooperating, which is exactly when
you are looking at it.

The licences the app was missing

Flutter's licence page only walks Dart packages, so the AndroidX Car App
Library
behind Android Auto had no attribution in the app at all. Native
dependencies are now registered explicitly and appear alongside the rest. Every
other licence was already current.

Breeze 2.2.6

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 16 Aug 16:34

The outdoor sensor, finally used

Your units report an outdoor temperature — the diagnostics have been printing it all along — and the app was throwing it away. The control screen now reads:

I: 27.0 °C  /  O: 33.0 °C

…with a slim bar underneath showing how indoor, outdoor and target relate to each other.

One rule, not three

The bar could be described as three separate behaviours, which is exactly how such things drift apart. It's implemented as one:

The warmest of indoor / outdoor / target sets the top of the scale. The other two are drawn from the floor as overlapping fills — the warmer of them lighter, the cooler darker on top.

  • Cooling (outdoor 33, indoor 27, target 24) — outdoor is the ceiling, indoor the lighter fill, target the darkest.
  • Heating (outdoor 5, indoor 20, target 23) — the target becomes the ceiling and the outdoor reading the darkest fill.
  • Indoor below target — the shades swap by themselves, because warmer is always lighter. No special case.

Failsafes

A temperature sensor has many ways to lie, and every one of these is covered by a test:

  • A unit without an outdoor probe may report a sentinel instead of null, so anything outside −50…80 °C is treated as missing. A bar scaled to 255 °C would render as an empty sliver with no clue why.
  • NaN and infinities are dropped the same way.
  • Below-zero outdoors extend the scale floor beneath 0 °C rather than clamping the reading to nothing — which would look like a dead sensor every winter.
  • Fewer than two real readings isn't a relationship: the numbers still show, the bar doesn't.
  • Two readings draw a single full-strength fill; the pale shade only makes sense when something darker sits on it.
  • Identical readings still get a 1 °C span, so nothing divides by zero.
  • Genuine extremes are kept — 45 °C on a sun-baked outdoor unit and −30 °C in a real winter are weather, not faults.

Geometry is computed in Celsius whatever the display unit, so °F users see identical proportions.

Requires a Breeze Core server on your network. Also on the package host: https://bolero.salataputarica.hr.eu.org/android/

Breeze 2.2.5

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 16 Aug 10:11

Switch between servers without re-pairing

Servers are now profiles. Each one keeps its own address, access key and device credential in the keystore, and switching is just a pointer move — so returning to a server you've used before is instant. That's the whole point: re-pairing means getting an admin onto that server's LAN to approve a code, which is fine once and miserable every time you move between a home and an office.

Settings → Server lists them all: switch, rename, add another, or forget one without touching the rest. An existing install migrates into a profile on first launch, writing the new keys before deleting the old ones so an interrupted migration retries instead of losing your credential.

The Nerd screen

The About row is now just a version number. Tap it seven times — the gesture Android uses for developer options, with a countdown for the last three — and you get everything:

  • This app — version, package, platform, Dart runtime, and the resolved version of every dependency (read from the shipped pubspec.lock, so it can't drift)
  • This connection — measured round-trip latency, auth version, and how the server sees you: your IP, whether that reads as private, Host header, scheme, X-Forwarded-For, proxy state
  • The server — version and build commit, OS, init system, CPU and architecture, every component version, install date, uptime, time zone, memory, the store paths and their file modes, the effective settings
  • Your air conditioners — addresses, credentials, cached capabilities, history depth
  • Everyone's devices — each enrolled client with its auth version, enrolment date, last use and expiry

One button copies the lot as JSON, for pasting into a bug report.

It needs Breeze Core ≥ 3.0.5. Against anything older there's no partial version worth rendering, so it says womp womp update your server and leaves it at that.

Also

  • A Licences page under the version row.
  • Gradle's heap is capped at 2 GB (the Flutter template asks for 8) and the daemon now exits after 10 minutes idle — a build used to leave a ~5 GB JVM resident long after it finished.

Requires a Breeze Core server on your network. Also on the package host: https://bolero.salataputarica.hr.eu.org/android/

Breeze 2.2.1

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 15 Aug 18:08

The Android Auto surface now actually appears in the car. It never did before — on a phone with Auto's developer mode and unknown sources enabled, Breeze was simply absent from the launcher, with nothing in any log to say why.

The fix

BreezeCarAppService declared its two categories (IOT and POI) as two separate <intent-filter> blocks. That resolves correctly in PackageManager — both category queries returned the service, which is why it looked healthy from every angle — but Auto's host reads the categories off the first ResolveInfo it gets, saw only IOT, and dropped the app before it ever reached the launcher. One filter carrying both categories (the shape SmartThings uses, which does appear) and Auto picked it up immediately.

Verified end to end against the Desktop Head Unit on Auto 17.3.662854:

GH.AppNotifier: Posting notification for new app ComponentInfo{app.breeze.breeze/…BreezeCarAppService}
BreezeCar:      CarAppService created
BreezeCar:      onCreateSession — host connected
BreezeCar:      onCreateScreen — building PowerScreen
BreezeCar:      onGetTemplate — paired=true units=3

Also in this release

  • Host validation relaxed for release builds. The old allowlist path was right for a Play app and wrong for a sideloaded one: the Desktop Head Unit isn't a signed host, so it made the car surface untestable, and any mismatch failed silently. What a rogue host can do here is toggle an air conditioner.
  • The car classes now log. onCreateonCreateSessiononCreateScreenonGetTemplate under tag BreezeCar. Previously "the host bound us and we threw" and "the host never bound us" produced identical logcat output, which is most of why this took so long to find.
  • The About dialog no longer lies about the version. It was a string literal, so it still read 2.2.0 in a 2.2.1 build; it's now read from the installed package, and Diagnostics reports the app's version alongside the server's.

Requires a Breeze Core server on your network. Also available from the package host: https://bolero.salataputarica.hr.eu.org/android/

Breeze 2.2.0

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 15 Aug 11:05

Breeze 2.2.0 — the app now actually feels like something you're touching.

Haptic feedback (it was effectively absent)

There were exactly two haptic calls in the whole app: one selectionClick — the faintest constant Android offers — fired after a control had already committed, plus one in diagnostics. Steppers, mode, fan, flap, power and page swipes were all silent. The VIBRATE permission wasn't declared either, so the stronger feedback paths did nothing regardless.

Feedback is now named by meaning rather than intensity, so it stays consistent as things get added:

when
tick a notch moved — temperature ±, a slider detent, swiping to another unit
select a setting chosen — mode, fan, a flap half, eco/turbo
toggle power on/off, deliberately the heaviest: it's the one action with a physical result you might be across the room from
success / failure pairing accepted, or a rejected key — failure is two beats so it's distinguishable without looking

The temperature slider ticks only when the value crosses a notch, not on every pixel of the drag.

Generated device names

Every install used to propose "Breeze", so a household ended up with several identically-named rows in the server's device list and no way to tell which phone to revoke. Names are now a climate word plus seven digits — Sirocco-4820937 — pre-filled at pairing with a dice button to re-roll. (Labels were never identity: the server keys on a token id, so the duplicates were harmless, just useless to a human.)

A welcome screen that welcomes

It was an icon and three bare fields, followed by an abrupt jump to a pairing code nobody had been warned about. Now it states the three steps before they happen — including that a person has to approve the pairing on your home network, which is the genuinely surprising one — with helper text under each field saying where the value comes from, a gradient drawn from your wallpaper palette, and errors in a proper container instead of loose red text.

Also in the 2.1 line, if you're coming from 2.0: Android Auto (one AC per screen, one huge power button), the widget's ON/OFF badge, and the fix that stops the app destroying its own credential over a transient 401.

Download Breeze-2.2.0.apk below, or from bolero.

Breeze 2.1.2

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 14 Aug 11:55

Breeze 2.1.2 — fixes the Android Auto app not appearing in the car at all.

The car surface was registered under androidx.car.app.category.IOT, which is the semantically right home for "control a device at my house" — and Google's own IoT guide recommends exactly the GridTemplate this app uses. But IOT is an Android Automotive OS category: Android Auto (phone projection) doesn't list an app that only declares it. Enabling Unknown sources couldn't have helped; nothing on the phone side could.

The service now also declares POI, the only Auto-supported templated category that permits these templates without the navigation-template permission, so Breeze shows up in the Android Auto launcher. IOT is kept for Automotive OS.

Caveat: POI is a stretch semantically and would be rejected in Play review. That's fine for a self-hosted APK; if this ever ships on Play, drop POI and offer the car surface on Automotive OS only.

Everything else is unchanged from 2.1.1 — the 401/credential fix, clock self-correction, widget ON/OFF badge, power switch and flap pill.

Breeze 2.1.1

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 13 Aug 16:26

Breeze 2.1.1 — the client half of the Breeze Core 3.0.2 reliability fix, plus the Android Auto surface from 2.1.0.

Fixed — the bug that locked users out

The app used to treat any 401 as "my credential is dead": it deleted the stored Ed25519 private key and demanded re-pairing. Re-pairing needs an admin to approve on the LAN, so a user who was away from home couldn't recover — and when the immediate re-enrolment also failed, the app fell through to onboarding having forgotten the server entirely ("the app has no servers any more").

The trigger didn't even have to be real: a phone whose clock had drifted past the server's 60 s window fails every signed request, which looked identical to a revoked credential.

Now:

  • Transient failures are retried once, transparently. On a clock_skew rejection the app learns server_time − device_time and signs everything afterwards with server time — a drifted clock self-heals in one round-trip instead of costing you your pairing.
  • Re-pairing only happens when the server says the credential is genuinely finished, or after 3 unexplained 401s in a row (for servers too old to say).
  • On a kept-credential 401 the app drops to its offline state instead of continuing to poll every 5 s. That hammering is what tripped the server's fail2ban and, behind NAT, banned everyone's shared address at once.
  • Diagnostics no longer probes the LAN-only admin endpoint /api/auth/devices when you're remote — a single 403 there could get your IP banned. It also reports your device clock offset, which would have identified this in one tap.

Also in the 2.1 line

  • Android Auto: one AC per screen, one huge power button, big ▲/▼ to switch units. Needs Unknown sources in Android Auto's developer settings — see the README.
  • Home-screen widget shows a bold ON / OFF / OFFLINE badge and goes colourful when running, colourless when off.
  • Power is a big switch (faintly red off, faintly green on); the flap control is one pill split into vertical/horizontal halves.

Download Breeze-2.1.1.apk below.

Breeze 2.0.1

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 23 Jul 14:58

Breeze 2.0.1 — a ground-up redesign of the Android client for Breeze Core. Deliberately generic branding; works against any server version, with the full experience on Breeze Core ≥ 3.0.

Highlights of the 2.0 line

  • One unit per screen, swipe to switch. Each unit fills the screen, tinted to its active mode, with modern custom controls: a stepped temperature slider, a fan slider that detaches to Auto, an on/off flap slider (up-down · both · left-right), big eco/turbo switches, and a colourful mode picker. Every change is optimistic with haptic feedback, and the screen never flickers while refreshing.
  • Live updates over SSE (≥ 3.0) — the server pushes changes so the phone stops polling, and falls back to polling if the stream drops.
  • Ed25519 request signing (≥ 3.0) — a per-device key kept in the Android Keystore that never leaves the phone; a device on the old bearer scheme upgrades itself in place.
  • Scan-to-add — find units on the network by their open ports, or add by LAN IP; rename and remove too. Home-screen widgets, °C/°F, theme override, and a beep-on-control toggle.

New in 2.0.1

  • Reopens on the unit you last viewed — remembered by unit (not position), so it survives adding, removing, or reordering units.
  • Full in-app diagnostics — now mirrors the server's diag: connectivity + server build/features, authentication & security posture (rejects missing/wrong keys, reports token-gating), this device's credential + expiry, config secret-sanitisation, input validation, batch state, a live-stream check, and per-unit health + hardware capabilities.

Install

Download Breeze-2.0.1.apk below (v2+v3 signed, allowBackup=false). You'll need a Breeze Core server on your LAN — see the server repo.

Breeze v2.0.0 (prerelease 2)

Pre-release

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 22 Jul 14:24

Prerelease 2 of the v2.0.0 app overhaul — from the overhaul branch, built @ c05cfb8.

Everything in pre1 (swipe one-unit-per-screen UI, modern controls, scan-to-add, beep, Ed25519 signing) plus:

  • Live updates over SSE — on Breeze Core ≥ 3.0.0 the app opens /api/units/stream and applies pushed changes in place, so the phone stops polling and changes from schedules or other clients appear instantly. On any drop it falls back to the 5 s poll and retries; older servers just poll as before.

Needs the Breeze Core v3.0.0 prerelease 2 server. The APK is debug-signed (test build, not Play-signed) — Android will warn about an unknown developer; allow "install unknown apps". flutter analyze clean; compiles for Android.

Breeze v2.0.0 (prerelease)

Pre-release

Choose a tag to compare

@monikapurpl3 monikapurpl3 released this 21 Jul 20:39

Prerelease of the v2.0.0 app overhaul — for testing, from the overhaul branch. Built from overhaul @ 01fdbfb.

Redesigned control experience

  • One unit per screen, swipe left/right between units (with page dots) — replaces the old scrolling list of cards. Each unit fills the screen, no scrolling.
  • Modern controls: a big temperature readout with a 0.5° stepped slider and −/+ buttons; a Low→High fan slider that detaches to Auto; a flap on/off + three-stop slider (up-down / both / left-right); huge colourful eco/turbo switches; a colourful segmented mode picker.
  • No more flicker on refresh — state updates in place with only a tiny discreet indicator; controls never jump while you're dragging them.

Also

  • Scan the network to add units (finds AC ports on your LAN) alongside manual IP entry.
  • Beep on control toggle in Settings.
  • Rides on the new Ed25519 request signing (auth v2) from Breeze Core v3.0.0.

This asset

Breeze-2.0.0-pre.apk — needs Breeze Core v3.0.0 prerelease on the server. The APK is debug-signed (test build, not Play-signed): Android will warn about an unknown developer — allow "install unknown apps" for your browser/file manager. flutter analyze clean; compiles for Android. Not yet visually QA'd on a range of devices.