feat(provider): add Gelios unit profile product
This commit is contained in:
parent
2def90fa33
commit
e843bbda66
|
|
@ -1,9 +1,15 @@
|
|||
# Gelios capability catalog
|
||||
|
||||
`capability-catalog-v1.mjs` is the complete classified inventory for the
|
||||
`capability-catalog-v1.mjs` is the immutable baseline classified inventory for the
|
||||
current `UnitModelOutput` surface and the adjacent object APIs that NODE.DC may
|
||||
consume. Its authority is the official Gelios OpenAPI, checked on 2026-07-22.
|
||||
|
||||
`capability-catalog-v2.mjs` preserves that inventory and records the first cold
|
||||
profile implementation: stable unit type, hardware classification and trip
|
||||
settings in `fleet.units.profile.current.v1`. Sensor definitions, fuel,
|
||||
storage and maintenance remain explicitly planned rather than being implied by
|
||||
the new product.
|
||||
|
||||
The catalog is deliberately separate from an active L2 package. `implemented`
|
||||
means a capability already has a governed collection and Data Product path;
|
||||
`catalogued` means NODE.DC understands the surface but has not activated it;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
import { geliosCapabilityCatalogV1 } from "./capability-catalog-v1.mjs";
|
||||
|
||||
export const geliosCapabilityCatalogV2 = deepFreeze(updateFamilies({
|
||||
...structuredClone(geliosCapabilityCatalogV1),
|
||||
version: "2.0.0",
|
||||
authority: {
|
||||
...geliosCapabilityCatalogV1.authority,
|
||||
checkedAt: "2026-07-22T20:32:27Z",
|
||||
},
|
||||
}));
|
||||
|
||||
function updateFamilies(value) {
|
||||
value.dataFamilies = value.dataFamilies.map((family) => {
|
||||
if (family.id === "gelios.unit.identity") {
|
||||
return implemented(family);
|
||||
}
|
||||
if (family.id === "gelios.unit.equipment") {
|
||||
return implemented({
|
||||
...family,
|
||||
sourcePaths: [
|
||||
"hwManufacturer.id",
|
||||
"hwManufacturer.name",
|
||||
"hwType.id",
|
||||
"hwType.name",
|
||||
"hwType.port",
|
||||
"hwType.type",
|
||||
],
|
||||
});
|
||||
}
|
||||
if (family.id === "gelios.unit.trip_settings") {
|
||||
return implemented(family);
|
||||
}
|
||||
return family;
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
function implemented(family) {
|
||||
return {
|
||||
...family,
|
||||
status: "implemented",
|
||||
dataProductIds: ["fleet.units.profile.current.v1"],
|
||||
};
|
||||
}
|
||||
|
||||
function deepFreeze(input) {
|
||||
if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
|
||||
Object.freeze(input);
|
||||
for (const child of Object.values(input)) deepFreeze(child);
|
||||
return input;
|
||||
}
|
||||
|
|
@ -1,2 +1,4 @@
|
|||
export { geliosCapabilityCatalogV1 } from "./capability-catalog-v1.mjs";
|
||||
export * from "./v7/index.mjs";
|
||||
export { geliosCapabilityCatalogV2 } from "./capability-catalog-v2.mjs";
|
||||
export { geliosProviderPackageV7 } from "./v7/index.mjs";
|
||||
export * from "./v8/index.mjs";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
# Gelios provider package v8
|
||||
|
||||
Version 8 preserves every v7 capability and product, and adds the immutable
|
||||
`fleet.units.profile.current.v1@1.0.0` cold-profile contract.
|
||||
|
||||
The profile uses the same credential-visible `/api/v1/units` authority as the
|
||||
accepted position flow, but has its own six-hour collection profile and Data
|
||||
Product lifecycle. It publishes only provider-neutral equipment classification
|
||||
and trip-detection settings keyed by the existing `gelios-unit-*` source id.
|
||||
IMEI, phones, decrypt keys, raw message parameters, provider access metadata,
|
||||
conversion tables and unclassified dynamic values remain excluded.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
export {
|
||||
GELIOS_PROVIDER_PACKAGE_ID,
|
||||
GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID,
|
||||
GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION,
|
||||
GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION,
|
||||
geliosProviderPackageV8,
|
||||
} from "./package.mjs";
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
import { geliosProviderPackageV7 } from "../v7/package.mjs";
|
||||
|
||||
export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v8";
|
||||
export const GELIOS_PROVIDER_PACKAGE_VERSION = "8.0.0";
|
||||
export const GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID = "fleet.units.profile.current.v1";
|
||||
export const GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION = "1.0.0";
|
||||
export const GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION = "ontology.map.moving_object.v3";
|
||||
|
||||
const FIELD_POLICY_ID = "gelios.units.profile.fields.v1";
|
||||
const COLLECTION_PROFILE_ID = "gelios.units.profile.cold.v1";
|
||||
const MAPPING_ID = "gelios.units.to.fleet.units.profile.current.v1";
|
||||
const TEMPLATE_ID = "gelios.units.profile.l2.v1";
|
||||
|
||||
const profileFields = Object.freeze([
|
||||
"corrected_engine_hours_factor",
|
||||
"corrected_mileage_factor",
|
||||
"display_name",
|
||||
"filter_by_satellite_count_enabled",
|
||||
"filter_by_satellite_count_value",
|
||||
"filter_emissions",
|
||||
"hardware_manufacturer_name",
|
||||
"hardware_port",
|
||||
"hardware_type_class",
|
||||
"hardware_type_name",
|
||||
"limit_acceleration",
|
||||
"lost_connection_enabled",
|
||||
"lost_connection_time_value",
|
||||
"maximum_permissible_speed",
|
||||
"maximum_valid_height",
|
||||
"maximum_valid_speed",
|
||||
"mileage_by_ignition",
|
||||
"minimum_movement_speed",
|
||||
"minimum_movement_time",
|
||||
"minimum_parking_time",
|
||||
"minimum_stop_time",
|
||||
"minimum_trip_distance",
|
||||
"minimum_valid_height",
|
||||
"speed_parameter",
|
||||
"trip_detection_type",
|
||||
"unit_type_class",
|
||||
"unit_type_name",
|
||||
"use_odometer",
|
||||
]);
|
||||
|
||||
const fieldContracts = Object.freeze({
|
||||
corrected_engine_hours_factor: optional("number"),
|
||||
corrected_mileage_factor: optional("number"),
|
||||
display_name: { type: "string", required: true },
|
||||
filter_by_satellite_count_enabled: optional("boolean"),
|
||||
filter_by_satellite_count_value: nonNegative(),
|
||||
filter_emissions: nonNegative(),
|
||||
hardware_manufacturer_name: optional("string"),
|
||||
hardware_port: nonNegative(),
|
||||
hardware_type_class: optional("string"),
|
||||
hardware_type_name: optional("string"),
|
||||
limit_acceleration: nonNegative(),
|
||||
lost_connection_enabled: optional("boolean"),
|
||||
lost_connection_time_value: nonNegative(),
|
||||
maximum_permissible_speed: nonNegative(),
|
||||
maximum_valid_height: optional("number"),
|
||||
maximum_valid_speed: nonNegative(),
|
||||
mileage_by_ignition: optional("boolean"),
|
||||
minimum_movement_speed: nonNegative(),
|
||||
minimum_movement_time: nonNegative(),
|
||||
minimum_parking_time: nonNegative(),
|
||||
minimum_stop_time: nonNegative(),
|
||||
minimum_trip_distance: nonNegative(),
|
||||
minimum_valid_height: optional("number"),
|
||||
speed_parameter: optional("string"),
|
||||
trip_detection_type: optional("string"),
|
||||
unit_type_class: optional("string"),
|
||||
unit_type_name: optional("string"),
|
||||
use_odometer: optional("boolean"),
|
||||
});
|
||||
|
||||
const value = structuredClone(geliosProviderPackageV7);
|
||||
value.id = GELIOS_PROVIDER_PACKAGE_ID;
|
||||
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
value.manifest = {
|
||||
...value.manifest,
|
||||
id: "gelios.provider.manifest.v8",
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
fieldPolicyIds: [...value.manifest.fieldPolicyIds, FIELD_POLICY_ID],
|
||||
collectionProfileIds: [...value.manifest.collectionProfileIds, COLLECTION_PROFILE_ID],
|
||||
dataProductIds: [...value.manifest.dataProductIds, GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID],
|
||||
mappingContractIds: [...value.manifest.mappingContractIds, MAPPING_ID],
|
||||
l2TemplateIds: [...value.manifest.l2TemplateIds, TEMPLATE_ID],
|
||||
};
|
||||
|
||||
value.fieldPolicies.push({
|
||||
id: FIELD_POLICY_ID,
|
||||
version: GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION,
|
||||
dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID,
|
||||
targetFields: [...profileFields],
|
||||
unknownSourceFields: "drop",
|
||||
dynamicSourceFields: "drop_until_classified",
|
||||
restrictedSourcePaths: [
|
||||
"availableToUsers",
|
||||
"commands",
|
||||
"creator",
|
||||
"currentUserAccess",
|
||||
"customFields",
|
||||
"driver",
|
||||
"extraInfo.autocompleteParams",
|
||||
"extraInfo.numberPlate",
|
||||
"extraInfo.vin",
|
||||
"hwDecryptKey",
|
||||
"imei",
|
||||
"lastMsg.address",
|
||||
"lastMsg.params",
|
||||
"lastSensorsVal",
|
||||
"phone",
|
||||
"phone2",
|
||||
"preSetCommandGroup",
|
||||
"sensors",
|
||||
"stationaryLat",
|
||||
"stationaryLon",
|
||||
],
|
||||
});
|
||||
|
||||
value.collectionProfiles.push({
|
||||
id: COLLECTION_PROFILE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
mode: "realtime",
|
||||
schedule: { intervalMs: 6 * 60 * 60 * 1000 },
|
||||
capabilityIds: ["gelios.units.current.read"],
|
||||
dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID,
|
||||
mappingContractId: MAPPING_ID,
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
l2TemplateId: TEMPLATE_ID,
|
||||
entityScope: {
|
||||
mode: "all_visible_to_credential",
|
||||
refresh: "each_collection_run",
|
||||
businessEntityFilter: "forbidden",
|
||||
},
|
||||
batching: { maxFacts: 5000 },
|
||||
cardinality: {
|
||||
maxCurrentEntities: 5000,
|
||||
onExceed: "require_partitioned_data_product",
|
||||
},
|
||||
retry: { maxAttempts: 4, backoff: "exponential_with_jitter" },
|
||||
});
|
||||
|
||||
value.dataProducts.push({
|
||||
id: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID,
|
||||
version: GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION,
|
||||
deliveryMode: "snapshot+patch",
|
||||
semanticTypes: ["map.moving_object"],
|
||||
fields: [...profileFields],
|
||||
fieldContracts,
|
||||
history: { mode: "none", retentionDays: 1 },
|
||||
});
|
||||
|
||||
value.mappingContracts.push({
|
||||
schemaVersion: "nodedc.semantic-mapping/v1",
|
||||
id: MAPPING_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
sourceCapabilityId: "gelios.units.current.read",
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
target: {
|
||||
dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID,
|
||||
version: GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION,
|
||||
semanticType: "map.moving_object",
|
||||
},
|
||||
derivations: {},
|
||||
fact: {
|
||||
sourceId: {
|
||||
strategy: "first_non_empty",
|
||||
paths: ["id", "unit_id", "unitId"],
|
||||
coerce: "string",
|
||||
prefix: "gelios-unit-",
|
||||
},
|
||||
semanticType: { constant: "map.moving_object" },
|
||||
observedAt: {
|
||||
strategy: "first_non_empty",
|
||||
paths: ["updatedAt"],
|
||||
coerce: "unix_or_iso_timestamp",
|
||||
fallback: "collection_received_at",
|
||||
},
|
||||
attributes: {
|
||||
corrected_engine_hours_factor: numberField(["tripParams.correctedEngineHoursFactor"]),
|
||||
corrected_mileage_factor: numberField(["tripParams.correctedMileageFactor"]),
|
||||
display_name: stringField(["name", "unit_name", "title", "label"], false),
|
||||
filter_by_satellite_count_enabled: booleanField(["tripParams.filterBySatellitesCountIsOn"]),
|
||||
filter_by_satellite_count_value: nonNegativeField(["tripParams.filterBySatellitesCountValue"]),
|
||||
filter_emissions: nonNegativeField(["tripParams.filterEmissions"]),
|
||||
hardware_manufacturer_name: stringField(["hwManufacturer.name"]),
|
||||
hardware_port: nonNegativeField(["hwType.port"]),
|
||||
hardware_type_class: stringField(["hwType.type"]),
|
||||
hardware_type_name: stringField(["hwType.name"]),
|
||||
limit_acceleration: nonNegativeField(["tripParams.limitAcceleration"]),
|
||||
lost_connection_enabled: booleanField(["tripParams.lostConnectionIsOn"]),
|
||||
lost_connection_time_value: nonNegativeField(["tripParams.lostConnectionTimeValue"]),
|
||||
maximum_permissible_speed: nonNegativeField(["tripParams.maximumPermissibleSpeed"]),
|
||||
maximum_valid_height: numberField(["tripParams.maximumValidHeight"]),
|
||||
maximum_valid_speed: nonNegativeField(["tripParams.maximumValidSpeed"]),
|
||||
mileage_by_ignition: booleanField(["tripParams.mileageByIgnition"]),
|
||||
minimum_movement_speed: nonNegativeField(["tripParams.minimumMovementSpeed"]),
|
||||
minimum_movement_time: nonNegativeField(["tripParams.minimumMovementTime"]),
|
||||
minimum_parking_time: nonNegativeField(["tripParams.minimumParkingTime"]),
|
||||
minimum_stop_time: nonNegativeField(["tripParams.minimumTimeStop"]),
|
||||
minimum_trip_distance: nonNegativeField(["tripParams.minimumTripDistance"]),
|
||||
minimum_valid_height: numberField(["tripParams.minimumValidHeight"]),
|
||||
speed_parameter: stringField(["tripParams.speedParam"]),
|
||||
trip_detection_type: stringField(["tripParams.tripDetectionType.name"]),
|
||||
unit_type_class: stringField(["unitType.type"]),
|
||||
unit_type_name: stringField(["unitType.name"]),
|
||||
use_odometer: booleanField(["tripParams.useOdometer"]),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const positionsTemplate = value.l2Templates.find((template) => template.id === "gelios.positions.current.l2.v7");
|
||||
if (!positionsTemplate) throw new Error("gelios_v8_positions_template_missing");
|
||||
value.l2Templates.push({
|
||||
...structuredClone(positionsTemplate),
|
||||
id: TEMPLATE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
steps: [
|
||||
{ id: "collection.trigger", kind: "collection_trigger", collectionProfileDriven: true },
|
||||
{ id: "provider.fetch-units", kind: "provider_request", capabilityId: "gelios.units.current.read" },
|
||||
{ id: "provider.extract-units", kind: "extract_items", capabilityId: "gelios.units.current.read" },
|
||||
{ id: "ontology.map", kind: "semantic_mapping", mappingContractId: MAPPING_ID },
|
||||
{
|
||||
id: "data-product.publish",
|
||||
kind: "data_product_publish",
|
||||
dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID,
|
||||
nodeType: "n8n-nodes-ndc.ndcDataProductPublish",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const geliosProviderPackageV8 = deepFreeze(value);
|
||||
|
||||
function optional(type) {
|
||||
return { type, required: false };
|
||||
}
|
||||
|
||||
function nonNegative() {
|
||||
return { type: "number", required: false, minimum: 0 };
|
||||
}
|
||||
|
||||
function stringField(paths, omitIfMissing = true) {
|
||||
return {
|
||||
strategy: "first_non_empty",
|
||||
paths,
|
||||
coerce: "string",
|
||||
...(omitIfMissing ? { omitIfMissing: true } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function numberField(paths) {
|
||||
return { strategy: "first_non_empty", paths, coerce: "number", omitIfMissing: true };
|
||||
}
|
||||
|
||||
function nonNegativeField(paths) {
|
||||
return {
|
||||
strategy: "first_non_empty",
|
||||
paths,
|
||||
coerce: "number",
|
||||
minimum: 0,
|
||||
omitIfMissing: true,
|
||||
omitIfInvalid: true,
|
||||
};
|
||||
}
|
||||
|
||||
function booleanField(paths) {
|
||||
return { strategy: "first_non_empty", paths, coerce: "boolean", omitIfMissing: true };
|
||||
}
|
||||
|
||||
function deepFreeze(input) {
|
||||
if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
|
||||
Object.freeze(input);
|
||||
for (const child of Object.values(input)) deepFreeze(child);
|
||||
return input;
|
||||
}
|
||||
|
|
@ -1,8 +1,13 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { validateProviderCapabilityCatalog } from "../src/index.mjs";
|
||||
import { geliosCapabilityCatalogV1, geliosProviderPackageV7 } from "../providers/gelios/index.mjs";
|
||||
import {
|
||||
geliosCapabilityCatalogV1,
|
||||
geliosCapabilityCatalogV2,
|
||||
geliosProviderPackageV8,
|
||||
} from "../providers/gelios/index.mjs";
|
||||
|
||||
assert.deepEqual(validateProviderCapabilityCatalog(geliosCapabilityCatalogV1), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderCapabilityCatalog(geliosCapabilityCatalogV2), { ok: true, errors: [] });
|
||||
|
||||
const expectedUnitRoots = [
|
||||
"activatedAt", "availableToUsers", "blockTime", "commands", "counters", "createdAt",
|
||||
|
|
@ -20,10 +25,10 @@ const expectedIncludeFlags = [
|
|||
];
|
||||
assert.deepEqual(geliosCapabilityCatalogV1.queryFlags.map(({ id }) => id), expectedIncludeFlags);
|
||||
|
||||
const unitCapability = geliosProviderPackageV7.capabilities.find(({ id }) => id === "gelios.units.current.read");
|
||||
const unitCapability = geliosProviderPackageV8.capabilities.find(({ id }) => id === "gelios.units.current.read");
|
||||
assert.ok(unitCapability);
|
||||
for (const enabledFlag of Object.keys(unitCapability.request.query)) {
|
||||
assert.ok(expectedIncludeFlags.includes(enabledFlag), `v7 query flag is missing from the capability catalog: ${enabledFlag}`);
|
||||
assert.ok(expectedIncludeFlags.includes(enabledFlag), `provider query flag is missing from the capability catalog: ${enabledFlag}`);
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
|
|
@ -34,6 +39,21 @@ assert.equal(
|
|||
geliosCapabilityCatalogV1.capabilities.filter(({ classification }) => classification === "control").every(({ status }) => status === "disabled"),
|
||||
true,
|
||||
);
|
||||
assert.deepEqual(
|
||||
["gelios.unit.identity", "gelios.unit.equipment", "gelios.unit.trip_settings"].map((id) => {
|
||||
const family = geliosCapabilityCatalogV2.dataFamilies.find((item) => item.id === id);
|
||||
return { id, status: family.status, dataProductIds: family.dataProductIds };
|
||||
}),
|
||||
[
|
||||
{ id: "gelios.unit.identity", status: "implemented", dataProductIds: ["fleet.units.profile.current.v1"] },
|
||||
{ id: "gelios.unit.equipment", status: "implemented", dataProductIds: ["fleet.units.profile.current.v1"] },
|
||||
{ id: "gelios.unit.trip_settings", status: "implemented", dataProductIds: ["fleet.units.profile.current.v1"] },
|
||||
],
|
||||
);
|
||||
assert.equal(
|
||||
geliosCapabilityCatalogV2.dataFamilies.find(({ id }) => id === "gelios.unit.sensor_definitions").status,
|
||||
"planned",
|
||||
);
|
||||
|
||||
const restrictedPublish = structuredClone(geliosCapabilityCatalogV1);
|
||||
restrictedPublish.dataFamilies.find(({ id }) => id === "gelios.unit.device_identifiers").disposition = "publish";
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { geliosProviderPackageV4 } from "../providers/gelios/v4/index.mjs";
|
|||
import { geliosProviderPackageV5 } from "../providers/gelios/v5/index.mjs";
|
||||
import { geliosProviderPackageV6 } from "../providers/gelios/v6/index.mjs";
|
||||
import { geliosProviderPackageV7 } from "../providers/gelios/v7/index.mjs";
|
||||
import { geliosProviderPackageV8 } from "../providers/gelios/v8/index.mjs";
|
||||
import { normalizeDataProductDefinition } from "../../../services/external-data-plane/src/data-product-policy.mjs";
|
||||
|
||||
const expectedFields = [
|
||||
|
|
@ -45,6 +46,24 @@ assert.deepEqual(validateProviderPackage(geliosProviderPackageV4), { ok: true, e
|
|||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV5), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV6), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV7), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV8), { ok: true, errors: [] });
|
||||
|
||||
const profileProduct = geliosProviderPackageV8.dataProducts.find((product) => product.id === "fleet.units.profile.current.v1");
|
||||
const registeredProfileProduct = JSON.parse(await readFile(new URL(
|
||||
"../../../services/external-data-plane/definitions/fleet.units.profile.current.v1.json",
|
||||
import.meta.url,
|
||||
), "utf8"));
|
||||
assert.deepEqual(profileProduct, registeredProfileProduct);
|
||||
assert.deepEqual(profileProduct.semanticTypes, ["map.moving_object"]);
|
||||
assert.equal(profileProduct.history.mode, "none");
|
||||
const profileCollection = geliosProviderPackageV8.collectionProfiles.find((profile) => profile.id === "gelios.units.profile.cold.v1");
|
||||
assert.equal(profileCollection.schedule.intervalMs, 6 * 60 * 60 * 1000);
|
||||
assert.deepEqual(profileCollection.capabilityIds, ["gelios.units.current.read"]);
|
||||
const profileMapping = geliosProviderPackageV8.mappingContracts.find((mapping) => mapping.id === "gelios.units.to.fleet.units.profile.current.v1");
|
||||
assert.equal(profileMapping.fact.sourceId.prefix, "gelios-unit-");
|
||||
assert.equal(profileMapping.fact.attributes.hardware_type_name.paths[0], "hwType.name");
|
||||
assert.equal(profileMapping.fact.attributes.trip_detection_type.paths[0], "tripParams.tripDetectionType.name");
|
||||
assert.equal(profileMapping.fact.attributes.use_odometer.coerce, "boolean");
|
||||
|
||||
const telemetryProduct = geliosProviderPackageV7.dataProducts.find((product) => product.id === "fleet.positions.current.v5");
|
||||
const registeredTelemetryProduct = JSON.parse(await readFile(new URL(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"id": "fleet.units.profile.current.v1",
|
||||
"version": "1.0.0",
|
||||
"ontologyRevision": "ontology.map.moving_object.v3",
|
||||
"deliveryMode": "snapshot+patch",
|
||||
"semanticTypes": [
|
||||
"map.moving_object"
|
||||
],
|
||||
"fields": [
|
||||
"corrected_engine_hours_factor",
|
||||
"corrected_mileage_factor",
|
||||
"display_name",
|
||||
"filter_by_satellite_count_enabled",
|
||||
"filter_by_satellite_count_value",
|
||||
"filter_emissions",
|
||||
"hardware_manufacturer_name",
|
||||
"hardware_port",
|
||||
"hardware_type_class",
|
||||
"hardware_type_name",
|
||||
"limit_acceleration",
|
||||
"lost_connection_enabled",
|
||||
"lost_connection_time_value",
|
||||
"maximum_permissible_speed",
|
||||
"maximum_valid_height",
|
||||
"maximum_valid_speed",
|
||||
"mileage_by_ignition",
|
||||
"minimum_movement_speed",
|
||||
"minimum_movement_time",
|
||||
"minimum_parking_time",
|
||||
"minimum_stop_time",
|
||||
"minimum_trip_distance",
|
||||
"minimum_valid_height",
|
||||
"speed_parameter",
|
||||
"trip_detection_type",
|
||||
"unit_type_class",
|
||||
"unit_type_name",
|
||||
"use_odometer"
|
||||
],
|
||||
"fieldContracts": {
|
||||
"corrected_engine_hours_factor": { "type": "number", "required": false },
|
||||
"corrected_mileage_factor": { "type": "number", "required": false },
|
||||
"display_name": { "type": "string", "required": true },
|
||||
"filter_by_satellite_count_enabled": { "type": "boolean", "required": false },
|
||||
"filter_by_satellite_count_value": { "type": "number", "required": false, "minimum": 0 },
|
||||
"filter_emissions": { "type": "number", "required": false, "minimum": 0 },
|
||||
"hardware_manufacturer_name": { "type": "string", "required": false },
|
||||
"hardware_port": { "type": "number", "required": false, "minimum": 0 },
|
||||
"hardware_type_class": { "type": "string", "required": false },
|
||||
"hardware_type_name": { "type": "string", "required": false },
|
||||
"limit_acceleration": { "type": "number", "required": false, "minimum": 0 },
|
||||
"lost_connection_enabled": { "type": "boolean", "required": false },
|
||||
"lost_connection_time_value": { "type": "number", "required": false, "minimum": 0 },
|
||||
"maximum_permissible_speed": { "type": "number", "required": false, "minimum": 0 },
|
||||
"maximum_valid_height": { "type": "number", "required": false },
|
||||
"maximum_valid_speed": { "type": "number", "required": false, "minimum": 0 },
|
||||
"mileage_by_ignition": { "type": "boolean", "required": false },
|
||||
"minimum_movement_speed": { "type": "number", "required": false, "minimum": 0 },
|
||||
"minimum_movement_time": { "type": "number", "required": false, "minimum": 0 },
|
||||
"minimum_parking_time": { "type": "number", "required": false, "minimum": 0 },
|
||||
"minimum_stop_time": { "type": "number", "required": false, "minimum": 0 },
|
||||
"minimum_trip_distance": { "type": "number", "required": false, "minimum": 0 },
|
||||
"minimum_valid_height": { "type": "number", "required": false },
|
||||
"speed_parameter": { "type": "string", "required": false },
|
||||
"trip_detection_type": { "type": "string", "required": false },
|
||||
"unit_type_class": { "type": "string", "required": false },
|
||||
"unit_type_name": { "type": "string", "required": false },
|
||||
"use_odometer": { "type": "boolean", "required": false }
|
||||
},
|
||||
"history": {
|
||||
"mode": "none",
|
||||
"retentionDays": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ assert.deepEqual(bundled.map((definition) => definition.id), [
|
|||
"fleet.positions.current.v3",
|
||||
"fleet.positions.current.v4",
|
||||
"fleet.positions.current.v5",
|
||||
"fleet.units.profile.current.v1",
|
||||
"map.zones.current.v1",
|
||||
"map.zones.current.v2",
|
||||
]);
|
||||
|
|
@ -52,19 +53,25 @@ assert.equal(bundled[4].version, "5.0.0");
|
|||
assert.equal(bundled[4].ontologyRevision, "ontology.map.moving_object.v3");
|
||||
assert.equal(bundled[4].fieldContracts.sensor_readings.type, "telemetry_readings");
|
||||
assert.equal(bundled[5].version, "1.0.0");
|
||||
assert.equal(bundled[5].ontologyRevision, "ontology.map.zone.v1");
|
||||
assert.deepEqual(bundled[5].semanticTypes, ["map.zone"]);
|
||||
assert.deepEqual(bundled[5].fieldContracts.geometry, { type: "geometry", required: true });
|
||||
assert.equal(bundled[5].fields.includes("dataset_authority"), false);
|
||||
assert.equal(bundled[6].version, "2.0.0");
|
||||
assert.equal(bundled[5].ontologyRevision, "ontology.map.moving_object.v3");
|
||||
assert.deepEqual(bundled[5].semanticTypes, ["map.moving_object"]);
|
||||
assert.equal(bundled[5].history.mode, "none");
|
||||
assert.equal(bundled[5].fieldContracts.hardware_port.type, "number");
|
||||
assert.equal(bundled[6].version, "1.0.0");
|
||||
assert.equal(bundled[6].ontologyRevision, "ontology.map.zone.v1");
|
||||
assert.deepEqual(bundled[6].semanticTypes, ["map.zone"]);
|
||||
assert.deepEqual(bundled[6].fieldContracts.geometry, { type: "geometry", required: true });
|
||||
assert.deepEqual(bundled[6].fieldContracts.dataset_authority.enum, ["moscow-department-of-transport"]);
|
||||
assert.equal(bundled[6].fields.includes("dataset_authority"), false);
|
||||
assert.equal(bundled[7].version, "2.0.0");
|
||||
assert.equal(bundled[7].ontologyRevision, "ontology.map.zone.v1");
|
||||
assert.deepEqual(bundled[7].semanticTypes, ["map.zone"]);
|
||||
assert.deepEqual(bundled[7].fieldContracts.geometry, { type: "geometry", required: true });
|
||||
assert.deepEqual(bundled[7].fieldContracts.dataset_authority.enum, ["moscow-department-of-transport"]);
|
||||
assert.equal(Object.keys(bundled[3].fieldContracts).length, bundled[3].fields.length);
|
||||
assert.equal(Object.keys(bundled[4].fieldContracts).length, bundled[4].fields.length);
|
||||
assert.equal(Object.keys(bundled[5].fieldContracts).length, bundled[5].fields.length);
|
||||
assert.equal(Object.keys(bundled[6].fieldContracts).length, bundled[6].fields.length);
|
||||
assert.equal(Object.keys(bundled[7].fieldContracts).length, bundled[7].fields.length);
|
||||
|
||||
const directory = await mkdtemp(join(tmpdir(), "nodedc-edp-definitions-"));
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue