Документация по новым модулям API v1.1 Battery Wizard Online

Данная документация описывает назначение и использование основных эндпоинтов API BatteryWizard, предназначенных для мобильных приложений Android/iOS: battery_photo.php, instrument_photo.php, start_work.php, end_work.php, measurements.php и defect.php. Для каждого модуля приведены подробные сведения: цель, метод и URL вызова, параметры запроса (с указанием типов и требований), примеры HTTP-запросов (как в формате multipart/form-data для загрузки файлов, так и в виде JSON), примеры успешных и ошибочных JSON-ответов, таблица возможных ошибок с пояснениями и рекомендациями, описание серверной логики обработки, а также особенности работы в офлайн/онлайн-режиме (например, передача данных задним числом и обработка сбоев сети).

battery_photo.php – Загрузка фото АКБ и распознавание

Назначение: Эндпоинт для загрузки фотографии аккумуляторной батареи (АКБ) и автоматического распознавания ее характеристик (например, наименование модели, тип, емкость) по изображению. Используется инженерами для ускорения ввода данных об АКБ: сервер сохраняет фотографию и извлекает данные с ее этикетки, возвращая параметры батареи, которые приложение может подставить в отчет.

URL и метод: POST /api/v1/battery_photo (HTTP POST запрос).

Параметры запроса:

ПараметрТипОбязательныйОписание и формат
tokenstringдаТокен аутентификации пользователя, выданный при входе. Используется для проверки прав доступа.
photofileда (при multipart)Файл фотографии АКБ в формате изображения (JPEG/PNG). Передается multipart-полем при загрузке файла.
filestringда (при JSON)Альтернатива photo для JSON-запроса: содержимое изображения, закодированное в Base64. Используется, если запрос отправляется с Content-Type: application/json.
timestampstringнетМетка времени съемки фотографии в ISO 8601 (UTC) или формате YYYY-MM-DD HH:MM:SS. Если указана, сервер сохранит указанное время как время фиксации фото; если не передавать, используется время получения запроса. (Не обязательна для онлайн-режима, может использоваться при загрузке фото задним числом.)

Пример HTTP-запроса (multipart/form-data): загрузка изображения файла с одновременной передачей токена. В примере используется curl с указанием файла battery.jpg:

curl -X POST «https://api.batterywizard.ru/v1/battery_photo» \
     -F «token=ABC123DEF456» \
     -F «photo=@/path/to/battery.jpg»

Пример HTTP-запроса (JSON): передача изображения в теле запроса в виде Base64 и токена авторизации:

curl -X POST «https://api.batterywizard.ru/v1/battery_photo» \
     -H «Content-Type: application/json» \
     -d ‘{
           «token»: «ABC123DEF456»,
           «file»: «/9j/4AAQSkZJRgABAQAAAQABAAD//…BASE64-ДАННЫЕ-ИЗОБРАЖЕНИЯ…//7A==»
         }’

Примечание: В JSON-примере поле file содержит укороченное представление данных изображения в Base64 для наглядности. В реальных запросах необходимо подставить полные данные.

Пример успешного ответа:

{
  «ok»: true,
  «code»: 200,
  «message»: «»,
  «batteryName»: «Enersys OPzV 100Ah»,
  «batteryType»: «OPzV»,
  «batteryCapacity»: 100
}

В случае успеха поле ok будет true, code = 200, а message пустое. Дополнительно возвращаются распознанные характеристики батареи, например: — batteryName – полное название/модель АКБ, извлеченное с этикетки. — batteryType – тип батареи (например, OPzV, AGM и т.д.). — batteryCapacity – емкость батареи (например, 100 Ах).

Пример ответа при ошибке:

{
  «ok»: false,
  «code»: 415,
  «message»: «Unsupported image format. Only JPEG or PNG allowed.»
}

Здесь ok = false, code указывает HTTP-код ошибки (например, 415 Unsupported Media Type), а message содержит описание проблемы – в данном случае, неподдерживаемый формат файла изображения.

Возможные ошибки:

Код ошибкиПричинаРекомендация для решения
400Отсутствует обязательный параметр (например, не передан файл).Проверьте корректность запроса: необходимо передать токен и файл фотографии.
401 или 403Неверный или отсутствующий токен аутентификации (доступ запрещен).Выполнить повторную авторизацию и получить актуальный токен перед вызовом.
415Файл имеет неподдерживаемый формат или MIME-тип.Убедитесь, что изображение в формате JPEG или PNG, и повторите попытку.
422Не удалось распознать данные с изображения (нечитаемая этикетка).Сделать более четкое фото этикетки и повторить вызов, либо ввести данные вручную.
500Внутренняя ошибка сервера при обработке изображения.Повторить запрос позже. Если ошибка сохраняется, связаться с поддержкой с предоставлением файла для диагностики.

Логика обработки на сервере: При получении запроса модуль battery_photo.php выполняет следующие шаги: 1. Аутентификация: Проверяет наличие и корректность токена в параметрах. Токен должен соответствовать активной сессии пользователя; если нет – возвращается ошибка 403 (доступ запрещен). 2. Проверка данных: Убеждается в наличии файла изображения. Если файл не прикреплен (или отсутствует Base64-данные при JSON-вызове), возвращается ошибка 400 (неверный запрос). 3. Сохранение файла: Загруженное изображение сохраняется на сервере (например, в файловой системе или базе данных). Файл может быть помещен в специальный каталог пользователя/проекта; имя или ID файла генерируется автоматически. При сохранении возможна проверка типа и размера файла. Неподходящие файлы (слишком большие, нулевого размера, неверного расширения) отклоняются с соответствующей ошибкой (например, 415 или 400). 4. Распознавание: Если файл успешно сохранен, сервер запускает процедуру OCR/распознавания. Специальный алгоритм анализирует изображение: ищет текст на этикетке батареи (название модели, емкость, тип и другие технические данные). Предполагается, что данные расположены в стандартизированной форме на наклейке АКБ. 5. Обработка результата: — Если распознавание прошло успешно, извлеченные поля (например, модель, тип, емкость) сохраняются и включаются в ответ. Возможна привязка к справочнику батарей: например, сервер может попытаться сопоставить распознанные данные с записью в базе (справочнике АКБ) для получения структурированной информации. — Если распознать текст не удалось или уверенность низкая (например, фото размыто или отсутствуют нужные надписи), сервер формирует ответ с ok:false и кодом ошибки (например, 422 Unprocessable Entity) и сообщением, предлагающим повторить фото или ввести данные вручную. 6. Формирование ответа: Сервер возвращает JSON с результатом. При успехе – подтверждение (ok:true) и поля с распознанными характеристиками батареи; при ошибке – соответствующие code и сообщение. Поле message при успехе обычно пустое, а при ошибке содержит описательную строку для отображения пользователю или логирования. 7. Логирование: В целях аудита сервер может вести лог (например, запись в файл или базу) с информацией о запросе: timestamp, пользователь (из токена), результат распознавания или причина отказа, имя сохраненного файла и пр.

Особенности offline/online режима: Модуль battery_photo требует сетевого соединения для отправки фото и выполнения распознавания на сервере. В офлайн-режиме мобильное приложение не сможет сразу получить результат: — Работа офлайн: Если сеть отсутствует, рекомендуется позволить инженеру вручную выбрать характеристики АКБ из локально сохраненного справочника (при подготовке к выезду приложение может загрузить справочные данные по типам батарей). Фотографию АКБ можно сохранить локально на устройстве. — Синхронизация: После восстановления соединения приложение может отправить сохраненную фотографию на этот эндпоинт. В запрос можно (опционально) включить timestamp с временем фактического снятия фото, однако для данного модуля это необязательно, так как основная цель – получить данные. Важнее синхронизировать распознанные характеристики: — Если к моменту онлайн-синхронизации пользователь уже ввел данные АКБ вручную, результат OCR можно использовать для проверки или можно пропустить вызов. — Если данные еще нужны, приложение отправляет фото и получает характеристики, затем обновляет локальную запись (или подтверждает корректность). — Обработка ошибок сети: При временных проблемах связи приложение должно повторять попытку отправки фото автоматически или по запросу пользователя. Если запрос несколько раз не удался (например, из-за плохого сигнала), рекомендуется сохранение задачи на передачу и фоновая отправка, когда связь улучшится. Дубликатов можно избежать, помечая фотографию как “отправлена” после успешного ответа. В случае получения ошибок распознавания (422) при поздней отправке – приложение может уведомить пользователя, но к этому моменту, вероятно, данные уже введены вручную, поэтому такую ошибку можно просто залогировать.

instrument_photo.php – Распознавание показаний прибора по фото

Назначение: Эндпоинт для загрузки фотографии измерительного прибора (например, мультиметра, термометра и др.) с отображаемыми значениями и автоматического считывания числовых показаний. Позволяет инженеру фиксировать результаты измерений (напряжение, температура, плотность электролита и т.п.) с помощью камеры — сервер распознает цифры на дисплее прибора и возвращает числовое значение, уменьшая ручной ввод и вероятность ошибки.

