How to create a custom mobile app with Habit Analytics

Before starting any coding, please access to our Selfcare to setup your project and get all the needed information to setup on your Custom mobile app.

Authentication

In order to interact with the our API, clients must authenticate using the OAuth 2.0 protocol, in particular the Resource Owner Password Credentials flow.

Account creation with mail (without mail validation)

A POST call must be made using the /v3/legacy/account endpoint, providing the following parameters:

  • appId, corresponding to the pre-generated client_id that you should get from your previous created project on Selfcare

  • device, indicating if is and 'android' or 'ios'

  • email, indicating your user's mail

  • name, indicating your user's name

  • password, indicating your user's password

  • type, should always be 'account'

The response will be populated with several attributes, mainly authToken and id (that corresponds to the user-id).

Call POST /v3/legacy/account

  • Request (application/json)

{
"appId":"{application-namespace}",
"device":"{android|ios}",
"email":"{user-mail}",
"name":"{user-name}",
"password":"{password}",
"type":"account"
}
  • Response 200 (application/json)

{
"message":"user created and signed in",
"success":true,
"user":{
"authToken":"{token}",
"clientId":"{mobile-application-client-id}",
"email":"{user-mail}",
"id":"{user-id}",
"name":"{user-name}",
"newUser":true,
"photoUrl":"https:\/\/cdn.muzzley.com\/users\/default.png",
"token":"{access-token}"
}
}

A GET call to /v3/auth/authorize should be immediately done to obtain all the other needed authentication information.

The response will be populated with, at least, 4 main attributes:

  • access_token, the actual token to be used in subsequent calls

  • expires, the validity of the returned tokens

  • refresh_token, for refreshing this information, before expires is reached

  • endpoints, an object containing the HTTP and MQTT base URLs assigned to the requesting client

Call GET /v3/auth/authorize

  • Request parameters:

    • response_type **should be password (required, string)

    • scope should be application,user (required, string)

    • client_id is your application client-id generated by Selfcare (required, string)

    • username (required, string)

    • password (required, string)

  • Response 200 (application/json)

{
"_id":"\/v3\/tokens\/{token}",
"access_token":"{token}",
"client_id":"{client-id}",
"code":"{code}",
"created":"2020-03-17T15:52:52.484+0000",
"endpoints":
{
"http":"https:\/\/api.platform.muzzley.com",
"mqtt":"mqtts:\/\/api.platform.muzzley.com:8881",
"uploader":"https:\/\/assets.ci.habit.io"
},
"expires":"2020-06-15T15:52:51.618+0000",
"grant_type":"password",
"href":"\/v3\/tokens\/{token}",
"id":"{id}",
"owner_id":"{user-id}",
"refresh_token":"{refresh-token}",
"scope":["application","user"],
"updated":"2020-03-17T15:52:52.484+0000"
}

For this first 2 calls the host to be used should be https://api.platform.muzzley.com/ but all subsequent calls must be directed to the base URL provided in endpoints.http and an Authorization header must be added to every API call, in the form:

Authorization: Bearer {access_token}

Account Sign in with mail

The response will be populated with, at least, 4 main attributes:

  • access_token, the actual token to be used in subsequent calls

  • expires, the validity of the returned tokens

  • refresh_token, for refreshing this information, before expires is reached

  • endpoints, an object containing the HTTP and MQTT base URLs assigned to the requesting client

Call GET /v3/auth/authorize

  • Request parameters:

    • client_id (required, string)

    • refresh_token (required, string)

    • grant_type (required, string)

    • redirect_uri (optional, string)

  • Response 200 (application/json)

{
"_id":"\/v3\/users\/{user-id}",
"_rev":"3-94c1450541b80ec43c7503d7b2ec8e6c",
"active_ts":"2019-05-24T09:58:16.824+0000",
"cdata":null,
"confirmation_hash":"qweqweqwe",
"created":"2019-05-24T09:58:15.841+0000",
"email":"{user-mail}",
"href":"\/v3\/users\/{user-id}",
"id":"{user-id}",
"inactive_ts":"1970-01-01T00:00:00.000+0000",
"name":"{user-name}",
"namespace":"qweqweqwe",
"secret":"qweqweqwe",
"state":"active",
"target_id":"{applciation-client-id}",
"type":"users",
"updated":"2019-05-24T09:58:16.825+0000"
}

