Adding an AI Fitness coach to a Smart Scale
Last updated:
We have previously hooked up the eufy Smart Scale to Home Assistant. Lets connect the data we get to an AI Assistant so it can coach us on our fitness goals. While it is also possible to implement this using native Home Assistant automations I found it quite cumbersome to debug, so instead I went with a Node-Red which is fairly straight forward for this use case.
Setup
Prerequisites
- Home Assistant with the Node-Red Add-on setup.
- An AI integration is set up to act as a conversation agent.
Setting up the Node-Red Automation
-
Create a Node-RED flow
- Create a new flow by clicking on the ”+” icon.
- Drag and drop an “inject” node, a “state” node, a “get history” node, three “function” nodes, an “API” node and a “debug” node into the workspace.
The output of every node while working on it can be seen by connecting it to the debug node and selecting the debug tab on the right sidebar. We can connect multiple nodes simultaneously to the same debug node which makes it easy to see any mistakes in any of the steps.
We will build up the autmoation node by node, connecting them up one by one.
-
Configure the “inject” node
- We will be using this to debug the output of each step, we can trigger the automation anytime after deploying by clicking its button.
-
Configure the “get history” node
- Double-click on the “get history” node to configure it.
- Lets name it
getWeightMeasurements
. - Select the sensor entity that stores the weight measurements.
- Check “Use relative time” and select a suitable time range e.g.
7d
. - Output type is
array
, Output location is the defaultmsg.payload
.
This give us a list of measurements, that looks like this:
{"entity_id":"sensor.weight","state":"81.25","attributes":{"state_class":"measurement","unit_of_measurement":"kg","device_class":"weight","friendly_name":"Weight"},"last_changed":"2025-03-21T12:08:28.123122+00:00","last_updated":"2025-03-21T12:08:28.123122+00:00"}That’s a lot of extraneous data that we will cull with the next function node.
-
Configure the
toSimpleList
“function” node- Double-click on the “function” node to configure it.
- Name it
toSimpleList
. - Add code to only keep the weight and timestamp of each measurement and prune it so a manageable amount of entries:
const maxEntries = 8;function toSimpleList (item = {}) {const {state,last_updated: timestamp} = item;const value = parseFloat(state);if (!value || !timestamp) return null;const unit = item.attributes?.unit_of_measurement || 'kg';const weight = `${value} ${unit}`;return {weight,timestamp}}const measurementsToAnalyze = msg.payload.map(toSimpleList).filter(Boolean).slice(-maxEntries);return {payload: measurementsToAnalyze}; -
Configure the
simpleListToAiRequest
“function” node- Double-click on the “function” node to configure it.
- Name it
simpleListToAiRequest
. - Add code convert the structured data into an AI prompt:
const weightMeasurements = JSON.stringify(msg.payload);return {payload: `You are a health coach, famous for phrasingsentences with laconic wit. The person tracking theirweight is 175 cm tall, with an target weight of 70 kg.Here is the JSON data of the weight measurements of the lastfew days: \`${weightMeasurements}\`.Based on the weight trend and their current weight,analyze the progress and estimate a target date.`.replace(/\n/g, ' ')}; -
Configure the “API” node
- This node will send the request to Home Assisttant’s AI conversation agent.
- Double-click on the “API” node to configure it.
- Name it
getAiResponse
. - Set “Protocol”
Webocket
. - Set “msg.payload” to
results
. - Set Data to JSON format and paste the request config:
{"type": "execute_script","sequence": [{"service": "conversation.process","data": {"agent_id": "conversation.openai_conversation","text": "{{payload}}"},"response_variable": "service_result"},{"stop": "done","response_variable": "service_result"}]} -
Configure the
getAiResponse
“function” node- Double-click on the “function” node to configure it.
- Name it
getAiResponse
. - Add code convert retrieve the AI response text from the response object:
const weightMeasurements = JSON.stringify(msg.payload);return {payload: msg.payload.response.response.speech.plain.speech};This could be extended to output the response to a nearby speaker.
-
Connect the nodes and test
- Connect the nodes in series and test if everything works.
-
Add an automatic trigger when using the scale
- Double-click on the “state” node to configure it.
- Name it
weightMeasurementTrigger
. - Select the weight sensor as the entity.
- “State type” is
String
. - Connect it up to the
getWeightMeasurements
node.
Conclusion
Node-Red on Home Assistant allows us to easily integrate an LLM with our smart scale. Depending on our individual requirements we can now tweak the AI prompt to provide better advice tailored to our needs. Note that there may be issues if the prompt sent to the TTS engine is too long. This could be mitigated by splitting the response into smaller chunks and sending them one at a time.
We have built a simple flow, but this could be extended with additional sensors or data points to provide more comprehensive coaching.