URL и метод: POST /api/v1/instrument_photo (HTTP POST запрос).

Параметры запроса:

ПараметрТипОбязательныйОписание и формат
tokenstringдаТокен аутентификации пользователя (должен быть действительным).
photofileда (при multipart)Фотография прибора с отображенными измерениями (файл изображения, JPEG/PNG).
filestringда (при JSON)Альтернатива при JSON: данные изображения в Base64 (строка).
measurementTypestringнетТип измерения для контекста (опция). Например: «voltage», «temperature», «density». Если передан, сервер может использовать эту информацию для уточнения распознавания или единиц измерения.
timestampstringнетВремя когда был произведен замер, в формате ISO 8601 или YYYY-MM-DD HH:MM:SS. Необязательный параметр: если не указан, по умолчанию фиксируется текущее серверное время. Используется, если фото сделано офлайн и отправлено позже.

Пример HTTP-запроса (multipart/form-data):

curl -X POST «https://api.batterywizard.ru/v1/instrument_photo» \
     -F «token=ABC123DEF456» \
     -F «measurementType=voltage» \
     -F «photo=@/path/to/multimeter.jpg»

Пример HTTP-запроса (JSON):

curl -X POST «https://api.batterywizard.ru/v1/instrument_photo» \
     -H «Content-Type: application/json» \
     -d ‘{
           «token»: «ABC123DEF456»,
           «measurementType»: «voltage»,
           «file»: «/9j/4AAQSkZJRgABAQAAAQABAAD//…BASE64-ДАННЫЕ…//7A==»,
           «timestamp»: «2025-08-22T14:30:00Z»
         }’

Пример успешного ответа:

{
  «ok»: true,
  «code»: 200,
  «message»: «»,
  «value»: 2.15,
  «unit»: «V»
}

Объяснение полей ответа при успехе: — value – распознанное числовое значение измерения (здесь 2.15, предположительно напряжение на элементе АКБ). — unit – единица измерения (здесь «V» – вольты; для температуры, например, будет «°C», для плотности – удельная плотность, может быть передано как относительная величина или особая строка). Поле unit может определяться на основе measurementType или контекста (например, если measurementType не указан, возможна попытка автоматического определения по величине и форматированию числа).

Пример ответа при ошибке (распознавание не удалось):

{
  «ok»: false,
  «code»: 422,
  «message»: «Reading not recognized. Please retake the photo or enter value manually.»
}

В данном случае сервер вернул код 422 (Unprocessable Entity), указывающий, что обработка изображения прошла, но извлечь числовое значение не удалось (например, дисплей неразборчив или данные отсутствуют). message содержит рекомендацию повторить попытку фотографии или ввести значение вручную.

Возможные ошибки:

Код ошибкиПричинаРекомендации
400Отсутствует обязательный параметр (например, файл с фотографией не передан).Проверьте тело запроса: должен быть прикреплен файл изображения прибора.
401/403Недействительный токен, пользователь не авторизован.Необходима авторизация. Получите новый токен и повторите запрос.
415Неподходящий формат файла.Убедитесь, что загружается изображение в поддерживаемом формате (JPEG/PNG).
422Не удалось распознать значение на фото прибора.Попробуйте сделать фото заново: убедитесь, что дисплей резкий, без бликов и отображает цифры четко. В качестве альтернативы, переходите к ручному вводу значения.
500Системная ошибка при обработке изображения (исключение OCR или др.).Повторите попытку позже. При постоянной ошибке обратитесь к разработчикам, приложив проблемное фото для анализа.

Логика обработки на сервере: Алгоритм работы instrument_photo.php на стороне сервера: 1. Проверка токена: Валидирует токен пользователя, аналогично другим защищенным эндпоинтам. Если токен отсутствует или невалиден – возвращается 401/403. 2. Прием файла: Проверяет наличие изображения в запросе (либо multipart-файл photo, либо JSON-поле file с Base64). Если файл не получен – ответ 400. 3. Сохранение и подготовка: Изображение сохраняется (временнó или постоянно) для последующей обработки. Может выполняться проверка размеров, типа файла (допустимы, например, JPEG/PNG). Если передан параметр measurementType, он фиксируется для использования в анализе. 4. Распознавание показаний: — Сервер вызывает модуль распознавания (OCR) специально настроенный для сегментации цифр на экране прибора. Если указано measurementType, алгоритм может быть настроен ожидать определенный формат (например, для напряжения – цифры с десятичной точкой и возможно две цифры после запятой, для температуры – может быть знак ° или определенный диапазон значений). — OCR возвращает распознанную строку/число или указывает, что чтение невозможно. 5. Постобработка результатов: Полученное значение конвертируется в числовой формат (float или int) при необходимости. Также определяется единица измерения: — Единица может задаваться явно на основе measurementType (например, если measurementType=»temperature», сервер знает, что значения в °C). — Если тип не указан, сервер может попытаться интерпретировать: например, числа в диапазоне ~1.20–1.30 могут быть плотностью электролита (без единиц), значения 2–15 вероятно напряжение элемента (В), 48–60 – напряжение группы (В), 20–30 – температура (°C), и т.д. Это эвристика, поэтому лучше передавать measurementType для однозначности. 6. Формирование ответа: — При успешном извлечении данных сервер отвечает ok:true, code:200, а в теле включает распознанное значение value и указатель единиц unit (если применимо). message при этом пуст. — Если OCR не смог уверенно выделить число, сервер возвращает ok:false с кодом 422 и сообщением об ошибке. В некоторых случаях, если фото совершенно пустое или не было даже попытки распознавания, может вернуться 400 (неверный запрос), но обычно различие между “файл не тот” (415) и “файл нормальный, но данных нет” (422) соблюдается. — Иные ошибки (например, сбой библиотеки OCR) приводят к code:500 с сообщением о внутренней ошибке. 7. Связывание с измерением: В зависимости от реализации, модуль может не только вернуть значение, но и сохранить его временно, например, в контексте текущей сессии или незавершенного отчета. Однако чаще ответственность за дальнейшее использование value лежит на клиенте: приложение получит число и подставит его в соответствующее поле измерения. Фото прибора также может сохраняться как доказательство в систему отчетности (например, в базу или файловое хранилище с привязкой к идентификатору измерения). 8. Логирование: Каждый запрос может логироваться (включая время, пользователя, тип измерения, результат или причину отказа). При распознавании можно сохранять полученный текст до обработки и финальное число.

Особенности offline/online режима: Использование instrument_photo тесно связано с доступностью сети, так как распознавание происходит на сервере: — Работа офлайн: При отсутствии подключения приложение не сможет отправить фото для распознавания. В таком случае инженеру следует вручную ввести показания прибора в приложение. Рекомендуется UI/UX: если сеть недоступна, сразу предоставить поле для ручного ввода, а функцию фото либо отключить, либо выполнять сохранение без отправки. — Сохранение фото: Если требуется сохранить фотографию показаний прибора (для отчетности или последующей верификации), приложение может позволить сделать фото офлайн и сохранить его локально. Однако смысл отправлять его позже на распознавание снижается, так как значение уже будет введено вручную. Тем не менее, синхронизация может включать загрузку этих фотографий позже для архива: — Приложение может при восстановлении сети отправить фото на instrument_photo только для сохранения, без необходимости получать значение (поскольку значение уже известно). В текущей версии API у instrument_photo нет режима «только сохранить», он всегда пытается распознать. Поэтому, если значение уже введено, повторная отправка фото необязательна. Альтернативно, может быть предусмотрен отдельный механизм загрузки фото без OCR. — Передача задним числом: Если все же решено отправить фото после восстановления связи (например, для подтверждения измерения), можно указать оригинальное время timestamp съемки, чтобы сервер сохранил правильное время измерения. Это обеспечит хронологическую целостность данных. — Обработка сбоев сети: Если при онлайн использовании отправка фото не удалась (сетевой сбой), приложение должно: — Сообщить пользователю, что автоматическое считывание невозможно, и предложить ввести данные вручную (чтобы не задерживать процесс измерений). — Сохранить фото в локальное хранилище (если требуется) и периодически пытаться отправить, либо дать возможность вручную попробовать снова позже. — При автоматической повторной отправке важно убедиться, что дубли не приводят к неконсистентности: например, если первый запрос все же дошел до сервера, а ответ не был получен клиентом. В текущей реализации сервер при каждом вызове instrument_photo будет заново пытаться распознать и вернет значение. Повторное распознавание той же фотографии не повредит данным, но может быть лишним. Поэтому, возможно, достаточно одного успешного распознавания; последующие отправки того же фото можно пропускать. — Рекомендация: В офлайн-режиме ориентироваться на ручной ввод. Функционал распознавания по фото использовать преимущественно в онлайн-режиме, когда скорость и удобство имеют значение.

start_work.php – Начало работ на объекте (регистрация прибытия)

