How the app works, from the first install to the report landing in Dropbox, and what keeps the code and the data safe.
A GUIDE FOR TECHNICIANS AND THE OFFICE · APP VERSION 87 · SEPTEMBER 2026
Nobody retypes anything. The numbers flow from the tester and the photos into the document.
Part 1
Install the app, connect it to the office, and do your first visit. About ten minutes the first time; a minute every time after.
Type it into any browser on the phone, or scan the code below. The page shows the current version and one Download button.
Android asks once whether this browser may install apps. Say yes; every Android app that does not come from the Play Store asks the same.
Whenever the app opens with signal it looks for a newer version, and the home screen shows a banner naming it. Tap the banner to download, open the file, allow the install: your visits stay where they are. Settings has Check for update too.
get.ohmee.app
Scan it with the phone's camera to open the download page. No store account today; a Google Play listing is on the roadmap.
A short code tied to your name, like Alex-8940. Type it once in Settings. That is all the access you need: no sign-up form, no login screen, no password.
The address is filled in already. On a visit started from a work order the office's engineer names come first, so check the Visit tab.
Tap the sync icon at the top, or pull the list down. Your work orders, plus every unit already on this phone, arrive in a few seconds. Nothing syncs by itself: you decide when.
Cloud accounts are the office's job, not yours. Dropbox is the only cloud link today, set up once on the server by the office. OneDrive and Google Drive are on the roadmap, not in the app yet.
Jobs the office has written up, one folder per job, named the way the office names them. Tap a folder to see its units.
Visits you have started and not finished. They stay here with or without signal.
Visits you marked finished. With signal, the report goes to the office in Dropbox, where it is checked and filed under the customer.
Earlier reports for the units on this phone, grouped by customer. The battery outlook is built from these.
Pull down or tap the sync icon to sync. The filter box matches customer, nickname, make, model, serial, job number or address within the tab you are on.
Units, history, work orders and your visits live on the phone after a sync. Readings, the tester, the checklist, notes and the Word report all work in a basement with no bars.
Photos to read and notes to draft are queued. The moment the phone is back online they run by themselves, and the suggestions appear on the visit.
Marking a visit finished uploads it and the photos, so do that with signal. If you marked it finished in a basement, it goes up at the next sync, or tap Send to the office now on the Report tab's With the office card once you are back online. Until then the office does not have it.
Sync is small and fast. The server sends only the units with current work orders plus the ones already on this phone, and only what changed since last time. A fresh sync is a few seconds, not minutes.
On site, the only thing that needs signal is the AI. Sync and sending to the office wait until you have it.
A new visit starts from the document the office wrote; the document itself is never changed. Customer, site, contact, job number and unit details are already there.
The label starts today's visit for that unit, pre-filled from its history, even with no signal. The phone's own camera app works too: the link opens Ohmee.
The QR code itself holds only a link with the unit's id, like upspm://unit/u-0a1b2c3d4e5f; anyone who scans it without the app sees an address and nothing else. The printed label adds the customer, the unit and the serial so a technician can find the right cabinet.
The office makes them with the laptop tool: pmtool qr-sheet writes one image with every unit at a customer, pmtool qr one label. Print, stick it on the UPS.
The QR button on the home screen scans with the camera, or reads a QR out of a picture already on the phone. If the unit is not on the phone yet, it is fetched from the server when you have signal.
Site, contact, unit and the job number. Mostly pre-filled.
Take photo, sorted by the AI: nameplates, displays, issues, infrared.
Three sub-tabs: battery testing, the outlook, and the strings.
Input, output, battery and load values. Typed, or read from a photo.
The inspection list with comments carried from last time.
Generate all drafts from the numbers, or dictate. You edit.
Pre-flight, hours, Generate Word report, Mark report finished.
Edits save about half a second after you stop typing. Leave with the arrow at the top left rather than the phone's Back gesture, which can drop the last edit.
Customer, site, contact, job and contract numbers, the engineers on site, the unit's make, model, serial and nickname. From the work order; correct anything that changed. The Previous visit card at the top names the last report on file and its View previous report button opens it, as the office wrote it. Everything below the header starts from that report, and the phone fetches it from the office first if it does not have it yet. A Next card names the first thing still missing; tap it and the right tab opens. Close the app mid-visit and it reopens on the same visit.
The unit's parameter table, laid out the way the office template prints it for that model. Last visit's values sit in the fields so you overwrite only what moved. A photo of the display can fill them for you. Under each value a line says where it came from: carried from last visit, typed today, or read from a photo (with the photo beside it), and a Confirm tap turns a carried value into today's. A reading the unit does not show is marked Not tested so the report says so instead of reprinting last year's.
Forty inspection items with their comment from the last report, word for word, because the office keeps those constant. Change a comment where something differs today; tap the flag on anything that needs attention, so it is listed in the report.
The USB cable that came with the tester. Open the Batteries tab on 01 Battery testing: it notices the cable and shows Read from tester. The first tap asks once for USB permission.
The tester pushes every jar it measured, 4,100 bytes in a couple of seconds however many jars there are. Nothing to type. A saved file from the tester's software imports the same way.
03 Strings grades every jar; 02 Battery outlook has the replacement date and a chart per string. Amber is at or above the warning line, one and a quarter times the reference. Red is at or above the replace line, one and a half times. A jar with a bad clip contact shows as open-probe: retest it before the report, because the app will not build around a bad reading. Chips over the grid filter it to Over a line, Re-test or New. Tap a jar to see that position's readings on every visit; This jar was replaced today records the swap, and the old readings stay with the old jar.
The reference impedance comes from the last real report for these batteries. You can change it on this tab. The warning and replace factors, the service life and the battery models come from one assessment profile the office keeps on the server; every report names the profile that judged it.
The install date on the report header starts the clock: tests before it belong to the old set and are set aside. With or without a date, the numbers mark a change too: a different number of jars, a reference more than 15% different (another battery model), or a string average falling by more than a fifth between two tests (fresh batteries read low; a worn set never recovers that much). The line starts again from there.
Every report on file for the unit since then, phone visits and the imported archive alike. A visit that only carries last time's numbers is not a test, and neither is an office document with a pasted chart. Tests of batteries that are gone never pull the line.
Inside a test, a jar with no voltage or an off-scale reading is a clip off the post: it is listed for a re-test and never judged. A jar reading several times the rest of its string is kept off the trend chart so the chart stays readable, but it still counts. One failed battery in a sound string (the rest near the reference) is its own action, replace that battery now, and the set is dated from the rest of the string; two or more over the line is a worn set. The outlook says how many jars stand over each line, and repeats any battery finding from the checklist as evidence in its own right.
The app prints the level of the highest jar, the office history behind the date and how many tests it used, and draws every test on the outlook curve, so the outlook can be checked rather than believed. Tests it set aside are counted too.
The highest jar in the string, divided by the reference R the office set for that model: level = z ÷ R. Warning at 1.25, replace at 1.5. This one number carries most of the forecast.
Every string the office ever tested was followed forward from each test: how many months until it was first seen over the warning line and the replace line. Grouped by level, that is the table on the right, here from one company's archive of 4,209 tests on 718 strings. The plan date is the first-quartile month among the strings that later crossed. Strings still under the line at their last test are left out, so counting every string far fewer than a quarter had crossed by then. A higher level never gets a later date: each level uses the shortest months of its own band and every band below it.
The app still works out a least-squares line through the earlier tests, but no chart draws it. Tested against the archive, the line called the crossing later than it came in 54% of real cases, by a median of three years: impedance creeps for years and then turns up. So the trend is the earliest of the line, a curve from the last reading and the last interval's slope, and it may pull the date earlier, never later.
Install date plus the service life in the office's profile, 5 years unless the office sets another. Counting sets still in service, a quarter were replaced by about 4 years. The plan date, Budget by, is the earliest of the three clocks: when the set is likely to reach the replace line or be replaced.
A highest jar under its reference gives no impedance date; age alone speaks. Fewer than two tests, or tests under six months apart, give no line; one test still gives a date from its level.
| level (× R) | tests | over the warning line: a quarter by / half by | over the replace line: a quarter by / half by |
|---|---|---|---|
| 1.0 to 1.1 | 631 | 12 mo / 19 mo | 18 mo / 28 mo |
| 1.1 to 1.2 | 371 | 6 mo / 9 mo | 9 mo / 17 mo |
| 1.2 to 1.3 | 169 | 6 mo / 7 mo | 9 mo / 13 mo |
| 1.3 to 1.4 | 72 | over it | 7 mo / 9 mo |
| 1.4 to 1.5 | 58 | over it | 5 mo / 6 mo |
The reading, the reference, this table and the rule that set the date are all printed, so the date can be checked by hand. The table is rebuilt from the archive as it grows.
Take photo on the Auto-sort card opens the camera and it stays open between shots, with a count and a torch. Tap the X when you are done. Shoot everything in one go: the AI works out which photos are screens and reads them; the rest go in the report as nameplate, cabinet, infrared, issue or other. Tap any photo to change what it is. Every photo is also copied to the phone's Gallery.
A photo of the UPS screen is read by an AI vision model. Its values arrive on the Readings tab as a card, Read from photo (6 values), with Accept all or Dismiss. Only fields that are blank or still last visit's are ever filled by themselves; a value you typed is never replaced.
A Sort by hand switch on the Auto-sort card brings back one tile per kind (display, nameplate, battery cabinet, issue, infrared, other), and the phone remembers the choice. Add photos from phone takes pictures from the Gallery, Files or an infrared camera; the AI sorts those too. Only display and unsorted photos go to the AI; nameplate, cabinet, issue and infrared photos never leave the phone until the report.
No signal? Photos wait in the queue and are read the moment the phone is back online, up to five tries each. You can keep working.
It may only use numbers that are in the visit. Every number in a draft is checked against the readings before you see it. A draft with an invented number is thrown away and the plain draft is used instead.
A plain draft is built from the numbers first: Inspection, Measurements and adjustments, Batteries, Checklist and Event log, plus Recommendations and Action required. The Battery outlook is arithmetic, not prose. The AI only rewords the draft in the office's tone, at most four sentences a section.
Generate Word report drafts the notes only while they are blank, still last visit's, or the app's own earlier draft; once you have typed in any note field it leaves all of them alone. Generate all, at the top of the Notes tab, starts every section over from the numbers, so use it before you type, not after.
Tap Add finding for anything worth a follow-up quote. Immediate goes into Action required, Next visit into Recommendations, and the office sees every finding on the web page. A finding carries over to the next visit until someone marks it Resolved, Quoted or Deferred, with a note; the report says which are still open and which were resolved this visit.
Each section has a No issues switch; off, a box takes what you found and the AI states it first. The Notes for the AI box takes tone and instructions, typed or spoken with Dictate notes; the field shows when it was last sent and the AI's one-line answer on what it did with it, or why it could not, such as a runtime that is not on the visit.
The question mark in the visit's top bar opens a panel that knows the open visit, the last report on file, the unit's history and outlook, the checklist and the photos read so far. Ask it anything about them, by button or in your own words.
Every number it states must be on the visit. A number that is not is listed in red under the answer, so nothing is taken on trust. Ask for a figure that is not on file and it says so, and where it would be entered.
It cannot change the visit. Wording it suggests is for you to copy. The conversation stays with the visit on the phone and can be cleared. About a cent a question, through the office server, logged under your name.
The button at the foot of the Report tab ("Build visit report"). Reads any waiting photos, drafts the notes, fills the runtime, then builds the Word document with the charts. It is the office's own template, so the customer sees no change. Tap Preview and the pages come back laid out by Word itself, through the office server, so what you see on the tablet is what the office prints.
Green ticks are done, amber is still missing (the report can be built anyway), red stops the build: no battery test, strings still last visit's, open-probe jars, unsorted photos. Each line names the reading or photo, and a tap opens its tab. Generate anyway overrides red.
Tap Mark report finished on the Mark visit finished card; it turns green and reads Finished, and a second tap reopens the visit. With signal, the visit and every photo go to the server, which builds the same report and sends it to the office in Dropbox. The With the office card, and the pill on the home row, say exactly where it stands: waiting for signal, uploading, received, or delivered to Dropbox. A change after delivery needs a one-line reason and goes out as a numbered revision; the office's own edits are never overwritten.
A copy of every report and the tester's raw data stays on the phone under Files › Documents › UPS PM (Android 10 and newer). Share works with email, Teams or anything else on the phone.
In Dropbox under Technicians › Work Orders › the job folder, like today.
Within two minutes it is a visit on the server. It reaches the phone's Work Orders tab at the next Sync.
Opens the folder, tests the batteries, takes photos, generates the report on the phone.
Marking it finished uploads the visit; the server builds the Word file and drops it into Technicians › App Temp under the job folder.
Moved on by hand to Service Reports, as before. Reports filed under Customers are what the server reads back as history.
The rule the server follows: it only reads Customers and Work Orders, and only ever writes inside App Temp. It never overwrites or deletes a file. The Dropbox history stays exactly as it is.
The office keeps working in Dropbox exactly as before. The server watches two folders and delivers into one.
The same workflow as the phone, on the office laptop, for bulk jobs. Unzip it, double-click UPS PM Tool.cmd, and a window opens with the menu. Nothing to install: Java is inside.
Reads old Word reports into visits: the header, the parameter table, the checklist, the battery readings. That is how years of reports become history.
The IBEX-Pro on a COM port, or its saved files.
QR sheets per customer, reports with trend charts in any style, and the Dropbox link the office does once.
Part 2
Where the app's code lives, how a change becomes a new version, and what a repository, a branch and a release actually are.
A repository is the one shared book that holds every recipe, every file, the app is made of.
Ours lives on GitHub, so it is not stuck on one laptop. Private: only people the company invites can open it.
Who changed what, when, and why. Nothing is ever erased, only added to. More than 130 pages so far.
Any earlier version can be opened again in seconds. A bad change is never the end.
New work goes on a branch, a copy of the book, so the real one keeps working.
Automatic tests and checks run before a page is allowed into the book. Part 3 shows them.
A copy of the book to write on. The real app is untouched while the change is being made.
The note that says: here is my change, please look. It shows exactly which lines changed and why.
The tests and Android Lint run on the change by themselves. A red tests check keeps the door shut; a red lint is a warning to fix.
Every photo goes through the in-app viewfinder
2026-09-11
The AI key comes from the server on every Sync
2026-09-11
The app ships with the office AI key built in
2026-09-11
Whatever is fixed next
soon
v31 marks the exact page in the book the phones are running.
The app file and pmtool are attached to the tag on GitHub, with checksums, forever.
Plain words: what a technician or the office would notice in this version.
From version 31 on, every publish does the three at once, so the version in Settings on the phone has a matching release page on GitHub.
All of it lives in Ohmee's private repository on GitHub.
One file, one section per version, one plain line per change. Newest at the top. It is written for the people who use the app, not for programmers.
Find the feature, read the version above it, check Settings on the phone.
The Unreleased section at the top lists what is coming in the next version before it is published.
Each release page shows its changelog section, next to the file that was published.
Part 3
Who can see what, where the secrets live, where AI is allowed to act, and the checks that run on every change before a person ever runs it.
If someone leaves, the office replaces one token in one file on the server and restarts the service. Nothing else changes.
Photo reading uses a Gemini vision model and note writing a Claude writing model by default (Settings can change either), both through one OpenRouter account the office holds. The key is handed to phones by the server on every sync and can be replaced in one place. A switch in Settings turns the AI off entirely.
The app is built from about sixty ready-made parts written by other people. Every Monday Dependabot checks whether any part has a security recall or a newer version, and writes up the swap as a pull request for us to approve.
A spell-checker for app code. It reads every screen and flags things that will break on some phones, waste battery, or are unsafe, before a person ever sees them. Its report is kept with every build.
Sixty-eight taste tests. Every time the code changes, they feed the tester decoder, the report builder, the importer and the battery maths known inputs and check the answers. Red means the change cannot go in.
A change only merges when the tests are green. History cannot be force-pushed and the main copy cannot be deleted, not even by accident. Only the repository owner can override, and it is logged.
If the app ever stops on a phone, it writes down what happened and sends it to the server on the next launch, with the version and the phone model. Nothing about the customer goes with it.
Much of this app was written with an AI assistant. Every one of those changes goes through the same door as a human one: the tests, the lint, the pull request and a person reading the diff. Nothing ships on trust.
Five of these run without anyone remembering to run them. The safety net does not depend on a person having a good day.
Settings shows the version. The job folder name is enough; no serial numbers or customer contacts in the report.
A screenshot is worth a paragraph. If the app stopped, the crash was already sent; just say roughly when.
Email hello@ohmee.app. We file it on GitHub with the Field bug report form, where it joins the same issue list as everything else and gets a number you can ask about.
hello@ohmee.app
The long version, how the system is built, is yours on request: write to hello@ohmee.app.