ll_device_flutter_sdk 1.0.0
ll_device_flutter_sdk: ^1.0.0 copied to clipboard
LinkLink Device Flutter SDK for controlling Broadlink devices via UDP. Provides APIs for smart home app integration with auto-pairing and device management.
LinkLink Device Flutter SDK #
A comprehensive Flutter SDK for controlling Broadlink devices via UDP. Designed specifically for smart home app integration with clean, simple APIs.
⨠Features #
-
đ Smart Device Discovery:
- Auto-pairing: Devices are automatically authenticated during discovery
- Real-time streaming: Device responses pushed instantly
- Multi-network support: Automatic network adaptation
- Intelligent deduplication: Based on unique device identifiers
-
đ Secure Authentication:
- Python-compatible: Fully compatible with python-broadlink authentication
- Auto-retry mechanism: >95% success rate in unstable networks
- Dynamic key management: Secure AES-128-CBC encryption and session management
- Complete error checking: Checksum validation + device error code detection
-
đĄ RM Device Control: IR/RF learning and sending with device-specific optimization
-
đ SP Device Control: Power control, nightlight, energy monitoring
-
đ Real-time Events: Device status and discovery event streams
-
đĄď¸ Error Handling: Comprehensive exception handling
-
đą Cross Platform: Android and iOS support
đď¸ Architecture #
This SDK provides a clean, event-driven API for smart home applications:
Your Smart Home App
â
LinkLink Device SDK
â
Broadlink Devices
đ Quick Start #
Installation #
Add to your pubspec.yaml:
dependencies:
flutter_sdk: ^1.0.0
Basic Usage #
import 'package:flutter_sdk/ll_device_flutter_sdk.dart';
// Get SDK instance
final sdk = LLDeviceFlutterSDK.getInstance();
// Listen to events
sdk.deviceEvents.listen((event) {
print('Device event: $event');
});
sdk.discoveryEvents.listen((event) {
print('Discovery event: $event');
});
// Discover devices with auto-pairing
final devices = await sdk.discoverDevices(
autoAuthenticate: true // Devices are automatically paired
);
for (final device in devices) {
if (device.aesKey != null) {
print('â
${device.name} - Already authenticated!');
}
}
// Control devices directly
if (devices.isNotEmpty) {
final device = devices.first;
// Control smart plug
if (device.capabilities.supportsPower) {
await sdk.setSPPower(device.id, true);
}
// Learn IR code
if (device.capabilities.supportsIR) {
print('Point remote at device and press button...');
final code = await sdk.learnIRCode(device.id);
if (code != null) {
await sdk.sendIRCode(device.id, code);
}
}
}
// Or use periodic probe for continuous monitoring
sdk.startProbe(
interval: 10,
autoAuthenticate: true,
);
Advanced Usage - Continuous Device Monitoring #
// Start continuous device discovery
sdk.startProbe(
interval: 10, // Check every 10 seconds
timeout: 3,
autoAuthenticate: true, // Auto-authenticate new devices
);
// Listen for new devices
sdk.discoveryEvents.listen((event) {
if (event is DeviceDiscoveredEvent) {
final device = event.device;
print('đŻ New device: ${device.name}');
// Device is automatically added and can be used immediately
if (device.aesKey != null && device.capabilities.supportsPower) {
sdk.setSPPower(device.id, true);
}
}
});
// Stop when done
// sdk.stopProbe();
đ API Reference #
Core SDK Class #
LLDeviceFlutterSDK
Main SDK class providing all functionality.
// Singleton instance
LLDeviceFlutterSDK sdk = LLDeviceFlutterSDK.getInstance();
// Event streams
Stream<DeviceEvent> deviceEvents;
Stream<DiscoveryEvent> discoveryEvents;
Device Discovery #
discoverDevices() with Auto-Pairing
Discover Broadlink devices on the network with automatic authentication.
Future<List<LLDNADeviceInfo>> discoverDevices({
int timeout = 10, // Discovery timeout in seconds
String? localIpAddress, // Local IP binding
String discoverIpAddress = '255.255.255.255',
int discoverPort = 80,
bool autoAuthenticate = true, // Auto-pair discovered devices
})
// Basic usage
final devices = await sdk.discoverDevices();
// Advanced usage
final devices = await sdk.discoverDevices(
timeout: 15,
autoAuthenticate: true, // Devices will be ready to use immediately
);
// Check authentication status
for (final device in devices) {
if (device.aesKey != null && device.deviceId != null) {
print('â
${device.name} is authenticated and ready');
}
}
discoverDevicesStream() - Real-time Discovery Stream
Provides real-time device discovery with optional auto-pairing:
Stream<LLDNADeviceInfo> discoverDevicesStream({
int timeout = 10,
String? localIpAddress,
String discoverIpAddress = '255.255.255.255',
int discoverPort = 80,
bool autoAuthenticate = true, // Auto-pair as devices are discovered
})
// Real-time device processing
await for (final device in sdk.discoverDevicesStream(
timeout: 10,
autoAuthenticate: true
)) {
print('đŻ Discovered: ${device.name} (${device.host})');
if (device.aesKey != null) {
print(' â Authenticated and ready to use!');
// Can use device immediately without manual authentication
}
}
hello() - Direct Device Contact
Contact a device at a known IP address:
Future<LLDNADeviceInfo?> hello(
String ipAddress,
{int port = 80, int timeout = 3}
)
// Check if device is online
final device = await sdk.hello('192.168.1.100');
if (device != null) {
print('â
Device online: ${device.name}');
}
Device Management #
initializeDevices() - Initialize Known Devices
Initialize the SDK with a list of known devices (e.g., loaded from storage):
void initializeDevices(List<LLDNADeviceInfo> devices)
// Example: Load devices from storage
final savedDevices = await loadDevicesFromStorage();
sdk.initializeDevices(savedDevices);
// Devices can now be controlled without re-discovery
for (final device in savedDevices) {
if (device.capabilities.supportsPower) {
await sdk.setSPPower(device.id, true);
}
}
connectDevice() - Manual Device Authentication
Manually authenticate a device (if not using auto-authentication):
Future<bool> connectDevice(String deviceId)
// Example
final success = await sdk.connectDevice(deviceId);
if (success) {
print('Device authenticated successfully');
}
getConnectedDevices()
Get list of devices with authentication keys:
List<LLDNADeviceInfo> getConnectedDevices()
// Example
final connectedDevices = sdk.getConnectedDevices();
print('Connected devices: ${connectedDevices.length}');
getDeviceStatus()
Get device status information:
Future<DeviceStatus> getDeviceStatus(String deviceId)
// Example
final status = await sdk.getDeviceStatus(deviceId);
print('Power: ${status.powerState}');
startProbe() & stopProbe() - Periodic Device Discovery
Start and stop periodic device discovery (probe) to continuously monitor for new devices:
void startProbe({
int interval = 10, // Probe interval in seconds
int timeout = 3, // Discovery timeout per probe
String? localIpAddress, // Local IP binding
String discoverIpAddress = '255.255.255.255',
int discoverPort = 80,
bool autoAuthenticate = false, // Auto-authenticate new devices
})
void stopProbe()
// Example: Start periodic discovery every 10 seconds
sdk.startProbe(
interval: 10,
timeout: 3,
autoAuthenticate: true, // Auto-authenticate newly discovered devices
);
// Listen to discovery events
sdk.discoveryEvents.listen((event) {
if (event is DeviceDiscoveredEvent) {
print('New device found: ${event.device.name}');
// Device is automatically added to device manager
}
});
// Stop probing when done
sdk.stopProbe();
Use Cases:
- Monitor for new devices joining the network
- Maintain real-time device availability status
- Auto-discover and configure new smart home devices
- Build dynamic device management dashboards
RM Device Control #
learnIRCode()
Learn IR/RF code from remote control:
Future<String?> learnIRCode(
String deviceId,
{int timeout = 30}
)
// Example
print('Point remote at device and press button...');
final code = await sdk.learnIRCode(deviceId, timeout: 30);
if (code != null) {
print('Learned code: $code');
// Save code for later use
}
sendIRCode()
Send IR/RF code to device:
Future<bool> sendIRCode(String deviceId, String code)
// Example
final success = await sdk.sendIRCode(deviceId, savedCode);
if (success) {
print('Code sent successfully');
}
getRMTemperature() & getRMHumidity()
Get sensor data from RM4 devices:
Future<double?> getRMTemperature(String deviceId)
Future<double?> getRMHumidity(String deviceId)
// Example
final temperature = await sdk.getRMTemperature(deviceId);
final humidity = await sdk.getRMHumidity(deviceId);
print('Temperature: ${temperature}°C, Humidity: ${humidity}%');
SP Device Control #
setSPPower() & getSPPower()
Control and check power state:
Future<bool> setSPPower(String deviceId, bool on)
Future<bool?> getSPPower(String deviceId)
// Example
await sdk.setSPPower(deviceId, true); // Turn on
await sdk.setSPPower(deviceId, false); // Turn off
final isOn = await sdk.getSPPower(deviceId);
print('Device is ${isOn ? 'ON' : 'OFF'}');
setSPNightlight()
Set nightlight (SP3 devices):
Future<bool> setSPNightlight(String deviceId, bool on)
// Example
await sdk.setSPNightlight(deviceId, true);
getSPEnergyConsumption()
Get energy consumption (SP2S devices):
Future<double?> getSPEnergyConsumption(String deviceId)
// Example
final watts = await sdk.getSPEnergyConsumption(deviceId);
print('Power consumption: ${watts}W');
đ Data Models #
LLDNADeviceInfo #
Contains device information and authentication state:
class LLDNADeviceInfo {
final String id; // Unique device identifier
final String name; // Device name
final String typeName; // Device type name (e.g., "RM2 Pro")
final int typeId; // Device type ID (hex value)
final String host; // IP address
final int port; // Port number
final String macAddress; // MAC address
final bool isLocked; // Whether device is locked
final DeviceCapabilities capabilities;
final DateTime lastSeen; // Last seen timestamp
// Authentication fields (populated after authentication)
Uint8List? aesKey; // AES encryption key
Uint8List? deviceId; // Device ID for commands
}
DeviceCapabilities #
Describes what the device supports:
class DeviceCapabilities {
final bool supportsIR; // IR control
final bool supportsRF; // RF control
final bool supportsPower; // Power control
final bool supportsNightlight; // Nightlight control
final bool supportsEnergyMonitoring;
final bool supportsSensors; // Temperature/humidity sensors
final bool supportsTemperature;
final bool supportsHumidity;
}
DeviceStatus #
Current device status information:
class DeviceStatus {
final String deviceId;
final bool isOnline;
final bool isConnected;
final int? firmwareVersion;
final bool? powerState;
final bool? nightlightState;
final double? energyConsumption;
final double? temperature;
final double? humidity;
final DateTime lastUpdate;
}
đŻ Events #
The SDK provides real-time events for device and discovery activities.
Device Events #
sdk.deviceEvents.listen((event) {
if (event is DeviceConnectedEvent) {
print('Device connected: ${event.deviceId}');
} else if (event is DeviceStateChangedEvent) {
print('Device state changed: ${event.changes}');
} else if (event is CodeLearnedEvent) {
print('IR code learned: ${event.code}');
}
});
Discovery Events #
sdk.discoveryEvents.listen((event) {
if (event is DiscoveryCompletedEvent) {
print('Discovery completed: ${event.devices.length} devices found');
} else if (event is DeviceDiscoveredEvent) {
print('Device discovered: ${event.device.name}');
}
});
đ§ Advanced Usage #
Save and Restore Devices #
// After discovery with auto-authentication
final devices = await sdk.discoverDevices(autoAuthenticate: true);
// Save authenticated devices
await saveDevicesToStorage(devices.map((d) => d.toJson()).toList());
// Later, restore devices
final savedData = await loadDevicesFromStorage();
final restoredDevices = savedData
.map((json) => LLDNADeviceInfo.fromJson(json))
.toList();
sdk.initializeDevices(restoredDevices);
// Use devices without re-authentication
for (final device in restoredDevices) {
if (device.aesKey != null) {
await sdk.setSPPower(device.id, true);
}
}
Error Handling #
try {
final devices = await sdk.discoverDevices();
} on BroadlinkDiscoveryException catch (e) {
print('Discovery failed: $e');
} on BroadlinkNetworkException catch (e) {
print('Network error: $e');
} catch (e) {
print('Unexpected error: $e');
}
đą Supported Devices #
RM Series (Remote Controllers) #
- RM2 (0x2712): IR learning and sending
- RM Mini (0x2737): IR learning and sending
- RM Pro (0x273d): IR/RF learning and sending
- RM4 Pro/Mini (0x51DA, 0x5209, etc.): IR/RF + temperature/humidity sensors
SP Series (Smart Plugs) #
- SP2 (0x2711): Basic power control
- SP3 (0x753e): Power control + nightlight
- SP2S (0x7918): Power control + energy monitoring
- SP4/SP4B: Advanced JSON-based control
đ Permissions #
Android #
Add to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
iOS #
Add to ios/Runner/Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to discover devices on your WiFi network.</string>
đ Troubleshooting #
Common Issues #
Device Discovery Fails:
- Ensure devices and phone are on same WiFi network
- Check router firewall settings
- Try manual discovery with IP address
Authentication Issues:
- If auto-authentication fails, the device may be locked by another app
- Try power cycling the device
- Use
connectDevice()to manually authenticate
Devices Not Responding:
- Verify device has valid
aesKeyanddeviceId - Check device is online with
hello() - Ensure correct device capabilities
Debug Logging #
All discovery operations include detailed logging with [LinkLinkSDK][DeviceDiscoveryService] prefix:
// Enable logging to see discovery details
[LinkLinkSDK][DeviceDiscoveryService] ĺźĺ§čŽžĺ¤ĺç°
[LinkLinkSDK][DeviceDiscoveryService] ĺç°čŽžĺ¤ - RM4 Pro (192.168.1.100:80)
[LinkLinkSDK][DeviceDiscoveryService] â
莞ĺ¤é
寚ćĺ: RM4 Pro
đ License #
This project is licensed under the MIT License - see the LICENSE file for details.
đ Acknowledgments #
This SDK is based on the reverse-engineered Broadlink protocol and is compatible with the python-broadlink library.
Made with â¤ď¸ for the Flutter and smart home communities.