Hoppa till huvudinnehåll

Translator API

Referens för IoT-plattformens Translator Service - objektschemat, kontraktet för translate-funktionen, och hur översättare väljs ut och körs. Detta är en referens; för en steg-för-steg-guide med genomarbetade exempel och en lokal test- rigg, se Utveckla översättare.

API-ändpunkter finns dokumenterade i Swagger.

Körmiljö​

Översättare körs i en sandlådad JavaScript-miljö (isolerad V8). Alla standard-JavaScript-inbyggda funktioner är tillgängliga (Date, Math, JSON, …), plus lodash som _, Buffer som Buffer, och console.log. Sandlådan tillhandahåller inte require/import, timers, eller nätverks-/filsystemsåtkomst. En översättare interagerar med plattformen enbart genom värdet den returnerar från translate.

Översättarobjektet​

En översättare är ett JSON-objekt med följande fält:

FältObligatorisktBeskrivning
namejaUnikt namn. Gemener, siffror och bindestreck, måste börja med en bokstav (/^[a-z][a-z0-9-]+$/).
versionjaSemver Major.Minor.Patch.
apiVersionjaDen API-version av översättartjänsten som översättaren riktar sig mot (nuvarande: 1.0).
descriptionjaAnvändarvänd Markdown-beskrivning (visas i IoT-plattformen).
matchjaVilka enheter den gäller för - ett objekt med deviceModelName (sträng).
specjaDe fält översättaren får skicka ut (se spec). Sätt spec: false för att inaktivera validering.
parametersnejAnvändarangivna indata (se parameters).
codejaEn sträng med JavaScript som definierar en translate-funktion (se code).

regex tas emot och lagras, men enhetsmatchningen är i dagsläget en exakt jämförelse av match.deviceModelName mot enhetens modellnamn. Sätt deviceModelName till det exakta namnet i stället för ett mönster.

spec​

spec deklarerar varje fält translate får skicka ut; sandlådan avvisar varje utskickad nyckel som inte finns i spec. Varje post är en av:

  • En ren typsträng - en av 'string', 'number', 'boolean', 'date', 'object', 'array'. Används för identifierare, booleaner och opaka värden:
    spec: { serialNumber: 'string', tamperAlarm: 'boolean' }
  • En mätvärdesbeskrivning - {type, unit, quantity}, där unit är en SI- symbol (eller '' för dimensionslös) och quantity är den semantiska gruppen:
    spec: { temperature: {type: 'number', unit: '°C', quantity: 'temperature'} }

Fältnamn, enheter och kvantiteter definieras av den kanoniska fältkatalogen (IoT-plattformens datamodell) - se Datamodell för de vanliga fälten och namnreglerna.

parameters​

parameters deklarerar värden som användaren anger när översättaren väljs. De valideras mot schemat och skickas som andra argument till translate.

parameters: {
// primitive
someNumber: 'number',
someBoolean: 'boolean',
someString: 'string',

// constrained
constrainedNumber: {type: 'number', min: 10, max: 30},
choice: {type: 'enum', values: ['apple', 'pear']},

// optional / default (both make the parameter optional to the user)
offset: {type: 'number', optional: true},
timeZone: {type: 'string', default: 'Europe/Stockholm'},
}

code​

code är en sträng med JavaScript som definierar en funktion med namnet translate (plus eventuella hjälpfunktioner den anropar - hjälpfunktioner måste finnas i samma code-sträng, eftersom hela strängen är det som körs i sandlådan).

Datamodell (fältkatalog)​

IoT-plattformen platttar ut varje enhet till en nod med hjälp av ett delat vokabulär av kanoniska fältnamn - fältkatalogen. Ett fälts betydelse ligger helt i dess namn, enhet och kvantitet, så översättare för olika tillverkare måste skicka ut samma fält för samma mätning. Mappa tillverkarens råa namn till kanoniska fält i både spec och det returnerade result.

Regler:

  • lowerCamelCase, platta NGSI-LD-namn - ingen snake_case, ingen tillverkarjargong (TempC_SHT, BatV) i utdatan.
  • SI-enheter (°C, %, Pa, V, A, W, kWh, m, m/s); dimensionslösa värden använder enheten '' med en camelCase-quantity. Konvertera i översättaren (t.ex. hPa → Pa är × 100, mV → V är / 1000).
  • Temperatur bär sitt medium i namnet: temperature = luft/omgivning; waterTemperature, soilTemperature, surfaceTemperature; externalTemperature/2/3 = sond med ospecificerat medium; internalTemperature/cpuTemperature = enhetens elektronik.
  • Indexerade kanaler: det rena namnet är det primära, extra kanaler börjar på 2 (temperature, temperature2; en …1-form är ett äldre alias).

