/**
* @namespace Entities
* @category Entities
* @module PositionEntity
* @rules No framework-related imports
* */
import {
formatDatetime,
formatTimeWithSeconds,
datetimeToTimestamp,
} from '@/utils/dates.js'
import { getFormattedAddress } from '@/utils/address'
import { getNestedValue } from '@/utils/object.js'
import { generateShortId } from '@/utils/crypto.js'
/**
* Normalize APIV2, APIV3, and inject computed properties.
*
* Used by Diagnostic module
*
* @example
*
* Output:
* {
* vehicleRegistrationPlate:""
* }
*
* @param {*} rawData
* @param {Boolean} options.reduced Reduced version for big lists
* @returns {Object} Normalized entity
*
*/
function normalizeEntity(rawData, options = {}) {
let normalizedData = {}
//normalize apiv2/apiv3 keys
let convertionTables = [getAPIV2ConvertionTable(), getAPIV3ConvertionTable()]
convertionTables.forEach((table) => {
Object.keys(table).forEach((key) => {
if (rawData[key] !== undefined) {
normalizedData[table[key]] = rawData[key]
}
})
})
//add addressFields if necessary
if (rawData.mapMatch) {
normalizedData['streetNumber'] = rawData.mapMatch.streetNumber
normalizedData['street'] = rawData.mapMatch.street
normalizedData['zipCode'] = rawData.mapMatch.zipCode
normalizedData['city'] = rawData.mapMatch.city
normalizedData['county'] = rawData.mapMatch.county
}
//add computed fields
let computedFields = getComputedFields()
Object.keys(computedFields).forEach((key) => {
if (typeof computedFields[key] === 'function') {
normalizedData[key] = computedFields[key](
normalizedData,
rawData,
options
)
}
})
normalizedData.id = normalizedData.id || generateShortId()
/*console.log("position::normalizeEntity", {
rawData,
normalizedData,
});*/
return Object.freeze(normalizedData)
}
/**
* Normalizes tor/ana from APIV2/AVPI3 response
* @param {String} sensorName i.g TOR/ANA
* @returns Function
*/
function normalizeSensorItemMapHandler(sensorName) {
const sensorAttributes = {
v2: {
name: 'nom',
number: 'num',
state: 'val',
value: 'value',
},
v3: {
name: 'name',
number: 'number',
state: 'state',
value: 'value',
},
}
function isSensorV2Item(sensor) {
return sensor.num !== undefined
}
return (sensor) => {
let attr = isSensorV2Item(sensor)
? sensorAttributes.v2
: sensorAttributes.v3
if (sensorName === 'TOR') {
return {
n: sensor[attr.number],
name: sensor[attr.name]
? sensor[attr.name]
: `${sensorName}${sensor[attr.number] || '?'}`,
enabled: sensor[attr.state] === 1,
}
}
if (sensorName === 'ANA') {
return {
n: sensor[attr.number],
name: sensor[attr.name]
? sensor[attr.name]
: `${sensorName}${sensor[attr.number] || '?'}`,
value: sensor[attr.value],
}
}
return {
...sensor,
}
}
}
function getComputedFields() {
return {
vehicleId: (normalizedData, rawData, options) =>
normalizedData.vehicleId || options.vehicleId,
datetimeFormatted: (normalizedData, rawData, options) =>
formatDatetime(normalizedData.datetime, {
inputFormat: options.datetimeInputFormat,
}),
timeFormatted: (normalizedData) =>
formatTimeWithSeconds(normalizedData.datetime),
addressFormatted: (normalizedData, rawData) =>
getFormattedAddress(normalizedData),
timestamp: (normalizedData, rawData, options) =>
datetimeToTimestamp(normalizedData.datetime, options.datetimeInputFormat),
speedFormatted: (normalizedData) => `${normalizedData.speed} Km/h`,
sensorTor: (normalizedData, rawData) =>
getNestedValue(rawData, 'tor', [])
.filter((tor) => tor.etat !== null)
.map(normalizeSensorItemMapHandler('TOR')),
sensorAna: (normalizedData, rawData) =>
getNestedValue(rawData, 'ana', [])
.filter((ana) => ana.etat !== null)
.map(normalizeSensorItemMapHandler('ANA')),
sensorCanCruise: (normalizedData, rawData) =>
getNestedValue(rawData, ['can_cruise', 'can.chronoCruiseControl'], null),
sensorCanBrakePedal: (normalizedData, rawData) =>
getNestedValue(rawData, ['can.brakePedal'], null),
sensorCanRPM: (normalizedData, rawData) =>
getNestedValue(rawData, ['can_vrm', 'can.vrm'], null),
sensorCanFuelPerc: (normalizedData, rawData) =>
getNestedValue(rawData, ['can_fuel'], null),
sensorCanFuelLiters: (normalizedData, rawData) =>
getNestedValue(rawData, ['can.fuelLevelLiters'], null),
sensorCanConsumptionLiters: (normalizedData, rawData) =>
getNestedValue(rawData, ['can_conso', 'can.consumption'], null),
sensorCanThrottle: (normalizedData, rawData) =>
getNestedValue(rawData, ['can_accelerateur', 'can.accelerator'], null),
vehicleDistance: (normalizedData, rawData) =>
getNestedValue(rawData, ['can.vehicleDistance'], null),
canServiceDistanceMeters: (normalizedData, rawData) =>
getNestedValue(rawData, ['can.serviceDistance'], null),
sensorCanBatteryPerc: (normalizedData, rawData) =>
getNestedValue(rawData, ['can.battery'], null),
speHarshBraking: (normalizeEntity, rawData) =>
getNestedValue(rawData, ['harsh_braking', 'spe.harshBraking'], null),
speHarshAcceleration: (normalizeEntity, rawData) =>
getNestedValue(
rawData,
['harsh_acceleration', 'spe.harshAcceleration'],
null
),
speHarshCornering: (normalizeEntity, rawData) =>
getNestedValue(rawData, ['harsh_cornering', 'spe.harshCornering'], null),
speExcessiveSpeed: (normalizeEntity, rawData) =>
getNestedValue(
rawData,
['vitesse_excessive', 'spe.excessiveSpeed'],
null
),
}
}
function getAPIV3ConvertionTable() {
return {
id: 'id',
latitude: 'lat',
longitude: 'lng',
datetime: 'datetime',
vehicleId: 'vehicleId',
speed: 'speed',
boxNumber: 'boxNumber',
distance: 'distanceMeters',
hasContactOn: 'hasContactOn',
receptionDatetime: 'receptionDatetime',
}
}
/**
* Transform positions from both /historique/positions and /historique/positions_capteurs
* @returns
*/
function getAPIV2ConvertionTable() {
return {
code: 'code', //position_capteurs items have code (TOR1,POS,etc)
code_capteurs: 'code_capteurs', //used by map cmp to render/filter sensors positions.
vehicule_id: 'vehicleId',
client_id: 'clientId',
//categorie_vehicule_id: "vehicleCategoryId",
//client_nom: "clientName",
vehicule_nom: 'vehicleName',
vehicule_immatriculation: 'vehicleRegistrationPlate',
//categorie_vehicule_nom: "vehicleCategoryName",
latitude: 'lat',
longitude: 'lng',
lon: 'lng',
lat: 'lat',
dateheure: 'datetime',
flag_contact: 'hasContactOn',
//qualitegps: "gpsQuality",
vitesse: 'speed',
//altitude: "altitude",
//dateheure_reception: "receptionDatetime",
//calculposition: "calculposition",
//etatelec: 'etatelec',
//flag_demarage: "flag_demarage",
//distance_m: "distance_m",
//troncon: "troncon",
//flag: "flag",
//capteurs: "capteurs",
//tor1: 'tor1',
//tor2: 'tor2',
//tor3: 'tor3',
//tor4: 'tor4',
//tor5: 'tor5',
//tor6: 'tor6',
//tor7: 'tor7',
//tor8: 'tor8',
//ana1: 'ana1',
//ana2: 'ana2',
//ana3: 'ana3',
//analog_input_1: 'analog_input_1',
//digital_output_1: 'digital_output_1',
can_conso: 'canConsumption',
//can_vrm: "canVRM",
can_accelerateur: 'canAccelerator',
can_cruise: 'sensorCanCruise',
//can_fuel: "canFuel",
//longitude_mapmatch: "longitude_mapmatch",
//latitude_mapmatch: "latitude_mapmatch",
numero_rue: 'streetNumber',
rue: 'streetName',
code_route: 'code_route',
codepostal: 'zipCode',
ville: 'city',
//departement: "departement",
//region: "region",
//pays: "pays",
}
}
export default normalizeEntity
export function normalizePositionV2(data) {
return {
id: data.id,
lat: getNestedValue(data, ['lat']),
lon: getNestedValue(data, ['lon']),
couleur: getNestedValue(data, ['couleur', 'color']),
code: getNestedValue(data, ['code']),
code_capteurs: getNestedValue(data, ['tor', 'code_capteurs']),
dateheure80: getNestedValue(data, ['dateheure80', 't80']),
dateheure: getNestedValue(data, ['dateheure', 'dt']),
flag_contact: getNestedValue(data, ['flag_contact', 'contact']),
qualite_gps: getNestedValue(data, ['qualite_gps', 'quality']),
vitesse: getNestedValue(data, ['vitesse', 'speed']),
}
}
Source