Files
NODEDC_DESIGN_GUIDELINE/apps/device-manager/src/deviceProfileCatalog.ts
T

466 lines
35 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export type DeviceFieldAccess = "read-only" | "managed" | "protected";
export type DeviceFieldValueKind = "text" | "number" | "boolean" | "date";
export interface DeviceProfileField {
key: string;
label: string;
path: string;
access?: DeviceFieldAccess;
valueKind?: DeviceFieldValueKind;
unit?: string;
description?: string;
sensitive?: boolean;
}
export interface DeviceProfileSection {
id: string;
label: string;
title: string;
description: string;
access: DeviceFieldAccess;
fields: DeviceProfileField[];
}
export interface DeviceProfileCatalog {
profileRef: string;
vendor: string;
model: string;
title: string;
sections: DeviceProfileSection[];
}
const field = (
key: string,
label: string,
path: string,
options: Omit<DeviceProfileField, "key" | "label" | "path"> = {},
): DeviceProfileField => ({ key, label, path, ...options });
const managed = (
key: string,
label: string,
path: string,
options: Omit<DeviceProfileField, "key" | "label" | "path" | "access"> = {},
) => field(key, label, path, { ...options, access: "managed" });
const protectedField = (
key: string,
label: string,
path: string,
options: Omit<DeviceProfileField, "key" | "label" | "path" | "access"> = {},
) => field(key, label, path, { ...options, access: "protected" });
const serverFields = (slot: number) => [
managed(`server-${slot}-host`, `Сервер ${slot}: DNS / IP`, `reported.configuration.monitoring.servers.${slot - 1}.host`),
managed(`server-${slot}-port`, `Сервер ${slot}: порт`, `reported.configuration.monitoring.servers.${slot - 1}.port`, { valueKind: "number" }),
managed(`server-${slot}-protocol`, `Сервер ${slot}: протокол`, `reported.configuration.monitoring.servers.${slot - 1}.protocol`),
managed(`server-${slot}-identity`, `Сервер ${slot}: ID (SN)`, `reported.configuration.monitoring.servers.${slot - 1}.identity`),
managed(`server-${slot}-password`, `Сервер ${slot}: пароль`, `reported.configuration.monitoring.servers.${slot - 1}.password`, { sensitive: true }),
];
const managedIndexedFields = (
count: number,
prefix: string,
label: string,
path: string,
options: Omit<DeviceProfileField, "key" | "label" | "path" | "access"> = {},
) => Array.from({ length: count }, (_, index) => managed(
`${prefix}-${index + 1}`,
`${label} ${index + 1}`,
`${path}.${index}`,
options,
));
const phoneFields = Array.from({ length: 5 }, (_, index) => [
managed(`phone-${index + 1}-number`, `Телефон ${index + 1}: номер`, `reported.configuration.phones.${index}.number`, { sensitive: true }),
managed(`phone-${index + 1}-mode`, `Телефон ${index + 1}: режим`, `reported.configuration.phones.${index}.mode`),
]).flat();
const simFields = (slot: number) => [
managed(`sim-${slot}-gprs`, `SIM ${slot}: передача данных`, `reported.configuration.simCards.${slot - 1}.gprsEnabled`, { valueKind: "boolean" }),
managed(`sim-${slot}-apn`, `SIM ${slot}: APN оператора`, `reported.configuration.simCards.${slot - 1}.apn`),
managed(`sim-${slot}-login`, `SIM ${slot}: логин APN`, `reported.configuration.simCards.${slot - 1}.login`, { sensitive: true }),
managed(`sim-${slot}-password`, `SIM ${slot}: пароль APN`, `reported.configuration.simCards.${slot - 1}.password`, { sensitive: true }),
managed(`sim-${slot}-roaming`, `SIM ${slot}: роуминг`, `reported.configuration.simCards.${slot - 1}.roamingEnabled`, { valueKind: "boolean" }),
managed(`sim-${slot}-operator`, `SIM ${slot}: приоритетный оператор`, `reported.configuration.simCards.${slot - 1}.preferredOperatorCode`),
managed(`sim-${slot}-pin`, `SIM ${slot}: PIN`, `reported.configuration.simCards.${slot - 1}.pin`, { sensitive: true }),
managed(`sim-${slot}-ussd`, `SIM ${slot}: USSD запроса баланса`, `reported.configuration.simCards.${slot - 1}.balanceUssd`, { sensitive: true }),
managed(`sim-${slot}-poll`, `SIM ${slot}: период запроса баланса`, `reported.configuration.simCards.${slot - 1}.balancePollHours`, { valueKind: "number", unit: "ч" }),
];
const motionEventFields = ["acceleration", "braking", "cornering", "vertical"].flatMap((event) => {
const labels: Record<string, string> = {
acceleration: "Разгон",
braking: "Торможение",
cornering: "Угловое ускорение",
vertical: "Вертикальное ускорение",
};
return Array.from({ length: 3 }, (_, level) => [
managed(`${event}-${level + 1}-threshold`, `${labels[event]} ${level + 1}: порог`, `reported.configuration.drivingStyle.${event}.${level}.thresholdMg`, { valueKind: "number", unit: "mg" }),
managed(`${event}-${level + 1}-duration`, `${labels[event]} ${level + 1}: длительность превышения`, `reported.configuration.drivingStyle.${event}.${level}.durationMs`, { valueKind: "number", unit: "мс" }),
managed(`${event}-${level + 1}-reset`, `${labels[event]} ${level + 1}: задержка сброса`, `reported.configuration.drivingStyle.${event}.${level}.resetDelayMs`, { valueKind: "number", unit: "мс" }),
]).flat();
}).flat();
const violationFields = ["speed", "rpm"].flatMap((kind) => Array.from({ length: 4 }, (_, level) => [
managed(`${kind}-${level + 1}-threshold`, `${kind === "speed" ? "Скорость" : "Обороты"} ${level + 1}: порог`, `reported.configuration.drivingStyle.violations.${kind}.${level}.threshold`, { valueKind: "number", unit: kind === "speed" ? "км/ч" : "об/мин" }),
managed(`${kind}-${level + 1}-duration`, `${kind === "speed" ? "Скорость" : "Обороты"} ${level + 1}: минимальное время`, `reported.configuration.drivingStyle.violations.${kind}.${level}.minimumDurationSeconds`, { valueKind: "number", unit: "с" }),
managed(`${kind}-${level + 1}-reset`, `${kind === "speed" ? "Скорость" : "Обороты"} ${level + 1}: порог сброса`, `reported.configuration.drivingStyle.violations.${kind}.${level}.resetThreshold`, { valueKind: "number", unit: kind === "speed" ? "км/ч" : "об/мин" }),
]).flat()).flat();
const modbusRegisterFields = Array.from({ length: 10 }, (_, index) => [
managed(`modbus-register-${index + 1}`, `Регистр ${index + 1}: номер`, `reported.configuration.modbus.registers.${index}.number`, { valueKind: "number" }),
managed(`modbus-register-${index + 1}-pair`, `Регистр ${index + 1}: читать два регистра`, `reported.configuration.modbus.registers.${index}.readPair`, { valueKind: "boolean" }),
]).flat();
const bleFields = Array.from({ length: 10 }, (_, index) => [
managed(`ble-${index + 1}-mac`, `BLE датчик ${index + 1}: MAC`, `reported.configuration.bluetooth.sensors.${index}.mac`),
managed(`ble-${index + 1}-integration`, `BLE датчик ${index + 1}: интеграция`, `reported.configuration.bluetooth.sensors.${index}.integrationExpression`),
]).flat();
export const ARUSNAVI_B2_CATALOG: DeviceProfileCatalog = {
profileRef: "arusnavi.b2.internal.v1",
vendor: "ARUSNAVI",
model: "B2",
title: "ARUSNAVI B2",
sections: [
{
id: "passport",
label: "Паспорт",
title: "Паспорт и состояние устройства",
description: "Реестровая идентичность, профиль модели и текущее состояние канала. Исходный идентификатор показывается только в проекции, разрешённой Device Core.",
access: "read-only",
fields: [
field("display-name", "Название", "device.displayName"),
field("device-key", "Ключ устройства", "device.deviceKey"),
field("device-ref", "Device Core ref", "device.deviceRef"),
field("vendor", "Производитель", "profile.vendor"),
field("model", "Модель", "profile.model"),
field("device-type", "Тип", "profile.deviceType"),
field("profile", "Профиль модели", "device.modelProfileRef"),
field("identifier-kind", "Тип идентификатора", "device.identifier.kind"),
field("identifier", "Идентификатор", "device.identifier.masked"),
field("iccid-1", "ICCID 1", "reported.identity.iccid1"),
field("iccid-2", "ICCID 2", "reported.identity.iccid2"),
field("lifecycle", "Состояние реестра", "device.lifecycleState"),
field("created", "Зарегистрирован", "device.createdAt", { valueKind: "date" }),
field("updated", "Обновлён", "device.updatedAt", { valueKind: "date" }),
field("reported-at", "Снимок устройства получен", "reported.observedAt", { valueKind: "date" }),
managed("asset-model", "Модель актива", "reported.metadata.model"),
managed("registration", "Регистрационный номер", "reported.metadata.registrationNumber"),
managed("object", "Объект", "reported.metadata.object"),
managed("description", "Описание", "reported.metadata.description"),
managed("sim-label-1", "Метка SIM 1", "reported.metadata.simLabel1"),
managed("sim-label-2", "Метка SIM 2", "reported.metadata.simLabel2"),
],
},
{
id: "live",
label: "Онлайн",
title: "Живой канал и телеметрия",
description: "Значения обновляются из последней gateway-сессии и безопасного снимка телеметрии. Интерфейс опрашивает Device Core, пока открыта карточка.",
access: "read-only",
fields: [
field("session-state", "Состояние соединения", "session.lifecycleState"),
field("session-route", "Маршрут", "session.routeName"),
field("session-connected", "Подключён", "session.connectedAt", { valueKind: "date" }),
field("session-last-seen", "Последний пакет", "session.lastSeenAt", { valueKind: "date" }),
field("session-frames", "Принято пакетов", "session.frameCount", { valueKind: "number" }),
field("session-bytes", "Принято данных", "session.byteCount", { valueKind: "number", unit: "байт" }),
field("latitude", "Широта", "reported.telemetry.navigation.latitude"),
field("longitude", "Долгота", "reported.telemetry.navigation.longitude"),
field("speed", "Скорость", "reported.telemetry.navigation.speedKph", { valueKind: "number", unit: "км/ч" }),
field("altitude", "Высота", "reported.telemetry.navigation.altitudeMeters", { valueKind: "number", unit: "м" }),
field("satellites", "Спутники", "reported.telemetry.navigation.satellites", { valueKind: "number" }),
field("course", "Курс", "reported.telemetry.navigation.courseDegrees", { valueKind: "number", unit: "°" }),
field("hdop", "HDOP", "reported.telemetry.navigation.hdop"),
field("gsm-signal", "Уровень GSM", "reported.telemetry.gsm.signal"),
field("gsm-operator", "Оператор", "reported.telemetry.gsm.operator"),
field("gsm-lac", "LAC", "reported.telemetry.gsm.lac"),
field("gsm-cid", "CID", "reported.telemetry.gsm.cid"),
field("external-voltage", "Внешнее напряжение", "reported.telemetry.system.externalVoltageMv", { valueKind: "number", unit: "мВ" }),
field("internal-voltage", "Внутреннее напряжение", "reported.telemetry.system.internalVoltageMv", { valueKind: "number", unit: "мВ" }),
field("errors", "Ошибки и статусы", "reported.telemetry.system.status"),
field("inputs", "Входы и выходы", "reported.telemetry.system.io"),
field("modules", "Статусы модулей", "reported.telemetry.system.modules"),
field("engine-hours", "Моточасы", "reported.telemetry.can.engineHours"),
field("odometer", "Пробег", "reported.telemetry.can.odometer"),
field("fuel-total", "Полный расход топлива", "reported.telemetry.can.fuelTotal"),
field("fuel-level", "Уровень топлива", "reported.telemetry.can.fuelLevel"),
field("rpm", "Обороты двигателя", "reported.telemetry.can.rpm"),
field("engine-temp", "Температура двигателя", "reported.telemetry.can.engineTemperature"),
field("vehicle-speed", "Скорость по CAN", "reported.telemetry.can.vehicleSpeed"),
field("axle-pressure", "Давление на оси", "reported.telemetry.can.axlePressure"),
field("crash", "Контроллер аварии", "reported.telemetry.can.crashController"),
field("instant-fuel", "Моментальный расход", "reported.telemetry.can.instantFuel"),
field("adblue", "Уровень AdBlue", "reported.telemetry.can.adBlueLevel"),
],
},
{
id: "firmware",
label: "Прошивка",
title: "Версия программного обеспечения",
description: "Версию и доступность обновления показываем, но запуск обновления для пилотного B2 запрещён. Этот запрет не снимается включением обычного командного канала.",
access: "protected",
fields: [
field("firmware-current", "Текущая версия", "reported.firmware.currentVersion"),
field("firmware-applied", "Версия применена", "reported.firmware.appliedAt", { valueKind: "date" }),
field("firmware-available", "Доступная версия", "reported.firmware.availableVersion"),
field("firmware-description", "Описание версии", "reported.firmware.description"),
protectedField("firmware-action", "Обновление прошивки", "policies.firmwareUpdate", { description: "Заблокировано для пилотного устройства" }),
],
},
{
id: "templates",
label: "Шаблоны",
title: "Шаблоны настроек",
description: "Шаблон хранит именованный снимок конфигурации модели. Применение должно создавать новую desired-ревизию, а не менять устройство в обход command ledger.",
access: "managed",
fields: [
field("template-current", "Применённый шаблон", "reported.configurationTemplate.name"),
field("template-applied", "Шаблон применён", "reported.configurationTemplate.appliedAt", { valueKind: "date" }),
managed("template-select", "Выбранный шаблон", "reported.configurationTemplate.selected"),
managed("template-name", "Название нового шаблона", "reported.configurationTemplate.draft.name"),
managed("template-description", "Описание нового шаблона", "reported.configurationTemplate.draft.description"),
],
},
{
id: "monitoring",
label: "Серверы",
title: "Серверы мониторинга",
description: "B2 поддерживает четыре серверных слота. Существующий Gelios сохраняется параллельно; новый маршрут не должен его перетирать.",
access: "managed",
fields: [1, 2, 3, 4].flatMap(serverFields),
},
{
id: "transmission",
label: "Передача",
title: "Набор передаваемых данных",
description: "Флаги определяют состав телеметрии, которую формирует устройство.",
access: "managed",
fields: [
managed("tx-nav-position", "Навигация: широта и долгота", "reported.configuration.transmission.navigation.position", { valueKind: "boolean" }),
managed("tx-nav-motion", "Навигация: скорость, высота, спутники и курс", "reported.configuration.transmission.navigation.motion", { valueKind: "boolean" }),
managed("tx-nav-hdop", "Навигация: HDOP", "reported.configuration.transmission.navigation.hdop", { valueKind: "boolean" }),
managed("tx-gsm-operator", "GSM: сигнал и оператор", "reported.configuration.transmission.gsm.operator", { valueKind: "boolean" }),
managed("tx-gsm-cell", "GSM: LAC и CID", "reported.configuration.transmission.gsm.cell", { valueKind: "boolean" }),
managed("tx-system-status", "Системные: ошибки и статусы", "reported.configuration.transmission.system.status", { valueKind: "boolean" }),
managed("tx-system-io", "Системные: входы, выходы и модули", "reported.configuration.transmission.system.io", { valueKind: "boolean" }),
managed("tx-system-voltage", "Системные: напряжения", "reported.configuration.transmission.system.voltage", { valueKind: "boolean" }),
...["statuses", "engineHours", "odometer", "fuelTotal", "fuelLevel", "rpm", "engineTemperature", "vehicleSpeed", "axlePressure", "crashController", "instantFuel", "adBlueLevel"].map((key) => managed(`tx-can-${key}`, `CAN: ${({ statuses: "статусы работы", engineHours: "моточасы", odometer: "пробег", fuelTotal: "полный расход топлива", fuelLevel: "уровень топлива", rpm: "обороты двигателя", engineTemperature: "температура двигателя", vehicleSpeed: "скорость", axlePressure: "давление на оси", crashController: "контроллер аварии", instantFuel: "моментальный расход", adBlueLevel: "уровень AdBlue" } as Record<string, string>)[key]}`, `reported.configuration.transmission.can.${key}`, { valueKind: "boolean" })),
],
},
{
id: "trajectory",
label: "Траектория",
title: "Отрисовка траектории и датчик движения",
description: "Обычные и роуминговые интервалы, заморозка координат и параметры встроенного датчика движения.",
access: "managed",
fields: [
...["normal", "roaming"].flatMap((mode) => {
const label = mode === "normal" ? "Основной режим" : "Роуминг";
return [
managed(`${mode}-course`, `${label}: изменение курса`, `reported.configuration.trajectory.${mode}.courseDeltaDegrees`, { valueKind: "number", unit: "°" }),
managed(`${mode}-speed`, `${label}: изменение скорости`, `reported.configuration.trajectory.${mode}.speedDeltaKph`, { valueKind: "number", unit: "км/ч" }),
managed(`${mode}-distance`, `${label}: расстояние между точками`, `reported.configuration.trajectory.${mode}.distanceMeters`, { valueKind: "number", unit: "м" }),
managed(`${mode}-parking`, `${label}: интервал на стоянке`, `reported.configuration.trajectory.${mode}.parkingIntervalSeconds`, { valueKind: "number", unit: "с" }),
];
}),
managed("freeze-low-speed", "Заморозка координат при скорости ниже 2 км/ч", "reported.configuration.trajectory.freeze.lowSpeed", { valueKind: "boolean" }),
managed("freeze-motion", "Заморозка по датчику движения", "reported.configuration.trajectory.freeze.motionSensor", { valueKind: "boolean" }),
managed("freeze-ignition", "Заморозка по зажиганию", "reported.configuration.trajectory.freeze.ignition", { valueKind: "boolean" }),
managed("freeze-quiet", "Тихоходная техника", "reported.configuration.trajectory.freeze.lowSpeedVehicle", { valueKind: "boolean" }),
managed("motion-sensitivity", "Чувствительность датчика движения", "reported.configuration.motionSensor.sensitivity", { valueKind: "number" }),
managed("motion-delay", "Задержка срабатывания", "reported.configuration.motionSensor.delaySeconds", { valueKind: "number", unit: "с" }),
managed("motion-impact", "Порог удара", "reported.configuration.motionSensor.impact", { valueKind: "number" }),
managed("motion-tilt", "Порог наклона", "reported.configuration.motionSensor.tilt", { valueKind: "number" }),
],
},
{
id: "io",
label: "Входы / выходы",
title: "Входы и выходы",
description: "Режимы PIN0–PIN7 и пороги. Непосредственное переключение выходов относится к защищённым командам.",
access: "managed",
fields: [
...managedIndexedFields(8, "pin-mode", "Режим PIN", "reported.configuration.io.pinModes"),
managed("speed-coefficient", "Коэффициент датчика скорости", "reported.configuration.io.speedSensorCoefficient", { valueKind: "number" }),
managed("virtual-ignition", "Порог виртуального зажигания", "reported.configuration.io.virtualIgnitionThresholdMv", { valueKind: "number", unit: "мВ" }),
managed("analog-pin-2", "Порог аналогового входа PIN2", "reported.configuration.io.analogThresholds.pin2Mv", { valueKind: "number", unit: "мВ" }),
managed("analog-pin-3", "Порог аналогового входа PIN3", "reported.configuration.io.analogThresholds.pin3Mv", { valueKind: "number", unit: "мВ" }),
protectedField("output-4", "Команда выхода PIN4", "reported.operations.outputs.pin4"),
protectedField("output-5", "Команда выхода PIN5", "reported.operations.outputs.pin5"),
protectedField("output-6", "Команда выхода PIN6", "reported.operations.outputs.pin6"),
],
},
{
id: "ports",
label: "Порты",
title: "Цифровые порты и датчики",
description: "RS232, RS485, CAN, WiFi, фотоснимки, 1‑Wire и фильтрация датчиков.",
access: "managed",
fields: [
managed("rs232", "RS232", "reported.configuration.ports.rs232.mode"),
managed("rs485", "RS485", "reported.configuration.ports.rs485.mode"),
managed("can-program", "Номер программы CAN", "reported.configuration.ports.can.program", { valueKind: "number" }),
managed("can-internal", "Активировать внутренний CAN", "reported.configuration.ports.can.internalEnabled", { valueKind: "boolean" }),
managed("can-seatbelt", "Контролировать ремень по CAN", "reported.configuration.ports.can.seatbelt", { valueKind: "boolean" }),
managed("can-headlight", "Контролировать ближний свет по CAN", "reported.configuration.ports.can.headlight", { valueKind: "boolean" }),
managed("wifi-ssid", "WiFi: имя сети", "reported.configuration.ports.wifi.ssid"),
managed("wifi-password", "WiFi: пароль", "reported.configuration.ports.wifi.password", { sensitive: true }),
managed("photo-interval", "Интервал фотоснимков", "reported.configuration.ports.camera.intervalMinutes", { valueKind: "number", unit: "мин" }),
managed("photo-resolution", "Разрешение фотоснимков", "reported.configuration.ports.camera.resolution"),
managed("one-wire-auto", "Сохранять новые термодатчики", "reported.configuration.ports.oneWire.autoDiscover", { valueKind: "boolean" }),
...managedIndexedFields(10, "one-wire", "Адрес термодатчика", "reported.configuration.ports.oneWire.sensorAddresses"),
managed("median-filter", "Медианный фильтр датчиков", "reported.configuration.ports.sensorFilter.medianEnabled", { valueKind: "boolean" }),
...managedIndexedFields(4, "lls-filter", "Степень фильтрации LLS", "reported.configuration.ports.sensorFilter.lls", { valueKind: "number" }),
],
},
{
id: "modbus",
label: "Modbus",
title: "Параметры Modbus",
description: "Последовательный порт, сетевые адреса и до десяти читаемых регистров.",
access: "managed",
fields: [
managed("modbus-baud", "Скорость обмена", "reported.configuration.modbus.baudRate", { valueKind: "number" }),
managed("modbus-poll", "Таймер опроса", "reported.configuration.modbus.pollSeconds", { valueKind: "number", unit: "с" }),
managed("modbus-parity", "Проверка на чётность", "reported.configuration.modbus.parity"),
managed("modbus-stop", "Stop bits", "reported.configuration.modbus.stopBits"),
managed("modbus-address-a", "Сетевой адрес датчика для регистров 1–5", "reported.configuration.modbus.addresses.first", { valueKind: "number" }),
managed("modbus-address-b", "Сетевой адрес датчика для регистров 6–10", "reported.configuration.modbus.addresses.second", { valueKind: "number" }),
...modbusRegisterFields,
],
},
{
id: "bluetooth",
label: "Bluetooth",
title: "Bluetooth (BLE) датчики",
description: "Режим BLE-модуля, код сопряжения и десять датчиков с выражениями универсальной интеграции.",
access: "managed",
fields: [
managed("ble-mode", "Режим работы Bluetooth", "reported.configuration.bluetooth.mode"),
managed("ble-pairing", "Код сопряжения", "reported.configuration.bluetooth.pairingCode", { sensitive: true }),
...bleFields,
],
},
{
id: "driving-style",
label: "Стиль вождения",
title: "Стиль вождения",
description: "Пороговые профили акселерометра и превышений скорости/оборотов.",
access: "managed",
fields: [
...motionEventFields,
managed("accelerometer-transmit", "Передавать данные акселерометра", "reported.configuration.drivingStyle.transmitAccelerometer", { valueKind: "boolean" }),
managed("accelerometer-reset-events", "Передавать события сброса", "reported.configuration.drivingStyle.transmitResetEvents", { valueKind: "boolean" }),
managed("accelerometer-bitmask", "Передавать состояния сработок", "reported.configuration.drivingStyle.transmitTriggerMask", { valueKind: "boolean" }),
managed("accelerometer-average", "Глубина усреднения акселерометра", "reported.configuration.drivingStyle.averagingDepth", { valueKind: "number" }),
...violationFields,
],
},
{
id: "phones",
label: "Телефоны",
title: "Разрешённые телефоны",
description: "До пяти номеров и индивидуальный режим доступа для SMS-управления.",
access: "managed",
fields: phoneFields,
},
{
id: "sim",
label: "SIM-карты",
title: "SIM-карты и мобильная сеть",
description: "Параметры двух SIM-профилей. Пароли, PIN и USSD не возвращаются в открытом виде.",
access: "managed",
fields: [...simFields(1), ...simFields(2)],
},
{
id: "navigation",
label: "Навигация",
title: "Навигация и фильтрация координат",
description: "Источники координат, спутниковые группировки, внешний локатор и фильтры качества.",
access: "managed",
fields: [
managed("nav-satellite", "Спутниковая навигация", "reported.configuration.navigation.sources.satellite", { valueKind: "boolean" }),
managed("nav-wifi", "WiFi локатор", "reported.configuration.navigation.sources.wifi", { valueKind: "boolean" }),
managed("nav-lbs", "LBS локатор", "reported.configuration.navigation.sources.lbs", { valueKind: "boolean" }),
managed("nav-tag", "Навигационная метка", "reported.configuration.navigation.sources.tag", { valueKind: "boolean" }),
...["gps", "glonass", "galileo", "beidou"].map((key) => managed(`nav-${key}`, key.toUpperCase(), `reported.configuration.navigation.constellations.${key}`, { valueKind: "boolean" })),
managed("locator-url", "URL локатора", "reported.configuration.navigation.locator.url", { sensitive: true }),
managed("locator-moving", "Интервал локатора в движении", "reported.configuration.navigation.locator.movingIntervalSeconds", { valueKind: "number", unit: "с" }),
managed("locator-parked", "Интервал локатора на стоянке", "reported.configuration.navigation.locator.parkedIntervalSeconds", { valueKind: "number", unit: "с" }),
managed("filter-satellites", "Минимальное число спутников", "reported.configuration.navigation.filter.minimumSatellites", { valueKind: "number" }),
managed("filter-hdop", "Максимальный HDOP × 10", "reported.configuration.navigation.filter.maximumHdopTimesTen", { valueKind: "number" }),
managed("filter-altitude-min", "Минимальная высота", "reported.configuration.navigation.filter.minimumAltitudeMeters", { valueKind: "number", unit: "м" }),
managed("filter-altitude-max", "Максимальная высота", "reported.configuration.navigation.filter.maximumAltitudeMeters", { valueKind: "number", unit: "м" }),
managed("filter-speed-min", "Минимальная мгновенная скорость", "reported.configuration.navigation.filter.minimumInstantSpeedKph", { valueKind: "number", unit: "км/ч" }),
managed("filter-speed-max", "Максимальная мгновенная скорость", "reported.configuration.navigation.filter.maximumInstantSpeedKph", { valueKind: "number", unit: "км/ч" }),
managed("filter-speed-average", "Максимальная средняя скорость", "reported.configuration.navigation.filter.maximumAverageSpeedKph", { valueKind: "number", unit: "км/ч" }),
managed("filter-time", "Максимальное время фильтрации", "reported.configuration.navigation.filter.maximumSeconds", { valueKind: "number", unit: "с" }),
],
},
{
id: "system",
label: "Системные",
title: "Системные параметры",
description: "Системные интервалы и энергосбережение. Секретные значения отображаются только как факт наличия.",
access: "managed",
fields: [
managed("sms-password", "Пароль устройства (SMS)", "reported.configuration.system.smsPassword", { sensitive: true }),
managed("web-check-hours", "Проверять WEB-конфигуратор каждые", "reported.configuration.system.webConfiguration.checkHours", { valueKind: "number", unit: "ч" }),
managed("web-check-start", "Проверять WEB-конфигуратор при старте", "reported.configuration.system.webConfiguration.onStart", { valueKind: "boolean" }),
managed("sleep-mode", "Режим сна", "reported.configuration.system.powerSaving.mode"),
managed("sleep-wake-interval", "Выходить на связь каждые", "reported.configuration.system.powerSaving.wakeIntervalMinutes", { valueKind: "number", unit: "мин" }),
managed("sleep-online", "Время пребывания на связи", "reported.configuration.system.powerSaving.onlineMinutes", { valueKind: "number", unit: "мин" }),
managed("sleep-motion", "Выходить из сна по датчику движения", "reported.configuration.system.powerSaving.wakeOnMotion", { valueKind: "boolean" }),
managed("sleep-input", "Выходить из сна по изменению входа", "reported.configuration.system.powerSaving.wakeOnInput", { valueKind: "boolean" }),
managed("battery-ignition", "Заряжать АКБ только при включённом зажигании", "reported.configuration.system.chargeBatteryOnIgnitionOnly", { valueKind: "boolean" }),
],
},
{
id: "diagnostics",
label: "Диагностика",
title: "Диагностика и операции",
description: "Доступные B2 операции отражены полностью, но выполняются только через подтверждённый двусторонний канал и отдельный command ledger.",
access: "protected",
fields: [
field("debug-last-session", "Последняя удалённая отладка", "reported.diagnostics.lastSessionAt", { valueKind: "date" }),
field("debug-output", "Результат удалённой отладки", "reported.diagnostics.output"),
protectedField("op-packet", "Запросить пакет телеметрии", "reported.operations.requestTelemetry"),
protectedField("op-info", "Запросить информацию", "reported.operations.requestInfo"),
protectedField("op-coordinates", "Запросить координаты", "reported.operations.requestCoordinates"),
protectedField("op-config", "Синхронизировать настройки", "reported.operations.syncConfiguration"),
protectedField("op-restart", "Перезапустить устройство", "reported.operations.restart"),
protectedField("op-clear", "Очистить память", "reported.operations.clearMemory"),
protectedField("op-firmware", "Обновить прошивку", "reported.operations.updateFirmware", { description: "Запрещено для пилотного B2" }),
],
},
],
};
const genericCatalog: DeviceProfileCatalog = {
profileRef: "generic.device.v1",
vendor: "NODE.DC",
model: "Generic device",
title: "Устройство",
sections: ARUSNAVI_B2_CATALOG.sections.filter((section) => ["passport", "live"].includes(section.id)),
};
const catalogs = new Map<string, DeviceProfileCatalog>([
[ARUSNAVI_B2_CATALOG.profileRef, ARUSNAVI_B2_CATALOG],
]);
export function getDeviceProfileCatalog(profileRef: string): DeviceProfileCatalog {
return catalogs.get(profileRef) ?? { ...genericCatalog, profileRef };
}
export function accessLabel(access: DeviceFieldAccess) {
return ({
"read-only": "Только чтение",
managed: "Управляемая настройка",
protected: "Защищённая операция",
})[access];
}