Назначение: Эндпоинт для отметки начала работы инженера на конкретном объекте. При вызове фиксируется, что пользователь прибыл и начал техническое обслуживание/контроль на выбранной площадке (сайте). Сервер сохраняет метку времени начала работ, а также может регистрировать геопозицию пользователя и идентификатор объекта. Этот вызов обычно инициируется при нажатии в приложении кнопки «Начать работу» (после выбора объекта из списка заданий).

URL и метод: POST /api/v1/start_work (HTTP POST запрос).

Параметры запроса:

ПараметрТипОбязательныйОписание и формат
tokenstringдаТокен аутентификации пользователя (инженера).
siteIdintдаИдентификатор объекта (сайта), на котором начинаются работы. Задаётся числовым ID, соответствующим записи в системе (например, полученному из списка объектов).
latitudefloatнетШирота координат места начала работ. Если передано, должно быть числом с десятичной точкой (например, 55.751244).
longitudefloatнетДолгота координат места начала работ. Формат аналогичен latitude (например, 37.618423).
timestampstringнетВременная метка начала работ, если требуется указать задним числом. Формат ISO 8601 (например, «2025-08-22T14:00:00Z») либо YYYY-MM-DD HH:MM:SS. Если не указано, будет использовано текущее время сервера.

Пример HTTP-запроса:

curl -X POST «https://api.batterywizard.ru/v1/start_work» \
     -H «Content-Type: application/json» \
     -d ‘{
           «token»: «ABC123DEF456»,
           «siteId»: 42,
           «latitude»: 55.751244,
           «longitude»: 37.618423,
           «timestamp»: «2025-08-22T14:05:00Z»
         }’

В примере отправляется JSON с необходимыми данными: токен пользователя, ID объекта 42, координаты местоположения и явное время начала (22 августа 2025 г., 14:05 UTC).

Пример успешного ответа:

{
  «ok»: true,
  «code»: 200,
  «message»: «»,
  «workId»: 128,
  «startTime»: «2025-08-22T14:05:00Z»
}

Объяснение: ok:true и код 200 подтверждают успешную регистрацию начала работ. workId – уникальный идентификатор сессии/работы, присвоенный сервером (например, ID записи в БД, связанной с этой рабочей сессией). Его можно использовать для сопоставления с последующими вызовами (end_work, измерениями и пр.), если это предусмотрено. startTime – зафиксированное сервером время начала работы (в UTC ISO8601), может совпадать с переданным timestamp или быть текущим временем, если timestamp не задавался.

Пример ответа при ошибке (например, не передан siteId):

{
  «ok»: false,
  «code»: 400,
  «message»: «Missing parameter: siteId»
}

Такой ответ указывает, что запрос некорректен: отсутствует обязательный параметр siteId. code:400 (Bad Request) и пояснение в message помогают разработчику обнаружить ошибку в формировании запроса.

Возможные ошибки:

Код ошибкиПричинаРекомендация
400Неправильный запрос: отсутствуют обязательные данные (например, siteId), либо они имеют неверный формат (например, текст вместо числа).Исправить запрос: убедиться в наличии всех обязательных полей и корректности их типов.
401/403Токен не предоставлен или недействителен – пользователь не авторизован.Авторизоваться (вызвать логин) и использовать корректный token в запросе.
404Указанный siteId не найден (несуществующий объект).Проверить правильность ID объекта. Возможно, объект был удален или сменил идентификатор. Получить актуальный список объектов от сервера.
409Конфликт: уже существует незавершенная сессия работы (например, ранее вызванный start_work без соответствующего end_work).В таких случаях сначала завершите предыдущую сессию (end_work), либо сервер автоматически завершит её. Рекомендуется избегать двойного начала работ без окончания предыдущих.
500Внутренняя ошибка сервера при создании записи о начале работ.Повторить попытку позже. Если проблема сохраняется, сообщить в техподдержку.

Логика обработки на сервере: На сервере start_work.php выполняет следующие действия: 1. Аутентификация: Проверяется токен пользователя. Если токен отсутствует или истек, возвращается 403 Forbidden (доступ запрещен) без выполнения дальнейших шагов. 2. Валидация входных данных: Сервер проверяет, что получен корректный siteId (например, целое число > 0). При наличии географических координат (latitude/longitude) проверяется их формат (числа в ожидаемом диапазоне). Неверные или отсутствующие обязательные поля вызывают ответ с кодом 400. 3. Проверка актуальности объекта: Возможно, сервер удостоверяется, что объект с данным siteId существует и доступен данному пользователю (например, пользователь действительно имеет задание на этот объект). Если нет – может вернуться 404 или 403 (в зависимости от политики доступа). 4. Проверка активной сессии: Сервер может проверить, не числится ли за данным пользователем уже начатая и не завершенная работа. Если обнаружено, что предыдущий start_work не был закрыт (end_work не вызывался), возможны варианты: — Вернуть ошибку 409 Conflict, сигнализируя о попытке начать новую работу, не завершив предыдущую. — Либо автоматически завершить предыдущую сессию (например, с проставлением текущего времени как времени окончания) и начать новую. Это зависит от бизнес-правил; как правило, рекомендуется явно требовать завершения. 5. Сохранение начала работы: Если всё в порядке, сервер создает новую запись в системе (например, в таблице WorkSessions/Visits) с деталями: — ID пользователя (из токена) и ID объекта. — Время начала: либо текущее (NOW()), либо предоставленное timestamp (если передан, сервер использует его, что позволяет регистрировать событие задним числом – важно, чтобы это время не было в будущем). — Координаты (если переданы) сохраняются для отчета/контроля (возможно, в отдельные поля Latitude/Longitude или в журнал геолокации). — Статус сессии помечается как “активный/в процессе”. — Генерируется уникальный идентификатор сессии (например, автоинкремент или UUID). Этот workId возвращается клиенту. 6. Ответ: При успешной регистрации сервер возвращает JSON с ok:true, код 200, и подтверждает начало. Помимо стандартных полей, может быть возвращен workId (идентификатор работы) и нормализованное время начала startTime (что мы видим в примере). message при успешном ответе пуст. 7. Логирование: Сервер записывает событие начала работы – это может быть сохранено в лог-файл (IP, пользователь, объект, время) или в аудит-таблицу. Эта информация может использоваться для учета рабочего времени и контроля местонахождения.

Особенности offline/online режима: Функциональность начала работы должна быть доступна даже без сети, с последующей синхронизацией: — Оффлайн режим: Если инженер прибывает на объект без связи, приложение должно все равно зафиксировать начало работ локально. При нажатии «Начать работу» можно: — Сохранить в локальной БД или памяти запись, содержащую siteId, отметку времени начала (взятую с устройства), и координаты (если доступны через GPS). — Предоставить пользователю визуальное подтверждение, что работа начата (даже без серверного ответа). — Возможно, заблокировать повторное нажатие «Начать» до синхронизации или до завершения этой работы. — Синхронизация начала работ: Как только интернет соединение появится, приложение должно отправить на сервер накопленные события start_work: — Перед отправкой важно убедиться, что передаются в правильном порядке (например, если пользователь успел посетить несколько объектов офлайн, их надо по порядку зарегистрировать). — Использовать сохраненные timestamp и координаты. Сервер воспринимает эти данные так, будто они поступили в реальном времени: благодаря timestamp начало сессии будет проставлено задним числом. — Обрабатывать ответы: при успехе можно пометить локальную запись как синхронизированную, сохранить workId если он возвращается. Если сервер вернул ошибку (например, 409 или 404), приложение может уведомить пользователя или попытаться исправить (в случае 409, возможно, сначала отправить end_work для незавершенного, если уместно). — Если к моменту синхронизации сессия уже фактически завершена: может возникнуть ситуация, когда офлайн период покрывает и начало, и окончание работ. В этом случае можно сразу после успешного start_work вызывать end_work с соответствующим timestamp окончания. — Дублирование и идемпотентность: Приложение должно избегать двойной отправки одного и того же события начала работы. Можно проставлять флаг «отправлено» локально. Если из-за сбоя сети неясно, зарегистрировалось ли событие на сервере, то при повторной попытке сервер, обнаружив дубликат (например, второй start_work с тем же временем на тот же объект), может вернуть ошибку или создать новую сессию. Чтобы не было дублей, можно: — Проверять на клиенте: если есть неподтвержденный ответом start_work, дождаться таймаута и только затем решать, отправлять повторно или нет. — В качестве альтернативы, (если предусмотрено) использовать workId или какой-то client-side unique ID в запросе, но в данном API такого поля нет. — Обработка ошибок сети: Если запрос start_work в онлайне не получает ответа (разрыв соединения), приложение должно решить: считать ли работу начатой? Рекомендуется, чтобы приложение всегда фиксировало начало локально сразу по действию пользователя, а серверная синхронизация шла независимо. Таким образом, даже если сеть пропала в момент нажатия, для пользователя работа началась (во избежание дублей, в случае восстановления связи приложение увидит, что локально «старт» уже зарегистрирован и попробует синхронизировать, а не выполнит повторный старт). — Геолокация: В офлайн-режиме координаты можно получить от GPS, поэтому их сохранение не требует интернета. При синхронизации они будут отправлены. Если координаты недоступны (например, GPS выключен), сервер просто не получит их – это не критично, start_work отработает и без них.