API Usage

For this first call the host to be used should be https://api.platform.muzzley.com/ but all subsequent calls must be directed to the base URL provided in endpoints.http and an Authorization header must be added to every API call, in the form:

Authorization: Bearer {access_token}

Retrieve User

The response will be populated with, at least, 4 main attributes:

  • id, the user ID

  • name, the user full name

  • namespace, unique user namespace

  • state, state of the user in the platform

  • target_id, application ID that the user belongs

Call GET /v3/users/[me|:user-id]

  • Response 200 (application/json)

{
"_id":"\/v3\/users\/{user-id}",
"_rev":"3-94c1450541b80ec43c7503d7b2ec8e6c",
"active_ts":"2019-05-24T09:58:16.824+0000",
"cdata":null,
"confirmation_hash":"qweqweqwe",
"created":"2019-05-24T09:58:15.841+0000",
"email":"{user-mail}",
"href":"\/v3\/users\/{user-id}",
"id":"{user-id}",
"inactive_ts":"1970-01-01T00:00:00.000+0000",
"name":"{user-name}",
"namespace":"qweqweqwe",
"secret":"qweqweqwe",
"state":"active",
"target_id":"{application-id}",
"type":"users",
"updated":"2019-05-24T09:58:16.825+0000"
}

List User Channels

Channel Instance Ontology:

  • profileId : Profile id of the database document.

  • channelId : Channel instance id.

  • component : An array of the parts that make up the actual channel instance.

  • id : Component id such as "bulb-3"

  • type : Component type (described in the channel spec).

  • label : Channel component label such as "Nightstand Left".

  • property : An array of properties listed in the channel spec.

Call GET /v3/legacy/users/{user-id}/channels

  • Request parameters:

    • include (optional, string) # ex: channelProperties,context,capabilities

  • Response 200 (application/json)

{
"_id":"\/v3\/legacy\/users\/{user-id}\/channels",
"_rev":"9-3d8b450212eafb9a9e02e192349b6a8b",
"channels":[
{
"_rev":"3-66beebb3261617dee4d80a789563bbd2",
"categories":[
"5478934836f3f24465ca061d"
],
"components":[
{
"classes":[
"com.muzzley.components.sensor.smoke"
],
"id":"smoke_sensor",
"label":"Smoke Detector",
"type":"smoke_sensor"
}
],
"content":"Device",
"id":"9fc96b08-c654-11e8-8567-000d3a38a46d",
"interface":{
"etag":"0",
"native":[
],
"src":"",
"url":"",
"uuid":"bf76f033-d36a-4ce2-af5e-9208ddd3b7e0"
},
"isActionable":false,
"isStateful":false,
"isTriggerable":true,
"photoUrl":"https:\/\/cdn.muzzley.com\/things\/profiles\/nest-v3\/allianz\/allianz-nest-protect-centered.jpg",
"profileId":"3a200576-04e1-11e8-9059-6e8e8fac3ec8",
"properties":[
{
"actions":[
],
"agentLabel":"",
"classes":[
"com.muzzley.properties.level.power.battery"
],
"components":[
"smoke_sensor"
],
"controlInterfaces":[
{
"config":{
"options":[
{
"label":"OK",
"value":"ok"
},
{
"label":"Replace",
"value":"replace"
},
{
"label":"Low",
"value":"low"
},
{
"label":"Full",
"value":"full"
}
]
},
"controlInterface":"text-picker",
"id":"ci1"
}
],
"id":"battery_health",
"io":"rs",
"isActionable":false,
"isStateful":false,
"isTriggerable":true,
"label":"Batterie",
"mainActionPriority":0,
"mainInformationPriority":0,
"onChange":false,
"rateLimit":0,
"requiredCapabilities":[
],
"schema":"https:\/\/ontology.muzzley.com\/schemas\/v1\/battery-status-string",
"schemaExtension":{
},
"states":[
],
"triggers":[
{
"condition":"equals",
"id":"3054a645-3ddf-48e5-9cf3-6956ea68264e",
"inputs":[
{
"controlInterfaceId":"ci1",
"id":"value",
"path":[
{
"source":"selection.value",
"target":"data.value"
}
]
}
],
"inputsLabel":"{{value}}",
"label":"",
"predicateLabel":"is equal to"
}
],
"unitsOptions":{
"muzzleyUnit":"",
"targetImperial":"",
"targetMetric":""
}
},
{
"actions":[
],
"agentLabel":"",
"classes":[
"com.muzzley.properties.status.co",
"com.muzzley.properties.status.co"
],
"components":[
"smoke_sensor"
],
"controlInterfaces":[
{
"config":{
"options":[
{
"label":"OK",
"value":"ok"
},
{
"label":"Warning",
"value":"warning"
},
{
"label":"Emergency",
"value":"emergency"
}
]
},
"controlInterface":"text-picker",
"id":"ci1"
}
],
"id":"co_status",
"io":"rs",
"isActionable":false,
"isStateful":false,
"isTriggerable":true,
"label":"Statut CO",
"mainActionPriority":0,
"mainInformationPriority":0,
"onChange":false,
"rateLimit":0,
"requiredCapabilities":[
],
"schema":"https:\/\/ontology.muzzley.com\/schemas\/v1\/alarm-status",
"schemaExtension":{
},
"states":[
],
"triggers":[
{
"condition":"equals",
"id":"170547a5-9dc1-4f10-9328-5ba034d5e02a",
"inputs":[
{
"controlInterfaceId":"ci1",
"id":"value",
"path":[
{
"source":"selection.value",
"target":"data.value"
}
]
}
],
"inputsLabel":"{{value}}",
"label":"",
"predicateLabel":"is equal to"
}
],
"unitsOptions":{
"muzzleyUnit":"",
"targetImperial":"",
"targetMetric":""
}
},
{
"actions":[
],
"agentLabel":"",
"classes":[
"com.muzzley.properties.status.smoke"
],
"components":[
"smoke_sensor"
],
"controlInterfaces":[
{
"config":{
"options":[
{
"label":"OK",
"value":"ok"
},
{
"label":"Warning",
"value":"warning"
},
{
"label":"Emergency",
"value":"emergency"
}
]
},
"controlInterface":"text-picker",
"id":"ci1"
}
],
"id":"smoke_status",
"io":"rs",
"isActionable":false,
"isStateful":false,
"isTriggerable":true,
"label":"Statut Fum\u00e9e",
"mainActionPriority":0,
"mainInformationPriority":0,
"onChange":false,
"rateLimit":0,
"requiredCapabilities":[
],
"schema":"https:\/\/ontology.muzzley.com\/schemas\/v1\/alarm-status",
"schemaExtension":{
},
"states":[
],
"triggers":[
{
"condition":"equals",
"id":"51ed5e32-633a-49b6-9f84-8d6d358812cc",
"inputs":[
{
"controlInterfaceId":"ci1",
"id":"value",
"path":[
{
"source":"selection.value",
"target":"data.value"
}
]
}
],
"inputsLabel":"{{value}}",
"label":"",
"predicateLabel":"is equal to"
}
],
"unitsOptions":{
"muzzleyUnit":"",
"targetImperial":"",
"targetMetric":""
}
},
{
"actions":[
],
"agentLabel":"",
"classes":[
"com.muzzley.properties.status.color"
],
"components":[
"smoke_sensor"
],
"controlInterfaces":[
],
"id":"color_status",
"io":"rs",
"isActionable":false,
"isStateful":false,
"isTriggerable":false,
"label":"Statut de Couleur",
"mainActionPriority":0,
"mainInformationPriority":0,
"onChange":false,
"rateLimit":0,
"requiredCapabilities":[
],
"schema":"https:\/\/ontology.muzzley.com\/schemas\/v1\/color-name",
"schemaExtension":{
},
"states":[
],
"triggers":[
],
"unitsOptions":{
"muzzleyUnit":"",
"targetImperial":"",
"targetMetric":""
}
}
],
"remoteId":"9fc96b08-c654-11e8-8567-000d3a38a46d",
"tilePhotoUrl":"https:\/\/cdn.muzzley.com\/things\/profiles\/nest-v3\/nest-smoke_center.jpg",
"user":"{user-id}"
}
],
"href":"\/v3\/legacy\/users\/{user-id}\/channels",
"id":"channels"
}

List User Tiles

Tiles are meant to represent a visual rendering of the most important properties and actions that physical devices can have, like a temperature reading, or an on/off switch.

Call GET /v3/legacy/users/{user-id}/tiles

  • Request parameters:

    • include (optional, string) # ex: specs

  • Response 200 (application/json)

{
"tiles":[
{
"_rev":"2-2cb3794172f6a8acd45607d176292c0e",
"actions":[
],
"channel":"{channel-id}",
"channelInfo":{
"backgroundPhotoUrl":"https:\/\/cdn.nest-protect-tiles.jpg",
"id":"{id}",
"photoUrl":"https:\/\/cdn.nest-protect-tiles.jpg",
"profileId":"{channeltemplate-id}",
"remoteId":"{remote-id}"
},
"components":[
{
"id":"smoke_sensor",
"type":"smoke_sensor"
}
],
"groups":[
"{group-id}"
],
"href":"\/v3\/legacy\/tiles\/{tile-id}",
"id":"{tile-id}",
"information":[
{
"componentType":"smoke_sensor",
"options":{
"inputPath":"data.value",
"mathExpression":"x * 100",
"prefix":"",
"suffix":"%"
},
"property":"battery_health",
"type":"text-expression"
}
],
"isGroupable":false,
"kind":"device",
"label":"Device",
"overlayUrl":"",
"photoUrl":"https:\/\/cdn.nest-protect-tiles.jpg",
"photoUrlAlt":"https:\/\/cdn.nest-protect-tiles.jpg",
"profile":"{channeltemplate-id}",
"user":"{user-id}"
},
{
"_rev":"2-7d3cbf7f7647b28ccb9a95c4366d530a",
"actions":[
],
"channel":"{channel-id}",
"channelInfo":{
"backgroundPhotoUrl":"https:\/\/cdn.nest_thermostat_left.jpg",
"id":"{id}",
"photoUrl":"https:\/\/cdn.nest_thermostat_left.jpg",
"profileId":"{channeltemplate-id}",
"remoteId":"{remote-id}"
},
"components":[
{
"id":"thermostat",
"type":"thermostat"
}
],
"groups":[
"{group-id}"
],
"href":"\/v3\/legacy\/tiles\/{tile-id}",
"id":"{tile-id}",
"information":[
{
"componentType":"thermostat",
"options":{
"inputPath":"data.value",
"mathExpression":"x * 100",
"prefix":"",
"suffix":"%"
},
"property":"humidity",
"type":"text-expression"
},
{
"componentType":"thermostat",
"options":{
"inputPath":"data.value",
"inputUnit":"C"
},
"property":"environment_temperature",
"type":"text-unit"
}
],
"isGroupable":false,
"kind":"device",
"label":"Device",
"overlayUrl":"",
"photoUrl":"https:\/\/cdn/nest_thermostat_left.jpg",
"photoUrlAlt":"https:\/\/cdn/nest_thermostat_left.jpg",
"profile":"{channeltemplate-id}",
"user":"{user-id}"
},
{
"_id":"\/v3\/legacy\/tiles\/{tile-id}",
"_rev":"1-d1780bc8367d83cd4dbea3c97a1bfe13",
"actions":[
{
"componentType":"light-bulb",
"options":{
"icon":"on_off",
"mappings":{
"off":false,
"on":true
},
"outputPath":"data.value"
},
"property":"status",
"type":"tri-state"
}
],
"channel":"{channel-id}",
"channelInfo":{
"backgroundPhotoUrl":"https:\/\/cdn\/allianz-hue-left.jpg",
"id":"{id}",
"photoUrl":"https:\/\/cdn\/allianz-hue-left.jpg",
"profileId":"{channeltemplate-id}",
"remoteId":"{remote-id}"
},
"components":[
{
"id":"light-bulb",
"type":"light-bulb"
}
],
"groups":[
"{group-id}"
],
"href":"\/v3\/legacy\/tiles\/{tile-id}",
"id":"{tile-id}",
"information":[
{
"componentType":"light-bulb",
"options":{
"char":"\ue600",
"format":"hsv"
},
"property":"color",
"type":"icon-color"
},
{
"componentType":"light-bulb",
"options":{
"inputPath":"data.value",
"mathExpression":"x * 100",
"prefix":"",
"suffix":"%"
},
"property":"brightness",
"type":"text-expression"
}
],
"isGroupable":true,
"kind":"device",
"label":"office light",
"overlayUrl":"https:\/\/cdn.\/muzzley_label_fr.png",
"photoUrl":"https:\/\/cdn\/allianz-hue-left.jpg",
"photoUrlAlt":"https:\/\/cdn\/allianz-hue-left.jpg",
"profile":"{channeltemplate-id}",
"user":"{user-id}"
}
]
}

