Flutter SDK for Frame
The Flutter SDK enables cross-platform application development for Frame using Dart.
Table of Contents
Installation
Add to your pubspec.yaml:
dependencies:
frame_sdk: ^1.0.0
Connection Example
import 'package:frame_sdk/frame_sdk.dart';
void main() async {
final frame = Frame();
await frame.connect();
print("Battery: ${await frame.getBatteryLevel()}%");
await frame.display.showText("Hello World!");
}
API Reference
Display
await frame.display.showText("Text");
await frame.display.scrollText("Long text");
await frame.display.drawRect(x, y, width, height);
// Example of text alignment
await frame.display.writeText("Top-left", align: Alignment2D.topLeft);
await frame.display.writeText("Top-Center", align: Alignment2D.topCenter);
await frame.display.writeText("Top-Right", align: Alignment2D.topRight);
await frame.display.writeText("Middle-Left", align: Alignment2D.middleLeft);
await frame.display.writeText("Middle-Center", align: Alignment2D.middleCenter);
await frame.display.writeText("Middle-Right", align: Alignment2D.middleRight);
await frame.display.writeText("Bottom-Left", align: Alignment2D.bottomLeft);
await frame.display.writeText("Bottom-Center", align: Alignment2D.bottomCenter);
await frame.display.writeText("Bottom-Right", align: Alignment2D.bottomRight);
await frame.display.show();
// Example of drawing rectangles
await frame.display.drawRect(220, 100, 200, 200, PaletteColors.white);
await frame.display.drawRect(320-8, 200-8, 16, 16, PaletteColors.red);
await frame.display.show();
// Example of drawing filled rectangles
await frame.display.drawRectFilled(
100, 100, 200, 200, 8, PaletteColors.red, PaletteColors.white);
await frame.display.writeText("Hello world!",
x: 110, y: 110, maxWidth: 180, maxHeight: 180,
align: Alignment2D.middleCenter);
await frame.display.show();
Camera
// Take photo
Uint8List photo = await frame.camera.takePhoto();
await frame.camera.savePhoto("photo.jpg");
// Take photo with more control
Uint8List photo = await frame.camera.takePhoto(
autofocusSeconds: 2,
quality: PhotoQuality.high,
autofocusType: AutoFocusType.centerWeighted
);
// Save photo
await frame.camera.savePhoto("frame-test-photo.jpg");
// Save photo with more control
await frame.camera.savePhoto(
"frame-test-photo-2.jpg",
autofocusSeconds: 3,
quality: PhotoQuality.high,
autofocusType: AutoFocusType.centerWeighted
);
File System
// Write file
await frame.files.writeFile("test.txt", utf8.encode("Content"));
// Read file
Uint8List content = await frame.files.readFile("test.txt");
// Delete file
bool didDelete = await frame.files.deleteFile("main.lua");
print("Deleted? $didDelete");
// Check if file exists
bool exists = await frame.files.fileExists("main.lua");
print("Main.lua ${exists ? 'exists' : 'does not exist'}");
Bluetooth
await frame.bluetooth.connect();
await frame.bluetooth.sendLua("print('hello')");
// Send break signal
await frame.bluetooth.sendBreakSignal();
// Send reset signal
await frame.bluetooth.sendResetSignal();
// Wait for data
Uint8List full_file_data = await frame.bluetooth.waitForData();
print(utf8.decode(full_file_data));
Microphone
// Record audio
Uint8List audio = await frame.microphone.recordAudio();
// Record audio with more control
Uint8List audio = await frame.microphone.recordAudio(
silenceCutoffLength: null,
maxLength: Duration(seconds: 5)
);
// Save audio file
await frame.microphone.saveAudioFile("test-audio.wav");
// Save audio file with more control
await frame.microphone.saveAudioFile(
"test-audio.wav",
silenceCutoffLength: null,
maxLength: Duration(seconds: 5)
);
Motion
// Get direction
Direction direction = await frame.motion.getDirection();
// Run on tap
void onTap() {
print("Frame was tapped!");
}
await frame.motion.runOnTap(
luaScript: "frame.display.text('I was tapped!',1,1);frame.display.show();",
callback: onTap
);
// Wait for tap
await frame.motion.waitForTap();
Complete Example
import 'dart:convert';
import 'dart:typed_data';
import 'package:frame_sdk/frame_sdk.dart';
import 'package:frame_sdk/display.dart';
import 'package:frame_sdk/motion.dart';
import 'package:frame_sdk/camera.dart';
import 'package:frame_sdk/microphone.dart';
import 'package:frame_sdk/bluetooth.dart';
import 'package:logging/logging.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:math';
import 'package:path_provider/path_provider.dart';
Future<void> runExample() async {
// Request bluetooth permission
await BrilliantBluetooth.requestPermission();
final frame = Frame();
// Connect to the frame
while (!frame.isConnected) {
print("Trying to connect...");
final didConnect = await frame.connect();
if (didConnect) {
print("Connected to device");
} else {
print("Failed to connect to device, will try again...");
}
}
// Get battery level
int batteryLevel = await frame.getBatteryLevel();
print("Frame battery: $batteryLevel%");
// Write file
await frame.files.writeFile("greeting.txt", utf8.encode("Hello world"));
// Read file
String fileContent = utf8.decode(await frame.files.readFile("greeting.txt"));
print(fileContent);
// Display text
await frame.runLua("frame.display.text('Hello world', 50, 100);frame.display.show()");
// Evaluate expression
print(await frame.evaluate("1+2"));
print("Tap the Frame to continue...");
await frame.display.showText("Tap the Frame to take a photo", align: Alignment2D.middleCenter);
await frame.motion.waitForTap();
// Take and save photo
await frame.display.showText("Taking photo...", align: Alignment2D.middleCenter);
await frame.camera.savePhoto("frame-test-photo.jpg");
await frame.display.showText("Photo saved!", align: Alignment2D.middleCenter);
// Take photo with more control
await frame.camera.savePhoto("frame-test-photo-2.jpg",
autofocusSeconds: 3,
quality: PhotoQuality.high,
autofocusType: AutoFocusType.centerWeighted);
// Get raw photo bytes
Uint8List photoBytes = await frame.camera.takePhoto(autofocusSeconds: 1);
print("Photo bytes: ${photoBytes.length}");
print("About to record until you stop talking");
await frame.display.showText("Say something...", align: Alignment2D.middleCenter);
// Record audio to file
double length = await frame.microphone.saveAudioFile("test-audio.wav");
print("Recorded ${length.toStringAsFixed(1)} seconds: \"./test-audio.wav\"");
await frame.display.showText("Recorded ${length.toStringAsFixed(1)} seconds", align: Alignment2D.middleCenter);
await Future.delayed(const Duration(seconds: 3));
// Record audio to memory
await frame.display.showText("Say something else...", align: Alignment2D.middleCenter);
Uint8List audioData = await frame.microphone.recordAudio(maxLength: const Duration(seconds: 10));
await frame.display.showText(
"Recorded ${(audioData.length / frame.microphone.sampleRate.toDouble()).toStringAsFixed(1)} seconds of audio",
align: Alignment2D.middleCenter);
print("Move around to track intensity of your motion");
await frame.display.showText("Move around to track intensity of your motion", align: Alignment2D.middleCenter);
double intensityOfMotion = 0;
Direction prevDirection = await frame.motion.getDirection();
for (int i = 0; i < 10; i++) {
await Future.delayed(const Duration(milliseconds: 100));
Direction direction = await frame.motion.getDirection();
intensityOfMotion = max(intensityOfMotion, (direction - prevDirection).amplitude());
prevDirection = direction;
}
print("Intensity of motion: ${intensityOfMotion.toStringAsFixed(2)}");
await frame.display.showText("Intensity of motion: ${intensityOfMotion.toStringAsFixed(2)}", align: Alignment2D.middleCenter);
print("Tap the Frame to continue...");
await frame.motion.waitForTap();
// Show the full palette
int width = 640 ~/ 4;
int height = 400 ~/ 4;
for (int color = 0; color < 16; color++) {
int tileX = (color % 4);
int tileY = (color ~/ 4);
await frame.display.drawRect(tileX * width + 1, tileY * height + 1, width, height, PaletteColors.fromIndex(color));
await frame.display.writeText("$color",
x: tileX * width + width ~/ 2 + 1,
y: tileY * height + height ~/ 2 + 1);
}
await frame.display.show();
print("Tap the Frame to continue...");
await frame.motion.waitForTap();
// Scroll some long text
await frame.display.scrollText(
"Never gonna give you up\nNever gonna let you down\nNever gonna run around and desert you\nNever gonna make you cry\nNever gonna say goodbye\nNever gonna tell a lie and hurt you");
// Display battery indicator and time as a home screen
batteryLevel = await frame.getBatteryLevel();
PaletteColors batteryFillColor = batteryLevel < 20
? PaletteColors.red
: batteryLevel < 50
? PaletteColors.yellow
: PaletteColors.green;
int batteryWidth = 150;
int batteryHeight = 75;
await frame.display.drawRect(
640 - 32, 40 + batteryHeight ~/ 2 - 8, 32, 16, PaletteColors.white);
await frame.display.drawRectFilled(
640 - 16 - batteryWidth,
40 - 8,
batteryWidth + 16,
batteryHeight + 16,
8,
PaletteColors.white,
PaletteColors.voidBlack);
await frame.display.drawRect(
640 - 8 - batteryWidth,
40,
(batteryWidth * 0.01 * batteryLevel).toInt(),
batteryHeight,
batteryFillColor);
await frame.display.writeText("$batteryLevel%",
x: 640 - 8 - batteryWidth,
y: 40,
maxWidth: batteryWidth,
maxHeight: batteryHeight,
align: Alignment2D.middleCenter);
await frame.display.writeText(DateTime.now().toString(), align: Alignment2D.middleCenter);
await frame.display.show();
// Set a wake screen via script
await frame.runOnWake(luaScript: """
frame.display.text('Battery: ' .. frame.battery_level() .. '%', 10, 10);
if frame.time.utc() > 10000 then
local time_now = frame.time.date();
frame.display.text(time_now['hour'] .. ':' .. time_now['minute'], 300, 160);
frame.display.text(time_now['month'] .. '/' .. time_now['day'] .. '/' .. time_now['year'], 300, 220)
end;
frame.display.show();
frame.sleep(10);
frame.display.text(' ',1,1);
frame.display.show();
frame.sleep()
""");
// Tell frame to sleep after 10 seconds then clear the screen and go to sleep
await frame.runLua("frame.sleep(10);frame.display.text(' ',1,1);frame.display.show();frame.sleep()");
}