279 lines
9.9 KiB
JavaScript
279 lines
9.9 KiB
JavaScript
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;
|
|
}
|