Units Table

The Units table is needed to determine which conversions between metric and imperial systems are needed. Some devices output their measurements in either metric or imperial system, and conversion is done on-device, according to user preferences.

  • Response 200 (application/json)

{
"version":"1",
"unitSpec":{
"celsius":{
"name":{
"singular":"celsius",
"plural":"celsius"
},
"prefix":"",
"suffix":" °C",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"millimeter":{
"name":{
"singular":"millimeter",
"plural":"millimeters"
},
"prefix":"",
"suffix":" mm",
"decimalPlaces":2,
"unitSystem":"metric"
},
"centimeter":{
"name":{
"singular":"centimeter",
"plural":"centimeters"
},
"prefix":"",
"suffix":" cm",
"decimalPlaces":2,
"unitSystem":"metric"
},
"meter":{
"name":{
"singular":"meter",
"plural":"meters"
},
"prefix":"",
"suffix":" m",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"kilometer":{
"name":{
"singular":"kilometer",
"plural":"kilometers"
},
"prefix":"",
"suffix":" km",
"decimalPlaces":1,
"unitSystem":"metric"
},
"milligram":{
"name":{
"singular":"milligram",
"plural":"milligrams"
},
"prefix":"",
"suffix":" mg",
"decimalPlaces":2,
"unitSystem":"metric"
},
"gram":{
"name":{
"singular":"gram",
"plural":"grams"
},
"prefix":"",
"suffix":" gr",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"kilogram":{
"name":{
"singular":"kilogram",
"plural":"kilograms"
},
"prefix":"",
"suffix":" kg",
"decimalPlaces":1,
"unitSystem":"metric"
},
"milliliter":{
"name":{
"singular":"milliliter",
"plural":"milliliters"
},
"prefix":"",
"suffix":" ml",
"decimalPlaces":2,
"unitSystem":"metric"
},
"liter":{
"name":{
"singular":"liter",
"plural":"liters"
},
"prefix":"",
"suffix":" l",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"lp100km":{
"name":{
"singular":"liters per 100 kilometers",
"plural":""
},
"prefix":"",
"suffix":" l/100km",
"decimalPlaces":1,
"unitSystem":"metric"
},
"kmpl":{
"name":{
"singular":"kilometers per liter",
"plural":""
},
"prefix":"",
"suffix":" km/L",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"mps":{
"name":{
"singular":"meters per second",
"plural":""
},
"prefix":"",
"suffix":" m/s",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"kmph":{
"name":{
"singular":"kilometers per hour",
"plural":""
},
"prefix":"",
"suffix":" km/h",
"decimalPlaces":0,
"unitSystem":"metric"
},
"watt":{
"name":{
"singular":"watt",
"plural":"watts"
},
"prefix":"",
"suffix":" W",
"decimalPlaces":4,
"unitSystem":"metric",
"public":true
},
"kilowatt":{
"name":{
"singular":"kilowatt",
"plural":"kilowatts"
},
"prefix":"",
"suffix":" kW",
"decimalPlaces":2,
"unitSystem":"metric"
},
"mbar":{
"name":{
"singular":"millibar",
"plural":"millibars"
},
"prefix":"",
"suffix":" mbar",
"decimalPlaces":1,
"unitSystem":"metric",
"public":true
},
"bar":{
"name":{
"singular":"bar",
"plural":"bars"
},
"prefix":"",
"suffix":" bar",
"decimalPlaces":0,
"unitSystem":"metric"
},
"pascal":{
"name":{
"singular":"pascal",
"plural":"pascals"
},
"prefix":"",
"suffix":" Pa",
"decimalPlaces":0,
"unitSystem":"metric"
},
"volt":{
"name":{
"singular":"volt",
"plural":"volts"
},
"prefix":"",
"suffix":" V",
"decimalPlaces":0,
"unitSystem":"metric"
},
"ampere":{
"name":{
"singular":"ampere",
"plural":"amperes"
},
"prefix":"",
"suffix":" A",
"decimalPlaces":3,
"unitSystem":"metric"
},
"hertz":{
"name":{
"singular":"hertz",
"plural":"hertz"
},
"prefix":"",
"suffix":" Hz",
"decimalPlaces":0,
"unitSystem":"metric"
},
"kph":{
"name":{
"singular":"kilowatt hour",
"plural":"kilowatts hour"
},
"prefix":"",
"suffix":" kWh",
"decimalPlaces":0,
"unitSystem":"metric"
},
"fahrenheit":{
"name":{
"singular":"fahrenheit",
"plural":"fahrenheit"
},
"prefix":"",
"suffix":" °F",
"decimalPlaces":1,
"unitSystem":"imperial"
},
"inch":{
"name":{
"singular":"inch",
"plural":"inches"
},
"prefix":"",
"suffix":" in",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"foot":{
"name":{
"singular":"foot",
"plural":"feet"
},
"prefix":"",
"suffix":" ft",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"yard":{
"name":{
"singular":"yard",
"plural":"yards"
},
"prefix":"",
"suffix":" yd",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"mile":{
"name":{
"singular":"mile",
"plural":"miles"
},
"prefix":"",
"suffix":" mi",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"grain":{
"name":{
"singular":"grain",
"plural":"grains"
},
"prefix":"",
"suffix":" gr",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"ounce":{
"name":{
"singular":"ounce",
"plural":"ounces"
},
"prefix":"",
"suffix":" oz",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"pound":{
"name":{
"singular":"pound",
"plural":"pounds"
},
"prefix":"",
"suffix":" lb",
"decimalPlaces":1,
"unitSystem":"imperial"
},
"gallon":{
"name":{
"singular":"gallon",
"plural":"gallons"
},
"prefix":"",
"suffix":" gal",
"decimalPlaces":2,
"unitSystem":"imperial"
},
"mpg":{
"name":{
"singular":"miles per gallon",
"plural":""
},
"prefix":"",
"suffix":" mpg",
"decimalPlaces":0,
"unitSystem":"imperial"
},
"mpgus":{
"name":{
"singular":"miles per gallon (US)",
"plural":""
},
"prefix":"",
"suffix":" mpg (US)",
"decimalPlaces":0,
"unitSystem":"imperial"
},
"fps":{
"name":{
"singular":"feet per second",
"plural":""
},
"prefix":"",
"suffix":" fps",
"decimalPlaces":0,
"unitSystem":"imperial"
},
"mph":{
"name":{
"singular":"miles per hour",
"plural":""
},
"prefix":"",
"suffix":" mph",
"decimalPlaces":1,
"unitSystem":"imperial"
},
"horsepower":{
"name":{
"singular":"horsepower",
"plural":"horsepowers"
},
"prefix":"",
"suffix":" hp",
"decimalPlaces":4,
"unitSystem":"imperial"
},
"psi":{
"name":{
"singular":"pounds per square inch",
"plural":""
},
"prefix":"",
"suffix":" psi",
"decimalPlaces":1,
"unitSystem":"imperial"
},
"inhg":{
"name":{
"singular":"inches of mercury",
"plural":""
},
"prefix":"",
"suffix":" inHg",
"decimalPlaces":1,
"unitSystem":"imperial"
},
"mmhg":{
"name":{
"singular":"blood pressure",
"plural":""
},
"prefix":"",
"suffix":" mmHg",
"decimalPlaces":0
},
"kelvin":{
"name":{
"singular":"kelvin",
"plural":"kelvins"
},
"prefix":"",
"suffix":" °K",
"decimalPlaces":0
},
"lux":{
"name":{
"singular":"lux",
"plural":"lux"
},
"prefix":"",
"suffix":" lx",
"decimalPlaces":0
},
"millisecond":{
"name":{
"singular":"millisecond",
"plural":"milliseconds"
},
"prefix":"",
"suffix":" ms",
"decimalPlaces":0
},
"second":{
"name":{
"singular":"second",
"plural":"seconds"
},
"prefix":"",
"suffix":" s",
"decimalPlaces":0
},
"hour":{
"name":{
"singular":"hour",
"plural":"hours"
},
"prefix":"",
"suffix":" h",
"decimalPlaces":0
},
"minute":{
"name":{
"singular":"minute",
"plural":"minutes"
},
"prefix":"",
"suffix":" min",
"decimalPlaces":0
},
"lumen":{
"name":{
"singular":"lumen",
"plural":"lumens"
},
"prefix":"",
"suffix":" lm",
"decimalPlaces":0
},
"rpm":{
"name":{
"singular":" revolutions per minute",
"plural":""
},
"prefix":"",
"suffix":" r/min",
"decimalPlaces":0
},
"bpm":{
"name":{
"singular":"beats per minute",
"plural":"beats per minute"
},
"prefix":"",
"suffix":" bpm",
"decimalPlaces":0
},
"spo2":{
"name":{
"singular":"pulse oximetry",
"plural":""
},
"prefix":"",
"suffix":" SpO2",
"decimalPlaces":0
},
"ppm":{
"name":{
"singular":"parts per million",
"plural":"parts per millions"
},
"prefix":"",
"suffix":" ppm",
"decimalPlaces":0
},
"decibel":{
"name":{
"singular":"decibel",
"plural":"decibels"
},
"prefix":"",
"suffix":" dB",
"decimalPlaces":0
},
"mgdl":{
"name":{
"singular":"milligrams per deciliter",
"plural":"milligrams per deciliters"
},
"prefix":"",
"suffix":" mg/dL",
"decimalPlaces":0
},
"calorie":{
"name":{
"singular":"calorie",
"plural":"calories"
},
"prefix":"",
"suffix":" cal",
"decimalPlaces":0
}
},
"unitCalc":{
"from":{
"to":"expression"
},
"fahrenheit":{
"celsius":"(x - 32) / 1.8"
},
"inch":{
"millimeter":"x / 0.03937",
"centimeter":"x / 0.3937"
},
"feet":{
"centimeter":"x / 30.5"
},
"yard":{
"meter":"x * 0.9144",
"kilometer":"x * 0.0009144",
"mile":"x / 1760"
},
"mile":{
"kilometer":"x / 0.6214",
"meter":"x * 1609.34",
"yard":"x * 1760"
},
"meter":{
"kilometer":"x * 0.001",
"yard":"x / 0.9144",
"mile":"x / 1609.34"
},
"kilometer":{
"meter":"x * 1000",
"yard":"x * 1093.61",
"mile":"x * 0.621371"
},
"grain":{
"milligram":"x * 0.015432358"
},
"ounce":{
"gram":"x / 0.03527"
},
"pound":{
"kilogram":"x / 2.2046"
},
"gallon":{
"liter":"x * 4.5"
},
"mpg":{
"kmpl":"x * 0.354006"
},
"mpgus":{
"kmpl":"x * 0.4251"
},
"fps":{
"mps":"x * 0.3048"
},
"mph":{
"kmph":"x * 1.609344",
"mps":"x * 0.44704"
},
"horsepower":{
"watt":"x * 745.7",
"kilowatt":"x * 0.7457"
},
"kilowatt":{
"watt":"x * 1000",
"horsepower":"x / 0.7457"
},
"watt":{
"kilowatt":"x / 1000",
"horsepower":"x / 745.7"
},
"psi":{
"bar":"x * 0.0689476",
"mbar":"x * 68.9476"
},
"inhg":{
"mbar":"x * 33.8639"
},
"celsius":{
"fahrenheit":"(x * 1.8) + 32"
},
"millimeter":{
"inch":"x * 0.03937"
},
"centimeter":{
"inch":"x * 0.3937",
"foot":"x / 30.5"
},
"milligram":{
"grain":"x * 0.015432358"
},
"gram":{
"ounce":"x * 0.03527"
},
"kilogram":{
"pound":"x * 2.2046"
},
"liter":{
"gallon":"x / 4.5"
},
"kmpl":{
"mpgus":"x / 0.4251",
"mpg":"x / 0.354006"
},
"mps":{
"fps":"x / 0.3048",
"mph":"x / 0.44704"
},
"kmph":{
"mph":"x / 1.609344"
},
"bar":{
"psi":"x / 0.0689476"
},
"mbar":{
"psi":"x / 68.9476",
"inhg":"x / 33.8639"
},
"second":{
"hour":"x/3600"
}
}
}