Vanliga fält​

FältEnhetKvantitet
temperature°Ctemperature
internalTemperature°Ctemperature
externalTemperature°Ctemperature
waterTemperature°Ctemperature
soilTemperature°Ctemperature
relativeHumidity%relativeHumidity
pressurePapressure
co2ppmco2
tvocppbtvoc
pm2_5ug/m^3pm2_5
pm10ug/m^3pm10
illuminancelxilluminance
windSpeedm/svelocity
precipitationmmprecipitation
distancemlength
waterLevelmlength
soilMoisture%soilMoisture
batteryLevel%fill
batteryVoltageVvoltage
current1Acurrent
voltageL1NVvoltage
activeEnergyImportkWhenergy
motion''count
lnglat- (typ geoJsonPoint)GNSS-position

Booleska fält / statusfält använder en ren typ: batteryLow, presence, digital, relayState ('boolean'); contact, occupied (litet enum, 'number'). Larm- fält är subjekt-först-booleaner med ett *Alarm-suffix (temperatureLowAlarm, tamperAlarm), quantity: 'alarm'.

Innan du hittar på ett namn, kontrollera de vanliga fälten ovan (eller GET /api/translators) efter ett befintligt.

Harmoniseringsexempel​

En översättares uppgift är att döpa om tillverkarens råa utdata till kanoniska fält.

När du omsluter en tillverkares referensdekoder, behåll dekodern oförändrad och utför harmoniseringen som det sista steget - mappa dess råa utdata till kanoniska fält i det returnerade result, och skala enheter korrekt (t.ex. hPa → Pa, mV → V, cm → m). Ändra inte tillverkardekoderns interna logik.

Dragino LHT65

RåttKanoniskt
TempC_SHT (inbyggd)internalTemperature
TempC_DS (extern sond)temperature
Hum_SHTrelativeHumidity
BatVbatteryVoltage

Milesight AM319 (observera enhetsfixet)

RåttKanoniskt
temperaturetemperature
humidityrelativeHumidity
batterybatteryLevel
co2co2
pressure (hPa)pressure (Pa, × 100)

Eftersom båda skickar ut relativeHumidity (%, relativeHumidity), betyder samma värde samma sak oavsett tillverkare - och samma nedströms-översättare och vyer fungerar för alla enheter.

translate-funktionen​

translate körs varje gång ny data anländer för enhetens IoTNode. Signatur:

function translate (iotnode, parameters) { /* ... */ }
  • iotnode - noden som översätts. En översättare kan läsa vilket fält som helst på den. Råa upplänkspayloads för en hårdvarudekoder finns under iotnode.encodedData ({hexEncoded, port}); tidpunkten för mottagen payload är iotnode.reportedAt. Föredra reportedAt framför Date.now() för observations-/händelsetider - Date.now()/new Date() fungerar, men klockan visar bearbetningstiden och är icke-deterministisk (det bryter reproducerbarheten om en översättning körs igen). När översättare kedjas, bär iotnode också de fält som producerats av tidigare översättare.
  • parameters - det validerade parameters-objektet (eller {}).

translate måste returnera ett objekt eller throw ett Error. Objektet kan vara tomt ({}) när ingenting kunde översättas. Kända returfält - returnera valfritt antal, alla eller inga:

ReturfältBetydelse
resultUppdaterade värden för iotnoden. Endast nycklar deklarerade i spec är tillåtna; undefined- och NaN-värden tas bort (null gör det inte - se nedan).
timeseriesEn array av {timestamp, value} - timestamp ett JS-Date-objekt, value följer samma regler som result.
additionalDeviceUpdatesUppdateringar för andra enheter (gateways) - se nedan.

Eftersom plattformen tar bort undefined och NaN från result, kan en översättare skicka ut ett fält villkorligt och returnera det vanliga objektet utan att själv rensa bort det.

null är undantaget, och inget ofarligt sådant. Ett null behålls i stället för att tas bort, och faller sedan på den deklarerade typen i spec, vilket avvisar hela översättningen i stället för bara det fältet. En leverantörsdekoder som returnerar null för en utebliven avläsning måste därför städas innan resultatet returneras - utelämna nyckeln, eller sätt den till undefined.

Fel och loggning​

När en översättare kastar ett fel registrerar IoT-plattformen felet i enhetens Loggar och behåller det i 6 timmar - filtrera Type = Debug, Category = System för att hitta det. En lyckad översättning loggar ingenting, så en tom logg innebär att översättaren antingen kördes felfritt eller aldrig utlöstes (kontrollera enhetens Last reported-tid för att avgöra vilket).

