tinytuya 0.1.1
tinytuya: ^0.1.1 copied to clipboard
Dart/Flutter port of Python TinyTuya - Control Tuya WiFi smart devices over LAN. Supports v3.1-v3.5 protocols, device discovery, cloud API, and all device types.
TinyTuya Dart #
A Dart/Flutter port of Python TinyTuya - a library to control Tuya WiFi smart devices.
Features #
- ✅ Complete Protocol Support: v3.1, v3.3, v3.4, and v3.5 (including GCM encryption)
- ✅ Device Control: Direct local network communication with Tuya devices
- ✅ Device Discovery: UDP scanner to find devices on your network
- ✅ Cloud API: Full Tuya Cloud API support for device management
- ✅ Device Types: Outlets, Bulbs (RGB/HSV), Covers, and generic devices
- ✅ Python Compatible: Byte-for-byte compatible with Python TinyTuya
- ✅ Well Tested: 56+ tests with Python comparison validation
Installation #
Add to your pubspec.yaml:
dependencies:
tinytuya: ^0.1.0
Then run:
dart pub get
# or
flutter pub get
Quick Start #
1. Control a Device #
import 'package:tinytuya/tinytuya.dart';
void main() async {
// Create device instance
final device = Device(
devId: 'your_device_id',
address: '192.168.1.100',
localKey: 'your_local_key',
version: 3.3,
);
// Connect and get status
try {
final status = await device.status();
print('Device status: $status');
// Turn on
await device.turnOn();
// Set brightness (outlet devices)
final outlet = OutletDevice(
devId: 'your_device_id',
address: '192.168.1.100',
localKey: 'your_local_key',
);
await outlet.setDimmer(percentage: 75);
} finally {
device.close();
}
}
2. Discover Devices #
import 'package:tinytuya/tinytuya.dart';
void main() async {
print('Scanning for Tuya devices...');
final devices = await deviceScan(scanTime: 10);
print('Found ${devices.length} devices:');
for (final device in devices) {
print(' ${device.ip} - ${device.gwId} (v${device.version})');
}
}
3. Use Cloud API #
import 'package:tinytuya/tinytuya.dart';
void main() async {
// Create cloud client
final cloud = Cloud(
apiKey: 'your_api_key',
apiSecret: 'your_api_secret',
apiRegion: 'us', // us, eu, cn, in, sg
);
// Authenticate
final success = await cloud.init();
if (!success) {
print('Authentication failed: ${cloud.error}');
return;
}
// Get all devices
final devices = await cloud.getDevices();
for (final device in devices) {
print('${device['name']}: ${device['id']}');
print(' Local Key: ${device['local_key']}');
}
// Get device status
final status = await cloud.getStatus('device_id');
print('Status: ${status?['result']}');
}
Device Types #
Generic Device #
All devices support these methods:
final device = Device(
devId: 'device_id',
address: '192.168.1.100',
localKey: 'local_key',
version: 3.3,
);
// Control methods
await device.turnOn(switch: 1);
await device.turnOff(switch: 2);
await device.setValue(index: 1, value: 100);
await device.setTimer(numSecs: 3600);
// Query methods
final status = await device.status();
final dpsValues = await device.detectAvailableDps();
// Low-level methods
final payload = device.generatePayload(command: dpQuery);
await device.send(payload);
final response = await device.receive();
OutletDevice (Smart Plugs) #
final outlet = OutletDevice(
devId: 'device_id',
address: '192.168.1.100',
localKey: 'local_key',
);
// Set dimmer/brightness
await outlet.setDimmer(percentage: 75); // 0-100%
BulbDevice (Smart Bulbs) #
final bulb = BulbDevice(
devId: 'device_id',
address: '192.168.1.100',
localKey: 'local_key',
);
// Auto-detect bulb type (A, B, or C)
bulb.detectBulb();
// Color control
await bulb.setColour(255, 0, 0); // Red
await bulb.setHsv(0.5, 1.0, 1.0); // HSV
// White control
await bulb.setWhite(brightness: 255, colourTemp: 128);
await bulb.setWhitePercentage(brightness: 100, colourTemp: 50);
// Brightness
await bulb.setBrightness(200); // 0-255
await bulb.setBrightnessPercentage(80); // 0-100%
// Color temperature
await bulb.setColourTemp(150); // Raw value
await bulb.setColourTempPercentage(60); // 0-100%
// Modes and scenes
await bulb.setMode('colour'); // white, colour, scene, music
await bulb.setScene(3); // 1=nature, 3=rave, 4=rainbow
// Query color state
final rgb = bulb.colourRgb(); // [r, g, b]
final hsv = bulb.colourHsv(); // [h, s, v]
final brightness = bulb.brightness();
final temp = bulb.colourTemp();
CoverDevice (Blinds/Curtains) #
final cover = CoverDevice(
devId: 'device_id',
address: '192.168.1.100',
localKey: 'local_key',
);
await cover.openCover();
await cover.closeCover();
await cover.stopCover();
Scanner #
Discover Tuya devices on your local network:
// Scan for 10 seconds (default)
final devices = await deviceScan();
// Custom scan time
final devices = await deviceScan(scanTime: 20);
// Verbose output
final devices = await deviceScan(verbose: true);
// Each device contains:
print(device.ip); // IP address
print(device.gwId); // Gateway ID (device ID)
print(device.version); // Protocol version
print(device.productKey); // Product key
print(device.rawData); // Full JSON data
The scanner listens on multiple UDP ports (6666, 6667, 7000) and decrypts UDP broadcast packets from all protocol versions (v3.1-v3.5).
Cloud API #
The Cloud API provides access to the Tuya IoT Platform for device management and control:
final cloud = Cloud(
apiKey: 'your_api_key',
apiSecret: 'your_api_secret',
apiRegion: 'us', // or 'eu', 'cn', 'in', 'sg'
);
// Initialize (get access token)
await cloud.init();
// Get all devices with local keys
final devices = await cloud.getDevices();
// Get device status
final status = await cloud.getStatus('device_id');
// Send command
await cloud.sendCommand('device_id', {
'commands': [
{'code': 'switch_1', 'value': true}
]
});
// Get device specifications
final specs = await cloud.getDps('device_id');
final functions = await cloud.getFunctions('device_id');
final properties = await cloud.getProperties('device_id');
// Generic cloud request
final response = await cloud.cloudRequest(
'/v1.0/devices/device_id/logs',
action: 'GET',
);
Getting Cloud Credentials #
- Sign up at Tuya IoT Platform
- Create a Cloud Project
- Link your devices to the project
- Get your API Key and Secret from the project overview
Configuration #
Finding Device Parameters #
You need three pieces of information to control a device:
- Device ID (
devId): Found in the Tuya/Smart Life app - Local Key: Obtained via Cloud API or tinytuya wizard
- IP Address: Use the scanner or check your router
Protocol Versions #
- v3.1: Older devices, basic encryption
- v3.3: Most common, improved security
- v3.4: Additional HMAC validation
- v3.5: Latest, uses AES-GCM encryption
The library automatically handles all protocol versions.
Socket Persistence #
The persist parameter controls socket connection behavior:
// persist=false (default) - Socket closes after each operation
// Matches Python TinyTuya's socketPersistent=False
final device = Device(
deviceId: 'your_device_id',
address: '192.168.1.100',
localKey: 'your_local_key',
version: 3.3,
persist: false, // Default - socket closes after each operation
);
// persist=true - Socket stays open between operations
// Better for frequent operations, but connection may timeout after ~1 minute idle
final devicePersistent = Device(
deviceId: 'your_device_id',
address: '192.168.1.100',
localKey: 'your_local_key',
version: 3.3,
persist: true, // Keep socket open
);
Recommendations:
- Use
persist=false(default) for reliability - socket closes/reopens for each operation - Use
persist=truefor performance when making many rapid consecutive operations - The library automatically handles session timeout and reconnection in both modes
Examples #
See the example/ directory for complete examples:
device_control_example.dart- Basic device controlbulb_example.dart- Smart bulb controlscanner_example.dart- Device discoverycloud_example.dart- Cloud API usage
Testing #
The library includes comprehensive tests with Python comparison validation:
# Run all tests
dart test
# Run specific test suite
dart test test/bulb_color_conversion_test.dart
# Run scanner comparison (requires devices on network)
./example/compare_scanners.sh
Tests include:
- AES encryption (ECB and GCM)
- Message packing/unpacking
- Payload generation
- Device helper methods
- Bulb color conversion
- Cloud API signatures
- Scanner functionality
All tests compare output byte-for-byte with Python TinyTuya to ensure compatibility.
Troubleshooting #
Device Connection Issues #
Problem: Cannot connect to device
Solutions:
- Verify device is on same network
- Check firewall settings
- Ensure correct protocol version
- Verify local key is correct
Problem: "Invalid JSON" errors
Solutions:
- Try different protocol versions (3.1, 3.3, 3.4, 3.5)
- Some devices require protocol auto-detection
Cloud API Issues #
Problem: Authentication fails
Solutions:
- Verify API key and secret
- Check API region matches your account
- Ensure devices are linked to your cloud project
Problem: "Device not found"
Solutions:
- Link device to cloud project in Tuya IoT Platform
- Wait a few minutes after linking for propagation
Comparison with Python TinyTuya #
This Dart port maintains full compatibility with Python TinyTuya:
| Feature | Python TinyTuya | TinyTuya Dart |
|---|---|---|
| Protocol Support | v3.1-v3.5 | ✅ v3.1-v3.5 |
| Device Control | ✅ | ✅ |
| Cloud API | ✅ | ✅ |
| Scanner | ✅ | ✅ |
| Bulb Control | ✅ | ✅ |
| Payload Generation | ✅ | ✅ (byte-compatible) |
| Encryption | ✅ | ✅ (byte-compatible) |
All cryptographic operations and message formats are validated against Python TinyTuya to ensure interoperability.
Why Not PointyCastle? #
This port uses the cryptography package instead of PointyCastle because:
- PointyCastle has known issues with GCM counter mode
- IV/nonce and tag size handling problems in cross-language scenarios
- The
cryptographypackage provides proper AES-GCM implementation - Better cross-platform support and performance
Contributing #
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
dart test - Submit a pull request
Credits #
This is a port of Python TinyTuya by Jason Cox.
Original Python TinyTuya credits:
- TuyaAPI by codetheweb and blackrozes - Protocol reverse engineering
- PyTuya by clach04 - Original Python implementation
- LocalTuya by rospogrigio - Device ID support improvements
License #
MIT License - see LICENSE file for details.