autostart
This commit is contained in:
parent
65235d8c9a
commit
ca110918b4
6 changed files with 243 additions and 22 deletions
104
SERVICE_README.md
Normal file
104
SERVICE_README.md
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# AutoKanban Service Setup
|
||||||
|
|
||||||
|
This directory contains files to run AutoKanban as a system service that starts automatically on boot.
|
||||||
|
|
||||||
|
## Quick Setup (Raspberry Pi)
|
||||||
|
|
||||||
|
1. **Run the setup script:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/autokanban
|
||||||
|
chmod +x setup_service.sh
|
||||||
|
./setup_service.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **The app will now start automatically on boot!**
|
||||||
|
|
||||||
|
## Service Management Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if service is running
|
||||||
|
sudo systemctl status autokanban
|
||||||
|
|
||||||
|
# Stop the service
|
||||||
|
sudo systemctl stop autokanban
|
||||||
|
|
||||||
|
# Start the service
|
||||||
|
sudo systemctl start autokanban
|
||||||
|
|
||||||
|
# Restart the service
|
||||||
|
sudo systemctl restart autokanban
|
||||||
|
|
||||||
|
# View live logs
|
||||||
|
sudo journalctl -u autokanban -f
|
||||||
|
|
||||||
|
# View recent logs
|
||||||
|
sudo journalctl -u autokanban -n 50
|
||||||
|
|
||||||
|
# Disable autostart on boot
|
||||||
|
sudo systemctl disable autokanban
|
||||||
|
|
||||||
|
# Enable autostart on boot
|
||||||
|
sudo systemctl enable autokanban
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Service Installation
|
||||||
|
|
||||||
|
If the setup script doesn't work, install manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy service file
|
||||||
|
sudo cp autokanban.service /etc/systemd/system/
|
||||||
|
|
||||||
|
# Edit paths if needed
|
||||||
|
sudo nano /etc/systemd/system/autokanban.service
|
||||||
|
|
||||||
|
# Reload systemd
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
# Enable and start
|
||||||
|
sudo systemctl enable autokanban
|
||||||
|
sudo systemctl start autokanban
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updating the App
|
||||||
|
|
||||||
|
After pulling new code:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/autokanban
|
||||||
|
git pull
|
||||||
|
sudo systemctl restart autokanban
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Service won't start:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check logs for errors
|
||||||
|
sudo journalctl -u autokanban -n 50
|
||||||
|
|
||||||
|
# Check Python path
|
||||||
|
which python
|
||||||
|
# Update ExecStart in service file if needed
|
||||||
|
```
|
||||||
|
|
||||||
|
**Permission issues:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Make sure user is in dialout group (for printer)
|
||||||
|
sudo usermod -a -G dialout $USER
|
||||||
|
|
||||||
|
# Reboot for group changes to take effect
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
**Port already in use:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check what's using port 8000
|
||||||
|
sudo lsof -i :8000
|
||||||
|
|
||||||
|
# Kill the process or change port in start_app.py
|
||||||
|
```
|
||||||
12
app/main.py
12
app/main.py
|
|
@ -147,11 +147,11 @@ def print_task(request: Request, task_id: str):
|
||||||
draw = ImageDraw.Draw(img)
|
draw = ImageDraw.Draw(img)
|
||||||
draw.rectangle([(0,0),(CARD_WIDTH_PX-1,CARD_HEIGHT_PX-1)], outline=0, width=4)
|
draw.rectangle([(0,0),(CARD_WIDTH_PX-1,CARD_HEIGHT_PX-1)], outline=0, width=4)
|
||||||
|
|
||||||
# Robust font loading
|
# Robust font loading - increased sizes for physical printer readability
|
||||||
font_title = load_font(FONT_BOLD, 36, font_label="title")
|
font_title = load_font(FONT_BOLD, 42, font_label="title")
|
||||||
font_label_f = load_font(FONT_BOLD, 18, font_label="label")
|
font_label_f = load_font(FONT_BOLD, 24, font_label="label")
|
||||||
font_text = load_font(FONT_REGULAR, 22, font_label="text")
|
font_text = load_font(FONT_REGULAR, 28, font_label="text")
|
||||||
font_icon = load_font(FA_FONT, 48, font_label="icon")
|
font_icon = load_font(FA_FONT, 60, font_label="icon")
|
||||||
|
|
||||||
# Prepare content for line wrapping
|
# Prepare content for line wrapping
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
@ -159,7 +159,7 @@ def print_task(request: Request, task_id: str):
|
||||||
max_text_width = CARD_WIDTH_PX - 40
|
max_text_width = CARD_WIDTH_PX - 40
|
||||||
content_lines = []
|
content_lines = []
|
||||||
if font_title:
|
if font_title:
|
||||||
wrapper = textwrap.TextWrapper(width=24)
|
wrapper = textwrap.TextWrapper(width=20) # Reduced from 24 due to larger font
|
||||||
lines = wrapper.wrap(task.content)
|
lines = wrapper.wrap(task.content)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
# Check pixel width, wrap further if needed
|
# Check pixel width, wrap further if needed
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,22 @@ button:hover {
|
||||||
color: #1C1C1E;
|
color: #1C1C1E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #E9EEF5;
|
||||||
|
color: #1C1C1E;
|
||||||
|
padding: 1.5em 0;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer .footer-logo {
|
||||||
|
height: 40px;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.container {
|
.container {
|
||||||
width: 95%;
|
width: 95%;
|
||||||
|
|
|
||||||
24
autokanban.service
Normal file
24
autokanban.service
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
[Unit]
|
||||||
|
Description=AutoKanban Thermal Printer Web App
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=pi
|
||||||
|
Group=pi
|
||||||
|
WorkingDirectory=/home/pi/autokanban
|
||||||
|
Environment="PATH=/home/pi/.pyenv/versions/autokanban/bin:/usr/local/bin:/usr/bin:/bin"
|
||||||
|
Environment="PYENV_ROOT=/home/pi/.pyenv"
|
||||||
|
ExecStart=/home/pi/.pyenv/versions/autokanban/bin/python /home/pi/autokanban/start_app.py
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
# Graceful shutdown
|
||||||
|
TimeoutStopSec=10
|
||||||
|
KillMode=mixed
|
||||||
|
KillSignal=SIGTERM
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
58
setup_service.sh
Normal file
58
setup_service.sh
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# AutoKanban Systemd Service Setup Script
|
||||||
|
# Run this on the Raspberry Pi to enable autostart on boot
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🚀 Setting up AutoKanban service..."
|
||||||
|
|
||||||
|
# Check if running as regular user
|
||||||
|
if [ "$EUID" -eq 0 ]; then
|
||||||
|
echo "❌ Please run as regular user (not sudo)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the directory where this script is located
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
SERVICE_FILE="$SCRIPT_DIR/autokanban.service"
|
||||||
|
|
||||||
|
echo "📁 Working directory: $SCRIPT_DIR"
|
||||||
|
|
||||||
|
# Update the service file with actual paths
|
||||||
|
echo "🔧 Updating service file paths..."
|
||||||
|
sed -i "s|/home/pi/autokanban|$SCRIPT_DIR|g" "$SERVICE_FILE"
|
||||||
|
sed -i "s|User=pi|User=$USER|g" "$SERVICE_FILE"
|
||||||
|
sed -i "s|Group=pi|Group=$USER|g" "$SERVICE_FILE"
|
||||||
|
|
||||||
|
# Copy service file to systemd
|
||||||
|
echo "📋 Installing systemd service..."
|
||||||
|
sudo cp "$SERVICE_FILE" /etc/systemd/system/autokanban.service
|
||||||
|
|
||||||
|
# Reload systemd
|
||||||
|
echo "🔄 Reloading systemd..."
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
# Enable the service
|
||||||
|
echo "✅ Enabling autokanban service..."
|
||||||
|
sudo systemctl enable autokanban.service
|
||||||
|
|
||||||
|
# Start the service
|
||||||
|
echo "▶️ Starting autokanban service..."
|
||||||
|
sudo systemctl start autokanban.service
|
||||||
|
|
||||||
|
# Show status
|
||||||
|
echo ""
|
||||||
|
echo "✨ Setup complete! Service status:"
|
||||||
|
sudo systemctl status autokanban.service --no-pager
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📝 Useful commands:"
|
||||||
|
echo " sudo systemctl status autokanban - Check service status"
|
||||||
|
echo " sudo systemctl stop autokanban - Stop the service"
|
||||||
|
echo " sudo systemctl start autokanban - Start the service"
|
||||||
|
echo " sudo systemctl restart autokanban - Restart the service"
|
||||||
|
echo " sudo journalctl -u autokanban -f - View live logs"
|
||||||
|
echo " sudo systemctl disable autokanban - Disable autostart"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 AutoKanban should now be running at http://$(hostname -I | awk '{print $1}'):8000"
|
||||||
51
start_app.py
51
start_app.py
|
|
@ -1,23 +1,42 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
|
|
||||||
# Activate venv if not already active
|
# Handle graceful shutdown
|
||||||
def activate_venv():
|
def signal_handler(sig, frame):
|
||||||
venv_path = os.path.join(os.path.dirname(__file__), '.venv', 'bin', 'activate_this.py')
|
print("\n[INFO] Shutting down gracefully...")
|
||||||
if os.path.exists(venv_path):
|
sys.exit(0)
|
||||||
with open(venv_path) as f:
|
|
||||||
exec(f.read(), {'__file__': venv_path})
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
signal.signal(signal.SIGTERM, signal_handler)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Optionally activate venv (works on Linux/macOS)
|
# Use pyenv python if available, otherwise fall back to venv or system python
|
||||||
venv_python = os.path.join(os.path.dirname(__file__), '.venv', 'bin', 'python')
|
python_exec = sys.executable
|
||||||
if os.path.exists(venv_python):
|
|
||||||
python_exec = venv_python
|
|
||||||
else:
|
|
||||||
python_exec = sys.executable
|
|
||||||
|
|
||||||
# Launch the FastAPI app with uvicorn
|
# Check for pyenv virtualenv
|
||||||
subprocess.run([
|
pyenv_root = os.environ.get('PYENV_ROOT')
|
||||||
python_exec, '-m', 'uvicorn', 'app.main:app', '--host', '0.0.0.0', '--port', '8000', '--reload'
|
if pyenv_root:
|
||||||
])
|
pyenv_python = os.path.join(pyenv_root, 'versions', 'autokanban', 'bin', 'python')
|
||||||
|
if os.path.exists(pyenv_python):
|
||||||
|
python_exec = pyenv_python
|
||||||
|
|
||||||
|
# Fall back to local venv
|
||||||
|
if python_exec == sys.executable:
|
||||||
|
venv_python = os.path.join(os.path.dirname(__file__), '.venv', 'bin', 'python')
|
||||||
|
if os.path.exists(venv_python):
|
||||||
|
python_exec = venv_python
|
||||||
|
|
||||||
|
print(f"[INFO] Using Python: {python_exec}")
|
||||||
|
print(f"[INFO] Starting AutoKanban on http://0.0.0.0:8000")
|
||||||
|
|
||||||
|
# Launch the FastAPI app with uvicorn (no --reload for production)
|
||||||
|
try:
|
||||||
|
subprocess.run([
|
||||||
|
python_exec, '-m', 'uvicorn', 'app.main:app',
|
||||||
|
'--host', '0.0.0.0', '--port', '8000'
|
||||||
|
])
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n[INFO] Shutting down gracefully...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue