Files
alfred-mobile/ALARM_SYSTEM_COMPLETE.md
jknapp 6d4ae2e5c3 Initial commit: Alfred Mobile - AI Assistant Android App
- OAuth authentication via Authentik
- WebSocket connection to OpenClaw gateway
- Configurable gateway URL with first-run setup
- User preferences sync across devices
- Multi-user support with custom assistant names
- ElevenLabs TTS integration (local + remote)
- FCM push notifications for alarms
- Voice input via Google Speech API
- No hardcoded secrets or internal IPs in tracked files
2026-02-09 11:12:51 -08:00

11 KiB

Alfred Mobile Alarm System - Implementation Complete

Date: 2026-02-04
Status: Fully Working
Integration: Alfred App → Proxy → Firebase → Mobile Device

Overview

Implemented a complete alarm and notification system that allows Alfred to send alerts, alarms, and notifications to your mobile device even when the app is closed, screen is locked, or device is asleep.

What Was Fixed Today

1. Firebase Permissions Issue

Problem:

  • Service account had wrong IAM role
  • Was using firebasenotifications.* (legacy API) instead of cloudmessaging.messages.create (v1 API)
  • FCM notifications failing with permission denied errors

Solution:

  • Updated IAM role to: Firebase Admin SDK Administrator Service Agent
  • This role includes the correct cloudmessaging.messages.create permission
  • Regenerated service account key
  • Updated documentation in FCM_SETUP.md

Files Modified:

  • alfred-proxy/service-account.json (replaced with fresh key)
  • alfred-mobile/FCM_SETUP.md (documented correct role)

2. FCM Token Persistence

Problem:

  • FCM tokens stored in memory only
  • Lost when proxy restarted
  • Required app reconnection to re-register
  • Alarms wouldn't work after proxy restarts if tablet was asleep

Solution:

  • Added token persistence to fcm-tokens.json
  • Tokens automatically saved on registration
  • Tokens automatically loaded on proxy startup
  • Alarms now work even after proxy restarts

Files Modified:

  • alfred-proxy/server.js (added loadFcmTokens/saveFcmTokens functions)
  • alfred-proxy/.gitignore (added fcm-tokens.json)

Code Changes:

// Load tokens on startup
loadFcmTokens();

// Save tokens when registered
function saveFcmTokens() {
  const data = {};
  fcmTokens.forEach((tokens, userId) => {
    data[userId] = Array.from(tokens);
  });
  writeFileSync(tokensFile, JSON.stringify(data, null, 2), 'utf8');
}

3. App Token Registration

Problem:

  • App only sent FCM token once using fcm_token_needs_sync flag
  • Token not re-sent after proxy restarts
  • Required manual reconnection to fix

Solution:

  • Removed fcm_token_needs_sync flag logic
  • App now sends FCM token on every connection
  • Token automatically re-registered when app reconnects after proxy restart

Files Modified:

  • alfred-mobile/app/src/main/java/com/openclaw/alfred/ui/screens/MainScreen.kt

Code Changes:

// Before (wrong):
if (fcmToken != null && needsSync) {
    gatewayClient?.sendFCMToken(fcmToken)
    prefs.edit().putBoolean("fcm_token_needs_sync", false).apply()
}

// After (correct):
if (fcmToken != null) {
    Log.d("MainScreen", "Sending FCM token to proxy on connect")
    gatewayClient?.sendFCMToken(fcmToken)
}

4. Created alfred-notify CLI Wrapper

Problem:

  • No easy way to send alarms/notifications from command line or cron
  • Had to manually craft curl commands
  • Error handling not user-friendly

Solution:

  • Created alfred-notify bash script
  • Simple CLI with intuitive options
  • Color-coded output
  • Helpful error messages
  • Support for alarms, custom titles, sound/vibrate control

Files Created:

  • alfred-proxy/alfred-notify (executable bash script)

Usage:

# Simple alarm
alfred-notify --alarm "Wake up!"

