Skip to main content

Command Palette

Search for a command to run...

Your Battery Has an API. The App Just Won't Tell You.

Updated
10 min read
Your Battery Has an API. The App Just Won't Tell You.

Your Battery Has an API. The App Just Won't Tell You.

I own two Mango Power Union battery units. One of them died in an overvoltage event. The app showed it as "offline" and that was it. No diagnostics. No historical data I could export. No way to investigate what happened.

So I did what any red-blooded American would do.

I decompiled the app.

What I found was more interesting than I expected. The Mango Power Union app doesn't talk to your battery. It talks to a cloud platform you've never heard of, run by a company you've never heard of, and once you know that, you don't need the app at all.


The Setup

The Mango Power Union is two stackable battery units. LFP home batteries, 6.9kWh combined, solar in, grid in, AC/DC out. Solid hardware. The software is a completely different story.

The official app is fine for checking your battery percentage and toggling outlets. But when things go wrong, when you need historical data, alarm logs, or any kind of automation, you hit a wall. There's no API documentation. No alerting. No developer access. No export. The app is the only interface, and it tells you exactly what it wants to.

I had a dead unit and a second one limping along with recurring BMS communication failures. The app showed "offline" for one and a battery percentage for the other. I had no idea what had actually happened. I tinkered, I troubleshot, I contacted support. Honestly, support was just as in the dark as I was. They concluded it was a hardware defect, sent me a replacement unit, and called it a day.

It wasn't until I decompiled the app and pulled two years of historical data from the backend that I found out what actually killed it. But I'm getting ahead of myself.


Decompiling the APK

The app is com.eybond.mangopower, version 1.7.1. I pulled the APK and ran it through jadx:

sudo pacman -S jadx
jadx -d ~/Downloads/mango_power_decompiled ~/Downloads/MP_Union_HK_V1.7.1.apk

18 decompilation errors, which didn't deter me. The Java sources decompiled cleanly, and then the first surprise hit: the Java layer is mostly scaffolding. The whole thing is built on DCloud's uni-app framework. It's a hybrid app, a native Java shell wrapping a bundled JavaScript web UI. I'd spent time poking around the Java code looking for device control logic and came up with almost nothing, because almost nothing was there. The real business logic lives in a single 400KB JavaScript file:

resources/assets/apps/__UNI__CDF6EAA/www/app-service.js

The Java code handles exactly one thing worth mentioning: Wi-Fi provisioning for the data collector module. It sends AT commands over a GATT characteristic to configure the collector's Wi-Fi credentials, like this:

AT+WFLKAP=<ssid>,AES,WPA2_PSK,<password>

That's it. No device control over BLE. Every button press in the app, every toggle, every setting change, goes through HTTP (super secure, I know) to a cloud server somewhere.


The Cloud Behind the Curtain

The Mango Power Union app is a white-label of Eybond's ShineMonitor platform, also known as DessMonitor and LampMonitor. They have a lot of names. Eybond is a Chinese IoT company that makes data collectors for solar equipment. They provide the cloud backend, the app framework, and a web portal.

The JS bundle had multiple API endpoints hardcoded: production, regional, and internal test servers. Most of them are plain HTTP. The API uses signed query strings instead of HTTPS for integrity, which is a choice.

The architecture looks like this:

[Mango Power Union]
        |
        | Wi-Fi
        ↓
[Eybond Data Collector]
        |
        | HTTP (plain, signed queries)
        ↓
[ShineMonitor Cloud] ←——— [Your phone / My CLI]

My battery talks to a small data collector module, which is the thing you pair over BLE during setup. The collector reports to Eybond's cloud over home Wi-Fi. The app reads from and writes to the cloud. The battery never sees your phone directly.

Which means: if you can talk to the cloud API, you can do everything the app does. And more.


Cracking the Auth

The signing scheme is SHA1-based with a shared secret model. I extracted it from the JS bundle.

The login flow hashes your password, combines it with a timestamp salt and an action string, signs the whole thing with SHA1, and sends it as a GET request. The response gives you a session token and secret. Every subsequent API call signs its parameters with the token and secret using the same scheme.

It's not OAuth. There are no API keys per se, just a shared platform key baked into every app install. There's an error code for rate limiting (525) but I've never hit it.

After all that — the APK pull, the decompile, the SHA1 reverse engineering, sifting through 400KB of minified JavaScript — I didn't crack anything. I didn't spoof anything. I just logged in. With my own credentials. The same ones I'd been using in the app for two years.


What the API Can Do

Pretty much everything I'd been trying to do for months. Way more than the app exposes.

Device Control

