- TypeScript 66%
- Makefile 18.6%
- Shell 15.4%
| .github | ||
| src | ||
| .env.example | ||
| .eslintignore | ||
| .eslintrc.json | ||
| .firebaserc | ||
| .gitignore | ||
| .prettierrc.js | ||
| CONTRIBUTING.md | ||
| firebase.json | ||
| init-smarthome.sh | ||
| LICENSE | ||
| Makefile | ||
| package-lock.json | ||
| package.json | ||
| QUICKSTART.md | ||
| README.md | ||
| test-fulfillment.sh | ||
| tsconfig.json | ||
Toggle Virtuel Google Home pour Homelab TrueNAS
Ce projet permet de contrôler votre homelab TrueNAS via Google Home avec un switch virtuel.
Fonctionnalités
- Allumage : Wake-on-LAN (WOL) pour démarrer le serveur
- Extinction : Appel HTTP vers une API personnalisée pour arrêter le serveur
- Vérification d'état : Ping HTTP pour connaître l'état réel du serveur
- Sécurité : Variables d'environnement Firebase pour les informations sensibles
Prérequis
- Node.js >= 18
- Firebase CLI :
npm install -g firebase-tools - Un projet Firebase créé
- Proxy WOL configuré (si vous utilisez depuis le cloud)
- Endpoint HTTP pour vérifier l'état du serveur (optionnel mais recommandé)
Installation
# Cloner le projet
git clone <votre-repo>
cd smart-home-nodejs
# Installer les dépendances
npm install
# Se connecter à Firebase
firebase login
# Sélectionner votre projet Firebase
firebase use homelab-f227c
Configuration
1. Variables d'environnement Firebase
Configurez les variables d'environnement pour votre serveur :
# Configuration WOL (obligatoire)
firebase functions:config:set \
wol.mac="XX:XX:XX:XX:XX:XX" \
wol.broadcast="192.168.1.255" \
wol.port="9"
# Configuration ping/health check (recommandé)
firebase functions:config:set \
ping.method="http" \
ping.url="https://votre-domaine.com/health" \
ping.timeout="2000"
# Configuration shutdown (optionnel pour l'instant)
firebase functions:config:set \
shutdown.url="https://votre-domaine.com/api/shutdown" \
shutdown.method="POST" \
shutdown.token="votre-token-secret-32-caracteres"
Notes importantes :
wol.mac: Adresse MAC de votre serveur TrueNAS (format XX:XX:XX:XX:XX:XX ou XX-XX-XX-XX-XX-XX)wol.broadcast: Adresse broadcast de votre réseau local (généralement X.X.X.255)ping.url: URL pour vérifier si le serveur est allumé (voir options ci-dessous)shutdown.token: Token d'authentification pour l'API de shutdown (à générer aléatoirement)
2. Configuration locale pour les tests
Pour tester localement, créez un fichier .runtimeconfig.json :
firebase functions:config:get > .runtimeconfig.json
Ou créez-le manuellement :
{
"wol": {
"mac": "XX:XX:XX:XX:XX:XX",
"broadcast": "192.168.1.255",
"port": "9"
},
"ping": {
"method": "http",
"url": "https://votre-domaine.com/health",
"timeout": "2000"
},
"shutdown": {
"url": "https://votre-domaine.com/api/shutdown",
"method": "POST",
"token": "votre-token-secret"
}
}
Endpoint de vérification d'état (Health Check)
Pour que Google Home affiche l'état correct du serveur, vous avez plusieurs options :
Option 1 : Nginx/Reverse Proxy Health Check (Recommandé)
Configurez une route /health sur votre reverse proxy qui retourne 200 si TrueNAS est accessible :
location /health {
access_log off;
proxy_pass http://truenas-ip/api/v2.0/system/info;
proxy_connect_timeout 2s;
proxy_read_timeout 2s;
}
Option 2 : Endpoint personnalisé léger
Créez un endpoint HTTP simple qui répond {"status": "ok"}. Pas besoin d'authentification car il sert uniquement à vérifier si le serveur est allumé.
Option 3 : API TrueNAS
Utilisez l'API TrueNAS existante (ex: /api/v2.0/system/info). Attention : nécessite d'exposer une API key.
Test local
# Compiler le code
npm run build
# Démarrer l'émulateur Firebase
npm run serve
L'émulateur démarrera les fonctions sur http://localhost:5001/homelab-f227c/us-central1/
Testez les endpoints :
# Test fulfillment (nécessite un token d'auth valide)
curl http://localhost:5001/homelab-f227c/us-central1/fulfillment
# Test auth provider
curl http://localhost:5001/homelab-f227c/us-central1/authProvider/fakeauth
Déploiement
# Vérifier la compilation et le linting
npm run build
npm run lint
# Déployer sur Firebase
firebase deploy --only functions
# Noter les URLs générées (exemple) :
# ✔ functions[fulfillment(us-central1)]: https://us-central1-homelab-f227c.cloudfunctions.net/fulfillment
# ✔ functions[authProvider(us-central1)]: https://us-central1-homelab-f227c.cloudfunctions.net/authProvider
Configuration Google Smart Home
1. Créer le projet dans Google Actions Console
- Allez sur Actions Console
- Créer un nouveau projet
- Sélectionner "Smart Home"
2. Configurer Account Linking (OAuth)
Dans la section "Account Linking" :
- Authorization URL :
https://us-central1-homelab-f227c.cloudfunctions.net/authProvider/fakeauth - Token URL :
https://us-central1-homelab-f227c.cloudfunctions.net/authProvider/faketoken - Client ID : n'importe quelle valeur (ex: "client-123")
- Client Secret : n'importe quelle valeur (ex: "secret-456")
- Scopes : laisser vide ou mettre "email"
Note : C'est un fake OAuth pour simplifier le développement. En production, utilisez un vrai système OAuth.
3. Configurer Fulfillment
Dans la section "Actions" :
- Fulfillment URL :
https://us-central1-homelab-f227c.cloudfunctions.net/fulfillment
4. Tester
- Ouvrez l'app Google Home sur votre téléphone
- Appuyez sur "+" puis "Configurer un appareil"
- Sélectionnez "Fonctionne avec Google"
- Cherchez "[test] Homelab Control" (ou le nom de votre projet)
- Liez votre compte (fake OAuth)
- Le switch "Serveur Maison" devrait apparaître
5. Utilisation
Commandes vocales :
- "Ok Google, allume le serveur"
- "Ok Google, éteins le serveur"
- "Ok Google, le serveur est allumé ?"
Service Shutdown (à créer sur TrueNAS)
Pour permettre l'extinction sécurisée, créez un service sur votre TrueNAS qui écoute les requêtes HTTP :
Exemple d'implémentation (Python/Flask)
from flask import Flask, request, jsonify
import os
import subprocess
import time
from functools import wraps
app = Flask(__name__)
# Token d'authentification (le même que shutdown.token dans Firebase)
SHUTDOWN_TOKEN = os.getenv('SHUTDOWN_TOKEN', 'votre-token-secret-32-caracteres')
# Rate limiting simple
last_requests = []
MAX_REQUESTS = 3
TIME_WINDOW = 60 # secondes
def rate_limit(f):
@wraps(f)
def decorated_function(*args, **kwargs):
global last_requests
now = time.time()
last_requests = [req for req in last_requests if now - req < TIME_WINDOW]
if len(last_requests) >= MAX_REQUESTS:
return jsonify({'error': 'rate_limit_exceeded'}), 429
last_requests.append(now)
return f(*args, **kwargs)
return decorated_function
@app.route('/api/shutdown', methods=['POST'])
@rate_limit
def shutdown():
# Vérifier l'authentification
auth = request.headers.get('Authorization')
if not auth or auth != f'Bearer {SHUTDOWN_TOKEN}':
app.logger.warning(f'Unauthorized shutdown attempt from {request.remote_addr}')
return jsonify({'error': 'unauthorized'}), 401
# Logger la requête
app.logger.info(f'Shutdown requested from {request.remote_addr}')
try:
# Arrêter le système
subprocess.run(['shutdown', '-h', 'now'], check=True)
return jsonify({'success': True, 'message': 'Shutdown initiated'})
except Exception as e:
app.logger.error(f'Shutdown failed: {e}')
return jsonify({'error': 'shutdown_failed'}), 500
@app.route('/health', methods=['GET'])
def health():
return jsonify({'status': 'ok', 'timestamp': time.time()})
if __name__ == '__main__':
# Écouter uniquement sur localhost (exposer via reverse proxy)
app.run(host='127.0.0.1', port=5000)
Sécurité
Important : Ce service doit être sécurisé car il permet d'arrêter votre serveur :
-
Token fort : Générer un token aléatoire de 32+ caractères
openssl rand -hex 32 -
Rate limiting : Limiter à 3-5 requêtes par minute maximum
-
Logging : Logger toutes les tentatives (succès et échecs)
-
HTTPS obligatoire : Ne jamais exposer en HTTP
-
Pas d'exposition directe : Passer par un reverse proxy (Nginx)
-
Optionnel : Whitelist des IPs Google Cloud Functions
Configuration Nginx pour le service shutdown
location /api/shutdown {
proxy_pass http://127.0.0.1:5000/api/shutdown;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Timeout court
proxy_connect_timeout 5s;
proxy_read_timeout 5s;
# Optionnel : Whitelist IPs Google Cloud
# allow 34.64.0.0/11;
# deny all;
}
Dépannage
Le serveur ne s'allume pas (WOL)
- Vérifiez que WOL est activé dans le BIOS
- Vérifiez l'adresse MAC dans la config
- Testez WOL manuellement depuis votre réseau local
- Si vous utilisez un proxy WOL, vérifiez qu'il fonctionne
L'état du serveur est toujours offline
- Vérifiez que
ping.urlest configuré et accessible - Testez l'URL manuellement :
curl https://votre-domaine.com/health - Vérifiez les logs Firebase :
firebase functions:log - Augmentez le timeout :
firebase functions:config:set ping.timeout="5000"
Le serveur ne s'éteint pas
- Le service shutdown n'est peut-être pas encore créé (c'est normal)
- Vérifiez que
shutdown.urletshutdown.tokensont configurés - Vérifiez les logs du service shutdown sur TrueNAS
- Testez manuellement :
curl -X POST https://votre-domaine.com/api/shutdown \ -H "Authorization: Bearer votre-token"
Erreurs de compilation
# Nettoyer et réinstaller
rm -rf node_modules build
npm install
npm run build
Voir les logs Firebase
# Logs en temps réel
firebase functions:log --only fulfillment
# Ou sur la console Firebase
# https://console.firebase.google.com/project/homelab-f227c/functions/logs
Prochaines étapes
- ✅ Configuration des variables d'environnement
- ✅ Test local avec l'émulateur
- ✅ Déploiement sur Firebase
- ✅ Configuration Google Actions Console
- ⏳ Créer l'endpoint health check sur TrueNAS
- ⏳ Créer le service shutdown sécurisé sur TrueNAS
- ⏳ Tester l'allumage et l'extinction complète
Licence
Apache-2.0