A brew timer & notification app that alerts your Microsoft Teams channel when your tea or coffee is ready.
Built with Avalonia UI for cross-platform support — runs on Raspberry Pi with a touchscreen, as well as Windows and Linux desktops.
- Pre-configured brew profiles (Turkish Tea, Filter Coffee) — editable durations, add/delete custom profiles
- Visual countdown timer with pause / resume / cancel — run several brews at once, each tracked on its own row
- Ambient idle screen — clock, date, and brew freshness scenes across 12 animation modes, three mode-aware background families, and smooth cinematic transitions
- Microsoft Teams Adaptive Card notifications (Power Automate webhook or Graph API)
- TR / EN language toggle in Settings (no restart required)
- Dark theme optimised for small screens
- No secrets in the repository
src/
├── BrewAlert.Core/ # Business logic, models, interfaces (zero dependencies)
├── BrewAlert.Infrastructure/ # Teams notifications, JSON persistence
└── BrewAlert.UI/ # Avalonia views + view models
tests/
├── BrewAlert.Core.Tests/
├── BrewAlert.Infrastructure.Tests/
└── BrewAlert.UI.Tests/
See docs/architecture.md for detailed design.
Prerequisites: .NET 10 SDK.
dotnet run --project src/BrewAlert.UI # run
dotnet test # testBrewAlert has three notification backends selected via a single Provider setting. Switch between them live from the Settings screen (no restart required) — or set it in config:
// %AppData%\BrewAlert\preferences.json
{ "BrewAlert": { "Notifications": { "Provider": "Webhook" } } }Provider |
Description |
|---|---|
"Webhook" |
Power Automate webhook — no Azure registration needed |
"Graph" |
Microsoft Graph API — posts to a specific Teams chat |
"Console" |
Stdout only — default for local dev |
Environment variables use the prefix BREWALERT__. AddEnvironmentVariables("BREWALERT__") strips the prefix and converts __ to :, so the BrewAlert: config root must remain in the name:
BREWALERT__BrewAlert__Notifications__Provider=WebhookSends an Adaptive Card to any Teams channel or chat via a Power Automate flow. No Azure AD app registration needed.
-
In flow.microsoft.com, create an Instant cloud flow with trigger "When a HTTP request is received".
-
Add a "Post a card in a chat or channel" action; set the Adaptive Card field to
triggerBody(). -
Copy the generated HTTP POST URL from the trigger step.
-
Set the URL via the Settings screen, env var, or
appsettings.Development.json:export BREWALERT__BrewAlert__Notifications__Teams__WebhookUrl="https://your-flow-url..." export BREWALERT__BrewAlert__Notifications__Provider="Webhook"
Or in
appsettings.Development.json(gitignored):{ "BrewAlert": { "Notifications": { "Provider": "Webhook", "Teams": { "WebhookUrl": "https://your-flow-url..." } } } }
Posts to a specific Teams chat via an Azure AD App Registration (client credentials flow).
Limitation:
POST /chats/{id}/messageswith application-only tokens requires Resource-Specific Consent (RSC) on the target chat in addition to theChat.ReadWrite.Allpermission. Without RSC the API returns 403. Use Option A unless you specifically need Graph.
-
Create an App Registration, add
Chat.ReadWrite.AllApplication permission, grant admin consent, and configure RSC for the target chat. -
Set the credentials via env vars or
appsettings.Development.json:export BREWALERT__BrewAlert__Notifications__Provider="Graph" export BREWALERT__BrewAlert__Notifications__TeamsGraph__TenantId="your-tenant-id" export BREWALERT__BrewAlert__Notifications__TeamsGraph__ClientId="your-client-id" export BREWALERT__BrewAlert__Notifications__TeamsGraph__ClientSecret="your-client-secret" export BREWALERT__BrewAlert__Notifications__TeamsGraph__ChatId="19:xxx@thread.v2"
Download the latest release and run the bundled installer on the Pi:
wget https://github.com/dogukanozen/BrewAlert/releases/latest/download/brewalert-<version>-linux-arm64.tar.gz
mkdir -p ~/brewalert
tar -xzf brewalert-*.tar.gz -C ~/brewalert/
bash ~/brewalert/install.shinstall.sh installs the required system libraries (libdrm2, libgbm1, libfontconfig1, libfreetype6, libinput10, libfuse2), copies BrewAlert.AppImage to ~/brewalert/, and sets up a systemd service that starts automatically on boot.
The app runs in DRM/KMS mode (--drm) for direct framebuffer access — no desktop environment required. Auto-updates are handled by Velopack: when a new release is published, the running app downloads and applies the update automatically, then restarts via systemd.
install.sh creates /etc/brewalert/env on first install and never overwrites it on subsequent updates — your credentials survive upgrades. Edit the file to enable Teams:
sudo nano /etc/brewalert/envBREWALERT__BrewAlert__Notifications__Provider=Webhook
BREWALERT__BrewAlert__Notifications__Teams__WebhookUrl=https://your-flow-url...
sudo systemctl restart brewalertNote: The URL may contain
%characters (Power Automate query strings). UsingEnvironmentFile=avoids systemd treating them as specifiers — do not put the URL directly in the[Service]section withEnvironment=.
To check the service after installation:
sudo systemctl status brewalert
sudo journalctl -u brewalert -n 50Contributions — human or AI — go through the shared brief in AGENT.md. Commit messages must follow docs/commit-style.md. PRs use the auto-loaded template.