rtl_ir_control 1.0.6
rtl_ir_control: ^1.0.6 copied to clipboard
A utility designed to simplify the setup and configuration of Remotec products using Bluetooth Low Energy (BLE).
rtl_ir_control #
A Flutter package for setup and controlling infrared (IR) devices via Bluetooth. This package
leverages
esp_blufi and flutter_blue_plus to set up and manage Bluetooth Low Energy (BLE) connections and
download ir code from api call to device.
Features #
- Device scanning and connection management using BLE.
- Blufi setup for BW8459 devices.
- Downloading IR code for device control.
Dependencies #
This package relies on the following external packages:
esp_blufi: For BLE communication with ESP-based devices.flutter_blue_plus: For Bluetooth Low Energy operations on Android and iOS.
Setup #
Permission #
To use this package, you must configure Bluetooth permissions for your Flutter app. Below are the steps for Android and iOS.
Android #
Add the following to android/app/src/main/AndroidManifest.xml:
<!-- Tell Google Play Store that your app uses Bluetooth LE
Set android:required="true" if bluetooth is necessary -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
<!-- New Bluetooth permissions in Android 12
https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" /><uses-permission
android:name="android.permission.BLUETOOTH_CONNECT" /><uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- legacy for Android 11 or lower -->
<uses-permission android:maxSdkVersion="30"
android:name="android.permission.BLUETOOTH" /><uses-permission android:maxSdkVersion="30"
android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- legacy for Android 9 or lower -->
<uses-permission android:maxSdkVersion="28"
android:name="android.permission.ACCESS_COARSE_LOCATION" />
iOS #
- In the
ios/Runner/Info.plistlet’s add:
<dict>
<!-- Required for Bluetooth usage on iOS 13 and later; explains why the app needs Bluetooth access -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app requires Bluetooth to scan and connect to devices.</string>
<!-- Legacy key for Bluetooth usage on iOS 12 and earlier; included for backward compatibility -->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app requires Bluetooth to scan and connect to devices.</string>
</dict>
- To use BLE in app background, add the following to your Info.plist
<dict>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
</array>
</dict>
Note: Ensure that Bluetooth and location permissions have been granted for the app.
How to use #
1. Scan Devices #
Scan for BW8459 devices using a name prefix filter.
- Both BLUETOOTH_SCAN and ACCESS_FINE_LOCATION permissions are required for Bluetooth scanning on Android.
import 'package:rtl_ir_control/rtl_ir_control.dart';
void scanDevices() {
RtlIrControl().startScan(nameFilter: ['BW8459', 'BLUFI', 'RM2']).listen((
List<RTLBluetoothScanRecord> scanResults,) {
print('Discovered devices (${scanResults.length}):');
for (var result in scanResults) {
print('Device Name: ${result.device.name} ${result.device.advName}');
}
});
}
2. Setup Device #
Checks the device's configuration status, prepares it for Wi-Fi setup by using enterSetupMode()
function
Future<void> verifyAndSetup(String id) async {
try {
// Initialize the device using the provided ID
final device = RtlIrControl().getDevice(id);
// Establish connection to the device
await device.connect();
// Create handler for device operations
final handler = BW8459DeviceHandler(device);
// OPTIONAL - check device is already configured
bool isConfigured = await handler.isConfigured();
// enter setup mode programmatically
await handler.enterSetupMode();
// IMPORTANT: release connection for blufi setup
await device.disconnect();
await setupDevice(id);
} catch (e) {
print("Setup failed: $e");
}
}
Connect to a device, scan for Wi-Fi networks, and configure Wi-Fi credentials.
Note: Ensure the device is in pairing mode before starting the setup process. Otherwise, it may appear disconnected or result in a connection timeout.
import 'package:rtl_ir_control/rtl_ir_control.dart';
Future<void> setupDevice(String id) async {
final blufi = RTLBlufiSetupUtils();
try {
// Set device ID form scan
await blufi.setCurrentId(id);
// Establish connection
await blufi.connect();
// Scan for Wi-Fi networks
var wifiList = await blufi.scanWifiList();
// Select Wi-Fi (replace with your UI logic)
var ssid = await selectWifi(wifiList);
// Get password (replace with your UI logic)
var password = await inputPassword(ssid);
// Provision Wi-Fi credentials
await blufi.configProvision(ssid: ssid, password: password);
print("Setup Completed");
} catch (e) {
print("Setup failed: $e");
}
}
// Placeholder UI functions
Future<String> selectWifi(List<String> wifiList) async {
return wifiList.first; // Replace with actual selection logic
}
Future<String> inputPassword(String ssid) async {
return "your_password"; // Replace with actual input logic
}
3. Read Device Information #
Read the device information to get IR data from the API.
import 'package:rtl_ir_control/rtl_ir_control.dart';
Future<void> readDeviceInfo(String id) async {
try {
// Initialize the device using the provided ID
final device = RtlIrControl().getDevice(id);
// Establish connection to the device
await device.connect();
// Create handler for device operations
final handler = BW8459DeviceHandler(device);
var masterKey = await handler.readMasterKey();
var macAddress = await handler.readMacAddress();
var firmwareVersion = await handler.readFirmwareVersion();
var hardwareVersion = await handler.readHardwareVersion();
var modelNumber = await handler.readRemoteModel();
// display device information
print('''
Master Key: $masterKey
MAC Address: $macAddress
Firmware Version: $firmwareVersion
Hardware Version: $hardwareVersion
Model Number: $modelNumber
''');
// Disconnect after the action is completed
await device.disconnect();
} catch (e) {
print("Read device info failed: $e");
} finally {
// Ensure device is properly disconnected
await device.disconnect();
}
}
4. Decoding API Response to IR Codeset #
Convert the API response to an IR codeset for downloading.
void decodeIrCodeset(String jsonResponse) {
try {
// Decode codeset from API response
RTLIrCodeset codeset = RTLIrCodeset.fromApiJson(jsonResponse);
print("Successfully decoded IR codeset: ${codeset.toString()}");
} catch (e) {
print("Failed to decode IR codeset: $e");
}
}
5. Download IR Codeset #
Download an IR codeset to a device.
import 'package:rtl_ir_control/rtl_ir_control.dart';
Future<void> downloadCodes(String id, RTLIrCodeset codeset) async {
try {
// Get device instance
var device = RtlIrControl().getDevice(id);
// Connect to device
await device.connect();
// Initialize handler
final handler = BW8459DeviceHandler(device);
// Download codeset with progress updates
handler.downloadCodeFromCodeset(
channel: 1,
brandName: "LG",
codeNum: "81",
codeset: codeset,
).listen((progress) => print("Download progress: $progress%"),
onDone: () {
print("Download completed");
device.disconnect();
},
onError: (e) {
print("Download failed: $e");
device.disconnect();
},
);
} catch (e) {
print("Code download failed: $e");
}
}
6. Delete IR Codeset #
Delete IR codes with channel.
import 'package:rtl_ir_control/rtl_ir_control.dart';
Future<void> deleteCodes(String id, int channel) async {
try {
// Get device instance
var device = RtlIrControl().getDevice(id);
// Connect to device
await device.connect();
// Initialize handler
final handler = BW8459DeviceHandler(device);
// Delete IR Codeset with channel
await handler.deleteCode(channel);
// Disconnect after the action is completed
await device.disconnect();
} catch (e) {
print("Delete code failed: $e");
}
}
Custom Device Handler #
Extend the functionality of rtl_ir_control by creating a custom DeviceHandler tailored to your
Bluetooth device.
import 'package:rtl_ir_control/rtl_ir_control.dart';
class CustomDeviceHandler extends GeneralDeviceHandler {
// Custom UUIDs for your device's BLE service and characteristic
static final RTLBluetoothUuid customServiceUuid =
RTLBluetoothUuid('00001800-0000-1000-8000-00805f9b34fb'); // Generic Access service
static final RTLBluetoothUuid customCharacteristicUuid =
RTLBluetoothUuid('00002a00-0000-1000-8000-00805f9b34fb'); // Device Name characteristic
// Constructor takes an RTLBluetoothDevice instance
CustomDeviceHandler(super.rtlBluetoothDevice);
// Read raw data from the device as a byte list
Future<List<int>> readCustomData() async {
final value = await rtlBluetoothDevice.readData(
customServiceUuid,
customCharacteristicUuid,
);
return value; // Returns raw bytes (e.g., for further processing)
}
// Send a custom command to the device
Future<void> sendCustomCommand(List<int> data) async {
await rtlBluetoothDevice.sendCommand(
customServiceUuid,
customCharacteristicUuid,
data, // Byte list representing your command
);
}
// Stream progress for a custom operation (e.g., firmware update)
Stream<int> performCustomOperation(int param) async* {
for (var i = 0; i <= 100; i += 20) {
await Future.delayed(Duration(milliseconds: 500)); // Simulate async work
yield i; // Emit progress percentage
}
// Replace with your device's specific operation logic
}
}
Once you've created your CustomDeviceHandler, use the following example to call its methods:
// Usage
Future<void> useCustomHandler(String deviceId) async {
try {
// Retrieve and connect to the device
var device = RtlIrControl().getDevice(deviceId);
await device.connect();
// Instantiate your custom handler
var handler = CustomDeviceHandler(device);
// Read data (raw bytes)
List<int> data = await handler.readCustomData();
print("Custom data (bytes): $data");
// Send a sample command
await handler.sendCustomCommand([0x01, 0x02, 0x03]);
print("Command sent successfully");
// Monitor a custom operation's progress
handler.performCustomOperation(42).listen(
(progress) => print("Operation progress: $progress%"),
onDone: () => print("Operation completed"),
);
} catch (e) {
print("Error in custom handler usage: $e");
}
}
Notes #
-
Handle exceptions (e.g., RTLBluetoothException) for errors like timeouts or permission issues.
-
The package is tailored for BW8459 devices; adapt for other devices as needed.
-
Use a real API response for apiJson in production.