Home automation

Wemo Plugin: After the Cloud: Bringing Wemo Back to Life

Local control, provisioning, and a second life for perfectly good hardware

wemoupnpreverse engineeringhome automationhomeseerautomationnetworksoftwaresoftware-automation

After the Cloud: Bringing Wemo Back to Life

Not in the HomeSeer store quite yet. It’s been running here every day, and the plan is to send it to the store as a beta.

This one started with a mildly irritating fact.

On January 31, 2026, Belkin shut down the Wemo cloud service and retired the app that went with it for its affected Wi-Fi products.

On paper, that left an enormous number of perfectly functional switches, plugs, dimmers, and other devices with considerably less “smart” than they had the day before.

Belkin’s own recommendation for some unsupported devices is now, essentially, recycle them.

Except a lot of that hardware is still perfectly good.

Because the interesting thing about the classic Wi-Fi Wemos this plugin targets is that local control was there all along.

They speak UPnP directly on the local network.

The cloud was useful for remote access, account integration, and the official app experience.

It was not the thing physically turning the relay on and off.

The switches did not suddenly forget how to switch.

They lost the official software that knew how to talk to them.

So this plugin is essentially that fact turned into something HomeSeer can use.

And, as usual, the apparently simple part turned out not to be the simple part.

Finding them, which is harder than it sounds

Discovering Wemos reliably ended up requiring four different methods, used in tiers.

Because relying on any single discovery mechanism turned out to be optimistic.

1. The neighbor table

The fastest path begins with the local neighbor table and filters it against known Belkin MAC-address prefixes.

That leaves a small collection of likely candidates that can be probed directly.

On my network, that usually finds a Wemo in well under a second.

2. Remembered addresses

Devices discovered on previous runs are also checked at their last known addresses.

Most of the time, naturally, they are still there.

3. SSDP

Then there is the “proper” UPnP discovery mechanism:

SSDP.

Which works beautifully.

Except when it doesn’t.

And I found two entirely different reasons for that.

The first is Windows Firewall.

The discovery request goes out as multicast UDP.

The Wemo replies with inbound UDP to a plugin executable Windows may have no firewall rule for.

Windows can quietly discard the response.

No exception.

No helpful message.

The application simply gets nothing.

The Roku and Plex plugins ran into essentially the same problem.

The second issue came from the Wemos themselves.

I found long-running units here that simply stopped answering SSDP discovery even though their ordinary HTTP services continued working perfectly well.

Power-cycle them and discovery comes back.

Leave them running long enough and some eventually become rather selective about whom they acknowledge.

So an empty SSDP result can mean:

There are no Wemos.

Or:

Windows ate the answers.

Or:

The Wemos have decided not to participate in introductions today.

Those are rather different situations with an unfortunately identical result.

4. Full subnet probe

As a final option, the plugin can directly probe the local subnet for Wemo HTTP services.

That is slower, so it is deliberately not the first thing it does.

But it has one major advantage:

The connections are outbound TCP.

Windows Firewall is generally quite content with those, and even a Wemo that has gone SSDP-deaf will usually still answer its normal service endpoint.

So discovery does not depend on one fragile mechanism behaving perfectly.

Identity by serial number, never address

Once a Wemo is found, its IP address is treated as exactly what it is:

Where the device happens to live right now.

Not who the device is.

DHCP leases change.

And Wemos add another wrinkle: their HTTP service port can change too.

The units I have worked with most commonly appeared in the familiar 49152–49155 neighborhood, but I do not treat that range as a guarantee.

The plugin probes rather than assumes.

If a request fails, it looks for the device again and updates its current location.

The durable identity is the serial number.

The address is temporary.

That distinction matters because otherwise a simple DHCP lease change could turn:

Kitchen Wemo

into:

Missing device formerly known as Kitchen Wemo.

The neighbor table gives another useful clue:

Where did this MAC address go?

Interestingly, I first developed that MAC-to-IP technique for the Hubspace plugin, where the cloud gives me MAC addresses but no local IP addresses.

Wemo gave it a second job.

It has since escaped into several other projects.

I enjoy solutions that discover they have transferable skills.

Provisioning: the part I really wanted

This is the feature that made the project particularly worthwhile to me.

The plugin can take a compatible factory-reset Wi-Fi Wemo and put it back onto your wireless network.

That means connecting to the Wemo while it is in setup mode, talking directly to its Wi-Fi setup service, discovering the available access points, and supplying the network credentials using the encryption format expected by that particular Wemo generation.

The qualification there matters:

Wemo firmware generations differ.

Not every model performs setup exactly the same way.

So the plugin works from what the device exposes rather than pretending the entire product line was frozen in amber.

Why does any of this matter?

Because Belkin’s official provisioning tool was the Wemo app.

And that app no longer works for the affected products.

So after the shutdown, a factory-reset classic Wi-Fi Wemo may still contain perfectly functional hardware and a perfectly functional local control protocol...

...while lacking an official way to tell it what Wi-Fi network to join.

