IoT · Bluetooth · Security

Two rules shaped the protocol between our technician app and a gateway on a battery management system — mutual authentication on every connection, and never reporting a write as "sent".

·4 min read·Appna Studio

Battery packs in electric vehicles are managed by a BMS — a battery management system that protects the cells, balances them and keeps count of the charge going in and out. Its settings decide when a pack cuts off, how hard it can be charged and when balancing starts. Change the wrong value and you can damage a pack worth more than the vehicle's motor.

For KnowyourEV, we put a small gateway of our own on each pack. It talks to the BMS over UART on one side and to a technician's phone over Bluetooth Low Energy on the other. The phone shows live telemetry and lets a technician change parameters on site; a cloud service keeps an audit ledger of every change.

Before writing any code, we wrote down two rules that the entire protocol exists to serve.

Rule one: nobody trusts anybody until they have proved it

Bluetooth makes it easy for any phone in range to connect to any device that is advertising. That is fine for headphones and dangerous for a battery.

So nothing leaves the gateway until the phone has proved two things: that it holds a ticket the server signed for this gateway, and that it holds the key that ticket was issued for. And the phone does not believe anything the gateway says until the gateway has proved it holds its own secret. It is mutual, it happens on every connection, and it happens before any telemetry or command.

The handshake is a short exchange of random nonces and HMAC-SHA-256 tags:

  1. The phone sends its server-signed ticket. The gateway checks the signature, the version, that the ticket names its own serial number and that it has not expired.
  2. The phone sends a random nonce; the gateway answers with its own nonce and a tag that only the real gateway could compute.
  3. The phone checks that tag. If it is wrong, the phone disconnects and reports the device as unverified — and reads nothing else from it.
  4. The phone sends its own tag; the gateway checks it and replies with a status.
  5. Both sides derive a session key from the two nonces. It lives only as long as the connection.

Neither side ever sends a secret over the air. A gateway that does not finish the handshake within a few seconds simply disconnects.

Permissions live on the gateway, not the phone. The ticket carries what the technician is allowed to do. If a ticket has no write permission, a write command is refused by the gateway and never reaches the BMS — no matter what the app's interface shows.

Rule two: "sent" is not an outcome

The second rule is about honesty. When a technician changes a setting, the only answer that matters is what the BMS holds afterwards. So every write is followed by a read-back, and the response carries the value the BMS actually has.

That gives us precise outcomes instead of a vague "done":

  • OK — the BMS holds exactly what was asked.
  • Adjusted — the BMS accepted the write but holds a slightly different value, and we show which.
  • Rejected — the value was out of range, read-only, unknown or not permitted.
  • Timeout — the BMS did not answer in time.
  • Indeterminate — the Bluetooth link dropped mid-write, so we genuinely do not know, and we say so.

Each of these lands in the audit ledger as-is. A fleet manager reading the history later sees what really happened to each pack, not what someone intended.

Every command is signed

After the handshake, every command carries a sequence number and a tag computed with the session key. The gateway verifies the tag before doing anything, and the response echoes the sequence number so an answer can never be matched to the wrong question. A command with a bad tag is refused and nothing is sent to the BMS.

One contract, tested from both sides

The firmware and the app share nothing except a written protocol document. The app's codec tests are written from that document, not from the firmware — so if the two ever disagree, a test fails on a developer's machine instead of in a technician's hands. Both sides are checked against the same byte vectors.

The document also keeps the phone away from vendor details: the app never sees a raw BMS packet. Supporting a different BMS is a new translation table in the firmware, not a change to the app.

What we took away

Hardware projects fail at the seams — between firmware and app, app and cloud, intention and outcome. Writing the contract first, enforcing security on the device and refusing to call anything "sent" closed most of those seams before they could open.

KnowyourEV is still in development. If you are building a connected product and want the firmware, app and cloud to behave like one system, have a look at our IoT and embedded software work — or get in touch.

Free · 30 seconds · No sign-up

How fast is your website on a phone?

Get your score, what Google can’t read, and the three fixes that matter, as a PDF in your inbox.

Check my website →
06Contact

Tell us what you’re building. Every enquiry gets a considered reply with honest thoughts on scope, approach and timeline.

Need an official quote? Attach your RFQ (request for quotation) or project brief to the form, and we’ll reply with a formal, itemised quote.

I’m interested in