# Power Management

Monitor and manage Socket Mobile scanner power states. Learn to read battery levels, configure battery change notifications, and track power state changes.

It is important to know the power state of the scanner as it is for the host to make sure it does not need to be recharged during the time the scanner is needed and the operation has a chance to change batteries or charge the scanner.

The application can check the battery level of the scanner using CaptureSDK. Additionally, many Socket Mobile scanners support battery level change notification.

Following are some examples on how to configure the scanner for these features.

## Reading the Battery Level

> **Not all scanners report battery**
>
> Only battery-powered scanners (for example cordless Bluetooth models) report a battery level. Wired scanners and some NFC readers do not have a battery, so asking for the battery level on those devices is not supported.

Here is example code showing how to request the scanner battery level information.

### Understanding the battery level value

To get a usable percentage you need to extract each piece from the integer. The helper methods shown in the snippets below (for example `CaptureHelperDevice.BatteryLevel` in C# or `getCurrentValue` in Dart) do this extraction for you — prefer using them rather than reading the raw integer directly, depending on the platform.

## Java

```java
void getBatteryLevel(DeviceClient device) {
    device.getBatteryLevel(new PropertyCallback() {
        @Override
        public void onComplete(CaptureError error, Property property) {
            if (error != null) {
                Log.e(TAG, "Get battery level failed: " + error.getMessage());
                return;
            }
            Log.d(TAG, "Battery level: " + property.getInt() + "%");
        }
    });
}
```

## Kotlin

```kotlin
fun getBatteryLevel(device: DeviceClient) {
    device.getBatteryLevel(PropertyCallback { error, property ->
        if (error != null) {
            Log.e(TAG, "Get battery level failed: ${error.message}")
            return@PropertyCallback
        }
        Log.d(TAG, "Battery level: ${property.int}%")
    })
}
```

## Swift

```swift
device.getBatteryLevelWithCompletionHandler({ result, batteryLevel in
    if let batteryLevel = batteryLevel {
        let finalBatteryLevel = SKTHelper.getCurrentLevel(fromBatteryLevel: Int(batteryLevel))
        print("Get Battery Level: \(finalBatteryLevel) - Result: \(result.rawValue)")
    }
})
```

## C#

```csharp
// ask for the Battery Level
CaptureHelperDevice.BatteryLevelResult resultBattery = await device.GetBatteryLevelAsync();
Console.WriteLine($"Battery Level: {resultBattery.Percentage}%");
```

## Dart

```dart
final int batteryLevel = await device.getBatteryLevel();
print('Battery: $batteryLevel%');

final int powerState = await device.getPowerState();
print('Power state: $powerState');
```

## JavaScript

```javascript
// Battery level is returned directly as a percentage (0-100)
const level = await device.getBatteryLevel();
console.log(`Battery level: ${level}%`);

// Power state
const power = await device.getPowerState();
console.log(`Power state: ${power}`);
```

## Get Battery Level Change and Power State Notifications

In order to receive the battery level change and power state notifications, you need to subscribe to the [device power events](/docs/using-capturesdk/capture-helper#device-power).

### Possible power states

When a power state notification is delivered, the value tells you how the scanner is currently powered:

- **Unknown** — the scanner could not determine its power source
- **On battery** — the scanner is running on its internal battery
- **On cradle** — the scanner is sitting on its charging cradle
- **On AC** — the scanner is plugged into an external power source

Use these values to decide, for example, whether to warn the user that the scanner is about to run out of power.

## Java

```java
// Ask the scanner to push battery level and power state notifications
void enablePowerNotifications(DeviceClient device) {
    int notifications = Notifications.BATTERY_LEVEL | Notifications.POWER_STATE;
    device.setProperty(
            Property.create(Property.DEVICE_NOTIFICATIONS, notifications),
            new PropertyCallback() {
                @Override
                public void onComplete(CaptureError error, Property property) {
                    if (error != null) {
                        Log.e(TAG, "Failed to enable power notifications: " + error.getMessage());
                    }
                }
            });
}

// Battery level changes are delivered to EventBus subscribers as BatteryLevelEvent.
@Subscribe(threadMode = ThreadMode.MAIN)
public void onBatteryLevelChanged(BatteryLevelEvent event) {
    Log.d(TAG, "Battery level changed: " + event.getLevel() + "%");
}

// Power state changes are delivered to EventBus subscribers as PowerStateEvent.
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPowerStateChanged(PowerStateEvent event) {
    Log.d(TAG, "Power state changed: " + PowerState.getString(event.getPowerState()));
}
```

## Kotlin

```kotlin
// Ask the scanner to push battery level and power state notifications
fun enablePowerNotifications(device: DeviceClient) {
    val notifications = Notifications.BATTERY_LEVEL or Notifications.POWER_STATE
    device.setProperty(
        Property.create(Property.DEVICE_NOTIFICATIONS, notifications),
        PropertyCallback { error, _ ->
            if (error != null) {
                Log.e(TAG, "Failed to enable power notifications: ${error.message}")
            }
        }
    )
}

// Battery level changes are delivered to EventBus subscribers as BatteryLevelEvent.
@Subscribe(threadMode = ThreadMode.MAIN)
fun onBatteryLevelChanged(event: BatteryLevelEvent) {
    Log.d(TAG, "Battery level changed: ${event.level}%")
}

// Power state changes are delivered to EventBus subscribers as PowerStateEvent.
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPowerStateChanged(event: PowerStateEvent) {
    Log.d(TAG, "Power state changed: ${PowerState.getString(event.powerState)}")
}
```

## Swift

```swift
import UIKit
import CaptureSDK

extension MyViewController: UIViewController,
    CaptureHelperDevicePresenceDelegate,
    CaptureHelperDeviceDecodedDataDelegate,
    CaptureHelperDevicePowerDelegate,
    CaptureHelperErrorDelegate {

    ...

    // MARK: - CaptureHelperDevicePowerDelegate

    func didChangeBatteryLevel(_ batteryLevel: Int, forDevice device: CaptureHelperDevice){
        print("Battery level did change: \(SKTHelper.getCurrentLevel(fromBatteryLevel: Int(batteryLevel)))% for device \(String(describing: device.deviceInfo.name!))")
    }

    func didChangePowerState(_ powerState: SKTCapturePowerState, forDevice device: CaptureHelperDevice) {
        print("Receive a power state change \(powerState) for device \(String(describing: device.deviceInfo.name!))")
    }

    ...

}
```

## C#

```csharp
// initialize CaptureHelper and subscribe to the events
capture = new CaptureHelper();
capture.ContextForEvents = WindowsFormsSynchronizationContext.Current;
capture.DeviceArrival += CaptureDeviceArrival;
capture.DeviceRemoval += CaptureDeviceRemoval;
capture.DeviceBatteryLevelChange += OnDeviceBatteryLevel;
capture.DevicePowerStateChange += OnDevicePowerState;
await capture.OpenAsync(<appId, developerId, appKey>);

// enable the Battery Level and Power State notifications when a device arrives
async void CaptureDeviceArrival(object sender, CaptureHelper.DeviceArgs e)
{
    CaptureHelperDevice device = e.CaptureDevice;
    CaptureHelperDevice.NotificationsResult resultGetNotifications = await device.GetNotificationsAsync();

    if (resultGetNotifications.IsSuccessful())
    {
        var notifications = resultGetNotifications.Notifications;
        bool hasChanges = false;

        // Enable Battery Level notifications
        if (!resultGetNotifications.Notifications.BatteryLevel)
        {
            notifications.BatteryLevel = true;
            hasChanges = true;
        }

        // Enable Power State notifications
        if (!resultGetNotifications.Notifications.PowerState)
        {
            notifications.PowerState = true;
            hasChanges = true;
        }

        // Apply notification changes
        if (hasChanges)
        {
            var resultSetNotifications = await device.SetNotificationsAsync(notifications);
            if (!resultSetNotifications.IsSuccessful())
            {
                Console.WriteLine($"Set Notifications failed - Error: {resultSetNotifications.Result}");
            }
        }
    }
}

// Battery Level change handler
void OnDeviceBatteryLevel(object? sender, CaptureHelper.BatteryLevelArgs e)
{
    string deviceName = e.CaptureDevice.GetDeviceInfo().Name;
    string percentage = CaptureHelper.ConvertBatteryLevelInPercentage(e.MinLevel, e.MaxLevel, e.CurrentLevel);
    Console.WriteLine($"Device: {deviceName}, Battery Level: {percentage}%");
}

// Power State change handler
void OnDevicePowerState(object? sender, CaptureHelper.PowerStateArgs e)
{
    string deviceName = e.CaptureDevice.GetDeviceInfo().Name;
    Console.WriteLine($"Device: {deviceName}, Power State: {e.State}");
}
```

## Dart

```dart
onBatteryLevel: (int level, CaptureHelperDevice device) {
  final int percent = (level >> 8) & 0xFF;
  print('Battery: $percent%');
},
onPowerState: (int state, CaptureHelperDevice device) {
  print('Power state: $state');
},
```

## JavaScript

```javascript
import { CaptureHelper } from 'react-native-capture';

const capture = new CaptureHelper({
  onBatteryLevel: (level, device) => {
    console.log(`Battery level for ${device.name}: ${level}%`);
  },
  onPowerState: (state, device) => {
    console.log(`Power state for ${device.name}: ${state}`);
  },
});

await capture.open(appInfo);
```