# Extensions: Health and Geo

Extensions are pieces of non-critical functionality going over the NervesHub WebSocket. They are separated out under the Extensions mechanism so that the client can happily ignore anything extension-related in service of keeping firmware updates healthy. That is always the top priority.

There are two extensions currently:

- [**Geo**](#geo) provides hooks to send a device's GeoIP information.
- [**Health**](#health) reports device metrics, alarms, metadata and similar.
- [**Local Shell**](#local-shell) gives NervesHub the ability to expose an interactive shell in the UI.

Your NervesHub server controls enabling and disabling extensions to allow you to switch them off if they impact operations.

## Geo

The Geo `NervesHubLink.Extensions.Geo.DefaultResolver` uses the https://whenwhere.nerves-project.org/ service to resolve the device's location using the publicly available IP address.

You can create your own resolver by implementing a module that implements the `NervesHubLink.Extensions.Geo.Resolver` behaviour. For example, if you have a GPS module, or your device can resolve a reasonably precise location via LTE, you could implement your own resolver called `MyApp.GPSGeoResolver` and update the config to:

```
config :nerves_hub_link,
  geo: [
    resolver: MyApp.GPSGeoResolver
  ]
```

Please see `NervesHubLink.Extensions.Geo.Resolver` for more information.

## Health

You can add your own metrics, metadata and alarms.

The default set of metrics used by the `Health.DefaultReport` are:

- `NervesHubLink.Extensions.Health.MetricSet.CPU` - CPU temperature, usage (percentage), and load averages.
- `NervesHubLink.Extensions.Health.MetricSet.Memory` - Memory size (MB), used (MB), and percentage used.
- `NervesHubLink.Extensions.Health.MetricSet.Disk` - Disk size (KB), available (KB), and percentage used.

And one optional metric set:
- `NervesHubLink.Extensions.Health.MetricSet.NetworkTraffic` - Total bytes sent and received (per interface).

You can also create your own metric sets by implementing the `NervesHubLink.Extensions.Health.MetricSet`
behaviour.

If a library you are using provides a metric set, you can add it to the list of metrics, but please ensure
to include all the metric sets you want to use. If you want to include the full default set, you can use
`:default` or `:defaults` in your metric set list.

eg.

```
config :nerves_hub_link,
  health: [
    metric_sets: [
      :defaults,
      MyApp.HealthMetrics,
      ALibrary.BatteryMetrics
    ]
  ]
```

If you only want to use some of the default metrics, you can specify them explicitly:

```
config :nerves_hub_link,
  health: [
    metric_sets: [
      NervesHubLink.Extensions.Health.MetricSet.CPU,
      NervesHubLink.Extensions.Health.MetricSet.Memory
      # the disk metrics have been excluded
    ]
  ]
```

And if you don't want to use any metric sets, you can set the `metric_sets` option to an empty list.

```
config :nerves_hub_link,
  health: [
    metric_sets: []
  ]
```

If you want to add custom metadata to the default health report, you can specify it with:

```
config :nerves_hub_link,
  health: [
    # metadata is added with a key and MFA
    # the function should return a string
    metadata: %{
      "placement" => {CatCounter, :venue, []}
    }
  ]
```

Or you can implement a completely custom reporting module by implementing `NervesHubLink.Extensions.Health.Report` and configuring it:

```
config :nerves_hub_link,
  health: [
    report: CatCounter.MyHealthReport
  ]
```

The `Health.DefaultReport` also sends the current system alarms to the connected NervesHub platform.

A built in default is to filter out the `:disk_almost_full` alarm for the `/` mount. This alarm is generated by Erlang upon startup, based on how the read-only root filesystem is sized to fit only whats included in the firmware.

You can customize the mounts ignored with:

```
config :nerves_hub_link,
  health: [
    alarms: [
      ignore_disk_full_mounts: [
        "/a_different_mount"
      ]
    ]
  ]
```

Specifying a list of mounts to ignore will override the default `/`, so make sure to include that in the list if you want to continue ignoring `/` while also adding other mounts.

### Alarms

The [default health report](`NervesHubLink.Extensions.Health.DefaultReport`) uses `:alarm_handler`, but we
recommend the [`alarmist`](https://hex.pm/packages/alarmist) library for improved alarms handling.

## Local Shell

Provides an interactive local shell for NervesHub to connect to. This is useful for debugging and troubleshooting issues with the device.

This extension is enabled by default, but must also be enabled in your Device and Product settings on your NervesHub platform.

To use this extension, you need to include the [`ExPTY`](https://hex.pm/packages/expty) library in your project's dependencies.