end_work.php – Завершение работ на объекте (регистрация ухода)

Назначение: Эндпоинт для фиксации окончания работ инженера на объекте. Вызывается при нажатии «Завершить работу» в приложении, когда инженер выполнил все необходимые замеры и действия на объекте. Сервер регистрирует время окончания, вычисляет длительность пребывания (при необходимости) и отмечает сессию как закрытую. Эта информация может использоваться для отчетов о затраченном времени и контроля посещения объектов.

URL и метод: POST /api/v1/end_work (HTTP POST запрос).

Параметры запроса:

ПараметрТипОбязательныйОписание и формат
tokenstringдаТокен аутентификации пользователя.
siteIdintдаИдентификатор объекта, на котором завершаются работы (должен совпадать с тем, что был передан в start_work).
workIdintнетИдентификатор сессии/работы, возвращенный ранее при start_work. Если система предусматривает явное использование workId, его лучше указать для однозначного сопоставления. В противном случае сервер определит завершаемую сессию по токену и siteId.
latitudefloatнетШирота координат на момент окончания работ. (Формат как в start_work.)
longitudefloatнетДолгота координат окончания работ.
timestampstringнетВременная метка окончания работ (если передается задним числом). Формат ISO 8601 или YYYY-MM-DD HH:MM:SS. Если не указано – берется текущее время сервера как фактическое время окончания.

Пример HTTP-запроса:

curl -X POST «https://api.batterywizard.ru/v1/end_work» \
     -H «Content-Type: application/json» \
     -d ‘{
           «token»: «ABC123DEF456»,
           «siteId»: 42,
           «workId»: 128,
           «latitude»: 55.751200,
           «longitude»: 37.618400,
           «timestamp»: «2025-08-22T15:20:00Z»
         }’

В примере завершается работа на объекте ID 42, сессия ID 128, координаты и время окончания указываются явно (15:20 UTC того же дня).

Пример успешного ответа:

{
  «ok»: true,
  «code»: 200,
  «message»: «»,
  «workId»: 128,
  «endTime»: «2025-08-22T15:20:00Z»,
  «duration»: 4500
}

Расшифровка: workId возвращается для ясности (какая сессия закрыта), endTime – зафиксированное время окончания. duration – общая продолжительность работы в секундах (например, 4500 секунд ~ 1 час 15 минут). Сервер мог вычислить эту длительность как разницу между endTime и соответствующим startTime. Это поле может отсутствовать или быть в другом формате (например, миллисекунды, или человекочитаемая строка), но в данном примере предполагается seconds.

Пример ответа при ошибке (например, нет активной сессии):

{
  «ok»: false,
  «code»: 409,
  «message»: «No active work session to end for siteId 42»
}

Такой ответ (код 409 Conflict) возможен, если сервер не нашел открытой сессии для указанного объекта или пользователя – например, start_work не был вызван либо уже вызывался end_work. Сообщение указывает, что нет активной работы для siteId 42, что подсказывает о некорректной последовательности вызовов на стороне клиента.

Возможные ошибки:

Код ошибкиПричинаРекомендация
400Некорректный запрос: отсутствует обязательный siteId (или workId, если в данной реализации он требуется), либо параметры имеют неправильный формат.Исправить формирование запроса, убедиться, что переданы нужные идентификаторы.
401/403Токен недействителен или отсутствует, пользователь не авторизован для совершения операции.Повторить авторизацию и отправить запрос с валидным токеном.
404Указанный объект (siteId) не найден или не соответствует начатой сессии пользователя.Убедиться, что правильный объект указан. Обычно siteId должен совпасть с тем, что использовался при start_work.
409Нет активной сессии работы, которую можно завершить, либо она уже была завершена. Также может возникнуть, если время окончания раньше времени начала (некорректный timestamp).Проверить логику приложения: вызывать end_work только после успешного start_work. Если сессия уже закрыта, не посылать повторный end_work. Убедиться, что timestamp окончания позже timestamp начала.
500Внутренняя ошибка сервера при закрытии сессии (например, проблема при записи длительности в базу).Повторить позже. Если ошибка сохраняется, сообщить разработчикам.

Логика обработки на сервере: При вызове end_work.php сервер выполняет следующие шаги: 1. Аутентификация: Проверяется валидность token. Без корректного токена операция не разрешена (403 Forbidden). 2. Проверка параметров: Убеждается, что передан обязательный идентификатор объекта siteId (и/или workId, если требуется). Если чего-то не хватает – 400 Bad Request. 3. Идентификация сессии: — Если workId предоставлен, сервер пытается найти активную сессию по этому идентификатору. Должны совпадать: пользователь (из токена) и объект (siteId) с указанной сессией. — Если workId не предоставлен, сервер ищет незавершенную (активную) сессию данного пользователя на указанном объекте. В системе обычно может быть только одна активная сессия на пользователя, но если пользователь мог параллельно работать на разных объектах, уточнение по siteId важно. — Если активная сессия не найдена – возвращается ошибка (например, 409 или 404). Это означает, что либо работа еще не была начата (нет start_work), либо уже была ранее завершена. 4. Регистрация окончания: — Сервер сохраняет время окончания. Если прислан timestamp, используется он (при условии, что он не противоречит логике – например, не раньше времени начала, не в будущем). Если timestamp нет, берется текущее время сервера. — Вычисляется продолжительность: обычно разница между временем начала (сохраненным в сессии) и временем окончания. Это значение может сохраняться в базе (для отчетов) и/или возвращаться клиенту. — Статус сессии обновляется на “завершена”. В БД это может быть флаг или факт наличия времени окончания. — При необходимости сохраняются координаты завершения (могут быть записаны в ту же запись сессии или в отдельный журнал). — Если в рамках сессии собирались какие-либо данные (например, измерения), они остаются привязанными и доступны для формирования отчетов. 5. Ответ клиенту: После успешного обновления сервер возвращает ok:true, код 200. В ответе подтверждается workId и может возвращаться зафиксированное endTime и рассчитанная duration. Поле message пустое. Если workId не был в запросе, но хранится на сервере, его могут включить, чтобы явно указать какую сессию закрыли (особенно полезно, если на будущее планируется поддержка нескольких параллельных сессий – тогда лучше указывать workId всегда). 6. Логирование: В журнале фиксируется, что пользователь завершил работу на объекте, с указанием времени. Это может использоваться для контроля трудозатрат и посещений.

Особенности offline/online режима: Завершение работы, как и начало, должно корректно отрабатываться при отсутствии сети: — Оффлайн окончание: Если инженер закончил работу, но все еще нет подключения, приложение должно позволить ему отметить завершение офлайн. Действия аналогичны start_work: — Сохранить локально событие end_work с указанием siteId (и workId при наличии), временем окончания (с устройства) и, при возможности, координатами. — Убедиться, что у соответствующей локальной сессии есть время начала (должно быть, если start_work также был офлайн). — Приложение может показать пользователю, что работа завершена (например, вывести длительность на экране отчета, если рассчитывает локально, или просто отметить объект как выполненный). — Синхронизация: Когда связь появится, приложение отправляет на сервер сохраненное завершение: — Порядок важен: если start_work для этой сессии еще не был синхронизирован, сначала нужно отправить его, затем end_work. В идеале, start_work и end_work отправляются парой, один за другим. Если start_work не удалось (например, объект не найден), возможно end_work тоже не имеет смысла отправлять. — В запросе timestamp указывается точно тот, который был сохранен при офлайн-завершении (чтобы длительность на сервере совпала с реальностью). — Обработка ответа: при успехе локальная запись помечается как синхронизированная. Если сервер вернул ошибку (например, 409 – нет сессии), нужно анализировать: это может значить, что start_work не был синхронно отправлен или произошел другой сбой. Приложение может попытаться отправить start_work заново (если упущено) или уведомить диспетчера о несоответствии. — Длительность и проверка последовательности: Сервер будет доверять присланным меткам времени, но возможно заложены проверки: — Если end_work.timestamp < связанного start_work.timestamp, сервер может либо исправить (обнаружив негативную длительность, поставить равным start), либо вернуть ошибку 409/400 о несогласованном времени. Поэтому приложение должно гарантировать целостность: не позволять пользователю выставить вручную время окончания раньше начала, и при редактировании офлайн данных сохранять корректную хронологию. — Повторная отправка и идемпотентность: Чтобы избежать дублей при нестабильной сети, стоит локально связывать start_work/end_work события. Например, хранить уникальный ключ сессии на стороне клиента. Если end_work отправлен и получил успех, второй раз его не отправлять. Если ответа нет, можно попробовать снова, но есть риск что сервер уже закрыл сессию на первый запрос. В текущем API явного поля для идемпотентного ключа нет, так что дубликат может привести к ошибке 409 (что лучше, чем создать дубль, но все равно требует обработки). — Например, если первый end_work дошел, второй вернет «No active session», что приложение может расценить как успешное (хотя пришло с кодом ошибки). Лучше в таком случае при получении 409 проверить: возможно, сессия уже закрыта. Можно попытаться выполнить запрос status или другой (если существует) для проверки состояния. — Отправка координат: Если в офлайн режиме координаты сохранялись, при синхронизации их можно передать. Если координат нет (GPS был выключен), не страшно – сессия все равно будет завершена, просто без данных о точке выхода. — Интеграция с отчетностью: Завершение работ офлайн означает, что итоговые данные (все замеры, фото дефектов и т.д.) тоже пока локально. Приложение может формировать предварительный отчет, но финальную передачу на сервер (чтобы сформировать официальный протокол) сделает только после синхронизации всех частичных данных. Поэтому end_work офлайн – это маркер, что работа завершена, но нужно убедиться, что все данные (начало, измерения, дефекты) также потом отправлены на сервер. Это повлияет на логику sync: возможно, имеет смысл отправлять данные в следующем порядке – start_work -> данные (measurement, photos, defects) -> end_work – чтобы к моменту закрытия на сервере уже все измерения были сохранены.

measurements.php – Передача результатов измерений АКБ

Назначение: Эндпоинт для отправки на сервер результатов измерений, полученных инженером при обслуживании батарей на объекте. Эти данные включают электрические параметры каждой группы аккумуляторов: например, общее напряжение группы, напряжения по каждому элементу (ячейке) в группе, температуры отдельных элементов, плотности электролита (для обслуживаемых батарей типа OPzS) и пр. Обычно приложение вызывает этот метод после того, как инженер завершил измерения на одной группе батарей и готов сохранить результаты (например, кнопка «Сохранить замеры» или «Сформировать отчет группы»).

URL и метод: POST /api/v1/measurements (HTTP POST запрос).

Параметры запроса:

Поскольку данных измерений много и они структурированы, рекомендуется передавать их в формате JSON. Ниже перечислены основные поля JSON-запроса:

ПараметрТипОбязательныйОписание и формат
tokenstringдаТокен пользователя.
siteIdintдаID объекта (сайта), на котором произведены измерения.
equipmentIdintдаID оборудования/установки (ЭПУ – электроустановки), к которой относится группа АКБ. Каждый объект может иметь несколько систем/установок; данный ID однозначно определяет, для какой системы передаются данные.
batteryGroupintдаНомер группы батарей внутри указанной установки, для которой приведены измерения (например, 1, 2 и т.д., если в ЭПУ несколько параллельных групп аккумуляторов).
totalVoltagefloatдаОбщее измеренное напряжение группы, В. Например, суммарное напряжение всей батарейной группы.
cellVoltagesarray<float>да (если есть замер напряжений по ячейкам)Массив значений напряжений по каждой ячейке (элементу) группы, В. Порядок в массиве соответствует нумерации ячеек в группе (1-й элемент массива – напряжение первой ячейки и т.д.). Количество значений должно равняться числу элементов в группе для полноты данных.
temperaturesarray<float>да (если выполнялся замер температуры)Массив замеренных температур, °C, на отдельных ячейках группы. Обычно это 3 значения (температура трёх произвольных элементов группы). Если замеры температуры не проводились, можно передать пустой массив или опустить поле.
densitiesarray<float>да (для батарей типа OPzS, иначе не требуется)Массив замеренных плотностей электролита, ед. плотности (обычно около 1.20–1.30). Обычно измеряется на 3 выбранных элементах группы. Для герметичных батарей (OPzV и др.) плотность не измеряется – поле можно опустить или оставить пустым.
timestampstringнетВремя проведения измерений (например, время начала замера группы) в ISO 8601 или YYYY-MM-DD HH:MM:SS. Если не указано, сервер проставит время получения запроса. Можно использовать для более точной хронологии, особенно при офлайн-отправке.
notesstringнетПримечания/комментарии к замерам этой группы (например, особые наблюдения инженера, которые не покрыты числовыми параметрами). Максимальная длина может быть ограничена (например, 255 символов).

Пример HTTP-запроса (JSON):

curl -X POST «https://api.batterywizard.ru/v1/measurements» \
     -H «Content-Type: application/json» \
     -d ‘{
           «token»: «ABC123DEF456»,
           «siteId»: 42,
           «equipmentId»: 7,
           «batteryGroup»: 1,
           «totalVoltage»: 53.5,
           «cellVoltages»: [2.12, 2.11, 2.10, 2.13, 2.14, 2.12, 2.11, 2.15, 2.14, 2.13, 2.12, 2.10, 2.13, 2.12, 2.11, 2.12, 2.13, 2.14, 2.12, 2.11, 2.10, 2.09, 2.10, 2.08],
           «temperatures»: [25.4, 25.0, 24.8],
           «densities»: [],
           «timestamp»: «2025-08-22T14:50:00Z»,
           «notes»: «Визуально все элементы в норме, подтёков нет.»
         }’

В данном примере: — equipmentId: 7 указывает конкретную электроустановку на объекте 42. — batteryGroup: 1 означает, что это первая группа АКБ в этой установке. — cellVoltages: приведен массив из 24 значений – предположительно, в группе 24 последовательно соединенных элементов (например, 48-вольтовая система с 2В элементами). — temperatures: три значения температуры. — densities: пустой массив, т.к. допустим, батареи герметичные (OPzV) и плотность не измерялась. — timestamp: показывает, что измерения были произведены в 14:50 UTC. — notes: содержит текстовое примечание.

Пример успешного ответа:

{
  «ok»: true,
  «code»: 200,
  «message»: «»,
  «recordId»: 501,
  «savedAt»: «2025-08-22T15:00:10Z»
}

Объяснение: recordId – идентификатор сохраненной записи измерений на сервере (например, ID отчета или внутренняя ссылка). savedAt – время, когда сервер сохранил данные (может чуть отличаться от timestamp, если отправлено позже). Клиент может использовать recordId для дальнейших операций (например, для обновления/повторной отправки, если такое предусматривается, или для получения отчета).

Пример ответа при ошибке (например, несовпадение числа ячеек):

{
  «ok»: false,
  «code»: 400,
  «message»: «cellVoltages count (20) does not match expected number of cells (24) for group 1»
}

Подобное сообщение указывает, что присланный массив напряжений ячеек имеет неправильную длину (20 вместо ожидаемых 24). Код 400 сигнализирует об ошибке в данных запроса. В ответе поясняется причина, чтобы разработчик мог исправить формирование данных.

Возможные ошибки:

Код ошибкиПричинаРекомендации
400Неверный формат или состав данных измерений. Примеры: отсутствует обязательное поле (equipmentId, batteryGroup, etc.), некорректные типы данных (например, строка вместо числа), несоответствие размеров массивов (неправильное число значений), или логическая ошибка (например, отрицательное напряжение).Проверить формирование JSON на стороне клиента. Убедиться, что все обязательные поля присутствуют, типы верны, и данные соответствуют реальности (количество ячеек, диапазоны значений).
401/403Проблемы с аутентификацией (неверный токен или истекшая сессия).Получить новый токен (повторно войти) и повторить запрос. Убедиться, что используемый токен соответствует авторизованному пользователю.
404Указанный объект (siteId) или установка (equipmentId) не найдены, либо не привязаны к пользователю/заявке. Также может возникнуть, если batteryGroup некорректен (например, группы с таким номером нет в данной установке).Уточнить справочные данные: возможно, siteId или equipmentId устарели или неверны. Получить актуальный список доступных объектов и их систем. Проверить правильность номера группы (сравнить с информацией, загруженной в справочник объекта).
409Конфликт состояния: например, попытка отправить повторно те же измерения, которые уже сохранены; либо измерения отправляются вне контекста начатой работы (start_work не был вызван).Убедиться, что для объекта открыта сессия работы (выполнен start_work), и что повторная отправка не дублирует уже существующие данные. При дублировании можно либо обновлять существующую запись через другой метод (если поддерживается), либо игнорировать повторное сохранение.
500Общая внутренняя ошибка при сохранении данных (например, сбой при записи в базу данных).Повторить запрос спустя некоторое время. Если ошибка связана с конкретными данными (в сообщении может быть указание), проверить их корректность. При частых сбоях обратиться к разработчикам сервера.

