17 KiB
TCK RTU - Technical Documentation
Table of Contents
- Overview
- System Architecture
- Components
- API Client
- Display Modes
- Navigation
- State Management
- Testing
- Performance
- Deployment
- Start Script
- Installation Script
- UI Design Decisions
- User Flow
- Future Phases
- Troubleshooting
Overview
TCKRTUIYO is a web-based interface for Base Station/Real-Time Unit (RTU) monitoring rainfall and related sensors. The system is designed to run on Raspberry Pi Zero 2 W with a 7" capacitive touchscreen display.
System Architecture
Hardware Requirements
- Raspberry Pi: Zero 2 W or 3B
- Display: 7" capacitive touchscreen, 1024x600 resolution
- Storage: MicroSD card for OS and data
- Network: Ethernet or WiFi for data transmission
Software Architecture
┌─────────────────────────────────────────────────────────────┐
│ Web Browser (Chromium) │
│ Kiosk Mode / Remote │
├─────────────────────────────────────────────────────────────┤
│ React Application │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Dashboard │ │ Settings │ │Calibration│ │ Memory │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────────┤
│ State Management (Zustand) │
├─────────────────────────────────────────────────────────────┤
│ API Client (with Mock Fallback) │
├─────────────────────────────────────────────────────────────┤
│ Python Backend (TBD) │
└─────────────────────────────────────────────────────────────┘
Components
Dashboard Components
| Component | File | Description |
|---|---|---|
| RainfallCard | RainfallCard.tsx |
Displays rainfall metrics with color coding |
| ClockDisplay | ClockDisplay.tsx |
Real-time clock and date |
| CommStatus | CommStatus.tsx |
Communication signal status |
| VoltageDisplay | VoltageDisplay.tsx |
Solar voltage display |
| BatteryStatus | BatteryStatus.tsx |
Battery voltage with status indicator |
| LoginIndicator | LoginIndicator.tsx |
Login status display |
View Components
| View | File | Description |
|---|---|---|
| Dashboard | DashboardView.tsx |
Main rainfall monitoring display |
| Graph | GraphView.tsx |
Data visualization with charts |
| Utility | UtilityView.tsx |
Additional utility functions |
| Calibration | CalibrationView.tsx |
Sensor calibration interface |
| FlashMemory | FlashMemoryView.tsx |
Data storage management |
| Setting | SettingView.tsx |
Main settings hub |
| Login | LoginView.tsx |
Authentication interface |
Settings Sub-Views
| Setting | File | Description |
|---|---|---|
| Station Info | StationInfoView.tsx |
Station ID, version info |
| Date/Time | DateTimeSettingView.tsx |
Date, time, timezone configuration |
| Mobile | MobileSettingView.tsx |
Mobile network (SIM) settings |
| ADC | ADCSettingView.tsx |
ADC calibration |
| Rainfall | RainfallSettingView.tsx |
Rainfall sensor settings |
| EVAP | EVAPSettingView.tsx |
Evaporation sensor settings |
| GPRS | GPRSSettingView.tsx |
GPRS configuration |
| Level | LevelSettingView.tsx |
Water level sensor settings |
| Siren | SirenSettingView.tsx |
Alarm/siren configuration |
| Network | NetworkSettingView.tsx |
WiFi/Ethernet settings |
Data Flow
-
Sensor Data Collection
- API client fetches data from backend
- Falls back to mock data if API unavailable
- Polling interval: 5 seconds (configurable)
-
State Management
- Zustand store holds all sensor data
- Components subscribe to relevant slices
- Changes trigger re-renders
-
Display Updates
- Real-time updates via polling
- Page Visibility API pauses polling when hidden
- Proper cleanup on unmount
API Client
Endpoint
GET /api/sensor-data
Response Format
{
"rainfall": {
"today": 12.5,
"hourly": 2.3,
"monthlyAcc": 156.8,
"yearlyAcc": 1847.2
},
"voltage": {
"solar": 12.4,
"battery": 12.8,
"batteryStatus": "HIGH"
},
"station": {
"id": "D007",
"version": "v4.0.4"
},
"communication": {
"asu": 15,
"dBm": -75,
"percentage": 50
},
"timestamp": "2026-03-13T12:00:00Z"
}
Mock Data
When the API is unavailable, mock data is automatically generated with realistic values:
- Rainfall: Random values 0-25mm
- Battery: Random values 11.5-13.5V
- Signal: Random ASU 0-31
Display Modes
Kiosk Mode (Port 8888)
- Fixed resolution: 1024x600
- Optimized for 7" touchscreen
- Compact layouts with 44px+ touch targets
- No scrollbars - navigation buttons instead
- Primary mode for local touchscreen display
Remote Mode (Port 9090)
- Responsive layout for any screen size
- Full HD optimized
- Expanded information display
- Standard scrollbars
- For remote access via network
Navigation
Menu Structure
├── HOME (Rainfall Dashboard)
├── GRAPH (Data Visualization)
├── UTILITY (Settings)
│ ├── Station Info
│ ├── Date / Time
│ ├── Mobile
│ ├── ADC
│ ├── Rainfall
│ ├── EVAP
│ ├── GPRS
│ ├── Level
│ ├── SIREN
│ └── Network
├── CALIBRATION
├── FLASH MEMORY
├── SETTING
└── LOGIN
View Components List
All views are located in sample_interface/src/app/components/views/:
DashboardView.tsx- Main rainfall dashboardGraphView.tsx- Data visualization with chartUtilityView.tsx- Utility functions hubCalibrationView.tsx- Sensor calibrationFlashMemoryView.tsx- File managementSettingView.tsx- Settings hub (side-by-side Display & System settings)LoginView.tsx- Login interface- Settings sub-views (StationInfo, DateTime, Mobile, ADC, Rainfall, EVAP, GPRS, Level, Siren, Network)
State Management
Zustand Store Structure
interface SensorState {
data: SensorData;
pollingInterval: number;
isPolling: boolean;
lastError: string | null;
setSensorData: (data: Partial<SensorData>) => void;
updatePollingInterval: (interval: number) => void;
setIsPolling: (polling: boolean) => void;
setError: (error: string | null) => void;
}
Usage
import { useSensorStore } from './stores/sensorStore';
// Get all data
const { data } = useSensorStore();
// Get specific slice
const rainfall = useSensorStore(state => state.data.rainfall);
// Update data
const setSensorData = useSensorStore(state => state.setSensorData);
Testing
Test Infrastructure
- Framework: Vitest
- Testing Library: @testing-library/react
- Environment: jsdom
Running Tests
npm test # Run once
npm run test:watch # Watch mode
Test Structure
src/
├── app/
│ ├── stores/
│ │ └── __tests__/
│ │ └── sensorStore.test.ts
│ ├── api/
│ │ └── __tests__/
│ │ └── client.test.ts
│ └── components/
│ └── __tests__/
│ ├── Header.test.tsx
│ └── RainfallCard.test.tsx
└── test/
└── setup.ts
Performance
Bundle Size Targets
| Metric | Target | Current |
|---|---|---|
| JS (gzip) | < 170KB | ~100KB |
| CSS (gzip) | < 20KB | ~15KB |
Optimizations
- Code splitting for routes
- Tree shaking for unused code
- Image optimization
- CSS purging (Tailwind)
Performance Tips
- Lazy Loading: Routes are lazy-loaded
- Memoization: Heavy computations memoized
- Virtualization: Long lists virtualized
- Polling Control: Pauses when tab hidden
Deployment
Build
npm run build
Output
dist/
├── index.html
└── assets/
├── index-xxxx.js
└── index-xxxx.css
Production Server
Automagically: Just run ./start.sh to serve the app.
Manually: Serve the dist folder with any static file server:
# Python
python -m http.server 8080
# Node
npx serve dist
Start Script
The start.sh script provides an interactive menu for common development commands.
Usage
./start.sh [option]
Options
| Option | Description |
|---|---|
1 or dev |
Start dev server (port 5173) |
2 or dev:8888 |
Start dev server on port 8888 (kiosk mode) |
3 or dev:9090 |
Start dev server on port 9090 (remote mode) |
4 or test |
Run tests |
5 or test:watch |
Run tests in watch mode |
6 or build |
Build for production |
7 or preview |
Preview production (port 4173) |
8 or lint |
Run linter |
9 or clean |
Clean build artifacts |
10 or install |
Install dependencies |
p or port |
Change default ports |
0 or exit |
Exit |
Note: Port 8888 is recommended for kiosk mode (7" touchscreen), port 9090 for remote access.
Installation Script
The install_everything.sh script automates the entire installation process including:
- Installing system dependencies (curl, git, nginx)
- Installing Node.js 20.x
- Cloning the repository
- Installing npm dependencies
- Starting the application
Quick Install
# Option 1: Clone and run locally
git clone https://github.com/your-repo/tck_rtu.git /opt/tck_rtu
cd /opt/tck_rtu
./install_everything.sh
# Option 2: From web server (see below)
curl -sL http://tckrtuiyo:3000/tck/tck_rtu/install_everything.sh | bash
# Option 3: From GitHub raw
curl -sL https://raw.githubusercontent.com/your-repo/main/install_everything.sh | bash
Web Server Setup
To serve the install script from a local web server for Option 2:
# Method 1: Using Python (simple)
sudo mkdir -p /var/www/html/tck/tck_rtu
sudo cp install_everything.sh /var/www/html/tck/tck_rtu/
cd /var/www/html/tck/tck_rtu
sudo python3 -m http.server 3000
# Method 2: Using nginx
sudo cp install_everything.sh /var/www/html/tck/tck_rtu/
sudo systemctl start nginx
# Access via:
# http://<server-ip>:3000/tck/tck_rtu/install_everything.sh
# or
# http://tckrtuiyo:80/tck/tck_rtu/install_everything.sh
Manual Install
If you prefer to install manually:
# 1. Install system dependencies (as root)
sudo apt-get update
sudo apt-get install -y curl git nginx
# 2. Install Node.js 20.x
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt-get install -y nodejs
# 3. Clone repository
sudo mkdir -p /opt
sudo git clone https://github.com/your-repo/tck_rtu.git /opt/tck_rtu
# 4. Install dependencies
cd /opt/tck_rtu/sample_interface
sudo npm install
# 5. Run
cd /opt/tck_rtu
sudo ./start.sh
UI Design Decisions
Layout Principles
- Vertical Stacking: Information flows top-to-bottom
- Controls at Bottom: Interactive elements (buttons, inputs) placed at bottom for easy thumb access
- Summary at Top: Key metrics and visualizations at top
- No Scrolling: All content fits within 1024x600 viewport
Touch Targets
- Minimum touch target: 44x44px
- Spacing between targets: 8px minimum
- Navigation buttons placed next to titles (not just in header)
Color Scheme
- Background: Dark gray (#1a1a2e, #16213e)
- Cards: Slightly lighter gray (#0f3460, #1f4068)
- Primary Accent: Blue (#4d96ff, #3a86ff)
- Text: White/light gray for contrast
- Status Colors:
- Green: Good/normal
- Yellow/Orange: Warning
- Red: Critical/alert
User Flow
Kiosk Mode Flow
- Boot: System starts, Chromium launches in kiosk mode
- Load: App loads at http://localhost:8888
- Dashboard: Shows rainfall data, clock, battery, signal
- Navigate: Use side buttons to switch views
- Interact: Touch screen for settings/siren tests
Navigation Buttons
- Horizontal placement: Next to view titles (not just in header)
- Clear labeling: Icon + text for clarity
- Consistent position: Same location across all views
Graph View Layout (example):
┌─────────────────────────────────────┐
│ [Icon] Graph View [↑] [↓] │ <- Header with nav buttons
├─────────────────────────────────────┤
│ Time Range | Data Pts | Avg Value │ <- Summary at top
├─────────────────────────────────────┤
│ │
│ Data Visualization │ <- Chart at bottom
│ │
└─────────────────────────────────────┘
Settings View Layout (example):
┌─────────────────────────────────────┐
│ [Icon] Setting [←] [→] │
├─────────────────────────────────────┤
│ Display Settings │ System Settings│ <- Side-by-side
├─────────────────────────────────────┤
│ Date │ Time │ Timezone │ <- Horizontal
├─────────────────────────────────────┤
│ Phone Number │ APN │ <- Horizontal (Mobile)
├─────────────────────────────────────┤
│ Enable EVAP │ Pan Coef │ Interval │ <- Horizontal (EVAP)
└─────────────────────────────────────┘
Future Phases
Phase 2: Settings Framework
- Station configuration
- Sensor calibration settings
- Network settings
- Mobile/GPRS configuration
Phase 3: Data Management & Network Stack
- CSV file management
- Data export
- Network protocol support (FTP/SCP/SFTP/WEBDAV)
- TIEDA data transmission
Troubleshooting
Common Issues
-
Build fails
- Check Node.js version (18+ required)
- Clear node_modules and reinstall
-
Bundle too large
- Check for unused imports
- Verify tree shaking enabled
-
API not connecting
- Check backend is running
- Verify CORS settings
-
Dev server wrong port
- Use
--portflag:npm run dev -- --port 8888 - Not
VITE_PORT=8888(doesn't work with npm)
- Use
Development Tools
- React DevTools
- Vite HMR
- Vitest test runner