Emporia: Energy Monitoring In HomeSeer
What started with a few smart plugs turned into a two-way energy manager, a cloud API deep dive, and an unfinished hunt for local control.
Building the Emporia Plugin for HomeSeer
It started, as a lot of these projects do, with a small frustration and a bigger question.
I had an Emporia Vue watching my electrical panel and a handful of Emporia smart plugs in use, plus a pile of additional plugs still sitting in their boxes because they effectively lived in their own world.
They worked in Emporia's app.
HomeSeer knew nothing about them.
So the question was simple:
Could HomeSeer see them?
First, looking for a local way in
Before writing a line of plugin code, I wanted to know whether I could communicate with the devices locally.
No cloud. No dependency on someone else's servers. Just the devices on my own network.
So I approached them the same way I would any unfamiliar network device.
Full port sweep.
mDNS.
SSDP.
Anything that might provide a way in.
Every one of the 65,535 TCP ports came back closed.
I ran it again.
Same result.
The devices answer a ping and essentially nothing else. They behave as pure outbound clients.
I did find the monitor's connection to Emporia's cloud, an MQTT connection over port 8883, and followed that far enough to watch it validate a certificate chained to Emporia's own private CA.
In other words, simply pretending to be Emporia's server wasn't a trivial shortcut.
The device checks.
So there was no straightforward local-control path, at least not one the devices were volunteering.
For the first version of the plugin, the cloud API was clearly the practical way forward.
But I have not given up on local control.
That rabbit hole is merely postponed.
The cloud, properly
If Emporia's cloud is the path the devices are already using, then that is where I started.
Emporia does not publish a public API, but naturally its own application talks to one, and the community pyemvue project has mapped a good deal of it.
Authentication goes through AWS Cognito using SRP (Secure Remote Password).
I reimplemented that flow in C# so the plugin can authenticate without sending the user's password as the authentication proof.
Credentials are stored locally using Windows DPAPI, encrypted to the account under which HomeSeer runs.
And a password never gets sent back to a browser page after it's entered.
That's a rule shared by the rest of my plugin framework, not something specific to Emporia.
Once authentication worked, the rest fell into place surprisingly quickly:
Sign in.
Enumerate the devices.
Read the monitor channels.
Turn a plug on.
Hear it click.
The first time a real Emporia plug changed state from a HomeSeer event, the thing I had wanted for more than a year just... worked.
Then the numbers looked wrong
This was the useful humbling part.
The wattage readings looked plausible.
But slightly wrong.
And one circuit, Rack 4, appeared twice.
Plausible-but-wrong is one of my least favorite classes of bug because nothing immediately screams that anything is broken.
The problem turned out to be in how I was interpreting the monitor's mains.
Vue reports its mains in a form I initially misunderstood, and I was summing values that shouldn't have been summed.
A whole-house total that double-counts part of its input can be spectacularly wrong while still looking perfectly believable.
The clue came from comparing the plugin directly with Emporia's own application.
That bug established one of the principles I kept coming back to while building the rest of the plugin:
Show only what is true.
If a circuit is off, cost is $0.00.
If a device is offline, say that it is offline.
If Emporia already knows the user's utility rate and provides its own calculated cost, use that rather than inventing another interpretation of the same data.
The cloud already knows the customer's rate schedule better than my plugin does.
From reading to managing
Once the readings were trustworthy, the plugin stopped being merely a monitor and started becoming a management interface.
Each circuit and device becomes a normal HomeSeer entity, which means its readings can participate in HomeSeer events, history, trending, and automation just like other device values.
The plugin's own pages add charts and sparklines for viewing usage across a day, week, or month.
But what I find most interesting is the two-way sync.
Rename a device or circuit in HomeSeer, and you can push that name back to Emporia.
Set the multiplier for a 240-volt circuit.
Identify a circuit as a water heater, EV charger, air conditioner, or another load type.
Edit the utility rate Emporia uses.
Those changes are written back to the Emporia account rather than existing only inside HomeSeer.
And I tested those writes by reading the live configuration back afterward and making sure the intended field changed while everything around it remained untouched.
The utility-rate update is a good example.
The rate lives inside a larger billing-configuration object.
So the plugin:
reads the entire object,
changes one field,
and writes the whole object back intact.
Careful beats clever.
Slow writes should not mean slow pages
Emporia's configuration endpoints can sometimes take a surprisingly long time to respond, occasionally approaching 45 seconds.
That creates another problem.
My plugins share common web infrastructure, and blocking a request for that long would do more than make one button feel sluggish. It could tie up page processing elsewhere too.
So configuration writes are performed asynchronously.
The page starts the operation and remains responsive.
The plugin does the work in the background.
When it finishes, the interface reports the result.
You never have to stare at a frozen HomeSeer page wondering whether clicking the button was a mistake.
The details, drawn by hand
A device list made entirely of identical gray gears is pretty depressing to look at.
So the plugin ships with 28 color-coded device icons.
An EV charger gets a car and lightning bolt.
Air conditioning gets a snowflake.
A water heater gets a tank.
A furnace gets a flame.
Circuits can infer an appropriate icon from their names.
That part was more entertaining than it probably should have been.
The air-conditioner icon went through several revisions because my first attempt looked suspiciously like a ceiling fan.
Which is technically related to cooling, but not quite the message I was going for.
The device-details page also tries to identify each Emporia device's local IP address.
The irony is that the plugin cannot currently control the device through that address.
But it knows the MAC address reported for the device, so it can correlate that against the local machine's neighbor/ARP table and tell you where the device currently lives on your network.
Sometimes information is useful even when it isn't yet a control path.
The provisioning rabbit hole
Naturally, I also tried to eliminate the phone app from initial device setup.
Emporia actually provides two onboarding paths.
The normal Quick Mode uses Bluetooth for the initial handshake and then hands the device the credentials for the 2.4 GHz Wi-Fi network.
If that fails, there is also a Hotspot Mode, where the plug creates its own temporary Wi-Fi network and the phone connects directly to it for configuration.
The second one especially interested me because it exposed something I could access directly.
I connected a machine to the plug's setup network and mapped what it exposes. There is a small custom V0.1 protocol running on an ESP32 provisioning service.
It looks reverse-engineerable.
But reverse-engineerable and finished are two very different things.
The bigger obstacle is that onboarding isn't just about supplying Wi-Fi credentials. The device also has to associate with the user's Emporia account, and that still involves Emporia's cloud workflow.
So, for now, new devices still need to be onboarded through Emporia's app.
I do not consider that investigation finished.
There are now at least two interesting paths to explore: the Bluetooth-based Quick Mode and the Wi-Fi Hotspot Mode I have already started mapping.
“Not solved yet” and “not possible” are two very different conclusions.
Sometimes the useful answer is “not us”
During one provisioning attempt, Emporia's app itself became unreliable.
Since I had just introduced another piece of software into the environment, the obvious suspicion was that my plugin or network configuration had somehow interfered with it.
So I checked.
DNS resolved to the legitimate Emporia infrastructure.
The device network could reach the cloud services it needed.
Existing plugs continued responding correctly through the plugin.
Nothing on our side was blocking the traffic.
The problem was elsewhere.
That may sound small, but it is one reason I like understanding integrations all the way down to the wire.
Sometimes the most useful conclusion a system can give you is:
The problem is somewhere else.
Where it landed
What began as a way to get a few smart plugs into HomeSeer became a fairly complete Emporia integration.
It now provides:
live power and cost data,
per-circuit monitoring,
smart-plug control,
historical charts,
device and circuit naming,
circuit configuration,
utility-rate management,
device discovery and network information,
offline-state reporting,
and live pages that update while someone is watching without hammering Emporia's API when nobody is.
The finished code also went through two independent audits.
One found a race condition that could create duplicate HomeSeer features.
Another exposed a page that didn't refresh as consistently as intended.
Both were fixed.
Both now have tests to make sure they stay fixed.
And the important limitation remains explicit:
Initial Emporia device onboarding still requires the Emporia app.
For now.
The current plugin uses Emporia's cloud because that is the reliable path I have actually demonstrated.
That does not mean I am finished looking for another one.
Not bad for a question that started with a box of plugs that lived in their own world.
They live in mine now.