Логика обработки на сервере: При получении данных measurements.php сервер совершает ряд шагов: 1. Аутентификация: Проверяется токен пользователя. Без валидного токена – отказ (403). 2. Валидация структуры запроса: JSON-разбор входных данных: — Убедиться, что siteId, equipmentId и batteryGroup присутствуют и являются целыми. — Проверить присутствие основных измерений. Минимально ожидается хотя бы totalVoltage и список cellVoltages (для каждой группы должны быть замеры напряжений по ячейкам, иначе ТО неполное). В некоторых сценариях допускается передавать частично (например, только общее напряжение), но тогда сервер может либо сохранить как частичные данные, либо вернуть 400, требуя полного набора – зависит от настроек. Предположим, требуется полный набор. — Проверить типы: числовые поля должны быть числами, массивы – массивами чисел. notes если есть – строка не длиннее допустимого. — Проверить логические взаимосвязи: например, длина cellVoltages должна соответствовать известному числу элементов в группе. Информация о количестве элементов может быть получена сервером из справочника по equipmentId и типу батарей. Если несоответствие – это ошибка (см. пример). — Если densities передаются для батарей типа, где их быть не должно, сервер может просто игнорировать или выдать предупреждение, но скорее просто сохранит или проигнорирует. Если наоборот, батареи обслуживаемые (OPzS) а плотность не передана, возможно, это ок (могли не мерить), либо логика требует хотя бы какие-то значения. Обычно плотность не строго обязательна каждый раз. — Проверить timestamp (если есть) – правильность формата и разумность (не будущая дата). 3. Проверка контекста: — Сервер может проверить, что на данном siteId/equipmentId сейчас открыта сессия работы (т.е. ранее вызывался start_work и не вызывался end_work для этого объекта). Если система строго связана с сессиями, отсутствие активной работы может быть поводом отклонить данные (код 409). Если же разрешено присылать данные вне явной сессии, этот шаг могут опустить. — Также может проверяться, не были ли уже получены измерения для этой группы ранее (например, если приложение повторно отправило, или инженер пытается дважды сохранить). Если обнаружится дубликат, возможны варианты: либо создавать новую запись (если логично, например, повторные замеры), либо возвращать 409/другой код, сигнализируя о существовании данных. Вероятно, проще принять все данные и сохранять версии, но документация должна предупреждать о потенциальном конфликте. 4. Сохранение данных: При успешной проверке сервер заносит измерения в базу: — Возможно, создается основная запись протокола для данной группы (recordId в примере), содержащая привязку к объекту, установке, группе, времени замера, автора (пользователя). — Детализированные данные могут сохраняться в связанных таблицах: напряжения по ячейкам, температуры, плотности. Например, может быть таблица CellMeasurements со столбцами (RecordID, CellNumber, Voltage, Temperature, Density, …), или же отдельные таблицы для разных типов показателей. В предоставленной структуре БД можно предположить таблицы CellVoltageData, StringData и др. (они могли быть частью системы). Вероятно, measurements.php перекладывает полученные JSON-поля в соответствующие таблицы: — Общее напряжение группы (totalVoltage) может пойти в поле String Voltage в таблице StringData. — Каждое напряжение ячейки – в CellVoltageData с указанием номера ячейки. — Температуры — либо тоже сохраняются с указанием номера элемента или отдельного поля (возможно, в примечания или в специальной колонке String Temperature – если средняя или отдельной таблице). — Плотности — аналогично, могут сохраняться либо в отдельной таблице, либо в виде записей как доп. параметр. — Все эти низкоуровневые детали могут быть скрыты от клиента: клиент получает только подтверждение, а на сервере данные распределены по таблицам, чтобы потом можно было формировать отчеты и анализ. 5. Формирование ответа: — Если запись успешно создана, возвращается ok:true, code 200. Сервер может выдать recordId – идентификатор созданного набора данных (если планируется, что клиент может запросить отчет или редактировать запись, знание ID полезно). Также можно вернуть savedAt – время записи на сервере (может отличаться от timestamp, если, например, данные офлайн). — message при успехе пуст. Если какие-то поля были автоматически скорректированы (например, отсечены лишние значения или пустые массивы), это обычно не указывается явно в ответе, но может логироваться. — В случае ошибок на этапе валидации/контекста – ответ с соответствующим кодом и сообщением. Сервер старается давать понятные сообщения (как в примере с cellVoltages count mismatch), чтобы разработчик приложений знал причину. 6. Логирование: В журнал может сохраняться запись о том, что получены замеры: пользователь, объект, группа, число ячеек, возможно первые/последние значения, и статус сохранения. Если произошла ошибка, то также логируются данные и причина (например, «rejected measurement for siteId X: no session» или «invalid data: …»).

Особенности offline/online режима: Передача измерений часто будет выполняться офлайн, поскольку инженер может закончить замеры и только позже получить связь: — Сбор данных офлайн: Приложение должно позволять вводить и сохранять все измеренные параметры без немедленной отправки. Типовой сценарий: — Инженер последовательно измеряет параметры (напряжения, температуры…). Если интернет доступен, он мог использовать instrument_photo для авто-сбора отдельных значений, но офлайн он, вероятно, вводил их вручную. — После заполнения всех полей для группы, он нажимает «Сохранить». Приложение сохраняет эти данные локально (например, в SQLite или in-memory, возможно, помечая их как несинхронизированные). — Инженер может продолжать ко второй группе (если есть) или к другому оборудованию, повторяя процесс, все офлайн. — Очередь на синхронизацию: При появлении подключения приложение должно отправить на сервер все накопленные measurements в правильном порядке. Порядок между разными группами не критичен для серверной части (они могут обрабатываться независимо), но логически можно придерживаться порядка выполнения работ или порядкового номера группы. — В каждом запросе передаются также соответствующие siteId, equipmentId, batteryGroup чтобы сервер правильно привязал данные. — Рекомендуется также сначала убедиться, что start_work для этого объекта уже на сервере (см. выше). Обычно, да, сначала синхронизируют start_work, потом данные. — Использование timestamp: Крайне важно при офлайн отправке указать timestamp измерений. Без него сервер при получении всех данных позже может считать, что все группы измерены практически одновременно (в момент синхронизации), что не отражает реальное время. Проставляя исходное время, мы сохраняем правдивую последовательность (например: группа 1 измерена в 14:50, группа 2 в 15:10 и т.д.). Это может понадобиться для анализа или просто для истории. — Успешная синхронизация и конфликтные ситуации: — Если при отправке сервер ответил успехом, приложение помечает локальные данные как отправленные (и может удалить локальную копию или пометить как синхронизированную). — Если сервер ответил ошибкой 400, значит данные были некорректны: такое может случиться, например, из-за бага в приложении или повреждения локальных данных. Приложению следует записать эту ошибку (лог) и не пытаться больше отправлять те же данные без изменения. Пользователю можно показать уведомление, что данные по группе не приняты сервером и требуют ручной проверки. Например, если явно сказано про несовпадение количества ячеек – вероятно, инженер выбрал не тот тип батареи или справочник не обновлен. В этом случае нужна вмешательство: либо исправление данных и повторная отправка, либо сообщить специалистам. — Если сервер вернул 409 (конфликт, например, из-за отсутствия start_work), приложение должно сначала решить проблему: например, выполнить синхронный start_work и затем повторить отправку измерений. — Другой конфликт: дубликат. Если, скажем, инженер нажал «Сохранить замеры» дважды и приложение по ошибке записало два идентичных набора, то при синхронизации второй может получить ошибку (если сервер не допускает дублей). Тогда приложение может игнорировать ошибку для второго, считая, что данные уже есть. — Массовая передача: Если сеть стала доступна ненадолго, а данных накопилось много (например, обслужено несколько объектов), приложение может отправлять данные пакетом или поочередно. Если API measurements поддерживает передачу массивов групп за раз, это можно использовать, но по описанию он ожидает одну группу за раз. Поэтому, следует поочередно вызывать для каждой сохраненной группы. — Отложенная отправка фото: Замеры часто сопровождаются фотографиями (приборов, дефектов). measurements.php сам по себе передает только цифры и текст. Фотографии должны быть отправлены через battery_photo, instrument_photo, defect до или после measurements. Если офлайн, приложение, скорее всего, сохранило фотографии локально. Их синхронизация может идти параллельно или последовательно с измерениями: — Например, можно сначала отправить все battery_photo (чтобы получить возможно недостающую инфу о батареях, хотя к моменту завершения измерений модель уже должна быть известна), затем measurements, затем defect фото. — В принципе, порядок фотографий относительно measurements не критичен, если в данных измерений нет прямой ссылки на фото (а обычно нет, фото связаны через контекст: фото батареи привязано к equipmentId/group, фото приборов мы вообще отдельно храним, дефекты тоже). — Важнее синхронизировать до end_work, чтобы к моменту закрытия все данные были на сервере. — Обработка ошибок сети: При потере сети во время отправки данных измерений онлайн (например, инженер вбил цифры и нажал сохранить, а сеть пропала): — Приложение должно переключиться на локальное сохранение (не терять данные!). Пользователю можно показать, что данные сохранены локально и будут отправлены позже. — При повторном появлении сети – аналогично офлайн режиму – эти данные уйдут. — Если частичный ответ получен или неполный – возможно, нужно решить, дублировать ли отправку. Как и с другими endpoint’ами, лучше иметь механизм подтверждения: напр., сервер при успешном сохранении возвращает recordId. Если клиент не получил ответа, он не знает, сохранилось или нет. В таких случаях, чтобы избежать дублирования: — Приложение может сравнивать отправляемые данные с теми, что на сервере (но без дополнительного API это сложно). — Либо повторить отправку, а сервер при попытке дублирования вернет конфликт (409). Если так произошло, можно считать, что первый запрос все-таки прошел и удалить дубликат локально. — Использование уникального идентификатора записи (например, генерация client-side UUID и отправка его) могло бы решить эту проблему (идемпотентность), но в текущем протоколе этого нет. Поэтому обработка дублей как ошибки 409 – приемлемое решение. — Локальное редактирование: Стоит предусмотреть, что инженер мог внести исправления в данные до отправки (например, заметил ошибку). Если данные локально изменены, на сервер должна уйти уже исправленная версия. Если до этого ошибочная версия успела отправиться (что маловероятно если он офлайн, но онлайн может), то потребуется механизм обновления. Сейчас measurements.php документация не описывает метод обновления; возможно, предполагается, что если нужно исправить – можно повторно отправить, и сервер перезапишет (если сделано так) или откажется (конфликт). Это за рамками данной документации, но важно помнить, что синхронизация должна учитывать только актуальные данные.

