UI framework
This commit is contained in:
10
arduino/hello.ino
Normal file
10
arduino/hello.ino
Normal file
@@ -0,0 +1,10 @@
|
||||
void setup() {
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(10);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(1000);
|
||||
}
|
||||
63
pi/ui/lib/main.dart
Normal file
63
pi/ui/lib/main.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const SmartSerowApp());
|
||||
}
|
||||
|
||||
class SmartSerowApp extends StatelessWidget {
|
||||
const SmartSerowApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Smart Serow',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.teal,
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const HomePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.terrain,
|
||||
size: 120,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text(
|
||||
'Smart Serow',
|
||||
style: Theme.of(context).textTheme.headlineLarge?.copyWith(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'System Ready',
|
||||
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
19
pi/ui/pubspec.yaml
Normal file
19
pi/ui/pubspec.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
name: smartserow_ui
|
||||
description: Smart Serow embedded UI for Raspberry Pi Zero 2W
|
||||
publish_to: 'none'
|
||||
version: 0.1.0
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^3.0.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
35
scripts/build.sh
Normal file
35
scripts/build.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
# Build script for Smart Serow Flutter UI
|
||||
# Run this in WSL2 with flutter-elinux installed
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
UI_DIR="$PROJECT_ROOT/pi/ui"
|
||||
|
||||
echo "=== Smart Serow Build ==="
|
||||
echo "Project: $UI_DIR"
|
||||
|
||||
cd "$UI_DIR"
|
||||
|
||||
# Clean previous build (optional, comment out for faster incremental builds)
|
||||
# flutter-elinux clean
|
||||
|
||||
echo "Fetching dependencies..."
|
||||
flutter-elinux pub get
|
||||
|
||||
echo "Building for ARM64 (elinux)..."
|
||||
flutter-elinux build elinux --target-arch=arm64 --release
|
||||
|
||||
BUILD_OUTPUT="$UI_DIR/build/elinux/arm64/release/bundle"
|
||||
|
||||
if [ -d "$BUILD_OUTPUT" ]; then
|
||||
echo ""
|
||||
echo "=== Build Complete ==="
|
||||
echo "Output: $BUILD_OUTPUT"
|
||||
ls -lh "$BUILD_OUTPUT"
|
||||
else
|
||||
echo "ERROR: Build output not found at $BUILD_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
53
scripts/deploy.sh
Normal file
53
scripts/deploy.sh
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
# Deploy script for Smart Serow Flutter UI
|
||||
# Pushes build bundle to Pi and optionally restarts service
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
CONFIG_FILE="$SCRIPT_DIR/deploy_target.json"
|
||||
|
||||
# Parse config
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "ERROR: Config file not found: $CONFIG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HOST=$(jq -r '.host' "$CONFIG_FILE")
|
||||
REMOTE_PATH=$(jq -r '.remote_path' "$CONFIG_FILE")
|
||||
SERVICE_NAME=$(jq -r '.service_name' "$CONFIG_FILE")
|
||||
|
||||
BUILD_DIR="$PROJECT_ROOT/pi/ui/build/elinux/arm64/release/bundle"
|
||||
|
||||
echo "=== Smart Serow Deploy ==="
|
||||
echo "Target: $HOST:$REMOTE_PATH"
|
||||
echo "Source: $BUILD_DIR"
|
||||
|
||||
if [ ! -d "$BUILD_DIR" ]; then
|
||||
echo "ERROR: Build directory not found. Run build.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Sync build to Pi
|
||||
echo ""
|
||||
echo "Syncing files..."
|
||||
rsync -avz --delete \
|
||||
"$BUILD_DIR/" \
|
||||
"$HOST:$REMOTE_PATH/bundle/"
|
||||
|
||||
# Restart service if requested
|
||||
RESTART="${1:-}"
|
||||
if [ "$RESTART" = "--restart" ] || [ "$RESTART" = "-r" ]; then
|
||||
echo ""
|
||||
echo "Restarting service: $SERVICE_NAME"
|
||||
ssh "$HOST" "sudo systemctl restart $SERVICE_NAME"
|
||||
sleep 2
|
||||
ssh "$HOST" "systemctl status $SERVICE_NAME --no-pager"
|
||||
else
|
||||
echo ""
|
||||
echo "Deploy complete. To restart service, run:"
|
||||
echo " ssh $HOST 'sudo systemctl restart $SERVICE_NAME'"
|
||||
echo ""
|
||||
echo "Or run this script with --restart flag"
|
||||
fi
|
||||
5
scripts/deploy_target.json
Normal file
5
scripts/deploy_target.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"host": "pi@smartserow.local",
|
||||
"remote_path": "/opt/smartserow",
|
||||
"service_name": "smartserow-ui"
|
||||
}
|
||||
76
scripts/pi_setup.sh
Normal file
76
scripts/pi_setup.sh
Normal file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
# One-time setup script for Smart Serow on Raspberry Pi
|
||||
# Run this ON the Pi itself
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Smart Serow Pi Setup ==="
|
||||
|
||||
# Check if running on Pi (arm architecture)
|
||||
ARCH=$(uname -m)
|
||||
if [[ "$ARCH" != "aarch64" && "$ARCH" != "armv7l" ]]; then
|
||||
echo "WARNING: This doesn't look like a Pi (arch: $ARCH)"
|
||||
echo "Continuing anyway..."
|
||||
fi
|
||||
|
||||
APP_DIR="/opt/smartserow"
|
||||
SERVICE_FILE="/etc/systemd/system/smartserow-ui.service"
|
||||
|
||||
# Create app directory
|
||||
echo "Creating app directory: $APP_DIR"
|
||||
sudo mkdir -p "$APP_DIR/bundle"
|
||||
sudo chown -R pi:pi "$APP_DIR"
|
||||
|
||||
# Install runtime dependencies for flutter-elinux
|
||||
echo "Installing runtime dependencies..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
libgl1-mesa-dri \
|
||||
libgles2-mesa \
|
||||
libegl1-mesa \
|
||||
libdrm2 \
|
||||
libgbm1 \
|
||||
libinput10 \
|
||||
libudev1 \
|
||||
fonts-noto
|
||||
|
||||
# For X11 debug mode (optional but useful)
|
||||
sudo apt-get install -y \
|
||||
xorg \
|
||||
xinit \
|
||||
libx11-6 \
|
||||
libxkbcommon-x11-0
|
||||
|
||||
# Copy systemd service
|
||||
echo "Installing systemd service..."
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
if [ -f "$SCRIPT_DIR/smartserow-ui.service" ]; then
|
||||
sudo cp "$SCRIPT_DIR/smartserow-ui.service" "$SERVICE_FILE"
|
||||
else
|
||||
echo "WARNING: Service file not found at $SCRIPT_DIR/smartserow-ui.service"
|
||||
echo "Copy it manually to $SERVICE_FILE"
|
||||
fi
|
||||
|
||||
# Enable service
|
||||
echo "Enabling service..."
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable smartserow-ui
|
||||
|
||||
# Add pi user to required groups for DRM/KMS access
|
||||
echo "Setting up permissions..."
|
||||
sudo usermod -aG video pi
|
||||
sudo usermod -aG input pi
|
||||
sudo usermod -aG render pi 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "=== Setup Complete ==="
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Deploy the app: run deploy.sh from your dev machine"
|
||||
echo "2. Start service: sudo systemctl start smartserow-ui"
|
||||
echo "3. Or reboot: sudo reboot"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " systemctl status smartserow-ui # Check status"
|
||||
echo " journalctl -u smartserow-ui -f # View logs"
|
||||
echo ""
|
||||
30
scripts/smartserow-ui.service
Normal file
30
scripts/smartserow-ui.service
Normal file
@@ -0,0 +1,30 @@
|
||||
[Unit]
|
||||
Description=Smart Serow UI
|
||||
After=multi-user.target
|
||||
Wants=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=pi
|
||||
Group=pi
|
||||
WorkingDirectory=/opt/smartserow/bundle
|
||||
|
||||
# DRM/KMS backend for direct framebuffer (no X11 needed)
|
||||
ExecStart=/opt/smartserow/bundle/smartserow_ui -b drm
|
||||
|
||||
# Restart on crash
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
|
||||
# Environment for DRM/KMS access
|
||||
Environment=XDG_RUNTIME_DIR=/run/user/1000
|
||||
Environment=HOME=/home/pi
|
||||
|
||||
# Give time for GPU to initialize on boot
|
||||
ExecStartPre=/bin/sleep 2
|
||||
|
||||
# Ensure clean shutdown
|
||||
TimeoutStopSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user