# How to create a custom mobile app with Habit Analytics

## Authentication

In order to interact with our API, clients must authenticate using the OAuth 2.0 protocol, in particular the [Resource Owner Password Credentials](https://tools.ietf.org/html/rfc6749#page-9) 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)

```javascript
{
    "appId":"{application-namespace}",
    "device":"{android|ios}",
    "email":"{user-mail}",
    "name":"{user-name}",
    "password":"{password}",
    "type":"account"
}
```

* Response 200 (application/json)

```javascript
{
    "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* *\*\**&#x73;hould 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)&#x20;
* Response 200 (application/json)

```javascript
{
    "_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)

```javascript
{
    "_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)

```javascript
{
    "_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)

```javascript
{
   "_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)

```javascript
{
   "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.

#### Call GET <https://cdn.muzzley.com/units/units_table.json>

* Response 200 (application/json)

```javascript
{
   "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"
      }
   }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.habit.io/how-to-create-a-custom-mobile-app-with-habit-analytics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