defect.php – Фиксация дефектов и неисправностей

Назначение: Эндпоинт для регистрации обнаруженных дефектов/неисправностей в аккумуляторах во время осмотра и измерений. Если инженер находит проблему (например: поднятые клеммы/борны, трещина на корпусе элемента, течь электролита, коррозия и т.д.), он отмечает это в приложении. defect.php позволяет отправить на сервер подробности дефекта: к какой батарейной системе и элементу он относится, тип проблемы, описание, а также приложить фотографию неисправности. Эта информация затем используется в отчетах (раздел «Замечания/неполадки») и при последующем анализе состояния оборудования.

URL и метод: POST /api/v1/defect (HTTP POST запрос).

Параметры запроса:

ПараметрТипОбязательныйОписание и формат
tokenstringдаТокен аутентификации пользователя.
siteIdintдаID объекта (сайта), на котором обнаружен дефект.
equipmentIdintдаID оборудования/системы (ЭПУ) внутри объекта, где найден дефект.
batteryGroupintдаНомер группы батарей, которой принадлежит дефектный элемент.
cellNumberintдаНомер конкретного элемента/ячейки в группе, на котором обнаружен дефект. Нумерация соответствует порядку элементов в группе (1,2,3,…).
defectTypestringдаТип дефекта. Строковый код или описание, определяющее проблему. Может быть ограниченный набор значений (например: «terminal_oxidation» – окисление клемм, «crack» – трещина, «leak» – утечка, «other» – прочее и т.д.). Рекомендуется использовать стандартизированные коды, но можно и текст.
descriptionstringнетДополнительное описание дефекта (комментарий инженера). Например: «Трещина на 3-м элементе, длина ~5 см». Если defectType=»other», здесь желательно указать суть проблемы. Максимальная длина текста — 255 символов (например).
photofileнет (да – если требуется фото)Фотография, иллюстрирующая дефект (например, снимок поврежденного элемента). Передается как файл изображения (JPEG/PNG) через multipart.
filestringнетАльтернатива при JSON: фото в виде Base64-строки. Если фото прилагается через JSON.
timestampstringнетВремя обнаружения дефекта, ISO 8601 или YYYY-MM-DD HH:MM:SS. Если не указано – по умолчанию время приема на сервере. Может быть использовано при офлайн-режиме, чтобы зафиксировать когда именно был найден дефект.

Пример HTTP-запроса (multipart/form-data):

curl -X POST «https://api.batterywizard.ru/v1/defect» \
     -F «token=ABC123DEF456» \
     -F «siteId=42» \
     -F «equipmentId=7» \
     -F «batteryGroup=2» \
     -F «cellNumber=5» \
     -F «defectType=crack» \
     -F «description=Трещина по шву корпуса элемента» \
     -F «photo=@/path/to/cracked_cell.jpg»

Пример HTTP-запроса (JSON):

curl -X POST «https://api.batterywizard.ru/v1/defect» \
     -H «Content-Type: application/json» \
     -d ‘{
           «token»: «ABC123DEF456»,
           «siteId»: 42,
           «equipmentId»: 7,
           «batteryGroup»: 2,
           «cellNumber»: 5,
           «defectType»: «crack»,
           «description»: «Трещина по шву корпуса элемента»,
           «file»: «/9j/4AAQSkZJRgABAQAAAQABAAD//…BASE64-IMAGE-DATA…//»,
           «timestamp»: «2025-08-22T15:10:30Z»
         }’

Пример успешного ответа:

{
  «ok»: true,
  «code»: 200,
  «message»: «»,
  «defectId»: 15,
  «savedAt»: «2025-08-22T15:11:00Z»
}

Здесь defectId – уникальный идентификатор зарегистрированного дефекта в системе (может соответствовать записи в таблице дефектов), а savedAt – время, зафиксированное сервером при сохранении (UTC). Если timestamp был предоставлен, savedAt может совпадать с ним или быть около текущего времени (в зависимости от политики; скорее, savedAt = текущее время записи, а само указанное время обнаружения хранится внутри записи дефекта).

Пример ответа при ошибке (например, неизвестный тип дефекта):

{
  «ok»: false,
  «code»: 400,
  «message»: «Unknown defectType. Allowed values: terminal_oxidation, crack, leak, other»
}

Такой ответ показывает, что передан некорректный тип дефекта (например, опечатка или значение вне списка). Сервер ожидает определенные значения, перечисленные в сообщении. Код 400 говорит о неправильном запросе.

Возможные ошибки:

Код ошибкиПричинаРекомендации
400Ошибка в структуре или содержании запроса. Возможные случаи:<br/>– Отсутствует какой-либо обязательный параметр (siteId, equipmentId, batteryGroup, cellNumber, defectType).<br/>– cellNumber вне допустимого диапазона (например, указан 5, а в группе всего 4 элемента).<br/>– defectType имеет недопустимое значение (не предусмотренное справочником типов дефектов).<br/>– Приложено фото, но файл поврежден или не прочитан.Проверить формирование запроса. Убедиться, что все обязательные поля присутствуют и корректны. Провалидировать cellNumber против числа элементов в группе (эту информацию приложение может знать из справочника объекта). Использовать валидные коды для defectType (приложение, вероятно, показывает список на основе справочника, избегая свободного ввода). Если фото не прикрепилось, повторить операцию с правильной передачей файла.
401/403Проблема с авторизацией (неверный токен или недостаточно прав).Выполнить повторную аутентификацию. Убедиться, что пользователь имеет права фиксировать дефекты на данном объекте (обычно это не ограничивается, если он имеет доступ к объекту).
404Не найден указанный объект или оборудование. Например, equipmentId не соответствует никакой системе на объекте siteId, либо объект siteId не существует.Убедиться, что отправляются актуальные идентификаторы. Возможно, справочник устарел – обновить данные объектов/оборудования перед поездкой.
409Конфликт: ситуация, когда тот же самый дефект уже был зарегистрирован. Например, если приложение по ошибке пытается отправить дублирующую запись (двойное нажатие). Либо если сессия работы на объекте не открыта/уже закрыта (зависит от требований – может не блокироваться).Если сервер указывает на дубликат (в сообщении, возможно, будет ID существующего дефекта), приложение может не дублировать запись локально. Проверить логику чтобы избегать повторной отправки. Если конфликт связан с сессией, убедиться, что вызовы start_work/end_work корректно обрамляют отправку дефектов.
413/415Слишком большой файл фотографии или неподдерживаемый формат.Уменьшить размер изображения (сжать/сконвертировать) и повторить. Форматы – JPEG/PNG.
500Внутренняя ошибка при сохранении дефекта (например, сбой БД).Попробовать позже. Если постоянно, передать информацию разработчикам сервера вместе с данными запроса для диагностики.

Логика обработки на сервере:

Модуль defect.php обрабатывает входящие данные следующим образом:

1. Аутентификация: Проверяет токен пользователя. Без валидного токена – отказ (как и в других модулях).

2. Валидация данных запроса: — Проверяются обязательные поля: siteId, equipmentId, batteryGroup, cellNumber, defectType. Если чего-то нет – 400. — Проверяется соответствие cellNumber и возможно batteryGroup с реальностью: сервер знает (или может выяснить из справочников), сколько ячеек в каждой группе указанного оборудования. Если cellNumber больше или меньше диапазона (например, 0 или > count) – возвращается ошибка (400) с описанием. — Проверяется defectType: скорее всего, существует фиксированный перечень типов дефектов (особенно если отчеты стандартизированы). Сервер может иметь справочник или жестко заданные допустимые строки. Если полученное значение не в списке, сервер вернет ошибку (как в примере). Если defectType = «other», желательно наличие description (но сервер, возможно, не строго требует, хотя может предупредить). — Размер и формат description: если он слишком длинный, сервер может обрезать или вернуть ошибку (400) – но обычно обрезают до лимита. — Фото: если запрос multipart, сервер ожидает файл в $_FILES. Если JSON – Base64 строку. — Проверяется тип (MIME) и размер фото: допустимы JPEG, PNG, ограничение по размеру, например, 5 МБ. Если нарушение – может быть код 415 (Unsupported Media Type) или 413 (Payload Too Large). — Если фото отсутствует – не критично, так как параметр не обязательный. Однако, если политика требует фото для серьезных дефектов, это не автоматом проверяется – инженер сам решает, но сервер примет дефект и без фото.