# Custom title
alfred-notify --title "Kitchen" "Oven ready"

# Silent notification
alfred-notify --no-sound "Background task done"

5. Documentation Updates

Updated Files:

  • alfred-mobile/FCM_SETUP.md - Correct Firebase IAM role documentation
  • alfred-proxy/README.md - Added FCM architecture and notification API docs
  • alfred-mobile/AGENT_TOOLS.md - Updated to use alfred-notify instead of mobile-notify
  • TOOLS.md - Updated alarm/notification section with alfred-notify usage
  • android-app-todo.md - Documented fixes and added OAuth token refresh as new bug
  • alfred-proxy/SETUP_COMPLETE.md - Created comprehensive setup guide

New Files:

  • alfred-proxy/SETUP_COMPLETE.md - Complete setup and troubleshooting guide
  • alfred-mobile/ALARM_SYSTEM_COMPLETE.md - This file

How It Works

Architecture

Alfred (AI Agent)
    ↓ (via cron or exec)
alfred-notify CLI
    ↓ (HTTP POST)
Alfred Proxy (Node.js)
    - Validates OAuth
    - Stores FCM tokens (fcm-tokens.json)
    - Dual delivery:
        ↓                          ↓
    WebSocket              Firebase Admin SDK
    (if connected)         (always works)
        ↓                          ↓
    Mobile App            Firebase Cloud Messaging
    (instant)                      ↓
                           Mobile Device
                           (even if asleep)

Token Flow

  1. App Connects:

    • Authenticates with OAuth
    • Sends FCM token via WebSocket
    • Proxy saves token to fcm-tokens.json
  2. Proxy Restarts:

    • Loads tokens from fcm-tokens.json
    • Ready to send notifications immediately
  3. App Reconnects:

    • Sends FCM token again (always)
    • Updates token in memory and disk
  4. Notification Sent:

    • Proxy broadcasts via WebSocket (if app connected)
    • Proxy sends via FCM (always)
    • Device receives notification even if asleep

Usage Examples

From Alfred AI

Set an alarm:

User: "Set an alarm for 5 minutes"
Alfred: [creates cron job with alfred-notify]

Send instant notification:

User: "Notify me when the build finishes"
Alfred: [monitors build, then runs alfred-notify]

From Command Line

# Test alarm
alfred-notify --alarm "Test"

# Kitchen timer
alfred-notify --title "Kitchen" "Oven is ready!"

# Silent notification
alfred-notify --no-sound --no-vibrate "Background task complete"

From Cron Jobs

{
  "name": "Morning alarm",
  "schedule": {
    "kind": "cron",
    "expr": "0 7 * * *",  // 7 AM daily
    "tz": "America/Los_Angeles"
  },
  "payload": {
    "kind": "agentTurn",
    "message": "Run: alfred-notify --alarm '⏰ Good morning!'",
    "deliver": false
  },
  "sessionTarget": "isolated"
}

Verification

Test 1: Send Alarm

cd ~/.openclaw/workspace/alfred-proxy
./alfred-notify --alarm "Test alarm"

Expected:

  • Tablet receives notification (even if locked)
  • Console shows: ✓ Notification sent
  • Logs show: [fcm] Successfully sent 1 message(s)

Test 2: Verify Token Persistence

# Restart proxy
systemctl --user restart alfred-proxy.service

# Check tokens loaded
tail -20 /tmp/alfred-proxy.log | grep fcm

# Expected: [fcm] Loaded 1 token(s) for 1 user(s) from disk

Test 3: Send Alarm After Restart

# Send alarm without reconnecting app
./alfred-notify --alarm "After restart test"

Expected:

  • Alarm delivered via FCM
  • Works even if app hasn't reconnected yet

Known Limitations & Future Work

Current Limitations

  1. OAuth Token Expiration

    • Access tokens expire after ~10-60 minutes
    • App doesn't implement token refresh yet
    • Workaround: Logout/login when connection fails
    • TODO: Implement automatic token refresh flow
  2. No Notification History

    • Past notifications not stored
    • Can't view missed notifications in app
    • TODO: Add notification history screen
  3. Single Notification Sound

    • Uses default alarm/notification sound
    • No custom sound selection
    • TODO: Add sound customization

Roadmap

  • OAuth token refresh implementation
  • Notification history in app
  • Custom notification sounds
  • Notification action buttons (snooze, dismiss)
  • Rich notifications (images, progress bars)
  • Do Not Disturb mode
  • Multi-device notification sync

Security

Sensitive Files (Git-Ignored)

  • alfred-proxy/service-account.json - Firebase credentials
  • alfred-proxy/fcm-tokens.json - User device tokens
  • alfred-proxy/.env - Configuration with API tokens

Permissions

  • Service account has minimal required permissions
  • Role: Firebase Admin SDK Administrator Service Agent
  • Only includes: cloudmessaging.messages.create + basic Firebase access
  • No admin, billing, or other sensitive permissions

Best Practices

  1. Rotate service account keys every 90 days
  2. Monitor FCM usage in Firebase Console
  3. Review notification logs regularly
  4. Use chmod 600 for sensitive files

Troubleshooting Guide

Issue: Permission Denied

Error: Permission 'cloudmessaging.messages.create' denied

Fix:

  1. Verify service account role in IAM
  2. Should be: Firebase Admin SDK Administrator Service Agent
  3. Regenerate service account key if needed
  4. Restart proxy

Issue: No Tokens Registered

Error: [fcm] No FCM tokens registered

Fix:

  1. Open Alfred app
  2. Verify "Connected " status
  3. Check logs for token registration
  4. Verify fcm-tokens.json exists

Issue: Notifications Not Arriving

Checklist:

  1. Proxy running? systemctl --user status alfred-proxy.service
  2. Tokens persisted? cat alfred-proxy/fcm-tokens.json
  3. FCM API enabled? Check Google Cloud Console
  4. Service account key valid? Check expiry
  5. Test succeeds? alfred-notify --alarm "Test"

Success Metrics

All Tests Passing

  • Send alarm via CLI
  • Alarm received on locked tablet
  • Token persists across proxy restart
  • Alarm works after restart (without app reconnect)
  • App auto-registers token on connect
  • Dual delivery (WebSocket + FCM)
  • Correct Firebase permissions
  • Documentation complete

Files Modified Summary

New Files

  • alfred-proxy/alfred-notify - CLI wrapper
  • alfred-proxy/fcm-tokens.json - Token storage (git-ignored)
  • alfred-proxy/SETUP_COMPLETE.md - Setup guide
  • alfred-mobile/ALARM_SYSTEM_COMPLETE.md - This document

Modified Files

  • alfred-proxy/server.js - Token persistence logic
  • alfred-proxy/.gitignore - Added fcm-tokens.json
  • alfred-proxy/service-account.json - Updated with fresh key
  • alfred-mobile/app/src/main/java/com/openclaw/alfred/ui/screens/MainScreen.kt - Always send token
  • alfred-mobile/FCM_SETUP.md - Correct IAM role documentation
  • alfred-proxy/README.md - Added FCM architecture
  • alfred-mobile/AGENT_TOOLS.md - Updated to alfred-notify
  • TOOLS.md - Updated alarm section
  • android-app-todo.md - Documented fixes

Next Steps

  1. Build and Deploy

    • App already rebuilt and installed
    • Proxy running with new code
    • FCM configured correctly
  2. Test in Production

    • Set real alarms via Alfred
    • Monitor reliability over next few days
    • Check token persistence after natural restarts
  3. Future Enhancements

    • Implement OAuth token refresh
    • Add notification history
    • Custom notification sounds

Implementation Date: 2026-02-04
Status: Complete and Working
Tested: Yes - All scenarios passing
Documentation: Complete
Ready for Production: Yes