The API exposes named registers for every physical control on the unit: AC outlet, DC outlet, Smart Charge, M-Boost, charging current, SOC target, ECO charge rate. Each is a simple key-value pair you can read or write. The multi-step UI flows in the app to change a setting? One API call.

Queries the App Doesn't Surface Well

  • Historical chart data with configurable precision: hourly solar output, grid consumption, battery levels over any date range
  • Full alarm history, not just "you have an alarm" but the specific bit codes, timestamps, and counts
  • Energy flow breakdown: solar→battery, solar→load, grid→battery, grid→load, battery→load as separate streams
  • Device management: add and remove collectors, bind and unbind Move+Home units, rename devices

Three Operating Modes

The Union has three modes that control charging behavior:

  • BAC (Backup): Set charging current (10/15/20A) and SOC threshold (85/90/95%)
  • ECO (Economy): Set a charge rate slider (0-100%)
  • ADV (Advanced): Set a time schedule with start/end times and enable flag

All controllable through the API. The app only exposes these through a multi-step UI flow. The API does it in one call.


The CLI Client

I wrote a ~450-line Python client that implements the signing scheme and wraps every API action into CLI commands. Login, list devices, check energy flow, toggle outlets, pull historical charts, read alarms, continuous monitoring. One dependency (requests). Session tokens persist locally so you authenticate once and forget about it.

The point wasn't to build something polished. It was to have a tool that could answer the questions the app wouldn't: when exactly did this unit stop reporting? What was the power reading right before it died? How many BMS failures happened in the last three months?


Forensics: What Killed My Battery

This is why I started the project. With historical chart data access, I could finally investigate why this thing started acting screwy.

The timeline:

Both my Union units, Home and Move, had been running normally since at least December 2024. Consistent 55-65W peak solar output. 11-18 active hours per day. BMS communication failures had been popping up since October 2024, 57 occurrences on the Home unit alone, but the system kept running.

Then, January 10, 2025:

  • Home unit: 243W spike at 2:00 AM. Normal range was 55-65W. At 2AM, when panels shouldn't be producing anything. The collector reported data until 1PM, then went permanently dark.
  • Move unit: 246W spike the same day. 16 active hours instead of the normal 11.

Both units hit roughly the same anomalous power level at the same time. The Home unit died immediately. The Move unit survived and ran for almost another year before going dark in December 2025.

The 243-246W readings are consistent with solar panels wired in parallel pushing above the 150V MPPT ceiling, but that explains a chronic stress condition, not a 2AM spike. Panels don't produce power at 2AM. Whatever hit these units that night was an event. A lightning-induced transient on the solar lines, a grid switching surge, something. I don't know. What I do know is that the BMS communication failures had been accumulating since October 2024, and by the time of the January event the system was already struggling. I never got a single alert. According to the app, everything was grand.

The app said "offline." It didn't say any of that.


Automation

With API access, monitoring becomes trivial. I built an n8n workflow that:

  1. Authenticates to ShineMonitor every 6 hours
  2. Pulls energy flow and battery levels for all registered devices
  3. Posts a status summary to my Discord homelab channel
  4. Triggers a grid charge command if battery drops below 5%

The n8n Code node needed a pure JavaScript SHA1 implementation since n8n doesn't expose Node.js crypto in its sandbox. Same signing logic, just uglier without a standard library.


What I'd Tell Other Mango Power Owners

  1. Your app account works at shinemonitor.com. You already have a web portal with data export, better charts, and device management. Same email and password.

  2. The API is undocumented but stable. Eybond hasn't changed their signing scheme or endpoints. If you can decompile an APK, you can figure out the rest. Your device identifiers are visible in the app's device list or the web portal.

  3. BLE is a dead end for control. If you're trying to talk to your battery locally without cloud, you can't. The BLE connection only configures Wi-Fi. All control goes through Eybond's servers. If their cloud goes down, you lose remote control. The touchscreen still works locally.

  4. The alarm history is more useful than the app shows. The API returns specific fault codes with timestamps and counts. Cross-reference with the fault code tables in the user manual and you get real diagnostics, not just "there's a problem."


The Bigger Picture

This isn't really a Mango Power story. It's an IoT story. A $4,000 home battery that depends entirely on a cloud platform run by a company most owners have never heard of. No local API. No documentation. No fallback if Eybond decides to sunset ShineMonitor tomorrow or change their terms.

The hardware is good. The protocol choices are not. Every home battery should have a local API. Even a simple Modbus register map would do. The fact that I had to decompile an APK to get historical data from my own device is absurd.

But now I have it. And if you have a Mango Power unit, you can too.


I'm not publishing the client or API details. But if you own a Mango Power unit, look up ShineMonitor. You already have an account.