Récupérer les données de son AppleWatch avec le moteur FaaS de CWCloud
Ce blogpost va nous permettre d'illustrer un cas d'utilisation concret de l'utilisation du moteur FaaS1 de CWCloud pour à la fois exposer des fonctions serverless comme webhooks publics et également montrer comment interagir avec des LLM2.
En dehors de l'IT, j'aime pratiquer réguliÚrement certains sports, notamment la course à pied ou encore le powerlifting. Depuis un certain temps, j'utilise une Apple Watch SE pour récupérer les métriques et suivre la progression, entre autres au niveau de l'endurance et du cardio.
Pour un utilisateur "non-tech", le niveau de détail et de présentation des données au cours d'un exercice est trÚs satisfaisant. Ici, vous avez par exemple le détail de ce qui se passe pendant une course : les positions GPS, le rythme cardiaque et les zones tout au long de l'exercice...
La montre donne également plein d'autres données sur la qualité du sommeil, le rythme cardiaque au repos, les calories dépensées... mais il y a toujours eu un souci qui me frustre, comparé à d'autres modÚles que j'ai pu avoir par le passé comme les montres Fitbit : pas d'API et webservices pour les développeurs. Or, j'aurais bien voulu récupérer ces données pour pouvoir les traiter avec des LLM en passant par le moteur FaaS low-code de CWCloud.
Cependant, pas d'API en ligne ne signifie pas pour autant qu'il est impossible de les récupérer : on voit que beaucoup d'applications sur l'iPhone sont capables de malgré tout récupérer les données de la montre, à l'exemple de Strava, MyFitnessPal...
Ces applications passent la plupart du temps par une lecture des données directement depuis l'iPhone en utilisant le framework d'Apple HealthKit et en donnant les permissions nécessaires depuis les paramÚtres de sécurité d'Apple.
Cependant, cela demande quand mĂȘme beaucoup d'efforts pour quelquâun qui nâest pas dĂ©veloppeur mobile iOS de devoir builder et valider une application dĂ©veloppĂ©e en Swift pour envoyer les donnĂ©es sur un webhook. Jâai cherchĂ© Ă voir si quelquâun dâautre nâavait pas dĂ©jĂ fait ce travail. Et câĂ©tait effectivement le cas avec lâapplication Health Auto Export_.
Cette application est assez mal notée, mais quand on lit les commentaires, on comprend parfaitement pourquoi : les gens n'ont pas compris à quoi elle servait. Entre autres, elle ne sert pas à faire de jolis dashboards d'agrégations statistiques, mais à exporter les données de santé d'Apple dans des formats exploitables par des développeurs (CSV ou JSON), et également à programmer des envois schedulés de ces exports vers des connecteurs externes (webhook REST/HTTP, fichiers MQTT, Dropbox...).
Dans notre cas, câest trĂšs exactement ce quâil nous fallait. Voici comment configurer, par exemple, un webhook HTTP pour envoyer les donnĂ©es Ă CWCloud dans une automation qui va tourner toutes les minutes :
Toutes les minutes, la fonction serverless de CWCloud va recevoir comme payload un JSON au format suivant :
{
"data" : {
"metrics" : [
{
"units" : "count\/min",
"data" : [
{
"Min" : 79,
"date" : "2025-06-30 23:17:40 +0200",
"Avg" : 79,
"Max" : 79,
"source" : "Idrissâs Apple Watch"
},
{
"Min" : 66,
"Max" : 66,
"Avg" : 66,
"source" : "Idrissâs Apple Watch",
"date" : "2025-06-30 23:23:45 +0200"
},
{
"Max" : 66,
"date" : "2025-06-30 23:26:52 +0200",
"source" : "Idrissâs Apple Watch",
"Min" : 66,
"Avg" : 66
}
],
"name" : "heart_rate"
}
]
}
}
Dans l'automation, on pourra noter que jâai filtrĂ© uniquement la mĂ©trique heart_rate
, car sinon cela pourrait en envoyer beaucoup dâautres, et pas uniquement provenant de lâApple Watch, mais Ă©galement dâautres applications comme MyFitnessPal, qui fait le tracking de vos macros (calories, protĂ©ines, lipides, glucides, calcium, etc.) de votre alimentation. Bref, il y a vraiment de quoi faire des usecases trĂšs intĂ©ressants đ.
Cela Ă©tant, ce payload nâest pas compatible avec le contrat dâinterface de notre moteur serverless avec les endpoints classiques que nous avons documentĂ©s dans plusieurs dĂ©mos, oĂč lâon attend Ă lâavance les paramĂštres de votre fonction.
Il existe toutefois un endpoint /v1/faas/webhook/{function_id}
(ou /v1/faas/webhook/{function_id}/sync
si vous souhaitez recevoir la réponse de la fonction en synchrone dans la réponse HTTP). Dans ce cas, il faut que votre fonction soit définie avec un unique argument raw_data
comme ceci :
Une fois que câest fait, il devient trĂšs simple dâinvoquer la fonction en lui passant ce que vous voulez comme body, que vous pourrez ensuite parser directement dans votre code :
$ curl "https://api.cwcloud.tech/v1/faas/webhook/ecb10330-02bf-400b-b6a8-d98107324ac3/sync" -X POST -d '{"foo":"bar"}' 2>/dev/null|jq .
{
"status": "ok",
"code": 200,
"entity": {
"id": "78774026-f75e-4c7c-850a-9b9eb2cb2ec0",
"invoker_id": 3,
"updated_at": "2025-07-05T14:39:53.119780",
"content": {
"args": [
{
"key": "raw_data",
"value": "{\"foo\":\"bar\"}"
}
],
"state": "complete",
"result": "The data is : {\"foo\":\"bar\"}\n",
"user_id": null,
"function_id": "ecb10330-02bf-400b-b6a8-d98107324ac3"
},
"created_at": "2025-07-05T14:39:52.443918"
}
}
Vous l'aurez compris, dans l'automation de l'application Health Auto Export c'est une URL au format https://api.cwcloud.tech/v1/faas/webhook/{function_id}
qu'il faudra définir (pas besoin du /sync
à la fin car vous n'aurez pas besoin d'attendre le résultat de l'exécution de la fonction).
Note : on a aussi exposĂ© la fonction en public pour pouvoir lâinvoquer sans authentification, mais ce nâest pas forcĂ©ment ce qui est souhaitable. Nâoubliez pas que vous ĂȘtes facturĂ©s aux tokens que vous consommerez dans le cas ou vous utilisez des modĂšles publics. Donc ici on le fait Ă des fins illustratives mais vous nâallez pas forcĂ©ment vouloir que tout le monde invoque votre webhook. Vous pouvez trĂšs bien gĂ©rer cela en gardant la fonction privĂ©e et en ajoutant un header X-User-Token
dans lâautomation sur lâapplication Health Auto Export.
Maintenant quâon sait comment crĂ©er un webhook, voici le code Blockly3 pour extraire la moyenne de votre heart rate, lâenvoyer au LLM gpt4omini
. Ici, on a demandĂ© au LLM de rĂ©agir avec un emoji Ă la valeur quâil reçoit et dâenvoyer le rĂ©sultat dans Discord :
Vous pouvez observer que je passe la phrase suivante "You're reacting with an emoji only if the heart rate is too slow or to high" comme prompt systÚme ainsi que le nombre de battements cardiaque récupérée des données de l'Apple Watch comme prompt utilisateur.
En outre, il faut savoir que les blocs AI vous obligent à vous authentifier pour pouvoir invoquer l'API CWCloud AI. Si vous voulez conserver le fait d'ouvrir ce webhook à n'importe qui il faudra créer une clef d'API en suivant ce tutoriel et en injectant cette clef dans une variable d'environnement AUTH_HEADER_VALUE
comme ceci :
Dans ce cas tous le monde pourra invoquer votre webhook et c'est votre compte qui sera facturĂ© Ă la consommation si vous utilisez des modĂšles d'IA publics. Vous pouvez aussi chosir d'utiliser votre propre LLM hĂ©bergĂ© sur vos instances Ă la place et dans ce cas cela ferait plus sens de garder le webhook public đ.
Il faut également savoir que si la variable AUTH_HEADER_VALUE
est définie, elle est prise en priorité sur l'authentification lorsque vous invoquez le webhook de façon authentifiée.
On peut également remarquer dans la capture d'écran précédant qu'un webhook pour Discord a été défini dans une autre variable d'environnement DISCORD_WEBHOOK_URL
afin d'ĂȘtre utilisĂ© pour envoyer la rĂ©ponse du LLM dans Discord, et voici le rĂ©sultat :
On peut voir que jusqu'ici tout va bien cĂŽtĂ© cardio, rien Ă signaler đ