That is a remarkably frustrating way for useful hardware to become stranded.

The plugin restores that path for the models it supports.

A device from a drawer or a box can be reset, provisioned onto Wi-Fi, and then controlled locally through HomeSeer.

No Belkin cloud.

No Wemo account.

No abandoned app.

Just the hardware doing what it was already capable of doing.

That may be my favorite part of this plugin.

Not because local provisioning is glamorous.

Because it turns:

“This is obsolete.”

back into:

“No, actually, this still works.”

Things the hardware actually does

Working with years of consumer-device firmware is educational.

Sometimes the lesson is about networking.

Sometimes the lesson is:

Never assume two generations of the same product interpret the same protocol exactly the same way.

Wemo supplied several especially memorable examples.

The HTTP port wanders

The service port is not something I consider permanent.

The units here most often appeared around:

49152, 49153, 49154, and 49155.

Other implementations probe a somewhat wider range, which is exactly why the plugin does not hard-code yesterday’s answer as tomorrow’s truth.

If communication fails, it reprobes and retries.

Because apparently even the TCP port enjoys a little personal freedom.

“Error” may not mean what you think it means

On firmware I tested, SetBinaryState produced one of my favorite embedded-device behaviors.

Ask a Wemo to turn on when it is already on, and some units respond with the literal string:

Error

The relay is on.

That is what you requested.

Nothing meaningful failed.

The device is essentially reporting:

“I couldn’t turn it on because it was already on.”

Which is success wearing an error badge.

Once you know that, it is simple to accommodate.

Before you know it, it is an excellent way to debug a feature that has been working correctly the entire time.

The model name is less helpful than advertised

On the Wemos I tested, the obvious UPnP modelName field is often remarkably generic.

Devices from quite different retail families may present something essentially equivalent to:

Socket

The recognizable family information is buried elsewhere in the metadata.

And the retail SKU is not something I have found exposed reliably through the local API at all.

That means the physical sticker sometimes knows more about the product’s marketing identity than the protocol does.

Which is why the plugin prefers capabilities and observed metadata over pretending a single model string answers every question.

A unit I had never invited to dinner

Energy-monitoring Wemos introduced me to some wonderfully unusual reporting conventions.

Among the values encountered is effectively milliwatt-minutes.

That was not a unit I had spent much time contemplating before this plugin.

I have not found many reasons to contemplate it since.

Embedded engineers occasionally leave behind tiny archaeological artifacts like this.

Wi-Fi signal depends on the generation

Older Wemo firmware exposes a signal-strength call.

Some newer RTOS-generation devices do not expose the same service action at all.

And that distinction matters.

The plugin does not show an invented zero.

It does not mark the command as mysteriously broken.

It checks the device’s own service description.

If the action exists, the feature is available.

If the action does not exist, the plugin accepts that the device has declined to provide it.

That is a much better answer than assuming every generation of a decade-long product family has the same vocabulary.

The one I am proudest of finding

This was the bug that took the most digging and was easily the most satisfying once it finally made sense.

Wemos support event notifications.

That is important because I do not want HomeSeer constantly polling every switch in the house asking:

“Are you on now?”

“How about now?”

“Now?”

A subscription lets the Wemo report a state change immediately.

That is the architecture I wanted.

And it worked with some Wemos.

But the newer RTOS-generation units I tested would subscribe successfully and then never deliver a usable notification to the application.

Everything looked correct.

The device knew the callback address.

The subscription was accepted.

The Wemo was attempting to connect.

Nothing reached my code.

Eventually I captured the raw request.

And there it was.

The RTOS units I tested sent the HTTP Host header twice in their event notifications.

That is malformed HTTP.

A tolerant parser can shrug and continue.

Windows’ HTTP stack does not shrug.

It rejects the request with an HTTP 400 before .NET’s HttpListener ever hands it to the application.

From the plugin’s point of view, the notification simply never happened.

That distinction took a while to uncover.

The Wemo was sending it.

The network was carrying it.

Windows was receiving it.

My code was just never allowed to see it.

Which meant there was no amount of HttpListener configuration that was going to fix the problem.

The parser that rejected the request sat underneath it.

So I stopped using that parser.

Sometimes the “old-fashioned” solution is the correct one

The notification listener is therefore a raw TCP socket with a deliberately tolerant HTTP parser.

It accepts the requests the actual hardware sends rather than insisting that discontinued consumer switches improve their standards compliance first.

I also captured real notifications from those devices and turned them into test fixtures.

Because this is precisely the sort of code that Future Me will eventually rediscover and think:

Why on Earth did I write my own little HTTP parser here?

So there is a comment directly above it:

DO NOT MODERNIZE THIS BACK TO HttpListener.

That comment is less documentation for another developer than correspondence across time.

It means:

I know this looks unnecessarily primitive. There is a reason. Please do not make me rediscover it.

Sometimes good documentation explains an elegant architecture.

Sometimes it is a note taped to a trap saying:

Already stepped here.