# Class SensorSession

java.lang.Object
com.codename1.health.sensors.SensorSession

public class SensorSession extends Object

A live connection to one health sensor, decoding its notifications into health samples.

Obtained from `HealthSensors.connect(HealthSensor,HealthSensorProfile,SensorSessionOptions)`. All listener callbacks arrive on the EDT.

##### Derived values

Speed and cadence sensors transmit cumulative counters rather than rates, so this class differences consecutive notifications -- handling the counter and event-timer wraps that would otherwise produce spikes of tens of thousands of rpm. See `CumulativeCounterTracker`.

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `SensorSession(String sensorId, HealthSensorProfile profile, SensorSessionOptions options)`
  Ports and `HealthSensors` construct sessions.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `final void`
  `addListener(SensorSampleListener listener)`
  Registers a listener for measurements and state changes.
  `protected final void`
  `fireError(HealthException error)`
  Delivers an error to listeners on the EDT.
  `protected final void`
  `fireSample(HealthSample sample)`
  Delivers a sample to listeners on the EDT.
  `protected final void`
  `flushPendingWrites()`
  Writes anything still buffered.
  `protected final void`
  `forgetFromManager()`
  Drops this session from `HealthSensors.getActiveSessions()`.
  `final Integer`
  `getBatteryPercent()`
  The device's battery level as a percentage, or `null` when it does not report one.
  `final int`
  `getBodySensorLocation()`
  Where a heart-rate sensor is worn, as a `BodySensorLocation` constant, or `-1` when unreported.
  `final HealthSample`
  `getLatest(HealthDataType type)`
  The most recent sample of `type`, or `null` when none has arrived or the last one is older than `SensorSessionOptions.getStaleSampleMillis()`.
  `final SensorSessionOptions`
  `getOptions()`
  The options this session was created with.
  `final HealthSensorProfile`
  `getProfile()`
  The profile this session is speaking.
  `final String`
  `getSensorId()`
  The stable identifier of the connected device -- see `HealthSensor.getId()`.
  `final SensorSessionState`
  `getState()`
  The current lifecycle state.
  `protected final boolean`
  `hasStreamed()`
  Moves the session to a new state and notifies listeners.
  `protected final void`
  `onMeasurement(byte[] value, long receivedAtMillis)`
  Decodes one raw characteristic value and emits the resulting samples.
  `final void`
  `removeListener(SensorSampleListener listener)`
  Removes a previously registered listener.
  `AsyncResource<Integer>`
  `requestStoredRecords(GlucoseRecordFilter filter)`
  Asks a glucose meter to replay stored records, delivering each one through the normal sample listeners, and resolving with how many were retrieved.
  `protected final void`
  `resetCounters()`
  Forgets the cumulative-counter baselines, so the next notification establishes a new one.
  `AsyncResource<Boolean>`
  `resetEnergyExpended()`
  Resets a heart-rate strap's accumulated energy-expended counter, by writing `0x01` to the Heart Rate Control Point (`0x2A39`).
  `protected final void`
  `setBatteryPercent(Integer percent)`
  Records the device's battery level.
  `protected final void`
  `setBodySensorLocation(int location)`
  Records where a heart-rate sensor is worn.
  `protected final boolean`
  `setState(SensorSessionState newState)`
  Moves to `newState`, reporting whether the move happened.
  `void`
  `stop()`
  Disconnects and stops delivering measurements.
  `String`
  `toString()`
  Returns a string representation of the object.

  ### Methods inherited from class Object

  `clone, equals, getClass, hashCode, notify, notifyAll, wait, wait, wait`

- ## Constructor Details

  - ### SensorSession

    protected SensorSession(String sensorId, HealthSensorProfile profile, SensorSessionOptions options)
    Ports and `HealthSensors` construct sessions.

