mob_sensors

Every phone sensor for Mob apps: list the device's sensors, read one sample, stream readings, and query step history. Android (SensorManager, every sensor including vendor ones) and iOS (CoreMotion, CMAltimeter, CMPedometer, proximity).

Install

# mix.exs
{:mob_sensors, "~> 0.1"}
# mob.exs
config :mob, :plugins, [:mob_sensors]
config :mob, :trusted_plugins, %{
# ...the other first-party plugins...
mob_sensors: "ed25519:nc56w+1Kx0gIt/4EkHxnMZCKHMzp4+S5kS/HoSzEZkg="
}

Then mix mob.deploy --native: the plugin's NIFs reach the device only through a native build.

Use

Call from any process; results arrive in that process's mailbox.

MobSensors.list()
#=> [%{type: :pressure, name: "...", vendor: "...", unit: "hPa", max_range: 1100.0,
# resolution: 0.005, wake_up: false}, ...]
:ok = MobSensors.read(:pressure)
# {:mob_sensors, :reading, :pressure, %{values: [1013.2], timestamp: 1791100000000, accuracy: 3}}
:ok = MobSensors.start(:accelerometer, interval_ms: 100)
# {:mob_sensors, :reading, :accelerometer, %{values: [x, y, z], ...}} every ~100 ms
:ok = MobSensors.stop(:accelerometer)
:ok = MobSensors.read("com.motorola.sensor.x") # a vendor sensor, by its string type
MobSensors.steps(midnight_ms, now_ms) # iOS; Android: {:error, :history_unavailable}
# {:mob_sensors, :steps, {:ok, %{steps: 4321, distance_m: 3010.5, floors_ascended: 3,
# from: midnight_ms, to: now_ms}}}

Errors arrive as {:mob_sensors, :error, type, reason} with reason one of :timeout, :permission, :unavailable or a platform message. read/2 and start/2 return {:error, :unknown_type} or {:error, :unavailable} straight away when the type is unknown or the device lacks the sensor.

A stream ends when its caller calls stop/1 or exits; nothing leaks.

Permissions

Step counter and step detector need :activity_recognition:

Mob.Permissions.request(socket, :activity_recognition)
# {:permission, :activity_recognition, :granted | :denied}

Android: ACTIVITY_RECOGNITION (API 29+), declared by the plugin. iOS: Motion & Fitness (NSMotionUsageDescription, merged from the plugin); it also covers the barometer and steps/2. Every other sensor needs nothing. Android heart rate needs BODY_SENSORS, which the host must declare and request itself.

Platforms

Sensor Android iOS
accelerometer, gyroscope, magnetic field yes yes (CMMotionManager)
pressure (barometer) yes yes (CMAltimeter, ~1 Hz)
proximity yes iPhone only: near [0.0], far [5.0] cm
step counter steps since boot steps since local midnight (CMPedometer)
step history, steps/2 {:error, :history_unavailable} yes
ambient light yes no public API
humidity, temperature, gravity, rotation vectors, hinge angle, heart rate, vendor sensors yes no

Values use Android's SensorEvent units and axes on both platforms (iOS acceleration is converted from g to m/s² with Android's sign, pressure from kPa to hPa). The iOS simulator has none of these sensors. See the MobSensors moduledoc for the full message shapes and value layouts.

License

MIT