Client: eMotors Direct
Role: Intermediate Full-Stack Developer
Overview#
At eMotors Direct, I worked on the Motiometer, an IoT device designed to monitor motor performance using vibration data, and report that information back to a centralized platform. The premise was to collect enough data from enough motors to identify patterns in their behaviour, with the longer-term goal of using those patterns to predict failures before they occurred and enable pre-emptive maintenance.
Challenges and Objectives#
- Implement push notifications and the authentication flow they depend on.
- Refactor notification logic to make triggers testable and messages editable.
- Reverse-engineer device messages to model the underlying data.
- Document manufacturing and provisioning workflows across several applications.
- Restore OTA updates to a device that had stopped provisioning.
My Contributions#
1. Firmware and OTA#
- Investigated a device stuck with a blinking status LED after provisioning it through the mobile app; used netcat to trace its repeated requests to the OTA endpoint.
- Traced the failure to a breaking change in the back-end, introduced after refactoring supportive functionality into a microservice.
- Fixed the regression and restored the device’s ability to receive OTA updates.
2. Back-End#
- Built the device-registration flow and supporting API endpoints in PHP/Symfony.
- Used ApiPlatform Actions rather than Controllers, defining routes on the Entity so the endpoints remained part of the automatically generated OpenAPI documentation.
- Refactored the notification logic so it could be tested; until then there was no way to know whether it was working.
- Added a
Create Super Userconsole command to provision accounts requiring elevated access without exposing that capability through the normal registration flow.
3. Android Application#
- Re-architected the app to MVVM and single-activity, with auth in its own flow and a ViewModel holding state across screens rather than inside any one of them.
- Implemented push notifications, registering/unregistering the device on login/logout.
- Kept the client in Java, using RxJava for async work rather than Kotlin coroutines.
- Added a camera switcher to the React QR scan flow for devices with multiple cameras, shipping front/back switching where the API didn’t support it.
4. Device Data Pipeline#
- Reverse-engineered the device’s message format and modeled the underlying data so the application could detect a motor running from the stream.
- Built valid JSON for a machine that could either be running or idle, and created it en masse using ZenStruck Foundry to test the application.
- The harness surfaced failures in the trigger pipeline. Refactored the notification logic; the triggers then ran correctly.
5. Documentation#
- Reverse-engineered the full project lifecycle, from manufacturing to the field-device data pipeline, and documented every step, tool call, and gotcha.
- The back-end endpoints documented themselves via ApiPlatform Actions; a README was prepared concerning the Android architecture changes.
Outcomes and Results#
- Notifications Delivered: Motor temperature and low-battery alerts reached users.
- Notification Pipeline Repaired: Templates separated from trigger logic; testing surfaced a defect in the alarm triggers, which was fixed.
- Fleet-Wide OTA Bug Found: A back-end regression had broken OTA updates for every provisioned device; it was invisible until a bench unit was reset and caught in a retry loop.
- Self-Documenting Endpoints: Custom routes appear in the generated OpenAPI spec.
- Lifecycle Documented: Manufacturing, provisioning, and the data pipeline, mapped into a single reference.
Technical Summary#
- Languages: PHP (Symfony), Java (Android), JavaScript (React)
- Tools & Frameworks: ApiPlatform, RxJava, Android SDK, Firebase Cloud Messaging, ZenStruck Foundry
- Hardware: ESP32 WROOM
- Key Features: OTA firmware updates, self-documenting endpoints, session-aware push notifications, device-data pipeline harness
Gallery#