Obs: bara den första översättaren i en kedja rapporterar ett kastat fel på det här sättet. Om en senare översättare kastar ett fel behåller plattformen resultatet som producerats hittills och skriver ingen loggpost, så en tom logg bevisar inte i sig att en kedjad översättare lyckades.

Minimalt exempel​

function translate (iotnode) {
return {result: {temperature: 21.4, batteryVoltage: 3.01}};
}

const translator = {
name: 'examplecorp-demodevice9000',
version: '1.0.0',
apiVersion: '1.0',
description: 'A translator for ExampleCorp DemoDevice 9000.',
match: {deviceModelName: 'examplecorp-demodevice9000'},
spec: {
temperature: {type: 'number', unit: '°C', quantity: 'temperature'},
batteryVoltage: {type: 'number', unit: 'V', quantity: 'voltage'},
},
code: translate.toString(),
};

Tidsserieexempel​

return {
timeseries: [
{timestamp: new Date('2021-11-12T14:30:00Z'), value: {temperature: 12}},
{timestamp: new Date('2021-11-12T14:15:00Z'), value: {temperature: 11}},
],
};

Välja översättare​

Vilka översättare som körs för en enhet bestäms av enhetens translatorPreferences (kan sättas vid enhetens skapande eller uppdatering):

translatorPreferences: [
{name: 'sensative-strips', userId: '…', version: '1.0.0', upgradePolicy: 'minor'},
{name: 'celsius-to-fahrenheit', userId: '…', version: '1.2.0', upgradePolicy: 'all'},
]

version + upgradePolicy avgör vilken version som körs:

upgradePolicyBeteende (vald 1.0.0)
nonealltid den valda versionen
patchsenaste 1.0.x
minorsenaste 1.x
allsenaste tillgängliga

Använd GET /api/translators (valfritt ?deviceModelName=…) för att lista översättare som passar en enhet och fylla translatorPreferences. När en enhet skapas med ett deviceModelName, fyller IoT-plattformen automatiskt i en lämplig standard- översättare.

Om en översättare skapad av Sensative matchar, föredras den framför andra.

Kedjning (flera översättare)​

Översättare körs sekventiellt; varje mottar de föregående resultaten sammanslagna med den ursprungliga iotnoden:

result = A(x) + B(x + A(x))

där A, B är översättare, x är den ursprungliga iotnoden, och + är en sammanslagning. En översättare läser alltså fälten som producerats av tidigare översättare. Om en översättare kastar ett fel stannar kedjan och senare översättare körs inte.

Gateways​

En översättare på en gateway (eller gatewayliknande enhet) kan uppdatera andra enheter via additionalDeviceUpdates - en array av {identifier, result}:

  • identifier - ett objekt som identifierar målenheten, t.ex. {devEui: '123456789012345'} eller {wMbusDeviceId: '12312312', manufacturer: 'BMT'}.
  • result - uppdateringarna för den enheten (samma regler som result).

Enheten kan också uppdatera sig själv i samma svar via result.

return {
result: {internalTemperature: 13},
additionalDeviceUpdates: [
{identifier: {devEui: '123456789012345'}, result: {temperature: 11}},
],
};

Versionshantering​

Versioner är semver Major.Minor.Patch. Vid uppdatering används den version som väljs av varje enhets upgradePolicy (med översättare skapade av Sensative föredragna). Du måste höja huvudversionen (major) varje gång datamodellen ändras - ett fält läggs till, byter namn eller tas bort, eller dess värdesemantik (enhet, skalning, betydelse) ändras. Ändringar som bara rör metadata eller buggfixar med samma utdata behöver inte en huvudversionshöjning.

Ägarskap och radering​

En uppladdad översättare ägs permanent av den som laddade upp den (userId). Användare kan inte radera översättare - för att inte förstöra för andra användare som är beroende av dem. En plattformsadministratör kan radera en endast under extraordinära omständigheter (t.ex. skadlig kod).

API-versioner​

apiVersion 1.0 är den nuvarande API:et för översättartjänsten och grunden för framtida versioner.


Se Utveckla översättare för datamodellens regler och genomarbetade mallar (hårdvara, calculate, set-alarm, analys), samt verktygen för att testa och skicka en översättare utan någon av IoT-plattformens infrastruktur:

  • translator-harness.js - kör din translate- funktion lokalt mot testpayloads (återskapar sandlådan med Nodes vm; kräver bara npm install lodash).
  • translator-build.js - paketera din funktion + metadata till den translator.json som ska POST-as till API:et.