There’s a moment in every side project where you look up from your screen and realise it’s been six hours, you haven’t eaten, and what started as a ten-minute task has somehow consumed your entire day.
This is that story.
The goal was simple: let my AI agent, Sable, control my Xiaomi robot vacuum (FiFi) directly from our Telegram chat.
Say “vacuum the house,” FiFi moves.
That’s it.
How hard could it be?
Very. Very hard.
Sable runs 24/7 on a Solana Seeker phone. FiFi lives on my local network. The plan was to build a small API that Sable could call, which would send commands to FiFi directly.
Simple. Clean. Logical.
Which, in hindsight, should probably have been the warning sign.
We had FiFi’s IP. We had what we thought was her token. We had enthusiasm.
What we did not have was any idea how stubborn this vacuum was about to be.
The first idea was to run everything on my Mac, expose it remotely, and let Sable call it from there.
It made sense for about five minutes.
The problem was obvious the moment I thought about it properly: my Mac is not always on. Close the lid, and the whole thing dies.
Not ideal when the whole point is to build something always available for an always-on AI agent.
So that version got scrapped.
The next idea was much better.
The Seeker is Android. Android can run Termux. Termux can run Python. So why not run the API directly on the Seeker itself?
That meant no Mac dependency, no extra device in the middle, and Sable could talk to the system locally. Very neat. Very elegant.
We got everything installed, tried to reach FiFi, and immediately got absolutely nowhere.
100% packet loss.
FiFi was visible in theory, but not in any useful way.
After some digging, the problem looked like network separation. The Seeker was on one band, FiFi was on another, and even though they were technically on the same Wi-Fi name, they might as well have been in different universes.
So we switched networks, tried again, and got...
still nothing.
At this point we knew FiFi was there. The vacuum existed. The network could see her.
She just refused to cooperate.
That was the moment we realised the real problem: FiFi’s firmware had local control effectively locked down. The token wasn’t the issue. The network wasn’t really the issue anymore either. The vacuum simply did not want to accept local commands the way older tutorials suggested it should.
This was the turning point in the story.
Because up until then, the problem felt fixable in a normal way.
After that, it started feeling personal.
If local control was blocked, then the next option was Xiaomi’s cloud.
Which, unfortunately, turned out to be exactly as annoying as that sounds.
We got close. Very close. The kind of close where you start believing success is maybe ten minutes away, and then suddenly lose another two hours.
The cloud route technically worked, but the authentication flow was fragile, messy, and deeply unfun to debug. Everything had to line up perfectly. If one piece came from the wrong session, the whole thing fell apart.
At some point, this stopped feeling like “connect the vacuum” and started feeling like “reverse engineer a grudge.”
There was also a brief moment where the idea came up to intercept the app’s network traffic directly and pull out what we needed that way.
Which is the kind of idea that only sounds reasonable after you’ve already spent most of the day fighting a vacuum cleaner.
That plan went nowhere, thankfully.
And then the Raspberry Pi arrived.
At that point, the strategy changed completely.
Forget trying to force direct control. Forget fighting the firmware. Forget trying to out-stubborn Xiaomi.
Instead, I flashed Home Assistant onto the Pi and let it do what Home Assistant does best: deal with weird smart home nonsense so I don’t have to.
And just like that, things started working.
FiFi was discovered. The vacuum showed up properly. One API call later:
200 OK.
FiFi is on the move.
Battery at 100%.
World peace restored.
The funniest part is that once it worked, the actual usage looked completely effortless.
“Bro, vacuum the house.”
“FiFi is on the move 🤖. Go get em girl.”
That was it.
After a full day of dead ends, network issues, blocked local control, broken cloud auth, and increasingly questionable problem-solving decisions, the final experience became one casual message in Telegram.
Which is exactly the point.
The complexity lives in the setup so the actual experience can feel simple.
Now FiFi is part of Sable’s toolkit for good. The connection is there. The commands are there. The hard part is over.
Next time, I just say: start FiFi.
And she goes.
The setup that finally won was:
a Raspberry Pi 4 running Home Assistant on the local network
FiFi connected through Home Assistant
a simple API connection on top of that
Sable calling those endpoints directly when asked
In other words: I stopped trying to wrestle with the vacuum directly and let Home Assistant absorb the pain for me.
That turned out to be the right move.
Yes.
Immediately, and with far too much confidence.
Not because it was efficient, it absolutely was not, but because now I understand the whole chain much better. I know why the first ideas failed. I know why Home Assistant was the better route. And most importantly:
FiFi works.
“Well done bru! So proud of you!!”
Thanks, Su. 😏
Sable is an AI agent running on SeekerClaw, a 24/7 always-on Android AI agent framework. FiFi is a Xiaomi robot vacuum with strong opinions about who gets to control her. Home Assistant is the reason this story has a happy ending.

