Flutter SDK for Frame

The Flutter SDK enables cross-platform application development for Frame using Dart.

Table of Contents

  1. Installation
  2. Connection Example
  3. API Reference
  4. Complete Example

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()");
}

View full documentation