Optional Express + WebSocket server for API proxying, KML generation, and real-time communication.
The Node.js companion server is optional — the Flutter app communicates directly with the LG rig via SSH and works independently. The server provides:
- API proxying — Fetch external data server-side (avoids CORS issues, reduces client complexity)
- KML generation — Server-side KML creation for complex use cases
- WebSocket — Real-time bidirectional communication between Flutter and server
- Sample data — Built-in city data for testing without external APIs
Location: server/
cd server
npm install
npm startOutput: Server running on port 3000
npm run devUses nodemon to auto-restart on file changes.
PORT=8080 npm startcurl http://localhost:3000/health
# → { "status": "healthy", "uptime": 12.345 }Health check.
Response:
{
"status": "ok",
"server": "LG Starter Kit Node Server"
}Server uptime and health status.
Response:
{
"status": "healthy",
"uptime": 123.456
}Server information and available endpoints.
Response:
{
"server": "LG Starter Kit Node Server",
"version": "1.0.0",
"endpoints": ["/", "/health", "/api/status", "/api/kml/generate", "/api/data"]
}Generate KML content server-side.
Request body:
{
"type": "placemark",
"lat": 41.6176,
"lng": 0.6200,
"name": "Lleida",
"description": "Home city"
}Supported types: placemark
Response:
{
"success": true,
"kml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>..."
}Sample city data for testing.
Response:
{
"data": [
{
"name": "Lleida",
"latitude": 41.6176,
"longitude": 0.6200,
"description": "Historic city in Catalonia"
},
{
"name": "Barcelona",
"latitude": 41.3874,
"longitude": 2.1686,
"description": "Capital of Catalonia"
},
{
"name": "Madrid",
"latitude": 40.4168,
"longitude": -3.7038,
"description": "Capital of Spain"
}
]
}URL: ws://localhost:3000
Client connects → Server sends: "Welcome to LG Starter Kit WebSocket Server"
Client sends: "Hello"
Server responds: "Server received: Hello (timestamp: 2026-02-18T10:30:00.000Z)"
| Event | Description |
|---|---|
connection |
Client connected — logged to console |
message |
Message received — echoed with timestamp |
close |
Client disconnected — logged to console |
final socketService = SocketService();
await socketService.connect('ws://localhost:3000');
socketService.messages.listen((msg) {
debugPrint('Server: $msg');
});
socketService.send('Hello from Flutter');| Package | Version | Purpose |
|---|---|---|
express |
^4.18.2 | HTTP framework |
cors |
^2.8.5 | Cross-origin request handling |
ws |
^8.16.0 | WebSocket server |
nodemon (dev) |
^3.0.2 | Auto-reload during development |
| Variable | Default | Override |
|---|---|---|
PORT |
3000 |
PORT=8080 npm start |
The server listens on all interfaces by default.
The Flutter app uses the http package to call REST endpoints:
import 'package:http/http.dart' as http;
final response = await http.get(Uri.parse('${Config.serverUrl}/api/data'));
final cities = jsonDecode(response.body)['data'];The Flutter app uses SocketService (wraps web_socket_channel):
final socket = SocketService();
await socket.connect(Config.serverUrl.replaceFirst('http', 'ws'));
socket.messages.listen((msg) => handleMessage(msg));
socket.send(jsonEncode({'type': 'request', 'data': 'earthquakes'}));The server URL is defined in flutter_client/lib/config.dart:
static const String serverUrl = 'http://localhost:3000';Update this to match your server deployment.