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 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 previously 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 the 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"
      }
   }
}

Last updated