This is the seventh post in the LocalPapa Notes dev-log series. Last time we built a phone sensor dashboard that shows the level, compass and G-force live on screen. But a next thought arrived quickly: if that data could be sent to a computer in real time, wouldn't the phone become a ready-made sensor data source?
So the tool grew a "streaming" ability.
From "viewing" to "sending"
The original dashboard was for humans to look at. The streaming feature is for machines to use: it packs the accelerometer, gyroscope, compass, gravity and G-force readings into JSON at a fixed rate and sends them live to an endpoint you specify.
You can send 10, 30 or 60 times per second (10/30/60Hz), emitted steadily via setInterval. A single phone instantly becomes a low-cost IMU (inertial measurement unit) data source — useful for machine-learning data collection, robotics telemetry, or interactive installations.
Three transports, for different scenarios
We offer three ways to ship the data out:
- WebSocket (
ws://): low-latency, bidirectional, for scenarios needing a continuous live stream.
- HTTP POST (
http://): simple, stateless, for tossing data at a REST endpoint.
- Web Serial (USB): via Chrome's native
navigator.serial, at baud rates like 9600/115200, straight over a wired USB serial port — no Wi-Fi dependency, the most stable latency.
Data alone isn't enough; the user needs to know "is it actually sending?" So the panel shows a live connection-status light, packets sent, upload bandwidth (KB/s) and a debug log — turning an invisible data flow into a visible gauge.
The most maddening obstacle: Mixed Content
The biggest technical hurdle here is a pit many have fallen into: Mixed Content.
LocalPapa loads over HTTPS. But when you want to send phone data to a computer on your LAN (say 192.168.42.x), that's usually an insecure http:// or ws:// address. The browser's security policy blocks outright an "insecure request made from an HTTPS page" — so the data simply never leaves.
This isn't a bug; it's deliberate browser security. Our fix is a pragmatic two-pronged one:
- Explain clearly in the UI how to lift the Mixed Content restriction for this page in browser settings.
- Provide an
http:// version of the tool's URL as an alternative — load the page over plain HTTP and the "HTTPS→HTTP" mixing problem disappears, lowering the testing barrier.
Rather than pretend the problem doesn't exist, lay the restriction bare and offer an actionable detour. Honestly facing the platform's security boundary is itself part of a tool's job.
Don't just hand over a spec for the receiver — hand over the code
Many "streaming tools" stop once they've sent the data, leaving "you figure out how to receive it" to the user. That dumps half the problem on them.
So we built in a one-click-copy Python receiving server script, supporting both WebSocket and HTTP POST. Copy, paste, run — and the computer immediately receives the phone's data stream, out of the box. Paving that "last mile" is what makes a tool actually usable.
Connect cleanly — and disconnect cleanly too
The thing streaming tools most often neglect is teardown. Web Serial especially:
- Before connecting, use
requestPort() to let the user pick a port (again, must be within a user gesture).
- When stopping, actually call
writer.releaseLock() to release the write lock, then port.close() to close the connection.
Skip that, and the port can stay locked and fail to connect next time. Opening cleanly is easy; closing cleanly is the key to stability.
We also use localStorage to remember the user's protocol, target URL and frequency, so they needn't re-enter them next visit.
GPS and a magnetometer came later
This line later gained GPS (navigator.geolocation.watchPosition) and a magnetometer (new Magnetometer()). The magnetometer isn't natively supported on iOS, so the panel shows a red fallback note and points users to the compass heading instead — another instance of "platform differences need proper aftercare." CSV export and the JSON stream gained these new fields too, with unit tests added to keep the serialization structure correct.
What we learned
- **Data has to be sendable and receivable.** Shipping a receiver script is what turns the tool from "half-built" into "usable."
- You can't brute-force platform security — you route around it elegantly. When Mixed Content blocks you, the right answer is explanation plus an alternative path, not telling users to disable all protection.
- Close your resources cleanly. Teardown like
releaseLock + close decides whether the tool still works smoothly the second and third time.
- Privacy still holds in a streaming scenario. The key: the endpoint is yours, the data flows to your own computer, and it never passes through our servers at any point.
The same question, one step further
From reading sensors to streaming them, this line advances the series' question again: a browser can not only read hardware, but turn it into a real-time, programmable data source — entirely under the user's control.
One phone plus one web page is a sensor. The answer, once again: yes.
In the next dev log, we move into fresh territory — turning LLM-generated Mermaid text into a diagram with one click. Want to follow the series? Bookmark LocalPapa Notes.