- ## Method Details

  - ### getSensorId

    public final String getSensorId()
    The stable identifier of the connected device -- see `HealthSensor.getId()`.

  - ### getProfile

    public final HealthSensorProfile getProfile()
    The profile this session is speaking.

  - ### getOptions

    public final SensorSessionOptions getOptions()

    The options this session was created with.

    A copy, so that reconfiguring what this returns cannot change a running session -- the same reason the session took a snapshot of what it was given.

  - ### getState

    public final SensorSessionState getState()
    The current lifecycle state.

  - ### addListener

    public final void addListener(SensorSampleListener listener)
    Registers a listener for measurements and state changes.

  - ### removeListener

    public final void removeListener(SensorSampleListener listener)
    Removes a previously registered listener.

  - ### getLatest

    public final HealthSample getLatest(HealthDataType type)

    The most recent sample of `type`, or `null` when none has arrived or the last one is older than `SensorSessionOptions.getStaleSampleMillis()`.

    Returning null rather than a stale value is deliberate: a UI bound to this shows a dash when the strap falls off, instead of continuing to display the wearer's last heart rate as though it were current.

  - ### getBatteryPercent

    public final Integer getBatteryPercent()
    The device's battery level as a percentage, or `null` when it does not report one.

  - ### getBodySensorLocation

    public final int getBodySensorLocation()
    Where a heart-rate sensor is worn, as a `BodySensorLocation` constant, or `-1` when unreported.

  - ### resetEnergyExpended

    public AsyncResource<Boolean> resetEnergyExpended()

    Resets a heart-rate strap's accumulated energy-expended counter, by writing `0x01` to the Heart Rate Control Point (`0x2A39`).

    Fails with `HealthError.NOT_SUPPORTED` on other profiles and on straps that do not expose the control point.

  - ### requestStoredRecords

    public AsyncResource<Integer> requestStoredRecords(GlucoseRecordFilter filter)

    Asks a glucose meter to replay stored records, delivering each one through the normal sample listeners, and resolving with how many were retrieved.

    Not implemented in this release: this always fails with `HealthError.NOT_SUPPORTED`, on the glucose profile as well as any other. Replay runs over the Record Access Control Point, a stateful request/response protocol on a second characteristic with its own operators, filters and abort semantics, and shipping it untested against real meters would be worse than saying plainly that it is absent. `GlucoseRecordFilter` and the rest of the vocabulary are here so the call site does not have to change when it lands.

    Live glucose notifications are unaffected and work today.

  - ### stop

    public void stop()
    Disconnects and stops delivering measurements. Idempotent.

  - ### forgetFromManager

    protected final void forgetFromManager()

    Drops this session from `HealthSensors.getActiveSessions()`.

    Without it a stopped or failed session stayed in the registry for the manager's lifetime, so the list documented as "connected or reconnecting" filled up with dead sessions and kept their peripherals and listeners alive with them.

  - ### onMeasurement

    protected final void onMeasurement(byte[] value, long receivedAtMillis)

    Decodes one raw characteristic value and emits the resulting samples. Called by the transport when a notification arrives.

    A malformed payload emits nothing and reports `HealthError.INVALID_DATA` rather than throwing: one misbehaving device must not take down the app.

  - ### flushPendingWrites

    protected final void flushPendingWrites()
    Writes anything still buffered. Called when the session stops so a short ride does not lose its last partial batch.

  - ### setBatteryPercent

    protected final void setBatteryPercent(Integer percent)
    Records the device's battery level. Called by the transport.

  - ### setBodySensorLocation

    protected final void setBodySensorLocation(int location)
    Records where a heart-rate sensor is worn. Called by the transport.

  - ### resetCounters

    protected final void resetCounters()
    Forgets the cumulative-counter baselines, so the next notification establishes a new one. Called by the transport on reconnect: a sensor that power-cycled restarts its counters from zero.

  - ### hasStreamed

    protected final boolean hasStreamed()

    Moves the session to a new state and notifies listeners. True once this session has actually streamed.

    A failed initial connect also publishes DISCONNECTED, and reconnecting from that resurrects a session the caller was already told had failed.

  - ### setState

    protected final boolean setState(SensorSessionState newState)

    Moves to `newState`, reporting whether the move happened.

    A refusal is not merely a no-op for the caller: it means the session went terminal underneath, and whatever the caller was about to do next -- connect a peripheral, arm a timer -- would be done on behalf of a session that has already been torn down.

  - ### fireSample

    protected final void fireSample(HealthSample sample)
    Delivers a sample to listeners on the EDT.

  - ### fireError

    protected final void fireError(HealthException error)
    Delivers an error to listeners on the EDT.

  - ### toString

    public String toString()
    Description copied from class: `Object`
    Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method. The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object. In other words, this method returns a string equal to the value of: getClass().getName() + '@' + Integer.toHexString(hashCode())
    Overrides:
      `toString` in class `Object`