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