3. Проверка контекста (сессии/прав): — Сервер может убедиться, что у пользователя есть активная сессия работы на данном объекте (start_work выполнен и end_work не выполнен). Если система строгая, то обнаружение дефекта вне открытой сессии может быть не разрешено. Возможна ошибка 409 или 403. Если не реализовано – пропускается. — Также можно проверить, не зарегистрирован ли уже такой дефект: критерии совпадения могут быть: — Тот же equipmentId, batteryGroup, cellNumber и defectType (и, возможно, очень близкое время). Вряд ли два одинаковых дефекта на одном элементе сразу – скорее это дубликат отправки. — Если обнаружен потенциальный дубликат (например, запись в базе с теми же параметрами), сервер может вернуть 409 Conflict с указанием, что дефект уже зафиксирован. — Эти проверки помогают избежать двойного ввода (например, если пользователь дважды нажал «Сохранить» по ошибке).

4. Сохранение дефекта: При прохождении всех проверок создается запись о дефекте в базе: — Основные поля: объект, оборудование, группа, номер элемента, тип дефекта, описание, кто создал (ID пользователя из токена), время обнаружения (либо timestamp от клиента, либо текущее). — Фото: — Если фото приложено, оно сохраняется аналогично случаям battery_photo/instrument_photo: обычно в файловую систему и/или таблицу файлов. Например, сервер может записать файл в каталог uploads/defects/<user_or_site>/… и добавить запись в таблицу Files с возвращением ID. — Этот fileId (или путь) привязывается к записи дефекта (например, поле PhotoID). — Может выполняться создание миниатюры или сжатие, но это детали. — В самой записи дефекта можно сохранить ссылку на фото, а также указать статус дефекта (например, открытый, не устранен).

5. Формирование ответа: После сохранения сервер возвращает подтверждение: — ok:true, code 200. Может вернуть defectId – ID созданного дефекта, если клиенту нужно знать (обычно можно и без него, но полезно для последующих операций, например, если есть API для обновления или удаления дефекта). — savedAt – время записи. Сам timestamp обнаружения в ответе обычно не дублируется (клиент его сам знает), но может быть для проверки, если сервер, например, откорректировал его (вдруг клиент прислал будущее время – сервер бы заменил на текущее и, возможно, отразил бы). — message пустой при успехе. — При ошибке возвращается соответствующий код: 400 для проблем в данных (с описанием), 409 для дублей, 401/403 для авторизации, и т.д.

6. Логирование: Каждое зарегистрированное событие дефекта логируется (кто, где, что, когда, с фото или нет). Это важно, так как дефекты могут потребовать последующих действий (ремонт, закупка запчастей). Логи также помогут отследить, если что-то пошло не так (например, фото не сохранилось).

Особенности offline/online режима:

Регистрация дефектов должна работать и без немедленной связи, чтобы инженер мог документировать проблемы в полевых условиях:

Оффлайн фиксация дефекта:

— Как только дефект обнаружен, инженер в приложении выбирает тип из списка (справочник типов должен быть загружен заранее в приложение) и вводит комментарий, фотографирует проблему.

— Приложение сохраняет эти сведения локально: вероятно, в том же хранилище, где остальные данные. Фото сохраняется в память устройства (например, файл в приватном хранилище приложения) и ассоциируется с записью дефекта. — Рекомендуется также сразу показывать пользователю, что дефект добавлен в список дефектов текущей сессии (в UI, список “замечаний”).

Синхронизация дефектов:

При появлении связи, приложение отправляет накопленные дефекты через API defect: — Отправлять нужно после отправки соответствующих измерений группы (порядок не строго обязателен, но логически: сначала данные замеров, потом – дефекты, либо можно вперемешку, т.к. независимые объекты). Можно даже отправить дефекты сразу после измерений своей группы офлайн, чтобы не забыть, но чаще они просто висят до конца.

— Если start_work не был синхронизирован, его сначала, но к моменту sync, скорее всего, уже сделают.

— Каждый дефект отправляется отдельным запросом (API рассчитан на один дефект за раз). Стоит учитывать: фото может увеличить объем данных, передача займет время. — В offline записи дефекта стоит хранить те же поля (siteId, equipmentId, group, cell, type, desc, filepath, timestamp). Это позволяет прямо маппить на JSON при отправке. — При успешном ответе сервера defectId можно сохранить, но обычно необязательно – если нужно, например, потом получить полный отчет, можно просто позже запросить по объекту. — Если сервер вернул ошибку для дефекта: — 400 (например, неверный тип) – маловероятно, если тип брался из справочника, но если справочник устарел и сервер не принимает код, надо будет обновить справочник. Такие случаи лучше отслеживать: приложение может сообщить «Ошибка синхронизации дефекта №X: тип не распознан» и записать лог. Пользователь, скорее всего, не сможет тут же решить, но разработчики обновят типы. — 409 (дубликат) – возможно, дефект был отправлен дважды. Приложение может просто убрать дубликат из очереди. — 404 (не найден equipmentId) – значит рассинхрон справочников, но раз инженеру удалось его выбрать, значит проблема на сервере – надо обновить справочник, и, возможно, ID изменились. В момент sync мало что сделать, можно логировать. — 413/415 (проблема с фото) – фото слишком большое или криво. Решение: либо пережимать фото перед отправкой (приложение могло бы это делать превентивно), либо по ошибке попробовать сжать и послать снова. Это можно автоматизировать: например, если пришел 413, приложение может взять фото, уменьшить резолюцию/качество и повторить отправку. — После успешной отправки дефекта, локальная запись помечается как синхронизированная (или удаляется). Фото можно тоже удалить или пометить как «залитое», чтобы не занимало память.

Работа с фото в офлайн: — Приложение должно аккуратно хранить фото до отправки. Желательно иметь механизм ограничения: например, если фото очень большие, возможно, стоит сохранять их сжимая сразу после съемки, чтобы не перегружать ни устройство, ни потом канал передачи. — Если пользователь попытался добавить дефект, но не сделал фото (и опция необязательна), все ок. Если фото обязательна по внутренним инструкциям – приложение должно контролировать это на уровне UI (сервер не обязывает, судя по API).

User Experience при офлайн: Пользователь видит, что дефекты добавлены, но, возможно, стоит предупредить его, что без сети они пока «не отправлены». Можно, например, помечать несинхронизированные дефекты значком. При появлении сети и удачной отправке, снимать пометку.

Параллельность данных: Дефекты как данные не зависят от измерений напрямую, поэтому они могут быть отправлены даже после end_work (если инженер закрыл сессию офлайн, а потом все синхронизирует). Сервер, даже если сессия закрыта, скорее всего, примет дефект, поскольку это просто запись о проблеме на объекте. — Однако, если сервер жестко требует, чтобы дефекты регистрировались до end_work, то синхронизацию лучше проводить до закрытия. В офлайн сценарии, скорее всего, сервер не будет так жестко связывать, а просто прикрепит дефект к отчету постфактум.

Обработка сбоев при онлайне: Если интернет есть, но запрос defect не проходит (например, таймаут): — Приложение должно уведомить, что дефект временно не отправлен, но сохранен локально. Затем попытаться в фоне. — Опять же, следить за дублированием: не отправлять повторно, если не уверен, что первый совсем не дошел. Если сервер и создаст дубль, получим 409 на второй – не критично, но лучше стараться избежать.

Отчеты: После синхронизации всех дефектов, измерений и пр., сервер сможет сформировать полный отчет. В отчете список дефектов (с фото) по каждой группе будет основан на записях, отправленных через defect.php. Поэтому важно, чтобы ничего не потерялось. Локально приложение может уже уметь формировать предварительный отчет, но окончательная версия будет на сервере с полученными данными.

Дополнение: Все описанные эндпоинты интегрируются друг с другом в рамках рабочего процесса: — Перед выездом приложение должно загрузить справочники (типы батарей, объекты, оборудование, возможные дефекты). Для этого, вероятно, существуют отдельные API (например, получение списка объектов, списков дефектов), которые здесь не описаны, но задействуются в режиме online/prepare. — Во время работы офлайн приложение опирается на эти локальные справочники. — После завершения и синхронизации сервер имеет полную информацию: время прихода/ухода (start_work/end_work), данные всех замеров (measurements), фото батарей и приборов (battery_photo/instrument_photo) – для подтверждения, а также описание дефектов (defect). На основе этого сервер может автоматически генерировать отчеты (например, Word/PDF, как упомянуто в требованиях), доступные специалистам и руководству. — Мобильным разработчикам важно следить за согласованностью: идентификаторы, отношения между вызовами (например, сначала start_work, потом остальное, потом end_work), обработка ошибок своевременно. Соблюдение описанного протокола обеспечит успешную интеграцию приложения с сервером BatteryWizard.


Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх